Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 11882 Details for
Bug 20919
ITE IT8212 ATA RAID support patch for 2.4.x kernels
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
iteraid patch for 2.4 kernel
iteraid.patch (text/plain), 201.96 KB, created by
Sami Näätänen
on 2003-05-13 07:34:21 UTC
(
hide
)
Description:
iteraid patch for 2.4 kernel
Filename:
MIME Type:
Creator:
Sami Näätänen
Created:
2003-05-13 07:34:21 UTC
Size:
201.96 KB
patch
obsolete
>diff -urHN linux-2.4.20/Documentation/Configure.help iteraid-2.4.20.patch/Documentation/Configure.help >--- linux-2.4.20/Documentation/Configure.help 2002-11-29 01:53:08.000000000 +0200 >+++ iteraid-2.4.20.patch/Documentation/Configure.help 2003-05-11 17:08:27.000000000 +0300 >@@ -8346,6 +8346,15 @@ > say M here and read <file:Documentation/modules.txt>. The module > will be called megaraid.o. > >+ITE ATA RAID support >+CONFIG_SCSI_ITERAID >+ This driver supports the ITE IT8212 ATA RAID host adapter. >+ >+ If you want to compile this driver as a module ( = code which can be >+ inserted in and removed from the running kernel whenever you want), >+ say M here and read <file:Documentation/modules.txt>. The module >+ will be called iteraid.o. >+ > Intel/ICP (former GDT SCSI Disk Array) RAID Controller support > CONFIG_SCSI_GDTH > Formerly called GDT SCSI Disk Array Controller Support. >diff -urHN linux-2.4.20/drivers/scsi/Config.in iteraid-2.4.20.patch/drivers/scsi/Config.in >--- linux-2.4.20/drivers/scsi/Config.in 2002-11-29 01:53:14.000000000 +0200 >+++ iteraid-2.4.20.patch/drivers/scsi/Config.in 2003-05-11 17:09:17.000000000 +0300 >@@ -65,6 +65,7 @@ > dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI > dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI $CONFIG_PCI > dep_tristate 'AMI MegaRAID support' CONFIG_SCSI_MEGARAID $CONFIG_SCSI >+dep_tristate 'ITE ATA RAID support' CONFIG_SCSI_ITERAID $CONFIG_SCSI > > dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI > if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then >diff -urHN linux-2.4.20/drivers/scsi/Makefile iteraid-2.4.20.patch/drivers/scsi/Makefile >--- linux-2.4.20/drivers/scsi/Makefile 2002-11-29 01:53:14.000000000 +0200 >+++ iteraid-2.4.20.patch/drivers/scsi/Makefile 2003-05-11 16:30:31.000000000 +0300 >@@ -106,6 +106,7 @@ > obj-$(CONFIG_SCSI_DC390T) += tmscsim.o > obj-$(CONFIG_SCSI_AM53C974) += AM53C974.o > obj-$(CONFIG_SCSI_MEGARAID) += megaraid.o >+obj-$(CONFIG_SCSI_ITERAID) += iteraid.o > obj-$(CONFIG_SCSI_ACARD) += atp870u.o > obj-$(CONFIG_SCSI_SUNESP) += esp.o > obj-$(CONFIG_SCSI_GDTH) += gdth.o >diff -urHN linux-2.4.20/drivers/scsi/README.iteraid iteraid-2.4.20.patch/drivers/scsi/README.iteraid >--- linux-2.4.20/drivers/scsi/README.iteraid 1970-01-01 02:00:00.000000000 +0200 >+++ iteraid-2.4.20.patch/drivers/scsi/README.iteraid 2003-05-11 16:59:22.000000000 +0300 >@@ -0,0 +1,8 @@ >+ >+You can check for newer driver version from >+ >+http://www.ite.com.tw/productInfo/pc_userinfo.asp?FileName=L2 >+ >+WARNING that page was very bad and didn't work with mozilla. >+With old netsacape one might have better luck. >+ >diff -urHN linux-2.4.20/drivers/scsi/iteraid.c iteraid-2.4.20.patch/drivers/scsi/iteraid.c >--- linux-2.4.20/drivers/scsi/iteraid.c 1970-01-01 02:00:00.000000000 +0200 >+++ iteraid-2.4.20.patch/drivers/scsi/iteraid.c 2003-05-11 16:29:33.000000000 +0300 >@@ -0,0 +1,5747 @@ >+/* >+ * linux/drivers/scsi/iteraid.c >+ * >+ * (C) Copyright 2002-2003 Integrated Technology Express, inc. >+ * >+ * Nov 11, 2002 Mark Lu file created. >+ * >+ * ITE IT8212 RAID controller device driver for Linux. >+ * >+ * This program is free software; you can redistribute it and/or modify it >+ * under the terms of the GNU General Public License as published by the >+ * Free Software Foundation; either version 2, or (at your option) any >+ * later version. >+ * >+ * This program is distributed in the hope that it will be useful, but >+ * WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >+ * General Public License for more details. >+ * >+ * Revision 0.0 2002/12/05 15:12:12 root >+ * Empty function bodies; detect() works. >+ * >+ * Revision 0.1 2002/12/17 19:21:37 root >+ * First "dma thing doesn't work" version. >+ * >+ * Revision 0.3 2002/12/23 17:12:09 root >+ * Rewrite the dma routines. Reference the ide-dma.c. >+ * >+ * Revision 0.4 2002/12/26 10:19:29 root >+ * The dma read/write works, using some ways to prove it. But there is a >+ * problem about the "unknown partition table". The fdisk is ok, but >+ * after writing the created partitions, it still shows the "unknown >+ * partition table" and i can't access the created partitions. >+ * >+ * Revision 0.5 2003/01/07 21:49:30 root >+ * The problem of "unknown partition table" has been solved. >+ * We must "ENABLE CLUSTERING". There is still a another problem about >+ * the SCATTER/GATHER. >+ * >+ * Revision 0.6 2003/01/10 17:45:32 root >+ * The SCATTER/GATHER problem has been solved. Now verify the read/write >+ * function and make sure each RAID configurations are workable. If testing >+ * is OK, then it will be a version 1.0..... >+ * >+ * Revision 1.0 2003/01/16 17:45:32 root >+ * First release version. >+ * >+ * FixME 1: >+ * In RedHat 7.3, if using SG_ALL, the SCSI will timeout. It looks like >+ * an command is requested but the interrupt is not been asserted. So >+ * try to add a watchdog timer to monitor the interrupts. But this kind >+ * of situration will not happen in Mandrake 9.0 and also when using >+ * SG_NONE in RedHat 7.3. >+ * >+ * FixME 2: >+ * Module load problem in RedHat 7.3. >+ * >+ * Fixed: Compile in the graphic mode (GNOME or KDE) will fix the >+ * module load problem. >+ * >+ * Revision 1.1 2003/02/10 10:32:21 root >+ * Compile in the graphic mode (GNOME or KDE) will fix the >+ * module load problem. >+ * >+ * Revision 1.2 2003/02/18 14:10:35 root >+ * Fix the interrupt service routine for share irq problem. >+ * >+ * ATAPI support ---> schedule is three weeks. (2003/02/28) >+ * >+ * Revision 1.3 2003/02/27 >+ * First relase ATAPI version. But there will be an error if no disc in the >+ * CD-ROM. Because the commands like TEST_UNIT_READY and READ_CAPACITY will >+ * get the error response. This situration in WINDOWS will be then send the >+ * REQUEST SENSE command to the device but in Linux, it will never get >+ * REQUEST SENSE command. So can we send by ourself??? >+ * >+ * 2003/03/05 root >+ * >+ * Note 1: >+ * According to "The Linux SCSI Generic (sg) HOWTO", the device will respond >+ * with a single byte value call the 'scsi_status'. GOOD is the scsi status >+ * indicating everything has gone well. The most common other status is >+ * CHECK CONDITION. In this latter case, the SCSI mid layer issues a REQUEST >+ * SENSE SCSI command. The response of the REQUEST SENSE is 18 bytes or more >+ * in length and is called the "sense buffer". It will indicate why the original >+ * command may not have been executed. It is important to realize that a CHECK >+ * CONDITION may very in severity from informative (e.g. command needed to be >+ * retried before succeeding) to fatal (e.g. 'medium error' which often indicates >+ * it is time to replace the disk). >+ * >+ * Note 2: >+ * When using the ATAPI BIOS, we also do not need to set up the timimg in linux >+ * driver. But it is necessary to write the timing routine in win system, cause it >+ * has a s1, s2, s3 mode and devices wake up from these modes need to be initialized >+ * again and do not pass through the BIOS. >+ * >+ * Note 3: >+ * The 48-bit support and AP for RAID in linux will the next job. >+ * >+ * Revision 1.31 2003/03/14 09:40:35 root >+ * Fix the 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. >+ * >+ * 2003/04/28 root >+ * Fixed: Do not enable interrupt again when send each command in >+ * IdeSendCommand() routine. >+ * >+ * TODO list: >+ * >+ * (1) Using the new error code handler instead of the old style. >+ * Because the old one will not be used above kernl-2.5. >+ * >+ * (2) Rewrite the abort and reset functions. >+ */ >+ >+#include <linux/module.h> >+ >+MODULE_AUTHOR ("ITE,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/blk.h> >+#include <linux/hdreg.h> >+#include <linux/string.h> >+#include <linux/delay.h> >+#include <linux/reboot.h> >+#include <linux/spinlock.h> >+#include <linux/fs.h> >+ >+#include <asm/errno.h> >+#include <asm/io.h> >+#include <asm/irq.h> >+#include <asm/uaccess.h> >+ >+#include "sd.h" >+#include "scsi.h" >+#include "hosts.h" >+ >+#include "iteraid.h" >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) >+MODULE_LICENSE("GPL"); >+#endif >+ >+#define MARK_DEBUG_DUMP_MEM 0 /* 1=Enable dump memory content */ >+#define MARK_DEBUG_BYPASS_MODE 0 /* 1=Enable use bypass mode */ >+ >+#define PRD_BYTES 8 /* PRD table size */ >+#define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES)) >+ >+struct Scsi_Host * ite_vhost = 0; /* SCSI virtual host */ >+Scsi_Cmnd * it8212_req_last = 0; /* SRB request list */ >+ >+unsigned int NumAdapters = 0; /* Adapters number */ >+PITE_ADAPTER ite_adapters[2]; /* How many adapters support */ >+ >+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 spinlock_t gio_request_lock = SPIN_LOCK_UNLOCKED; >+ >+static int driver_ver = 134; /* Current driver version */ >+ >+/************************************************************************ >+ * The File Operations structure for the ioctl interface of the driver. >+ ************************************************************************/ >+static struct file_operations itedev_fops = >+{ >+ 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. >+ ************************************************************************/ >+UCHAR >+MapError(PChannel pChan, PSCSI_REQUEST_BLOCK Srb) >+{ >+ >+ UCHAR errorByte; >+ UCHAR srbStatus; >+ UCHAR 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; >+ } >+ } >+ /* >+ * IF this is IDE error. >+ */ >+ else >+ { >+ 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 = 0xb; >+ 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 */ >+ >+/************************************************************************ >+ * >+ ************************************************************************/ >+UCHAR >+RaidGetHighestBit(UCHAR Number) >+{ >+ >+ char bit; >+ >+ for (bit = 7; bit >= 0; bit--) >+ { >+ if (Number & (1 << bit)) return bit; >+ } >+ >+ return 0xFF; >+ >+} /* end RaidGetHighestBit */ >+ >+/************************************************************************ >+ * Reset IDE controller or ATAPI device. >+ ************************************************************************/ >+BOOLEAN >+AtapiResetController(PChannel pChan) >+{ >+ >+ ULONG i; >+ UCHAR status; >+ ULONG dma_base = pChan->dma_base; >+ BOOLEAN resetResult = FALSE; >+ >+ printk("AtapiResetController\n"); >+ >+ /* >+ * 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((UCHAR)((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. >+ */ >+ >+ /* >+ * Clear request tracking fields. >+ */ >+ pChan->CurrentSrb = NULL; >+ pChan->WordsLeft = 0; >+ pChan->DataBuffer = NULL; >+ >+ /* >+ * Indicate ready for next request. >+ */ >+ TaskDone(pChan, pChan->CurrentSrb); >+ } >+ >+ /* >+ * Clear expecting interrupt flag. >+ */ >+ pChan->ExpectingInterrupt = FALSE; >+ pChan->RDP = FALSE; >+ >+ resetResult = IT8212ResetAdapter(); >+ >+ for (i = 0; i < 4; i++) >+ { >+ /* >+ * Reenable interrupts. >+ */ >+ outb((UCHAR)(((i & 1) << 4) | 0xA0), pChan->io_ports[ATAPI_SELECT_OFFSET]); >+ outb(IDE_DC_REENABLE_CONTROLLER, pChan->io_ports[ATAPI_CONTROL_OFFSET]); >+ } >+ >+ return resetResult; >+ >+} /* end AtapiResetController */ >+ >+/************************************************************************ >+ * IDE start read/write transfer >+ ************************************************************************/ >+void >+IdeStartTransfer >+( >+ PChannel pChan, >+ PSCSI_REQUEST_BLOCK Srb, >+ ULONG startingSector, >+ ULONG SectorNumber >+) >+{ >+ >+ UCHAR DiskId = (UCHAR) Srb->TargetId; >+ UCHAR drvSelect; >+ UCHAR bmClearStat; >+ ULONG dma_base = pChan->dma_base; >+ >+ dprintk("IdeStartTransfer enter\n"); >+ >+ /* >+ * Set watch dog timer to monitor interrupts. Timer will be removed >+ * on DeviceInterrupt. >+ */ >+#if (0) >+ SetWatchDogTimer(pChan); >+#endif >+ >+ /* >+ * 48-bit support. >+ */ >+ if ((startingSector + SectorNumber) > 0x0FFFFFFF) >+ { >+ /* >+ * Select drive and set LBA mode. >+ */ >+ outb((UCHAR) (((DiskId & 0x1) << 4) | 0xA0 | 0x40), >+ pChan->io_ports[IDE_SELECT_OFFSET]); >+ >+ /* >+ * Sector count register. >+ */ >+ outb((UCHAR) (SectorNumber >> 8), pChan->io_ports[IDE_NSECTOR_OFFSET]); >+ outb((UCHAR) SectorNumber, pChan->io_ports[IDE_NSECTOR_OFFSET]); >+ >+ /* >+ * LBA low register. >+ */ >+ outb((UCHAR) (startingSector >> 24), pChan->io_ports[IDE_LOCYL_OFFSET]); >+ outb((UCHAR) startingSector, pChan->io_ports[IDE_LOCYL_OFFSET]); >+ >+ /* >+ * LBA mid register. >+ */ >+ outb((UCHAR) 0, pChan->io_ports[IDE_MIDCYL_OFFSET]); >+ outb((UCHAR) (startingSector >> 8), pChan->io_ports[IDE_MIDCYL_OFFSET]); >+ >+ /* >+ * LBA high register. >+ */ >+ outb((UCHAR) 0, pChan->io_ports[IDE_HCYL_OFFSET]); >+ outb((UCHAR) (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]); >+ } >+ } >+ /* >+ * 28-bit addressing. >+ */ >+ else >+ { >+ /* >+ * Select drive and set LBA mode. >+ */ >+ drvSelect = (UCHAR) (startingSector >> 24); >+ drvSelect = drvSelect | (((UCHAR) DiskId & 0x1) << 4) | 0x40 | 0xA0; >+ >+ outb(drvSelect, pChan->io_ports[IDE_SELECT_OFFSET]); >+ outb((UCHAR) SectorNumber, pChan->io_ports[IDE_NSECTOR_OFFSET]); >+ outb((UCHAR) startingSector, pChan->io_ports[IDE_LOCYL_OFFSET]); >+ outb((UCHAR)(startingSector >> 8), pChan->io_ports[IDE_MIDCYL_OFFSET]); >+ outb((UCHAR)(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 */ >+ >+/************************************************************************ >+ * IDE setup the PRD table >+ ************************************************************************/ >+static int >+IdeBuildSglist(PChannel pChan, PSCSI_REQUEST_BLOCK Srb) >+{ >+ >+ int nents = 0; >+ ULONG 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].address = 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 int * table = pChan->dmatable_cpu; >+ unsigned int count = 0; >+ int i; >+ struct scatterlist * sg; >+ >+ pChan->sg_nents = 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, ULONG dma_base, USHORT num_ports) >+{ >+ >+ char * name0 = "CHANNEL0"; >+ char * name1 = "CHANNEL1"; >+ >+ printk("Channel[%d] BM-DMA at 0x%04lX-0x%04lX\n", pChan->channel, dma_base, >+ dma_base + num_ports - 1); >+ >+ /* >+ * Check if this io space is used by other device. >+ */ >+ if (check_region(dma_base, num_ports)) >+ { >+ printk("Port addresses already in use.\n"); >+ return; >+ } >+ >+ /* >+ * Request the io space (region). >+ */ >+ if (pChan->channel == 0) >+ { >+ request_region(dma_base, num_ports, name0); >+ } >+ else >+ { >+ request_region(dma_base, num_ports, name1); >+ } >+ >+ /* >+ * 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("Allocate prd table failed.\n"); >+ return; >+ } >+ >+ memset(pChan->dmatable_cpu, 0, PRD_ENTRIES * PRD_BYTES); >+ >+ /* >+ * Allocate SCATTER/GATHER table buffer. >+ */ >+ pChan->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, >+ GFP_KERNEL); >+ >+ if (pChan->sg_table == NULL) >+ { >+ printk("Allocate sg_table failed.\n"); >+ pci_free_consistent(pChan->pPciDev, PRD_ENTRIES * PRD_BYTES, >+ pChan->dmatable_cpu, pChan->dmatable_dma); >+ return; >+ } >+ >+ return; >+ >+} /* end IdeSetupDma */ >+ >+/************************************************************************ >+ * >+ ************************************************************************/ >+void >+IT8212ReconfigChannel(PChannel pChan, UCHAR ArrayId, UCHAR Operation) >+{ >+ >+ UCHAR enableVirtualChannel; >+ struct pci_dev * pPciDev = pChan->pPciDev; >+ >+ pci_read_config_byte(pPciDev, 0x43, &enableVirtualChannel); >+ >+ if (Operation == DisableChannel) >+ { >+ enableVirtualChannel &= ~(1 << ArrayId); >+ printk("IT8212ReconfigChannel: Disable channel %X\n", ArrayId); >+ } >+ else >+ { >+ enableVirtualChannel |= ~(1 << ArrayId); >+ printk("IT8212ReconfigChannel: Enable channel %X\n", ArrayId); >+ } >+ >+ printk("IT8212ReconfigChannel: Channel enabled after set 0x%X\n", >+ enableVirtualChannel); >+ >+ /* >+ * Set enabled virtual channels. >+ */ >+ pci_write_config_byte(pPciDev, 0x43, enableVirtualChannel); >+ >+} /* end IT8212ReconfigChannel */ >+ >+/************************************************************************ >+ * Get the chip status. This is a vendor specific command. According to >+ * all of the device configurations, the BIOS then can consider the >+ * existing RAID configuration reasonable. If the existing RAID configur- >+ * ation is not reasonable, or if there is NO existing RAID configuration >+ * , the BIOS can ask the user to setup the RAID configuration. Finally, >+ * the BIOS or AP should send the SET CHIP STATUS to every virtual device. >+ * Only after receiving SET CHIP STATUS command, the corresponding virtual >+ * device will be active. >+ ************************************************************************/ >+UCHAR >+IT8212GetChipStatus(uioctl_t *ioc) >+{ >+ >+ ULONG PriMasterIsNull = FALSE; >+ UCHAR statusByte; >+ UCHAR srbStatus; >+ PITE_ADAPTER pAdap; >+ PChannel pChan; >+ PHYSICAL_DISK_STATUS * pPhyDiskInfo; >+ >+ printk("IT8212GetChipStatus enter\n"); >+ >+ /* >+ * Only support one controller now! In the future, we can pass the >+ * argument (user ioctl structure) to know which controller need to be >+ * identified. >+ */ >+ pAdap = ite_adapters[0]; >+ pChan = &pAdap->IDEChannel[0]; >+ >+ /* >+ * Allocate space for PHYSICAL_DISK_STATUS. >+ */ >+ if ((pPhyDiskInfo = kmalloc(sizeof(PHYSICAL_DISK_STATUS) * 4, GFP_KERNEL)) == NULL) >+ { >+ printk("error kmalloc on PHYSCIAL_DISK_STATUS.\n"); >+ return -ENOMEM; >+ } >+ >+ >+ /* >+ * Always send GET CHIP STATUS command to primary channel master device. >+ * Select device. >+ */ >+ outb((UCHAR) 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, (PUSHORT)pPhyDiskInfo, 256); >+ >+ /* >+ * Copy physical disk info to user area. >+ */ >+ copy_to_user((PUSHORT)ioc->data, (PUSHORT)pPhyDiskInfo, 256); >+ >+ /* >+ * Check error. >+ */ >+ WaitForCommandComplete(pChan, statusByte); >+ >+ if (statusByte != IDE_STATUS_IDLE) >+ { >+ printk("IT8212GetChipStatus: Disk[0] return unexpected status after"); >+ printk("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); >+ } >+ >+ >+ printk("IT8212GetChipStatus exit\n"); >+ >+ return srbStatus; >+ >+} /* end IT8212GetChipStatus */ >+ >+/************************************************************************ >+ * Erase the partition table. >+ ************************************************************************/ >+UCHAR >+IT8212ErasePartition(uioctl_t *pioc) >+{ >+ >+ UCHAR drvSelect; >+ UCHAR statusByte = 0; >+ UCHAR srbStatus; >+ UCHAR * buffer; >+ PRAID_CREATE_INFO createInfo = (PRAID_CREATE_INFO) pioc->data; >+ PITE_ADAPTER pAdap; >+ PChannel pChan; >+ >+ if (!createInfo->ErasePartition || (createInfo->RaidType == RAID_LEVEL_NODISK)) >+ return SRB_STATUS_SUCCESS; >+ >+ pAdap = ite_adapters[0]; >+ >+ if (createInfo->DiskArrayId < 2) pChan = &pAdap->IDEChannel[0]; >+ pChan = &pAdap->IDEChannel[1]; >+ >+ /* >+ * Allocate 512 bytes for buffer. >+ */ >+ if ((buffer = kmalloc(512, GFP_KERNEL)) == NULL) >+ { >+ printk("IT8212ErasePartition: error kmalloc.\n"); >+ return -ENOMEM; >+ } >+ >+ memset(buffer, 0, 512); >+ >+ /* >+ * Select device. >+ */ >+ drvSelect = (((UCHAR) 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, (PUSHORT)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]); >+ >+ return srbStatus; >+ >+} /* end IT8212ErasePartition */ >+ >+/************************************************************************ >+ * >+ ************************************************************************/ >+UCHAR >+IT8212TruncateReduentSectors >+( >+ ULONG OriginalSectorCount, >+ USHORT StripeSizeInKBytes >+) >+{ >+ >+ USHORT stripeSizeInSector; >+ >+ /* >+ * 0 means using default value (32 sectors). >+ */ >+ if (StripeSizeInKBytes == 0) >+ { >+ stripeSizeInSector = 64 * 2; >+ } >+ else >+ { >+ stripeSizeInSector = StripeSizeInKBytes * 2; >+ } >+ >+ return ((OriginalSectorCount / stripeSizeInSector) * stripeSizeInSector); >+ >+ >+} /* end IT8212TruncateReduentSectors */ >+ >+/************************************************************************ >+ * >+ ************************************************************************/ >+ULONG >+IT8212DiskArrayAddressableSector(PUCHAR DiskArrayCreateInfo) >+{ >+ >+ PRAID_CREATE_INFO createInfo = (PRAID_CREATE_INFO) DiskArrayCreateInfo; >+ ULONG MinDiskCapacity; >+ ULONG ArrayCapacity; >+ UCHAR DiskNo; >+ UCHAR NumOfDisks; >+ >+ MinDiskCapacity = ArrayCapacity = NumOfDisks = 0; >+ >+ 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]); >+ >+ 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 - 2; >+ 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. >+ ************************************************************************/ >+UCHAR >+IT8212CreateDiskArray(uioctl_t *pioc) >+{ >+ >+ UCHAR i; >+ UCHAR subCommand = 0xFF; >+ UCHAR statusByte; >+ UCHAR dmaSupported; >+ UCHAR udmaSupported; >+ UCHAR srbStatus; >+ void * buffer; >+ ULONG UserAddressableSectors; >+ ULONG PriMasterIsNull = FALSE; >+ PRAID_CREATE_INFO createInfo = (PRAID_CREATE_INFO)pioc->data; >+ PIDENTIFY_DATA2 identifyData; >+ PIT8212_SET_CHIP_STATUS_INFO setChipStatus; >+ PITE_ADAPTER pAdap; >+ PChannel pChan; >+ >+ USHORT 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 */ >+ }; >+ >+ USHORT 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 */ >+ }; >+ >+ 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; >+ } >+ >+ pAdap = ite_adapters[pioc->AdapterNo]; >+ if (pioc->DiskNo < 2) >+ { >+ pChan = &pAdap->IDEChannel[0]; >+ } >+ else >+ { >+ pChan = &pAdap->IDEChannel[1]; >+ } >+ >+ /* >+ * Allocate 512-bytes buffer. >+ */ >+ if ((buffer = kmalloc(512, GFP_KERNEL)) == NULL) >+ { >+ printk("IT8212CreateDiskArray: error kmalloc.\n"); >+ return -ENOMEM; >+ } >+ >+ identifyData = (PIDENTIFY_DATA2) buffer; >+ setChipStatus = (PIT8212_SET_CHIP_STATUS_INFO) (buffer + 256); >+ >+ /* >+ * Configure to RAID or NORMAL. >+ */ >+ if (subCommand == 0x50) >+ { >+ /* >+ * Zero identify data structure. >+ */ >+ memset((PUCHAR) 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 = %lX\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 &= (UCHAR) createInfo->DMASupported[i]; >+ udmaSupported &= (UCHAR) 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; >+ } >+ >+ /* >+ * There are some contrains of disk placement. AP will take care of it. >+ */ >+ >+ /* >+ * This command should be sent to Virtual Primary Master. >+ */ >+ >+ /* >+ * Select device. >+ */ >+ outb((UCHAR) 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) >+ { >+ goto exit_error; >+ } >+ >+ IT8212ReconfigChannel(pChan, createInfo->DiskArrayId, EnableChannel); >+ srbStatus = SRB_STATUS_ERROR; >+ } >+ >+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]); >+ >+ return srbStatus; >+ >+ >+} /* end IT8212CreateDiskArray */ >+ >+/************************************************************************ >+ * Return "virtual" drive 512 bytes identification data. >+ ************************************************************************/ >+UCHAR >+IT8212IssueIdentify(uioctl_t *pioc) >+{ >+ >+ UCHAR channum; >+ UCHAR devnum; >+ UCHAR statusByte; >+ UCHAR srbStatus = 0; >+ 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[pioc->AdapterNo]; >+ >+ 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((UCHAR)((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, (PUSHORT)&pChan->FullIdentifyData, 256); >+ >+ /* >+ * Then copy to user area. >+ * unsigned long copy_to_user(void *to, const void *from, unsigned long count). >+ */ >+ copy_to_user((PUSHORT) (pioc->data + ((devnum + channum * 2) * 512)), >+ (PUSHORT)&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 */ >+ >+/************************************************************************ >+ * Reset the controller >+ ************************************************************************/ >+BOOLEAN >+IT8212ResetAdapter(void) >+{ >+ >+ BOOLEAN resetChannel[2]; >+ UCHAR channel; >+ UCHAR device; >+ UCHAR i; >+ UCHAR status[4]; >+ PChannel pChan; >+ PITE_ADAPTER pAdap = ite_adapters[0]; >+ >+ /* >+ * First, perform ATAPI softreset if ATAPI devices 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 present on this channel, perform channel reset. >+ */ >+ for (channel = 0; channel < 2; 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++) >+ { >+ for (device = 0; device < 2; device++) >+ { >+ if (pChan->DeviceFlags[device] & DFLAGS_DEVICE_PRESENT) >+ { >+ outb((UCHAR)((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. >+ ************************************************************************/ >+UCHAR >+IT8212Rebuild(uioctl_t *pioc) >+{ >+ >+ UCHAR rebuildDirection; >+ UCHAR statusByte = 0; >+ PRAID_REBUILD_INFO apRebuildInfo = (PRAID_REBUILD_INFO) pioc->data; >+ PITE_ADAPTER pAdap; >+ PChannel pChan; >+ >+ rebuildDirection = (apRebuildInfo->Resume << 4) | (apRebuildInfo->DestDisk << 2) | >+ apRebuildInfo->SrcDisk; >+ >+ apRebuildInfo->Status = 0xFF; >+ >+ pAdap = ite_adapters[pioc->AdapterNo]; >+ if (pioc->DiskNo < 2) >+ { >+ pChan = &pAdap->IDEChannel[0]; >+ } >+ else >+ { >+ pChan = &pAdap->IDEChannel[1]; >+ } >+ >+ /* >+ * Selcet device. >+ */ >+ outb((UCHAR)((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 SRB_STATUS_ERROR; >+ } >+ >+ return SRB_STATUS_SUCCESS; >+ >+} /* 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 >+ ************************************************************************/ >+VOID >+IT8212SwitchDmaMode(PChannel pChan, UCHAR DeviceId) >+{ >+ >+ UCHAR pciControl; >+ UCHAR channel; >+ UCHAR device; >+ UCHAR configByte = 0; >+ UCHAR RevisionID; >+ struct pci_dev * pPciDev = pChan->pPciDev; >+ >+ /* >+ * These tables are for performance issue. Better formance than lots >+ * of "Shifts". >+ */ >+ UCHAR dmaModeV10[4] = {0x18, 0x18, 0x60, 0x60}; >+ UCHAR udmaModeV10[4] = {0xE7, 0xE7, 0x9F, 0x9F}; >+ UCHAR ideClock[4] = {0xFD, 0xFD, 0xFB, 0xFB}; >+ >+#if (0) >+ UCHAR dmaMode[4] = {0x08, 0x10, 0x20, 0x40}; >+ UCHAR udmaMode[4] = {0xF7, 0xEF, 0xDF, 0xBF}; >+#endif >+ >+ /* >+ * 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("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); >+ } >+ /* >+ * Running on ULTRA DMA mode. >+ */ >+ else >+ { >+ /* >+ * 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, (UCHAR) (0x56 + (channel * 4)), configByte); >+ pci_write_config_byte(pPciDev, (UCHAR) (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, (UCHAR) (0x54 + (channel * 4)), configByte); >+ } >+ >+ /* >+ * Record the Active device on this channel >+ */ >+ pChan->ActiveDevice = device; >+ >+} /* end IT8212SwitchDmaMode */ >+ >+/************************************************************************ >+ * IT8212 read/write routines >+ ************************************************************************/ >+ULONG >+IT8212ReadWrite(PChannel pChan, PSCSI_REQUEST_BLOCK Srb) >+{ >+ >+ UCHAR statusByte = 0; >+ ULONG startingSector; >+ ULONG sectorNumber; >+ ULONG capacity; >+ PITE_ADAPTER pAdap = ite_adapters[0]; >+ >+ /* >+ * 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 = (USHORT) ((Srb->DataTransferLength + 0x1FF) / 0x200); >+ >+ capacity = pChan->IdentifyData[Srb->TargetId & 0x1].UserAddressableSectors; >+ if (capacity == 0x0FFFFFFF) >+ { >+ capacity = pChan->IdentifyData[Srb->TargetId].Capacity_48bit_LOW; >+ } >+ >+ if ((startingSector + sectorNumber - 1) > capacity) >+ { >+ printk("IT8212ReadWrite: Disk[%d] over disk size.\n", Srb->TargetId); >+ printk("Capacity: %ld. Starting sector: %ld. Sector number: %ld\n", >+ capacity, startingSector, sectorNumber); >+ return SRB_STATUS_ERROR; >+ } >+ >+ /* >+ * Select device. >+ */ >+ outb((UCHAR)((Srb->TargetId & 0x1) << 4 | 0xA0), pChan->io_ports[IDE_SELECT_OFFSET]); >+ >+ /* >+ * Wait for device ready (Not Busy and Not DRQ). >+ */ >+ WaitForDeviceReady(pChan, statusByte); >+ if ((statusByte & IDE_STATUS_BUSY) || (statusByte & IDE_STATUS_DRQ) || >+ (statusByte == 0)) >+ { >+ printk("IT8212ReadWrite: Disk[%d] not ready. Status=0x%x\n", >+ Srb->TargetId, statusByte); >+ return SRB_STATUS_BUSY; >+ } >+ >+ /* >+ * First, switch to DMA or UDMA mode if running on bypass mode. >+ */ >+ if (pAdap->bypass_mode) >+ { >+ IT8212SwitchDmaMode(pChan, Srb->TargetId); >+ } >+ >+ /* >+ * Check the SCATTER/GATHER count. The upper will give the different >+ * memory address depend on whether use_sg is used or not. >+ */ >+ if (Srb->UseSg == 0) >+ { >+ IdeBuildDmaTable(pChan, Srb); >+ } >+ else >+ { >+ IdeBuildDmaSgTable(pChan, Srb); >+ } >+ >+ /* >+ * Start transfer the data. >+ */ >+ IdeStartTransfer(pChan, Srb, startingSector, sectorNumber); >+ >+ /* >+ * Wait for interrupt. >+ */ >+ return SRB_STATUS_PENDING; >+ >+} /* end IT8212ReadWrite */ >+ >+/************************************************************************ >+ * Setup the transfer mode. >+ ************************************************************************/ >+VOID >+IT8212SetTransferMode >+( >+ PChannel pChan, >+ ULONG DiskId, >+ UCHAR TransferMode, >+ UCHAR ModeNumber >+) >+{ >+ >+ UCHAR statusByte = 0; >+ >+ /* >+ * Select device. >+ */ >+ outb((UCHAR) ((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[%ld] 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[%ld]", DiskId); >+ printk("return unexpected status after issue command. 0x%x\n", >+ statusByte); >+ } >+ >+} /* end IT8212SetTransferMode */ >+ >+/************************************************************************ >+ * Set the best transfer mode for device >+ ************************************************************************/ >+VOID >+IT8212SetBestTransferMode(PITE_ADAPTER pAdap, PChannel pChan, UCHAR channel) >+{ >+ >+ UCHAR i; >+ UCHAR k; >+ UCHAR transferMode; >+ UCHAR modeNumber; >+ UCHAR pciControl; >+ UCHAR device; >+ UCHAR configByte; >+ UCHAR cableStatus[2] = {CABLE_40_PIN, CABLE_40_PIN}; >+ UCHAR 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. >+ */ >+ UCHAR 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. >+ */ >+ UCHAR dmaTiming[2][3] = >+ { >+ {0x88, 0x32, 0x31}, >+ {0x66, 0x22, 0x21} >+ }; >+ >+ /* >+ * PIO timing table for 66 MHz clock. >+ * PIO timing table for 50 MHz clock. >+ */ >+ UCHAR pioTiming[2][5] = >+ { >+ {0xAA, 0xA3, 0xA1, 0x33, 0x31}, >+ {0x88, 0x82, 0x81, 0x32, 0x21} >+ }; >+ >+ UCHAR 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". >+ */ >+ //UCHAR dmaModeV10[4] = {0x18, 0x18, 0x60, 0x60}; >+ UCHAR udmaModeV10[4] = {0xE7, 0xE7, 0x9F, 0x9F}; >+ UCHAR dmaMode[4] = {0x08, 0x10, 0x20, 0x40}; >+ UCHAR udmaMode[4] = {0xF7, 0xEF, 0xDF, 0xBF}; >+ UCHAR ideClock[4] = {0xFD, 0xFD, 0xFB, 0xFB}; >+ >+ for (i = 0; i < 2; i++) >+ { >+ /* >+ * The dafault of cable status is in PCI configuration 0x40. >+ */ >+ cableStatus[i] = pChan->Cable80[i]; >+ >+ /* >+ * channel -->0 to 1. >+ * device -->0 or 1. >+ */ >+ pChan->UseDma[i] = TRUE; >+ device = i & 1; >+ >+ if (!(pChan->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT) || >+ (pChan->DeviceFlags[i] & DFLAGS_CONFIG_CHANGED)) >+ { >+ pio_dma_timing[0][channel][device] = pio_dma_timing[0][channel][device + 2] = 0; >+ pio_dma_timing[1][channel][device] = pio_dma_timing[1][channel][device + 2] = 0; >+ continue; >+ } >+ >+ /* >+ * Set PIO Mode. >+ */ >+ ideIdentifyData = &pChan->IdentifyData[i]; >+ if ((!(ideIdentifyData->ValidFieldIndicator & 0x02)) || (ideIdentifyData->AdvancedPIOModes == 0)) >+ { >+ transferMode = PIO_FLOW_CONTROL; >+ modeNumber = 2; >+ } >+ else >+ { >+ transferMode = PIO_FLOW_CONTROL; >+ modeNumber = RaidGetHighestBit((UCHAR) 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, (UCHAR) (0x56 + (channel * 4)), configByte); >+ pci_write_config_byte(pPciDev, (UCHAR) (0x56 + (channel * 4) + 1), configByte); >+ } >+ else >+ { >+ pci_write_config_byte(pPciDev, (UCHAR) (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, (UCHAR) (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 */ >+ >+/************************************************************************ >+ * Initialize bypass(transparent) mode if BIOS is not ready >+ ************************************************************************/ >+BOOLEAN >+IT8212InitBypassMode(struct pci_dev *pPciDev) >+{ >+ >+ USHORT configWord = 0; >+ >+ /* >+ * 1.2. Reset local CPU, and set BIOS not ready. >+ */ >+ pci_write_config_byte(pPciDev, 0x5E, 0x01); >+ >+ /* >+ * 3.4. Set to bypass mode, and reset PCI bus. >+ */ >+ pci_write_config_byte(pPciDev, 0x50, 0x80); >+ pci_write_config_byte(pPciDev, 0x50, 0x00); >+ >+ /* >+ * 5. Set PIO timing register of primary register. >+ */ >+ pci_write_config_byte(pPciDev, 0x54, 0xA3); >+ >+ /* >+ * 6. Set PIO timing register of secondary register. >+ */ >+ pci_write_config_byte(pPciDev, 0x58, 0xA3); >+ >+ /* >+ * Testing. >+ */ >+ pci_write_config_word(pPciDev, 0x4, 0x7); >+ >+ pci_read_config_word(pPciDev, 0x50, &configWord); >+ configWord = configWord | 0xA000; >+ pci_write_config_word(pPciDev, 0x40, configWord); >+ >+ pci_write_config_byte(pPciDev, 0x0D, 0x00); >+ pci_write_config_dword(pPciDev,0x4C, 0x02040204); >+ pci_write_config_byte(pPciDev, 0x42, 0x36); >+ >+ return TRUE; >+ >+} /* end IT8212InitBypassMode */ >+ >+/************************************************************************ >+ * This is the interrupt service routine for ATAPI IDE miniport driver. >+ * TURE if expecting an interrupt. >+ ************************************************************************/ >+BOOLEAN >+IT8212Interrupt(PChannel pChan) >+{ >+ >+ UCHAR statusByte = 0; >+ UCHAR bmstatus = 0; >+ ULONG i = 0; >+ ULONG bmbase = pChan->dma_base; >+ PSCSI_REQUEST_BLOCK Srb = pChan->CurrentSrb; >+ PITE_ADAPTER pAdap = ite_adapters[0]; >+ >+ if (!Srb || !pChan->ExpectingInterrupt) >+ { >+ dprintk("!Suspicious Interrupt\n"); >+ >+ /* >+ * Clear interrupt by reading status register. >+ */ >+ outb((UCHAR) 0xA0, pChan->io_ports[IDE_SELECT_OFFSET]); >+ GetBaseStatus(pChan, statusByte); >+ outb((UCHAR) 0xB0, pChan->io_ports[IDE_SELECT_OFFSET]); >+ GetBaseStatus(pChan, statusByte); >+ outb(bmbase + 2, (UCHAR) (inb(bmbase + 2) | BM_STAT_FLG_INT)); >+ >+ return FALSE; >+ } >+ >+ /* >+ * To handle share IRQ condition. >+ * If the interrupt is not ours, return FALSE. >+ */ >+ bmstatus = inb(bmbase + 2); >+ if ((bmstatus & BM_STAT_FLG_INT) == 0) >+ { >+ printk("IT8212Interrupt: Spurious interrupt (Interrupt bit is not on)\n"); >+ return FALSE; >+ } >+ >+ /* >+ * Bug Fix: All PIO access are blocked during bus master operation, so >+ * stop bus master operation before we try to access IDE registers. >+ */ >+ if (pAdap->bypass_mode) >+ { >+ outb(bmbase, 0); >+ } >+ >+ /* >+ * Clear interrupt by reading status. >+ */ >+ GetBaseStatus(pChan, statusByte); >+ outb(bmbase + 2, (UCHAR) (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. >+ ************************************************************************/ >+BOOLEAN >+AtapiInterrupt(PChannel pChan) >+{ >+ >+ ULONG wordCount = 0; >+ ULONG wordsThisInterrupt = 256; >+ ULONG status; >+ ULONG i; >+ UCHAR statusByte; >+ UCHAR interruptReason; >+ PSCSI_REQUEST_BLOCK srb = pChan->CurrentSrb; >+ >+ /* >+ * 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, (PUSHORT)srb->Cdb, 6); >+ >+ return TRUE; >+ } >+ else if (interruptReason == 0x0 && (statusByte & IDE_STATUS_DRQ)) >+ { >+ /* >+ * Write the data. >+ */ >+ >+ /* >+ * Pick up bytes to transfer and convert to words. >+ */ >+ wordCount = inb(pChan->io_ports[ATAPI_LCYL_OFFSET]); >+ wordCount |= inb(pChan->io_ports[ATAPI_HCYL_OFFSET]) << 8; >+ >+ /* >+ * Covert bytes to words. >+ */ >+ wordCount >>= 1; >+ >+ if (wordCount != pChan->WordsLeft) >+ { >+ printk( "AtapiInterrupt: %ld words requested; %ld words xferred\n", >+ pChan->WordsLeft, wordCount); >+ } >+ >+ /* >+ * Verify this makes sense. >+ */ >+ if (wordCount > pChan->WordsLeft) >+ { >+ wordCount = pChan->WordsLeft; >+ } >+ >+ /* >+ * Ensure that this is a write command. >+ */ >+ if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) >+ { >+ dprintk("AtapiInterrupt: Write interrupt\n"); >+ WaitOnBusy(pChan, statusByte); >+ WriteBuffer(pChan, pChan->DataBuffer, wordCount); >+ >+# if (0) >+ /* >+ * Translate ATAPI data back to SCSI data if needed (don't >+ * convert if the original command is SCSIOP_MODE_SELECT10) >+ */ >+ if (srb->Cdb[0] == ATAPI_MODE_SELECT && pchan->ConvertCdb) >+ { >+ Atapi2Scsi(pChan, srb, (char *)pChan->DataBuffer, wordCount << 1); >+ } >+# endif >+ } >+ else >+ { >+ printk("AtapiInterrupt: Int reason %x, but srb is for a write %p.\n", >+ interruptReason, srb); >+ >+ /* >+ * Fail this request. >+ */ >+ status = SRB_STATUS_ERROR; >+ goto CompleteRequest; >+ } >+ >+ /* >+ * Advance data buffer pointer and bytes left. >+ */ >+ pChan->DataBuffer += wordCount; >+ pChan->WordsLeft -= wordCount; >+ >+ return TRUE; >+ } >+ else if (interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) >+ { >+ /* >+ * Pick up bytes to transfer and convert to words. >+ */ >+ wordCount = inb(pChan->io_ports[ATAPI_LCYL_OFFSET]); >+ wordCount |= inb(pChan->io_ports[ATAPI_HCYL_OFFSET]) << 8; >+ >+ /* >+ * Covert bytes to words. >+ */ >+ wordCount >>= 1; >+ if (wordCount != pChan->WordsLeft) >+ { >+ printk("AtapiInterrupt: %ld words requested; %ld 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); >+ >+ /* >+ * From Windows DDK >+ * 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. >+ */ >+ *((PUCHAR)pChan->DataBuffer + 2) = 2; >+ } >+ } >+ else >+ { >+ printk("AtapiInterrupt: Int reason %x, but srb is for a read %p.\n", >+ interruptReason, srb); >+ >+ /* >+ * Fail this request. >+ */ >+ status = SRB_STATUS_ERROR; >+ goto CompleteRequest; >+ } >+ >+ /* >+ * Advance data buffer pointer and bytes left. >+ */ >+ pChan->DataBuffer += wordCount; >+ pChan->WordsLeft -= wordCount; >+ >+ /* >+ * Check for read command complete. >+ */ >+ if (pChan->WordsLeft == 0) >+ { >+ /* >+ * Work around to make many atapi devices return correct sector size >+ * of 2048. Also certain devices will have sector count == 0x00, check >+ * for that also. >+ */ >+ if ((srb->Cdb[0] == 0x25) && >+ ((pChan->IdentifyData[srb->TargetId & 1].GeneralConfiguration >> 8) & 0x1F) == 0x05) >+ { >+ pChan->DataBuffer -= wordCount; >+ if (pChan->DataBuffer[0] == 0x00) >+ { >+ *((ULONG *) &(pChan->DataBuffer[0])) = 0xFFFFFF7F; >+ } >+ >+ *((ULONG *) &(pChan->DataBuffer[2])) = 0x00080000; >+ pChan->DataBuffer += wordCount; >+ } >+ } >+ return TRUE; >+ } >+ else if (interruptReason == 0x3 && !(statusByte & IDE_STATUS_DRQ)) >+ { >+ dprintk("Command Complete!\n"); >+ /* >+ * Command complete. >+ */ >+ if (pChan->WordsLeft) >+ { >+ status = SRB_STATUS_DATA_OVERRUN; >+ } >+ else >+ { >+ status = SRB_STATUS_SUCCESS; >+ } >+ >+CompleteRequest: >+ >+ if (status == SRB_STATUS_ERROR) >+ { >+ /* >+ * Map error to specific SRB status and handle request sense. >+ */ >+ printk("AtapiInterrupt error\n"); >+ >+ status = MapError(pChan, srb); >+ >+ /* >+ * Try to recover it.... 2003/02/27 >+ */ >+ >+ >+ pChan->RDP = FALSE; >+ } >+ else >+ { >+ /* >+ * Wait for busy to drop. >+ */ >+ for (i = 0; i < 30; i++) >+ { >+ GetStatus(pChan, statusByte); >+ if (!(statusByte & IDE_STATUS_BUSY)) >+ { >+ break; >+ } >+ udelay(500); >+ } >+ >+ if (i == 30) >+ { >+ /* >+ * Reset the controller. >+ */ >+ printk("AtapiInterrupt: Resetting due to BSY still up - %x.\n", statusByte); >+ AtapiResetController(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(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 = (UCHAR)status; >+ >+ /* >+ * Check for underflow. >+ */ >+ if (pChan->WordsLeft) >+ { >+ /* >+ * Subtract out residual words and update if filemark hit, >+ * setmark hit , end of data, end of media... >+ */ >+ if (!(pChan->DeviceFlags[srb->TargetId & 1] & DFLAGS_TAPE_DEVICE)) >+ { >+ if (status == SRB_STATUS_DATA_OVERRUN) >+ { >+ srb->DataTransferLength -= pChan->WordsLeft * 2; >+ } >+ else >+ { >+ srb->DataTransferLength = 0; >+ } >+ } >+ else >+ { >+ srb->DataTransferLength -= pChan->WordsLeft * 2; >+ } >+ } >+ >+ GetBaseStatus(pChan, statusByte); >+ if (pChan->RDP && !(statusByte & IDE_STATUS_DSC)) >+ { >+ printk("-@@-\n"); >+ } >+ else >+ { >+ /* >+ * Clear current SRB. Indicate ready for next request. >+ */ >+ pChan->CurrentSrb = NULL; >+ TaskDone(pChan, srb); >+ } >+ } >+ else >+ { >+ printk( "AtapiInterrupt: No SRB!\n"); >+ } >+ >+ return TRUE; >+ } >+ else >+ { >+ /* >+ * Unexpected int. >+ */ >+ printk("AtapiInterrupt: Unexpected interrupt. InterruptReason %x. Status %x.\n", >+ interruptReason, statusByte); >+ return FALSE; >+ } >+ >+ return TRUE; >+ >+} /* end AtapiInterrupt */ >+ >+/************************************************************************ >+ * IRQ handler >+ ************************************************************************/ >+static void >+Irq_Handler(int irq, void *dev_id, struct pt_regs *regs) >+{ >+ >+ UCHAR i; >+ UCHAR j; >+ ULONG flags; >+ >+ dprintk("Irq_Handler enter\n"); >+ >+ spin_lock_irqsave(&io_request_lock, flags); >+ >+ /* >+ * Scan for interrupt to process. >+ */ >+ for (i = 0; i < NumAdapters; i++) >+ { >+ PITE_ADAPTER pAdap = ite_adapters[i]; >+ if (pAdap->irq != irq) continue; >+ >+ for (j = 0; j < pAdap->num_channels; j++) >+ { >+ IT8212Interrupt(&pAdap->IDEChannel[j]); >+ } >+ } >+ >+ spin_unlock_irqrestore(&io_request_lock, flags); >+ >+ dprintk("Irq_Handler exit\n"); >+ >+} /* end Irq_Handler */ >+ >+/************************************************************************ >+ * This routine handles IDE Verify. >+ ************************************************************************/ >+UCHAR >+IdeVerify(PChannel pChan, PSCSI_REQUEST_BLOCK Srb) >+{ >+ >+ ULONG startingSector; >+ ULONG sectors; >+ ULONG endSector; >+ USHORT sectorCount; >+ UCHAR drvSelect; >+ UCHAR statusByte = 0; >+ >+ /* >+ * Select device >+ */ >+ outb((UCHAR)((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 = (USHORT)(((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 %ld, Ending sector %ld\n", >+ startingSector, endSector); >+ >+ if (endSector > sectors) >+ { >+ /* >+ * Too big, round down. >+ */ >+ printk("IdeVerify: Truncating request to %lx blocks\n", sectors - startingSector - 1); >+ >+ outb((UCHAR)((sectors - startingSector - 1) >> 8), pChan->io_ports[IDE_NSECTOR_OFFSET]); >+ outb((UCHAR)(sectors - startingSector - 1), pChan->io_ports[IDE_NSECTOR_OFFSET]); >+ } >+ else >+ { >+ /* >+ * Set up sector count register. Round up to next block. >+ */ >+ if (sectorCount > 0xFFFF) >+ { >+ sectorCount = (USHORT)0xFFFF; >+ } >+ >+ outb((UCHAR)(sectorCount >> 8), pChan->io_ports[IDE_NSECTOR_OFFSET]); >+ outb((UCHAR) sectorCount, pChan->io_ports[IDE_NSECTOR_OFFSET]); >+ } >+ >+ /* >+ * Indicate expecting an interrupt. >+ */ >+ pChan->ExpectingInterrupt = TRUE; >+ >+ /* >+ * Set up LBA address >+ */ >+ outb((UCHAR) (startingSector >> 24), pChan->io_ports[IDE_LOCYL_OFFSET]); >+ outb((UCHAR) startingSector, pChan->io_ports[IDE_LOCYL_OFFSET]); >+ outb((UCHAR) 0, pChan->io_ports[IDE_MIDCYL_OFFSET]); >+ outb((UCHAR) (startingSector >> 8), pChan->io_ports[IDE_MIDCYL_OFFSET]); >+ outb((UCHAR) 0, pChan->io_ports[IDE_HCYL_OFFSET]); >+ outb((UCHAR) (startingSector >> 16), pChan->io_ports[IDE_HCYL_OFFSET]); >+ >+ /* >+ * Send verify command. >+ */ >+ outb(IDE_COMMAND_READ_VERIFY_EXT, pChan->io_ports[IDE_COMMAND_OFFSET]); >+ } >+ /* >+ * 28-bit addressing >+ */ >+ else >+ { >+ sectors = pChan->IdentifyData[Srb->TargetId & 0x01].UserAddressableSectors; >+ >+ printk("IdeVerify: Starting sector %ld, Ending sector %ld\n", >+ startingSector, endSector); >+ >+ if (endSector > sectors) >+ { >+ /* >+ * Too big, round down. >+ */ >+ printk("IdeVerify: Truncating request to %ld blocks\n", sectors - startingSector - 1); >+ outb((UCHAR)(sectors - startingSector - 1), pChan->io_ports[IDE_NSECTOR_OFFSET]); >+ } >+ else >+ { >+ /* >+ * Set up sector count register. Round up to next block. >+ */ >+ if (sectorCount > 0xFF) >+ { >+ sectorCount = (USHORT)0xFF; >+ } >+ outb((UCHAR)sectorCount, pChan->io_ports[IDE_NSECTOR_OFFSET]); >+ } >+ >+ /* >+ * Indicate expecting an interrupt. >+ */ >+ pChan->ExpectingInterrupt = TRUE; >+ >+ /* >+ * Set up LBA address >+ */ >+ outb((UCHAR) startingSector, pChan->io_ports[IDE_LOCYL_OFFSET]); >+ outb((UCHAR) (startingSector >> 8), pChan->io_ports[IDE_MIDCYL_OFFSET]); >+ outb((UCHAR) (startingSector >> 16),pChan->io_ports[IDE_HCYL_OFFSET]); >+ >+ /* >+ * Select driver, set LBA mode, set LBA (27:27) >+ */ >+ drvSelect = (UCHAR) (startingSector >> 24); >+ drvSelect = drvSelect | (((UCHAR) Srb->TargetId & 0x1) << 4) | 0xA0 | 0x40; >+ outb(drvSelect, pChan->io_ports[IDE_SELECT_OFFSET]); >+ >+ /* >+ * Send verify command. >+ */ >+ outb(IDE_COMMAND_READ_VERIFY, pChan->io_ports[IDE_COMMAND_OFFSET]); >+ } >+ >+ /* >+ * Wait for interrupt. >+ */ >+ return SRB_STATUS_PENDING; >+ >+} /* end IdeVerify */ >+ >+/************************************************************************ >+ * This function is used to copy memory with overlapped destination and >+ * source. I guess ScsiPortMoveMemory cannot handle this well. Can it? >+ ************************************************************************/ >+void >+IT8212MoveMemory(PUCHAR DestAddr, PUCHAR SrcAddr, LONG ByteCount) >+{ >+ >+ long i; >+ >+ dprintk("IT8212MoveMemory: DestAddr=0x%x, SrcAddr=0x%x, ByteCount=0x%x\n", >+ DestAddr, SrcAddr, ByteCount); >+ >+ if (DestAddr > SrcAddr) >+ { >+ /* >+ * If Destination Area is in the back of the Source Area, copy from >+ * the end of the requested area. >+ */ >+ for (i = (ByteCount - 1); i >= 0; i--) >+ { >+ *(DestAddr + i) = *(SrcAddr + i); >+ } >+ } >+ else if (DestAddr < SrcAddr) >+ { >+ /* >+ * If Destination Area is in the front of the Source Area, copy from >+ * the begin of the requested area. >+ */ >+ for (i = 0; i < ByteCount; i++) >+ { >+ *(DestAddr + i) = *(SrcAddr + i); >+ } >+ } >+ >+} /* end IT8212MoveMemory */ >+ >+/************************************************************************ >+ * Convert SCSI packet command to Atapi packet command. >+ ************************************************************************/ >+void >+Scsi2Atapi(PChannel pChan, PSCSI_REQUEST_BLOCK Srb) >+{ >+ >+ dprintk("++++++++++ Scsi2Atapi (0x%X) ++++++++++\n", Srb->Cdb[0]); >+ dprintk("Srb->DataBuffer=0x%x\n", Srb->DataBuffer); >+ dprintk("Srb->DataTransferLength=0x%x\n", Srb->DataTransferLength); >+ dprintk("CDB=0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", >+ Srb->Cdb[0], Srb->Cdb[1], Srb->Cdb[2], Srb->Cdb[3], Srb->Cdb[4], Srb->Cdb[5], >+ Srb->Cdb[6], Srb->Cdb[7], Srb->Cdb[8], Srb->Cdb[9], Srb->Cdb[10], Srb->Cdb[11]); >+ >+ /* >+ * 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((PUCHAR)modeSense10, 0, MAXIMUM_CDB_SIZE); >+ >+ /* >+ * 2. Fill in command code (SCSI_MODE_SENSE10). >+ */ >+ modeSense10->OperationCode = ATAPI_MODE_SENSE; >+ modeSense10->Dbd = modeSense6->Dbd; >+ modeSense10->PageCode = modeSense6->PageCode; >+ modeSense10->Pc = modeSense6->Pc; >+ modeSense10->SubpageCode = modeSense6->SubpageCode; >+ modeSense10->AllocationLengthLsb = modeSense6->AllocationLength; >+ modeSense10->Control = modeSense6->Control; >+ >+ /* >+ * 3. Becasuse we will fake a block descripter (-8), and >+ * translate the header (+4), so the requested length >+ * should be modified. That is, -8+4=-4 bytes. >+ */ >+ modeSense10->AllocationLengthLsb -= 4; >+ >+ break; >+ } >+ >+ /* >+ * Convert the command from SCSIOP_MODE_SELECT (0x15) to >+ * SCSIOP_MODE_SELECT10 (0x5A). >+ */ >+ case SCSIOP_MODE_SELECT: >+ { >+ UCHAR tempHeader[sizeof(PSCSI_MODE_PARAMETER_HEADER6)]; >+ USHORT 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((PUCHAR)modeSelect10, 0, MAXIMUM_CDB_SIZE); >+ >+ /* >+ * 2. Fill in command code (SCSI_MODE_SENSE10). >+ */ >+ modeSelect10->OperationCode = ATAPI_MODE_SELECT; >+ modeSelect10->SPBit = modeSelect6->SPBit; >+ modeSelect10->PFBit = modeSelect6->PFBit; >+ modeSelect10->ParameterListLengthLsb = modeSelect6->ParameterListLength; >+ modeSelect10->Control = modeSelect6->Control; >+ >+ /* >+ * 3. Becasuse we will remove the block descripter (-8), and >+ * translate the header (+4), so the requested length should >+ * be modified. That is, -8+4=-4 bytes. >+ */ >+ modeSelect10->ParameterListLengthLsb -= 4; >+ >+ /* >+ * Second, convert the parameter page format from SCSI to ATAPI. >+ */ >+ >+ /* >+ * Remove the mode parameter data (except the header and the >+ * block descripter). >+ */ >+ byteCount = modeSelect6->ParameterListLength - sizeof(SCSI_MODE_PARAMETER_HEADER6) - sizeof(SCSI_MODE_PARAMTER_BLOCK_DESCRIPTER); >+ if (byteCount > 0) >+ { >+ IT8212MoveMemory( >+ (PUCHAR) header10 + sizeof(SCSI_MODE_PARAMETER_HEADER10), >+ (PUCHAR) 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((PUCHAR)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; >+ } >+ } >+ >+ dprintk("Srb->DataTransferLength=0x%x\n", Srb->DataTransferLength); >+ dprintk("Final CDB=0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", >+ Srb->Cdb[0], Srb->Cdb[1], Srb->Cdb[2], Srb->Cdb[3], Srb->Cdb[4], Srb->Cdb[5], >+ Srb->Cdb[6], Srb->Cdb[7], Srb->Cdb[8], Srb->Cdb[9], Srb->Cdb[10], Srb->Cdb[11]); >+ dprintk("---------- Scsi2Atapi (0x%X) ----------\n", Srb->Cdb[0]); >+ >+} /* end Scsi2Atapi */ >+ >+/************************************************************************ >+ * Send ATAPI packet command to device. >+ ************************************************************************/ >+UCHAR >+AtapiSendCommand(PChannel pChan, PSCSI_REQUEST_BLOCK Srb) >+{ >+ >+ ULONG bmAddress = pChan->dma_base; >+ ULONG i; >+ ULONG flags; >+ UCHAR statusByte; >+ UCHAR byteCountLow; >+ UCHAR byteCountHigh; >+ UCHAR useDMA; >+ UCHAR RevisionID = 0; >+ UCHAR bmClearStat; >+ 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((UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0), >+ pChan->io_ports[ATAPI_SELECT_OFFSET]); >+ >+ /* >+ * Try to enable interrupt again. (2003/02/25) >+ */ >+#if (0) >+ outb(0x00, pChan->io_ports[ATAPI_CONTROL_OFFSET]); >+#endif >+ >+ /* >+ * Verify that controller is ready for next command. >+ */ >+ GetStatus(pChan, statusByte); >+ >+ dprintk("AtapiSendCommand: Entered with status %x\n", statusByte); >+ >+ if (statusByte & IDE_STATUS_BUSY) >+ { >+ printk("AtapiSendCommand: Device busy (%x)\n", statusByte); >+ return SRB_STATUS_BUSY; >+ } >+ >+ if (statusByte & IDE_STATUS_ERROR) >+ { >+ if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) >+ { >+ printk("AtapiSendCommand: Error on entry: (%x)\n", statusByte); >+ >+ /* >+ * Read the error reg. to clear it and fail this request. >+ */ >+ return MapError(pChan, Srb); >+ } >+ } >+ >+ /* >+ * If a tape drive doesn't have DSC set and the last command is >+ * restrictive, don't send the next command. See discussion of >+ * Restrictive Delayed Process commands in QIC-157. >+ */ >+ if ((!(statusByte & IDE_STATUS_DSC)) && (flags & DFLAGS_TAPE_DEVICE) && pChan->RDP) >+ { >+ mdelay(1); >+ printk("AtapiSendCommand: DSC not set. %x\n", statusByte); >+ return SRB_STATUS_BUSY; >+ } >+ >+ if (statusByte & IDE_STATUS_DRQ) >+ { >+ printk("AtapiSendCommand: Enter with status (%x). Attempt to recover.\n", >+ statusByte); >+ >+ /* >+ * Try to drain the data that one preliminary device thinks that it has >+ * to transfer. Hopefully this random assertion of DRQ will not be present >+ * in production devices. >+ */ >+ for (i = 0; i < 0x10000; i++) >+ { >+ GetStatus(pChan, statusByte); >+ >+ if (statusByte & IDE_STATUS_DRQ) >+ { >+ /* >+ * Note: The data register is always referenced as a 16-bit word. >+ */ >+ inw(pChan->io_ports[ATAPI_DATA_OFFSET]); >+ } >+ else >+ { >+ break; >+ } >+ } >+ >+ if (i == 0x10000) >+ { >+ printk("AtapiSendCommand: DRQ still asserted.Status (%x)\n", statusByte); >+ printk("AtapiSendCommand: Issued soft reset to Atapi device. \n"); >+ >+ AtapiSoftReset(pChan, Srb->TargetId); >+ >+ /* >+ * Re-initialize Atapi device. >+ */ >+ IssueIdentify(pChan, (Srb->TargetId & 1), IDE_COMMAND_ATAPI_IDENTIFY); >+ >+ /* >+ * Inform the port driver that the bus has been reset. >+ */ >+ >+ /* >+ * Clean up device extension fields that AtapiStartIo won't. >+ */ >+ pChan->ExpectingInterrupt = FALSE; >+ pChan->RDP = FALSE; >+ >+ return SRB_STATUS_BUS_RESET; >+ } >+ } >+ >+ if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) >+ { >+ /* >+ * As the cdrom driver sets the LUN field in the cdb, it must be removed. >+ */ >+ Srb->Cdb[1] &= ~0xE0; >+ >+ if ((Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY) && (flags & DFLAGS_SANYO_ATAPI_CHANGER)) >+ { >+ /* >+ * Torisan changer. TUR's are overloaded to be platter switches. >+ */ >+ Srb->Cdb[7] = Srb->Lun; >+ } >+ } >+ >+ /* >+ * Convert SCSI to ATAPI commands if needed >+ */ >+ switch (Srb->Cdb[0]) >+ { >+ case SCSIOP_MODE_SENSE: >+ case SCSIOP_MODE_SELECT: >+ if (flags & DFLAGS_ATAPI_DEVICE) >+ { >+ Scsi2Atapi(pChan, Srb); >+ } >+ break; >+ } >+ >+ if (pChan->UseDma[Srb->TargetId & 1]) >+ { >+ switch (Srb->Cdb[0]) >+ { >+ case SCSIOP_READ: /* (0x28) */ >+ case 0xA8: /* READ(12) */ >+ case SCSIOP_READ_CD: >+ >+ if (Srb->DataTransferLength == 0) >+ { >+ break; >+ } >+ >+ /* >+ * First, switch to DMA or UDMA mode if running on Bypass mode. >+ */ >+ if (pAdap->bypass_mode) >+ { >+ IT8212SwitchDmaMode(pChan, Srb->TargetId); >+ } >+ >+ /* >+ * Check the SCATTER/GATHER count. The upper will give the >+ * different memory address depend on whether use_sg is used >+ * or not. >+ */ >+ if (Srb->UseSg == 0) >+ { >+ IdeBuildDmaTable(pChan, Srb); >+ } >+ else >+ { >+ IdeBuildDmaSgTable(pChan, Srb); >+ } >+ >+ bmClearStat = inb(bmAddress + 2); >+ if (Srb->TargetId & 0x01) >+ { >+ bmClearStat = bmClearStat | BM_DRV1_DMA_CAPABLE | >+ BM_STAT_FLG_INT | BM_STAT_FLG_ERR; >+ } >+ else >+ { >+ bmClearStat = bmClearStat | BM_DRV0_DMA_CAPABLE | >+ BM_STAT_FLG_INT | BM_STAT_FLG_ERR; >+ } >+ >+ useDMA = 1; >+ >+ outb(0, bmAddress); >+ >+ /* >+ * Setup PRD table physical address. >+ */ >+ outl(pChan->dmatable_dma, bmAddress + 4); >+ >+ /* >+ * Clear the status. >+ */ >+ outb(bmClearStat, bmAddress + 2); >+ >+ break; >+ } /* end switch (Srb->Cdb[0]) */ >+ } >+ >+ /* >+ * Set data buffer pointer and words left. >+ */ >+ pChan->DataBuffer = (PUSHORT)Srb->DataBuffer; >+ >+ if (useDMA) >+ { >+ pChan->WordsLeft = 0; >+ } >+ else >+ { >+ pChan->WordsLeft = Srb->DataTransferLength / 2; >+ } >+ >+ outb((UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0), >+ pChan->io_ports[ATAPI_SELECT_OFFSET]); >+ >+ WaitOnBusy(pChan, statusByte); >+ >+ /* >+ * Write transfer byte count to registers. >+ */ >+ byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF); >+ byteCountHigh = (UCHAR)(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, (PUSHORT)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=%ld\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. >+ ************************************************************************/ >+ULONG >+IdeSendCommand(PChannel pChan, PSCSI_REQUEST_BLOCK Srb) >+{ >+ >+ UCHAR statusByte; >+ ULONG status; >+ ULONG 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->lun != 0) || >+ (!pChan->DeviceFlags[pREQ->target & 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], "IT8212X ", 16); >+ memcpy(&request_buffer[32], "1.3", 3); >+ >+ /* >+ * Set the removable bit, if applicable. >+ */ >+ if (pChan->DeviceFlags[pREQ->target & 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->target & 0x01].UserAddressableSectors == 0x0FFFFFFF) >+ { >+ i = pChan->IdentifyData[pREQ->target & 0x01].Capacity_48bit_LOW - 1; >+ } >+ else >+ { >+ i = pChan->IdentifyData[pREQ->target & 0x01].UserAddressableSectors - 1; >+ } >+ >+ ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress = >+ (((PUCHAR)&i)[0] << 24) | (((PUCHAR)&i)[1] << 16) | >+ (((PUCHAR)&i)[2] << 8) | ((PUCHAR)&i)[3]; >+ >+ status = SRB_STATUS_SUCCESS; >+ break; >+ >+ case SCSIOP_VERIFY: >+ status = IdeVerify(pChan, Srb); >+ break; >+ >+ case SCSIOP_READ: >+ case SCSIOP_WRITE: >+ status = IT8212ReadWrite(pChan, Srb); >+ break; >+ >+ case SCSIOP_START_STOP_UNIT: >+ /* >+ * Determine what type of operation we should perform >+ */ >+ status = SRB_STATUS_SUCCESS; >+ break; >+ >+ case SCSIOP_REQUEST_SENSE: >+ /* >+ * This function makes sense buffers to report the results >+ * of the original GET_MEDIA_STATUS command >+ */ >+ status = SRB_STATUS_INVALID_REQUEST; >+ break; >+ >+ default: >+ printk("IdeSendCommand: Unsupported command %x\n", Srb->Cdb[0]); >+ status = SRB_STATUS_INVALID_REQUEST; >+ } /* end switch */ >+ >+ return status; >+ >+} /* end IdeSendCommand */ >+ >+/************************************************************************ >+ * This routine is called from the SCSI port driver synchronized with >+ * the kernel to start an IO request. If the current SRB is busy, return >+ * FALSE, else return TURE. >+ ************************************************************************/ >+BOOLEAN >+AtapiStartIo(PChannel pChan, PSCSI_REQUEST_BLOCK Srb) >+{ >+ >+ ULONG 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 = (UCHAR)status; >+ dprintk("AtapiStartIo: status=%lx\n", status); >+ TaskDone(pChan, Srb); >+ } >+ >+ return TRUE; >+ >+} /* end AtapiStartIo */ >+ >+/************************************************************************ >+ * Convert Scsi_Cmnd structure to SCSI_REQUEST_BLOCK >+ ************************************************************************/ >+void >+MapRequest(Scsi_Cmnd * pREQ, PSCSI_REQUEST_BLOCK Srb) >+{ >+ >+ Srb->Length = sizeof(SCSI_REQUEST_BLOCK); >+ Srb->CdbLength = pREQ->cmd_len; >+ Srb->TargetId = pREQ->target; >+ Srb->Lun = pREQ->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 */ >+ >+/************************************************************************ >+ * Function: void ite_watch_timer(PChannel pChan) >+ * Description: WatchDog timer >+ * Returns: None >+ ************************************************************************/ >+void >+ite_watch_timer(PChannel pChan) >+{ >+ >+ unsigned long flags; >+ Scsi_Cmnd * pREQ; >+ PSCSI_REQUEST_BLOCK Srb; >+ >+ printk("ite_watch_timer enter\n"); >+ >+ spin_lock_irqsave (&io_request_lock, flags); >+ >+ Srb = pChan->CurrentSrb; >+ if (Srb) { pREQ = Srb->pREQ; } >+ else { pREQ = NULL; } >+ >+ spin_unlock_irqrestore (&io_request_lock, flags); >+ >+ printk("ite_watch_timer exit\n"); >+ >+} /* end ite_watch_timer */ >+ >+/************************************************************************ >+ * Function: void iteretry(PChannel pChan) >+ * Description: This function will be call after waitting 1 ticks (1 tick >+ * = 1/Hz second). It will execute retry operation. >+ * Returns: None >+ ************************************************************************/ >+void >+iteretry(PChannel pChan) >+{ >+ >+ Scsi_Cmnd * pREQ; >+ unsigned long flags; >+ >+ spin_lock_irqsave(&io_request_lock, flags); >+ >+ if (pChan->CurrentSrb) >+ { >+ pREQ = pChan->CurrentSrb->pREQ; >+ printk("##iteretry##\n"); >+ TaskStart(pChan, pREQ); >+ } >+ >+ spin_unlock_irqrestore(&io_request_lock, flags); >+ >+} /* end iteretry */ >+ >+/************************************************************************ >+ * A task execution has been done. For OS request, we need to Notify OS >+ * and invoke next take which wait at queue >+ ************************************************************************/ >+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. >+ ************************************************************************/ >+void >+TaskStart(PChannel pChan, Scsi_Cmnd *pREQ) >+{ >+ >+ PSCSI_REQUEST_BLOCK Srb; >+ >+ dprintk("TaskStart(pChan=%p, pREQ=%p)\n", pChan, pREQ); >+ >+ Srb = &pChan->_Srb; >+ >+ /* >+ * Clear the SRB structure. >+ */ >+ memset(Srb, 0, sizeof(SCSI_REQUEST_BLOCK)); >+ >+ /* >+ * Convert Scsi_Cmnd structure to SCSI_REQUEST_BLOCK. >+ */ >+ MapRequest(pREQ, Srb); >+ >+ /* >+ * Start IDE I/O command. >+ */ >+ AtapiStartIo(pChan, Srb); >+ >+} /* end TaskStart */ >+ >+/************************************************************************ >+ * Check if queue is empty. If there are request in queue, transfer the >+ * request to HIM's request and execute the request. >+ ************************************************************************/ >+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); >+ >+ pAdap = ite_adapters[0]; >+ >+ if (SCpnt->target < 2) pChan = &pAdap->IDEChannel[0]; >+ else pChan = &pAdap->IDEChannel[1]; >+ >+ /* >+ * Check the command. >+ */ >+ if (SCpnt->host) >+ { >+ if (SCpnt->channel != 0 || SCpnt->target >= 4) >+ { >+ /* >+ * Returns that we have a bad target. >+ */ >+ dprintk("BAD TARGET\n"); >+ SCpnt->result = (DID_BAD_TARGET << 16); >+ SCpnt->scsi_done(SCpnt); >+ goto check_next; >+ } >+ } >+ >+ 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. >+ ****************************************************************/ >+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); >+ >+ spin_lock_irqsave(&gio_request_lock, flags); >+ TaskQueue(); >+ spin_unlock_irqrestore(&gio_request_lock, flags); >+ >+ dprintk("@@Queuecommand exit@@\n"); >+ >+ return 0; >+ >+} /* end iteraid_queuecommand */ >+ >+/**************************************************************** >+ * Name: internal_done :LOCAL >+ * Description: Done handler for non-queued commands >+ * Parameters: SCpnt - Pointer to SCSI command structure. >+ * Returns: Nothing. >+ ****************************************************************/ >+static void >+internal_done(Scsi_Cmnd * SCpnt) >+{ >+ >+ SCpnt->SCp.Status++; >+ >+} /* end internal_done */ >+ >+/**************************************************************** >+ * Name: iteraid_command >+ * Description: Process a command from the SCSI manager. >+ * Parameters: SCpnt - Pointer to SCSI command structure. >+ * Returns: Status code. >+ ****************************************************************/ >+int >+iteraid_command(Scsi_Cmnd *SCpnt) >+{ >+ >+ DWORD 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 */ >+ >+/************************************************************************ >+ * Enables disables media status notification >+ ************************************************************************/ >+void >+IdeMediaStatus(BOOLEAN EnableMSN, PChannel pChan, ULONG Device) >+{ >+ >+ UCHAR statusByte; >+ UCHAR errorByte; >+ >+ statusByte = 0; >+ >+ if (EnableMSN == TRUE) >+ { >+ /* >+ * If supported enable Media Status Notification support. >+ */ >+ if ((pChan->DeviceFlags[Device] & DFLAGS_REMOVABLE_DRIVE)) >+ { >+ outb((UCHAR) (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("Error enabling media status. Status %u, error byte %u\n", >+ statusByte, errorByte); >+ } >+ else >+ { >+ pChan->DeviceFlags[Device] |= DFLAGS_MEDIA_STATUS_ENABLED; >+ printk("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((UCHAR)(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 */ >+ >+/************************************************************************ >+ * Add watchdog timer. >+ ************************************************************************/ >+void >+SetWatchDogTimer(PChannel pChan) >+{ >+ >+ pChan->watch_timer->expires = jiffies + 3 * HZ; >+ add_timer(pChan->watch_timer); >+ >+} /* end SetWatchDogTimer */ >+ >+/************************************************************************ >+ * Cancel the watchdog timer. >+ ************************************************************************/ >+void >+CancelWatchDogTimer(PChannel pChan) >+{ >+ >+ del_timer(pChan->watch_timer); >+ >+} /* end CancelWatchDogTimer */ >+ >+/************************************************************************ >+ * Issue IDENTIFY command to a device >+ * Either the standard (EC) or the ATAPI packet (A1) IDENTIFY. >+ ************************************************************************/ >+BOOLEAN >+IssueIdentify(PChannel pChan, UCHAR DeviceNumber, UCHAR Command) >+{ >+ >+ ULONG i, j; >+ UCHAR statusByte = 0; >+ >+ /* >+ * 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); >+ >+ printk("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((UCHAR)((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((UCHAR)((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((UCHAR)((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((UCHAR)((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, (PUSHORT)&pChan->FullIdentifyData, 256); >+ >+ /* >+ * Check out a few capabilities / limitations of the device. >+ * 01/29/2003 >+ */ >+ if (pChan->FullIdentifyData.SpecialFunctionsEnabled & 1) >+ { >+ /* >+ * Determine if this drive supports the MSN functions. >+ */ >+ printk("Marking drive %x as removable. SFE = %x\n", >+ DeviceNumber, pChan->FullIdentifyData.SpecialFunctionsEnabled); >+ pChan->DeviceFlags[DeviceNumber] |= DFLAGS_REMOVABLE_DRIVE; >+ } >+ >+ memcpy(&pChan->IdentifyData[DeviceNumber], &pChan->FullIdentifyData, >+ sizeof(IDENTIFY_DATA2)); >+ >+ if (pChan->IdentifyData[DeviceNumber].GeneralConfiguration & 0x20 && >+ Command != IDE_COMMAND_IDENTIFY) >+ { >+ /* >+ * This device interrupts with the assertion of DRQ after receiving >+ * Atapi Packet Command. >+ */ >+ pChan->DeviceFlags[DeviceNumber] |= DFLAGS_INT_DRQ; >+ >+ dprintk(KERN_NOTICE "Device interrupts on assertion of DRQ.\n"); >+ } >+ else >+ { >+ dprintk(KERN_NOTICE "Device does't interrupt on assertion of DRQ.\n"); >+ } >+ >+ if (((pChan->IdentifyData[DeviceNumber].GeneralConfiguration & 0xF00) >+ == 0x100) && Command != IDE_COMMAND_IDENTIFY) >+ { >+ /* >+ * This is a tape. >+ */ >+ pChan->DeviceFlags[DeviceNumber] |= DFLAGS_TAPE_DEVICE; >+ printk(KERN_NOTICE "IssueIdentify: Device is a tape drive.\n"); >+ } >+ else >+ { >+ dprintk(KERN_NOTICE "IssueIdentify: Device is not a tape drive.\n"); >+ } >+ >+ /* >+ * Work around for some IDE and one model Atapi that will present more >+ * then 256 bytes for the Identify data. >+ */ >+ WaitOnBaseBusy(pChan, statusByte); >+ >+ for (i = 0; i < 0x10000; i++) >+ { >+ GetStatus(pChan, statusByte); >+ >+ if (statusByte & IDE_STATUS_DRQ) >+ { >+ /* >+ * Suck out any remaining bytes and throw away. >+ */ >+ inw(pChan->io_ports[IDE_DATA_OFFSET]); >+ } >+ else >+ { >+ break; >+ } >+ } >+ >+ return TRUE; >+ >+} /* end IssueIdentify() */ >+ >+/************************************************************************ >+ * Check this is the IDE or ATAPI disk then identify it >+ ************************************************************************/ >+static BOOLEAN >+iteraid_find_device(PChannel pChan, UCHAR channel) >+{ >+ >+ BOOLEAN deviceResponded = FALSE; >+ UCHAR deviceNumber; >+ UCHAR signatureLow; >+ UCHAR signatureHigh; >+ UCHAR 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((UCHAR)((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 not respond.\n", >+ channel, deviceNumber); >+ pChan->DeviceFlags[deviceNumber] &= ~DFLAGS_DEVICE_PRESENT; >+ } >+ } >+ else >+ { >+ /* >+ * Select the device. >+ */ >+ outb((UCHAR)((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. >+ */ >+ dprintk(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 >+ { >+ dprintk(KERN_WARNING "FindDevices: Device %u is not present\n", >+ (channel * 2) + deviceNumber); >+ pChan->DeviceFlags[deviceNumber] &= ~DFLAGS_DEVICE_PRESENT; >+ } >+ } >+ } >+ >+ return deviceResponded; >+ >+} /* end iteraid_find_device */ >+ >+/************************************************************************ >+ * IDE disk hardware initialize >+ ************************************************************************/ >+BOOLEAN >+AtapiHwInitialize(PITE_ADAPTER pAdap, PChannel pChan, UCHAR channel) >+{ >+ >+ UCHAR i; >+ UCHAR 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((UCHAR) (0xA0 | ((UCHAR) 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 */ >+ >+/************************************************************************ >+ * Initialize a adapter, return 0 means success >+ ************************************************************************/ >+static int >+iteraid_init(PITE_ADAPTER pAdap, struct pci_dev *pPciDev) >+{ >+ >+ unsigned char z; >+ unsigned char i; >+ unsigned char j; >+ unsigned int set_irq; >+ USHORT control_addr; /* Control reg base address */ >+ USHORT base_addr; /* IDE I/O port base address */ >+ USHORT bm_base_addr; /* Bus Master base address */ >+ PChannel pChan; /* Use for each channel */ >+ >+ /* >+ * Common settings. >+ */ >+ pAdap->pci_bus = pPciDev->bus->number; >+ pAdap->devfn = pPciDev->devfn; >+ pAdap->irq = pPciDev->irq; >+ pAdap->irqOwned = 0; >+ >+ printk(KERN_NOTICE "iteraid_init: 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: kmalloc() failed for channels.\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("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++) >+ { >+ /* >+ * Reference the book "LINUX DEVICE DRIVER 2nd", Page 484 >+ * unsigned long pci_resource_start(struct pci_dev *dev, int bar); >+ * >+ * This function returns the first address (memory address or I/O >+ * port number) associated with one of the six PCI I/O regions. The >+ * region is selected by the integer bar (the base address register) >+ * ranging from 0 to 5, inclusive. >+ */ >+ base_addr = pci_resource_start(pPciDev, i * 2); >+ bm_base_addr = pci_resource_start(pPciDev, 4); >+ >+ pChan = &pAdap->IDEChannel[i]; >+ >+ if (i == 0) >+ { >+ control_addr = pci_resource_start(pPciDev, 1); >+ pChan->dma_base = bm_base_addr; >+ } >+ else >+ { >+ control_addr = pci_resource_start(pPciDev, 3); >+ pChan->dma_base = bm_base_addr + 8; >+ } >+ >+ for (j = 0; j <= IDE_STATUS_OFFSET; j++) >+ { >+ pChan->io_ports[j] = base_addr; >+ base_addr += 1; >+ } >+ >+ pChan->io_ports[IDE_CONTROL_OFFSET] = control_addr + 2; >+ } >+ >+ /* >+ * Initialize channels. >+ */ >+ for (z = 0; z < pAdap->num_channels; z++) >+ { >+ pChan = &pAdap->IDEChannel[z]; >+ pChan->pPciDev = pPciDev; >+ pChan->channel = z; >+ >+ /* >+ * This section should be masked off if BIOS is ready. >+ */ >+# if (MARK_DEBUG_BYPASS_MODE) >+ /* >+ * BIOS is not ready, so I change to ByPass Mode by myself. >+ */ >+ pAdap->bypass_mode = TRUE; >+ >+ /* >+ * Change to bypass mode. >+ */ >+ IT8212InitBypassMode(pPciDev); >+# endif >+ >+ /* >+ * Hardware initialize. >+ */ >+# if (0) >+ AtapiHwInitialize(pAdap, pChan, z); >+# endif >+ >+ /* >+ * Find and identify the IDE or ATAPI device. >+ */ >+ iteraid_find_device(pChan, z); >+ >+ /* >+ * Set the best transfer mode. >+ */ >+ IT8212SetBestTransferMode(pAdap, pChan, z); >+ >+ /* >+ * Set Scatter/Gather List buffer for the channel. >+ */ >+ IdeSetupDma(pChan, pChan->dma_base, 8); >+ >+ /* >+ * Setup retry timer. >+ */ >+ pChan->retry_timer = >+ (struct timer_list *)kmalloc(sizeof(struct timer_list) * 2, GFP_ATOMIC); >+ >+ if (pChan->retry_timer == NULL) >+ { >+ printk("Allocate retry_timer failed\n"); >+ return -1; >+ } >+ >+ init_timer(pChan->retry_timer); >+ pChan->retry_timer->function = (void (*)(ULONG))iteretry; >+ pChan->retry_timer->data = (ULONG)pChan; >+ >+ pChan->watch_timer = pChan->retry_timer + 1; >+ init_timer(pChan->watch_timer); >+ pChan->watch_timer->function = (void (*)(ULONG))ite_watch_timer; >+ pChan->watch_timer->data = (ULONG)pChan; >+ } >+ >+ return 0; >+ >+} /* end iteraid_init */ >+ >+/************************************************************************ >+ * This function will find and initialize any cards >+ ************************************************************************/ >+int >+iteraid_detect(Scsi_Host_Template *tpnt) >+{ >+ >+ int major = 0; >+ UCHAR i; >+ UCHAR j; >+ UCHAR mode = 0; >+ PChannel pChan; >+ PITE_ADAPTER pAdap; >+ struct pci_dev * pPciDev; >+ >+ /* >+ * Check if the kernel has PCI interface compiled in. >+ */ >+ if (!pci_present()) >+ { >+ printk("iteraid_detect: No pci interface present.\n"); >+ return 0; >+ } >+ >+ /* >+ * Search ITE IT8212 chip. >+ */ >+ pPciDev = NULL; >+ while ((pPciDev = pci_find_device(ITE_VENDOR_ID, ITE_DEVICE_ID, pPciDev))) >+ { >+ if (PCI_FUNC(pPciDev->devfn)) continue; >+ >+ /* >+ * Allocate memory for Adapter. >+ */ >+ pAdap = (PITE_ADAPTER)kmalloc(sizeof(ITE_ADAPTER), GFP_ATOMIC); >+ >+ if (pAdap == NULL) >+ { >+ printk("iteraid_detect: kmalloc() failed for card.\n"); >+ 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\n"); pAdap->bypass_mode = FALSE; } >+ else { dprintk("Bypass mode\n"); pAdap->bypass_mode = TRUE; } >+ >+ if (iteraid_init(pAdap, pPciDev) == 0) >+ { >+ ite_adapters[NumAdapters++] = pAdap; >+ } >+ } >+ >+ /* >+ * 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; >+ scsi_set_pci_device(ite_vhost, pPciDev); >+ >+ /* >+ * Register the driver as a character device, for applications to >+ * acess 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. >+ */ >+ major = register_chrdev(0, "itedev", &itedev_fops); >+ >+ /* >+ * Register the Shutdown Notification hook in the kernel. >+ */ >+ >+ /* >+ * Initialize ioctl semphore. >+ */ >+ init_MUTEX(&mimd_entry_mtx); >+ } >+ >+ return 1; >+ >+} /* end iteraid_detect() */ >+ >+/************************************************************************ >+ * Name: iteraid_release >+ * Description: Release resources allocated for a single each adapter. >+ * Parameters: pshost - Pointer to SCSI command structure. >+ * Returns: zero. >+ ************************************************************************/ >+int >+iteraid_release(struct Scsi_Host *pshost) >+{ >+ >+ int i; >+ int j; >+ PITE_ADAPTER pAdap; >+ >+ for (i = 0; i < NumAdapters; i++) >+ { >+ pAdap = ite_adapters[i]; >+ >+ if (pAdap->irqOwned) free_irq(pAdap->irq, pAdap); >+ >+ for (j = 0; j < pAdap->num_channels; j++) >+ { >+ kfree(pAdap->IDEChannel[j].retry_timer); >+ } >+ if (pAdap->IDEChannel != NULL) { kfree(pAdap->IDEChannel); } >+ if (pAdap != NULL) { kfree(pAdap); } >+ } >+ >+ scsi_unregister(pshost); >+ >+ return 0; >+ >+} /* end iteraid_Release */ >+ >+/************************************************************************ >+ * Name: iteraid_old_abort >+ * Description: Process the Abort command from the SCSI manager. >+ * Parameters: SCpnt - Pointer to SCSI command structure. >+ * Returns: Always snooze(A short sleep). >+ ************************************************************************/ >+int >+iteraid_old_abort(Scsi_Cmnd *SCpnt) >+{ >+ >+ return SCSI_ABORT_SNOOZE; >+ >+} /* end iteraid_old_abort */ >+ >+/************************************************************************ >+ * Name: iteraid_old_reset >+ * Description: Process the Reset command from the SCSI manager. >+ * Parameters: SCpnt - Pointer to SCSI command structure. >+ * flags - Flags about the reset command >+ * Returns: No active command at this time, so this means >+ * that each time we got some kind of response the >+ * last time through. Tell the mid-level code to >+ * request sense information in order to decide what >+ * to do next. >+ ************************************************************************/ >+int >+iteraid_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) >+{ >+ >+ return SCSI_RESET_SUCCESS; >+ >+} /* end iteraid_old_reset */ >+ >+/************************************************************************ >+ * Name: iteraid_biosparam >+ * Description: Process the biosparam request from the SCSI manager to >+ * return C/H/S data. >+ * Parameters: disk - Pointer to SCSI disk structure. >+ * dev - Major/minor number from kernel. >+ * geom - Pointer to integer array to place geometry data. >+ * Returns: zero. >+ ************************************************************************/ >+int >+iteraid_biosparam(Scsi_Disk *disk, kdev_t dev, int geom[]) >+{ >+ >+ int heads, sectors, cylinders; >+ >+ /* >+ * Default heads (64) & sectors (32) >+ * Handle extended translation size for logical drives > 1Gb >+ */ >+ if (disk->capacity >= 0x200000) >+ { >+ heads = 255; >+ sectors = 63; >+ } >+ else >+ { >+ heads = 64; >+ sectors = 32; >+ } >+ >+ cylinders = disk->capacity / (heads * sectors); >+ >+ /* >+ * Return result >+ */ >+ geom[0] = heads; >+ geom[1] = sectors; >+ geom[2] = cylinders; >+ >+ return 0; >+ >+} /* end iteraid_biosparam */ >+ >+/************************************************************************ >+ * >+ ************************************************************************/ >+int >+iteraid_proc_info >+( >+char * buffer, >+char ** start, >+off_t offset, >+int length, >+int host_no, >+int inout >+) >+{ >+ >+ return 0; >+ >+} /* end iteraid_proc_info */ >+ >+/************************************************************************ >+ * >+ ************************************************************************/ >+static int >+itedev_open(struct inode *inode, struct file *filep) >+{ >+ >+ MOD_INC_USE_COUNT; >+ >+ return 0; >+ >+} /* end itedev_open */ >+ >+/************************************************************************ >+ * IOCTL code entry. >+ ************************************************************************/ >+static int >+itedev_ioctl_entry >+( >+ struct inode * inode, >+ struct file * filep, >+ unsigned int cmd, >+ unsigned long arg >+) >+{ >+ >+ int ret = -1; >+ >+ /* >+ * We do not allow parallel ioctls to the driver as of now. >+ */ >+ down(&mimd_entry_mtx); >+ ret = itedev_ioctl(inode, filep, cmd, arg); >+ up(&mimd_entry_mtx); >+ >+ return ret; >+ >+} /* end itedev_ioctl_entry */ >+ >+/************************************************************************ >+ * Real IOCTL code. >+ ************************************************************************/ >+static int >+itedev_ioctl >+( >+ struct inode * inode, >+ struct file * filep, >+ unsigned int cmd, >+ unsigned long arg >+) >+{ >+ >+ UCHAR diskArrayId; >+ UCHAR statusByte = 0; >+ UCHAR srbStatus; >+ UCHAR progress; >+ UCHAR status; >+ uioctl_t * pioc; >+ PITE_ADAPTER pAdap; >+ PChannel pChan; >+ >+ printk("itedev_ioctl enter\n"); >+ >+ /* >+ * Extract the type and number bitfield. >+ */ >+ if (_IOC_TYPE(cmd) != ITE_IOCMAGIC) >+ return -EINVAL; >+ >+ /* >+ * Allocate space for ioctl data structure. >+ */ >+ if ((pioc = kmalloc(sizeof(uioctl_t), GFP_KERNEL)) == NULL) >+ { >+ printk("itedev_ioctl: error kmalloc on ioctl\n"); >+ return -ENOMEM; >+ } >+ >+ /* >+ * Get the user ioctl structure. >+ */ >+ if (copy_from_user(pioc, (uioctl_t *)arg, sizeof(uioctl_t))) >+ { >+ kfree(pioc); >+ return -EFAULT; >+ } >+ >+ /* >+ * Check which command to do. >+ */ >+ switch (cmd) >+ { >+ case ITE_IOC_GET_IDENTIFY_DATA: >+ printk("ITE_IOCGIDENTIFY\n"); >+ >+ /* >+ * Get the virtual device identify data. >+ */ >+ status = IT8212IssueIdentify(pioc); >+ >+ return 0; >+ >+ case ITE_IOC_GET_PHY_DISK_STATUS: >+ printk("ITE_IOC_GET_PHY_DISK_STATUS\n"); >+ >+ /* >+ * Get the physical disk status. >+ */ >+ status = IT8212GetChipStatus(pioc); >+ >+ return 0; >+ >+ case ITE_IOC_CREATE_DISK_ARRAY: >+ printk("ITE_IOC_CREATE_DISK_ARRAY\n"); >+ >+ /* >+ * Create disk array. >+ */ >+ status = IT8212CreateDiskArray(pioc); >+ >+ if (status != SRB_STATUS_SUCCESS) return status; >+ >+ status = IT8212ErasePartition(pioc); >+ >+ return 0; >+ >+ case ITE_IOC_REBUILD_START: >+ printk("ITE_IOC_REBUILD_START\n"); >+ >+ /* >+ * Rebuild array. >+ */ >+ status = IT8212Rebuild(pioc); >+ >+ return 0; >+ >+ case ITE_IOC_GET_REBUILD_STATUS: >+ printk("ITE_IOC_GET_REBUILD_STATUS\n"); >+ >+ pAdap = ite_adapters[pioc->AdapterNo]; >+ >+ /* >+ * Get the rebuild disk ID. >+ */ >+ diskArrayId = pioc->DiskNo; >+ >+ /* >+ * Select channel. >+ */ >+ if (diskArrayId < 2) >+ { >+ pChan = &pAdap->IDEChannel[0]; >+ } >+ else >+ { >+ pChan = &pAdap->IDEChannel[1]; >+ } >+ >+ /* >+ * Select device. >+ */ >+ outb(((UCHAR) (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; >+ goto exit; >+ } >+ >+ progress = inb(pChan->io_ports[IDE_NSECTOR_OFFSET]); >+ srbStatus = SRB_STATUS_SUCCESS; >+ >+ /* >+ * Put the rebuld status to user space. >+ */ >+ put_user(progress, (UCHAR *)arg); >+ >+exit: >+ >+ return 0; >+ >+ case ITE_IOC_RESET_ADAPTER: >+ printk("ITE_IOC_RESET_ADAPTER\n"); >+ >+ /* >+ * Reset the adapter. >+ */ >+ status = IT8212ResetAdapter(); >+ >+ /* >+ * Return TURE or FALSE to user space. >+ */ >+ put_user(status, (UCHAR *)arg); >+ >+ return 0; >+ >+ case ITE_IOC_GET_DRIVER_VERSION: >+ printk("ITE_IOC_GET_DRIVER_VERSION\n"); >+ >+ /* >+ * Get the current driver version. >+ */ >+ put_user(driver_ver, (int *)arg); >+ >+ return 0; >+ >+ default: >+ return -EINVAL; >+ >+ } /* end switch */ >+ >+ >+} /* end itedev_ioctl */ >+ >+/************************************************************************ >+ * >+ ************************************************************************/ >+static int >+itedev_close(struct inode *inode, struct file *filep) >+{ >+ >+#ifdef MODULE >+ MOD_DEC_USE_COUNT; >+#endif >+ >+ return 0; >+ >+} /* end itedev_close */ >+ >+/* >+ * To make our driver a SCSI module, we have to include some magic at the >+ * end of the file. This generates the init_module and clean_module code >+ * nedded for a SCSI device, rather than having the author replicate it >+ * each time a new driver is written. >+ */ >+static Scsi_Host_Template driver_template = ITERAID; >+#include "scsi_module.c" >diff -urHN linux-2.4.20/drivers/scsi/iteraid.h iteraid-2.4.20.patch/drivers/scsi/iteraid.h >--- linux-2.4.20/drivers/scsi/iteraid.h 1970-01-01 02:00:00.000000000 +0200 >+++ iteraid-2.4.20.patch/drivers/scsi/iteraid.h 2003-05-11 16:29:33.000000000 +0300 >@@ -0,0 +1,1574 @@ >+/* >+ * linux/drivers/scsi/iteraid.h >+ * >+ * (C) Copyright 2002 ITE, inc. >+ * >+ * Nov 11, 2002-2003 Mark Lu file created. >+ * >+ * ITE IT8212 RAID Controller device driver header for Linux >+ */ >+ >+#ifndef _ITERAID_H_ >+#define _ITERAID_H_ >+ >+#include <linux/version.h> >+#include <linux/types.h> >+#include <linux/kdev_t.h> >+ >+#define ITE_VENDOR_ID 0x1283 /* Vendor ID (ITE) */ >+#define ITE_DEVICE_ID 0x8212 /* Device IF (IT8212) */ >+#define MAX_ADAPTERS 2 /* Max Board supported */ >+#define MAX_DEVICES (MAX_ADAPTERS * 4) /* Max Dev supported */ >+ >+#define TRUE 1 >+#define FALSE 0 >+ >+/* >+ * Undef macros which may conflict >+ */ >+#undef START_STOP >+ >+/************************************************************************ >+ * Some data types define >+ ************************************************************************/ >+typedef long LONG, *PLONG; >+typedef unsigned long ULONG, *PULONG; >+typedef unsigned long DWORD, *PDWORD, BOOL; >+typedef unsigned int UINT, *PUINT; >+typedef unsigned char BYTE, *PBYTE; >+typedef unsigned char UCHAR, *PUCHAR; >+typedef unsigned char BOOLEAN; >+typedef unsigned short USHORT,*PUSHORT; >+typedef unsigned short WORD, *PWORD; >+typedef void VOID, *PVOID; >+typedef unsigned char *ADDRESS; >+ >+/************************************************************************ >+ * Debugging macro >+ ************************************************************************/ >+#ifdef ITE_DEBUG >+#define dprintk(msg...) printk(msg) >+#else >+#define dprintk(msg...) do { } while(0) >+#endif >+ >+/************************************************************************ >+ * Raid level definitions >+ ************************************************************************/ >+#define RAID_LEVEL_0 0 >+#define RAID_LEVEL_1 1 >+#define RAID_LEVEL_10 2 >+#define RAID_LEVEL_JBOD 3 >+#define RAID_LEVEL_NORMAL 4 >+#define RAID_LEVEL_NODISK 5 >+ >+/************************************************************************ >+ * Physical disk status definitions >+ ************************************************************************/ >+#define DISK_KEY_OFF 0 >+#define DISK_OFF_LINE 1 >+#define DISK_ON_LINE 2 >+#define DISK_REBUILDING 3 >+#define DISK_PLUGGING 4 >+#define DISK_PLUGGING_OK 5 >+ >+#define MaximumLBAOf28Bit 0x10000000 >+ >+#define DisableChannel 1 >+#define EnableChannel 2 >+ >+#define CABLE_40_PIN 0 >+#define CABLE_80_PIN 1 >+ >+#define RaidActive 0 >+#define RaidInactive 1 >+ >+#define IDE_CLOCK_66 0 >+#define IDE_CLOCK_50 1 >+ >+#define USE_ULTRA_DMA 0 >+#define USE_MULTIWORD_DMA 1 >+ >+/************************************************************************ >+ * >+ ************************************************************************/ >+typedef struct _PHYSICAL_DISK_STATUS >+{ >+ UCHAR ModelNumber[40]; /* Byte 00-39 */ >+ ULONG UserAddressableSectors_LOW; /* Byte 40-43 */ >+ ULONG UserAddressableSectors_HIGH; /* Byte 44-47 */ >+ UCHAR MultiWordDMASupport; /* Byte 48 */ >+ UCHAR MultiWordDMAActive; /* Byte 49 */ >+ UCHAR UltraDMASupport; /* Byte 50 */ >+ UCHAR UltraDMAActive; /* Byte 51 */ >+ UCHAR RaidType; /* Byte 52 */ >+ UCHAR RaidNumber; /* Byte 53 */ >+ UCHAR SerialNumber[20]; /* Byte 54-73 */ >+ UCHAR DiskStatus; /* Byte 74 */ >+ UCHAR DiskOriginalLocation; /* Byte 75 */ >+ UCHAR Cable80Pin; /* Byte 76 */ >+ UCHAR BootableDisk; /* Byte 77 */ >+ UCHAR StorageSize[8]; /* Byte 78-85 */ >+ UCHAR Reserved[35]; /* Byte 86-120 */ >+ UCHAR UpdateYear; /* Byte 121 */ >+ UCHAR UpdateMonth; /* Byte 122 */ >+ UCHAR UpdateDay; /* Byte 123 */ >+ UCHAR FirmwareVer; /* Byte 124 */ >+ UCHAR RebuildStatus; /* Byte 125 */ >+ UCHAR StripeSize; /* Byte 126 */ >+ UCHAR AutoRebuildEnable; /* Byte 127 */ >+} PHYSICAL_DISK_STATUS, *PPHYSICAL_DISK_STATUS; >+ >+/************************************************************************ >+ * >+ ************************************************************************/ >+typedef struct _IT8212_SET_CHIP_STATUS_INFO >+{ >+ USHORT RaidType; /* Word 129 */ >+ USHORT ContainingDisks; /* Word 130 */ >+ USHORT UltraDmaTiming01; /* Word 131 */ >+ USHORT UltraDmaTiming23; /* Word 132 */ >+ USHORT UltraDmaTiming45; /* Word 133 */ >+ USHORT UltraDmaTiming6; /* Word 134 */ >+ USHORT MultiWordDmaTiming01; /* Word 135 */ >+ USHORT UltraDmaTiming2; /* Word 136 */ >+ USHORT PioTiming4; /* Word 137 */ >+ USHORT AutoRebuildEnable; /* Word 138 */ >+ USHORT IdeClkUDma01; /* Word 139 */ >+ USHORT IdeClkUDma23; /* Word 140 */ >+ USHORT IdeClkUDma45; /* Word 141 */ >+ USHORT IdeClkUDma6; /* Word 142 */ >+ USHORT IdeClkMDma01; /* Word 143 */ >+ USHORT IdeClkMDma2; /* Word 144 */ >+ USHORT IdeClkPio4; /* Word 145 */ >+ USHORT StripeSize; /* Word 146 */ >+ USHORT BootableDisk; /* Word 147 */ >+ USHORT CheckHotSwapInterval; /* Word 148 */ >+ USHORT TargetSourceDisk; /* Word 149 */ >+ USHORT RebuildBlockSize; /* Word 150 */ >+ USHORT ResetInterval1; /* Word 151 */ >+ USHORT ResetInterval2; /* Word 152 */ >+ USHORT RebuildRetryTimes; /* Word 153 */ >+ USHORT 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 >+{ >+ USHORT Year; >+ UCHAR Month; >+ UCHAR Date; >+ UCHAR Day; >+ UCHAR Hour; >+ UCHAR Minute; >+ UCHAR Second; >+ UCHAR MiniSec; >+ UCHAR RaidType; >+ UCHAR ContainingDisks; >+ UCHAR DontCare[9]; >+} RAID_SERIAL_NUMBER, *PRAID_SERIAL_NUMBER; >+ >+/************************************************************************ >+ * Disk array create information >+ ************************************************************************/ >+typedef struct _RAID_CREATE_INFO >+{ >+ UCHAR DiskArrayId; >+ RAID_SERIAL_NUMBER SerialNumber; >+ UCHAR ModelNumber[40]; >+ USHORT RaidType; >+ USHORT ContainingDisks; >+ USHORT AutoRebuildEnable; >+ USHORT StripeSize; >+ USHORT BootableDisk; >+ USHORT TargetSourceDisk; >+ UCHAR ErasePartition; >+ /* >+ * Following items index definition >+ * 0: Primary Master >+ * 1: Secondary Master >+ * 2: Primary Slave >+ * 3: Secondary Slave >+ */ >+ UCHAR DMASupported[4]; >+ UCHAR UDMASupported[4]; >+ ULONG AddressableSectors[4]; >+ UCHAR NewlyCreated; >+} RAID_CREATE_INFO, *PRAID_CREATE_INFO; >+ >+/************************************************************************ >+ * Rebuild data structure >+ ************************************************************************/ >+typedef struct _RAID_REBUILD_INFO >+{ >+ UCHAR DiskArrayId; /* Virtual device number (0-3) */ >+ UCHAR SrcDisk; /* Source disk (0-3) */ >+ UCHAR DestDisk; /* Destination disk (0-3) */ >+ UCHAR Resume; /* 1: Resume the last time rebuild */ >+ /* 0: Rebuild from LBA 0 */ >+ UCHAR Status; /* Indicate the status of the current */ >+ /* rebuild command filled by drivers */ >+} 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 // defined by Andy, not accusys >+ >+/************************************************************************ >+ * 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 >+{ >+ UCHAR OperationCode; >+ UCHAR Reserved1 : 3; >+ UCHAR Dbd : 1; >+ UCHAR Reserved2 : 4; >+ UCHAR PageCode : 6; >+ UCHAR Pc : 2; >+ UCHAR SubpageCode; >+ UCHAR AllocationLength; >+ UCHAR Control; >+} SCSI_MODE_SENSE6, *PSCSI_MODE_SENSE6; >+ >+typedef struct _SCSI_MODE_SENSE10 >+{ >+ UCHAR OperationCode; >+ UCHAR Reserved1 : 3; >+ UCHAR Dbd : 1; >+ UCHAR LLBAA : 1; >+ UCHAR Reserved2 : 3; >+ UCHAR PageCode : 6; >+ UCHAR Pc : 2; >+ UCHAR SubpageCode; >+ UCHAR Reserved3[3]; >+ UCHAR AllocationLengthMsb; >+ UCHAR AllocationLengthLsb; >+ UCHAR Control; >+} SCSI_MODE_SENSE10, *PSCSI_MODE_SENSE10; >+ >+typedef struct _SCSI_MODE_SELECT6 >+{ >+ UCHAR OperationCode; >+ UCHAR SPBit : 1; >+ UCHAR Reserved1 : 3; >+ UCHAR PFBit : 1; >+ UCHAR Reserved2 : 3; >+ UCHAR Reserved3[2]; >+ UCHAR ParameterListLength; >+ UCHAR Control; >+} SCSI_MODE_SELECT6, *PSCSI_MODE_SELECT6; >+ >+typedef struct _SCSI_MODE_SELECT10 >+{ >+ UCHAR OperationCode; >+ UCHAR SPBit : 1; >+ UCHAR Reserved1 : 3; >+ UCHAR PFBit : 1; >+ UCHAR Reserved2 : 3; >+ UCHAR Reserved3[5]; >+ UCHAR ParameterListLengthMsb; >+ UCHAR ParameterListLengthLsb; >+ UCHAR Control; >+} SCSI_MODE_SELECT10, *PSCSI_MODE_SELECT10; >+ >+typedef struct _SCSI_MODE_PARAMETER_HEADER6 >+{ >+ UCHAR ModeDataLength; >+ UCHAR MediumType; >+ UCHAR DeviceSpecificParameter; >+ UCHAR BlockDescriptorLength; >+} SCSI_MODE_PARAMETER_HEADER6, *PSCSI_MODE_PARAMETER_HEADER6; >+ >+typedef struct _SCSI_MODE_PARAMETER_HEADER10 >+{ >+ UCHAR ModeDataLengthMsb; >+ UCHAR ModeDataLengthLsb; >+ UCHAR MediumType; >+ UCHAR DeviceSpecificParameter; >+ UCHAR Reserved[2]; >+ UCHAR BlockDescriptorLengthMsb; >+ UCHAR BlockDescriptorLengthLsb; >+} SCSI_MODE_PARAMETER_HEADER10, *PSCSI_MODE_PARAMETER_HEADER10; >+ >+typedef struct _SCSI_MODE_PARAMTER_BLOCK_DESCRIPTER >+{ >+ UCHAR DesityCode; >+ UCHAR NumberOfBlocks2; >+ UCHAR NumberOfBlocks1; >+ UCHAR NumberOfBlocks0; >+ UCHAR Reserved; >+ UCHAR BlockLength2; >+ UCHAR BlockLength1; >+ UCHAR BlockLength0; >+} SCSI_MODE_PARAMTER_BLOCK_DESCRIPTER, *PSCSI_MODE_PARAMTER_BLOCK_DESCRIPTER; >+ >+/************************************************************************ >+ * IDE command definitions >+ ************************************************************************/ >+#define IDE_COMMAND_ATAPI_RESET 0x08 >+#define IDE_COMMAND_RECALIBRATE 0x10 >+#define IDE_COMMAND_READ_SECTOR 0x20 >+#define IDE_COMMAND_READ_SECTOR_EXT 0x24 >+#define IDE_COMMAND_READ_DMA_EXT 0x25 >+#define IDE_COMMAND_READ_MULTIPLE_EXT 0x29 >+#define IDE_COMMAND_WRITE_SECTOR 0x30 >+#define IDE_COMMAND_WRITE_SECTOR_EXT 0x34 >+#define IDE_COMMAND_WRITE_DMA_EXT 0x35 >+#define IDE_COMMAND_WRITE_MULTIPLE_EXT 0x39 >+#define IDE_COMMAND_READ_VERIFY 0x40 >+#define IDE_COMMAND_READ_VERIFY_EXT 0x42 >+#define IDE_COMMAND_SEEK 0x70 >+#define IDE_COMMAND_SET_DRIVE_PARAMETERS 0x91 >+#define IDE_COMMAND_ATAPI_PACKET 0xA0 >+#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1 >+#define IDE_COMMAND_READ_MULTIPLE 0xC4 >+#define IDE_COMMAND_WRITE_MULTIPLE 0xC5 >+#define IDE_COMMAND_SET_MULTIPLE 0xC6 >+#define IDE_COMMAND_READ_DMA 0xC8 >+#define IDE_COMMAND_WRITE_DMA 0xCA >+#define IDE_COMMAND_GET_MEDIA_STATUS 0xDA >+#define IDE_COMMAND_ENABLE_MEDIA_STATUS 0xEF >+#define IDE_COMMAND_SET_FEATURE 0xEF >+#define IDE_COMMAND_IDENTIFY 0xEC >+#define IDE_COMMAND_MEDIA_EJECT 0xED >+ >+/************************************************************************ >+ * IDE status definitions >+ ************************************************************************/ >+#define IDE_STATUS_ERROR 0x01 >+#define IDE_STATUS_INDEX 0x02 >+#define IDE_STATUS_CORRECTED_ERROR 0x04 >+#define IDE_STATUS_DRQ 0x08 >+#define IDE_STATUS_DSC 0x10 >+#define IDE_STATUS_DRDY 0x40 >+#define IDE_STATUS_IDLE 0x50 >+#define IDE_STATUS_BUSY 0x80 >+ >+/************************************************************************ >+ * IDE drive control definitions >+ ************************************************************************/ >+#define IDE_DC_DISABLE_INTERRUPTS 0x02 >+#define IDE_DC_RESET_CONTROLLER 0x04 >+#define IDE_DC_REENABLE_CONTROLLER 0x00 >+ >+/************************************************************************ >+ * IDE error definitions >+ ************************************************************************/ >+#define IDE_ERROR_BAD_BLOCK 0x80 >+#define IDE_ERROR_DATA_ERROR 0x40 >+#define IDE_ERROR_MEDIA_CHANGE 0x20 >+#define IDE_ERROR_ID_NOT_FOUND 0x10 >+#define IDE_ERROR_MEDIA_CHANGE_REQ 0x08 >+#define IDE_ERROR_COMMAND_ABORTED 0x04 >+#define IDE_ERROR_END_OF_MEDIA 0x02 >+#define IDE_ERROR_ILLEGAL_LENGTH 0x01 >+ >+/************************************************************************ >+ * IDENTIFY data >+ ************************************************************************/ >+typedef struct _IDENTIFY_DATA >+{ >+ USHORT GeneralConfiguration; // 00 00 >+ USHORT NumberOfCylinders; // 02 1 >+ USHORT Reserved1; // 04 2 >+ USHORT NumberOfHeads; // 06 3 >+ USHORT UnformattedBytesPerTrack; // 08 4 >+ USHORT UnformattedBytesPerSector; // 0A 5 >+ USHORT SectorsPerTrack; // 0C 6 >+ USHORT VendorUnique1[3]; // 0E 7-9 >+ USHORT SerialNumber[10]; // 14 10-19 >+ USHORT BufferType; // 28 20 >+ USHORT BufferSectorSize; // 2A 21 >+ USHORT NumberOfEccBytes; // 2C 22 >+ USHORT FirmwareRevision[4]; // 2E 23-26 >+ USHORT ModelNumber[20]; // 36 27-46 >+ UCHAR MaximumBlockTransfer; // 5E 47 >+ UCHAR VendorUnique2; // 5F >+ USHORT DoubleWordIo; // 60 48 >+ USHORT Capabilities; // 62 49 >+ USHORT Reserved2; // 64 50 >+ UCHAR VendorUnique3; // 66 51 >+ UCHAR PioCycleTimingMode; // 67 >+ UCHAR VendorUnique4; // 68 52 >+ UCHAR DmaCycleTimingMode; // 69 >+ USHORT TranslationFieldsValid : 1; // 6A 53 >+ USHORT Reserved3 : 15; // >+ USHORT NumberOfCurrentCylinders; // 6C 54 >+ USHORT NumberOfCurrentHeads; // 6E 55 >+ USHORT CurrentSectorsPerTrack; // 70 56 >+ ULONG CurrentSectorCapacity; // 72 57-58 >+ USHORT CurrentMultiSectorSetting; // 59 >+ ULONG UserAddressableSectors; // 60-61 >+ USHORT SingleWordDMASupport : 8; // 62 >+ USHORT SingleWordDMAActive : 8; // >+ USHORT MultiWordDMASupport : 8; // 63 >+ USHORT MultiWordDMAActive : 8; // >+ USHORT AdvancedPIOModes : 8; // 64 >+ USHORT Reserved4 : 8; // >+ USHORT MinimumMWXferCycleTime; // 65 >+ USHORT RecommendedMWXferCycleTime; // 66 >+ USHORT MinimumPIOCycleTime; // 67 >+ USHORT MinimumPIOCycleTimeIORDY; // 68 >+ USHORT Reserved5[2]; // 69-70 >+ USHORT ReleaseTimeOverlapped; // 71 >+ USHORT ReleaseTimeServiceCommand; // 72 >+ USHORT MajorRevision; // 73 >+ USHORT MinorRevision; // 74 >+ USHORT Reserved6[50]; // 75-126 >+ USHORT SpecialFunctionsEnabled; // 127 >+ USHORT Reserved7[128]; // 128-255 >+} IDENTIFY_DATA, *PIDENTIFY_DATA; >+ >+/************************************************************************ >+ * Identify data without the Reserved4 >+ ************************************************************************/ >+typedef struct _IDENTIFY_DATA2 >+{ >+ USHORT GeneralConfiguration; // 00 >+ USHORT NumberOfCylinders; // 01 >+ USHORT Reserved1; // 02 >+ USHORT NumberOfHeads; // 03 >+ USHORT Reserved2[2]; // 04-05 >+ USHORT SectorsPerTrack; // 06 >+ USHORT Reserved3[3]; // 07-09 >+ USHORT SerialNumber[10]; // 10-19 >+ USHORT Reserved4[3]; // 20-22 >+ USHORT FirmwareRevision[4]; // 23-26 >+ USHORT ModelNumber[20]; // 27-46 >+ USHORT MaximumBlockTransfer; // 47 >+ USHORT Reserved5; // 48 >+ USHORT Capabilities[2]; // 49-50 >+ USHORT Reserved6[2]; // 51-52 >+ USHORT ValidFieldIndicator; // 53 >+ USHORT NumberOfCurrentCylinders; // 54 >+ USHORT NumberOfCurrentHeads; // 55 >+ USHORT CurrentSectorsPerTrack; // 56 >+ USHORT CurrentSectorCapacityLow; // 57 >+ USHORT CurrentSectorCapacityHigh; // 58 >+ USHORT CurrentMultiSectorSetting; // 59 >+ ULONG UserAddressableSectors; // 60-61 >+ USHORT Reserved7; // 62 >+ UCHAR MultiWordDMASupport; // 63 >+ UCHAR MultiWordDMAActive; // >+ USHORT AdvancedPIOModes; // 64 >+ USHORT MinimumMWXferCycleTime; // 65 >+ USHORT RecommendedMWXferCycleTime; // 66 >+ USHORT MinimumPIOCycleTime; // 67 >+ USHORT MinimumPIOCycleTimeIORDY; // 68 >+ USHORT Reserved8[6]; // 69-74 >+ USHORT QueueDepth; // 75 >+ USHORT Reserved9[4]; // 76-79 >+ USHORT MajorVersionNumber; // 80 >+ USHORT MinorVersionNumber; // 81 >+ ULONG CmdSetSupported; // 82-83 >+ USHORT CmdSetFeatureSupportedExt; // 84 >+ USHORT CmdSetFeatureEnabledLow; // 85 >+ USHORT CmdSetFeatureEnabledHigh; // 86 >+ USHORT CmdSetFeatureDefault; // 87 >+ UCHAR UltraDMASupport; // 88 >+ UCHAR UltraDMAActive; // >+ USHORT SecurityEraseTime; // 89 >+ USHORT EnhancedSecurityEraseTime; // 90 >+ USHORT PowerManagementValue; // 91 >+ USHORT MasterPasswordRevision; // 92 >+ USHORT HwResetResult; // 93 >+ USHORT Reserved11[6]; // 94-99 >+ ULONG Capacity_48bit_LOW; // 100-101 >+ ULONG Capacity_48bit_HIGH; // 102-103 >+ USHORT Reserved12[24]; // 104-127 >+ USHORT SecurityStatus; // 128 >+ USHORT Reserved13[31]; // 129-159 vendor specific >+ USHORT Reserved14[96]; // 160-255 >+} IDENTIFY_DATA2, *PIDENTIFY_DATA2; >+ >+#define IDENTIFY_DATA_SIZE sizeof(IDENTIFY_DATA) >+ >+/************************************************************************ >+ * IDENTIFY capability bit definitions. >+ ************************************************************************/ >+#define IDENTIFY_CAPABILITIES_DMA_SUPPORTED 0x0100 >+#define IDENTIFY_CAPABILITIES_LBA_SUPPORTED 0x0200 >+ >+/************************************************************************ >+ * IDENTIFY DMA timing cycle modes. >+ ************************************************************************/ >+#define IDENTIFY_DMA_CYCLES_MODE_0 0x00 >+#define IDENTIFY_DMA_CYCLES_MODE_1 0x01 >+#define IDENTIFY_DMA_CYCLES_MODE_2 0x02 >+ >+typedef struct _SENSE_DATA >+{ >+ UCHAR ErrorCode:7; >+ UCHAR Valid:1; >+ UCHAR SegmentNumber; >+ UCHAR SenseKey:4; >+ UCHAR Reserved:1; >+ UCHAR IncorrectLength:1; >+ UCHAR EndOfMedia:1; >+ UCHAR FileMark:1; >+ UCHAR Information[4]; >+ UCHAR AdditionalSenseLength; >+ UCHAR CommandSpecificInformation[4]; >+ UCHAR AdditionalSenseCode; >+ UCHAR AdditionalSenseCodeQualifier; >+ UCHAR FieldReplaceableUnitCode; >+ UCHAR 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 >+{ >+ UCHAR DeviceType : 5; >+ UCHAR DeviceTypeQualifier : 3; >+ UCHAR DeviceTypeModifier : 7; >+ UCHAR RemovableMedia : 1; >+ UCHAR Versions; >+ UCHAR ResponseDataFormat; >+ UCHAR AdditionalLength; >+ UCHAR Reserved[2]; >+ UCHAR SoftReset : 1; >+ UCHAR CommandQueue : 1; >+ UCHAR Reserved2 : 1; >+ UCHAR LinkedCommands : 1; >+ UCHAR Synchronous : 1; >+ UCHAR Wide16Bit : 1; >+ UCHAR Wide32Bit : 1; >+ UCHAR RelativeAddressing : 1; >+ UCHAR VendorId[8]; >+ UCHAR ProductId[16]; >+ UCHAR ProductRevisionLevel[4]; >+ UCHAR VendorSpecific[20]; >+ UCHAR Reserved3[40]; >+} INQUIRYDATA, *PINQUIRYDATA; >+ >+#define DIRECT_ACCESS_DEVICE 0x00 /* Disks */ >+ >+/************************************************************************ >+ * Read Capacity Data - returned in Big Endian format >+ ************************************************************************/ >+typedef struct _READ_CAPACITY_DATA >+{ >+ ULONG LogicalBlockAddress; >+ ULONG BytesPerBlock; >+} READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA; >+ >+#define MAXIMUM_CDB_SIZE 12 >+ >+/************************************************************************ >+ * CDB (Command Descriptor Block) >+ ************************************************************************/ >+typedef union _CDB >+{ >+ /* >+ * Standard 6-byte CDB >+ */ >+ struct _CDB6READWRITE >+ { >+ UCHAR OperationCode; >+ UCHAR LogicalBlockMsb1 : 5; >+ UCHAR LogicalUnitNumber : 3; >+ UCHAR LogicalBlockMsb0; >+ UCHAR LogicalBlockLsb; >+ UCHAR TransferBlocks; >+ UCHAR Control; >+ } CDB6READWRITE, *PCDB6READWRITE; >+ >+ /* >+ * Standard 10-byte CDB >+ */ >+ struct _CDB10 >+ { >+ UCHAR OperationCode; >+ UCHAR Reserved1 : 5; >+ UCHAR LogicalUnitNumber : 3; >+ UCHAR LogicalBlockByte0; >+ UCHAR LogicalBlockByte1; >+ UCHAR LogicalBlockByte2; >+ UCHAR LogicalBlockByte3; >+ UCHAR Reserved2; >+ UCHAR TransferBlocksMsb; >+ UCHAR TransferBlocksLsb; >+ UCHAR Control; >+ } CDB10, *PCDB10; >+ >+ struct _START_STOP >+ { >+ UCHAR OperationCode; >+ UCHAR Immediate: 1; >+ UCHAR Reserved1 : 4; >+ UCHAR LogicalUnitNumber : 3; >+ UCHAR Reserved2[2]; >+ UCHAR Start : 1; >+ UCHAR LoadEject : 1; >+ UCHAR Reserved3 : 6; >+ UCHAR 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 >+{ >+ ULONG PhysicalBaseAddress; /* Byte0 - Byte3 */ >+ USHORT ByteCount; /* Byte4 - Byte5 */ >+ USHORT EndOfTable; /* Byte6 - Byte7 */ >+} PRD_TABLE_ENTRY, *PPRD_TABLE_ENTRY; >+ >+#define SG_FLAG_EOT 0x8000 /* End of PRD */ >+#define MAX_SG_DESCRIPTORS 17 /* 17 -- maximum 64K */ >+ >+#define NUM_OF_PRD_TABLE_ENTRY 0x10 >+ >+/************************************************************************ >+ * Bus master register bits definition >+ ************************************************************************/ >+#define BM_CMD_FLG_START 0x01 >+#define BM_CMD_FLG_WRTTOMEM 0x08 >+#define BM_CMD_FLG_WRTTODSK 0x00 >+ >+#define BM_STAT_FLG_ACTIVE 0x01 >+#define BM_STAT_FLG_ERR 0x02 >+#define BM_STAT_FLG_INT 0x04 >+#define BM_DRV0_DMA_CAPABLE 0x20 >+#define BM_DRV1_DMA_CAPABLE 0x40 >+ >+#define BM_PRD_FLG_EOT 0x8000 >+ >+/************************************************************************ >+ * SRB Functions >+ ************************************************************************/ >+#define SRB_FUNCTION_EXECUTE_SCSI 0x00 >+#define SRB_FUNCTION_IO_CONTROL 0x02 >+#define SRB_FUNCTION_SHUTDOWN 0x07 >+#define SRB_FUNCTION_FLUSH 0x08 >+ >+/************************************************************************ >+ * SRB Status >+ ************************************************************************/ >+#define SRB_STATUS_PENDING 0x00 >+#define SRB_STATUS_SUCCESS 0x01 >+#define SRB_STATUS_ABORTED 0x02 >+#define SRB_STATUS_ABORT_FAILED 0x03 >+#define SRB_STATUS_ERROR 0x04 >+#define SRB_STATUS_BUSY 0x05 >+#define SRB_STATUS_INVALID_REQUEST 0x06 >+#define SRB_STATUS_INVALID_PATH_ID 0x07 >+#define SRB_STATUS_NO_DEVICE 0x08 >+#define SRB_STATUS_TIMEOUT 0x09 >+#define SRB_STATUS_SELECTION_TIMEOUT 0x0A >+#define SRB_STATUS_COMMAND_TIMEOUT 0x0B >+#define SRB_STATUS_MESSAGE_REJECTED 0x0D >+#define SRB_STATUS_BUS_RESET 0x0E >+#define SRB_STATUS_PARITY_ERROR 0x0F >+#define SRB_STATUS_REQUEST_SENSE_FAILED 0x10 >+#define SRB_STATUS_NO_HBA 0x11 >+#define SRB_STATUS_DATA_OVERRUN 0x12 >+#define SRB_STATUS_UNEXPECTED_BUS_FREE 0x13 >+#define SRB_STATUS_BAD_SRB_BLOCK_LENGTH 0x15 >+#define SRB_STATUS_REQUEST_FLUSHED 0x16 >+#define SRB_STATUS_INVALID_LUN 0x20 >+#define SRB_STATUS_INVALID_TARGET_ID 0x21 >+#define SRB_STATUS_BAD_FUNCTION 0x22 >+#define SRB_STATUS_ERROR_RECOVERY 0x23 >+#define SRB_STATUS_NEED_REQUEUE 0x24 >+ >+/************************************************************************ >+ * SRB Status Masks >+ ************************************************************************/ >+#define SRB_STATUS_QUEUE_FROZEN 0x40 >+#define SRB_STATUS_AUTOSENSE_VALID 0x80 >+ >+#define SRB_STATUS(Status) \ >+ (Status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN)) >+ >+/************************************************************************ >+ * SRB Flag Bits >+ ************************************************************************/ >+#define SRB_FLAGS_DATA_IN 0x00000040 >+#define SRB_FLAGS_DATA_OUT 0x00000080 >+ >+/************************************************************************ >+ * SRB Working flags define area >+ ************************************************************************/ >+#define SRB_WFLAGS_USE_INTERNAL_BUFFER 0x00000001 >+#define SRB_WFLAGS_IGNORE_ARRAY 0x00000002 >+#define SRB_WFLAGS_HAS_CALL_BACK 0x00000004 >+#define SRB_WFLAGS_MUST_DONE 0x00000008 >+#define SRB_WFLAGS_ON_MIRROR_DISK 0x00000010 >+#define SRB_WFLAGS_ON_SOURCE_DISK 0x00000020 >+#define SRB_WFLAGS_ARRAY_IO_STARTED 0x10000000 >+#define SRB_WFLAGS_WATCHTIMER_CALLED 0x20000000 >+#define SRB_WFLAGS_USE_SG 0x40000000 >+ >+/************************************************************************ >+ * SCSI I/O Request Block >+ ************************************************************************/ >+typedef struct _SCSI_REQUEST_BLOCK >+{ >+ USHORT Length; >+ UCHAR Function; >+ UCHAR SrbStatus; >+ UCHAR ScsiStatus; >+ UCHAR TargetId; >+ UCHAR Lun; >+ UCHAR CdbLength; >+ UCHAR SenseInfoBufferLength; >+ UCHAR UseSg; >+ UCHAR reseved[2]; >+ ULONG WorkingFlags; >+ ULONG SrbFlags; >+ ULONG DataTransferLength; >+ ULONG TimeOutValue; >+ PVOID DataBuffer; >+ PVOID SenseInfoBuffer; >+ UCHAR Cdb[16]; >+ Scsi_Cmnd * pREQ; >+} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK; >+ >+#define SCSI_REQUEST_BLOCK_SIZE sizeof(SCSI_REQUEST_BLOCK) >+ >+/************************************************************************ >+ * Second device flags >+ ***********************************************************************/ >+#define DFLAGS_REDUCE_MODE 0x00010000 >+#define DFLAGS_DEVICE_DISABLED 0x00020000 >+#define DFLAGS_BOOTABLE_DEVICE 0x00080000 >+#define DFLAGS_BOOT_MARK 0x00100000 >+#define DFLAGS_NEW_ADDED 0x40000000 >+#define DFLAGS_REMAINED_MEMBER 0x80000000 >+ >+/************************************************************************ >+ * Device Extension Device Flags >+ ************************************************************************/ >+/* >+ * Indicates that some device is present. >+ */ >+#define DFLAGS_DEVICE_PRESENT 0x0001 >+ >+/* >+ * Indicates whether ATAPI commands can be used. >+ */ >+#define DFLAGS_ATAPI_DEVICE 0x0002 >+ >+/* >+ * Indicates whether this is a tape device. >+ */ >+#define DFLAGS_TAPE_DEVICE 0x0004 >+ >+/* >+ * Indicates whether device interrupts as DRQ is set after >+ * receiving Atapi Packet Command. >+ */ >+#define DFLAGS_INT_DRQ 0x0008 >+ >+/* >+ * Indicates that the drive has the 'removable' bit set in >+ * identify data (offset 128) >+ */ >+#define DFLAGS_REMOVABLE_DRIVE 0x0010 >+ >+/* >+ * Media status notification enabled. >+ */ >+#define DFLAGS_MEDIA_STATUS_ENABLED 0x0020 >+ >+/* >+ * Indicates atapi 2.5 changer present. >+ */ >+#define DFLAGS_ATAPI_CHANGER 0x0040 >+ >+/* >+ * Indicates multi-platter device, not conforming to the 2.5 spec. >+ */ >+#define DFLAGS_SANYO_ATAPI_CHANGER 0x0080 >+ >+/* >+ * Indicates that the init path for changers has already been done. >+ */ >+#define DFLAGS_CHANGER_INITED 0x0100 >+#define DFLAGS_CONFIG_CHANGED 0x0200 >+ >+#define UDMA_MODE_5_6 0x80 >+ >+/************************************************************************ >+ * Used to disable 'advanced' features. >+ ************************************************************************/ >+#define MAX_ERRORS 4 >+ >+/************************************************************************ >+ * ATAPI command definitions >+ ************************************************************************/ >+#define ATAPI_MODE_SENSE 0x5A >+#define ATAPI_MODE_SELECT 0x55 >+#define ATAPI_FORMAT_UNIT 0x24 >+ >+/************************************************************************ >+ * User IOCTL structure >+ * Notes: >+ * (1) Data transfers are limited to PAGE_SIZE (4k on i386, 8k for alpha) >+ ************************************************************************/ >+typedef struct _uioctl_t >+{ >+ USHORT inlen; /* Length of data written to device */ >+ USHORT outlen; /* Length of data read from device */ >+ UCHAR DiskNo; /* The disk number */ >+ UCHAR AdapterNo; /* The adapter number */ >+ UCHAR Status; /* The ioctls status */ >+ UCHAR Reserved; /* Reserved for alignment */ >+ void * data; /* Data read from devic starts here */ >+} uioctl_t; >+ >+/************************************************************************ >+ * IOCTL commands for RAID >+ ************************************************************************/ >+#define ITE_IOCMAGIC 't' >+ >+#define ITE_IOC_GET_IDENTIFY_DATA _IOWR(ITE_IOCMAGIC, 0, IDENTIFY_DATA) >+#define ITE_IOC_GET_PHY_DISK_STATUS _IO(ITE_IOCMAGIC, 7) >+#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 _IOW(ITE_IOCMAGIC, 6, int) >+ >+/************************************************************************ >+ * _Channel >+ ************************************************************************/ >+typedef struct _Channel >+{ >+ /* >+ * IDE (ATAPI) io port address. >+ */ >+ ULONG io_ports[IDE_NR_PORTS]; >+ >+ /* >+ * DMA base address. >+ */ >+ ULONG dma_base; >+ >+ /* >+ * Flags word for each possible device. >+ */ >+ USHORT DeviceFlags[2]; >+ >+ /* >+ * Indicates number of platters on changer-ish devices. >+ */ >+ ULONG DiscsPresent[2]; >+ >+ /* >+ * Indicates expecting an interrupt. >+ */ >+ BOOLEAN ExpectingInterrupt; >+ >+ /* >+ * Indicate last tape command was DSC Restrictive. >+ */ >+ BOOLEAN RDP; >+ >+ /* >+ * Interrupt level. >+ */ >+ UCHAR InterruptLevel; >+ >+ /* >+ * Placeholder for status register after a GET_MEDIA_STATUS command. >+ */ >+ UCHAR ReturningMediaStatus; >+ >+ /* >+ * Remember the channel number (0, 1) >+ */ >+ UCHAR channel; >+ >+ /* >+ * Indicates cable status. >+ */ >+ UCHAR Cable80[2]; >+ >+ /* >+ * Data buffer pointer. >+ */ >+ PUSHORT DataBuffer; >+ >+ /* >+ * Data words left. >+ */ >+ ULONG WordsLeft; >+ >+ /* >+ * Retry count. >+ */ >+ ULONG RetryCount; >+ >+ /* >+ * Keep DMA type (MULTIWORD_DMA or ULTRA_DMA) for each device. >+ */ >+ UCHAR DmaType[2]; >+ >+ /* >+ * Keep UDMA timing for each device. >+ */ >+ UCHAR UdmaTiming[2]; >+ >+ /* >+ * Keep PIO/DMA timing for each channel. PioDmaTiming[clock][channel] >+ */ >+ UCHAR PioDmaTiming[2]; >+ >+ /* >+ * Keep IDE clock (50 MHz or 66 MHz) for each device. >+ */ >+ UCHAR IdeClock[2]; >+ >+ /* >+ * Keep the active device for each channel. >+ */ >+ UCHAR ActiveDevice; >+ >+ /* >+ * Indicate whether we should perform DMA mode switch on this channel? >+ */ >+ UCHAR DoSwitch; >+ >+ /* >+ * ??? >+ */ >+ BOOLEAN ConvertCdb; >+ >+ /* >+ * Use or do not use DMA. >+ */ >+ BOOLEAN UseDma[2]; >+ >+ /* >+ * Flags for initialization. >+ */ >+ BOOLEAN Initializing; >+ >+ /* >+ * Reserved for alignment. >+ */ >+ UCHAR reserved[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 int * dmatable_cpu; >+ >+ /* >+ * Point to SCATTER/GATHER data buffer. >+ */ >+ struct scatterlist * sg_table; >+ >+ /* >+ * How many SCATTER/GATHER counts. >+ */ >+ int sg_nents; >+ >+ /* >+ * DMA read or write. >+ */ >+ int sg_dma_direction; >+ >+ /* >+ * For retry timer. >+ */ >+ struct timer_list * retry_timer; >+ >+ /* >+ * For watchdog timer. >+ */ >+ struct timer_list * watch_timer; >+ >+ /* >+ * Current request on controller. >+ */ >+ PSCSI_REQUEST_BLOCK CurrentSrb; >+ >+ /* >+ * Original request on controller. >+ */ >+ PSCSI_REQUEST_BLOCK OriginalSrb; >+ >+ /* >+ * Internal SRB. >+ */ >+ SCSI_REQUEST_BLOCK _Srb; >+ >+ /* >+ * Remember the PCI device. >+ */ >+ struct pci_dev * pPciDev; >+ >+ /* >+ * Placeholder for CDB. >+ */ >+ UCHAR TempCdb[MAXIMUM_CDB_SIZE]; >+} Channel, *PChannel; >+ >+/************************************************************************ >+ * _Adapter >+ ************************************************************************/ >+typedef struct _Adapter >+{ >+ char * name; /* Adapter's name */ >+ UCHAR num_channels; /* How many channels support */ >+ UCHAR irq; /* irq number */ >+ UCHAR irqOwned; /* If any irq is use */ >+ UCHAR pci_bus; /* PCI bus number */ >+ UCHAR devfn; /* Device and function number */ >+ UCHAR offline; /* On line or off line */ >+ BOOLEAN bypass_mode; /* bypass or firware mode */ >+ UCHAR reserved2[1]; /* Reserved for alignment */ >+ Channel * IDEChannel; /* IT8212 supports two channels */ >+ struct pci_dev * pci_dev; /* For PCI device */ >+} >+ITE_ADAPTER, *PITE_ADAPTER; >+ >+/************************************************************************ >+ * Function prototypes >+ ************************************************************************/ >+const char *iteraid_info (struct Scsi_Host *); >+int iteraid_detect (Scsi_Host_Template *); >+int iteraid_release (struct Scsi_Host *); >+int iteraid_command (Scsi_Cmnd *); >+int iteraid_old_abort (Scsi_Cmnd *); >+int iteraid_old_reset (Scsi_Cmnd *, unsigned int); >+int iteraid_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); >+int iteraid_biosparam (Disk *, kdev_t, int *); >+int iteraid_proc_info (char *buffer, char **start, off_t offset, >+ int length, int hostno, int inout); >+ >+/************************************************************************ >+ * Scsi_Host_Template Initializer >+ ************************************************************************/ >+#define ITERAID \ >+{ \ >+ next: NULL, \ >+ module: NULL, \ >+ proc_name: "it8212", \ >+ proc_info: iteraid_proc_info, \ >+ name: "RAIDExpress133", \ >+ detect: iteraid_detect, \ >+ release: iteraid_release, \ >+ info: NULL, \ >+ ioctl: NULL, \ >+ command: iteraid_command, \ >+ queuecommand: iteraid_queuecommand, \ >+ abort: iteraid_old_abort, \ >+ reset: iteraid_old_reset, \ >+ slave_attach: NULL, \ >+ bios_param: iteraid_biosparam, \ >+ can_queue: 124, \ >+ this_id: -1, \ >+ sg_tablesize: 16, \ >+ cmd_per_lun: 1, \ >+ present: 0, \ >+ unchecked_isa_dma: 0, \ >+ use_clustering: DISABLE_CLUSTERING, \ >+ use_new_eh_code: 0 \ >+} >+ >+/************************************************************************ >+ * Beautification macros >+ ************************************************************************/ >+#define MAX_RETRY_COUNT 5 >+ >+#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) \ >+{ \ >+ ULONG i; \ >+ for (i = 0; i < 20000; i++) \ >+ { \ >+ GetStatus(pChan, Status); \ >+ if (Status & IDE_STATUS_BUSY) \ >+ { \ >+ udelay(150); \ >+ continue; \ >+ } \ >+ else \ >+ { \ >+ break; \ >+ } \ >+ } \ >+} >+ >+#define WaitOnBaseBusy(pChan, Status) \ >+{ \ >+ ULONG i; \ >+ for (i = 0; i < 20000; i++) \ >+ { \ >+ GetBaseStatus(pChan, Status); \ >+ if (Status & IDE_STATUS_BUSY) \ >+ { \ >+ udelay(150); \ >+ continue; \ >+ } \ >+ else \ >+ { \ >+ break; \ >+ } \ >+ } \ >+} >+ >+#define WaitForDrq(pChan, Status) \ >+{ \ >+ ULONG 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) \ >+{ \ >+ ULONG 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) \ >+{ \ >+ ULONG 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) \ >+{ \ >+ ULONG 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) \ >+{ \ >+ ULONG 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) \ >+{ \ >+ ULONG 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) \ >+{ \ >+ ULONG 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) \ >+{ \ >+ UCHAR statusByte; \ >+ outb((UCHAR)(((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((UCHAR)(((DevNum & 0x1) << 4) | 0xA0), pChan->io_ports[IDE_SELECT_OFFSET]); \ >+ WaitOnBusy(pChan, statusByte); \ >+ udelay(500); \ >+} >+ >+#define IdeHardReset(pChan, result) \ >+{ \ >+ UCHAR statusByte; \ >+ ULONG 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; \ >+ } \ >+} >+ >+/************************************************************************ >+ * Function prototypes >+ ************************************************************************/ >+void iteretry(PChannel); >+void TaskStart(PChannel, Scsi_Cmnd *); >+void TaskQueue(void); >+void TaskDone(PChannel, PSCSI_REQUEST_BLOCK); >+ULONG IdeSendCommand(PChannel, PSCSI_REQUEST_BLOCK); >+void IdeMediaStatus(BOOLEAN, PChannel, ULONG); >+static void IdeSetupDma(PChannel, ULONG, USHORT); >+void MapRequest(Scsi_Cmnd *, PSCSI_REQUEST_BLOCK); >+BOOLEAN IssueIdentify(PChannel, UCHAR, UCHAR); >+BOOLEAN AtapiStartIo(PChannel, PSCSI_REQUEST_BLOCK); >+BOOLEAN IT8212ResetAdapter(void); >+BOOLEAN 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 *); >+ >+#endif /* #ifndef _ITERAID_H_ */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 20919
: 11882