Warning!

Notice: the grml team migrated from Mercurial to Git.
Please visit git.grml.org instead!

patchset and configuration for 2.6.20-grml grml.02
authorMichael Prokop <mika@grml.org>
Sun Feb 25 13:04:04 2007 +0100 (2 years ago)
changeset 22036807a852e7
manifest036807a852e7
parent 217a552dcb6a53
child 23e6892c881c68
patchset and configuration for 2.6.20-grml grml.02
2.6.20/1000_2.6.20.1.patch
2.6.20/4150_iteraid.patch
2.6.20/4310_unionfs-2.6.20-u1.patch
2.6.20/5001_grml_logo.patch
2.6.20/5002_commandlinesize.patch
2.6.20/5003_grml-kernelversion.patch
config/config-2.6.20
--- a/config/config-2.6.20 Wed Feb 07 23:57:30 2007 +0100
+++ b/config/config-2.6.20 Sun Feb 25 13:04:04 2007 +0100
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20
-# Wed Feb 7 23:56:20 2007
+# Linux kernel version: 2.6.20-grml
+# Sun Feb 25 12:45:29 2007
#
CONFIG_X86_32=y
CONFIG_GENERIC_TIME=y
@@ -1285,6 +1285,7 @@ CONFIG_SCSI_3W_9XXX=m
CONFIG_SCSI_3W_9XXX=m
CONFIG_SCSI_7000FASST=m
CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_ITERAID=m
CONFIG_SCSI_AHA152X=m
CONFIG_SCSI_AHA1542=m
CONFIG_SCSI_AHA1740=m
@@ -3638,6 +3639,8 @@ CONFIG_UFS_FS=m
CONFIG_UFS_FS=m
# CONFIG_UFS_FS_WRITE is not set
# CONFIG_UFS_DEBUG is not set
+CONFIG_UNION_FS=m
+# CONFIG_UNION_FS_XATTR is not set
#
# Network File Systems
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2.6.20/1000_2.6.20.1.patch Sun Feb 25 13:04:04 2007 +0100
@@ -0,0 +1,53 @@
+diff --git a/Makefile b/Makefile
+index 7e2750f..d26f3f5 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 6
+ SUBLEVEL = 20
+-EXTRAVERSION =
++EXTRAVERSION = .1
+ NAME = Homicidal Dwarf Hamster
+
+ # *DOCUMENTATION*
+diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
+index edde5dc..b617428 100644
+--- a/fs/nfsd/nfs2acl.c
++++ b/fs/nfsd/nfs2acl.c
+@@ -287,13 +287,20 @@ static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
+ return 1;
+ }
+
+-static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
+- struct nfsd_fhandle *resp)
++static int nfsaclsvc_release_attrstat(struct svc_rqst *rqstp, __be32 *p,
++ struct nfsd_attrstat *resp)
+ {
+ fh_put(&resp->fh);
+ return 1;
+ }
+
++static int nfsaclsvc_release_access(struct svc_rqst *rqstp, __be32 *p,
++ struct nfsd3_accessres *resp)
++{
++ fh_put(&resp->fh);
++ return 1;
++}
++
+ #define nfsaclsvc_decode_voidargs NULL
+ #define nfsaclsvc_encode_voidres NULL
+ #define nfsaclsvc_release_void NULL
+@@ -322,9 +329,9 @@ struct nfsd3_voidargs { int dummy; };
+ static struct svc_procedure nfsd_acl_procedures2[] = {
+ PROC(null, void, void, void, RC_NOCACHE, ST),
+ PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
+- PROC(setacl, setacl, attrstat, fhandle, RC_NOCACHE, ST+AT),
+- PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT),
+- PROC(access, access, access, fhandle, RC_NOCACHE, ST+AT+1),
++ PROC(setacl, setacl, attrstat, attrstat, RC_NOCACHE, ST+AT),
++ PROC(getattr, fhandle, attrstat, attrstat, RC_NOCACHE, ST+AT),
++ PROC(access, access, access, access, RC_NOCACHE, ST+AT+1),
+ };
+
+ struct svc_version nfsd_acl_version2 = {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2.6.20/4150_iteraid.patch Sun Feb 25 13:04:04 2007 +0100
@@ -0,0 +1,6548 @@
+diff -urN -X dontdiff-mika linux-2.6.17.clean/drivers/scsi/iteraid.c linux-2.6.17/drivers/scsi/iteraid.c
+--- linux-2.6.17.clean/drivers/scsi/iteraid.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17/drivers/scsi/iteraid.c 2006-06-20 15:58:04.344112250 +0200
+@@ -0,0 +1,5152 @@
++/*
++ * 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 release 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))
++static struct Scsi_Host *ite_vhost = NULL; /* SCSI virtual host */
++static Scsi_Cmnd *it8212_req_last = NULL; /* SRB request list */
++static unsigned int NumAdapters = 0; /* Adapters number */
++static PITE_ADAPTER ite_adapters[2]; /* How many adapters support */
++
++/*
++ * Notifier block to get a notify on system shutdown/halt/reboot.
++ */
++static int ite_halt(struct notifier_block *nb, ulong event, void *buf);
++static struct notifier_block ite_notifier = {
++ .notifier_call = ite_halt,
++ .next = NULL,
++ .priority = 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 void TaskQueue(void);
++static void TaskDone(PChannel, PSCSI_REQUEST_BLOCK);
++static u8 IssueIdentify(PChannel, u8, u8);
++static u8 IT8212ResetAdapter(PITE_ADAPTER);
++static u8 AtapiInterrupt(PChannel);
++
++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;
++static int ite_major = 0;
++
++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 */
++
++/*
++ * 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);
++
++ 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.
++ */
++static 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 */
++
++/*
++ * 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 configuration 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.
++ */
++static 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];
++
++ 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) * 4);
++
++ /*
++ * 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_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.
++ */
++static 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];
++
++ 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];
++
++ if ((buffer = kmalloc(512, GFP_KERNEL)) == NULL) {
++ printk("IT8212CreateDiskArray: error kmalloc.\n");
++ return -ENOMEM;
++ }
++ identifyData = (PIDENTIFY_DATA2) buffer;
++
++ /*
++ * 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) {
++ 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);
++
++ 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.
++ */
++static 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];
++
++ /*
++ * Select 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 */
++
++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);
++
++ 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
++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 };
++
++ /*
++ * If running on Firmware mode, get cable status from it.
++ */
++ for (i = 0; i < 2; i++) {
++ /*
++ * The default 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.
++ * TRUE 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;
++
++ /*
++ * Convert 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;
++ }
++
++ 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;
++
++ /*
++ * Convert 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;
++ }
++
++ 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) {
++ 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 {
++ printk("AtapiInterrupt: unexpected interrupt. intReason %x. "
++ "status %x.\n", interruptReason, statusByte);
++ return FALSE;
++ }
++ return TRUE;
++} /* end AtapiInterrupt */
++
++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 */
++
++/*
++ * 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. Because 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. Because 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) {
++ memmove((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.
++ */
++#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 TRUE.
++ */
++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;
++
++ 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
++/*
++ * Done handler for non-queued commands
++ */
++static void internal_done(Scsi_Cmnd * SCpnt)
++{
++ SCpnt->SCp.Status++;
++}
++#endif
++
++#if 0
++/*
++ * Process a command from the SCSI manager.
++ */
++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.
++ */
++ 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 an 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);
++
++#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 */
++
++/*
++ * Find and initialize any cards.
++ */
++static int iteraid_detect(struct 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;
++
++ 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
++ scsi_set_device(ite_vhost, &pPciDev->dev);
++#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 semaphore.
++ */
++ init_MUTEX(&mimd_entry_mtx);
++ }
++ dprintk("iteraid_detect exit\n");
++ return 1;
++} /* end iteraid_detect() */
++
++static int iteraid_release(struct Scsi_Host *pshost)
++{
++ u8 i;
++ PITE_ADAPTER pAdap;
++
++ if (ite_major > 0) {
++ unregister_chrdev(ite_major, "itedev");
++ ite_major = -1;
++ }
++
++ 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_reboot_notifier(&ite_notifier);
++
++ /*
++ * Tell kernel scsi-layer we are gone.
++ */
++ scsi_unregister(pshost);
++ return 0;
++} /* end iteraid_Release */
++
++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;
++}
++
++/*
++ * Process the biosparam request from the SCSI manager to return C/H/S data.
++ */
++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;
++}
++
++static int iteraid_proc_info(struct Scsi_Host *shost, char *buffer,
++ char **start, off_t offset, int length, int inout)
++{
++ return 0;
++}
++
++/*
++ * IOCTL open entry.
++ */
++static int itedev_open(struct inode *inode, struct file *filep)
++{
++ return 0;
++}
++
++/*
++ * 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;
++
++ if ((pioc = kmalloc(sizeof(uioctl_t), GFP_KERNEL)) == NULL) {
++ printk("itedev_ioctl: error kmalloc on ioctl\n");
++ return -ENOMEM;
++ }
++
++ 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");
++
++ status = IT8212GetChipStatus(pioc);
++ return 0;
++ case ITE_IOC_CREATE_DISK_ARRAY:
++ dprintk("ITE_IOC_CREATE_DISK_ARRAY\n");
++
++ 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;
++
++ return put_user(progress, (u8 *) pioc->data);
++exit:
++ return 0;
++ case ITE_IOC_RESET_ADAPTER:
++ dprintk("ITE_IOC_RESET_ADAPTER\n");
++
++#if 0
++ status = IT8212ResetAdapter();
++
++#endif
++
++ put_user(status, (u8 __user *) arg);
++ return 0;
++ case ITE_IOC_GET_DRIVER_VERSION:
++ dprintk("ITE_IOC_GET_DRIVER_VERSION\n");
++
++ put_user(driver_ver, (int __user *)arg);
++ return 0;
++ default:
++ return -EINVAL;
++ } /* end switch */
++} /* end itedev_ioctl */
++
++/*
++ * IOCTL close routine.
++ */
++static int itedev_close(struct inode *inode, struct file *filep)
++{
++ return 0;
++}
++
++static struct 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 -urN -X dontdiff-mika linux-2.6.17.clean/drivers/scsi/iteraid.h linux-2.6.17/drivers/scsi/iteraid.h
+--- linux-2.6.17.clean/drivers/scsi/iteraid.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17/drivers/scsi/iteraid.h 2006-06-20 15:57:52.931399000 +0200
+@@ -0,0 +1,1358 @@
++/*
++ * 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
++#define ITE_DEVICE_ID 0x8212 /* IT8212 */
++#define MAX_ADAPTERS 2
++#define MAX_DEVICES (MAX_ADAPTERS * 4)
++
++#define TRUE 1
++#define FALSE 0
++
++/*
++ * Undef macros which may conflict
++ */
++#undef START_STOP
++
++#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
++
++#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
++
++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)
++
++#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
++
++/*
++ * 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
++
++#define SRB_FUNCTION_EXECUTE_SCSI 0x00
++#define SRB_FUNCTION_IO_CONTROL 0x02
++#define SRB_FUNCTION_SHUTDOWN 0x07
++#define SRB_FUNCTION_FLUSH 0x08
++
++#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
++
++#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))
++
++#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
++ */
++#define DFLAGS_DEVICE_PRESENT 0x0001
++#define DFLAGS_ATAPI_DEVICE 0x0002
++#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
++ * 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 device 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)
++
++typedef struct _Channel {
++ /*
++ * IDE (ATAPI) io port address.
++ */
++ unsigned long io_ports[IDE_NR_PORTS];
++ unsigned long dma_base;
++ u16 DeviceFlags[2];
++
++ /*
++ * Indicates number of platters on changer-ish devices.
++ */
++ u32 DiscsPresent[2];
++ u8 ExpectingInterrupt;
++
++ /*
++ * Indicate last tape command was DSC Restrictive.
++ */
++ u8 RDP;
++ u8 InterruptLevel;
++
++ /*
++ * Placeholder for status register after a GET_MEDIA_STATUS command.
++ */
++ u8 ReturningMediaStatus;
++ u8 channel;
++
++ /*
++ * Indicates cable status.
++ */
++ u8 Cable80[2];
++
++ /*
++ * Reserved for alignment.
++ */
++ u8 reserved1[0];
++ unsigned short *DataBuffer;
++ u32 WordsLeft;
++ u32 RetryCount;
++
++ /*
++ * MULTIWORD_DMA or ULTRA_DMA
++ */
++ u8 DmaType[2];
++ u8 UdmaTiming[2];
++ u8 PioDmaTiming[2];
++
++ /*
++ * Keep IDE clock (50 MHz or 66 MHz) for each device.
++ */
++ u8 IdeClock[2];
++ u8 ActiveDevice;
++
++ /*
++ * Indicate whether we should perform DMA mode switch on this channel?
++ */
++ u8 DoSwitch;
++
++ /*
++ * ???
++ */
++ u8 ConvertCdb;
++ 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;
++ 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;
++ struct pci_dev *pPciDev;
++
++ /*
++ * Placeholder for CDB.
++ */
++ u8 TempCdb[MAXIMUM_CDB_SIZE];
++} Channel, *PChannel;
++
++typedef struct _Adapter {
++ char *name;
++ u8 num_channels;
++ unsigned int irq;
++ unsigned int irqOwned; /* If any irq is use */
++ u8 pci_bus;
++ u8 devfn;
++ u8 offline;
++ u8 bypass_mode; /* bypass or firmware mode */
++ u8 reserved2[1]; /* Reserved for alignment */
++ Channel *IDEChannel; /* IT8212 supports two channels */
++ struct pci_dev *pci_dev;
++} ITE_ADAPTER, *PITE_ADAPTER;
++
++#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)
++
++#endif /* #ifndef _ITERAID_H_ */
+diff -urN -X dontdiff-mika linux-2.6.17.clean/drivers/scsi/Kconfig linux-2.6.17/drivers/scsi/Kconfig
+--- linux-2.6.17.clean/drivers/scsi/Kconfig 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17/drivers/scsi/Kconfig 2006-06-20 15:57:52.935399250 +0200
+@@ -333,6 +333,15 @@
+ 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 -urN -X dontdiff-mika linux-2.6.17.clean/drivers/scsi/Makefile linux-2.6.17/drivers/scsi/Makefile
+--- linux-2.6.17.clean/drivers/scsi/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17/drivers/scsi/Makefile 2006-06-20 15:57:52.935399250 +0200
+@@ -100,6 +100,7 @@
+ 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2.6.20/4310_unionfs-2.6.20-u1.patch Sun Feb 25 13:04:04 2007 +0100
@@ -0,0 +1,7524 @@
+diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
+index 4dc28cc..c737e3e 100644
+--- a/Documentation/filesystems/00-INDEX
++++ b/Documentation/filesystems/00-INDEX
+@@ -82,6 +82,8 @@ udf.txt
+ - info and mount options for the UDF filesystem.
+ ufs.txt
+ - info on the ufs filesystem.
++unionfs/
++ - info on the unionfs filesystem
+ v9fs.txt
+ - v9fs is a Unix implementation of the Plan 9 9p remote fs protocol.
+ vfat.txt
+diff --git a/Documentation/filesystems/unionfs/00-INDEX b/Documentation/filesystems/unionfs/00-INDEX
+new file mode 100644
+index 0000000..32e96f2
+--- /dev/null
++++ b/Documentation/filesystems/unionfs/00-INDEX
+@@ -0,0 +1,8 @@
++00-INDEX
++ - this file.
++concepts.txt
++ - A brief introduction of concepts
++rename.txt
++ - Information regarding rename operations
++usage.txt
++ - Usage and known limitations
+diff --git a/Documentation/filesystems/unionfs/concepts.txt b/Documentation/filesystems/unionfs/concepts.txt
+new file mode 100644
+index 0000000..d417576
+--- /dev/null
++++ b/Documentation/filesystems/unionfs/concepts.txt
+@@ -0,0 +1,70 @@
++This file describes the concepts needed by a namespace unification file
++system.
++
++Branch Priority:
++================
++
++Each branch is assigned a unique priority - starting from 0 (highest
++priority). No two branches can have the same priority.
++
++
++Branch Mode:
++============
++
++Each branch is assigned a mode - read-write or read-only. This allows
++directories on media mounted read-write to be used in a read-only manner.
++
++
++Whiteouts:
++==========
++
++A whiteout removes a file name from the namespace. Whiteouts are needed when
++one attempts to remove a file on a read-only branch.
++
++Suppose we have a two-branch union, where branch 0 is read-write and branch
++1 is read-only. And a file 'foo' on branch 1:
++
++./b0/
++./b1/
++./b1/foo
++
++The unified view would simply be:
++
++./union/
++./union/foo
++
++Since 'foo' is stored on a read-only branch, it cannot be removed. A
++whiteout is used to remove the name 'foo' from the unified namespace. Again,
++since branch 1 is read-only, the whiteout cannot be created there. So, we
++try on a higher priority (lower numerically) branch and create the whiteout
++there.
++
++./b0/
++./b0/.wh.foo
++./b1/
++./b1/foo
++
++Later, when Unionfs traverses branches (due to lookup or readdir), it
++eliminate 'foo' from the namespace (as well as the whiteout itself.)
++
++
++Duplicate Elimination:
++======================
++
++It is possible for files on different branches to have the same name.
++Unionfs then has to select which instance of the file to show to the user.
++Given the fact that each branch has a priority associated with it, the
++simplest solution is to take the instance from the highest priority
++(numerically lowest value) and "hide" the others.
++
++
++Copyup:
++=======
++
++When a change is made to the contents of a file's data or meta-data, they
++have to be stored somewhere. The best way is to create a copy of the
++original file on a branch that is writable, and then redirect the write
++though to this copy. The copy must be made on a higher priority branch so
++that lookup and readdir return this newer "version" of the file rather than
++the original (see duplicate elimination).
++
+diff --git a/Documentation/filesystems/unionfs/rename.txt b/Documentation/filesystems/unionfs/rename.txt
+new file mode 100644
+index 0000000..e20bb82
+--- /dev/null
++++ b/Documentation/filesystems/unionfs/rename.txt
+@@ -0,0 +1,31 @@
++Rename is a complex beast. The following table shows which rename(2) operations
++should succeed and which should fail.
++
++o: success
++E: error (either unionfs or vfs)
++X: EXDEV
++
++none = file does not exist
++file = file is a file
++dir = file is a empty directory
++child= file is a non-empty directory
++wh = file is a directory containing only whiteouts; this makes it logically
++ empty
++
++ none file dir child wh
++file o o E E E
++dir o E o E o
++child X E X E X
++wh o E o E o
++
++
++Renaming directories:
++=====================
++
++Whenever a empty (either physically or logically) directory is being renamed,
++the following sequence of events should take place:
++
++1) Remove whiteouts from both source and destination directory
++2) Rename source to destination
++3) Make destination opaque to prevent anything under it from showing up
++
+diff --git a/Documentation/filesystems/unionfs/usage.txt b/Documentation/filesystems/unionfs/usage.txt
+new file mode 100644
+index 0000000..3968c9e
+--- /dev/null
++++ b/Documentation/filesystems/unionfs/usage.txt
+@@ -0,0 +1,42 @@
++Unionfs is a stackable unification file system, which can appear to merge
++the contents of several directories (branches), while keeping their physical
++content separate. Unionfs is useful for unified source tree management,
++merged contents of split CD-ROM, merged separate software package
++directories, data grids, and more. Unionfs allows any mix of read-only and
++read-write branches, as well as insertion and deletion of branches anywhere
++in the fan-out. To maintain unix semantics, Unionfs handles elimination of
++duplicates, partial-error conditions, and more.
++
++mount -t unionfs -o branch-option[,union-options[,...]] none MOUNTPOINT
++
++The available branch-option for the mount command is:
++
++dirs=branch[=ro|=rw][:...]
++specifies a separated list of which directories compose the union.
++Directories that come earlier in the list have a higher precedence than
++those which come later. Additionally, read-only or read-write permissions of
++the branch can be specified by appending =ro or =rw (default) to each
++directory.
++
++Syntax:
++dirs=/branch1[=ro|=rw]:/branch2[=ro|=rw]:...:/branchN[=ro|=rw]
++
++Example:
++dirs=/writable_branch=rw:/read-only_branch=ro
++
++
++KNOWN ISSUES:
++=============
++
++The NFS server returns -EACCES for read-only exports, instead of -EROFS.
++This means we can't reliably detect a read-only NFS export.
++
++Modifying a Unionfs branch directly, while the union is mounted, is
++currently unsupported. Any such change can cause Unionfs to oops, or stay
++silent and even RESULT IN DATA LOSS.
++
++Unionfs should not use lookup_one_len() on the underlying fs as it confuses
++NFS. Currently, unionfs_lookup() passes lookup intents to the lower
++filesystem, this eliminates part of the problem. The remaining calls to
++lookup_one_len may need to be changed to pass an intent.
++
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 0ad8803..dc0dd54 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -3282,6 +3282,13 @@ L: linux-kernel@vger.kernel.org
+ W: http://www.kernel.dk
+ S: Maintained
+
++UNIONFS
++P: Josef "Jeff" Sipek
++M: jsipek@cs.sunysb.edu
++L: unionfs@filesystems.org
++W: http://unionfs.filesystems.org/
++S: Maintained
++
+ USB ACM DRIVER
+ P: Oliver Neukum
+ M: oliver@neukum.name
+diff --git a/fs/Kconfig b/fs/Kconfig
+index 8cd2417..cf46c71 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -1554,6 +1554,25 @@ config UFS_DEBUG
+ Y here. This will result in _many_ additional debugging messages to be
+ written to the system log.
+
++config UNION_FS
++ tristate "Union file system (EXPERIMENTAL)"
++ depends on EXPERIMENTAL
++ help
++ Unionfs is a stackable unification file system, which appears to
++ merge the contents of several directories (branches), while keeping
++ their physical content separate.
++
++ See <http://unionfs.filesystems.org/> for details
++
++config UNION_FS_XATTR
++ bool "Unionfs extended attributes"
++ depends on UNION_FS
++ help
++ Extended attributes are name:value pairs associated with inodes by
++ the kernel or by users (see the attr(5) manual page).
++
++ If unsure, say N.
++
+ endmenu
+
+ menu "Network File Systems"
+diff --git a/fs/Makefile b/fs/Makefile
+index b9ffa63..76c6acc 100644
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -115,3 +115,4 @@ obj-$(CONFIG_HPPFS) += hppfs/
+ obj-$(CONFIG_DEBUG_FS) += debugfs/
+ obj-$(CONFIG_OCFS2_FS) += ocfs2/
+ obj-$(CONFIG_GFS2_FS) += gfs2/
++obj-$(CONFIG_UNION_FS) += unionfs/
+diff --git a/fs/namei.c b/fs/namei.c
+index e4f108f..5a2e89a 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -1292,8 +1292,8 @@ static struct dentry *lookup_hash(struct nameidata *nd)
+ return __lookup_hash(&nd->last, nd->dentry, nd);
+ }
+
+-/* SMP-safe */
+-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++struct dentry *lookup_one_len_nd(const char *name, struct dentry *base,
++ int len, struct nameidata *nd)
+ {
+ unsigned long hash;
+ struct qstr this;
+@@ -1313,7 +1313,7 @@ struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
+ }
+ this.hash = end_name_hash(hash);
+
+- return __lookup_hash(&this, base, NULL);
++ return __lookup_hash(&this, base, nd);
+ access:
+ return ERR_PTR(-EACCES);
+ }
+@@ -2757,7 +2757,7 @@ EXPORT_SYMBOL(follow_up);
+ EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
+ EXPORT_SYMBOL(getname);
+ EXPORT_SYMBOL(lock_rename);
+-EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_one_len_nd);
+ EXPORT_SYMBOL(page_follow_link_light);
+ EXPORT_SYMBOL(page_put_link);
+ EXPORT_SYMBOL(page_readlink);
+diff --git a/fs/unionfs/Makefile b/fs/unionfs/Makefile
+new file mode 100644
+index 0000000..e6b2e0c
+--- /dev/null
++++ b/fs/unionfs/Makefile
+@@ -0,0 +1,7 @@
++obj-$(CONFIG_UNION_FS) += unionfs.o
++
++unionfs-y := subr.o dentry.o file.o inode.o main.o super.o \
++ branchman.o rdstate.o copyup.o dirhelper.o rename.o \
++ unlink.o lookup.o commonfops.o dirfops.o sioq.o
++
++unionfs-$(CONFIG_UNION_FS_XATTR) += xattr.o
+diff --git a/fs/unionfs/branchman.c b/fs/unionfs/branchman.c
+new file mode 100644
+index 0000000..83d443a
+--- /dev/null
++++ b/fs/unionfs/branchman.c
+@@ -0,0 +1,81 @@
++/*
++ * Copyright (c) 2003-2007 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2007 Stony Brook University
++ * Copyright (c) 2003-2007 The Research Foundation of State University of New York
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/* increase the superblock generation count; effectively invalidating every
++ * upper inode, dentry and file object */
++int unionfs_ioctl_incgen(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ struct super_block *sb;
++ int gen;
++
++ sb = file->f_dentry->d_sb;
++
++ unionfs_write_lock(sb);
++
++ gen = atomic_inc_return(&UNIONFS_SB(sb)->generation);
++
++ atomic_set(&UNIONFS_D(sb->s_root)->generation, gen);
++ atomic_set(&UNIONFS_I(sb->s_root->d_inode)->generation, gen);
++
++ unionfs_write_unlock(sb);
++
++ return gen;
++}
++
++/* return to userspace the branch indices containing the file in question
++ *
++ * We use fd_set and therefore we are limited to the number of the branches
++ * to FD_SETSIZE, which is currently 1024 - plenty for most people
++ */
++int unionfs_ioctl_queryfile(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int err = 0;
++ fd_set branchlist;
++
++ int bstart = 0, bend = 0, bindex = 0;
++ struct dentry *dentry, *hidden_dentry;
++
++ dentry = file->f_dentry;
++ unionfs_lock_dentry(dentry);
++ if ((err = unionfs_partial_lookup(dentry)))
++ goto out;
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++
++ FD_ZERO(&branchlist);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ hidden_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!hidden_dentry)
++ continue;
++ if (hidden_dentry->d_inode)
++ FD_SET(bindex, &branchlist);
++ }
++
++ err = copy_to_user((void __user *)arg, &branchlist, sizeof(fd_set));
++ if (err)