From: <Donald.Huang@ite.com.tw>

Re-add this - someone might find it useful.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 drivers/scsi/Kconfig   |    9 
 drivers/scsi/Makefile  |    1 
 drivers/scsi/iteraid.c | 5371 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/iteraid.h | 1463 +++++++++++++
 4 files changed, 6844 insertions(+)

diff -puN /dev/null drivers/scsi/iteraid.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/scsi/iteraid.c	2005-06-16 17:49:12.000000000 -0700
@@ -0,0 +1,5371 @@
+/*
+ * linux/drivers/scsi/iteraid.c
+ *
+ * (C) Copyright 2002-2004 ITE Tech, inc.
+ *
+ * Nov 11, 2002	Mark Lu	file created.
+ *
+ * Aug 2 , 2004 Donald Huang published the ITE driver.
+ *
+ * ITE IT8212 RAID controller device driver for Linux.
+ *
+ * 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 0.0  2002/12/05	15:12:12  root
+ * Empty function bodies; detect() works.
+ *
+ * Revision 0.1 2002/12/17	19:21:37  root
+ * First "dma thing doesn't work" version.
+ *
+ * Revision 0.3 2002/12/23	17:12:09  root
+ * Rewrite the dma routines. Reference the ide-dma.c.
+ *
+ * Revision 0.4 2002/12/26	10:19:29  root
+ * The dma read/write works, using some ways to prove it. But there is a
+ * problem about the "unknown partition table". The fdisk is ok, but
+ * after writing the created partitions, it still shows the "unknown
+ * partition table" and i can't access the created partitions.
+ *
+ * Revision 0.5 2003/01/07	21:49:30 root
+ * The problem of "unknown partition table" has been solved.
+ * We must "ENABLE CLUSTERING". There is still a another problem about
+ * the SCATTER/GATHER.
+ *
+ * Revision 0.6 2003/01/10	17:45:32 root
+ * The SCATTER/GATHER problem has been solved. Now verify the read/write
+ * function and make sure each RAID configurations are workable. If testing
+ * is OK, then it will be a version 1.0.....
+ *
+ * Revision 1.0 2003/01/16	17:45:32 root
+ * First release version.
+ *
+ * FixME 1:
+ * In RedHat 7.3, if using SG_ALL, the SCSI will timeout. It looks like
+ * an command is requested but the interrupt is not been asserted. So
+ * try to add a watchdog timer to monitor the interrupts. But this kind
+ * of situration will not happen in Mandrake 9.0 and also when using
+ * SG_NONE in RedHat 7.3.
+ *
+ * FixME 2:
+ * Module load problem in RedHat 7.3.
+ *
+ * Fixed: Compile in the graphic mode (GNOME or KDE) will fix the
+ *	  module load problem.
+ *
+ * Revision 1.1 2003/02/10	10:32:21 root
+ * Compile in the graphic mode (GNOME or KDE) will fix the
+ * module load problem.
+ *
+ * Revision 1.2 2003/02/18	14:10:35 root
+ * Fix the interrupt service routine for share irq problem.
+ *
+ * ATAPI support ---> schedule is three weeks. (2003/02/28)
+ *
+ * Revision 1.3 2003/02/27
+ * First relase ATAPI version. But there will be an error if no disc in the
+ * CD-ROM. Because the commands like TEST_UNIT_READY and READ_CAPACITY will
+ * get the error response. This situration in WINDOWS will be then send the
+ * REQUEST SENSE command to the device but in Linux, it will never get
+ * REQUEST SENSE command. So can we send by ourself???
+ *
+ * 2003/03/05	root
+ *
+ * Note 1:
+ * According to "The Linux SCSI Generic (sg) HOWTO", the device will respond
+ * with a single byte value call the 'scsi_status'. GOOD is the scsi status
+ * indicating everything has gone well. The most common other status is
+ * CHECK CONDITION. In this latter case, the SCSI mid layer issues a REQUEST
+ * SENSE SCSI command. The response of the REQUEST SENSE is 18 bytes or more
+ * in length and is called the "sense buffer". It will indicate why the original
+ * command may not have been executed. It is important to realize that a CHECK
+ * CONDITION may very in severity from informative (e.g. command needed to be
+ * retried before succeeding) to fatal (e.g. 'medium error' which often
+ * indicates it is time to replace the disk).
+ *
+ * Note 2:
+ * When using the ATAPI BIOS, we also do not need to set up the timimg in linux
+ * driver. But it is necessary to write the timing routine in win system,
+ * cause it has a s1, s2, s3 mode and devices wake up from these modes need to
+ * be initialized again and do not pass through the BIOS.
+ *
+ * Note 3:
+ * The 48-bit support and AP for RAID in linux will the next job.
+ *
+ * Revision 1.31 2003/03/14	09:40:35 root
+ * Fix an error when no disc is on the CD-ROM and the audio cd is ready to play.
+ *
+ * 2003/04/08	root
+ * The ioctl code sklection is finished. But there is a problem about
+ * "Bad address" when copy_from_user() is called.
+ *
+ * Fixed: Use kmalloc() and kfree() to allocate the buffer instead of automatic
+ * variables (use stack). The stack size is limited in kernel space.
+ *
+ * Revision 1.32 2003/04/14	18:20:23 root
+ * Complete the IOCTLs code.
+ *
+ * The IOCTLs are listed below
+ * ===========================
+ *
+ * (1) ITE_IOC_GET_IDENTIFY_DATA
+ *
+ *     Return virtual drive 512 bytes identification data.
+ *
+ * (2) ITE_IOC_GET_PHY_DISK_STATUS
+ *
+ *     Developer can decide to return 4 physical disk information in
+ *     512 bytes (data structure should be defined) or 512 bytes
+ *     identification data of the physical disk specified by AP.
+ *
+ * (3) ITE_IOC_CREATE_DISK_ARRAY
+ *
+ *     Create a new array and erase (or keep) boot sector.
+ *
+ * (4) ITE_IOC_REBUILD_START
+ *
+ *     AP nees to specify target/source drive, starting LBA and length.
+ *
+ * (5) ITE_IOC_GET_REBUILD_STATUS
+ *
+ *     Return rebuild percentage or last LBA No.
+ *
+ * (6) ITE_IOC_RESET_ADAPTER
+ *
+ *     Reset the controller.
+ *
+ * Revision 1.33 2003/04/15	11:10:08 root
+ * The 48-bit support.
+ *
+ * Revision 1.34 2003/04/20	13:20:38 root
+ * Change some values in iteraid.h, so it will not hang in Red Hat Linux
+ * and improve the performance.
+ *
+ * can_queue: 1 --------------------> can_queue: 124
+ * sg_tablesize: SG_NONE -----------> sg_tablesize: 16
+ * cmd_per_lun: 128 ----------------> cmd_per_lun: 1
+ * use_clustering: ENABLE_CLUSTER --> use_clustering: DISABLE_CLUSTER
+ *
+ * 2003/04/25	root
+ * The code will hang on Gigabyte's motherboard when the sourth bridge is
+ * sis 962L and 963.
+ *
+ * Revision 1.35 2003/04/28	10:06:20 root
+ * Fixed: Do not enable interrupt again when send each command in
+ * IdeSendCommand() routine.
+ *
+ * 2003/05/20	root
+ * Linux SCSI error handling code should be changed to new one.
+ *
+ * The shortcomings of the existing code.
+ *
+ * 1. The old error handling code is an imperfect state machine. It
+ *    would occasionally get stuck in loops whereby the bus would be reset
+ *    over and over again, where the problem would never be resolved and
+ *    control of the machine would never return to the user.
+ *
+ * Reference the http://www.andante.org/scsi.html
+ *
+ * The kernel after 2.5 or 2.6 will not use the old error handling codes.
+ *
+ * In iteraid.h
+ *
+ * #define ITERAID					\
+ *	{						\
+ *	 proc_name: "it8212",				\
+ *	 proc_info: iteraid_proc_info,			\
+ *	 .						\
+ *	 .						\
+ *	 eh_about_handler: iteraid_about_eh,		\  --> New added
+ *	 eh_device_reset_handler: NULL			\  --> New added
+ *	 eh_bus_reset_handler: NULL			\  --> New added
+ *	 eh_host_reset_handler: iteraid_reset_eh	\  --> New added
+ *	 use_new_eh_code: 0 --> 1			\
+ *	}
+ *
+ * 2003/06/23	root	17:30:41
+ * TODO: Error code still use the old method.
+ *
+ * Revision 1.36 2003/06/23	19:52:31 root
+ * Fixed: Use the new error handling code.
+ *
+ * Revision 1.40 2003/07/25	10:00:00 root
+ * Released version 1.40 by Mark Lu.
+ *
+ * Revision 1.41 2003/08/06	13:55:17 root
+ * Added support for clean shutdown notification/feature table.
+ *
+ * Revision 1.42 2003/08/21	11:38:57 root
+ * Problem: When linux was installed onto IT8212 controller with two disks,
+ *	    configured as RAID 1 (P0S0), the hot swap will hang the system.
+ * Solve: Use the AtapiResetController() instead of only IT8212ResetAdapter().
+ *
+ * Revision 1.43 2003/12/24	23:19:07 root
+ * Fixed: Fixed a compile error at line 5815. Just move up the variable
+ *	  rebuild_info of type PRAID_REBUILD_INFO with other variables.
+ *
+ * Revision 1.44 2004/03/16	13:12:35 root
+ * Fixed: (1) The crash problem when using "rmmod" to remove the iteraid module.
+ *        (2) Support two IT8212 cards or chips.
+ *        (3) A bug when accessing the slave disk more than 137G.
+ *            Thanks for Martine Purschke kindly help to find this bug and
+ *            fix it.
+ *	  (4) can_queue: 12 --------------------> can_queue: 1
+ *	  (5) Change the Transparent(Bypass) mode initial PCI registers setting.
+ *	  (6) Change IDE I/O, control and dma base address from USHORT to ULONG,
+ *	      so that the non x86 platform, like MIPS, will load the correct
+ *	      address.
+ *	  (7) Add GPL license in iteraid.h.
+ *
+ * Revision 1.45 2004/05/07	11:07:16 root
+ * Fixed : (1) 64-bit support.
+ *         (2) In IT8212SetBestTransferMode() there are a number of arrays,
+ *             all of which are defined read/write and assigned on the stack.
+ *             Now put them in a R/O segment, by replacing e.g. "UCHAR
+ *             udmaTiming" with "static const UCHAR udmaTiming".
+ */
+
+#include <linux/module.h>
+MODULE_AUTHOR("ITE Tech,Inc.");
+MODULE_DESCRIPTION("ITE IT8212 RAID Controller Linux Driver");
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/string.h>
+#include <linux/smp.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+#include "iteraid.h"
+MODULE_LICENSE("GPL");
+
+#define MARK_DEBUG_DUMP_MEM	0	/* 1=Enable dump memory content */
+#define	MARK_DEBUG_BYPASS_MODE	0	/* 1=Enable use bypass mode     */
+#define MARK_DUMP_CREATE_INFO	0	/* 1=Dump raid create info      */
+#define MARK_SET_BEST_TRANSFER	0	/* 0=BIOS set best trans mode   */
+
+#define	PRD_BYTES		8	/* PRD table size               */
+#define PRD_ENTRIES		(PAGE_SIZE / (2 * PRD_BYTES))
+struct Scsi_Host *ite_vhost = 0;	/* SCSI virtual host            */
+Scsi_Cmnd *it8212_req_last = 0;	/* SRB request list             */
+unsigned int NumAdapters = 0;	/* Adapters number              */
+PITE_ADAPTER ite_adapters[2];	/* How many adapters support    */
+
+/************************************************************************
+ * Notifier blockto get a notify on system shutdown/halt/reboot.
+ ************************************************************************/
+static int ite_halt(struct notifier_block *nb, ulong event, void *buf);
+struct notifier_block ite_notifier = { ite_halt, NULL, 0
+};
+static struct semaphore mimd_entry_mtx;
+static spinlock_t queue_request_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t io_request_lock = SPIN_LOCK_UNLOCKED;
+
+static int iteraid_detect(Scsi_Host_Template *);
+static int iteraid_release(struct Scsi_Host *);
+#if 0
+static int iteraid_command(Scsi_Cmnd *);
+#endif
+static int iteraid_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int iteraid_biosparam(struct scsi_device *, struct block_device *,
+				sector_t, int *);
+static int iteraid_proc_info(struct Scsi_Host *, char *buffer, char **start,
+		      off_t offset, int length, int inout);
+
+static void TaskStart(PChannel, Scsi_Cmnd *);
+static void TaskQueue(void);
+static void TaskDone(PChannel, PSCSI_REQUEST_BLOCK);
+static u32 IdeSendCommand(PChannel, PSCSI_REQUEST_BLOCK);
+//static void IdeMediaStatus(u8, PChannel, u8);
+static void IdeSetupDma(PChannel, unsigned long, unsigned short);
+static void MapRequest(Scsi_Cmnd *, PSCSI_REQUEST_BLOCK);
+static u8 IssueIdentify(PChannel, u8, u8);
+static u8 IT8212ResetAdapter(PITE_ADAPTER);
+static void AtapiStartIo(PChannel, PSCSI_REQUEST_BLOCK);
+static u8 AtapiInterrupt(PChannel);
+static void AtapiResetController(PITE_ADAPTER pAdap, PChannel pChan);
+
+static int itedev_open(struct inode *, struct file *);
+static int itedev_ioctl_entry(struct inode *, struct file *, unsigned int,
+			      unsigned long);
+static int itedev_ioctl(struct inode *, struct file *, unsigned int,
+			unsigned long);
+static int itedev_close(struct inode *, struct file *);
+
+
+#define DRV_VER_8212 "1.45"
+static int driver_ver = 145;	/* Current driver version       */
+static int ite_major = 0;	/* itedev chardev major number  */
+
+/************************************************************************
+ * The File Operations structure for the ioctl interface of the driver.
+ ************************************************************************/
+static struct file_operations itedev_fops =
+    {.owner = THIS_MODULE,.ioctl = itedev_ioctl_entry,.open =
+itedev_open,.release = itedev_close
+};
+
+#if (MARK_DEBUG_DUMP_MEM)
+/************************************************************************
+ * Dump buffer.
+ ************************************************************************/
+static void HexDump(unsigned char *buf, int length)
+{
+	unsigned int i = 0;
+	unsigned int j = 0;
+
+	printk("\n");
+	for (i = 0; i < length; i += 16) {
+		printk("%04X    ", i);
+		for (j = i; (j < i + 8) && (j < length); j++)
+			printk(" %02X", buf[j]);
+		if (j == i + 8)
+			printk("-");
+		for (j = i + 8; (j < i + 16) && (j < length); j++)
+			printk("%02X ", buf[j]);
+		printk("\n");
+	}
+}				/* end HexDump */
+#endif
+
+/************************************************************************
+ * This routine maps ATAPI and IDE errors to specific SRB statuses.
+ ************************************************************************/
+static u8 MapError(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+	u8 errorByte;
+	u8 srbStatus;
+	u8 scsiStatus;
+
+	/*
+	 * Read the error register.
+	 */
+	errorByte = inb(pChan->io_ports[IDE_ERROR_OFFSET]);
+	printk("MapError: error register is %x\n", errorByte);
+
+	/*
+	 * If this is ATAPI error.
+	 */
+	if (pChan->DeviceFlags[Srb->TargetId & 1] & DFLAGS_ATAPI_DEVICE) {
+		switch (errorByte >> 4) {
+		case SCSI_SENSE_NO_SENSE:
+			printk("ATAPI: no sense information\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			break;
+		case SCSI_SENSE_RECOVERED_ERROR:
+			printk("ATAPI: recovered error\n");
+			scsiStatus = 0;
+			srbStatus = SRB_STATUS_SUCCESS;
+			break;
+		case SCSI_SENSE_NOT_READY:
+			printk("ATAPI: device not ready\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			break;
+		case SCSI_SENSE_MEDIUM_ERROR:
+			printk("ATAPI: media error\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			break;
+		case SCSI_SENSE_HARDWARE_ERROR:
+			printk("ATAPI: hardware error\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			break;
+		case SCSI_SENSE_ILLEGAL_REQUEST:
+			printk("ATAPI: illegal request\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			break;
+		case SCSI_SENSE_UNIT_ATTENTION:
+			printk("ATAPI: unit attention\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			break;
+		case SCSI_SENSE_DATA_PROTECT:
+			printk("ATAPI: data protect\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			break;
+		case SCSI_SENSE_BLANK_CHECK:
+			printk("ATAPI: blank check\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			break;
+		case SCSI_SENSE_ABORTED_COMMAND:
+			printk("ATAPI: command Aborted\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			break;
+		default:
+			printk("ATAPI: invalid sense information\n");
+			scsiStatus = 0;
+			srbStatus = SRB_STATUS_ERROR;
+			break;
+		}
+	} else {
+		/*
+		 * If this is IDE error.
+		 */
+		scsiStatus = 0;
+		srbStatus = SRB_STATUS_ERROR;
+
+		/*
+		 * Save errorByte, to be used by SCSIOP_REQUEST_SENSE.
+		 */
+		pChan->ReturningMediaStatus = errorByte;
+		if (errorByte & IDE_ERROR_MEDIA_CHANGE_REQ) {
+			printk("IDE: media change\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+		} else if (errorByte & IDE_ERROR_COMMAND_ABORTED) {
+			printk("IDE: command abort\n");
+			srbStatus = SRB_STATUS_ABORTED;
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			if (Srb->SenseInfoBuffer) {
+				PSENSE_DATA senseBuffer =
+				    (PSENSE_DATA) Srb->SenseInfoBuffer;
+				senseBuffer->ErrorCode = 0x70;
+				senseBuffer->Valid = 1;
+				senseBuffer->AdditionalSenseLength = 0xB;
+				senseBuffer->SenseKey =
+				    SCSI_SENSE_ABORTED_COMMAND;
+				senseBuffer->AdditionalSenseCode = 0;
+				senseBuffer->AdditionalSenseCodeQualifier = 0;
+				srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+			}
+
+			/*
+			 * pChan->ErrorCount++;
+			 */
+		} else if (errorByte & IDE_ERROR_END_OF_MEDIA) {
+			printk("IDE: end of media\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			if (!
+			    (pChan->
+			     DeviceFlags[Srb->
+					 TargetId & 1] &
+			     DFLAGS_MEDIA_STATUS_ENABLED)) {
+
+				/*
+				 * pChan->ErrorCount++;
+				 */
+			}
+		} else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH) {
+			printk("IDE: illegal length\n");
+			srbStatus = SRB_STATUS_INVALID_REQUEST;
+		} else if (errorByte & IDE_ERROR_BAD_BLOCK) {
+			printk("IDE: bad block\n");
+			srbStatus = SRB_STATUS_ERROR;
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			if (Srb->SenseInfoBuffer) {
+				PSENSE_DATA senseBuffer =
+				    (PSENSE_DATA) Srb->SenseInfoBuffer;
+				senseBuffer->ErrorCode = 0x70;
+				senseBuffer->Valid = 1;
+				senseBuffer->AdditionalSenseLength = 0xB;
+				senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR;
+				senseBuffer->AdditionalSenseCode = 0;
+				senseBuffer->AdditionalSenseCodeQualifier = 0;
+				srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+			}
+		} else if (errorByte & IDE_ERROR_ID_NOT_FOUND) {
+			printk("IDE: id not found\n");
+			srbStatus = SRB_STATUS_ERROR;
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			if (Srb->SenseInfoBuffer) {
+				PSENSE_DATA senseBuffer =
+				    (PSENSE_DATA) Srb->SenseInfoBuffer;
+				senseBuffer->ErrorCode = 0x70;
+				senseBuffer->Valid = 1;
+				senseBuffer->AdditionalSenseLength = 0xB;
+				senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR;
+				senseBuffer->AdditionalSenseCode = 0;
+				senseBuffer->AdditionalSenseCodeQualifier = 0;
+				srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+			}
+
+			/*
+			 * pChan->ErrorCount++;
+			 */
+		} else if (errorByte & IDE_ERROR_MEDIA_CHANGE) {
+			printk("IDE: media change\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			if (Srb->SenseInfoBuffer) {
+				PSENSE_DATA senseBuffer =
+				    (PSENSE_DATA) Srb->SenseInfoBuffer;
+				senseBuffer->ErrorCode = 0x70;
+				senseBuffer->Valid = 1;
+				senseBuffer->AdditionalSenseLength = 0xD;
+				senseBuffer->SenseKey =
+				    SCSI_SENSE_UNIT_ATTENTION;
+				senseBuffer->AdditionalSenseCode =
+				    SCSI_ADSENSE_MEDIUM_CHANGED;
+				senseBuffer->AdditionalSenseCodeQualifier = 0;
+				srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+			}
+		} else if (errorByte & IDE_ERROR_DATA_ERROR) {
+			printk("IDE: data error\n");
+			scsiStatus = SCSISTAT_CHECK_CONDITION;
+			srbStatus = SRB_STATUS_ERROR;
+			if (!
+			    (pChan->
+			     DeviceFlags[Srb->
+					 TargetId & 1] &
+			     DFLAGS_MEDIA_STATUS_ENABLED)) {
+
+				/*
+				 * pChan->ErrorCount++;
+				 */
+			}
+
+			/*
+			 * Build sense buffer.
+			 */
+			if (Srb->SenseInfoBuffer) {
+				PSENSE_DATA senseBuffer =
+				    (PSENSE_DATA) Srb->SenseInfoBuffer;
+				senseBuffer->ErrorCode = 0x70;
+				senseBuffer->Valid = 1;
+				senseBuffer->AdditionalSenseLength = 0xB;
+				senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR;
+				senseBuffer->AdditionalSenseCode = 0;
+				senseBuffer->AdditionalSenseCodeQualifier = 0;
+				srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+			}
+		}
+	}
+
+	/*
+	 * Set SCSI status to indicate a check condition.
+	 */
+	Srb->ScsiStatus = scsiStatus;
+	return srbStatus;
+}				/* end MapError */
+
+#if 0
+/************************************************************************
+ * Just get the higest bit value.
+ ************************************************************************/
+static u8 RaidGetHighestBit(u8 Number)
+{
+	char bit;
+
+	for (bit = 7; bit >= 0; bit--) {
+		if (Number & (1 << bit))
+			return bit;
+	}
+	return 0xFF;
+}				/* end RaidGetHighestBit */
+#endif
+
+/************************************************************************
+ * Reset IDE controller or ATAPI device.
+ ************************************************************************/
+static void AtapiResetController(PITE_ADAPTER pAdap, PChannel pChan)
+{
+	u8 resetResult;
+	u8 status;
+	u8 i;
+	unsigned long dma_base;
+	SCSI_REQUEST_BLOCK srb;
+
+	printk("AtapiResetController enter\n");
+	dma_base = pChan->dma_base;
+	resetResult = FALSE;
+
+	/*
+	 * Check and see if we are processing an internal srb.
+	 */
+	if (pChan->OriginalSrb) {
+		pChan->CurrentSrb = pChan->OriginalSrb;
+		pChan->OriginalSrb = NULL;
+	}
+
+	/*
+	 * To avoid unexpected interrupts occurs during reset procedure.
+	 *
+	 * 1. Stop bus master operation.
+	 */
+	outb(0, dma_base);
+	for (i = 0; i < 2; i++) {
+		outb((u8) ((i << 4) | 0xA0),
+		     pChan->io_ports[ATAPI_SELECT_OFFSET]);
+
+		/*
+		 * 2. Clear interrupts if there is any.
+		 */
+		GetBaseStatus(pChan, status);
+
+		/*
+		 * 3. Disable interrupts.
+		 */
+		outb(IDE_DC_DISABLE_INTERRUPTS,
+		     pChan->io_ports[ATAPI_CONTROL_OFFSET]);
+
+		/*
+		 * 4. Clear interrupts again.
+		 */
+		GetBaseStatus(pChan, status);
+	}
+
+	/*
+	 * Check if request is in progress.
+	 */
+	if (pChan->CurrentSrb) {
+
+		/*
+		 * Complete outstanding request with SRB_STATUS_BUS_RESET.
+		 */
+		srb.SrbStatus = SRB_STATUS_BUS_RESET;
+
+		/*
+		 * Clear request tracking fields.
+		 */
+		pChan->CurrentSrb = NULL;
+		pChan->WordsLeft = 0;
+		pChan->DataBuffer = NULL;
+
+		/*
+		 * Indicate ready for next request.
+		 */
+		TaskDone(pChan, &srb);
+	}
+
+	/*
+	 * Clear expecting interrupt flag.
+	 */
+	pChan->ExpectingInterrupt = FALSE;
+	pChan->RDP = FALSE;
+	resetResult = IT8212ResetAdapter(pAdap);
+
+	/*
+	 * Set transfer modes after resetting the adapter.
+	 */
+
+	/*
+	 * Reenable interrupts.
+	 */
+	for (i = 0; i < 4; i++) {
+		outb((u8) (((i & 1) << 4) | 0xA0),
+		     pChan->io_ports[ATAPI_SELECT_OFFSET]);
+		outb(IDE_DC_REENABLE_CONTROLLER,
+		     pChan->io_ports[ATAPI_CONTROL_OFFSET]);
+	}
+	printk("AtapiResetController exit\n");
+}				/* end AtapiResetController */
+
+/************************************************************************
+ * IDE start read/write transfer.
+ ************************************************************************/
+static void IdeStartTransfer(PChannel pChan, PSCSI_REQUEST_BLOCK Srb,
+			u32 startingSector, u32 SectorNumber)
+{
+	u8 DiskId;
+	u8 drvSelect;
+	u8 bmClearStat;
+	unsigned long dma_base;
+
+	dprintk("IdeStartTransfer enter\n");
+	DiskId = (u8) Srb->TargetId;
+	dma_base = pChan->dma_base;
+
+	/*
+	 * 48-bit support.
+	 */
+	if ((startingSector + SectorNumber) > 0x0FFFFFFF) {
+
+		/*
+		 * Select drive and set LBA mode.
+		 */
+		outb((u8) (((DiskId & 0x1) << 4) | 0xA0 | 0x40),
+		     pChan->io_ports[IDE_SELECT_OFFSET]);
+
+		/*
+		 * Sector count register.
+		 */
+		outb((u8) (SectorNumber >> 8),
+		     pChan->io_ports[IDE_NSECTOR_OFFSET]);
+		outb((u8) SectorNumber, pChan->io_ports[IDE_NSECTOR_OFFSET]);
+
+		/*
+		 * LBA low register.
+		 */
+		outb((u8) (startingSector >> 24),
+		     pChan->io_ports[IDE_LOCYL_OFFSET]);
+		outb((u8) startingSector, pChan->io_ports[IDE_LOCYL_OFFSET]);
+
+		/*
+		 * LBA mid register.
+		 */
+		outb((u8) 0, pChan->io_ports[IDE_MIDCYL_OFFSET]);
+		outb((u8) (startingSector >> 8),
+		     pChan->io_ports[IDE_MIDCYL_OFFSET]);
+
+		/*
+		 * LBA high register.
+		 */
+		outb((u8) 0, pChan->io_ports[IDE_HCYL_OFFSET]);
+		outb((u8) (startingSector >> 16),
+		     pChan->io_ports[IDE_HCYL_OFFSET]);
+
+		/*
+		 * Start the IDE read/write DMA command.
+		 */
+		if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+			outb(IDE_COMMAND_READ_DMA_EXT,
+			     pChan->io_ports[IDE_COMMAND_OFFSET]);
+		} else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+			outb(IDE_COMMAND_WRITE_DMA_EXT,
+			     pChan->io_ports[IDE_COMMAND_OFFSET]);
+		}
+	} else {
+		/*
+		 * 28-bit addressing.
+		 */
+
+		/*
+		 * Select drive and set LBA mode.
+		 */
+		drvSelect = (u8) (startingSector >> 24);
+		drvSelect = drvSelect | (((u8) DiskId & 0x1) << 4)|0x40|0xA0;
+		outb(drvSelect, pChan->io_ports[IDE_SELECT_OFFSET]);
+		outb((u8) SectorNumber, pChan->io_ports[IDE_NSECTOR_OFFSET]);
+		outb((u8) startingSector, pChan->io_ports[IDE_LOCYL_OFFSET]);
+		outb((u8) (startingSector >> 8),
+		     pChan->io_ports[IDE_MIDCYL_OFFSET]);
+		outb((u8) (startingSector >> 16),
+		     pChan->io_ports[IDE_HCYL_OFFSET]);
+
+		/*
+		 * Start the IDE read/write DMA command.
+		 */
+		if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+			outb(IDE_COMMAND_READ_DMA,
+			     pChan->io_ports[IDE_COMMAND_OFFSET]);
+		} else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+			outb(IDE_COMMAND_WRITE_DMA,
+			     pChan->io_ports[IDE_COMMAND_OFFSET]);
+		}
+	}
+
+	/*
+	 * Indicate expecting an interrupt.
+	 */
+	pChan->ExpectingInterrupt = TRUE;
+
+	/*
+	 * Setup PRD table physical address.
+	 */
+	outl(pChan->dmatable_dma, dma_base + 4);
+
+	/*
+	 * Read Bus Master status.
+	 */
+	bmClearStat = inb(dma_base + 2);
+	if (Srb->TargetId & 1) {
+		bmClearStat =
+		    bmClearStat | BM_DRV1_DMA_CAPABLE | BM_STAT_FLG_INT |
+		    BM_STAT_FLG_ERR;
+	} else {
+		bmClearStat =
+		    bmClearStat | BM_DRV0_DMA_CAPABLE | BM_STAT_FLG_INT |
+		    BM_STAT_FLG_ERR;
+	}
+	outb(0, dma_base);
+
+	/*
+	 * Clear INTR and ERROR flags.
+	 */
+	outb(bmClearStat, dma_base + 2);
+
+	/*
+	 * Start DMA read/write.
+	 */
+	if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+		outb(BM_CMD_FLG_START | BM_CMD_FLG_WRTTOMEM, dma_base);
+	else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
+		outb(BM_CMD_FLG_START | BM_CMD_FLG_WRTTODSK, dma_base);
+	dprintk("IdeStartTransfer exit\n");
+}				/* end IdeStartTransfer */
+
+/************************************************************************
+ * Setup the PRD table.
+ ************************************************************************/
+static int IdeBuildSglist(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+	int nents = 0;
+	u32 bytesRemaining = Srb->DataTransferLength;
+	unsigned char *virt_addr = Srb->DataBuffer;
+	struct scatterlist *sg = pChan->sg_table;
+
+	if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+		pChan->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		pChan->sg_dma_direction = PCI_DMA_TODEVICE;
+
+	/*
+	 * The upper layer will never give the memory more than 64K bytes.
+	 */
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].dma_address = (dma_addr_t) virt_addr;
+	sg[nents].length = bytesRemaining;
+	nents++;
+	return pci_map_sg(pChan->pPciDev, sg, nents, pChan->sg_dma_direction);
+}				/* end IdeBuildSglist */
+
+/************************************************************************
+ * Prepares a dma request.
+ ************************************************************************/
+static int IdeBuildDmaTable(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+	unsigned long *table = pChan->dmatable_cpu;
+	unsigned int count = 0;
+	int i;
+	struct scatterlist *sg;
+
+	i = IdeBuildSglist(pChan, Srb);
+	sg = pChan->sg_table;
+	while (i && sg_dma_len(sg)) {
+		u32 cur_len;
+		u32 cur_addr;
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		/*
+		 * Fill in the dma table, without crossing any 64kB boundaries.
+		 */
+		while (cur_len) {
+			if (count++ >= PRD_ENTRIES) {
+				printk(KERN_WARNING "@@DMA table too small\n");
+			} else {
+				u32 xcount, bcount =
+				    0x10000 - (cur_addr & 0xFFFF);
+				if (bcount > cur_len)
+					bcount = cur_len;
+				*table++ = cpu_to_le32(cur_addr);
+				xcount = bcount & 0xFFFF;
+				if (xcount == 0x0000) {
+					/*
+					 * Most chipsets correctly interpret a
+					 * length of 0x0000 as 64KB, but at
+					 * least one (e.g. CS5530) misinterprets
+					 * it as zero (!).  So here we break the
+					 * 64KB entry into two 32KB entries
+					 * instead.
+					 */
+					if (count++ >= PRD_ENTRIES)
+						printk(KERN_WARNING
+						     "##DMA table too small\n");
+					*table++ = cpu_to_le32(0x8000);
+					*table++ =
+						cpu_to_le32(cur_addr + 0x8000);
+					xcount = 0x8000;
+				}
+				*table++ = cpu_to_le32(xcount);
+				cur_addr += bcount;
+				cur_len -= bcount;
+			}
+		}
+		sg++;
+		i--;
+	}
+	if (count) {
+		*--table |= cpu_to_le32(0x80000000);
+		return count;
+	} else {
+		printk(KERN_WARNING "Empty DMA table?\n");
+	}
+	return count;
+}				/* end IdeBuildDmaTable */
+
+/************************************************************************
+ * Prepares a dma scatter/gather request.
+ ************************************************************************/
+static void IdeBuildDmaSgTable(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+	int use_sg = 0;
+	int i;
+	PPRD_TABLE_ENTRY pSG = (PPRD_TABLE_ENTRY) pChan->dmatable_cpu;
+	struct scatterlist *sg = (struct scatterlist *)Srb->DataBuffer;
+
+	if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+		pChan->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		pChan->sg_dma_direction = PCI_DMA_TODEVICE;
+
+	use_sg = pci_map_sg(pChan->pPciDev, Srb->DataBuffer, Srb->UseSg,
+				pChan->sg_dma_direction);
+	for (i = 0; i < use_sg; i++) {
+		pSG[i].PhysicalBaseAddress = sg_dma_address(&sg[i]);
+		pSG[i].ByteCount = sg_dma_len(&sg[i]);
+		pSG[i].EndOfTable = (i == use_sg - 1) ? SG_FLAG_EOT : 0;
+	}
+}				/* end IdeBuildDmaSgTable */
+
+/************************************************************************
+ * Setup DMA table for channel.
+ ************************************************************************/
+static void
+IdeSetupDma(PChannel pChan, unsigned long dma_base, unsigned short num_ports)
+{
+	printk("Channel[%d] BM-DMA at 0x%lX-0x%lX\n", pChan->channel,
+	       dma_base, dma_base + num_ports - 1);
+
+	/*
+	 * Allocate IDE DMA buffer.
+	 */
+	pChan->dmatable_cpu =
+	    pci_alloc_consistent(pChan->pPciDev, PRD_ENTRIES * PRD_BYTES,
+				 &pChan->dmatable_dma);
+	if (pChan->dmatable_cpu == NULL) {
+		printk("IdeSetupDma: allocate prd table failed.\n");
+		return;
+	}
+	memset(pChan->dmatable_cpu, 0, PRD_ENTRIES * PRD_BYTES);
+
+	/*
+	 * Allocate SCATTER/GATHER table buffer.
+	 */
+	pChan->sg_table =
+	    kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, GFP_KERNEL);
+	if (pChan->sg_table == NULL) {
+		printk("IdeSetupDma: allocate sg_table failed.\n");
+		pci_free_consistent(pChan->pPciDev, PRD_ENTRIES * PRD_BYTES,
+				    pChan->dmatable_cpu, pChan->dmatable_dma);
+		return;
+	}
+	return;
+}				/* end IdeSetupDma */
+
+/************************************************************************
+ * This will be only used in RAID mode.
+ ************************************************************************/
+void IT8212ReconfigChannel(PChannel pChan, u8 ArrayId, u8 Operation)
+{
+	u8 enableVirtualChannel;
+	struct pci_dev *pPciDev = pChan->pPciDev;
+
+	pci_read_config_byte(pPciDev, 0x43, &enableVirtualChannel);
+	if (Operation == DisableChannel) {
+		enableVirtualChannel &= ~(1 << ArrayId);
+		printk("IT8212ReconfigChannel: disable channel %X\n", ArrayId);
+	} else {
+		enableVirtualChannel |= ~(1 << ArrayId);
+		printk("IT8212ReconfigChannel: enable channel %X\n", ArrayId);
+	}
+	printk("IT8212ReconfigChannel: channel enabled after set 0x%X\n",
+	       enableVirtualChannel);
+
+	/*
+	 * Set enabled virtual channels.
+	 */
+	pci_write_config_byte(pPciDev, 0x43, enableVirtualChannel);
+}				/* end IT8212ReconfigChannel */
+
+/************************************************************************
+ * Get the chip status. This is a vendor specific command. According to
+ * all of the device configurations, the BIOS then can consider the
+ * existing RAID configuration reasonable. If the existing RAID configur-
+ * ation is not reasonable, or if there is NO existing RAID configuration
+ * , the BIOS can ask the user to setup the RAID configuration. Finally,
+ * the BIOS or AP should send the SET CHIP STATUS to every virtual device.
+ * Only after receiving SET CHIP STATUS command, the corresponding virtual
+ * device will be active.
+ ************************************************************************/
+u8 IT8212GetChipStatus(uioctl_t * ioc)
+{
+	u8 PriMasterIsNull = FALSE;
+	u8 statusByte;
+	u8 srbStatus;
+	PChannel pChan;
+	PITE_ADAPTER pAdap;
+	PHYSICAL_DISK_STATUS *pPhyDiskInfo;
+
+	dprintk("IT8212GetChipStatus enter\n");
+
+	/*
+	 * Only support one controller now! In the future, we can pass the
+	 * argument (user ioctl structure) to know which controller need to be
+	 * identified.
+	 */
+	pAdap = ite_adapters[0];
+	pChan = &pAdap->IDEChannel[0];
+
+	/*
+	 * Allocate space for PHYSICAL_DISK_STATUS.
+	 */
+	pPhyDiskInfo = kmalloc(sizeof(PHYSICAL_DISK_STATUS) * 4, GFP_KERNEL);
+	if (pPhyDiskInfo == NULL) {
+		printk("IT8212GetChipStatus: error kmalloc for "
+				"PHYSCIAL_DISK_STATUS.\n");
+		return -ENOMEM;
+	}
+	memset(pPhyDiskInfo, 0, sizeof(PHYSICAL_DISK_STATUS));
+
+	/*
+	 * Always send GET CHIP STATUS command to primary channel master device.
+	 * Select device.
+	 */
+	outb((u8) 0xA0, pChan->io_ports[IDE_SELECT_OFFSET]);
+
+	/*
+	 * If primary master channel is not enabled, enable it.
+	 */
+	statusByte = inb(pChan->io_ports[IDE_ALTERNATE_OFFSET]);
+	if (statusByte == 0) {
+		PriMasterIsNull = TRUE;
+		IT8212ReconfigChannel(pChan, 0, EnableChannel);
+	}
+
+	/*
+	 * Wait for device ready (Not BUSY and not DRQ)
+	 */
+	WaitForDeviceReady(pChan, statusByte);
+	if ((statusByte & IDE_STATUS_BUSY) || (statusByte & IDE_STATUS_DRQ)
+	    || (statusByte == 0)) {
+		printk("IT8212GetChipStatus: disk[0] not ready. status=0x%X\n",
+		       statusByte);
+		srbStatus = SRB_STATUS_BUSY;
+		goto exit;
+	}
+
+	/*
+	 * Disable interrupt to avoid the unexpected interrupt.
+	 */
+	outb(IDE_DC_DISABLE_INTERRUPTS, pChan->io_ports[IDE_CONTROL_OFFSET]);
+
+	/*
+	 * Issue the command.
+	 */
+	outb(IDE_COMMAND_GET_CHIP_STATUS, pChan->io_ports[IDE_COMMAND_OFFSET]);
+
+	/*
+	 * Wait for BUSY = 0, DRQ = 1.
+	 */
+	CheckBusyDrq(pChan, statusByte) if (statusByte != 0x58) {
+		printk("IT8212GetChipStatus: disk[0] return unexpected "
+				"status after");
+		printk("issue command. status=0x%X\n", statusByte);
+		goto exit_error;
+	}
+
+	/*
+	 * Read the physical disk info.
+	 */
+	ReadBuffer(pChan, (unsigned short *)pPhyDiskInfo, 256);
+
+#if (0)
+	HexDump((unsigned char *)pPhyDiskInfo, 512);
+
+#endif
+
+	/*
+	 * Copy physical disk info to user area.
+	 */
+	copy_to_user((unsigned short *)ioc->data,
+		     (unsigned char *)pPhyDiskInfo, 512);
+
+	/*
+	 * Check error.
+	 */
+	WaitForCommandComplete(pChan, statusByte);
+	if (statusByte != IDE_STATUS_IDLE) {
+		printk("IT8212GetChipStatus: disk[0] return unexpected "
+			"status after read data. status=0x%X\n", statusByte);
+		goto exit_error;
+	}
+	srbStatus = SRB_STATUS_SUCCESS;
+	goto exit;
+exit_error:
+	/*
+	 * If fail, hard reset to avoid the DRQ status pending.
+	 */
+	srbStatus = SRB_STATUS_ERROR;
+	IdeHardReset(pChan, statusByte);
+exit:
+	/*
+	 * Reenable interrupt after command complete.
+	 */
+	outb(IDE_DC_REENABLE_CONTROLLER, pChan->io_ports[IDE_CONTROL_OFFSET]);
+
+	/*
+	 * If primary master is null, disable primary master channel before we
+	 * leave.
+	 */
+	if (PriMasterIsNull)
+		IT8212ReconfigChannel(pChan, 0, DisableChannel);
+	dprintk("IT8212GetChipStatus exit\n");
+	return srbStatus;
+}				/* end IT8212GetChipStatus */
+
+/************************************************************************
+ * Erase the partition table.
+ ************************************************************************/
+unsigned char IT8212ErasePartition(uioctl_t * pioc)
+{
+	unsigned char drvSelect;
+	unsigned char statusByte = 0;
+	unsigned char srbStatus;
+	unsigned char *buffer;
+	PRAID_CREATE_INFO createInfo = (PRAID_CREATE_INFO) pioc->data;
+	PITE_ADAPTER pAdap;
+	PChannel pChan;
+
+	printk("IT8212ErasePartition enter\n");
+	printk("createInfo->DiskArrayId = %d\n", createInfo->DiskArrayId);
+	if (createInfo->ErasePartition == 0
+	    || (createInfo->RaidType == RAID_LEVEL_NODISK))
+		return SRB_STATUS_SUCCESS;
+	pAdap = ite_adapters[0];
+	if (createInfo->DiskArrayId < 2)
+		pChan = &pAdap->IDEChannel[0];
+	else
+		pChan = &pAdap->IDEChannel[1];
+
+	/*
+	 * Allocate 512 bytes for buffer.
+	 */
+	if ((buffer = kmalloc(512, GFP_KERNEL)) == NULL) {
+		printk("IT8212ErasePartition: error kmalloc.\n");
+		return -ENOMEM;
+	}
+	memset(buffer, 0, 512);
+
+	/*
+	 * Select device.
+	 */
+	drvSelect = (((u8) createInfo->DiskArrayId & 0x1) << 4) | 0xA0 | 0x40;
+	outb(drvSelect, pChan->io_ports[IDE_SELECT_OFFSET]);
+
+	/*
+	 * Wait for device ready (not BUSY and not DRQ).
+	 */
+	WaitForDeviceReady(pChan, statusByte);
+	if ((statusByte & IDE_STATUS_BUSY) || (statusByte & IDE_STATUS_DRQ)
+	    || (statusByte == 0)) {
+		printk
+		    ("IT8212ErasePartition: disk[%d] not ready. status=0x%X\n",
+		     createInfo->DiskArrayId, statusByte);
+		return SRB_STATUS_BUSY;
+	}
+
+	/*
+	 * Disable interrupt to avoid the unexpected interrupt.
+	 */
+	outb(IDE_DC_DISABLE_INTERRUPTS, pChan->io_ports[IDE_CONTROL_OFFSET]);
+
+	/*
+	 * Write LBA 0 (1 sector).
+	 */
+	outb(1, pChan->io_ports[IDE_NSECTOR_OFFSET]);
+	outb(0, pChan->io_ports[IDE_LOCYL_OFFSET]);
+	outb(0, pChan->io_ports[IDE_MIDCYL_OFFSET]);
+	outb(0, pChan->io_ports[IDE_HCYL_OFFSET]);
+	outb(drvSelect, pChan->io_ports[IDE_SELECT_OFFSET]);
+	outb(IDE_COMMAND_WRITE_SECTOR, pChan->io_ports[IDE_COMMAND_OFFSET]);
+
+	/*
+	 * Wait for BUSY = 0, DRQ = 1.
+	 */
+	CheckBusyDrq(pChan, statusByte);
+	if (statusByte != 0x58) {
+		printk("IT8212ErasePartition: disk[%d] error status. "
+			"status=0x%X\n", createInfo->DiskArrayId, statusByte);
+		goto exit_error;
+	}
+
+	/*
+	 * Start erase partition table.
+	 */
+	WriteBuffer(pChan, (unsigned short *)buffer, 256);
+
+	/*
+	 * Check error.
+	 */
+	WaitForCommandComplete(pChan, statusByte);
+	if (statusByte != IDE_STATUS_IDLE) {
+		printk("IT8212ErasePartition: disk[%d] error status. "
+			"status=0x%X\n", createInfo->DiskArrayId, statusByte);
+		goto exit_error;
+	}
+	srbStatus = SRB_STATUS_SUCCESS;
+	goto exit;
+exit_error:
+	/*
+	 * If failed, hard reset to avoid the DRQ status pending.
+	 */
+	IdeHardReset(pChan, statusByte);
+	srbStatus = SRB_STATUS_ERROR;
+exit:
+	/*
+	 * Reenable interrupt after command complete.
+	 */
+	outb(IDE_DC_REENABLE_CONTROLLER, pChan->io_ports[IDE_CONTROL_OFFSET]);
+	printk("IT8212ErasePartition exit\n");
+	return srbStatus;
+}				/* end IT8212ErasePartition */
+
+/************************************************************************
+ *
+ ************************************************************************/
+static u32 IT8212TruncateReduentSectors(u32 OriginalSectorCount,
+				u16 StripeSizeInKBytes)
+{
+	u16 stripeSizeInSector;
+
+	/*
+	 * 0 means using default value (32 sectors).
+	 */
+	if (StripeSizeInKBytes == 0)
+		stripeSizeInSector = 64 * 2;
+	else
+		stripeSizeInSector = StripeSizeInKBytes * 2;
+	return ((OriginalSectorCount / stripeSizeInSector) *
+		stripeSizeInSector);
+}				/* end IT8212TruncateReduentSectors */
+
+/************************************************************************
+ * Calculate the addressable sector for this RAID.
+ ************************************************************************/
+static u32 IT8212DiskArrayAddressableSector(unsigned char *DiskArrayCreateInfo)
+{
+	u8 DiskNo;
+	u8 NumOfDisks;
+	u32 MinDiskCapacity;
+	u32 ArrayCapacity;
+	PRAID_CREATE_INFO createInfo = (PRAID_CREATE_INFO) DiskArrayCreateInfo;
+
+	MinDiskCapacity = ArrayCapacity = NumOfDisks = 0;
+	printk("createInfo->AddressableSectors[0] = 0x%X\n",
+	       createInfo->AddressableSectors[0]);
+	printk("createInfo->AddressableSectors[1] = 0x%X\n",
+	       createInfo->AddressableSectors[1]);
+	printk("createInfo->AddressableSectors[2] = 0x%X\n",
+	       createInfo->AddressableSectors[2]);
+	printk("createInfo->AddressableSectors[3] = 0x%X\n",
+	       createInfo->AddressableSectors[3]);
+	for (DiskNo = 0; DiskNo < 4; DiskNo++) {
+
+		/*
+		 * If disk exist.
+		 */
+		if ((createInfo->ContainingDisks >> DiskNo) & 0x1) {
+			NumOfDisks += 1;
+			if (!MinDiskCapacity
+			    || (createInfo->AddressableSectors[DiskNo] <
+				MinDiskCapacity)) {
+				MinDiskCapacity =
+				    createInfo->AddressableSectors[DiskNo];
+			}
+		}
+	}
+	switch (createInfo->RaidType) {
+
+		/*
+		 * Containing 2 or 3 or 4 disks.
+		 */
+	case RAID_LEVEL_0:
+		MinDiskCapacity =
+		    IT8212TruncateReduentSectors(MinDiskCapacity - 2,
+						 createInfo->StripeSize);
+		ArrayCapacity = MinDiskCapacity * NumOfDisks;
+		break;
+
+		/*
+		 * Containing 2 disks.
+		 */
+	case RAID_LEVEL_1:
+		ArrayCapacity = MinDiskCapacity - 2;
+		break;
+
+		/*
+		 * Containing 4 disks.
+		 */
+	case RAID_LEVEL_10:
+		MinDiskCapacity =
+		    IT8212TruncateReduentSectors(MinDiskCapacity - 2,
+						 createInfo->StripeSize);
+		ArrayCapacity = MinDiskCapacity * 2;
+		break;
+
+		/*
+		 * Containing 2, 3, or 4 disks.
+		 */
+	case RAID_LEVEL_JBOD:
+		for (DiskNo = 0; DiskNo < 4; DiskNo++) {
+			if ((createInfo->ContainingDisks >> DiskNo) & 0x1) {
+				ArrayCapacity =
+				    ArrayCapacity +
+				    (createInfo->AddressableSectors[DiskNo] -
+				     2);
+			}
+		}
+		break;
+
+		/*
+		 * Containing only 1 disk.
+		 */
+	case RAID_LEVEL_NORMAL:
+		ArrayCapacity = MinDiskCapacity;
+		break;
+	}
+	return ArrayCapacity;
+}				/* end IT8212DiskArrayAddressableSector */
+
+/************************************************************************
+ * Create a new array.
+ ************************************************************************/
+static u8 IT8212CreateDiskArray(uioctl_t * pioc)
+{
+	u8 i;
+	u8 subCommand = 0xFF;
+	u8 statusByte;
+	u8 dmaSupported;
+	u8 udmaSupported;
+	u8 srbStatus;
+	u8 PriMasterIsNull = FALSE;
+	u32 UserAddressableSectors;
+	void *buffer;
+	PChannel pChan;
+	PITE_ADAPTER pAdap;
+	PRAID_CREATE_INFO createInfo = (PRAID_CREATE_INFO) pioc->data;
+	PIDENTIFY_DATA2 identifyData;
+	PIT8212_SET_CHIP_STATUS_INFO setChipStatus;
+	static const u16 IT8212TimingTable[7] = { 0x3133,	/* UDMA timimg register 01              */
+		0x2121,		/* UDMA timimg register 23              */
+		0x9111,		/* UDMA timimg register 45              */
+		0x0091,		/* UDMA timimg register 6               */
+		0x3266,		/* DMA  timimg register 01              */
+		0x0021,		/* DMA  timimg register 2               */
+		0x0021		/* PIO  timimg register                 */
+	};
+	static const u16 IT8212ClockTable[7] = { 0x0505,	/* UDMA clock register 01               */
+		0x0005,		/* UDMA clock register 23               */
+		0x0500,		/* UDMA clock register 45               */
+		0x0000,		/* UDMA clock register 6                */
+		0x0005,		/* DMA  clock register 01               */
+		0x0005,		/* DMA  clock register 2                */
+		0x0005		/* PIO  clock register                  */
+	};
+
+	printk("IT8212CreateDiskArray enter\n");
+
+#if (MARK_DUMP_CREATE_INFO)
+	printk("createInfo->DiskArrayId           = %d\n",
+	       createInfo->DiskArrayId);
+	printk("createInfo->ModelNumber           = %s\n",
+	       createInfo->ModelNumber);
+	printk("createInfo->RaidType              = %d\n",
+	       createInfo->RaidType);
+	printk("createInfo->ContainingDisks       = %d\n",
+	       createInfo->ContainingDisks);
+	printk("createInfo->AutoRebuildEnable     = %d\n",
+	       createInfo->AutoRebuildEnable);
+	printk("createInfo->StripeSize            = %d\n",
+	       createInfo->StripeSize);
+	printk("createInfo->BootableDisk          = %d\n",
+	       createInfo->BootableDisk);
+	printk("createInfo->NewlyCreated          = %d\n",
+	       createInfo->NewlyCreated);
+	printk("createInfo->ErasePartition        = %d\n",
+	       createInfo->ErasePartition);
+	printk("createInfo->DMASupported[0]       = 0x%x\n",
+	       createInfo->DMASupported[0]);
+	printk("createInfo->DMASupported[1]       = 0x%x\n",
+	       createInfo->DMASupported[1]);
+	printk("createInfo->DMASupported[2]       = 0x%x\n",
+	       createInfo->DMASupported[2]);
+	printk("createInfo->DMASupported[3]       = 0x%x\n",
+	       createInfo->DMASupported[3]);
+	printk("createInfo->UDMASupported[0]      = 0x%x\n",
+	       createInfo->UDMASupported[0]);
+	printk("createInfo->UDMASupported[1]      = 0x%x\n",
+	       createInfo->UDMASupported[1]);
+	printk("createInfo->UDMASupported[2]      = 0x%x\n",
+	       createInfo->UDMASupported[2]);
+	printk("createInfo->UDMASupported[3]      = 0x%x\n",
+	       createInfo->UDMASupported[3]);
+	printk("createInfo->AddressableSectors[0] = 0x%lX\n",
+	       createInfo->AddressableSectors[0]);
+	printk("createInfo->AddressableSectors[1] = 0x%lX\n",
+	       createInfo->AddressableSectors[1]);
+	printk("createInfo->AddressableSectors[2] = 0x%lX\n",
+	       createInfo->AddressableSectors[2]);
+	printk("createInfo->AddressableSectors[3] = 0x%lX\n",
+	       createInfo->AddressableSectors[3]);
+
+#endif				/*  */
+	switch (createInfo->RaidType) {
+	case RAID_LEVEL_0:
+	case RAID_LEVEL_1:
+	case RAID_LEVEL_10:
+	case RAID_LEVEL_JBOD:
+	case RAID_LEVEL_NORMAL:
+		subCommand = 0x50;
+		break;
+	case RAID_LEVEL_NODISK:
+		subCommand = 0x48;
+		break;
+	}
+
+	/*
+	 * The command should be sent to virtual primary master.
+	 */
+	pAdap = ite_adapters[0];
+	pChan = &pAdap->IDEChannel[0];
+
+	/*
+	 * Allocate 512-bytes buffer.
+	 */
+	if ((buffer = kmalloc(512, GFP_KERNEL)) == NULL) {
+		printk("IT8212CreateDiskArray: error kmalloc.\n");
+		return -ENOMEM;
+	}
+	identifyData = (PIDENTIFY_DATA2) buffer;
+
+	/*
+	 * 2003/05/08
+	 * Remember the vendor specific parameters starts from word 129 not 128.
+	 */
+	setChipStatus = (PIT8212_SET_CHIP_STATUS_INFO) (buffer + 258);
+
+	/*
+	 * Configure to RAID or NORMAL.
+	 */
+	if (subCommand == 0x50) {
+
+		/*
+		 * Zero identify data structure.
+		 */
+		memset((unsigned char *)identifyData, 0, sizeof(IDENTIFY_DATA));
+
+		/*
+		 * Fill up identify data.
+		 */
+		memmove(identifyData->ModelNumber, createInfo->ModelNumber, 40);
+		memmove(identifyData->SerialNumber, &createInfo->SerialNumber,
+			sizeof(RAID_SERIAL_NUMBER));
+
+		/*
+		 * Set disk array virtual capacity.
+		 */
+		UserAddressableSectors =
+		    IT8212DiskArrayAddressableSector(pioc->data);
+		printk("IT8212CreateDiskArray: array capacity = %X\n",
+		       UserAddressableSectors);
+		identifyData->Capacity_48bit_LOW = UserAddressableSectors;
+		identifyData->Capacity_48bit_HIGH = 0;
+		if (UserAddressableSectors > 0x0FFFFFFF)
+			identifyData->UserAddressableSectors = 0x0FFFFFFF;
+		else
+			identifyData->UserAddressableSectors =
+					UserAddressableSectors;
+
+		/*
+		 * Get DMA supported mode and UDMA supported mode.
+		 */
+		dmaSupported = udmaSupported = 0xFF;
+		for (i = 0; i < 4; i++) {
+			if ((createInfo->ContainingDisks >> i) & 1) {
+				dmaSupported &=
+				    (u8) createInfo->DMASupported[i];
+				udmaSupported &=
+				    (u8) createInfo->UDMASupported[i];
+			}
+		}
+		identifyData->MultiWordDMASupport = dmaSupported;
+		identifyData->UltraDMASupport = udmaSupported;
+
+		/*
+		 * Fill up SET CHIP STATUS data (word 129 - 153)
+		 */
+		setChipStatus->RaidType = createInfo->RaidType;
+		setChipStatus->ContainingDisks = createInfo->ContainingDisks;
+		setChipStatus->UltraDmaTiming01 = IT8212TimingTable[0];
+		setChipStatus->UltraDmaTiming23 = IT8212TimingTable[1];
+		setChipStatus->UltraDmaTiming45 = IT8212TimingTable[2];
+		setChipStatus->UltraDmaTiming6 = IT8212TimingTable[3];
+		setChipStatus->MultiWordDmaTiming01 = IT8212TimingTable[4];
+		setChipStatus->UltraDmaTiming2 = IT8212TimingTable[5];
+		setChipStatus->PioTiming4 = IT8212TimingTable[6];
+		setChipStatus->AutoRebuildEnable =
+		    createInfo->AutoRebuildEnable;
+		setChipStatus->IdeClkUDma01 = IT8212ClockTable[0];
+		setChipStatus->IdeClkUDma23 = IT8212ClockTable[1];
+		setChipStatus->IdeClkUDma45 = IT8212ClockTable[2];
+		setChipStatus->IdeClkUDma6 = IT8212ClockTable[3];
+		setChipStatus->IdeClkMDma01 = IT8212ClockTable[4];
+		setChipStatus->IdeClkMDma2 = IT8212ClockTable[5];
+		setChipStatus->IdeClkPio4 = IT8212ClockTable[6];
+		setChipStatus->StripeSize = createInfo->StripeSize;
+		setChipStatus->BootableDisk = createInfo->BootableDisk;
+		setChipStatus->CheckHotSwapInterval = 0;
+		setChipStatus->TargetSourceDisk = createInfo->TargetSourceDisk;
+		setChipStatus->RebuildBlockSize = 0;
+		setChipStatus->ResetInterval1 = 0;
+		setChipStatus->ResetInterval2 = 0;
+		setChipStatus->RebuildRetryTimes = 0;
+		setChipStatus->NewlyCreated = createInfo->NewlyCreated;
+	}
+#if (MARK_DEBUG_DUMP_MEM)
+	HexDump(buffer, 512);
+
+#endif
+
+	/*
+	 * There are some contrains of disk placement. AP will take care of it.
+	 */
+
+	/*
+	 * Select device.
+	 */
+	outb((u8) 0xA0, pChan->io_ports[IDE_SELECT_OFFSET]);
+
+	/*
+	 * If primary master channel is not enabled, enable it.
+	 */
+	statusByte = inb(pChan->io_ports[IDE_CONTROL_OFFSET]);
+	if (statusByte == 0) {
+		PriMasterIsNull = TRUE;
+		IT8212ReconfigChannel(pChan, 0, EnableChannel);
+	}
+
+	/*
+	 * Wait for device ready (not BUSY and not DRQ)
+	 */
+	WaitForDeviceReady(pChan, statusByte);
+	if ((statusByte & IDE_STATUS_BUSY) || (statusByte & IDE_STATUS_DRQ)
+	    || (statusByte == 0)) {
+		printk
+		    ("IT8212CreateDiskArray: disk[0] not ready. status=0x%X\n",
+		     statusByte);
+		srbStatus = SRB_STATUS_BUSY;
+		goto exit;
+	}
+
+	/*
+	 * Disable interrupt to avoid the unexpected interrupt.
+	 */
+	outb(IDE_DC_DISABLE_INTERRUPTS, pChan->io_ports[IDE_CONTROL_OFFSET]);
+	outb(subCommand, pChan->io_ports[IDE_FEATURE_OFFSET]);
+	outb(createInfo->DiskArrayId, pChan->io_ports[IDE_SELECT_OFFSET]);
+	outb(IDE_COMMAND_SET_CHIP_STATUS, pChan->io_ports[IDE_COMMAND_OFFSET]);
+
+	/*
+	 * No disk (no data command protocol)
+	 */
+	if (subCommand == 0x48) {
+		WaitForCommandComplete(pChan, statusByte);
+		if (statusByte != IDE_STATUS_IDLE) {
+			printk("IT8212CreateDiskArray: disk[0] return "
+				"unexpected status after issue command.\n");
+			goto exit_error;
+		}
+		IT8212ReconfigChannel(pChan, createInfo->DiskArrayId,
+				      DisableChannel);
+		srbStatus = SRB_STATUS_SUCCESS;
+		goto exit;
+	}
+
+	/*
+	 * Create RAID (PIO data out command protocol).
+	 */
+	if (subCommand == 0x50) {
+
+		/*
+		 * Wait for BUSY=0, DRQ=1.
+		 */
+		CheckBusyDrq(pChan, statusByte);
+		if (statusByte != 0x58) {
+			printk("IT8212CreateDiskArray: disk[0] return "
+				"unexpected status after issue command.\n");
+			goto exit_error;
+		}
+		WriteBuffer(pChan, buffer, 256);
+
+		/*
+		 * Check error.
+		 */
+		WaitForCommandComplete(pChan, statusByte);
+		if (statusByte != IDE_STATUS_IDLE) {
+			printk("IT8212CreateDiskArray: disk[0] return "
+				"unexpected status after issue command.\n");
+			goto exit_error;
+		}
+		IT8212ReconfigChannel(pChan, createInfo->DiskArrayId,
+				      EnableChannel);
+		srbStatus = SRB_STATUS_SUCCESS;
+		goto exit;
+	}
+exit_error:
+	/*
+	 * If fail, hard reset to avoid the DRQ pending.
+	 */
+	IdeHardReset(pChan, statusByte);
+	srbStatus = SRB_STATUS_ERROR;
+exit:
+	/*
+	 * If primary master is null, and we are not configuring array 0.
+	 * Disable primary master channel again.
+	 */
+	if (PriMasterIsNull && createInfo->DiskArrayId)
+		IT8212ReconfigChannel(pChan, 0, DisableChannel);
+
+	/*
+	 * Reenable interrupt after command complete.
+	 */
+	outb(IDE_DC_REENABLE_CONTROLLER, pChan->io_ports[IDE_CONTROL_OFFSET]);
+	printk("IT8212CreateDiskArray exit\n");
+	return srbStatus;
+}				/* end IT8212CreateDiskArray */
+
+#if 0
+/************************************************************************
+ * Return "virtual" drive 512 bytes identification data.
+ ************************************************************************/
+static u8 IT8212IssueIdentify(uioctl_t *pioc)
+{
+	u8 channum;
+	u8 devnum;
+	u8 statusByte;
+	u8 srbStatus;
+	PITE_ADAPTER pAdap;
+	PChannel pChan;
+
+	/*
+	 * Only support one adapter now! In the future, we can pass the argument
+	 * to know which adapter need to be identified.
+	 */
+	pAdap = ite_adapters[0];
+	memset(pioc->data, 0, 512 * 4);
+
+	/*
+	 * Two channels per controller.
+	 */
+	for (channum = 0; channum < pAdap->num_channels; channum++) {
+		pChan = &pAdap->IDEChannel[channum];
+
+		/*
+		 * Two devices per channel.
+		 */
+		for (devnum = 0; devnum < 2; devnum++) {
+
+			/*
+			 * Select device.
+			 */
+			outb((u8) ((devnum << 4) | 0xA0),
+			     pChan->io_ports[IDE_SELECT_OFFSET]);
+
+			/*
+			 * Check if disk online?
+			 */
+			statusByte = inb(pChan->io_ports[IDE_ALTERNATE_OFFSET]);
+			if ((statusByte & 0x40) != 0x40) {
+				printk("IT8212IssueIdentify: disk[%d] is "
+					"offline\n", devnum + channum * 2);
+				continue;
+			}
+
+			/*
+			 * Wait for device ready (Not busy and not DRQ)
+			 */
+			WaitForDeviceReady(pChan, statusByte);
+			if ((statusByte & IDE_STATUS_BUSY)
+			    || (statusByte & IDE_STATUS_DRQ)
+			    || (statusByte == 0)) {
+				printk("IT8212IssueIdentify: disk[%d] not "
+					"ready. status=0x%X\n",
+					devnum + channum * 2, statusByte);
+				srbStatus = SRB_STATUS_BUSY;
+				goto exit;
+			}
+
+			/*
+			 * Disable interrupt to avoid the unexpected interrupt.
+			 */
+			outb(IDE_DC_DISABLE_INTERRUPTS,
+			     pChan->io_ports[IDE_CONTROL_OFFSET]);
+
+			/*
+			 * Issue command.
+			 */
+			outb(IDE_COMMAND_IDENTIFY,
+			     pChan->io_ports[IDE_COMMAND_OFFSET]);
+
+			/*
+			 * Wait for BUSY = 0 and DRQ = 1.
+			 */
+			CheckBusyDrq(pChan, statusByte);
+			if (statusByte != 0x58) {
+				printk("IT8212IssueIndetify: disk[%d] returns "
+					"unexpedted status after issue command."
+					" status=0x%X\n",
+					devnum + channum * 2, statusByte);
+				goto error;
+			}
+
+			/*
+			 * Read the identify data.
+			 */
+			ReadBuffer(pChan,
+				   (unsigned short *)&pChan->
+				   FullIdentifyData, 256);
+
+			/*
+			 * Then copy to user area.
+			 */
+			copy_to_user((unsigned short *)(pioc->data +
+							((devnum +
+							  channum * 2) *
+							 512)),
+				     (unsigned short *)&pChan->
+				     FullIdentifyData, 256);
+
+			/*
+			 * Check error after reading data.
+			 */
+			WaitForCommandComplete(pChan, statusByte);
+			if (statusByte != IDE_STATUS_IDLE) {
+				printk("IT8212IssueIdentify: disk[%d] returns "
+					"unexpected status after read data. "
+					"status=0x%X\n",
+					devnum + channum * 2, statusByte);
+				goto error;
+			}
+		}		/* end for each device */
+	}			/* end for each channel */
+	srbStatus = SRB_STATUS_SUCCESS;
+	goto exit;
+error:
+	/*
+	 * If failed, hard reset to avoid the IRQ pending.
+	 */
+	IdeHardReset(pChan, statusByte);
+	srbStatus = SRB_STATUS_ERROR;
+exit:
+	/*
+	 * Reenable interrupt after command complete.
+	 */
+	for (channum = 0; channum < pAdap->num_channels; channum++) {
+		pChan = &pAdap->IDEChannel[channum];
+		outb(IDE_DC_REENABLE_CONTROLLER,
+		     pChan->io_ports[IDE_CONTROL_OFFSET]);
+	}
+	return srbStatus;
+}				/* end IT8212IssueIdentify */
+#endif
+
+/************************************************************************
+ * Reset the controller.
+ ************************************************************************/
+static u8 IT8212ResetAdapter(PITE_ADAPTER pAdap)
+{
+	u8 resetChannel[2];
+	u8 channel;
+	u8 device;
+	u8 status[4];
+	int i;
+	PChannel pChan;
+
+	/*
+	 * First, perform ATAPI soft reset if ATAPI devices are attached.
+	 */
+	for (channel = 0; channel < 2; channel++) {
+		pChan = &pAdap->IDEChannel[channel];
+		resetChannel[channel] = FALSE;
+		for (device = 0; device < 2; device++) {
+			if (pChan->DeviceFlags[device] & DFLAGS_DEVICE_PRESENT) {
+				if (pChan->
+				    DeviceFlags[device] & DFLAGS_ATAPI_DEVICE) {
+					printk("IT8212ResetAdapter: perform "
+						"ATAPI soft reset (%d, %d)\n",
+						channel, device);
+					AtapiSoftReset(pChan, device);
+				} else {
+					resetChannel[channel] = TRUE;
+				}
+			}
+		}
+	}
+
+	/*
+	 * If ATA device is present on this channel, perform channel reset.
+	 */
+	for (channel = 0; channel < 2; channel++) {
+		pChan = &pAdap->IDEChannel[channel];
+		if (resetChannel[channel]) {
+			printk("IT8212ResetAdapter: reset channel %d\n",
+			       channel);
+			outb(IDE_DC_RESET_CONTROLLER,
+			     pChan->io_ports[IDE_CONTROL_OFFSET]);
+			mdelay(50);
+			outb(IDE_DC_REENABLE_CONTROLLER,
+			     pChan->io_ports[IDE_CONTROL_OFFSET]);
+		}
+	}
+
+	/*
+	 * Check device status after reset.
+	 */
+	for (i = 0; i < 1000 * 1000; i++) {
+		for (channel = 0; channel < 2; channel++) {
+			pChan = &pAdap->IDEChannel[channel];
+			for (device = 0; device < 2; device++) {
+				if (pChan->
+				    DeviceFlags[device] &
+				    DFLAGS_DEVICE_PRESENT) {
+					outb((u8) ((device << 4) | 0xA0),
+					     pChan->
+					     io_ports[IDE_SELECT_OFFSET]);
+					status[(channel * 2) + device] =
+					    inb(pChan->
+						io_ports[IDE_COMMAND_OFFSET]);
+				} else {
+					status[(channel * 2) + device] = 0;
+				}
+			}
+		}
+
+		/*
+		 * ATA device should present status 0x50 after reset.
+		 * ATAPI device should present status 0 after reset.
+		 */
+		if ((status[0] != IDE_STATUS_IDLE && status[0] != 0x0) ||
+		    (status[1] != IDE_STATUS_IDLE && status[1] != 0x0) ||
+		    (status[2] != IDE_STATUS_IDLE && status[2] != 0x0) ||
+		    (status[3] != IDE_STATUS_IDLE && status[3] != 0x0)) {
+			udelay(30);
+		} else {
+			break;
+		}
+	}
+	if (i == 1000 * 1000) {
+		printk("IT8212ResetAdapter Fail!\n");
+		printk("Device status after reset = [0x%x, 0x%x, 0x%x, 0x%x]\n",
+		     status[0], status[1], status[2], status[3]);
+		return FALSE;
+	} else {
+		printk("IT8212ResetAdapter Success!\n");
+		return TRUE;
+	}
+}				/* end IT8212ResetAdapter */
+
+/************************************************************************
+ * Rebuild disk array.
+ ************************************************************************/
+u8 IT8212Rebuild(uioctl_t * pioc)
+{
+	u8 rebuildDirection;
+	u8 statusByte = 0;
+	PRAID_REBUILD_INFO apRebuildInfo = (PRAID_REBUILD_INFO) pioc->data;
+	PITE_ADAPTER pAdap;
+	PChannel pChan;
+
+	dprintk("IT8212Rebuild enter\n");
+	rebuildDirection =
+	    (apRebuildInfo->Resume << 4) | (apRebuildInfo->
+					    DestDisk << 2) | apRebuildInfo->
+	    SrcDisk;
+	apRebuildInfo->Status = 0xFF;
+	pAdap = ite_adapters[0];
+	printk("IT8212Rebuild: diskArrayId=%d\n", apRebuildInfo->DiskArrayId);
+	if (apRebuildInfo->DiskArrayId < 2)
+		pChan = &pAdap->IDEChannel[0];
+	else
+		pChan = &pAdap->IDEChannel[1];
+
+	/*
+	 * Selcet device.
+	 */
+	outb((u8) ((apRebuildInfo->DiskArrayId & 0x1) << 4 | 0xA0),
+	     pChan->io_ports[IDE_SELECT_OFFSET]);
+
+	/*
+	 * Wait for device ready (not BUSY and not DRQ).
+	 */
+	WaitForDeviceReady(pChan, statusByte);
+	if ((statusByte & IDE_STATUS_BUSY) || (statusByte & IDE_STATUS_DRQ)
+	    || (statusByte == 0)) {
+		apRebuildInfo->Status = REBUILD_ERR_DISK_BUSY;
+		printk("IT8212Rebuild: disk[%d] not ready. status=0x%X\n",
+		       apRebuildInfo->DiskArrayId, statusByte);
+		return SRB_STATUS_BUSY;
+	}
+
+	/*
+	 * Disable interrupt to avoid the unexpected interrupt.
+	 */
+	outb(IDE_DC_DISABLE_INTERRUPTS, pChan->io_ports[IDE_CONTROL_OFFSET]);
+
+	/*
+	 * Give a direction.
+	 */
+	outb(rebuildDirection, pChan->io_ports[IDE_FEATURE_OFFSET]);
+
+	/*
+	 * Issue a REBUILD commmand.
+	 */
+	outb(IDE_COMMAND_REBUILD, pChan->io_ports[IDE_COMMAND_OFFSET]);
+
+	/*
+	 * Check for errors.
+	 */
+	WaitForCommandComplete(pChan, statusByte);
+
+	/*
+	 * Reenable interrupt after command complete.
+	 */
+	outb(IDE_DC_REENABLE_CONTROLLER, pChan->io_ports[IDE_CONTROL_OFFSET]);
+	if (statusByte != IDE_STATUS_IDLE) {
+		if (statusByte & IDE_STATUS_ERROR) {
+			apRebuildInfo->Status =
+			    inb(pChan->io_ports[IDE_NSECTOR_OFFSET]);
+			printk("IT8212Rebuild: rebuild error. reason=0x%X\n",
+			       apRebuildInfo->Status);
+		}
+		return apRebuildInfo->Status;
+	}
+	dprintk("IT8212Rebuild exit\n");
+	return SRB_STATUS_PENDING;
+}				/* end IT8212Rebuild */
+
+/************************************************************************
+ * Switch to DMA mode if necessary.
+ *
+ * offset 0x50 = PCI Mode Control Register
+ *
+ * Bit 0 = PCI Mode Select (1=firmware mode, 0=transparent mode)
+ * Bit 1 = Primary Channel IDE Clock Frequency Select (1=50, 0=66)
+ * Bit 2 = Secondary Channel IDE Clock Freq Select (1=50, 0=66)
+ * Bit 3 = Primary   Channel Dev 0 Transfer Mode (1=MultiWord DMA, 0=Ultra DMA)
+ * Bit 4 = Primary   Channel Dev 1 Transfer Mode (1=MultiWord DMA, 0=Ultra DMA)
+ * Bit 5 = Secondary Channel Dev 0 Transfer Mode (1=MultiWord DMA, 0=Ultra DMA)
+ * Bit 6 = Secondary Channel Dev 1 Transfer Mode (1=MultiWord DMA, 0=Ultra DMA)
+ * Bit 7 = PCI Mode Reset
+ ************************************************************************/
+static void IT8212SwitchDmaMode(PChannel pChan, u8 DeviceId)
+{
+	u8 pciControl;
+	u8 channel;
+	u8 device;
+	u8 configByte = 0;
+	u8 RevisionID;
+	struct pci_dev *pPciDev = pChan->pPciDev;
+
+	/*
+	 * These tables are for performance issue. Better formance than lots
+	 * of "Shifts".
+	 */
+	static const u8 dmaModeV10[4] = { 0x18, 0x18, 0x60, 0x60 };
+	static const u8 udmaModeV10[4] = { 0xE7, 0xE7, 0x9F, 0x9F };
+	static const u8 ideClock[4] = { 0xFD, 0xFD, 0xFB, 0xFB };
+
+	/*
+	 * channel --> 0-1; device --> 0-1; DeviceId --> 0-3;
+	 */
+	channel = DeviceId >> 1;
+	device = DeviceId & 1;
+
+	/*
+	 * Do nothing if the mode switch is unnecessary.
+	 */
+	if (!pChan->DoSwitch || pChan->ActiveDevice == DeviceId) {
+		dprintk("IT8212SwitchDmaMode: do not need to switch mode!\n");
+		return;
+	}
+	printk("IT8212SwitchDmaMode: switch DMA mode for dev (%x)\n", DeviceId);
+	pci_read_config_byte(pPciDev, 0x50, &pciControl);
+	pci_read_config_byte(pPciDev, 0x08, &RevisionID);
+
+	/*
+	 * Running on MULTIWORD_DMA mode.
+	 */
+	if (pChan->DmaType[device] == USE_MULTIWORD_DMA) {
+
+		/*
+		 * Switch to DMA mode.
+		 */
+		if (RevisionID == 0x10)
+			configByte = pciControl | dmaModeV10[DeviceId];
+		pci_write_config_byte(pPciDev, 0x50, configByte);
+	} else {
+		/*
+		 * Running on ULTRA DMA mode.
+		 */
+
+		/*
+		 * Select UDMA mode.
+		 */
+		configByte = pciControl;
+		if (RevisionID == 0x10)
+			configByte &= udmaModeV10[DeviceId];
+
+		/*
+		 * Select IDE clock.
+		 */
+		configByte = (configByte & ideClock[DeviceId]) |
+		    (pChan->IdeClock[device] << (channel + 1));
+		pci_write_config_byte(pPciDev, 0x50, configByte);
+
+		/*
+		 * Set UDMA timing.
+		 *
+		 * offset 0x56 = PCI Mode Primary Device 0 Ultra DMA Timing Registers
+		 * offset 0x57 = PCI Mode Primary Device 1 Ultra DMA Timing Registers
+		 * offset 0x5A = PCI Mode Secondary Device 0 Ultra DMA Timing Registers
+		 * offset 0x5B = PCI Mode Secondary Device 1 Ultra DMA Timing Registers
+		 */
+		if (RevisionID == 0x10) {
+			configByte = pChan->UdmaTiming[device];
+			pci_write_config_byte(pPciDev,
+					      (u8) (0x56 + (channel * 4)),
+					      configByte);
+			pci_write_config_byte(pPciDev,
+					      (u8) (0x56 + (channel * 4) + 1),
+					      configByte);
+		}
+
+		/*
+		 * Set PIO/DMA timing (Becasuse maybe the IDE clock is changed.)
+		 */
+		configByte = pChan->PioDmaTiming[pChan->IdeClock[device]];
+		pci_write_config_byte(pPciDev, (u8) (0x54 + (channel * 4)),
+				      configByte);
+	}
+
+	/*
+	 * Record the Active device on this channel
+	 */
+	pChan->ActiveDevice = device;
+}				/* end IT8212SwitchDmaMode */
+
+/************************************************************************
+ * IT8212 read/write routine.
+ ************************************************************************/
+static u32 IT8212ReadWrite(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+	u8 statusByte = 0;
+	u32 startingSector;
+	u32 sectorNumber;
+	u32 capacity;
+	PITE_ADAPTER pAdap;
+
+	if (Srb->TargetId >= 4) {
+		pAdap = ite_adapters[1];
+		if (Srb->TargetId < 6)
+			pChan = &pAdap->IDEChannel[0];
+
+		else
+			pChan = &pAdap->IDEChannel[1];
+	} else {
+		pAdap = ite_adapters[0];
+		if (Srb->TargetId < 2)
+			pChan = &pAdap->IDEChannel[0];
+
+		else
+			pChan = &pAdap->IDEChannel[1];
+	}
+
+	/*
+	 * Return error if overrun.
+	 */
+	startingSector = ((PCDB) Srb->Cdb)->CDB10.LogicalBlockByte3 |
+	    ((PCDB) Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
+	    ((PCDB) Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
+	    ((PCDB) Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
+	sectorNumber =
+	    (unsigned short)((Srb->DataTransferLength + 0x1FF) / 0x200);
+	capacity =
+	    pChan->IdentifyData[Srb->TargetId & 0x1].UserAddressableSectors;
+	if (capacity == 0x0FFFFFFF) {
+		capacity =
+		    pChan->IdentifyData[Srb->TargetId & 0x1].Capacity_48bit_LOW;
+	}
+	if ((startingSector + sectorNumber - 1) > capacity) {
+		printk("IT8212ReadWrite: disk[%d] over disk size.\n",
+		       Srb->TargetId);
+		printk
+		    ("capacity: %d. starting sector: %d. sector number: %d\n",
+		     capacity, startingSector, sectorNumber);
+		return SRB_STATUS_ERROR;
+	}
+
+	/*
+	 * Select device.
+	 */
+	outb((u8) ((Srb->TargetId & 0x1) << 4 | 0xA0),
+	     pChan->io_ports[IDE_SELECT_OFFSET]);
+
+	/*
+	 * Wait for device ready (Not Busy and Not DRQ).
+	 */
+	WaitForDeviceReady(pChan, statusByte);
+	if ((statusByte & IDE_STATUS_BUSY) || (statusByte & IDE_STATUS_DRQ)
+	    || (statusByte == 0)) {
+		printk("IT8212ReadWrite: disk[%d] not ready. status=0x%x\n",
+		       Srb->TargetId, statusByte);
+		return SRB_STATUS_BUSY;
+	}
+
+	/*
+	 * First, switch to DMA or UDMA mode if running on bypass mode.
+	 */
+	if (pAdap->bypass_mode)
+		IT8212SwitchDmaMode(pChan, Srb->TargetId);
+
+	/*
+	 * Check the SCATTER/GATHER count. The upper will give the different
+	 * memory address depend on whether use_sg is used or not.
+	 */
+	if (Srb->UseSg == 0)
+		IdeBuildDmaTable(pChan, Srb);
+	else
+		IdeBuildDmaSgTable(pChan, Srb);
+
+	/*
+	 * Start transfer the data.
+	 */
+	IdeStartTransfer(pChan, Srb, startingSector, sectorNumber);
+
+	/*
+	 * Wait for interrupt.
+	 */
+	return SRB_STATUS_PENDING;
+}				/* end IT8212ReadWrite */
+
+#if 0
+/************************************************************************
+ * Setup the transfer mode.
+ ************************************************************************/
+static void IT8212SetTransferMode(PChannel pChan, u32 DiskId, u8 TransferMode,
+			u8 ModeNumber)
+{
+	u8 statusByte = 0;
+
+	/*
+	 * Select device.
+	 */
+	outb((u8) ((DiskId & 0x1) << 4 | 0xA0),
+	     pChan->io_ports[IDE_SELECT_OFFSET]);
+
+	/*
+	 * Wait for device ready (Not Busy and Not DRQ).
+	 */
+	WaitForDeviceReady(pChan, statusByte);
+	if ((statusByte & IDE_STATUS_BUSY) || (statusByte & IDE_STATUS_DRQ)) {
+		printk("IT8212SetTransferMode: disk[%d] not ready. "
+				"status=0x%x\n", DiskId, statusByte);
+		return;
+	}
+
+	/*
+	 * Feature number ==> 03
+	 *
+	 * Mode contained in Sector Count Register.
+	 *
+	 * Bits(7:3)   Bits(2:0)       Mode
+	 *
+	 * 00000       000             PIO default mode
+	 * 00000       001             PIO default mode, disable IORDY
+	 * 00001       mode            PIO flow control transfer mode
+	 * 00010       mode            Single Word DMA mode
+	 * 00100       mode            Multi-word DMA mode
+	 * 01000       mode            Ultra DMA mode
+	 */
+	TransferMode |= ModeNumber;
+	outb(0x03, pChan->io_ports[IDE_FEATURE_OFFSET]);
+	outb(TransferMode, pChan->io_ports[IDE_NSECTOR_OFFSET]);
+	outb(0, pChan->io_ports[IDE_HCYL_OFFSET]);
+	outb(0, pChan->io_ports[IDE_MIDCYL_OFFSET]);
+	outb(IDE_COMMAND_SET_FEATURE, pChan->io_ports[IDE_COMMAND_OFFSET]);
+
+	/*
+	 * Check error.
+	 */
+	WaitForBaseCommandComplete(pChan, statusByte);
+	if ((statusByte != IDE_STATUS_IDLE) && (statusByte != 0)) {
+		printk("IT8212SetTransferMode: disk[%d]", DiskId);
+		printk("return unexpected status after issue command. 0x%x\n",
+		       statusByte);
+	}
+}				/* end IT8212SetTransferMode */
+#endif
+
+#if 0
+/************************************************************************
+ * Set the best transfer mode for device.
+ ************************************************************************/
+static void IT8212SetBestTransferMode(PITE_ADAPTER pAdap, PChannel pChan,
+					u8 channel)
+{
+	u8 i;
+	u8 k;
+	u8 transferMode;
+	u8 modeNumber;
+	u8 pciControl;
+	u8 device;
+	u8 configByte;
+	u8 cableStatus[2] = {
+		CABLE_40_PIN, CABLE_40_PIN
+	};
+	u8 RevisionID;
+	struct pci_dev *pPciDev = pChan->pPciDev;
+	PIDENTIFY_DATA2 ideIdentifyData;
+
+	/*
+	 * UDMA timing table for 66MHz clock.
+	 * UDMA timing table for 50MHz clock.
+	 * Best of IDE clock in this mode.
+	 */
+	static const u8 udmaTiming[3][7] = {
+		{0x44, 0x42, 0x31, 0x21, 0x11, 0x22, 0x11},
+		{0x33, 0x31, 0x21, 0x21, 0x11, 0x11, 0x11},
+		{IDE_CLOCK_66, IDE_CLOCK_50, IDE_CLOCK_66, IDE_CLOCK_66,
+		 IDE_CLOCK_66, IDE_CLOCK_50,
+		 IDE_CLOCK_66}
+	};
+
+	/*
+	 * DMA timing table for 66 MHz clock.
+	 * DMA timing table for 50 MHz clock.
+	 */
+	static const u8 dmaTiming[2][3] =
+	    { {0x88, 0x32, 0x31}, {0x66, 0x22, 0x21}
+	};
+
+	/*
+	 * PIO timing table for 66 MHz clock.
+	 * PIO timing table for 50 MHz clock.
+	 */
+	static const u8 pioTiming[2][5] =
+	    { {0xAA, 0xA3, 0xA1, 0x33, 0x31}, {0x88, 0x82, 0x81, 0x32, 0x21}
+	};
+	u8 pio_dma_timing[2][2][4] = {
+		{{
+		  0, 0, 0, 0}, {
+				0, 0, 0, 0}}, {{
+						0, 0, 0, 0}, {
+							      0, 0, 0, 0}}
+	};
+
+	/*
+	 * These tables are for performance issue. Better formance than lots
+	 * of "Shifts".
+	 */
+	static const u8 udmaModeV10[4] = { 0xE7, 0xE7, 0x9F, 0x9F };
+	static const u8 dmaMode[4] = { 0x08, 0x10, 0x20, 0x40 };
+	static const u8 udmaMode[4] = { 0xF7, 0xEF, 0xDF, 0xBF };
+	static const u8 ideClock[4] = { 0xFD, 0xFD, 0xFB, 0xFB };
+
+	/*
+	 * 2003/07/24
+	 * If running on Firmware mode, get cable status from it.
+	 */
+	for (i = 0; i < 2; i++) {
+
+		/*
+		 * The dafault of cable status is in PCI configuration 0x40.
+		 */
+		cableStatus[i] = pChan->Cable80[i];
+
+		/*
+		 * channel -->0 to 1.
+		 * device  -->0 or 1.
+		 */
+		pChan->UseDma[i] = TRUE;
+		device = i & 1;
+		if (!(pChan->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT) ||
+		    (pChan->DeviceFlags[i] & DFLAGS_CONFIG_CHANGED)) {
+			pio_dma_timing[0][channel][device] =
+			    pio_dma_timing[0][channel][device + 2] = 0;
+			pio_dma_timing[1][channel][device] =
+			    pio_dma_timing[1][channel][device + 2] = 0;
+			continue;
+		}
+
+		/*
+		 * Set PIO Mode.
+		 */
+		ideIdentifyData = &pChan->IdentifyData[i];
+		if ((!(ideIdentifyData->ValidFieldIndicator & 0x02))
+		    || (ideIdentifyData->AdvancedPIOModes == 0)) {
+			transferMode = PIO_FLOW_CONTROL;
+			modeNumber = 2;
+		} else {
+			transferMode = PIO_FLOW_CONTROL;
+			modeNumber =
+			    RaidGetHighestBit((u8) ideIdentifyData->
+					      AdvancedPIOModes) + 3;
+		}
+		IT8212SetTransferMode(pChan, i, transferMode, modeNumber);
+
+		/*
+		 * Record the PIO timing for later use.(0 to 4)
+		 */
+		pio_dma_timing[0][channel][device] = pioTiming[0][modeNumber];
+		pio_dma_timing[1][channel][device] = pioTiming[1][modeNumber];
+
+		/*
+		 * Get the best transfer mode (maybe Ultra DMA or Multi-Word
+		 * DMA).
+		 */
+		ideIdentifyData = &pChan->IdentifyData[i];
+		if ((!(ideIdentifyData->ValidFieldIndicator & 0x04))
+		    || (ideIdentifyData->UltraDMASupport == 0)) {
+
+			/*
+			 * UltraDMA is not valid.
+			 */
+			transferMode = MULTIWORD_DMA;
+			modeNumber =
+			    RaidGetHighestBit(ideIdentifyData->
+					      MultiWordDMASupport);
+			printk("The best transfer mode of Device[%d] is "
+				"DMA-%d\n", i, modeNumber);
+		} else {
+			transferMode = ULTRA_DMA;
+			modeNumber =
+			    RaidGetHighestBit(ideIdentifyData->UltraDMASupport);
+			printk("The best transfer mode of Device[%d] is "
+					"Ultra-%d\n", i, modeNumber);
+
+			/*
+			 * If this is 40-pin cable. Limit to Ultra DMA mode 2.
+			 */
+#if (0)
+			if ((cableStatus[i] == CABLE_40_PIN)
+			    && (modeNumber > 2)) {
+				printk("Reduce trans mode of Device[%d] to "
+					"Ultra-2 for cable issue.\n", i);
+				modeNumber = 0x02;
+			}
+#endif
+		}
+		IT8212SetTransferMode(pChan, i, transferMode, modeNumber);
+
+		/*
+		 * If running on ByPass mode, driver must take the
+		 * responsibility to set the PIO/DMA/UDMA timing.
+		 */
+		if (pAdap->bypass_mode) {
+			pci_read_config_byte(pPciDev, 0x50, &pciControl);
+			pci_read_config_byte(pPciDev, 0x08, &RevisionID);
+			if (transferMode == ULTRA_DMA) {
+
+				/*
+				 * Set this channel to UDMA mode (not only the
+				 * device).
+				 */
+				if (RevisionID == 0x10) {
+					configByte =
+					    pciControl & udmaModeV10[i +
+								     channel *
+								     2];
+				} else {
+					configByte =
+					    pciControl & udmaMode[i +
+								  channel * 2];
+				}
+
+				/*
+				 * Select IDE clock (50MHz or 66MHz).
+				 */
+				configByte &= ideClock[i + channel * 2];
+				configByte |=
+				    (udmaTiming[2][modeNumber] <<
+				     (channel + 1));
+				pci_write_config_byte(pPciDev, 0x50,
+						      configByte);
+
+				/*
+				 * Set UDMA timing.
+				 */
+				configByte =
+				    udmaTiming[udmaTiming[2][modeNumber]]
+				    [modeNumber];
+				if (modeNumber == 5 || modeNumber == 6) {
+
+					/*
+					 * Enable UDMA mode 5/6
+					 */
+					configByte |= UDMA_MODE_5_6;
+				}
+
+				/*
+				 * Bug Bug. Fill these two fields into the same
+				 * value.
+				 */
+				if (RevisionID == 0x10) {
+					pci_write_config_byte(pPciDev,
+							      (u8) (0x56 +
+								    (channel *
+								     4)),
+							      configByte);
+					pci_write_config_byte(pPciDev,
+							      (u8) (0x56 +
+								    (channel *
+								     4) + 1),
+							      configByte);
+				} else {
+					pci_write_config_byte(pPciDev,
+							      (u8) (0x56 +
+								    (channel *
+								     4) +
+								    device),
+							      configByte);
+				}
+
+				/*
+				 * Record the best UDMA mode for this device.
+				 */
+				pChan->DmaType[i] = ULTRA_DMA;
+				pChan->IdeClock[i] = udmaTiming[2][modeNumber];
+				pChan->UdmaTiming[i] = configByte;
+			} else if (transferMode == MULTIWORD_DMA) {
+
+				/*
+				 * If an ATAPI device with DMA mode, force it
+				 * to run in PIO mode.
+				 */
+				if (RevisionID == 0x10
+				    && pChan->
+				    DeviceFlags[i] & DFLAGS_ATAPI_DEVICE) {
+					pChan->UseDma[i] = FALSE;
+				} else {
+
+					/*
+					 * Set this device to DMA mode.
+					 */
+					configByte =
+					    pciControl | dmaMode[i +
+								 channel * 2];
+					pci_write_config_byte(pPciDev, 0x50,
+							      configByte);
+
+					/*
+					 * Record DMA timing (for later use).
+					 */
+					pio_dma_timing[0][channel][device +
+								   2] =
+					    dmaTiming[0][modeNumber];
+					pio_dma_timing[1][channel][device +
+								   2] =
+					    dmaTiming[1][modeNumber];
+				}
+				pChan->DmaType[i] = USE_MULTIWORD_DMA;
+			}
+			pChan->ActiveDevice = device;
+		}
+	}
+
+	/*
+	 * Because each channel owns one PIO/DMA timimg register only, so we
+	 * must set the timing to the slowest one to fit all. Really stupid
+	 * H/W! :(
+	 */
+	if (pAdap->bypass_mode) {
+
+		/*
+		 * Loop for the two IDE clocks (50 MHz and 66 MHz).
+		 */
+		for (i = 0; i < 2; i++) {
+			configByte = 0;
+			for (k = 0; k < 4; k++) {
+
+				/*
+				 * High part.
+				 */
+				if ((pio_dma_timing[i][channel][k] & 0xF0) >
+				    (configByte & 0xF0)) {
+					configByte =
+					    (configByte & 0xF) |
+					    (pio_dma_timing[i][channel][k] &
+					     0xF0);
+				}
+
+				/*
+				 * Low part.
+				 */
+				if ((pio_dma_timing[i][channel][k] & 0xF) >
+				    (configByte & 0xF)) {
+					configByte =
+					    (configByte & 0xF0) |
+					    (pio_dma_timing[i][channel][k] &
+					     0xF);
+				}
+			}
+
+			/*
+			 * Record the PIO/DMA timing for this channel.
+			 */
+			pChan->PioDmaTiming[i] = configByte;
+		}
+
+		/*
+		 * Set PIO/DMA timing register for each channel.
+		 */
+		configByte =
+		    pChan->PioDmaTiming[(pciControl >> (channel + 1)) & 1];
+		if (configByte != 0)
+			pci_write_config_byte(pPciDev,
+					      (u8) (0x54 + (channel * 4)),
+					      configByte);
+
+		/*
+		 * Check shall we do switch between the two devices
+		 */
+		for (i = 0; i < 2; i++) {
+			pChan->DoSwitch = TRUE;
+
+			/*
+			 * Master is not present
+			 */
+			if (!(pChan->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT)
+			    || (pChan->DeviceFlags[i] & DFLAGS_CONFIG_CHANGED)) {
+				printk("Channel %x: master is not present. No "
+					"switch mode.\n", channel);
+				pChan->DoSwitch = FALSE;
+				continue;
+			}
+
+			/*
+			 * Slave is not present
+			 */
+			if (!(pChan->DeviceFlags[i + 1] & DFLAGS_DEVICE_PRESENT)
+			    || (pChan->
+				DeviceFlags[i + 1] & DFLAGS_CONFIG_CHANGED)) {
+				printk("Channel %x: slave is not present. No "
+					"switch mode.\n", channel);
+				pChan->DoSwitch = FALSE;
+				continue;
+			}
+
+			/*
+			 * If both devices are running on DMA mode, no switch.
+			 */
+			if (pChan->DmaType[i] == USE_MULTIWORD_DMA
+			    && pChan->DmaType[i + 1] == USE_MULTIWORD_DMA) {
+				printk("Channel %x: run on DMA mode only. No "
+					"switch mode.\n", channel);
+				pChan->DoSwitch = FALSE;
+				continue;
+			}
+
+			/*
+			 * No switch if the two devices are running on the same mode.
+			 */
+			if ((pChan->DmaType[i] == pChan->DmaType[i + 1])
+			    && (pChan->UdmaTiming[i] ==
+				pChan->UdmaTiming[i + 1])
+			    && (pChan->IdeClock[i] == pChan->IdeClock[i + 1])) {
+				printk("Channel %x: two dev run on the same "
+					"mode. No switch mode.\n", channel);
+				pChan->DoSwitch = FALSE;
+				continue;
+			}
+			printk("Channel %x: switch mode if needed.\n", channel);
+		}
+	}
+}				/* end IT8212SetBestTransferMode */
+#endif
+
+#if 0
+/************************************************************************
+ * Initialize bypass(transparent) mode if BIOS is not ready.
+ ************************************************************************/
+static u8 IT8212InitBypassMode(struct pci_dev *pPciDev)
+{
+
+	/*
+	 * Reset local CPU, and set BIOS not ready.
+	 */
+	pci_write_config_byte(pPciDev, 0x5E, 0x01);
+
+	/*
+	 * Set to bypass mode, and reset PCI bus.
+	 */
+	pci_write_config_byte(pPciDev, 0x50, 0x00);
+	pci_write_config_word(pPciDev, 0x4, 0x0047);
+	pci_write_config_word(pPciDev, 0x40, 0xA0F3);
+	pci_write_config_dword(pPciDev, 0x4C, 0x02040204);
+	pci_write_config_byte(pPciDev, 0x42, 0x36);
+	pci_write_config_byte(pPciDev, 0x0D, 0x00);
+	return TRUE;
+}				/* end IT8212InitBypassMode */
+#endif
+
+/************************************************************************
+ * This is the interrupt service routine for ATAPI IDE miniport driver.
+ * TURE if expecting an interrupt.
+ ************************************************************************/
+static u8 IT8212Interrupt(PChannel pChan, u8 bypass_mode)
+{
+	u8 statusByte;
+	u8 bmstatus;
+	u32 i;
+	unsigned long bmbase;
+	PSCSI_REQUEST_BLOCK Srb;
+
+	bmstatus = 0;
+	bmbase = pChan->dma_base;
+	Srb = pChan->CurrentSrb;
+	if (Srb == 0 || pChan->ExpectingInterrupt == 0) {
+		dprintk("IT8212Interrupt: suspicious interrupt!\n");
+
+		/*
+		 * Clear interrupt by reading status register.
+		 */
+		outb((u8) 0xA0, pChan->io_ports[IDE_SELECT_OFFSET]);
+		GetBaseStatus(pChan, statusByte);
+		outb((u8) 0xB0, pChan->io_ports[IDE_SELECT_OFFSET]);
+		GetBaseStatus(pChan, statusByte);
+		outb(bmbase + 2, (u8) (inb(bmbase + 2) | BM_STAT_FLG_INT));
+		return FALSE;
+	}
+
+	/*
+	 * To handle share IRQ condition. If the interrupt is not ours, just
+	 * return FALSE.
+	 */
+	bmstatus = inb(bmbase + 2);
+	if ((bmstatus & BM_STAT_FLG_INT) == 0) {
+		dprintk("IT8212Interrupt: suspicious interrupt (int bit is not "
+			"on)\n");
+		return FALSE;
+	}
+
+	/*
+	 * Bug Fixed: All PIO access are blocked during bus master operation, so
+	 * stop bus master operation before we try to access IDE registers.
+	 */
+	if (bypass_mode)
+		outb(bmbase, 0);
+
+	/*
+	 * Clear interrupt by reading status register.
+	 */
+	GetBaseStatus(pChan, statusByte);
+	outb(bmbase + 2, (u8) (bmstatus | BM_STAT_FLG_INT));
+
+	/*
+	 * Handle ATAPI interrupt.
+	 */
+	if (pChan->DeviceFlags[Srb->TargetId & 1] & DFLAGS_ATAPI_DEVICE)
+		return AtapiInterrupt(pChan);
+	pChan->ExpectingInterrupt = FALSE;
+	if ((statusByte & IDE_STATUS_BUSY) || (statusByte & IDE_STATUS_DRQ)) {
+
+		/*
+		 * Ensure BUSY and DRQ is non-asserted.
+		 */
+		for (i = 0; i < 100; i++) {
+			GetBaseStatus(pChan, statusByte);
+			if (!(statusByte & IDE_STATUS_BUSY)
+			    && !(statusByte & IDE_STATUS_DRQ)) {
+				break;
+			}
+			mdelay(5);
+		}
+		if (i == 100) {
+			printk("IT8212Interrupt: disk[%x] return busy or drq "
+				"status. status = 0x%x\n",
+				Srb->TargetId, statusByte);
+			return FALSE;
+		}
+	}
+	if (statusByte & IDE_STATUS_ERROR) {
+
+		/*
+		 * Stop bus master operation.
+		 */
+		outb(bmbase, 0);
+		printk("IT8212Interrupt: error!\n");
+
+		/*
+		 * Map error to specific SRB status and handle request sense.
+		 */
+		Srb->SrbStatus = MapError(pChan, Srb);
+	} else {
+		Srb->SrbStatus = SRB_STATUS_SUCCESS;
+	}
+	pChan->CurrentSrb = NULL;
+	TaskDone(pChan, Srb);
+	return TRUE;
+}				/* end IT8212Interrupt */
+
+/************************************************************************
+ * This is the interrupt service routine for ATAPI IDE miniport driver.
+ * TRUE if expecting an interrupt. Remember the ATAPI io registers are
+ * different from IDE io registers and this is for each channel not for
+ * entire controller.
+ ************************************************************************/
+static u8 AtapiInterrupt(PChannel pChan)
+{
+	u32 wordCount;
+	u32 wordsThisInterrupt;
+	u32 status;
+	u32 i;
+	u8 statusByte;
+	u8 interruptReason;
+	u8 target_id;
+	PSCSI_REQUEST_BLOCK srb;
+	PITE_ADAPTER pAdap;
+
+	wordCount = 0;
+	wordsThisInterrupt = 256;
+	srb = pChan->CurrentSrb;
+	target_id = srb->TargetId;
+	if (target_id >= 4) {
+		pAdap = ite_adapters[1];
+		if (target_id < 6)
+			pChan = &pAdap->IDEChannel[0];
+
+		else
+			pChan = &pAdap->IDEChannel[1];
+	} else {
+		pAdap = ite_adapters[0];
+		if (target_id < 2)
+			pChan = &pAdap->IDEChannel[0];
+
+		else
+			pChan = &pAdap->IDEChannel[1];
+	}
+
+	/*
+	 * Clear interrupt by reading status.
+	 */
+	GetBaseStatus(pChan, statusByte);
+	dprintk("AtapiInterrupt: entered with status (%x)\n", statusByte);
+	if (statusByte & IDE_STATUS_BUSY) {
+
+		/*
+		 * Ensure BUSY is non-asserted.
+		 */
+		for (i = 0; i < 10; i++) {
+			GetBaseStatus(pChan, statusByte);
+			if (!(statusByte & IDE_STATUS_BUSY)) {
+				break;
+			}
+			mdelay(5);
+		}
+		if (i == 10) {
+			printk("AtapiInterrupt: BUSY on entry. Status %x\n",
+			       statusByte);
+			return FALSE;
+		}
+	}
+
+	/*
+	 * Check for error conditions.
+	 */
+	if (statusByte & IDE_STATUS_ERROR) {
+		if (srb->Cdb[0] != SCSIOP_REQUEST_SENSE) {
+
+			/*
+			 * Fail this request.
+			 */
+			status = SRB_STATUS_ERROR;
+			goto CompleteRequest;
+		}
+	}
+
+	/*
+	 * Check reason for this interrupt.
+	 */
+	interruptReason = (inb(pChan->io_ports[ATAPI_INTREASON_OFFSET]) & 0x3);
+	wordsThisInterrupt = 256;
+	if (interruptReason == 0x1 && (statusByte & IDE_STATUS_DRQ)) {
+
+		/*
+		 * Write the packet.
+		 */
+		printk("AtapiInterrupt: writing Atapi packet.\n");
+
+		/*
+		 * Send CDB to device.
+		 */
+		WriteBuffer(pChan, (unsigned short *)srb->Cdb, 6);
+		return TRUE;
+	} else if (interruptReason == 0x0 && (statusByte & IDE_STATUS_DRQ)) {
+
+		/*
+		 * Write the data.
+		 */
+
+		/*
+		 * Pick up bytes to transfer and convert to words.
+		 */
+		wordCount = inb(pChan->io_ports[ATAPI_LCYL_OFFSET]);
+		wordCount |= inb(pChan->io_ports[ATAPI_HCYL_OFFSET]) << 8;
+
+		/*
+		 * Covert bytes to words.
+		 */
+		wordCount >>= 1;
+		if (wordCount != pChan->WordsLeft) {
+			printk("AtapiInterrupt: %d words requested; %d words "
+				"xferred\n", pChan->WordsLeft, wordCount);
+		}
+
+		/*
+		 * Verify this makes sense.
+		 */
+		if (wordCount > pChan->WordsLeft)
+			wordCount = pChan->WordsLeft;
+
+		/*
+		 * Ensure that this is a write command.
+		 */
+		if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+			dprintk("AtapiInterrupt: write interrupt\n");
+			WaitOnBusy(pChan, statusByte);
+			WriteBuffer(pChan, pChan->DataBuffer, wordCount);
+
+#if (0)
+			/*
+			 * Translate ATAPI data back to SCSI data if needed
+			 * (don't convert if the original command is
+			 * SCSIOP_MODE_SELECT10)
+			 */
+			if (srb->Cdb[0] == ATAPI_MODE_SELECT
+			    && pchan->ConvertCdb) {
+				Atapi2Scsi(pChan, srb,
+					   (char *)pChan->DataBuffer,
+					   wordCount << 1);
+			}
+#endif
+		} else {
+			printk("AtapiInterrupt: int reason %x, but srb is for "
+				"a write %p.\n", interruptReason, srb);
+
+			/*
+			 * Fail this request.
+			 */
+			status = SRB_STATUS_ERROR;
+			goto CompleteRequest;
+		}
+
+		/*
+		 * Advance data buffer pointer and bytes left.
+		 */
+		pChan->DataBuffer += wordCount;
+		pChan->WordsLeft -= wordCount;
+		return TRUE;
+	} else if (interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) {
+
+		/*
+		 * Pick up bytes to transfer and convert to words.
+		 */
+		wordCount = inb(pChan->io_ports[ATAPI_LCYL_OFFSET]);
+		wordCount |= inb(pChan->io_ports[ATAPI_HCYL_OFFSET]) << 8;
+
+		/*
+		 * Covert bytes to words.
+		 */
+		wordCount >>= 1;
+		if (wordCount != pChan->WordsLeft) {
+			printk("AtapiInterrupt: %d words requested; %d words "
+				"xferred\n", pChan->WordsLeft, wordCount);
+		}
+
+		/*
+		 * Verify this makes sense.
+		 */
+		if (wordCount > pChan->WordsLeft)
+			wordCount = pChan->WordsLeft;
+
+		/*
+		 * Ensure that this is a read command.
+		 */
+		if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+			dprintk("AtapiInterrupt: read interrupt\n");
+			WaitOnBusy(pChan, statusByte);
+			ReadBuffer(pChan, pChan->DataBuffer, wordCount);
+
+			/*
+			 * You should typically set the ANSI-approved Version
+			 * field, in the INQUIRY response, to at least 2.
+			 */
+			if (srb->Cdb[0] == SCSIOP_INQUIRY) {
+
+				/*
+				 * Maybe it's not necessary in Linux driver.
+				 */
+				*((unsigned char *)pChan->DataBuffer + 2) = 2;
+			}
+		} else {
+			printk("AtapiInterrupt: int reason %x, but srb is for "
+				"a read %p.\n", interruptReason, srb);
+
+			/*
+			 * Fail this request.
+			 */
+			status = SRB_STATUS_ERROR;
+			goto CompleteRequest;
+		}
+
+		/*
+		 * Advance data buffer pointer and bytes left.
+		 */
+		pChan->DataBuffer += wordCount;
+		pChan->WordsLeft -= wordCount;
+
+		/*
+		 * Check for read command complete.
+		 */
+		if (pChan->WordsLeft == 0) {
+
+			/*
+			 * Work around to make many atapi devices return
+			 * correct sector size of 2048. Also certain devices
+			 * will have sector count == 0x00, check for that also.
+			 */
+			if ((srb->Cdb[0] == 0x25) &&
+			    ((pChan->IdentifyData[srb->TargetId & 1].
+			      GeneralConfiguration >> 8) & 0x1F) == 0x05) {
+				pChan->DataBuffer -= wordCount;
+				if (pChan->DataBuffer[0] == 0x00) {
+					*((u32 *) & (pChan->DataBuffer[0])) =
+					    0xFFFFFF7F;
+				}
+				*((u32 *) & (pChan->DataBuffer[2])) =
+				    0x00080000;
+				pChan->DataBuffer += wordCount;
+			}
+		}
+		return TRUE;
+	} else if (interruptReason == 0x3 && !(statusByte & IDE_STATUS_DRQ)) {
+		dprintk("AtapiInterrupt: command complete!\n");
+
+		/*
+		 * Command complete.
+		 */
+		if (pChan->WordsLeft)
+			status = SRB_STATUS_DATA_OVERRUN;
+		else
+			status = SRB_STATUS_SUCCESS;
+CompleteRequest:
+		if (status == SRB_STATUS_ERROR) {
+
+			/*
+			 * Map error to specific SRB status and handle request
+			 * sense.
+			 */
+			printk("AtapiInterrupt error\n");
+			status = MapError(pChan, srb);
+
+			/*
+			 * Try to recover it.... 2003/02/27
+			 */
+			pChan->RDP = FALSE;
+		} else {
+
+			/*
+			 * Wait for busy to drop.
+			 */
+			for (i = 0; i < 30; i++) {
+				GetStatus(pChan, statusByte);
+				if (!(statusByte & IDE_STATUS_BUSY)) {
+					break;
+				}
+				udelay(500);
+			}
+			if (i == 30) {
+
+				/*
+				 * Reset the controller.
+				 */
+				printk("AtapiInterrupt: resetting due to BSY "
+					"still up - %x.\n", statusByte);
+				AtapiResetController(pAdap, pChan);
+				return TRUE;
+			}
+
+			/*
+			 * Check to see if DRQ is still up.
+			 */
+			if (statusByte & IDE_STATUS_DRQ) {
+				for (i = 0; i < 500; i++) {
+					GetStatus(pChan, statusByte);
+					if (!(statusByte & IDE_STATUS_DRQ)) {
+						break;
+					}
+					udelay(100);
+				}
+				if (i == 500) {
+
+					/*
+					 * Reset the controller.
+					 */
+					printk("AtapiInterrupt: resetting due "
+						"to DRQ still up - %x\n",
+						statusByte);
+					AtapiResetController(pAdap, pChan);
+					return TRUE;
+				}
+			}
+		}
+
+		/*
+		 * Clear interrupt expecting flag.
+		 */
+		pChan->ExpectingInterrupt = FALSE;
+
+		/*
+		 * Sanity check that there is a current request.
+		 */
+		if (srb != NULL) {
+
+			/*
+			 * Set status in SRB.
+			 */
+			srb->SrbStatus = (u8) status;
+
+			/*
+			 * Check for underflow.
+			 */
+			if (pChan->WordsLeft) {
+
+				/*
+				 * Subtract out residual words and update if
+				 * filemark hit, setmark hit , end of data,
+				 * end of media...
+				 */
+				if (!(pChan->DeviceFlags[srb->TargetId & 1] &
+				     DFLAGS_TAPE_DEVICE)) {
+					if (status == SRB_STATUS_DATA_OVERRUN) {
+						srb->DataTransferLength -=
+						    pChan->WordsLeft * 2;
+					} else {
+						srb->DataTransferLength = 0;
+					}
+				} else {
+					srb->DataTransferLength -=
+					    pChan->WordsLeft * 2;
+				}
+			}
+			GetBaseStatus(pChan, statusByte);
+			if (pChan->RDP && !(statusByte & IDE_STATUS_DSC)) {
+				printk("-@@-\n");
+			} else {
+
+				/*
+				 * Clear current SRB. Indicate ready for next
+				 * request.
+				 */
+				pChan->CurrentSrb = NULL;
+				TaskDone(pChan, srb);
+			}
+		} else {
+			printk("AtapiInterrupt: no SRB!\n");
+		}
+		return TRUE;
+	} else {
+
+		/*
+		 * Unexpected int.
+		 */
+		printk("AtapiInterrupt: unexpected interrupt. intReason %x. "
+			"status %x.\n", interruptReason, statusByte);
+		return FALSE;
+	}
+	return TRUE;
+}				/* end AtapiInterrupt */
+
+/************************************************************************
+ * IRQ handler.
+ ************************************************************************/
+static irqreturn_t Irq_Handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int handled = 0;
+	u8 i;
+	u8 j;
+	unsigned long flags;
+	PITE_ADAPTER pAdap;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	/*
+	 * Scan for interrupt to process.
+	 */
+	for (i = 0; i < NumAdapters; i++) {
+		pAdap = ite_adapters[i];
+		if (pAdap->irq != irq)
+			continue;
+		handled = 1;
+		for (j = 0; j < pAdap->num_channels; j++) {
+			IT8212Interrupt(&pAdap->IDEChannel[j],
+					pAdap->bypass_mode);
+		}
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return IRQ_RETVAL(handled);
+}				/* end Irq_Handler */
+
+/************************************************************************
+ * This routine handles IDE Verify.
+ ************************************************************************/
+static u8 IdeVerify(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+	u8 drvSelect;
+	u8 statusByte = 0;
+	u32 startingSector;
+	u32 sectors;
+	u32 endSector;
+	u32 sectorCount;
+
+	/*
+	 * Select device
+	 */
+	outb((u8) ((Srb->TargetId & 0x1) << 4 | 0xA0),
+	     pChan->io_ports[IDE_SELECT_OFFSET]);
+
+	/*
+	 * Wait for device ready (Not BUSY and Not DRQ)
+	 */
+	WaitForDeviceReady(pChan, statusByte);
+	if ((statusByte & IDE_STATUS_BUSY) || (statusByte & IDE_STATUS_DRQ)
+	    || (statusByte == 0)) {
+		printk("IdeVerify: disk[%d] not ready. status=0x%x\n",
+		       Srb->TargetId, statusByte);
+		return SRB_STATUS_BUSY;
+	}
+
+	/*
+	 * Get the starting sector number from CDB.
+	 */
+	startingSector = ((PCDB) Srb->Cdb)->CDB10.LogicalBlockByte3 |
+	    ((PCDB) Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
+	    ((PCDB) Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
+	    ((PCDB) Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
+	sectorCount =
+	    (u16) (((PCDB) Srb->Cdb)->CDB10.
+		   TransferBlocksMsb << 8 | ((PCDB) Srb->Cdb)->CDB10.
+		   TransferBlocksLsb);
+	endSector = startingSector + sectorCount;
+
+	/*
+	 * Drive has these number sectors.
+	 *
+	 * 48-bit addressing.
+	 */
+	if (endSector > 0x0FFFFFFF) {
+		sectors =
+		    pChan->IdentifyData[Srb->TargetId & 0x01].
+		    Capacity_48bit_LOW;
+		printk("IdeVerify (48-bit): starting sector %d, Ending "
+			"sector %d\n", startingSector, endSector);
+		if (endSector > sectors) {
+
+			/*
+			 * Too big, round down.
+			 */
+			printk
+			    ("IdeVerify: truncating request to %x blocks\n",
+			     sectors - startingSector - 1);
+			outb((u8) ((sectors - startingSector - 1) >> 8),
+			     pChan->io_ports[IDE_NSECTOR_OFFSET]);
+			outb((u8) (sectors - startingSector - 1),
+			     pChan->io_ports[IDE_NSECTOR_OFFSET]);
+		} else {
+
+			/*
+			 * Set up sector count register. Round up to next block.
+			 */
+			if (sectorCount > 0xFFFF) {
+				sectorCount = (u16) 0xFFFF;
+			}
+			outb((u8) (sectorCount >> 8),
+			     pChan->io_ports[IDE_NSECTOR_OFFSET]);
+			outb((u8) sectorCount,
+			     pChan->io_ports[IDE_NSECTOR_OFFSET]);
+		}
+
+		/*
+		 * Indicate expecting an interrupt.
+		 */
+		pChan->ExpectingInterrupt = TRUE;
+
+		/*
+		 * Set up LBA address
+		 */
+		outb((u8) (startingSector >> 24),
+		     pChan->io_ports[IDE_LOCYL_OFFSET]);
+		outb((u8) startingSector, pChan->io_ports[IDE_LOCYL_OFFSET]);
+		outb((u8) 0, pChan->io_ports[IDE_MIDCYL_OFFSET]);
+		outb((u8) (startingSector >> 8),
+		     pChan->io_ports[IDE_MIDCYL_OFFSET]);
+		outb((u8) 0, pChan->io_ports[IDE_HCYL_OFFSET]);
+		outb((u8) (startingSector >> 16),
+		     pChan->io_ports[IDE_HCYL_OFFSET]);
+
+		/*
+		 * Send verify command.
+		 */
+		outb(IDE_COMMAND_READ_VERIFY_EXT,
+		     pChan->io_ports[IDE_COMMAND_OFFSET]);
+	} else {
+		/*
+		 * 28-bit addressing
+		 */
+		sectors = pChan->IdentifyData[Srb->TargetId & 0x01].
+						UserAddressableSectors;
+		printk("IdeVerify: starting sector %d, ending sector %d\n",
+		       startingSector, endSector);
+		if (endSector > sectors) {
+
+			/*
+			 * Too big, round down.
+			 */
+			printk
+			    ("IdeVerify: truncating request to %d blocks\n",
+			     sectors - startingSector - 1);
+			outb((u8) (sectors - startingSector - 1),
+			     pChan->io_ports[IDE_NSECTOR_OFFSET]);
+		} else {
+
+			/*
+			 * Set up sector count register. Round up to next block.
+			 */
+			if (sectorCount > 0xFF)
+				sectorCount = (u16) 0xFF;
+			outb((u8)sectorCount,
+				pChan->io_ports[IDE_NSECTOR_OFFSET]);
+		}
+
+		/*
+		 * Indicate expecting an interrupt.
+		 */
+		pChan->ExpectingInterrupt = TRUE;
+
+		/*
+		 * Set up LBA address
+		 */
+		outb((u8) startingSector, pChan->io_ports[IDE_LOCYL_OFFSET]);
+		outb((u8) (startingSector >> 8),
+		     pChan->io_ports[IDE_MIDCYL_OFFSET]);
+		outb((u8) (startingSector >> 16),
+		     pChan->io_ports[IDE_HCYL_OFFSET]);
+
+		/*
+		 * Select driver, set LBA mode, set LBA (27:27)
+		 */
+		drvSelect = (u8) (startingSector >> 24);
+		drvSelect =
+		    drvSelect | (((u8) Srb->TargetId & 0x1) << 4) | 0xA0 | 0x40;
+		outb(drvSelect, pChan->io_ports[IDE_SELECT_OFFSET]);
+
+		/*
+		 * Send verify command.
+		 */
+		outb(IDE_COMMAND_READ_VERIFY,
+		     pChan->io_ports[IDE_COMMAND_OFFSET]);
+	}
+
+	/*
+	 * Wait for interrupt.
+	 */
+	return SRB_STATUS_PENDING;
+}				/* end IdeVerify */
+
+/************************************************************************
+ * This function is used to copy memory with overlapped destination and
+ * source. I guess ScsiPortMoveMemory cannot handle this well. Can it?
+ ************************************************************************/
+void
+IT8212MoveMemory(unsigned char *DestAddr, unsigned char *SrcAddr, u32 ByteCount)
+{
+	long i;
+
+	dprintk("IT8212MoveMemory: DestAddr=0x%p, SrcAddr=0x%p, "
+		"ByteCount=0x%x\n", DestAddr, SrcAddr, ByteCount);
+	if (DestAddr > SrcAddr) {
+
+		/*
+		 * If Destination Area is in the back of the Source Area, copy
+		 * from the end of the requested area.
+		 */
+		for (i = (ByteCount - 1); i >= 0; i--)
+			*(DestAddr + i) = *(SrcAddr + i);
+	} else if (DestAddr < SrcAddr) {
+
+		/*
+		 * If Destination Area is in the front of the Source Area, copy
+		 * from the begin of the requested area.
+		 */
+		for (i = 0; i < ByteCount; i++)
+			*(DestAddr + i) = *(SrcAddr + i);
+	}
+}				/* end IT8212MoveMemory */
+
+/************************************************************************
+ * Convert SCSI packet command to Atapi packet command.
+ ************************************************************************/
+static void Scsi2Atapi(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+
+	/*
+	 * Change the cdb length.
+	 */
+	Srb->CdbLength = 12;
+
+	/*
+	 * Because the block descripter and the header translation, we must
+	 * adjust the requested length.
+	 */
+	Srb->DataTransferLength -= 4;
+
+	/*
+	 * Record the original CDB for later restore.
+	 */
+	memcpy(pChan->TempCdb, Srb->Cdb, MAXIMUM_CDB_SIZE);
+
+	/*
+	 * Indicate that we have performed Scsi2Atapi function. And we must
+	 * restore the CDB back once the command complete.
+	 */
+	pChan->ConvertCdb = TRUE;
+	switch (Srb->Cdb[0]) {
+
+		/*
+		 * Convert the command from SCSIOP_MODE_SENSE (0x1A) to
+		 * SCSIOP_MODE_SENSE10 (0x5A).
+		 */
+	case SCSIOP_MODE_SENSE:
+		{
+			PSCSI_MODE_SENSE10 modeSense10 =
+			    (PSCSI_MODE_SENSE10) Srb->Cdb;
+			PSCSI_MODE_SENSE6 modeSense6 =
+			    (PSCSI_MODE_SENSE6) pChan->TempCdb;
+
+			/*
+			 * 1. Zero out the whole CDB.
+			 */
+			memset((unsigned char *)modeSense10, 0,
+			       MAXIMUM_CDB_SIZE);
+
+			/*
+			 * 2. Fill in command code (SCSI_MODE_SENSE10).
+			 */
+			modeSense10->OperationCode = ATAPI_MODE_SENSE;
+			modeSense10->Dbd = modeSense6->Dbd;
+			modeSense10->PageCode = modeSense6->PageCode;
+			modeSense10->Pc = modeSense6->Pc;
+			modeSense10->SubpageCode = modeSense6->SubpageCode;
+			modeSense10->AllocationLengthLsb =
+			    modeSense6->AllocationLength;
+			modeSense10->Control = modeSense6->Control;
+
+			/*
+			 * 3. Becasuse we will fake a block descripter (-8), and
+			 * translate the header (+4), so the requested length
+			 * should be modified. That is, -8+4=-4 bytes.
+			 */
+			modeSense10->AllocationLengthLsb -= 4;
+			break;
+		}
+
+		/*
+		 * Convert the command from SCSIOP_MODE_SELECT (0x15) to
+		 * SCSIOP_MODE_SELECT10 (0x5A).
+		 */
+	case SCSIOP_MODE_SELECT:
+		{
+			u8 tempHeader[sizeof(PSCSI_MODE_PARAMETER_HEADER6)];
+			u16 byteCount;
+			PSCSI_MODE_PARAMETER_HEADER10 header10 =
+			    (PSCSI_MODE_PARAMETER_HEADER10) Srb->DataBuffer;
+			PSCSI_MODE_PARAMETER_HEADER6 header6 =
+			    (PSCSI_MODE_PARAMETER_HEADER6) tempHeader;
+			PSCSI_MODE_SELECT10 modeSelect10 =
+			    (PSCSI_MODE_SELECT10) Srb->Cdb;
+			PSCSI_MODE_SELECT6 modeSelect6 =
+			    (PSCSI_MODE_SELECT6) pChan->TempCdb;
+
+			/*
+			 * First, convert the command block.
+			 */
+
+			/*
+			 * 1. Zero out the whole CDB.
+			 */
+			memset((unsigned char *)modeSelect10, 0,
+			       MAXIMUM_CDB_SIZE);
+
+			/*
+			 * 2. Fill in command code (SCSI_MODE_SENSE10).
+			 */
+			modeSelect10->OperationCode = ATAPI_MODE_SELECT;
+			modeSelect10->SPBit = modeSelect6->SPBit;
+			modeSelect10->PFBit = modeSelect6->PFBit;
+			modeSelect10->ParameterListLengthLsb =
+			    modeSelect6->ParameterListLength;
+			modeSelect10->Control = modeSelect6->Control;
+
+			/*
+			 * 3. Becasuse we will remove the block descripter (-8),
+			 * and translate the header (+4), so the requested
+			 * length should be modified. That is, -8+4=-4 bytes.
+			 */
+			modeSelect10->ParameterListLengthLsb -= 4;
+
+			/*
+			 * Second, convert the parameter page format from SCSI
+			 * to ATAPI.
+			 */
+
+			/*
+			 * Remove the mode parameter data (except the header
+			 * and the block descripter).
+			 */
+			byteCount =
+			    modeSelect6->ParameterListLength -
+			    sizeof(SCSI_MODE_PARAMETER_HEADER6) -
+			    sizeof(SCSI_MODE_PARAMTER_BLOCK_DESCRIPTER);
+			if (byteCount > 0) {
+				IT8212MoveMemory((unsigned char *)header10 +
+						 sizeof
+						 (SCSI_MODE_PARAMETER_HEADER10),
+						 (unsigned char *)header10 +
+						 sizeof
+						 (SCSI_MODE_PARAMETER_HEADER6)
+						 +
+						 sizeof
+						 (SCSI_MODE_PARAMTER_BLOCK_DESCRIPTER),
+						 byteCount);
+			}
+
+			/*
+			 * Keep the original header6 (4 bytes) in tempHeader for
+			 * later use
+			 */
+			memcpy(tempHeader, header10,
+			       sizeof(SCSI_MODE_PARAMETER_HEADER6));
+
+			/*
+			 * Change the "mode parameter header(6)" to "mode
+			 * parameter header(10)"
+			 * Notice: Remove the block descripter in SCSI-2 command
+			 * out. It won't be used in MMC.
+			 */
+			memset((unsigned char *)header10, 0,
+			       sizeof(SCSI_MODE_PARAMETER_HEADER10));
+			header10->ModeDataLengthLsb = header6->ModeDataLength;
+			header10->MediumType = header6->MediumType;
+			header10->DeviceSpecificParameter =
+			    header6->DeviceSpecificParameter;
+			header10->BlockDescriptorLengthLsb =
+			    header6->BlockDescriptorLength;
+
+			/*
+			 * ATAPI doesn't support block descripter, so remove it
+			 * from the mode paramter.
+			 */
+			header10->BlockDescriptorLengthLsb = 0;
+			break;
+		}
+	}
+}				/* end Scsi2Atapi */
+
+/************************************************************************
+ * Send ATAPI packet command to device.
+ ************************************************************************/
+static u32 AtapiSendCommand(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+	u8 statusByte;
+	u8 byteCountLow;
+	u8 byteCountHigh;
+	u8 useDMA;
+	u8 RevisionID = 0;
+	u8 bmClearStat;
+	u32 flags;
+	int i;
+	unsigned long bmAddress = pChan->dma_base;
+	PITE_ADAPTER pAdap = ite_adapters[0];
+
+	dprintk("AtapiSendCommand: command 0x%X to device %d\n", Srb->Cdb[0],
+		Srb->TargetId);
+
+	/*
+	 * Default use PIO mode.
+	 */
+	useDMA = 0;
+	pChan->ConvertCdb = FALSE;
+
+	/*
+	 * Make sure command is to ATAPI device.
+	 */
+	flags = pChan->DeviceFlags[Srb->TargetId & 1];
+	if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) {
+		if ((Srb->Lun) > (pChan->DiscsPresent[Srb->TargetId & 1] - 1)) {
+
+			/*
+			 * Indicate no device found at this address.
+			 */
+			return SRB_STATUS_SELECTION_TIMEOUT;
+		}
+	} else if (Srb->Lun > 0) {
+		return SRB_STATUS_SELECTION_TIMEOUT;
+	}
+
+	if (!(flags & DFLAGS_ATAPI_DEVICE))
+		return SRB_STATUS_SELECTION_TIMEOUT;
+
+	/*
+	 * Select device 0 or 1.
+	 */
+	outb((u8) (((Srb->TargetId & 0x1) << 4) | 0xA0),
+	     pChan->io_ports[ATAPI_SELECT_OFFSET]);
+
+	/*
+	 * Try to enable interrupt again. (2003/02/25)
+	 */
+#if (0)
+	outb(0x00, pChan->io_ports[ATAPI_CONTROL_OFFSET]);
+
+#endif
+
+	/*
+	 * Verify that controller is ready for next command.
+	 */
+	GetStatus(pChan, statusByte);
+	dprintk("AtapiSendCommand: entered with status %x\n", statusByte);
+	if (statusByte & IDE_STATUS_BUSY) {
+		printk("AtapiSendCommand: device busy (%x)\n", statusByte);
+		return SRB_STATUS_BUSY;
+	}
+	if (statusByte & IDE_STATUS_ERROR) {
+		if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) {
+			printk("AtapiSendCommand: error on entry: (%x)\n",
+			       statusByte);
+
+			/*
+			 * Read the error reg. to clear it and fail this request.
+			 */
+			return MapError(pChan, Srb);
+		}
+	}
+
+	/*
+	 * If a tape drive doesn't have DSC set and the last command is
+	 * restrictive, don't send the next command. See discussion of
+	 * Restrictive Delayed Process commands in QIC-157.
+	 */
+	if ((!(statusByte & IDE_STATUS_DSC)) && (flags & DFLAGS_TAPE_DEVICE)
+	    && pChan->RDP) {
+		mdelay(1);
+		printk("AtapiSendCommand: DSC not set. %x\n", statusByte);
+		return SRB_STATUS_BUSY;
+	}
+	if (statusByte & IDE_STATUS_DRQ) {
+		printk("AtapiSendCommand: enter with status (%x). Attempt to "
+			"recover.\n", statusByte);
+
+		/*
+		 * Try to drain the data that one preliminary device thinks that
+		 * it has to transfer. Hopefully this random assertion of DRQ
+		 * will not be present in production devices.
+		 */
+		for (i = 0; i < 0x10000; i++) {
+			GetStatus(pChan, statusByte);
+			if (statusByte & IDE_STATUS_DRQ) {
+
+				/*
+				 * Note: The data register is always referenced
+				 * as a 16-bit word.
+				 */
+				inw(pChan->io_ports[ATAPI_DATA_OFFSET]);
+			} else {
+				break;
+			}
+		}
+		if (i == 0x10000) {
+			printk("AtapiSendCommand: DRQ still asserted.Status "
+				"(%x)\n", statusByte);
+			printk("AtapiSendCommand: issued soft reset to Atapi "
+				"device. \n");
+			AtapiSoftReset(pChan, Srb->TargetId);
+
+			/*
+			 * Re-initialize Atapi device.
+			 */
+			IssueIdentify(pChan, (Srb->TargetId & 1),
+				      IDE_COMMAND_ATAPI_IDENTIFY);
+
+			/*
+			 * Inform the port driver that the bus has been reset.
+			 */
+
+			/*
+			 * Clean up device extension fields that AtapiStartIo
+			 * won't.
+			 */
+			pChan->ExpectingInterrupt = FALSE;
+			pChan->RDP = FALSE;
+			return SRB_STATUS_BUS_RESET;
+		}
+	}
+	if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) {
+
+		/*
+		 * As the cdrom driver sets the LUN field in the cdb, it must
+		 * be removed.
+		 */
+		Srb->Cdb[1] &= ~0xE0;
+		if ((Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY)
+		    && (flags & DFLAGS_SANYO_ATAPI_CHANGER)) {
+
+			/*
+			 * Torisan changer. TUR's are overloaded to be platter
+			 * switches.
+			 */
+			Srb->Cdb[7] = Srb->Lun;
+		}
+	}
+
+	/*
+	 * Convert SCSI to ATAPI commands if needed
+	 */
+	switch (Srb->Cdb[0]) {
+	case SCSIOP_MODE_SENSE:
+	case SCSIOP_MODE_SELECT:
+		if (flags & DFLAGS_ATAPI_DEVICE) {
+			Scsi2Atapi(pChan, Srb);
+		}
+		break;
+	}
+	if (pChan->UseDma[Srb->TargetId & 1]) {
+		switch (Srb->Cdb[0]) {
+		case SCSIOP_READ:	/* (0x28)               */
+		case 0xA8:	/* READ(12)             */
+		case SCSIOP_READ_CD:
+			if (Srb->DataTransferLength == 0) {
+				break;
+			}
+
+			/*
+			 * First, switch to DMA or UDMA mode if running on
+			 * Bypass mode.
+			 */
+			if (pAdap->bypass_mode)
+				IT8212SwitchDmaMode(pChan, Srb->TargetId);
+
+			/*
+			 * Check the SCATTER/GATHER count. The upper will give
+			 * the different memory address depend on whether
+			 * use_sg is used or not.
+			 */
+			if (Srb->UseSg == 0)
+				IdeBuildDmaTable(pChan, Srb);
+			else
+				IdeBuildDmaSgTable(pChan, Srb);
+			bmClearStat = inb(bmAddress + 2);
+			if (Srb->TargetId & 0x01) {
+				bmClearStat =
+				    bmClearStat | BM_DRV1_DMA_CAPABLE |
+				    BM_STAT_FLG_INT | BM_STAT_FLG_ERR;
+			} else {
+				bmClearStat =
+				    bmClearStat | BM_DRV0_DMA_CAPABLE |
+				    BM_STAT_FLG_INT | BM_STAT_FLG_ERR;
+			}
+			useDMA = 1;
+			outb(0, bmAddress);
+
+			/*
+			 * Setup PRD table physical address.
+			 */
+			outl(pChan->dmatable_dma, bmAddress + 4);
+
+			/*
+			 * Clear the status.
+			 */
+			outb(bmClearStat, bmAddress + 2);
+			break;
+		}		/* end switch (Srb->Cdb[0]) */
+	}
+
+	/*
+	 * Set data buffer pointer and words left.
+	 */
+	pChan->DataBuffer = (unsigned short *)Srb->DataBuffer;
+	if (useDMA)
+		pChan->WordsLeft = 0;
+	else
+		pChan->WordsLeft = Srb->DataTransferLength / 2;
+	outb((u8) (((Srb->TargetId & 0x1) << 4) | 0xA0),
+	     pChan->io_ports[ATAPI_SELECT_OFFSET]);
+	WaitOnBusy(pChan, statusByte);
+
+	/*
+	 * Write transfer byte count to registers.
+	 */
+	byteCountLow = (u8) (Srb->DataTransferLength & 0xFF);
+	byteCountHigh = (u8) (Srb->DataTransferLength >> 8);
+	if (Srb->DataTransferLength >= 0x10000)
+		byteCountLow = byteCountHigh = 0xFF;
+	outb(byteCountLow, pChan->io_ports[ATAPI_LCYL_OFFSET]);
+	outb(byteCountHigh, pChan->io_ports[ATAPI_HCYL_OFFSET]);
+	outb(0, pChan->io_ports[ATAPI_INTREASON_OFFSET]);
+	outb(0, pChan->io_ports[ATAPI_UNUSED1_OFFSET]);
+	outb(useDMA, pChan->io_ports[ATAPI_FEATURE_OFFSET]);
+	WaitOnBusy(pChan, statusByte);
+	if (flags & DFLAGS_INT_DRQ) {
+
+		/*
+		 * This device interrupts when ready to receive the packet.
+		 *
+		 * Write ATAPI packet command.
+		 */
+		outb(IDE_COMMAND_ATAPI_PACKET,
+		     pChan->io_ports[IDE_COMMAND_OFFSET]);
+		printk("AtapiSendCommand: wait for int. to send packet. "
+				"status (%x)\n", statusByte);
+		pChan->ExpectingInterrupt = TRUE;
+		return SRB_STATUS_PENDING;
+	} else {
+
+		/*
+		 * Write ATAPI packet command.
+		 */
+		outb(IDE_COMMAND_ATAPI_PACKET,
+		     pChan->io_ports[IDE_COMMAND_OFFSET]);
+
+		/*
+		 * Wait for DRQ.
+		 */
+		WaitOnBusy(pChan, statusByte);
+		WaitForDrq(pChan, statusByte);
+		if (!(statusByte & IDE_STATUS_DRQ)) {
+			printk("AtapiSendCommand: DRQ never asserted (%x)\n",
+			       statusByte);
+			return SRB_STATUS_ERROR;
+		}
+	}
+
+	/*
+	 * Need to read status register.
+	 */
+	GetBaseStatus(pChan, statusByte);
+
+	/*
+	 * Send CDB to device.
+	 * After detecting DRQ, the host writes the 12 bytes(6 words) of Command
+	 * to the Data Register.
+	 */
+	WaitOnBusy(pChan, statusByte);
+	WriteBuffer(pChan, (unsigned short *)Srb->Cdb, 6);
+
+	/*
+	 * If running on DMA mode, start BUS MASTER operation.
+	 */
+	if (useDMA) {
+
+		/*
+		 * If SCSIOP_READ command is sent to an Audio CD, error will be
+		 * returned. But the error will be blocked by our controller if
+		 * bus master operation started. So wait for a short period to
+		 * check if error occurs. If error occurs, don't start bus
+		 * master operation.
+		 */
+		if (RevisionID == 0x10) {
+			for (i = 0; i < 500; i++) {
+				udelay(1);
+				statusByte = inb(bmAddress + 2);
+				if (statusByte & BM_STAT_FLG_INT) {
+
+					/*
+					 * If error occurs, give up this round.
+					 */
+					printk("AtapiSendCommand: command "
+						"failed. Don't start bus "
+						"master.");
+					printk("status=%x, i=%d\n", statusByte,
+					       i);
+					pChan->ExpectingInterrupt = TRUE;
+					return SRB_STATUS_PENDING;
+				}
+			}
+		}
+		if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+			outb(BM_CMD_FLG_START | BM_CMD_FLG_WRTTOMEM, bmAddress);
+		else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
+			outb(BM_CMD_FLG_START | BM_CMD_FLG_WRTTODSK, bmAddress);
+	}
+
+	/* end if (useDMA) */
+	/*
+	 * Indicate expecting an interrupt and wait for it.
+	 */
+	pChan->ExpectingInterrupt = TRUE;
+	return SRB_STATUS_PENDING;
+}				/* end AtapiSendCommand */
+
+/************************************************************************
+ * Program ATA registers for IDE disk transfer.
+ ************************************************************************/
+static u32 IdeSendCommand(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+	u8 statusByte;
+	u32 status;
+	u32 i;
+	Scsi_Cmnd *pREQ;
+	unsigned char *request_buffer;
+	PINQUIRYDATA inquiryData;
+
+	pREQ = Srb->pREQ;
+	status = SRB_STATUS_SUCCESS;
+	statusByte = 0;
+	switch (Srb->Cdb[0]) {
+	case SCSIOP_INQUIRY:
+		dprintk("SCSIOP_INQUIRY\n");
+
+		/*
+		 * Filter out all TIDs but 0 and 1 since this is an IDE
+		 * interface which support up to two devices.
+		 */
+		if ((pREQ->device->lun != 0) ||
+		    (!pChan->
+		     DeviceFlags[pREQ->device->
+				 id & 1] & DFLAGS_DEVICE_PRESENT)) {
+
+			/*
+			 * Indicate no device found at this address.
+			 */
+			status = SRB_STATUS_INVALID_TARGET_ID;
+			break;
+		} else {
+			request_buffer = Srb->DataBuffer;
+			inquiryData = Srb->DataBuffer;
+
+			/*
+			 * Zero INQUIRY data structure.
+			 */
+			memset(request_buffer, 0, Srb->DataTransferLength);
+
+			/*
+			 * Standard IDE interface only supports disks.
+			 */
+			inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+
+			/*
+			 * Device type modifer.
+			 */
+			request_buffer[1] = 0;
+
+			/*
+			 * No ANSI/ISO compliance.
+			 */
+			request_buffer[2] = 0;
+
+			/*
+			 * Additional length.
+			 */
+			request_buffer[4] = 31;
+			memcpy(&request_buffer[8], "ITE     ", 8);
+			memcpy(&request_buffer[16], "IT8212F         ", 16);
+			memcpy(&request_buffer[32], DRV_VER_8212, 4);
+
+			/*
+			 * Set the removable bit, if applicable.
+			 */
+			if (pChan->
+			    DeviceFlags[pREQ->device->
+					id & 1] & DFLAGS_REMOVABLE_DRIVE) {
+				inquiryData->RemovableMedia = 1;
+			}
+			status = SRB_STATUS_SUCCESS;
+		}
+		break;
+	case SCSIOP_MODE_SENSE:
+		status = SRB_STATUS_INVALID_REQUEST;
+		break;
+	case SCSIOP_TEST_UNIT_READY:
+		status = SRB_STATUS_SUCCESS;
+		break;
+	case SCSIOP_READ_CAPACITY:
+
+		/*
+		 * Claim 512 byte blocks (big-endian).
+		 */
+		((PREAD_CAPACITY_DATA) Srb->DataBuffer)->BytesPerBlock =
+		    0x20000;
+
+		/*
+		 * Calculate last sector.
+		 */
+		if (pChan->IdentifyData[pREQ->device->id & 0x01].
+		    UserAddressableSectors == 0x0FFFFFFF) {
+			i = pChan->IdentifyData[pREQ->device->id & 0x01].
+			    Capacity_48bit_LOW - 1;
+		} else {
+			i = pChan->IdentifyData[pREQ->device->id & 0x01].
+			    UserAddressableSectors - 1;
+		}
+		((PREAD_CAPACITY_DATA) Srb->DataBuffer)->LogicalBlockAddress =
+		    (((unsigned char *)&i)[0] << 24) |
+		    (((unsigned char *)&i)[1] << 16) |
+		    (((unsigned char *)&i)[2] << 8) | ((unsigned char *)&i)[3];
+		status = SRB_STATUS_SUCCESS;
+		break;
+	case SCSIOP_VERIFY:
+		status = IdeVerify(pChan, Srb);
+		break;
+	case SCSIOP_READ:
+	case SCSIOP_WRITE:
+		status = IT8212ReadWrite(pChan, Srb);
+		break;
+	case SCSIOP_START_STOP_UNIT:
+
+		/*
+		 * Determine what type of operation we should perform
+		 */
+		status = SRB_STATUS_SUCCESS;
+		break;
+	case SCSIOP_REQUEST_SENSE:
+
+		/*
+		 * This function makes sense buffers to report the results
+		 * of the original GET_MEDIA_STATUS command
+		 */
+		status = SRB_STATUS_INVALID_REQUEST;
+		break;
+	default:
+		printk("IdeSendCommand: unsupported command %x\n", Srb->Cdb[0]);
+		status = SRB_STATUS_INVALID_REQUEST;
+	}			/* end switch */
+	return status;
+}				/* end IdeSendCommand */
+
+/************************************************************************
+ * This routine is called from the SCSI port driver synchronized with
+ * the kernel to start an IO request. If the current SRB is busy, return
+ * FALSE, else return TURE.
+ ************************************************************************/
+static void AtapiStartIo(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+	u32 status = 0;
+
+	/*
+	 * Determine which function.
+	 */
+	switch (Srb->Function) {
+	case SRB_FUNCTION_EXECUTE_SCSI:
+
+		/*
+		 * Sanity check. Only one request can be outstanding on a
+		 * controller.
+		 */
+		if (pChan->CurrentSrb) {
+			printk("AtapiStartIo: already have a request!\n");
+			status = SRB_STATUS_BUSY;
+			Srb->SrbStatus = SRB_STATUS_BUSY;
+			goto busy;
+		}
+
+		/*
+		 * Indicate that a request is active on the controller.
+		 */
+		pChan->CurrentSrb = Srb;
+		Srb->SrbStatus = SRB_STATUS_PENDING;
+
+		/*
+		 * Send command to device.
+		 */
+		if (pChan->DeviceFlags[Srb->TargetId & 1] &
+				DFLAGS_ATAPI_DEVICE) {
+
+			/*
+			 * If this is ATAPI device.
+			 */
+			status = AtapiSendCommand(pChan, Srb);
+		} else if (pChan->DeviceFlags[Srb->TargetId & 1] &
+				DFLAGS_DEVICE_PRESENT) {
+
+			/*
+			 * If this is IDE device.
+			 */
+			status = IdeSendCommand(pChan, Srb);
+		} else {
+
+			/*
+			 * Nothing else.
+			 */
+			status = SRB_STATUS_SELECTION_TIMEOUT;
+		}
+		break;
+	case SRB_FUNCTION_IO_CONTROL:
+
+		/*
+		 * IO control function.
+		 */
+		printk("AtapiStartIo: IO control\n");
+		break;
+	default:
+
+		/*
+		 * Indicate unsupported command.
+		 */
+		status = SRB_STATUS_INVALID_REQUEST;
+		break;
+	}			/* end switch */
+busy:
+	if (status != SRB_STATUS_PENDING) {
+
+		/*
+		 * Set status in SRB.
+		 */
+		Srb->SrbStatus = (u8) status;
+		dprintk("AtapiStartIo: status=%x\n", status);
+		TaskDone(pChan, Srb);
+	}
+}				/* end AtapiStartIo */
+
+/************************************************************************
+ * Convert Scsi_Cmnd structure to SCSI_REQUEST_BLOCK.
+ ************************************************************************/
+static void MapRequest(Scsi_Cmnd * pREQ, PSCSI_REQUEST_BLOCK Srb)
+{
+	Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+	Srb->CdbLength = pREQ->cmd_len;
+	Srb->TargetId = pREQ->device->id;
+	Srb->Lun = pREQ->device->lun;
+	Srb->UseSg = pREQ->use_sg;
+
+	/*
+	 * Copy the actual command from Scsi_Cmnd to CDB.
+	 */
+	memcpy(Srb->Cdb, pREQ->cmnd, Srb->CdbLength);
+
+	/*
+	 * Always the SCSI_FUNCTION_EXECUTE_SCSI now.
+	 */
+	Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+	Srb->SrbStatus = 0;
+	Srb->ScsiStatus = 0;
+	Srb->SenseInfoBufferLength = 16;
+
+	/*
+	 * The CDB's first byte is operation code.
+	 */
+	if ((Srb->Cdb[0] == SCSIOP_WRITE6) || (Srb->Cdb[0] == SCSIOP_WRITE)
+	    || (Srb->Cdb[0] == SCSIOP_MODE_SELECT10)) {
+		Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
+	} else {
+		Srb->SrbFlags = SRB_FLAGS_DATA_IN;
+	}
+	Srb->TimeOutValue = 0;
+	Srb->SenseInfoBuffer = pREQ->sense_buffer;
+	if (Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
+		Srb->DataTransferLength = 0x40;
+		Srb->DataBuffer = pREQ->sense_buffer;
+	} else {
+		Srb->DataTransferLength = pREQ->request_bufflen;
+		Srb->DataBuffer = pREQ->request_buffer;
+	}
+
+	if (pREQ->use_sg) {
+		Srb->WorkingFlags |= SRB_WFLAGS_USE_SG;
+	}
+	Srb->pREQ = pREQ;
+}				/* end MapRequest */
+
+/************************************************************************
+ * A task execution has been done. For OS request, we need to Notify OS
+ * and invoke next take which wait at queue.
+ ************************************************************************/
+static void TaskDone(PChannel pChan, PSCSI_REQUEST_BLOCK Srb)
+{
+	Scsi_Cmnd *pREQ = Srb->pREQ;
+	pChan->CurrentSrb = NULL;
+	pChan->RetryCount = 0;
+	switch (SRB_STATUS(Srb->SrbStatus)) {
+	case SRB_STATUS_SUCCESS:
+		pREQ->result = (DID_OK << 16);
+		break;
+	case SRB_STATUS_SELECTION_TIMEOUT:
+		pREQ->result = (DID_NO_CONNECT << 16);
+		break;
+	case SRB_STATUS_BUSY:
+		pREQ->result = (DID_BUS_BUSY << 16);
+		break;
+	case SRB_STATUS_BUS_RESET:
+		pREQ->result = (DID_RESET << 16);
+		break;
+	case SRB_STATUS_INVALID_TARGET_ID:
+	case SRB_STATUS_INVALID_PATH_ID:
+	case SRB_STATUS_INVALID_LUN:
+	case SRB_STATUS_NO_HBA:
+		pREQ->result = (DID_BAD_TARGET << 16);
+		break;
+	case SRB_STATUS_NO_DEVICE:
+		pREQ->result = (DID_BAD_TARGET << 16);
+		break;
+	case SRB_STATUS_ERROR:
+		pREQ->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
+		    (CHECK_CONDITION << 1);
+		break;
+	}
+	dprintk("TaskDone(pChan=%p, pREQ=%p, result=%x)\n", pChan, pREQ,
+		pREQ->result);
+
+	/*
+	 * Notify OS that this OS request has been done.
+	 */
+	pREQ->scsi_done(pREQ);
+
+	/*
+	 * Check the queue again.
+	 */
+	TaskQueue();
+}				/* end TaskDone */
+
+/************************************************************************
+ * Start a command, doing convert first.
+ ************************************************************************/
+static void TaskStart(PChannel pChan, Scsi_Cmnd * pREQ)
+{
+	PSCSI_REQUEST_BLOCK Srb;
+	dprintk("TaskStart(pChan=%p, pREQ=%p)\n", pChan, pREQ);
+	Srb = &pChan->_Srb;
+
+	/*
+	 * Clear the SRB structure.
+	 */
+	memset(Srb, 0, sizeof(SCSI_REQUEST_BLOCK));
+
+	/*
+	 * Convert Scsi_Cmnd structure to SCSI_REQUEST_BLOCK.
+	 */
+	MapRequest(pREQ, Srb);
+
+	/*
+	 * Start IDE I/O command.
+	 */
+	AtapiStartIo(pChan, Srb);
+}				/* end TaskStart */
+
+/************************************************************************
+ * Check if queue is empty. If there are request in queue, transfer the
+ * request to HIM's request and execute the request.
+ ************************************************************************/
+static void TaskQueue(void)
+{
+	unsigned long flags;
+	Scsi_Cmnd *SCpnt;
+	PChannel pChan;
+	PITE_ADAPTER pAdap;
+
+check_next:
+	if (it8212_req_last != NULL) {
+		spin_lock_irqsave(&queue_request_lock, flags);
+
+		SCpnt = (Scsi_Cmnd *) it8212_req_last->SCp.ptr;
+		if (it8212_req_last == SCpnt)
+			it8212_req_last = NULL;
+		else
+			it8212_req_last->SCp.ptr = (char *)SCpnt->SCp.ptr;
+
+		spin_unlock_irqrestore(&queue_request_lock, flags);
+
+		/*
+		 * Check the command.
+		 */
+		if (SCpnt->device->host) {
+			if ((SCpnt->device->channel != 0) ||
+			    (SCpnt->device->id >= (4 * NumAdapters))) {
+
+				/*
+				 * Returns that we have a bad target.
+				 */
+				SCpnt->result = (DID_BAD_TARGET << 16);
+				SCpnt->scsi_done(SCpnt);
+				goto check_next;
+			}
+		}
+		if (SCpnt->device->id >= 4) {
+			pAdap = ite_adapters[1];
+			if (SCpnt->device->id < 6)
+				pChan = &pAdap->IDEChannel[0];
+
+			else
+				pChan = &pAdap->IDEChannel[1];
+		} else {
+			pAdap = ite_adapters[0];
+			if (SCpnt->device->id < 2)
+				pChan = &pAdap->IDEChannel[0];
+
+			else
+				pChan = &pAdap->IDEChannel[1];
+		}
+		TaskStart(pChan, SCpnt);
+		return;
+	}
+}				/* end TaskQueue */
+
+/****************************************************************
+ * Name:	iteraid_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 iteraid_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+	unsigned long flags;
+	dprintk("##Queuecommand enter##\n");
+
+	/*
+	 * Hooks the done routine.
+	 */
+	SCpnt->scsi_done = (void *)done;
+	spin_lock_irqsave(&queue_request_lock, flags);
+	if (it8212_req_last == NULL) {
+		SCpnt->SCp.ptr = (char *)SCpnt;
+	} else {
+		SCpnt->SCp.ptr = it8212_req_last->SCp.ptr;
+		it8212_req_last->SCp.ptr = (char *)SCpnt;
+	}
+	it8212_req_last = SCpnt;
+	spin_unlock_irqrestore(&queue_request_lock, flags);
+	TaskQueue();
+	dprintk("@@Queuecommand exit@@\n");
+	return 0;
+}				/* end iteraid_queuecommand */
+
+#if 0
+/****************************************************************
+ * Name:	internal_done :LOCAL
+ * Description:	Done handler for non-queued commands
+ * Parameters:	SCpnt - Pointer to SCSI command structure.
+ * Returns:	Nothing.
+ ****************************************************************/
+static void internal_done(Scsi_Cmnd * SCpnt)
+{
+	SCpnt->SCp.Status++;
+}				/* end internal_done */
+#endif
+
+#if 0
+/****************************************************************
+ * Name:	iteraid_command
+ * Description:	Process a command from the SCSI manager.
+ * Parameters:	SCpnt - Pointer to SCSI command structure.
+ * Returns:	Status code.
+ ****************************************************************/
+static int iteraid_command(Scsi_Cmnd * SCpnt)
+{
+	unsigned long timeout;
+	SCpnt->SCp.Status = 0;
+	iteraid_queuecommand(SCpnt, internal_done);
+
+	/*
+	 * Should be longer than hard-reset time.
+	 */
+	timeout = jiffies + 60 * HZ;
+	while (!SCpnt->SCp.Status && time_before(jiffies, timeout))
+		barrier();
+	if (!SCpnt->SCp.Status)
+		SCpnt->result = (DID_ERROR << 16);
+	return SCpnt->result;
+}				/* end iteraid_command */
+#endif
+
+/************************************************************************
+ * Enables/disables media status notification.
+ ************************************************************************/
+#if 0
+static void IdeMediaStatus(u8 EnableMSN, PChannel pChan, u8 Device)
+{
+	u8 statusByte;
+	u8 errorByte;
+	statusByte = 0;
+	if (EnableMSN == TRUE) {
+
+		/*
+		 * If supported enable Media Status Notification support.
+		 */
+		if ((pChan->DeviceFlags[Device] & DFLAGS_REMOVABLE_DRIVE)) {
+			outb((u8) (0x95), pChan->io_ports[IDE_FEATURE_OFFSET]);
+			outb(IDE_COMMAND_ENABLE_MEDIA_STATUS,
+			     pChan->io_ports[IDE_COMMAND_OFFSET]);
+			WaitOnBaseBusy(pChan, statusByte);
+			if (statusByte & IDE_STATUS_ERROR) {
+
+				/*
+				 * Read the error register.
+				 */
+				errorByte =
+				    inb(pChan->io_ports[IDE_ERROR_OFFSET]);
+				printk("IdeMediaStatus: error enabling media "
+					"status. status %u, error byte %u\n",
+					statusByte, errorByte);
+			} else {
+				pChan->DeviceFlags[Device] |=
+				    DFLAGS_MEDIA_STATUS_ENABLED;
+				printk("IdeMediaStatus: media status "
+					"notification supported!\n");
+				pChan->ReturningMediaStatus = 0;
+			}
+		}
+	} else {			/* end if EnableMSN == TRUE */
+
+		/*
+		 * Disable if previously enabled.
+		 */
+		if ((pChan->DeviceFlags[Device] &
+				DFLAGS_MEDIA_STATUS_ENABLED)) {
+			outb((u8) (0x31), pChan->io_ports[IDE_FEATURE_OFFSET]);
+			outb(IDE_COMMAND_ENABLE_MEDIA_STATUS,
+			     pChan->io_ports[IDE_COMMAND_OFFSET]);
+			WaitOnBaseBusy(pChan, statusByte);
+			pChan->DeviceFlags[Device] &=
+			    ~DFLAGS_MEDIA_STATUS_ENABLED;
+		}
+	}
+}				/* end IdeMediaStatus */
+
+#endif				/*  */
+/************************************************************************
+ * Issue IDENTIFY command to a device.
+ * Either the standard (EC) or the ATAPI packet (A1) IDENTIFY.
+ ************************************************************************/
+static u8 IssueIdentify(PChannel pChan, u8 DeviceNumber, u8 Command)
+{
+	u8 statusByte = 0;
+	u32 i;
+	u32 j;
+
+	/*
+	 * Check that the status register makes sense.
+	 */
+	GetBaseStatus(pChan, statusByte);
+	if (Command == IDE_COMMAND_IDENTIFY) {
+
+		/*
+		 * Mask status byte ERROR bits.
+		 */
+		statusByte &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX);
+		dprintk("IssueIdentify: checking for IDE. status (%x)\n",
+			statusByte);
+
+		/*
+		 * Check if register value is reasonable.
+		 */
+		if (statusByte != IDE_STATUS_IDLE) {
+
+			/*
+			 * Reset the channel.
+			 */
+			printk("IssueIdentify: resetting channel.\n");
+			IdeHardReset(pChan, statusByte);
+			outb((u8) ((DeviceNumber << 4) | 0xA0),
+			     pChan->io_ports[IDE_SELECT_OFFSET]);
+			GetBaseStatus(pChan, statusByte);
+			statusByte &= ~IDE_STATUS_INDEX;
+			if (statusByte != IDE_STATUS_IDLE) {
+
+				/*
+				 * Give up on this.
+				 */
+				printk("IssueIdentify(IDE): disk[%d] not "
+					"ready. status=0x%x\n",
+					DeviceNumber, statusByte);
+				return FALSE;
+			}
+		}
+	} else {
+		dprintk("IssueIdentify: checking for ATAPI. status (%x)\n",
+			statusByte);
+		if ((statusByte & IDE_STATUS_BUSY)
+		    || (statusByte & IDE_STATUS_DRQ)) {
+
+			/*
+			 * Reset the device.
+			 */
+			dprintk("IssueIdentify: resetting device.\n");
+			AtapiSoftReset(pChan, DeviceNumber);
+			outb((u8) ((DeviceNumber << 4) | 0xA0),
+			     pChan->io_ports[IDE_SELECT_OFFSET]);
+			GetBaseStatus(pChan, statusByte);
+			if (statusByte != 0) {
+
+				/*
+				 * Give up on this.
+				 */
+				printk("IssueIdentify(ATAPI): disk[%d] not "
+					"ready. status=0x%x\n",
+					DeviceNumber, statusByte);
+				return FALSE;
+			}
+		}
+	}
+	for (j = 0; j < 2; j++) {
+
+		/*
+		 * Wait for device ready (Not Busy and Not DRQ).
+		 */
+		outb((u8) ((DeviceNumber << 4) | 0xA0),
+		     pChan->io_ports[IDE_SELECT_OFFSET]);
+		WaitForDeviceReady(pChan, statusByte);
+		if ((statusByte & IDE_STATUS_BUSY)
+		    || (statusByte & IDE_STATUS_DRQ)) {
+			printk
+			    ("IssueIdentify: disk[%d] not ready. status=0x%x\n",
+			     DeviceNumber, statusByte);
+			continue;
+		}
+
+		/*
+		 * Send IDENTIFY command.
+		 */
+		outb(Command, pChan->io_ports[IDE_COMMAND_OFFSET]);
+
+		/*
+		 * Wait for DRQ.
+		 */
+		WaitForBaseDrq(pChan, statusByte);
+		if (!(statusByte & IDE_STATUS_DRQ)) {
+			printk("IssueIdentify: disk[%d] DRQ never asserted. "
+				"status=%x\n", DeviceNumber, statusByte);
+
+			/*
+			 * Give one more chance.
+			 */
+			if (Command == IDE_COMMAND_IDENTIFY)
+				IdeHardReset(pChan, statusByte);
+			else
+				AtapiSoftReset(pChan, DeviceNumber);
+		} else {
+			break;
+		}
+	}
+
+	/*
+	 * Check for error on really stupid master devices that assert random
+	 * patterns of bits in the status register at the slave address.
+	 */
+	outb((u8) ((DeviceNumber << 4) | 0xA0),
+	     pChan->io_ports[IDE_SELECT_OFFSET]);
+	GetBaseStatus(pChan, statusByte);
+	if (statusByte & IDE_STATUS_ERROR) {
+		printk("IssueIdentify: disk[%d] returns error status\n",
+		       DeviceNumber);
+		return FALSE;
+	}
+	dprintk("IssueIdentify: status before read words %x\n", statusByte);
+
+	/*
+	 * Suck out 256 words. After waiting for one model that asserts busy
+	 * after receiving the Packet Identify command.
+	 */
+	WaitOnBusy(pChan, statusByte);
+	if (!(statusByte & IDE_STATUS_DRQ)) {
+		return FALSE;
+	}
+	ReadBuffer(pChan, (unsigned short *)&pChan->FullIdentifyData, 256);
+
+	/*
+	 * Check out a few capabilities / limitations of the device.
+	 * 01/29/2003
+	 */
+	if (pChan->FullIdentifyData.SpecialFunctionsEnabled & 1) {
+
+		/*
+		 * Determine if this drive supports the MSN functions.
+		 */
+		printk("Marking drive %x as removable. SFE = %x\n",
+		       DeviceNumber,
+		       pChan->FullIdentifyData.SpecialFunctionsEnabled);
+		pChan->DeviceFlags[DeviceNumber] |= DFLAGS_REMOVABLE_DRIVE;
+	}
+	memcpy(&pChan->IdentifyData[DeviceNumber], &pChan->FullIdentifyData,
+	       sizeof(IDENTIFY_DATA2));
+	if (pChan->IdentifyData[DeviceNumber].GeneralConfiguration & 0x20
+	    && Command != IDE_COMMAND_IDENTIFY) {
+
+		/*
+		 * This device interrupts with the assertion of DRQ after
+		 * receiving Atapi Packet Command.
+		 */
+		pChan->DeviceFlags[DeviceNumber] |= DFLAGS_INT_DRQ;
+		dprintk(KERN_NOTICE "Device interrupts on assertion of DRQ.\n");
+	} else {
+		dprintk(KERN_NOTICE
+			"Device does't interrupt on assertion of DRQ.\n");
+	}
+	if (((pChan->IdentifyData[DeviceNumber].
+	      GeneralConfiguration & 0xF00) == 0x100)
+	    && Command != IDE_COMMAND_IDENTIFY) {
+
+		/*
+		 * This is a tape.
+		 */
+		pChan->DeviceFlags[DeviceNumber] |= DFLAGS_TAPE_DEVICE;
+		printk(KERN_NOTICE "IssueIdentify: device is a tape drive.\n");
+	} else {
+		dprintk(KERN_NOTICE
+			"IssueIdentify: device is not a tape drive.\n");
+	}
+
+	/*
+	 * Work around for some IDE and one model Atapi that will present more
+	 * then 256 bytes for the Identify data.
+	 */
+	WaitOnBaseBusy(pChan, statusByte);
+	for (i = 0; i < 0x10000; i++) {
+		GetStatus(pChan, statusByte);
+		if (statusByte & IDE_STATUS_DRQ) {
+
+			/*
+			 * Suck out any remaining bytes and throw away.
+			 */
+			inw(pChan->io_ports[IDE_DATA_OFFSET]);
+		} else {
+			break;
+		}
+	}
+	return TRUE;
+}				/* end IssueIdentify() */
+
+/************************************************************************
+ * Check this is the IDE or ATAPI disk then identify it.
+ ************************************************************************/
+static u8 iteraid_find_device(PChannel pChan, u8 channel)
+{
+	u8 deviceNumber;
+	u8 signatureLow;
+	u8 signatureHigh;
+	u8 deviceResponded = FALSE;
+	u8 statusByte = 0;
+
+	/*
+	 * Clear expecting interrupt flag and current SRB field.
+	 */
+	pChan->ExpectingInterrupt = FALSE;
+	pChan->CurrentSrb = NULL;
+
+	/*
+	 * Search for devices in each channel.
+	 */
+	for (deviceNumber = 0; deviceNumber < 2; deviceNumber++) {
+
+		/*
+		 * Select the device.
+		 */
+		outb((u8) ((deviceNumber << 4) | 0xA0),
+		     pChan->io_ports[IDE_SELECT_OFFSET]);
+
+		/*
+		 * Disable interrupts during initialization.
+		 */
+		outb(IDE_DC_DISABLE_INTERRUPTS,
+		     pChan->io_ports[IDE_CONTROL_OFFSET]);
+
+		/*
+		 * Check here for some SCSI adapters that incorporate IDE
+		 * emulation.
+		 */
+		statusByte = inb(pChan->io_ports[IDE_CONTROL_OFFSET]);
+
+		/*
+		 * Do soft reset on selected device. (AtapiSoftReset)
+		 */
+		AtapiSoftReset(pChan, deviceNumber);
+		WaitOnBusy(pChan, statusByte);
+		signatureLow = inb(pChan->io_ports[IDE_MIDCYL_OFFSET]);
+		signatureHigh = inb(pChan->io_ports[IDE_HCYL_OFFSET]);
+		if (signatureLow == 0x14 && signatureHigh == 0xEB) {
+
+			/*
+			 * ATAPI signature found. Issue ATAPI packet identify
+			 * command.
+			 */
+			if (IssueIdentify(pChan, deviceNumber,
+					IDE_COMMAND_ATAPI_IDENTIFY)) {
+
+				/*
+				 * Indicate ATAPI device.
+				 */
+				printk("iteraid_find_device: channel %x "
+					"device %x is ATAPI.\n",
+					channel, deviceNumber);
+				pChan->DeviceFlags[deviceNumber] |=
+				    DFLAGS_ATAPI_DEVICE;
+				pChan->DeviceFlags[deviceNumber] |=
+				    DFLAGS_DEVICE_PRESENT;
+				pChan->DeviceFlags[deviceNumber] &=
+				    ~DFLAGS_CONFIG_CHANGED;
+				deviceResponded = TRUE;
+				GetStatus(pChan, statusByte);
+				if (statusByte & IDE_STATUS_ERROR) {
+					AtapiSoftReset(pChan, deviceNumber);
+				}
+			} else {
+
+				/*
+				 * Indicate no working device.
+				 */
+				printk("iteraid_find_device: channel %x device "
+					"%x doesn't respond.\n",
+					channel, deviceNumber);
+				pChan->DeviceFlags[deviceNumber] &=
+				    ~DFLAGS_DEVICE_PRESENT;
+			}
+		} else {
+
+			/*
+			 * Select the device.
+			 */
+			outb((u8) ((deviceNumber << 4) | 0xA0),
+			     pChan->io_ports[IDE_SELECT_OFFSET]);
+
+			/*
+			 * Check here for some SCSI adapters that incorporate
+			 * IDE emulation.
+			 */
+			GetStatus(pChan, statusByte);
+
+			/*
+			 * No Disk.
+			 */
+			if (statusByte == 0xFF || statusByte == 0x7F
+			    || statusByte == 0x0) {
+				dprintk("FindDevices: cannot find IDE device. "
+					"status = %x\n", statusByte);
+				continue;
+			}
+
+			/*
+			 * Issue IDE Identify. If an ATAPI device is actually
+			 * present, the signature will be asserted, and the
+			 * drive will be recognized as such.
+			 */
+			if (IssueIdentify(pChan, deviceNumber,
+					IDE_COMMAND_IDENTIFY)) {
+
+				/*
+				 * IDE drive found.
+				 */
+				printk(KERN_WARNING
+				       "FindDevices: device %u is IDE\n",
+				       (channel * 2) + deviceNumber);
+				pChan->DeviceFlags[deviceNumber] |=
+				    DFLAGS_DEVICE_PRESENT;
+				pChan->DeviceFlags[deviceNumber] &=
+				    ~DFLAGS_ATAPI_DEVICE;
+				pChan->DeviceFlags[deviceNumber] &=
+				    ~DFLAGS_CONFIG_CHANGED;
+				deviceResponded = TRUE;
+			} else {
+				printk(KERN_WARNING
+				       "FindDevices: device %u is not present\n",
+				       (channel * 2) + deviceNumber);
+				pChan->DeviceFlags[deviceNumber] &=
+				    ~DFLAGS_DEVICE_PRESENT;
+			}
+		}
+	}
+	return deviceResponded;
+}				/* end iteraid_find_device */
+
+#if 0
+/************************************************************************
+ * IDE disk hardware initialize.
+ ************************************************************************/
+static u8 AtapiHwInitialize(PITE_ADAPTER pAdap, PChannel pChan, u8 channel)
+{
+	u8 i;
+	u8 statusByte = 0;
+
+	/*
+	 * For two devices in this channel.
+	 */
+	for (i = 0; i < 2; i++) {
+
+		/*
+		 * only check in Fireware mode.
+		 */
+		if (pAdap->bypass_mode == FALSE) {
+			outb((u8) (0xA0 | ((u8) i << 4)),
+			     pChan->io_ports[IDE_SELECT_OFFSET]);
+
+			/*
+			 * Check if card at this address.
+			 */
+			outb(0xAA, pChan->io_ports[IDE_MIDCYL_OFFSET]);
+
+			/*
+			 * Check if indentifier can be read back.
+			 */
+			if ((statusByte =
+			     inb(pChan->io_ports[IDE_MIDCYL_OFFSET])) != 0xAA) {
+				printk("AtapiHwInitialize: identifier read "
+					"back from (%x, %x) = %x\n",
+					channel, i, statusByte);
+
+				/*
+				 * ***** Dont free it....For later use *****
+				 * ScsiPortFreeDeviceBase(HwDeviceExtension,
+				 * ioSpace1);
+				 */
+				continue;
+			}
+			printk("AtapiHwInitialize: found ATA device (%x, %x)n",
+			     channel, i);
+		}
+	}
+	return TRUE;
+}				/* end AtapiHwInitialize */
+#endif
+
+/************************************************************************
+ * Initialize a adapter, return 0 means success.
+ ************************************************************************/
+static int iteraid_init(PITE_ADAPTER pAdap, struct pci_dev *pPciDev)
+{
+	u8 z;
+	u8 i;
+	u8 j;
+	u8 set_irq;
+	unsigned long control_addr;	/* Control reg base address     */
+	unsigned long base_addr;	/* IDE I/O port base address    */
+	unsigned long bm_base_addr;	/* Bus Master base address      */
+	PChannel pChan;		/* Use for each channel         */
+	dprintk("iteraid_init enter\n");
+
+	/*
+	 * Common settings.
+	 */
+	pAdap->pci_bus = pPciDev->bus->number;
+	pAdap->devfn = pPciDev->devfn;
+	pAdap->irq = pPciDev->irq;
+	pAdap->irqOwned = 0;
+	printk(KERN_NOTICE "Found Controller: %s\n", pAdap->name);
+
+	/*
+	 * Allocate buffer for IDE channles (One IT8212 supports two channels)
+	 */
+	pAdap->IDEChannel =
+	    (PChannel) kmalloc(sizeof(Channel) * pAdap->num_channels,
+			       GFP_ATOMIC);
+	if (pAdap->IDEChannel == 0) {
+		printk("iteraid_init: pChan allocate failed.\n");
+		return -1;
+	}
+	memset(pAdap->IDEChannel, 0, sizeof(Channel) * pAdap->num_channels);
+	set_irq = 1;
+	for (i = 0; i < NumAdapters; i++) {
+		if (ite_adapters[i]->irqOwned == pAdap->irq)
+			set_irq = 0;
+	}
+
+	/*
+	 * Request the irq (share irq) and hook the interrupt service routine.
+	 */
+	if (set_irq) {
+		if (request_irq
+		    (pAdap->irq, Irq_Handler, SA_SHIRQ, PROC_DIR_NAME,
+		     pAdap) < 0) {
+			printk("iteraid_init: unable to allocate IRQ for %s\n",
+			       pAdap->name);
+			return -1;
+		}
+		pAdap->irqOwned = pAdap->irq;
+	}
+
+	/*
+	 * Get the IDE port and DMA registers.
+	 */
+	for (i = 0; i < pAdap->num_channels; i++) {
+		pChan = &pAdap->IDEChannel[i];
+
+		/*
+		 * Reference the book "LINUX DEVICE DRIVER 2nd", Page 484
+		 * unsigned long pci_resource_start(struct pci_dev *dev,
+		 * int bar);
+		 */
+		base_addr = pci_resource_start(pPciDev, i * 2);
+		control_addr = pci_resource_start(pPciDev, i * 2 + 1);
+		bm_base_addr = pci_resource_start(pPciDev, 4);
+		pChan->dma_base = bm_base_addr + i * 8;
+		for (j = 0; j <= IDE_STATUS_OFFSET; j++) {
+			pChan->io_ports[j] = base_addr;
+			base_addr += 1;
+		}
+		pChan->io_ports[IDE_CONTROL_OFFSET] = control_addr + 2;
+	}
+
+	/*
+	 * Initialize channels.
+	 */
+	for (z = 0; z < pAdap->num_channels; z++) {
+		pChan = &pAdap->IDEChannel[z];
+		pChan->pPciDev = pPciDev;
+		pChan->channel = z;
+
+		/*
+		 * This section should be masked off if BIOS is ready.
+		 */
+#if (MARK_DEBUG_BYPASS_MODE)
+		/*
+		 * BIOS is not ready, so I change to ByPass Mode by myself.
+		 */
+		pAdap->bypass_mode = TRUE;
+
+		/*
+		 * Change to bypass mode.
+		 */
+		IT8212InitBypassMode(pPciDev);
+
+#endif
+
+		/*
+		 * Hardware initialize.
+		 */
+#if (0)
+		AtapiHwInitialize(pAdap, pChan, z);
+
+#endif
+
+		/*
+		 * Find and identify the IDE or ATAPI device.
+		 */
+		iteraid_find_device(pChan, z);
+
+		/*
+		 * Set the best transfer mode.
+		 */
+#if (MARK_SET_BEST_TRANSFER)
+		IT8212SetBestTransferMode(pAdap, pChan, z);
+
+#endif
+
+		/*
+		 * Set Scatter/Gather List buffer for the channel.
+		 */
+		IdeSetupDma(pChan, pChan->dma_base, 8);
+	}
+	dprintk("iteraid_init exit\n");
+	return 0;
+}				/* end iteraid_init */
+
+/************************************************************************
+ * This function will find and initialize any cards.
+ ************************************************************************/
+static int iteraid_detect(Scsi_Host_Template * tpnt)
+{
+	u8 i;
+	u8 j;
+	u8 mode;
+	u8 pci_id;
+	PChannel pChan;
+	PITE_ADAPTER pAdap;
+	struct pci_dev *pPciDev;
+	dprintk("iteraid_detect enter\n");
+
+	/*
+	 * Search ITE IT8212 chip.
+	 */
+	pPciDev = NULL;
+	pci_id = 0;
+	while ((pPciDev =
+		pci_find_device(ITE_VENDOR_ID, ITE_DEVICE_ID, pPciDev))) {
+		if (PCI_FUNC(pPciDev->devfn))
+			continue;
+
+		if (pci_enable_device(pPciDev))
+			continue;
+
+		/*
+		 * Allocate memory for Adapter.
+		 */
+		pAdap = (PITE_ADAPTER) kmalloc(sizeof(ITE_ADAPTER), GFP_ATOMIC);
+		if (pAdap == NULL) {
+			printk("iteraid_detect: pAdap allocate failed.\n");
+			pci_disable_device(pPciDev);
+			continue;
+		}
+		memset(pAdap, 0, sizeof(ITE_ADAPTER));
+		pAdap->name = CONTROLLER_NAME_IT8212;
+		pAdap->num_channels = 2;
+		pAdap->pci_dev = pPciDev;
+
+		/*
+		 * Check if we are in bypass(transparent) or firmware mode.
+		 */
+		pci_read_config_byte(pPciDev, 0x50, &mode);
+		if (mode & 1) {
+			dprintk("Firmware mode in PCI#%d\n", pci_id);
+			pAdap->bypass_mode = FALSE;
+		} else {
+			dprintk("Transparent mode in PCI#%d\n", pci_id);
+			pAdap->bypass_mode = TRUE;
+		}
+		if (iteraid_init(pAdap, pPciDev) == 0)
+			ite_adapters[NumAdapters++] = pAdap;
+		pci_id++;
+	}
+
+	/*
+	 * Reenable interrupt after initialization. 2003/04/28
+	 */
+	for (i = 0; i < NumAdapters; i++) {
+		pAdap = ite_adapters[i];
+		for (j = 0; j < pAdap->num_channels; j++) {
+			pChan = &pAdap->IDEChannel[j];
+			outb(IDE_DC_REENABLE_CONTROLLER,
+			     pChan->io_ports[IDE_CONTROL_OFFSET]);
+		}
+	}
+	if (NumAdapters) {
+
+		/*
+		 * Register a virtual host.
+		 */
+		ite_vhost = scsi_register(tpnt, 0);
+		ite_vhost->io_port = 0;
+		ite_vhost->n_io_port = 0;
+		ite_vhost->max_channel = 0;
+		ite_vhost->max_id = MAX_DEVICES;
+		ite_vhost->max_lun = 1;
+
+#if (0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		scsi_set_device(ite_vhost, &pPciDev->dev);
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
+		scsi_set_pci_device(ite_vhost, pPciDev);
+
+#endif
+#endif
+
+		/*
+		 * Register the driver as a character device, for applications
+		 * to access it for ioctls. Ideally, this should go in the
+		 * init_module() routine, but since it is hidden in the file
+		 * "scsi_module.c" (included in the end), we define it here.
+		 * First argument (major) to register_chrdev implies a dynamic
+		 * major number allocation.
+		 */
+		ite_major = register_chrdev(0, "itedev", &itedev_fops);
+
+		/*
+		 * Register the Shutdown Notification hook in the kernel.
+		 */
+		register_reboot_notifier(&ite_notifier);
+
+		/*
+		 * Initialize ioctl semphore.
+		 */
+		init_MUTEX(&mimd_entry_mtx);
+	}
+	dprintk("iteraid_detect exit\n");
+	return 1;
+}				/* end iteraid_detect() */
+
+/************************************************************************
+ * Name:	iteraid_release
+ * Description:	Release resources allocated for a single each adapter.
+ * Parameters:	pshost - Pointer to SCSI command structure.
+ * Returns:	zero.
+ ************************************************************************/
+static int iteraid_release(struct Scsi_Host *pshost)
+{
+	u8 i;
+	PITE_ADAPTER pAdap;
+
+	/*
+	 * Unregister the character device.
+	 */
+	if (ite_major > 0) {
+		unregister_chrdev(ite_major, "itedev");
+		ite_major = -1;
+	}
+
+	/*
+	 * Free irq and memory.
+	 */
+	for (i = 0; i < NumAdapters; i++) {
+		pAdap = ite_adapters[i];
+		if (pAdap->irqOwned)
+			free_irq(pAdap->irq, pAdap);
+		if (pAdap->IDEChannel != NULL) {
+			kfree(pAdap->IDEChannel);
+		}
+		pci_disable_device(pAdap->pci_dev);
+		if (pAdap != NULL) {
+			kfree(pAdap);
+		}
+	}
+
+	/*
+	 * Unregister the reboot notifier.
+	 */
+	unregister_reboot_notifier(&ite_notifier);
+
+	/*
+	 * Tell kernel scsi-layer we are gone.
+	 */
+	scsi_unregister(pshost);
+	return 0;
+}				/* end iteraid_Release */
+
+/************************************************************************
+ * This is the new scsi eh reset function.
+ ************************************************************************/
+static int iteraid_reset_eh(Scsi_Cmnd * SCpnt)
+{
+	u8 i;
+	u8 j;
+	PChannel pChan;
+	PITE_ADAPTER pAdap;
+
+	if (SCpnt == NULL) {
+		printk("iteraid_reset_eh: invalid Scsi_Cmnd\n");
+		return FAILED;
+	}
+	for (i = 0; i < NumAdapters; i++) {
+		pAdap = ite_adapters[i];
+		for (j = 0; j < pAdap->num_channels; j++) {
+			pChan = &pAdap->IDEChannel[j];
+			AtapiResetController(pAdap, pChan);
+		}
+	}
+	return SUCCESS;
+}				/* end iteraid_reset_eh */
+
+/************************************************************************
+ * The new error handling code.
+ ************************************************************************/
+static int iteraid_abort_eh(Scsi_Cmnd * SCpnt)
+{
+	if (SCpnt == NULL) {
+		printk("iteraid_reset_eh: invalid Scsi_Cmnd\n");
+		return FAILED;
+	}
+	return SUCCESS;
+}				/* end iteraid_abort_eh */
+
+/************************************************************************
+ * Name:	iteraid_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 iteraid_biosparam(struct scsi_device *sdev,
+		struct block_device *bdev, sector_t capacity, int geom[])
+{
+	int heads;
+	int sectors;
+	int cylinders;
+
+	/*
+	 * Default heads (64) & sectors (32)
+	 * Handle extended translation size for logical drives > 1Gb
+	 */
+	if (capacity >= 0x200000) {
+		heads = 255;
+		sectors = 63;
+	} else {
+		heads = 64;
+		sectors = 32;
+	}
+	cylinders = (unsigned long)capacity / (heads * sectors);
+
+	/*
+	 * Return result
+	 */
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+	return 0;
+}				/* end iteraid_biosparam */
+
+/************************************************************************
+ * Shutdown routine.
+ ************************************************************************/
+static int ite_halt(struct notifier_block *nb, ulong event, void *buf)
+{
+	if (event != SYS_RESTART && event != SYS_HALT &&
+			event != SYS_POWER_OFF) {
+		return NOTIFY_DONE;
+	}
+	unregister_reboot_notifier(&ite_notifier);
+	return NOTIFY_OK;
+}				/* end ite_halt */
+
+/************************************************************************
+ * PROC information.
+ ************************************************************************/
+static int iteraid_proc_info(struct Scsi_Host *shost, char *buffer,
+			char **start, off_t offset, int length, int inout)
+{
+	return 0;
+}				/* end iteraid_proc_info */
+
+/************************************************************************
+ * IOCTL open entry.
+ ************************************************************************/
+static int itedev_open(struct inode *inode, struct file *filep)
+{
+
+	//MOD_INC_USE_COUNT;
+	return 0;
+}				/* end itedev_open */
+
+/************************************************************************
+ * IOCTL code entry.
+ ************************************************************************/
+static int itedev_ioctl_entry(struct inode *inode, struct file *filep,
+				unsigned int cmd, unsigned long arg)
+{
+	int ret = -1;
+
+	/*
+	 * We do not allow parallel ioctls to the driver as of now.
+	 */
+	down(&mimd_entry_mtx);
+	ret = itedev_ioctl(inode, filep, cmd, arg);
+	up(&mimd_entry_mtx);
+	return ret;
+}				/* end itedev_ioctl_entry */
+
+/************************************************************************
+ * Real IOCTL function handles ioctl for the character device.
+ ************************************************************************/
+static int itedev_ioctl(struct inode *inode, struct file *filep,
+			unsigned int cmd, unsigned long arg)
+{
+	u8 diskArrayId;
+	u8 statusByte = 0;
+	u8 srbStatus;
+	u8 progress = 0;
+	u8 status = 0;
+	uioctl_t *pioc;
+	PITE_ADAPTER pAdap;
+	PChannel pChan;
+	PRAID_REBUILD_INFO rebuild_info;
+	dprintk("itedev_ioctl enter\n");
+
+	/*
+	 * Extract the type and number bitfield.
+	 */
+	if (_IOC_TYPE(cmd) != ITE_IOCMAGIC)
+		return -EINVAL;
+
+	/*
+	 * Allocate space for ioctl data structure.
+	 */
+	if ((pioc = kmalloc(sizeof(uioctl_t), GFP_KERNEL)) == NULL) {
+		printk("itedev_ioctl: error kmalloc on ioctl\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * Get the user ioctl structure.
+	 */
+	if (copy_from_user(pioc, (uioctl_t *) arg, sizeof(uioctl_t))) {
+		kfree(pioc);
+		return -EFAULT;
+	}
+
+	/*
+	 * Check which command to do.
+	 */
+	switch (cmd) {
+	case ITE_IOC_GET_PHY_DISK_STATUS:
+		dprintk("ITE_IOC_GET_PHY_DISK_STATUS\n");
+
+		/*
+		 * Get the physical disk status.
+		 */
+		status = IT8212GetChipStatus(pioc);
+		return 0;
+	case ITE_IOC_CREATE_DISK_ARRAY:
+		dprintk("ITE_IOC_CREATE_DISK_ARRAY\n");
+
+		/*
+		 * Create disk array.
+		 */
+		status = IT8212CreateDiskArray(pioc);
+		if (status != SRB_STATUS_SUCCESS)
+			return status;
+		status = IT8212ErasePartition(pioc);
+		return 0;
+	case ITE_IOC_REBUILD_START:
+		dprintk("ITE_IOC_REBUILD_START\n");
+
+		/*
+		 * Rebuild array.
+		 */
+		status = IT8212Rebuild(pioc);
+		put_user(status, (u8 *) pioc->data);
+		return 0;
+	case ITE_IOC_GET_REBUILD_STATUS:
+		dprintk("ITE_IOC_GET_REBUILD_STATUS\n");
+		pAdap = ite_adapters[0];
+
+		/*
+		 * Get the rebuild disk ID.
+		 */
+		rebuild_info = (PRAID_REBUILD_INFO) pioc->data;
+		diskArrayId = rebuild_info->DiskArrayId;
+
+		/*
+		 * Select channel.
+		 */
+		if (diskArrayId < 2)
+			pChan = &pAdap->IDEChannel[0];
+		else
+			pChan = &pAdap->IDEChannel[1];
+
+		/*
+		 * Select device.
+		 */
+		outb(((u8) (diskArrayId << 4) | 0xA0),
+		     pChan->io_ports[IDE_SELECT_OFFSET]);
+
+		/*
+		 * Wait for device ready (not BUSY and not DRQ).
+		 */
+		WaitForDeviceReady(pChan, statusByte);
+		if ((statusByte & IDE_STATUS_BUSY)
+		    || (statusByte & IDE_STATUS_DRQ) || (statusByte == 0)) {
+			printk("IT8212GetRebuildStatus: Disk[%d] busy. "
+					"Status=0x%X\n",
+					diskArrayId, statusByte);
+			srbStatus = SRB_STATUS_BUSY;
+			goto exit;
+		}
+
+		/*
+		 * Disable interrupt to avoid the unexpected interrupt.
+		 */
+		outb(IDE_DC_DISABLE_INTERRUPTS,
+		     pChan->io_ports[IDE_CONTROL_OFFSET]);
+
+		/*
+		 * Issue command.
+		 */
+		outb(IDE_COMMAND_REBUILD_STATUS,
+		     pChan->io_ports[IDE_COMMAND_OFFSET]);
+
+		/*
+		 * Check error.
+		 */
+		WaitForCommandComplete(pChan, statusByte);
+
+		/*
+		 * Reenable interrupt after command complete.
+		 */
+		outb(IDE_DC_REENABLE_CONTROLLER,
+		     pChan->io_ports[IDE_CONTROL_OFFSET]);
+		if (statusByte != IDE_STATUS_IDLE) {
+			srbStatus = SRB_STATUS_ERROR;
+			printk("GetRebuildStatus: ERROR\n");
+			goto exit;
+		}
+		progress = inb(pChan->io_ports[IDE_NSECTOR_OFFSET]);
+		srbStatus = SRB_STATUS_SUCCESS;
+		if (progress != 0xFF)
+			progress = 0x64 - progress;
+
+		/*
+		 * Put the rebuild status to user space.
+		 */
+		return put_user(progress, (u8 *) pioc->data);
+exit:
+		return 0;
+	case ITE_IOC_RESET_ADAPTER:
+		dprintk("ITE_IOC_RESET_ADAPTER\n");
+
+		/*
+		 * Reset the adapter.
+		 */
+#if (0)
+		status = IT8212ResetAdapter();
+
+#endif
+
+		/*
+		 * Return TURE or FALSE to user space.
+		 */
+		put_user(status, (u8 *) arg);
+		return 0;
+	case ITE_IOC_GET_DRIVER_VERSION:
+		dprintk("ITE_IOC_GET_DRIVER_VERSION\n");
+
+		/*
+		 * Get the current driver version.
+		 */
+		put_user(driver_ver, (int *)arg);
+		return 0;
+	default:
+		return -EINVAL;
+	}			/* end switch */
+}				/* end itedev_ioctl */
+
+/************************************************************************
+ * IOCTL close routine.
+ ************************************************************************/
+static int itedev_close(struct inode *inode, struct file *filep)
+{
+
+	//MOD_DEC_USE_COUNT;
+	return 0;
+}				/* end itedev_close */
+
+/************************************************************************
+ * Scsi_Host_Template Initializer
+ ************************************************************************/
+static Scsi_Host_Template driver_template = {
+	.proc_name = 			"IT8212",
+	.proc_info =			iteraid_proc_info,
+	.name =				"ITE RAIDExpress133",
+	.detect =			iteraid_detect,
+	.release =			iteraid_release,
+	.queuecommand =			iteraid_queuecommand,
+	.eh_abort_handler =		iteraid_abort_eh,
+	.eh_host_reset_handler =	iteraid_reset_eh,
+	.bios_param =			iteraid_biosparam,
+	.can_queue =			1,
+	.this_id =			-1,
+	.sg_tablesize =			32,
+	.max_sectors =			256,
+	.cmd_per_lun =			1,
+	.use_clustering =		DISABLE_CLUSTERING,
+	.emulated =			1,
+};
+
+#include "scsi_module.c"
diff -puN /dev/null drivers/scsi/iteraid.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/scsi/iteraid.h	2005-06-16 17:49:12.000000000 -0700
@@ -0,0 +1,1463 @@
+/*
+ * linux/drivers/scsi/iteraid.h
+ *
+ * (C) Copyright 2002-2004 ITE Tech, inc.
+ *
+ * Nov 11, 2002	Mark Lu	file created.
+ *
+ * Aug 2, 2004 Donald Huang published the ITE driver.
+ *
+ * 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.
+ *
+ * ITE IT8212 RAID Controller device driver header for Linux.
+ */
+
+#ifndef _ITERAID_H_
+#define _ITERAID_H_
+
+#include <linux/version.h>
+#include <linux/types.h>
+
+#define ITE_VENDOR_ID	0x1283	/* Vendor ID (ITE)      */
+#define ITE_DEVICE_ID	0x8212	/* Device IF (IT8212)   */
+#define MAX_ADAPTERS	2	/* Max Board supported  */
+#define MAX_DEVICES	(MAX_ADAPTERS * 4)	/* Max Dev supported    */
+
+#define TRUE		1
+#define FALSE 		0
+
+/*
+ * Undef macros which may conflict
+ */
+#undef	START_STOP
+
+/************************************************************************
+ * Debugging macro
+ ************************************************************************/
+#ifdef ITE_DEBUG
+#define dprintk(msg...) printk(msg)
+#else
+#define dprintk(msg...) do { } while(0)
+#endif
+
+/************************************************************************
+ * Raid level definitions
+ ************************************************************************/
+#define RAID_LEVEL_0			0
+#define RAID_LEVEL_1			1
+#define RAID_LEVEL_10			2
+#define RAID_LEVEL_JBOD			3
+#define RAID_LEVEL_NORMAL		4
+#define RAID_LEVEL_NODISK		5
+
+/************************************************************************
+ * Physical disk status definitions
+ ************************************************************************/
+#define DISK_KEY_OFF			0
+#define DISK_OFF_LINE			1
+#define DISK_ON_LINE			2
+#define DISK_REBUILDING			3
+#define DISK_PLUGGING			4
+#define DISK_PLUGGING_OK		5
+
+#define MaximumLBAOf28Bit		0x10000000
+
+#define DisableChannel			1
+#define EnableChannel			2
+
+#define CABLE_40_PIN			0
+#define CABLE_80_PIN			1
+
+#define RaidActive			0
+#define RaidInactive			1
+
+#define IDE_CLOCK_66			0
+#define IDE_CLOCK_50			1
+
+#define USE_ULTRA_DMA			0
+#define USE_MULTIWORD_DMA		1
+
+/************************************************************************
+ * Vendor specific information
+ ************************************************************************/
+typedef struct _PHYSICAL_DISK_STATUS {
+	u8 ModelNumber[40];	/* Byte 00-39           */
+	u32 UserAddressableSectors_LOW;	/* Byte 40-43           */
+	u32 UserAddressableSectors_HIGH;	/* Byte 44-47           */
+	u8 MultiWordDMASupport;	/* Byte 48              */
+	u8 MultiWordDMAActive;	/* Byte 49              */
+	u8 UltraDMASupport;	/* Byte 50              */
+	u8 UltraDMAActive;	/* Byte 51              */
+	u8 RaidType;		/* Byte 52              */
+	u8 RaidNumber;		/* Byte 53              */
+	u8 SerialNumber[20];	/* Byte 54-73           */
+	u8 DiskStatus;		/* Byte 74              */
+	u8 DiskOriginalLocation;	/* Byte 75              */
+	u8 Cable80Pin;		/* Byte 76              */
+	u8 BootableDisk;	/* Byte 77              */
+	u8 StorageSize[8];	/* Byte 78-85           */
+	u8 Reserved[35];	/* Byte 86-120          */
+	u8 UpdateYear;		/* Byte 121             */
+	u8 UpdateMonth;		/* Byte 122             */
+	u8 UpdateDay;		/* Byte 123             */
+	u8 FirmwareVer;		/* Byte 124             */
+	u8 RebuildStatus;	/* Byte 125             */
+	u8 StripeSize;		/* Byte 126             */
+	u8 AutoRebuildEnable;	/* Byte 127             */
+} PHYSICAL_DISK_STATUS, *PPHYSICAL_DISK_STATUS;
+
+/************************************************************************
+ * vendor specific information
+ ************************************************************************/
+typedef struct _IT8212_SET_CHIP_STATUS_INFO {
+	u16 RaidType;		/* Word 129             */
+	u16 ContainingDisks;	/* Word 130             */
+	u16 UltraDmaTiming01;	/* Word 131             */
+	u16 UltraDmaTiming23;	/* Word 132             */
+	u16 UltraDmaTiming45;	/* Word 133             */
+	u16 UltraDmaTiming6;	/* Word 134             */
+	u16 MultiWordDmaTiming01;	/* Word 135             */
+	u16 UltraDmaTiming2;	/* Word 136             */
+	u16 PioTiming4;		/* Word 137             */
+	u16 AutoRebuildEnable;	/* Word 138             */
+	u16 IdeClkUDma01;	/* Word 139             */
+	u16 IdeClkUDma23;	/* Word 140             */
+	u16 IdeClkUDma45;	/* Word 141             */
+	u16 IdeClkUDma6;	/* Word 142             */
+	u16 IdeClkMDma01;	/* Word 143             */
+	u16 IdeClkMDma2;	/* Word 144             */
+	u16 IdeClkPio4;		/* Word 145             */
+	u16 StripeSize;		/* Word 146             */
+	u16 BootableDisk;	/* Word 147             */
+	u16 CheckHotSwapInterval;	/* Word 148             */
+	u16 TargetSourceDisk;	/* Word 149             */
+	u16 RebuildBlockSize;	/* Word 150             */
+	u16 ResetInterval1;	/* Word 151             */
+	u16 ResetInterval2;	/* Word 152             */
+	u16 RebuildRetryTimes;	/* Word 153             */
+	u16 NewlyCreated;	/* Word 154             */
+} IT8212_SET_CHIP_STATUS_INFO, *PIT8212_SET_CHIP_STATUS_INFO;
+
+/************************************************************************
+ * Serial number written to HDD (20 bytes)
+ ************************************************************************/
+typedef struct _RAID_SERIAL_NUMBER {
+	u16 Year;
+	u8 Month;
+	u8 Date;
+	u8 Day;
+	u8 Hour;
+	u8 Minute;
+	u8 Second;
+	u8 MiniSec;
+	u8 RaidType;
+	u8 ContainingDisks;
+	u8 DontCare[9];
+} RAID_SERIAL_NUMBER, *PRAID_SERIAL_NUMBER;
+
+/************************************************************************
+ * Disk array create information
+ *
+ * Following items index definition
+ * 0: Primary Master
+ * 1: Secondary Master
+ * 2: Primary Slave
+ * 3: Secondary Slave
+ ************************************************************************/
+typedef struct _RAID_CREATE_INFO {
+	u8 DiskArrayId;
+	RAID_SERIAL_NUMBER SerialNumber;
+	u8 ModelNumber[40];
+	u16 RaidType;
+	u16 ContainingDisks;
+	u16 AutoRebuildEnable;
+	u16 StripeSize;
+	u16 BootableDisk;
+	u16 TargetSourceDisk;
+	u8 ErasePartition;
+	u8 DMASupported[4];
+	u8 UDMASupported[4];
+	u8 AddressableSectors[4];
+	u8 NewlyCreated;
+	u8 Reserved;
+} RAID_CREATE_INFO, *PRAID_CREATE_INFO;
+
+/************************************************************************
+ * Rebuild data structure
+ ************************************************************************/
+typedef struct _RAID_REBUILD_INFO {
+	u8 DiskArrayId;		/* Virtual device number (0-3)          */
+	u8 SrcDisk;		/* Source disk (0-3)                    */
+	u8 DestDisk;		/* Destination disk (0-3)               */
+	u8 Resume;		/* 1: Resume the last time rebuild      */
+	/* 0: Rebuild from LBA 0                */
+	u8 Status;		/* Indicate the status of the current   */
+	/* rebuild command filled by drivers    */
+	u8 Reserved[3];		/* For aligement                        */
+} RAID_REBUILD_INFO, *PRAID_REBUILD_INFO;
+
+/************************************************************************
+ * ATA transfer modes
+ ************************************************************************/
+#define PIO_DEFAULT			0x00
+#define PIO_DEFAULT_IORDY_DISABLE	0x01
+#define PIO_FLOW_CONTROL		0x08
+#define SINGLEWORD_DMA			0x10
+#define MULTIWORD_DMA			0x20
+#define ULTRA_DMA			0x40
+
+#define ITE_DRV_SIGNATURE		"ITE RAID CONTROLLER"
+#define ITE_DRV_BYPASS			"ITE BYPASS MODE"
+
+/************************************************************************
+ * Extra IDE commands supported by Accusys
+ ************************************************************************/
+#define IDE_COMMAND_GET_CHIP_STATUS	0xFA
+#define IDE_COMMAND_SET_CHIP_STATUS	0xFB
+#define IDE_COMMAND_REBUILD		0xFC
+#define IDE_COMMAND_REBUILD_STATUS	0xFD
+
+#define REBUILD_ERR_WRONG_ARRAY_TYPE		0x01
+#define REBUILD_ERR_DISK_TOO_SMALL		0x02
+#define REBUILD_ERR_SRC_DISK_LOCATION_INCORRECT	0x03
+#define REBUILD_ERR_SRC_DISK_OFFLINE		0x04
+#define REBUILD_ERR_DEST_DISK_OFFLINE		0x05
+#define REBUILD_ERR_DISK_BUSY			0x10
+
+/************************************************************************
+ * ATA transfer modes
+ ************************************************************************/
+#define PIO_DEFAULT			0x00
+#define PIO_DEFAULT_IORDY_DISABLE	0x01
+#define PIO_FLOW_CONTROL		0x08
+#define SINGLEWORD_DMA			0x10
+#define MULTIWORD_DMA			0x20
+#define ULTRA_DMA			0x40
+
+/************************************************************************
+ * IDE registers offset
+ ************************************************************************/
+#define IDE_NR_PORTS			10
+
+#define IDE_DATA_OFFSET			0
+#define IDE_ERROR_OFFSET		1
+#define IDE_NSECTOR_OFFSET		2
+#define IDE_LOCYL_OFFSET		3
+#define IDE_MIDCYL_OFFSET		4
+#define IDE_HCYL_OFFSET			5
+#define IDE_SELECT_OFFSET		6
+#define IDE_STATUS_OFFSET		7
+#define IDE_CONTROL_OFFSET		8
+#define IDE_IRQ_OFFSET			9
+
+#define	IDE_FEATURE_OFFSET		IDE_ERROR_OFFSET
+#define IDE_COMMAND_OFFSET		IDE_STATUS_OFFSET
+#define IDE_ALTERNATE_OFFSET		IDE_CONTROL_OFFSET
+
+/************************************************************************
+ * ATAPI registers offset
+ ************************************************************************/
+#define ATAPI_DATA_OFFSET		0
+#define ATAPI_ERROR_OFFSET		1
+#define ATAPI_INTREASON_OFFSET		2
+#define ATAPI_UNUSED1_OFFSET		3
+#define ATAPI_LCYL_OFFSET		4
+#define ATAPI_HCYL_OFFSET		5
+#define ATAPI_SELECT_OFFSET		6
+#define ATAPI_STATUS_OFFSET		7
+#define ATAPI_CONTROL_OFFSET		8
+
+#define ATAPI_COMMAND_OFFSET		ATAPI_STATUS_OFFSET
+#define	ATAPI_FEATURE_OFFSET		ATAPI_ERROR_OFFSET
+
+/************************************************************************
+ * Following structures are according to SPC-3 (by Chanel)
+ ************************************************************************/
+typedef struct _SCSI_MODE_SENSE6 {
+	u8 OperationCode;
+	u8 Reserved1:3;
+	u8 Dbd:1;
+	u8 Reserved2:4;
+	u8 PageCode:6;
+	u8 Pc:2;
+	u8 SubpageCode;
+	u8 AllocationLength;
+	u8 Control;
+} SCSI_MODE_SENSE6, *PSCSI_MODE_SENSE6;
+
+typedef struct _SCSI_MODE_SENSE10 {
+	u8 OperationCode;
+	u8 Reserved1:3;
+	u8 Dbd:1;
+	u8 LLBAA:1;
+	u8 Reserved2:3;
+	u8 PageCode:6;
+	u8 Pc:2;
+	u8 SubpageCode;
+	u8 Reserved3[3];
+	u8 AllocationLengthMsb;
+	u8 AllocationLengthLsb;
+	u8 Control;
+} SCSI_MODE_SENSE10, *PSCSI_MODE_SENSE10;
+
+typedef struct _SCSI_MODE_SELECT6 {
+	u8 OperationCode;
+	u8 SPBit:1;
+	u8 Reserved1:3;
+	u8 PFBit:1;
+	u8 Reserved2:3;
+	u8 Reserved3[2];
+	u8 ParameterListLength;
+	u8 Control;
+} SCSI_MODE_SELECT6, *PSCSI_MODE_SELECT6;
+
+typedef struct _SCSI_MODE_SELECT10 {
+	u8 OperationCode;
+	u8 SPBit:1;
+	u8 Reserved1:3;
+	u8 PFBit:1;
+	u8 Reserved2:3;
+	u8 Reserved3[5];
+	u8 ParameterListLengthMsb;
+	u8 ParameterListLengthLsb;
+	u8 Control;
+} SCSI_MODE_SELECT10, *PSCSI_MODE_SELECT10;
+
+typedef struct _SCSI_MODE_PARAMETER_HEADER6 {
+	u8 ModeDataLength;
+	u8 MediumType;
+	u8 DeviceSpecificParameter;
+	u8 BlockDescriptorLength;
+} SCSI_MODE_PARAMETER_HEADER6, *PSCSI_MODE_PARAMETER_HEADER6;
+
+typedef struct _SCSI_MODE_PARAMETER_HEADER10 {
+	u8 ModeDataLengthMsb;
+	u8 ModeDataLengthLsb;
+	u8 MediumType;
+	u8 DeviceSpecificParameter;
+	u8 Reserved[2];
+	u8 BlockDescriptorLengthMsb;
+	u8 BlockDescriptorLengthLsb;
+} SCSI_MODE_PARAMETER_HEADER10, *PSCSI_MODE_PARAMETER_HEADER10;
+
+typedef struct _SCSI_MODE_PARAMTER_BLOCK_DESCRIPTER {
+	u8 DesityCode;
+	u8 NumberOfBlocks2;
+	u8 NumberOfBlocks1;
+	u8 NumberOfBlocks0;
+	u8 Reserved;
+	u8 BlockLength2;
+	u8 BlockLength1;
+	u8 BlockLength0;
+} SCSI_MODE_PARAMTER_BLOCK_DESCRIPTER, *PSCSI_MODE_PARAMTER_BLOCK_DESCRIPTER;
+
+/************************************************************************
+ * IDE command definitions
+ ************************************************************************/
+#define IDE_COMMAND_ATAPI_RESET			0x08
+#define IDE_COMMAND_RECALIBRATE			0x10
+#define IDE_COMMAND_READ_SECTOR			0x20
+#define IDE_COMMAND_READ_SECTOR_EXT		0x24
+#define IDE_COMMAND_READ_DMA_EXT		0x25
+#define IDE_COMMAND_READ_MULTIPLE_EXT		0x29
+#define IDE_COMMAND_WRITE_SECTOR		0x30
+#define IDE_COMMAND_WRITE_SECTOR_EXT		0x34
+#define IDE_COMMAND_WRITE_DMA_EXT		0x35
+#define IDE_COMMAND_WRITE_MULTIPLE_EXT		0x39
+#define IDE_COMMAND_READ_VERIFY			0x40
+#define IDE_COMMAND_READ_VERIFY_EXT		0x42
+#define IDE_COMMAND_SEEK			0x70
+#define IDE_COMMAND_SET_DRIVE_PARAMETERS	0x91
+#define IDE_COMMAND_ATAPI_PACKET		0xA0
+#define IDE_COMMAND_ATAPI_IDENTIFY		0xA1
+#define IDE_COMMAND_READ_MULTIPLE		0xC4
+#define IDE_COMMAND_WRITE_MULTIPLE		0xC5
+#define IDE_COMMAND_SET_MULTIPLE		0xC6
+#define IDE_COMMAND_READ_DMA			0xC8
+#define IDE_COMMAND_WRITE_DMA			0xCA
+#define IDE_COMMAND_GET_MEDIA_STATUS		0xDA
+#define IDE_COMMAND_ENABLE_MEDIA_STATUS		0xEF
+#define IDE_COMMAND_SET_FEATURE			0xEF
+#define IDE_COMMAND_IDENTIFY			0xEC
+#define IDE_COMMAND_MEDIA_EJECT			0xED
+
+/************************************************************************
+ * 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_DRDY				0x40
+#define IDE_STATUS_IDLE				0x50
+#define IDE_STATUS_BUSY				0x80
+
+/************************************************************************
+ * IDE drive control definitions.
+ ************************************************************************/
+#define IDE_DC_DISABLE_INTERRUPTS		0x02
+#define IDE_DC_RESET_CONTROLLER			0x04
+#define IDE_DC_REENABLE_CONTROLLER		0x00
+
+/************************************************************************
+ * IDE error definitions.
+ ************************************************************************/
+#define IDE_ERROR_BAD_BLOCK			0x80
+#define IDE_ERROR_DATA_ERROR			0x40
+#define IDE_ERROR_MEDIA_CHANGE			0x20
+#define IDE_ERROR_ID_NOT_FOUND			0x10
+#define IDE_ERROR_MEDIA_CHANGE_REQ		0x08
+#define IDE_ERROR_COMMAND_ABORTED		0x04
+#define IDE_ERROR_END_OF_MEDIA			0x02
+#define IDE_ERROR_ILLEGAL_LENGTH		0x01
+
+/************************************************************************
+ * IDENTIFY data.
+ ************************************************************************/
+typedef struct _IDENTIFY_DATA {
+	u16 GeneralConfiguration;	/* 00 00                */
+	u16 NumberOfCylinders;	/* 02  1                */
+	u16 Reserved1;		/* 04  2                */
+	u16 NumberOfHeads;	/* 06  3                */
+	u16 UnformattedBytesPerTrack;	/* 08  4                */
+	u16 UnformattedBytesPerSector;	/* 0A  5                */
+	u16 SectorsPerTrack;	/* 0C  6                */
+	u16 VendorUnique1[3];	/* 0E  7-9              */
+	u16 SerialNumber[10];	/* 14  10-19            */
+	u16 BufferType;		/* 28  20               */
+	u16 BufferSectorSize;	/* 2A  21               */
+	u16 NumberOfEccBytes;	/* 2C  22               */
+	u16 FirmwareRevision[4];	/* 2E  23-26            */
+	u16 ModelNumber[20];	/* 36  27-46            */
+	u8 MaximumBlockTransfer;	/* 5E  47               */
+	u8 VendorUnique2;	/* 5F                   */
+	u16 DoubleWordIo;	/* 60  48               */
+	u16 Capabilities;	/* 62  49               */
+	u16 Reserved2;		/* 64  50               */
+	u8 VendorUnique3;	/* 66  51               */
+	u8 PioCycleTimingMode;	/* 67                   */
+	u8 VendorUnique4;	/* 68  52               */
+	u8 DmaCycleTimingMode;	/* 69                   */
+	u16 TranslationFieldsValid:1;	/* 6A  53               */
+	u16 Reserved3:15;	/*                      */
+	u16 NumberOfCurrentCylinders;	/* 6C  54               */
+	u16 NumberOfCurrentHeads;	/* 6E  55               */
+	u16 CurrentSectorsPerTrack;	/* 70  56               */
+	u32 CurrentSectorCapacity;	/* 72  57-58            */
+	u16 CurrentMultiSectorSetting;	/*     59               */
+	u32 UserAddressableSectors;	/*     60-61            */
+	u16 SingleWordDMASupport:8;	/*     62               */
+	u16 SingleWordDMAActive:8;	/*                      */
+	u16 MultiWordDMASupport:8;	/*     63               */
+	u16 MultiWordDMAActive:8;	/*                      */
+	u16 AdvancedPIOModes:8;	/*     64               */
+	u16 Reserved4:8;	/*                      */
+	u16 MinimumMWXferCycleTime;	/*     65               */
+	u16 RecommendedMWXferCycleTime;	/*     66               */
+	u16 MinimumPIOCycleTime;	/*     67               */
+	u16 MinimumPIOCycleTimeIORDY;	/*     68               */
+	u16 Reserved5[2];	/*     69-70            */
+	u16 ReleaseTimeOverlapped;	/*     71               */
+	u16 ReleaseTimeServiceCommand;	/*     72               */
+	u16 MajorRevision;	/*     73               */
+	u16 MinorRevision;	/*     74               */
+	u16 Reserved6[50];	/*     75-126           */
+	u16 SpecialFunctionsEnabled;	/*     127              */
+	u16 Reserved7[128];	/*     128-255          */
+} IDENTIFY_DATA, *PIDENTIFY_DATA;
+
+/************************************************************************
+ * Identify data without the Reserved4.
+ ************************************************************************/
+typedef struct _IDENTIFY_DATA2 {
+	u16 GeneralConfiguration;	/* 00                   */
+	u16 NumberOfCylinders;	/* 01                   */
+	u16 Reserved1;		/* 02                   */
+	u16 NumberOfHeads;	/* 03                   */
+	u16 Reserved2[2];	/* 04-05                */
+	u16 SectorsPerTrack;	/* 06                   */
+	u16 Reserved3[3];	/* 07-09                */
+	u16 SerialNumber[10];	/* 10-19                */
+	u16 Reserved4[3];	/* 20-22                */
+	u16 FirmwareRevision[4];	/* 23-26                */
+	u16 ModelNumber[20];	/* 27-46                */
+	u16 MaximumBlockTransfer;	/* 47                   */
+	u16 Reserved5;		/* 48                   */
+	u16 Capabilities[2];	/* 49-50                */
+	u16 Reserved6[2];	/* 51-52                */
+	u16 ValidFieldIndicator;	/* 53                   */
+	u16 NumberOfCurrentCylinders;	/* 54                   */
+	u16 NumberOfCurrentHeads;	/* 55                   */
+	u16 CurrentSectorsPerTrack;	/* 56                   */
+	u16 CurrentSectorCapacityLow;	/* 57                   */
+	u16 CurrentSectorCapacityHigh;	/* 58                   */
+	u16 CurrentMultiSectorSetting;	/* 59                   */
+	u32 UserAddressableSectors;	/* 60-61                */
+	u16 Reserved7;		/* 62                   */
+	u8 MultiWordDMASupport;	/* 63                   */
+	u8 MultiWordDMAActive;	/*                      */
+	u16 AdvancedPIOModes;	/* 64                   */
+	u16 MinimumMWXferCycleTime;	/* 65                   */
+	u16 RecommendedMWXferCycleTime;	/* 66                   */
+	u16 MinimumPIOCycleTime;	/* 67                   */
+	u16 MinimumPIOCycleTimeIORDY;	/* 68                   */
+	u16 Reserved8[6];	/* 69-74                */
+	u16 QueueDepth;		/* 75                   */
+	u16 Reserved9[4];	/* 76-79                */
+	u16 MajorVersionNumber;	/* 80                   */
+	u16 MinorVersionNumber;	/* 81                   */
+	u32 CmdSetSupported;	/* 82-83                */
+	u16 CmdSetFeatureSupportedExt;	/* 84                   */
+	u16 CmdSetFeatureEnabledLow;	/* 85                   */
+	u16 CmdSetFeatureEnabledHigh;	/* 86                   */
+	u16 CmdSetFeatureDefault;	/* 87                   */
+	u8 UltraDMASupport;	/* 88                   */
+	u8 UltraDMAActive;	/*                      */
+	u16 SecurityEraseTime;	/* 89                   */
+	u16 EnhancedSecurityEraseTime;	/* 90                   */
+	u16 PowerManagementValue;	/* 91                   */
+	u16 MasterPasswordRevision;	/* 92                   */
+	u16 HwResetResult;	/* 93                   */
+	u16 Reserved11[6];	/* 94-99                */
+	u32 Capacity_48bit_LOW;	/* 100-101              */
+	u32 Capacity_48bit_HIGH;	/* 102-103              */
+	u16 Reserved12[24];	/* 104-127              */
+	u16 SecurityStatus;	/* 128                  */
+	u16 Reserved13[31];	/* 129-159 vendor spec  */
+	u16 Reserved14[96];	/* 160-255              */
+} IDENTIFY_DATA2, *PIDENTIFY_DATA2;
+
+#define IDENTIFY_DATA_SIZE sizeof(IDENTIFY_DATA)
+
+/************************************************************************
+ * IDENTIFY capability bit definitions.
+ ************************************************************************/
+#define IDENTIFY_CAPABILITIES_DMA_SUPPORTED	0x0100
+#define IDENTIFY_CAPABILITIES_LBA_SUPPORTED	0x0200
+
+/************************************************************************
+ * IDENTIFY DMA timing cycle modes.
+ ************************************************************************/
+#define IDENTIFY_DMA_CYCLES_MODE_0		0x00
+#define IDENTIFY_DMA_CYCLES_MODE_1		0x01
+#define IDENTIFY_DMA_CYCLES_MODE_2		0x02
+
+typedef struct _SENSE_DATA {
+	u8 ErrorCode:7;
+	u8 Valid:1;
+	u8 SegmentNumber;
+	u8 SenseKey:4;
+	u8 Reserved:1;
+	u8 IncorrectLength:1;
+	u8 EndOfMedia:1;
+	u8 FileMark:1;
+	u8 Information[4];
+	u8 AdditionalSenseLength;
+	u8 CommandSpecificInformation[4];
+	u8 AdditionalSenseCode;
+	u8 AdditionalSenseCodeQualifier;
+	u8 FieldReplaceableUnitCode;
+	u8 SenseKeySpecific[3];
+} SENSE_DATA, *PSENSE_DATA;
+
+/************************************************************************
+ * Sense codes
+ ************************************************************************/
+#define SCSI_SENSE_NO_SENSE		0x00
+#define SCSI_SENSE_RECOVERED_ERROR	0x01
+#define SCSI_SENSE_NOT_READY		0x02
+#define SCSI_SENSE_MEDIUM_ERROR		0x03
+#define SCSI_SENSE_HARDWARE_ERROR	0x04
+#define SCSI_SENSE_ILLEGAL_REQUEST	0x05
+#define SCSI_SENSE_UNIT_ATTENTION	0x06
+#define SCSI_SENSE_DATA_PROTECT		0x07
+#define SCSI_SENSE_BLANK_CHECK		0x08
+#define SCSI_SENSE_UNIQUE		0x09
+#define SCSI_SENSE_COPY_ABORTED		0x0A
+#define SCSI_SENSE_ABORTED_COMMAND	0x0B
+#define SCSI_SENSE_EQUAL		0x0C
+#define SCSI_SENSE_VOL_OVERFLOW		0x0D
+#define SCSI_SENSE_MISCOMPARE		0x0E
+#define SCSI_SENSE_RESERVED		0x0F
+
+/************************************************************************
+ * Additional Sense codes
+ ************************************************************************/
+#define SCSI_ADSENSE_NO_SENSE		0x00
+#define SCSI_ADSENSE_MAN_INTERV		0x03
+#define SCSI_ADSENSE_LUN_NOT_READY	0x04
+#define SCSI_ADSENSE_ILLEGAL_COMMAND	0x20
+#define SCSI_ADSENSE_ILLEGAL_BLOCK	0x21
+#define SCSI_ADSENSE_INVALID_LUN	0x25
+#define SCSI_ADSENSE_SELECT_TIMEOUT	0x45
+#define SCSI_ADSENSE_MUSIC_AREA		0xA0
+#define SCSI_ADSENSE_DATA_AREA		0xA1
+#define SCSI_ADSENSE_VOLUME_OVERFLOW	0xA7
+
+#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE	0x3A
+#define SCSI_ADWRITE_PROTECT		0x27
+#define SCSI_ADSENSE_MEDIUM_CHANGED	0x28
+#define SCSI_ADSENSE_BUS_RESET		0x29
+#define SCSI_ADSENSE_TRACK_ERROR	0x14
+#define SCSI_ADSENSE_SEEK_ERROR		0x15
+#define SCSI_ADSENSE_REC_DATA_NOECC	0x17
+#define SCSI_ADSENSE_REC_DATA_ECC	0x18
+#define SCSI_ADSENSE_ILLEGAL_MODE	0x64
+#define SCSI_ADSENSE_BAD_CDB		0x24
+#define SCSI_ADSENSE_BAD_PARM_LIST	0x26
+#define SCSI_ADSENSE_CANNOT_READ_MEDIUM	0x30
+
+#define SCSISTAT_CHECK_CONDITION	0x02
+
+/************************************************************************
+ * Inquiry buffer structure. This is the data returned from the target
+ * after it receives an inquiry.
+ *
+ * This structure may be extended by the number of bytes specified
+ * in the field AdditionalLength. The defined size constant only
+ * includes fields through ProductRevisionLevel.
+ *
+ * The NT SCSI drivers are only interested in the first 36 bytes of data.
+ ************************************************************************/
+
+#define INQUIRYDATABUFFERSIZE 36
+
+typedef struct _INQUIRYDATA {
+	u8 DeviceType:5;
+	u8 DeviceTypeQualifier:3;
+	u8 DeviceTypeModifier:7;
+	u8 RemovableMedia:1;
+	u8 Versions;
+	u8 ResponseDataFormat;
+	u8 AdditionalLength;
+	u8 Reserved[2];
+	u8 SoftReset:1;
+	u8 CommandQueue:1;
+	u8 Reserved2:1;
+	u8 LinkedCommands:1;
+	u8 Synchronous:1;
+	u8 Wide16Bit:1;
+	u8 Wide32Bit:1;
+	u8 RelativeAddressing:1;
+	u8 VendorId[8];
+	u8 ProductId[16];
+	u8 ProductRevisionLevel[4];
+	u8 VendorSpecific[20];
+	u8 Reserved3[40];
+} INQUIRYDATA, *PINQUIRYDATA;
+
+#define DIRECT_ACCESS_DEVICE		0x00	/* Disks                */
+
+/************************************************************************
+ * Read Capacity Data - returned in Big Endian format
+ ************************************************************************/
+typedef struct _READ_CAPACITY_DATA {
+	u32 LogicalBlockAddress;
+	u32 BytesPerBlock;
+} READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
+
+#define MAXIMUM_CDB_SIZE	12
+
+/************************************************************************
+ * CDB (Command Descriptor Block)
+ ************************************************************************/
+typedef union _CDB {
+	/*
+	 * Standard 6-byte CDB
+	 */
+	struct _CDB6READWRITE {
+		u8 OperationCode;	/* Opcode                       */
+		u8 LogicalBlockMsb1:5;	/* Logical block MSB 5-bit      */
+		u8 LogicalUnitNumber:3;	/* LUN                          */
+		u8 LogicalBlockMsb0;	/* Logical block MSB 8-bit      */
+		u8 LogicalBlockLsb;	/* Logical block LSB 8-bit      */
+		u8 TransferBlocks;	/* Data length                  */
+		u8 Control;	/* Control byte                 */
+	} CDB6READWRITE, *PCDB6READWRITE;
+
+	/*
+	 * Standard 10-byte CDB
+	 */
+	struct _CDB10 {
+		u8 OperationCode;
+		u8 Reserved1:5;
+		u8 LogicalUnitNumber:3;
+		u8 LogicalBlockByte0;
+		u8 LogicalBlockByte1;
+		u8 LogicalBlockByte2;
+		u8 LogicalBlockByte3;
+		u8 Reserved2;
+		u8 TransferBlocksMsb;
+		u8 TransferBlocksLsb;
+		u8 Control;
+	} CDB10, *PCDB10;
+
+	struct _START_STOP {
+		u8 OperationCode;
+		u8 Immediate:1;
+		u8 Reserved1:4;
+		u8 LogicalUnitNumber:3;
+		u8 Reserved2[2];
+		u8 Start:1;
+		u8 LoadEject:1;
+		u8 Reserved3:6;
+		u8 Control;
+	} START_STOP, *PSTART_STOP;
+
+} CDB, *PCDB;
+
+/************************************************************************
+ * 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
+
+#define DRIVER_NAME		"Device Driver for IT8212 RAID Controller"
+#define COMPANY_NAME		"Integrated Technology Express, Inc."
+#define CONTROLLER_NAME_IT8212	"IT8212 UDMA/ATA133 RAID Controller"
+#define PROC_DIR_NAME		"it8212"
+#define ITE_MAX_CMDS		124
+
+#define PCI_IOSEN	0x01	/* Enable IO space                      */
+#define PCI_BMEN	0x04	/* Enable IDE bus master                */
+
+/************************************************************************
+ * PRD (Physical Region Descriptor) = Scatter-gather table
+ *
+ * |  byte3   |	 byte2	 |  byte1   |   byte0   |
+ * +--------------------------------------------+
+ * | Memory Region Physical Base Address[31:1]  |
+ * +----+----------------+----------------------+
+ * |EOT |  reserved      |   Byte count[15:1]   |
+ * +----+----------------+----------------------+
+ ************************************************************************/
+typedef struct _PRD_TABLE_ENTRY {
+	u32 PhysicalBaseAddress;	/* Byte0 - Byte3        */
+	u16 ByteCount;		/* Byte4 - Byte5        */
+	u16 EndOfTable;		/* Byte6 - Byte7        */
+} PRD_TABLE_ENTRY, *PPRD_TABLE_ENTRY;
+
+#define SG_FLAG_EOT			0x8000	/* End of PRD           */
+#define MAX_SG_DESCRIPTORS		17	/* 17 -- maximum 64K    */
+
+#define NUM_OF_PRD_TABLE_ENTRY		0x10
+
+/************************************************************************
+ * Bus master register bits definition
+ ************************************************************************/
+#define BM_CMD_FLG_START		0x01
+#define BM_CMD_FLG_WRTTOMEM		0x08
+#define BM_CMD_FLG_WRTTODSK		0x00
+
+#define BM_STAT_FLG_ACTIVE		0x01
+#define BM_STAT_FLG_ERR			0x02
+#define BM_STAT_FLG_INT			0x04
+#define BM_DRV0_DMA_CAPABLE		0x20
+#define BM_DRV1_DMA_CAPABLE		0x40
+
+#define BM_PRD_FLG_EOT  		0x8000
+
+/************************************************************************
+ * SRB Functions
+ ************************************************************************/
+#define SRB_FUNCTION_EXECUTE_SCSI	0x00
+#define SRB_FUNCTION_IO_CONTROL		0x02
+#define SRB_FUNCTION_SHUTDOWN		0x07
+#define SRB_FUNCTION_FLUSH		0x08
+
+/************************************************************************
+ * SRB 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_BAD_SRB_BLOCK_LENGTH	0x15
+#define SRB_STATUS_REQUEST_FLUSHED	0x16
+#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_NEED_REQUEUE		0x24
+
+/************************************************************************
+ * SRB Status Masks
+ ************************************************************************/
+#define SRB_STATUS_QUEUE_FROZEN		0x40
+#define SRB_STATUS_AUTOSENSE_VALID	0x80
+
+#define SRB_STATUS(Status)	\
+	(Status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
+
+/************************************************************************
+ * SRB Flag Bits
+ ************************************************************************/
+#define SRB_FLAGS_DATA_IN		0x00000040
+#define SRB_FLAGS_DATA_OUT		0x00000080
+
+/************************************************************************
+ * SRB Working flags define area
+ ************************************************************************/
+#define	SRB_WFLAGS_USE_INTERNAL_BUFFER	0x00000001
+#define	SRB_WFLAGS_IGNORE_ARRAY		0x00000002
+#define	SRB_WFLAGS_HAS_CALL_BACK	0x00000004
+#define	SRB_WFLAGS_MUST_DONE		0x00000008
+#define	SRB_WFLAGS_ON_MIRROR_DISK	0x00000010
+#define	SRB_WFLAGS_ON_SOURCE_DISK	0x00000020
+#define SRB_WFLAGS_ARRAY_IO_STARTED	0x10000000
+#define SRB_WFLAGS_WATCHTIMER_CALLED	0x20000000
+#define SRB_WFLAGS_USE_SG		0x40000000
+
+/************************************************************************
+ * SCSI I/O Request Block
+ ************************************************************************/
+typedef struct _SCSI_REQUEST_BLOCK {
+	u16 Length;
+	u8 Function;
+	u8 SrbStatus;
+	u8 ScsiStatus;
+	u8 TargetId;
+	u8 Lun;
+	u8 CdbLength;
+	u8 SenseInfoBufferLength;
+	u8 UseSg;
+	u8 reseved[2];
+	u32 WorkingFlags;
+	u32 SrbFlags;
+	u32 DataTransferLength;
+	u32 TimeOutValue;
+	void *DataBuffer;
+	void *SenseInfoBuffer;
+	u8 Cdb[16];
+	Scsi_Cmnd *pREQ;
+} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;
+
+#define SCSI_REQUEST_BLOCK_SIZE sizeof(SCSI_REQUEST_BLOCK)
+
+/************************************************************************
+ * Second device flags
+ ***********************************************************************/
+#define DFLAGS_REDUCE_MODE	        0x00010000
+#define DFLAGS_DEVICE_DISABLED		0x00020000
+#define DFLAGS_BOOTABLE_DEVICE		0x00080000
+#define DFLAGS_BOOT_MARK		0x00100000
+#define DFLAGS_NEW_ADDED		0x40000000
+#define DFLAGS_REMAINED_MEMBER		0x80000000
+
+/************************************************************************
+ * Device Extension Device Flags
+ ************************************************************************/
+/*
+ * Indicates that some device is present.
+ */
+#define DFLAGS_DEVICE_PRESENT		0x0001
+
+/*
+ * Indicates whether ATAPI commands can be used.
+ */
+#define DFLAGS_ATAPI_DEVICE		0x0002
+
+/*
+ * Indicates whether this is a tape device.
+ */
+#define DFLAGS_TAPE_DEVICE		0x0004
+
+/*
+ * Indicates whether device interrupts as DRQ is set after
+ * receiving Atapi Packet Command.
+ */
+#define DFLAGS_INT_DRQ			0x0008
+
+/*
+ * Indicates that the drive has the 'removable' bit set in
+ * identify data (offset 128)
+ */
+#define DFLAGS_REMOVABLE_DRIVE		0x0010
+
+/*
+ * Media status notification enabled.
+ */
+#define DFLAGS_MEDIA_STATUS_ENABLED	0x0020
+
+/*
+ * Indicates atapi 2.5 changer present.
+ */
+#define DFLAGS_ATAPI_CHANGER		0x0040
+
+/*
+ * Indicates multi-platter device, not conforming to the 2.5 spec.
+ */
+#define DFLAGS_SANYO_ATAPI_CHANGER	0x0080
+
+/*
+ * Indicates that the init path for changers has already been done.
+ */
+#define DFLAGS_CHANGER_INITED		0x0100
+#define DFLAGS_CONFIG_CHANGED		0x0200
+
+#define UDMA_MODE_5_6			0x80
+
+/************************************************************************
+ * Used to disable 'advanced' features.
+ ************************************************************************/
+#define MAX_ERRORS			4
+
+/************************************************************************
+ * ATAPI command definitions
+ ************************************************************************/
+#define ATAPI_MODE_SENSE		0x5A
+#define ATAPI_MODE_SELECT		0x55
+#define ATAPI_FORMAT_UNIT		0x24
+
+/************************************************************************
+ * User IOCTL structure
+ * Notes:
+ * (1) Data transfers are limited to PAGE_SIZE (4k on i386, 8k for alpha)
+ ************************************************************************/
+typedef struct _uioctl_t {
+	u16 inlen;		/* Length of data written to device     */
+	u16 outlen;		/* Length of data read from device      */
+	void *data;		/* Data read from devic starts here     */
+	u8 status;		/* Status return from driver            */
+	u8 reserved[3];		/* For 4-byte alignment                 */
+} uioctl_t;
+
+/************************************************************************
+ * IOCTL commands for RAID
+ ************************************************************************/
+#define ITE_IOCMAGIC			't'
+
+#define ITE_IOC_GET_PHY_DISK_STATUS	_IO(ITE_IOCMAGIC, 1)
+#define ITE_IOC_CREATE_DISK_ARRAY	_IO(ITE_IOCMAGIC, 2)
+#define ITE_IOC_REBUILD_START		_IO(ITE_IOCMAGIC, 3)
+#define ITE_IOC_GET_REBUILD_STATUS	_IO(ITE_IOCMAGIC, 4)
+#define ITE_IOC_RESET_ADAPTER		_IO(ITE_IOCMAGIC, 5)
+#define ITE_IOC_GET_DRIVER_VERSION	_IO(ITE_IOCMAGIC, 6)
+
+/************************************************************************
+ * _Channel
+ ************************************************************************/
+typedef struct _Channel {
+	/*
+	 * IDE (ATAPI) io port address.
+	 */
+	unsigned long io_ports[IDE_NR_PORTS];
+
+	/*
+	 * DMA base address.
+	 */
+	unsigned long dma_base;
+
+	/*
+	 * Flags word for each possible device.
+	 */
+	u16 DeviceFlags[2];
+
+	/*
+	 * Indicates number of platters on changer-ish devices.
+	 */
+	u32 DiscsPresent[2];
+
+	/*
+	 * Indicates expecting an interrupt.
+	 */
+	u8 ExpectingInterrupt;
+
+	/*
+	 * Indicate last tape command was DSC Restrictive.
+	 */
+	u8 RDP;
+
+	/*
+	 * Interrupt level.
+	 */
+	u8 InterruptLevel;
+
+	/*
+	 * Placeholder for status register after a GET_MEDIA_STATUS command.
+	 */
+	u8 ReturningMediaStatus;
+
+	/*
+	 * Remember the channel number (0, 1)
+	 */
+	u8 channel;
+
+	/*
+	 * Indicates cable status.
+	 */
+	u8 Cable80[2];
+
+	/*
+	 * Reserved for alignment.
+	 */
+	u8 reserved1[0];
+
+	/*
+	 * Data buffer pointer.
+	 */
+	unsigned short *DataBuffer;
+
+	/*
+	 * Data words left.
+	 */
+	u32 WordsLeft;
+
+	/*
+	 * Retry count.
+	 */
+	u32 RetryCount;
+
+	/*
+	 * Keep DMA type (MULTIWORD_DMA or ULTRA_DMA) for each device.
+	 */
+	u8 DmaType[2];
+
+	/*
+	 * Keep UDMA timing for each device.
+	 */
+	u8 UdmaTiming[2];
+
+	/*
+	 * Keep PIO/DMA timing for each channel. PioDmaTiming[clock][channel]
+	 */
+	u8 PioDmaTiming[2];
+
+	/*
+	 * Keep IDE clock (50 MHz or 66 MHz) for each device.
+	 */
+	u8 IdeClock[2];
+
+	/*
+	 * Keep the active device for each channel.
+	 */
+	u8 ActiveDevice;
+
+	/*
+	 * Indicate whether we should perform DMA mode switch on this channel?
+	 */
+	u8 DoSwitch;
+
+	/*
+	 * ???
+	 */
+	u8 ConvertCdb;
+
+	/*
+	 * Use or do not use DMA.
+	 */
+	u8 UseDma[2];
+
+	/*
+	 * Reserved for alignment.
+	 */
+	u8 reserved2[3];
+
+	/*
+	 * Identify data for device.
+	 */
+	IDENTIFY_DATA FullIdentifyData;
+	IDENTIFY_DATA2 IdentifyData[2];
+
+	/*
+	 * DMA PRD table physical address.
+	 */
+	dma_addr_t dmatable_dma;
+
+	/*
+	 * DMA PRD table virtual address.
+	 */
+	unsigned long *dmatable_cpu;
+
+	/*
+	 * Point to SCATTER/GATHER data buffer.
+	 */
+	struct scatterlist *sg_table;
+
+	/*
+	 * DMA read or write.
+	 */
+	int sg_dma_direction;
+
+	/*
+	 * Current request on controller.
+	 */
+	PSCSI_REQUEST_BLOCK CurrentSrb;
+
+	/*
+	 * Original request on controller.
+	 */
+	PSCSI_REQUEST_BLOCK OriginalSrb;
+
+	/*
+	 * Internal SRB.
+	 */
+	SCSI_REQUEST_BLOCK _Srb;
+
+	/*
+	 * Remember the PCI device.
+	 */
+	struct pci_dev *pPciDev;
+
+	/*
+	 * Placeholder for CDB.
+	 */
+	u8 TempCdb[MAXIMUM_CDB_SIZE];
+} Channel, *PChannel;
+
+/************************************************************************
+ * _Adapter
+ ************************************************************************/
+typedef struct _Adapter {
+	char *name;		/* Adapter's name               */
+	u8 num_channels;	/* How many channels support    */
+	unsigned int irq;	/* irq number                   */
+	unsigned int irqOwned;	/* If any irq is use            */
+	u8 pci_bus;		/* PCI bus number               */
+	u8 devfn;		/* Device and function number   */
+	u8 offline;		/* On line or off line          */
+	u8 bypass_mode;		/* bypass or firware mode       */
+	u8 reserved2[1];	/* Reserved for alignment       */
+	Channel *IDEChannel;	/* IT8212 supports two channels */
+	struct pci_dev *pci_dev;	/* For PCI device               */
+} ITE_ADAPTER, *PITE_ADAPTER;
+
+/************************************************************************
+ * Beautification macros
+ ************************************************************************/
+#define ScheduleRetryProcess(pChan) do {		\
+	pChan->retry_timer->expires = jiffies + 10;	\
+	add_timer(pChan->retry_timer);			\
+	} while (0)
+
+#define CancelRetryProcess(pChan) del_timer(pChan->retry_timer)
+
+#define GetStatus(pChan, Status)	\
+    Status = inb(pChan->io_ports[IDE_CONTROL_OFFSET]);
+
+#define GetBaseStatus(pChan, Status)	\
+    Status = inb(pChan->io_ports[IDE_COMMAND_OFFSET]);
+
+#define GetError(pChan, Error)		\
+    Error = inb(pChan->io_ports[IDE_ERROR_OFFSET]);
+
+#define ReadBuffer(pChan, Buffer, Count) \
+    insw(pChan->io_ports[IDE_DATA_OFFSET], Buffer, Count);
+
+#define WriteCommand(BaseIoAddress, Command) \
+    outb(pChan->io_ports[IDE_COMMAND_OFFSET], Command);
+
+#define WriteBuffer(pChan, Buffer, Count) \
+    outsw(pChan->io_ports[IDE_DATA_OFFSET], Buffer, Count);
+
+#define WaitOnBusy(pChan, Status)		\
+{						\
+ int		i;				\
+ for (i = 0; i < 20000; i++)			\
+    {						\
+     GetStatus(pChan, Status);			\
+     if (Status & IDE_STATUS_BUSY)		\
+	{					\
+	 udelay(150);				\
+	 continue;				\
+	}					\
+     else 					\
+	{					\
+	 break;					\
+	}					\
+    }						\
+}
+
+#define WaitOnBaseBusy(pChan, Status)		\
+{						\
+ int		i;				\
+ for (i = 0; i < 20000; i++)			\
+    {						\
+     GetBaseStatus(pChan, Status);		\
+     if (Status & IDE_STATUS_BUSY)		\
+	{					\
+	 udelay(150);				\
+	 continue;				\
+	} 					\
+     else					\
+	{					\
+	 break;					\
+	}					\
+    }						\
+}
+
+#define WaitForDrq(pChan, Status)		\
+{						\
+ int		i;				\
+ for (i = 0; i < 1000; i++)			\
+    {						\
+     GetStatus(pChan, Status);			\
+     if (Status & IDE_STATUS_BUSY)		\
+	{					\
+	 udelay(100);				\
+	}					\
+     else if (Status & IDE_STATUS_DRQ)		\
+	{					\
+	 break;					\
+	}					\
+     else					\
+	{					\
+	 udelay(200);				\
+	}					\
+    }						\
+}
+
+#define WaitForBaseDrq(pChan, Status)		\
+{						\
+ int		i;				\
+ for (i = 0; i < 50000; i++)			\
+    {						\
+     GetBaseStatus(pChan, Status);		\
+     if (Status & IDE_STATUS_BUSY)		\
+	{					\
+	 udelay(100);				\
+	}					\
+     else if (Status & IDE_STATUS_DRQ)		\
+	{					\
+	 break;					\
+	}					\
+     else					\
+	{					\
+	 udelay(200);				\
+	}					\
+    }						\
+}
+
+#define CheckBusyDrq(pChan, Status)		\
+{						\
+ int		i;				\
+ for (i = 0; i < 50000; i++)			\
+    {						\
+     GetBaseStatus(pChan, Status);		\
+     if ((Status & IDE_STATUS_BUSY) ||		\
+	!(Status & IDE_STATUS_DRQ))		\
+	{					\
+	 udelay(200);				\
+	}					\
+     else					\
+	{					\
+	 break;					\
+	}					\
+    }						\
+}
+
+#define WaitShortForDrq(pChan, Status)		\
+{						\
+ int		i;				\
+ for (i = 0; i < 2; i++)			\
+    {						\
+     GetStatus(pChan, Status);			\
+     if (Status & IDE_STATUS_BUSY)		\
+	{					\
+	 udelay(100);				\
+	}					\
+     else if (Status & IDE_STATUS_DRQ)		\
+	{					\
+	 break;					\
+	}					\
+     else					\
+	{					\
+	 udelay(100);				\
+	}					\
+    }						\
+}
+
+#define WaitForDeviceReady(pChan, Status)	\
+{						\
+ int		i;				\
+ for (i = 0; i < 50000; i++)			\
+    {						\
+     GetStatus(pChan, Status);			\
+     if (Status == 0)				\
+	{					\
+	 break;					\
+	}					\
+     if ((Status & IDE_STATUS_BUSY) || (Status & IDE_STATUS_DRQ)) \
+	{					\
+	 udelay(200);				\
+	 continue;				\
+	}					\
+     else					\
+	{					\
+	 break;					\
+	}					\
+    }						\
+}
+
+#define WaitForCommandComplete(pChan, Status)		\
+{							\
+ int		i;					\
+ for (i = 0; i < 50000; i++)				\
+    { 							\
+     GetStatus(pChan, Status);				\
+     if ((Status == 0) || (Status & IDE_STATUS_ERROR)	\
+      || (Status == IDE_STATUS_IDLE))			\
+	{						\
+	 break;						\
+	}						\
+     udelay(200);					\
+     continue;						\
+    }							\
+}
+
+#define WaitForBaseCommandComplete(pChan, Status)	\
+{							\
+ int		i;					\
+ for (i = 0; i < 50000; i++)				\
+    { 							\
+     GetBaseStatus(pChan, Status);			\
+     if ((Status == 0) || (Status & IDE_STATUS_ERROR)	\
+      || (Status == IDE_STATUS_IDLE))			\
+	{						\
+	 break;						\
+	}						\
+     udelay(200);					\
+     continue;						\
+    }							\
+}
+
+#define AtapiSoftReset(pChan, DevNum)		\
+{						\
+ unsigned char		statusByte;		\
+ outb((unsigned char)(((DevNum & 0x1) << 4) | 0xA0), pChan->io_ports[IDE_SELECT_OFFSET]); \
+ udelay(500);									  \
+ outb(IDE_COMMAND_ATAPI_RESET, pChan->io_ports[IDE_COMMAND_OFFSET]);		  \
+ mdelay(1000);									  \
+ outb((unsigned char)(((DevNum & 0x1) << 4) | 0xA0), pChan->io_ports[IDE_SELECT_OFFSET]); \
+ WaitOnBusy(pChan, statusByte);			\
+ udelay(500);					\
+}
+
+#define IdeHardReset(pChan, result)		\
+do {						\
+ unsigned char	statusByte;			\
+ int		i;				\
+ outb(IDE_DC_RESET_CONTROLLER, pChan->io_ports[IDE_CONTROL_OFFSET]);	\
+ mdelay(50);								\
+ outb(IDE_DC_REENABLE_CONTROLLER, pChan->io_ports[IDE_CONTROL_OFFSET]);	\
+ for (i = 0; i < 1000 * 1000; i++)					\
+    {									\
+     statusByte = inb(pChan->io_ports[IDE_CONTROL_OFFSET]);		\
+     if (statusByte != IDE_STATUS_IDLE && statusByte != 0x0)		\
+	{					\
+	 udelay(30);				\
+	}					\
+     else					\
+	{					\
+	 break;					\
+	}					\
+    }						\
+ if (i == 1000 * 1000)				\
+    {						\
+     printk("IdeHardReset Fail!\n");		\
+     result = FALSE;				\
+    }						\
+ else						\
+    {						\
+     dprintk("IdeHardReset Success!\n");	\
+     result = TRUE;				\
+    }						\
+} while (0)
+
+/************************************************************************
+ * Function prototypes
+ ************************************************************************/
+
+#endif				/* #ifndef _ITERAID_H_ */
diff -puN drivers/scsi/Kconfig~iteraid drivers/scsi/Kconfig
--- 25/drivers/scsi/Kconfig~iteraid	2005-06-16 17:49:12.000000000 -0700
+++ 25-akpm/drivers/scsi/Kconfig	2005-06-16 17:49:12.000000000 -0700
@@ -310,6 +310,15 @@ config SCSI_ACARD
 	  To compile this driver as a module, choose M here: the
 	  module will be called atp870u.
 
+config SCSI_ITERAID
+	tristate "ITE IT8212 RAID CARD support"
+	depends on PCI && SCSI
+	help
+	  This driver supports the ITE IT8212 RAID card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iteraid.
+
 config SCSI_AHA152X
 	tristate "Adaptec AHA152X/2825 support"
 	depends on ISA && SCSI && !64BIT
diff -puN drivers/scsi/Makefile~iteraid drivers/scsi/Makefile
--- 25/drivers/scsi/Makefile~iteraid	2005-06-16 17:49:12.000000000 -0700
+++ 25-akpm/drivers/scsi/Makefile	2005-06-16 17:49:12.000000000 -0700
@@ -99,6 +99,7 @@ obj-$(CONFIG_MEGARAID_LEGACY)	+= megarai
 obj-$(CONFIG_MEGARAID_NEWGEN)	+= megaraid/
 obj-$(CONFIG_MEGARAID_SAS)	+= megaraid/
 obj-$(CONFIG_SCSI_ACARD)	+= atp870u.o
+obj-$(CONFIG_SCSI_ITERAID)	+= iteraid.o
 obj-$(CONFIG_SCSI_SUNESP)	+= esp.o
 obj-$(CONFIG_SCSI_GDTH)		+= gdth.o
 obj-$(CONFIG_SCSI_INITIO)	+= initio.o
_