Notice: the grml team migrated from Mercurial to Git.
Please visit git.grml.org instead!
| author | Michael Prokop <mika@grml.org> |
| Sun Feb 25 13:04:04 2007 +0100 (2 years ago) | |
| changeset 22 | 036807a852e7 |
| manifest | 036807a852e7 |
| parent 21 | 7a552dcb6a53 |
| child 23 | e6892c881c68 |
--- 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=yCONFIG_GENERIC_TIME=y@@ -1285,6 +1285,7 @@ CONFIG_SCSI_3W_9XXX=mCONFIG_SCSI_3W_9XXX=mCONFIG_SCSI_7000FASST=mCONFIG_SCSI_ACARD=m+CONFIG_SCSI_ITERAID=mCONFIG_SCSI_AHA152X=mCONFIG_SCSI_AHA1542=mCONFIG_SCSI_AHA1740=m@@ -3638,6 +3639,8 @@ CONFIG_UFS_FS=mCONFIG_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)