--- /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[