diff -Ncr linux-2.4.22/drivers/scsi/Config.in linux-2.4.22-ashuariadevel/drivers/scsi/Config.in
*** linux-2.4.22/drivers/scsi/Config.in	2003-12-18 00:52:40.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/Config.in	2003-12-17 20:05:49.000000000 +0900
***************
*** 213,218 ****
--- 213,227 ----
  if [ "$CONFIG_X86" = "y" ]; then
     dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
  fi
+ if [ "$CONFIG_X86" = "y" ]; then
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       dep_tristate 'Ultima RAID 100 support (EXPERIMENTAL)' CONFIG_SCSI_ULTIMARAID100 $CONFIG_SCSI
+       dep_tristate 'Ultima RAID 133 support (EXPERIMENTAL)' CONFIG_SCSI_ULTIMARAID133 $CONFIG_SCSI
+       if [ "$CONFIG_SCSI_ULTIMARAID133" != "n" ]; then
+         bool '  Use old type of detection. ' CONFIG_SCSI_ULTIMARAID133_OLDDETECT
+       fi
+    fi
+ fi
  dep_tristate 'Workbit NinjaSCSI-32Bi/UDE support' CONFIG_SCSI_NSP32 $CONFIG_SCSI
  #
  # Note - this is a very special 'host' adapter that simulates the presence of some disks.
diff -Ncr linux-2.4.22/drivers/scsi/Makefile linux-2.4.22-ashuariadevel/drivers/scsi/Makefile
*** linux-2.4.22/drivers/scsi/Makefile	2003-12-18 00:52:56.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/Makefile	2003-12-09 11:52:22.000000000 +0900
***************
*** 29,34 ****
--- 29,36 ----
  subdir-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx
  subdir-$(CONFIG_SCSI_AIC79XX)	+= aic7xxx
  subdir-$(CONFIG_PCMCIA)		+= pcmcia
+ subdir-$(CONFIG_SCSI_ULTIMARAID100)	+= ultimaraid100
+ subdir-$(CONFIG_SCSI_ULTIMARAID133)	+= ultimaraid133
  
  
  obj-$(CONFIG_SCSI)		+= scsi_mod.o
***************
*** 75,80 ****
--- 77,88 ----
  ifeq ($(CONFIG_SCSI_AIC79XX),y)
    obj-$(CONFIG_SCSI_AIC79XX)	+= aic7xxx/aic79xx.o
  endif
+ ifeq ($(CONFIG_SCSI_ULTIMARAID100),y)
+   obj-$(CONFIG_SCSI_ULTIMARAID100)	+= ultimaraid100/ultimaraid100.o
+ endif
+ ifeq ($(CONFIG_SCSI_ULTIMARAID133),y)
+   obj-$(CONFIG_SCSI_ULTIMARAID133)	+= ultimaraid133/ultimaraid133.o
+ endif
  obj-$(CONFIG_SCSI_AIC7XXX_OLD)	+= aic7xxx_old.o
  obj-$(CONFIG_SCSI_IPS)		+= ips.o
  obj-$(CONFIG_SCSI_FD_MCS)	+= fd_mcs.o
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid100/Makefile linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/Makefile
*** linux-2.4.22/drivers/scsi/ultimaraid100/Makefile	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/Makefile	2003-12-09 11:52:22.000000000 +0900
***************
*** 0 ****
--- 1,16 ----
+ # File: drivers/ultimaraid100/Makefile
+ # Makefile for the Ultima RAID 100 PCI controllers driver.
+ 
+ list-multi := ultimaraid100.o
+ ultima100-objs := ultima.o
+ obj-$(CONFIG_SCSI_ULTIMARAID100) := ultimaraid100.o
+ 
+ EXTRA_CFLAGS += -I.
+ 
+ ultimaraid100.o: $(ultima100-objs)
+ 	$(LD) -r -o $@ $(ultima100-objs)
+ 
+ include $(TOPDIR)/Rules.make
+ 
+ clean:
+ 	rm -f *.o
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid100/README linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/README
*** linux-2.4.22/drivers/scsi/ultimaraid100/README	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/README	2003-12-09 11:52:22.000000000 +0900
***************
*** 0 ****
--- 1,26 ----
+ Ultima RAID 100 Driver for Linux
+ 
+ Introduction
+ -------------------------
+ Original Driver was supported by Aralion(http://www.aralion.co.kr)
+ 
+ Supported Cards/Chipsets
+ -------------------------
+ 	Ultima RAID 100(ARS106S)
+ 
+ People
+ -------------------------
+ Aralion Linux Dev. <www.aralion.co.kr>	(Original ATA ONLY Driver source)
+ Ashuaria Lee <ashuaria@intizen.com>	(Patch for Linux Kernel Tree)
+ 
+ Original Driver
+ -------------------------
+ Aralion Linux Development
+ 
+ Mailing List
+ -------------------------
+ mailto:aralion0303-user@lists.kldp.net
+ mailto:aralion0303-news@lists.kldp.net
+ mailto:aralion0303-develop@lists.kldp.net
+ mailto:aralion0303-tester@lists.kldp.net
+ 
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid100/TODO linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/TODO
*** linux-2.4.22/drivers/scsi/ultimaraid100/TODO	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/TODO	2003-12-09 11:52:22.000000000 +0900
***************
*** 0 ****
--- 1,3 ----
+ o	Testing
+ o	More testing
+ o	Many more
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid100/atapi.h linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/atapi.h
*** linux-2.4.22/drivers/scsi/ultimaraid100/atapi.h	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/atapi.h	2003-12-09 11:52:22.000000000 +0900
***************
*** 0 ****
--- 1,300 ----
+ #ifndef _ATAPI_H
+ #define _ATAPI_H
+ 
+ #ifndef UCHAR 
+ #define UCHAR 	unsigned char
+ #define USHORT	unsigned short
+ #define	ULONG	unsigned long
+ #endif 
+ 
+ #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  
+ 
+ 
+ #define IDE_ERROR_BAD_BLOCK          0x80  // ICRC  :Crc error
+ #define IDE_ERROR_DATA_ERROR         0x40  // UNC   :data error
+ #define IDE_ERROR_MEDIA_CHANGE       0x20   
+ #define IDE_ERROR_ID_NOT_FOUND       0x10  // IDNF  :sector's ID field error
+ #define IDE_ERROR_MEDIA_CHANGE_REQ   0x08   
+ #define IDE_ERROR_COMMAND_ABORTED    0x04  // ABRT  :command error 
+ #define IDE_ERROR_END_OF_MEDIA       0x02  
+ #define IDE_ERROR_ILLEGAL_LENGTH     0x01
+ //
+ // IDE command definitions
+ //
+ #define IDE_COMMAND_ATAPI_RESET           0x08  // Don't use!
+ #define IDE_COMMAND_RECALIBRATE           0x10
+ #define IDE_COMMAND_READ                  0x20  // <---
+ #define IDE_COMMAND_WRITE                 0x30  // <---
+ #define IDE_COMMAND_VERIFY                0x40  // <---
+ #define IDE_COMMAND_SEEK                  0x70
+ #define IDE_COMMAND_SET_DRIVE_PARAMETERS  0x91
+ #define IDE_COMMAND_ATAPI_PACKET          0xA0  // Don't use!
+ #define IDE_COMMAND_ATAPI_IDENTIFY        0xA1  // Don't use!
+ #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  // Feature Set 
+ #define IDE_COMMAND_IDENTIFY              0xEC  // <---
+ #define IDE_COMMAND_MEDIA_EJECT           0xED
+ 
+ 
+ //////////////////////////////////KHG133s_Big//////////////////////////////////////
+ #define IDE_COMMAND_READ_DMA_EXT	  0x25
+ #define IDE_COMMAND_WRITE_DMA_EXT	  0x35
+ #define IDE_COMMAND_READ_SECTORS	  0x20
+ #define IDE_COMMAND_WRITE_SECTORS	  0x30
+ #define IDE_COMMAND_READ_SECTORS_EXT	  0x24
+ #define IDE_COMMAND_WRITE_SECTORS_EXT	  0x34
+ ///////////////////////////////////////////////////////////////////////////////////
+ //
+ //DmaCommand bits definition
+ //
+ #define DMA_READ     0x07
+ #define DMA_WRITE    0x06
+ 
+ //
+ // Mode Register bit definotion
+ //
+ #define MODE_PIO        0x00
+ #define MODE_DMA        0x01
+ #define MODE_UDMA       0x03
+ 
+ //
+ // HDD DMA Mode Support
+ //
+ #define DMA_0           0x01
+ #define DMA_1           0x03
+ #define DMA_2           0x07
+ #define UDMA_0          0x08
+ #define UDMA_1          0x18
+ #define UDMA_2          0x38
+ 
+ //
+ // Multiple sector setting is valid by HBA.
+ //
+ #define MULTIPLE_SET    0x0100
+ 
+ //
+ // Device Extension Device Flags
+ //
+ #define DFLAGS_DEVICE_PRESENT        0x0001    // Indicates that some device is present.
+ #define DFLAGS_DMA_DEVICE            0x0002    // Device is a DMA or UDMA device.
+ #define DFLAGS_PIO_DEVICE            0x0004    // Device is a PIO device.
+ 
+ //
+ // Used to disable 'advanced' features.
+ //
+ #define MAX_ERRORS                     4       // FOR IDE ERROR in MapError()
+ 
+ #ifdef XXX
+ 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[11];                   //     75-126
+ 	USHORT DmaMode[6];
+ 	USHORT Reserved7[33];                   //     75-126
+ 	USHORT SpecialFunctionsEnabled;         //     127
+ 	USHORT Reserved8[128];                  //     128-255
+ } IDENTIFY_DATA, *PIDENTIFY_DATA;
+ #endif
+ 
+ //
+ // 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
+     
+ 	UCHAR  TranslationFieldsValid;          // 6A  53
+     UCHAR  Reserved3;
+ 	/*
+ 	USHORT TranslationFieldsValid:3;        // 6A  53
+     USHORT Reserved3:13;
+     */
+ 
+     USHORT NumberOfCurrentCylinders;        // 6C  54
+     USHORT NumberOfCurrentHeads;            // 6E  55
+     USHORT CurrentSectorsPerTrack;          // 70  56
+     USHORT CurrentSectorCapacity[2];        // 72  57-58
+ 
+ 	/////// Out of spec! //////////// 
+     USHORT CurrentMultiSectorSetting;       //     59
+     USHORT UserAddressableSectors[2];          //     60-61
+ 
+     UCHAR  SingleWordDMASupport;            //     62  Low
+     UCHAR  SingleWordDMAActive;             //         High
+ 	/*
+     USHORT SingleWordDMASupport:8;          //     62  Low
+     USHORT SingleWordDMAActive:8;           //         High
+     */
+ 
+ 	UCHAR  MultiWordDMASupport;             //     63  Low
+     UCHAR  MultiWordDMAActive;              //         High
+ 	/*
+ 	USHORT MultiWordDMASupport:3;           //     63  Low
+     USHORT MultiWordDMAActive:13;           //         High
+     */
+ 
+ 	UCHAR  AdvancedPIOModes;                //     64
+     UCHAR  Reserved4;
+     /*
+ 	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
+ 
+ //////////////////////////////////KHG-133s_Big////////////////////////////////	
+ 	USHORT Reserved6[8];                   //     75-82
+ 	USHORT BIT48;                  		 //     83
+ 	USHORT Reserved6_1[4];                   //     84-87
+ ////////////////////////////////////////////////////////////////////////////// 
+ 	
+ 	UCHAR  UDMASupport;                     //     88
+ 	UCHAR  UDMASelected;                    //
+ 	/*
+ 	USHORT UDMASupport:3;                   //     88
+ 	USHORT UDMASelected:13;                 //
+     */
+ 
+ 	USHORT Reserved7[38];                   //     89-126
+     USHORT SpecialFunctionsEnabled;         //     127
+     USHORT Reserved8[128];                  //     128-255
+ } IDENTIFY_DATA, *PIDENTIFY_DATA;
+ 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
+ #define SEQUENTIAL_ACCESS_DEVICE        0x01    // tapes
+ #define PRINTER_DEVICE                  0x02    // printers
+ #define PROCESSOR_DEVICE                0x03    // scanners, printers, etc
+ #define WRITE_ONCE_READ_MULTIPLE_DEVICE 0x04    // worms
+ #define READ_ONLY_DIRECT_ACCESS_DEVICE  0x05    // cdroms
+ #define SCANNER_DEVICE                  0x06    // scanners
+ #define OPTICAL_DEVICE                  0x07    // optical disks
+ #define MEDIUM_CHANGER                  0x08    // jukebox
+ #define COMMUNICATION_DEVICE            0x09    // network
+ #define LOGICAL_UNIT_NOT_PRESENT_DEVICE 0x7F
+ #define DEVICE_QUALIFIER_NOT_SUPPORTED  0x03
+ 
+ #define PDTLAR						0X00
+ #define PDTHAR						0x02
+ #define CMDR						0x04
+ #define DMAMODE						0x06
+ #define PIO_TIM						0x08
+ #define MDM_TIM						0x0a
+ #define UDM_TIM						0x0c
+ #define CONSR						0x0e
+ 
+ #define INTSRC						0x00
+ #define CBL_ID						0x02
+ #define INTENA						0x04
+ #define RAIDSTAT					0x06
+ 
+ #endif
+ 
+ 
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid100/ultima.c linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/ultima.c
*** linux-2.4.22/drivers/scsi/ultimaraid100/ultima.c	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/ultima.c	2003-12-09 11:52:22.000000000 +0900
***************
*** 0 ****
--- 1,2134 ----
+ /*******************************************************************
+ 
+ 	 Aralion Ultima ATA100 IDE Raid Controller
+ 	 Linux Device Driver source, programmed by soonsoo@hitel.net
+ 
+ *******************************************************************/
+ //#define  __BOOT_KERNEL_BOOT	1
+ 
+ //#define	DEBUG1	1
+ //#define	DEBUG2	1
+ //#define	DEBUG3	1
+ //#define	DEBUG4	1
+ 
+ #include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/sched.h>
+ #include <asm/io.h>
+ #include <linux/blk.h>
+ #include "../scsi.h"
+ #include "../hosts.h"
+ #include "../sd.h"
+ #include "ultima.h"
+ #include "atapi.h"
+ #include <asm/system.h>
+ #include <linux/errno.h>
+ #include <linux/string.h>
+ #include <linux/ioport.h>
+ #include <linux/proc_fs.h>
+ #include <linux/pci.h>
+ #include <linux/stat.h>
+ #include <linux/delay.h>
+ #include <linux/config.h>	/* for CONFIG_PCI */
+ #include <linux/fs.h>
+ #include <asm/segment.h> /* for put_user_byte */
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+ #include <asm/bitops.h>
+ #include <asm/atomic.h>
+ //#include "iocontrol.h"
+ //#include "flash.h"
+ 
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ #define KERNEL240
+ #else
+ #define KERNEL220
+ #endif
+ 
+ #define S_BOARD(x) (DiskID[x].DiskStatus.BoardID)
+ #define S_CHAN(x) (DiskID[x].DiskStatus.Channel)
+ #define S_DRV(x) (DiskID[x].DiskStatus.Drive)
+ #define RAID(x) (DiskID[x].RaidStatus)
+ 
+ ////////////////////////////////////////////////////////////////////////////////////////
+ 
+  static void	print_banner(struct Scsi_Host *shpnt);
+  char * 		GetCmdName(char code);
+  static void    print_banner(struct Scsi_Host *shpnt);
+  static void    do_pause(ULONG amount);
+  static int     aralion_pci_bios_detect(int *irq);
+  ULONG			GetBlockCount(int BoardID,int channel,int drive);
+  void 			SetBlockCount(int BoardID,int channel,int drive,ULONG nCount);
+  int			RequestAllIrq(void);
+  int 			PutOneDriveToDiskSet(int board,int disk,_DiskIDTable *DiskID,V6BDISKINFO *DiskInfo);
+  void 			PutLBAvalue(
+ 						ULONG IOPort1,
+ 						ULONG lba,
+ 						ULONG numsectors,
+ 						ULONG DriveSelect);
+  void			DisableInterrupt(int BoardID);
+  void			EnableInterrupt(int BoardID);
+  ULONG			SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status);
+  ULONG 			SetScatterList(
+  						Scsi_Cmnd * SCpnt,
+ 						ULONG lba,
+ 						ULONG numsectors,
+ 						ULONG	ReadWrite);
+  void 			SetIOPort(DISKLIST *pList,USHORT DmaRW,DWORD OrderFlag);
+  void 			SetIOInformation(int tid,USHORT DmaRW,DWORD OrderFlag);
+  ULONG 			PutOneScatterList(
+ 						ULONG 		CurrentID,
+ 						DWORD		PrimaryDiskArrayCount,
+ 						DISKLIST	*PrimaryDiskArray,
+ 						ULONG 		lba,
+ 						ULONG 		buffer,
+ 						USHORT 		length);
+  void 			SetIDECommand(DWORD Command, DWORD order);
+  DWORD			BigDiskCommand (DWORD cmnd);
+  void           SetDMACommand(USHORT DmaRW,DWORD OrderFlag);
+  void FillDump(	Scsi_Cmnd * SCpnt);
+  static int		ReadDMA(
+ 						Scsi_Cmnd * SCpnt,
+ 						ULONG lba,
+ 						ULONG numsectors);
+  static int		WriteDMA(
+ 						Scsi_Cmnd * SCpnt,
+ 						ULONG lba,
+ 						ULONG numsectors);
+  void 			GetUDMAMode(
+ 						USHORT *mode,
+ 						USHORT *Timing,
+ 						IDENTIFY_DATA * IdentifyData);
+  void 			SetUDMAMode(
+ 						int BoardID,
+ 						int Channel, 
+ 						int DriveSelect, 
+ 						IDENTIFY_DATA * IdentifyData);
+  static int		IdentifyDisk( 
+ 						int BoardID,
+ 						int Channel, 
+ 						int DriveSelect, 
+ 						IDENTIFY_DATA * IdentifyData);
+  static void	my_done(int error);
+  int			CheckScsiError(ULONG Channel,ULONG IOPort1,UCHAR statusByte);
+  void 			CheckJobFinished(ULONG BoardID,ULONG Channel);
+  int 			IsSplitter(char c);
+  int            ultima_1cardreset(int BoardID);
+  int            ultima_cardreset(void);
+  void 			do_ultima_intr(int irq, void *dev_id, struct pt_regs *regs);
+  void			internal_done(Scsi_Cmnd * SCpnt);
+  void           print_info(Scsi_Cmnd * SCpnt);
+ 
+ ////////////////////////////////////////////////////////////////////////////////////////
+ 
+ struct proc_dir_entry proc_scsi_aralion = {
+     0x10, 7, "aralion",
+     S_IFDIR | S_IRUGO | S_IXUGO, 2
+ };
+ 
+ Scsi_Host_Template driver_template = ULTIMA_DMA100;
+ 
+ #define VERSION          "$Revision: LV2.01X-X86-ATA $"
+ 
+ 
+ enum {
+     in_arbitration = 0x02,
+     in_selection = 0x04,
+     in_other = 0x08,
+     disconnect = 0x10,
+     aborted = 0x20,
+     sent_ident = 0x40,
+ };
+ 
+  typedef struct {
+ 	char name[23];
+ 	char code;
+  } CMDNAME;
+ 
+ CMDNAME CmdName[] =
+ {
+ 	{"TEST_UNIT_READY",0x00},
+ 	{"REZERO_UNIT",0x01},
+ 	{"REQUEST_SENSE",0x03},
+ 	{"FORMAT_UNIT",0x04},
+ 	{"READ_BLOCK_LIMITS",0x05},
+ 	{"REASSIGN_BLOCKS",0x07},
+ 	{"READ_6",0x08},
+ 	{"WRITE_6",0x0a},
+ 	{"SEEK_6",0x0b},
+ 	{"READ_REVERSE",0x0f},
+ 	{"WRITE_FILEMARKS",0x10},
+ 	{"SPACE",0x11},
+ 	{"INQUIRY",0x12},
+ 	{"RECOVER_BUFFERED_DATA",0x14},
+ 	{"MODE_SELECT",0x15},
+ 	{"RESERVE",0x16},
+ 	{"RELEASE",0x17},
+ 	{"COPY",0x18},
+ 	{"ERASE",0x19},
+ 	{"MODE_SENSE",0x1a},
+ 	{"START_STOP",0x1b},
+ 	{"RECEIVE_DIAGNOSTIC",0x1c},
+ 	{"SEND_DIAGNOSTIC",0x1d},
+ 	{"ALLOW_MEDIUM_REMOVAL",0x1e},
+ 	{"SET_WINDOW",0x24},
+ 	{"READ_CAPACITY",0x25},
+ 	{"READ_10",0x28},
+ 	{"WRITE_10",0x2a},
+ 	{"SEEK_10",0x2b},
+ 	{"WRITE_VERIFY",0x2e},
+ 	{"VERIFY",0x2f},
+ 	{"SEARCH_HIGH",0x30},
+ 	{"SEARCH_EQUAL",0x31},
+ 	{"SEARCH_LOW",0x32},
+ 	{"SET_LIMITS",0x33},
+ 	{"PRE_FETCH",0x34},
+ 	{"READ_POSITION",0x34},
+ 	{"SYNCHRONIZE_CACHE",0x35},
+ 	{"LOCK_UNLOCK_CACHE",0x36},
+ 	{"READ_DEFECT_DATA",0x37},
+ 	{"MEDIUM_SCAN",0x38},
+ 	{"COMPARE",0x39},
+ 	{"COPY_VERIFY",0x3a},
+ 	{"WRITE_BUFFER",0x3b},
+ 	{"READ_BUFFER",0x3c},
+ 	{"UPDATE_BLOCK",0x3d},
+ 	{"READ_LONG",0x3e},
+ 	{"WRITE_LONG",0x3f},
+ 	{"CHANGE_DEFINITION",0x40},
+ 	{"WRITE_SAME",0x41},
+ 	{"READ_TOC",0x43},
+ 	{"LOG_SELECT",0x4c},
+ 	{"LOG_SENSE",0x4d},
+ 	{"MODE_SELECT_10",0x55},
+ 	{"RESERVE_10",0x56},
+ 	{"RELEASE_10",0x57},
+ 	{"MODE_SENSE_10",0x5a},
+ 	{"PERSISTENT_RESERVE_IN",0x5e},
+ 	{"PERSISTENT_RESERVE_OUT",0x5f},
+ 	{"MOVE_MEDIUM",0xa5},
+ 	{"READ_12",0xa8},
+ 	{"WRITE_12",0xaa},
+ 	{"WRITE_VERIFY_12",0xae},
+ 	{"SEARCH_HIGH_12",0xb0},
+ 	{"SEARCH_EQUAL_12",0xb1},
+ 	{"SEARCH_LOW_12",0xb2},
+ 	{"READ_ELEMENT_STATUS",0xb8},
+ 	{"SEND_VOLUME_TAG",0xb6},
+ 	{"WRITE_LONG_2",0xea}
+ };
+ 
+ ///////////////////////////////////////////////////////////////////////
+ static volatile int 		internal_done_flag = 0;
+ static volatile int 		internal_done_errcode = 0;
+ static Scsi_Cmnd 			*current_SC = NULL;
+ static int      			this_id = 31;
+ V6INTERFACEB 				V6;
+ static _DiskIDTable			DiskID[16];
+ static DISKRWINFO			DiskRWInfo[MAXBOARD][2][2];
+ static IDENTIFY_DATA 		DiskIdentifyData[MAXBOARD][2][2];
+ static int					gBoardCount = 0;
+ IrqID						ultimaID[MAXBOARD];
+ BOARDTABLE					BoardInfo[MAXBOARD];
+ static int					IrqFlag[16] = {0,};
+ static int					DriverInit = 0;
+ static int					DiskCount = 0;
+ ULONG						LastErrorBlock,LastErrorCode;
+ static ULONG				RWStatus;
+ static ULONG				OrderStatus;
+ static ULONG				CurrentDisk;
+ static int      			interrupt_level = 0;
+ /////////////////////////////////////////////////
+ #define IOCTL_LOCK	1
+ static int 					in_ioctl = 0;
+ static int 					ClearReady = 0;
+ static int 					in_command = 0;
+ unsigned long 				LockValue = 0;
+ static DECLARE_WAIT_QUEUE_HEAD (WaitingQ);
+ static int					HddConnected[MAXBOARD][2][2];
+ /////////////////////////////////////////////////
+ DWORD						gResetFlag = 0;
+  char * GetCmdName(char code)
+ {
+ 	int i;
+ 	int count;
+ 	char *s = "unknown function";
+ 
+ 	count = sizeof(CmdName) / sizeof(CMDNAME);
+ 
+ 	for(i=0;i<count;i++) {
+ 		if (CmdName[i].code == code)
+ 			return CmdName[i].name;
+ 	}
+ 	return s;
+ }
+ 
+ static void     print_banner(struct Scsi_Host *shpnt)
+ {
+     if (!shpnt)
+ 	return;			/* This won't ever happen */
+ 
+     printk("using scsi id %d\n", shpnt->this_id);
+ 
+     if (interrupt_level)
+ 	printk(" int %d", interrupt_level);
+     else
+ 	printk("<none>");
+ 
+     printk("\n");
+ }
+ 
+ static void            aralion_setup(char *str, int *ints)
+ {
+     this_id = 31;
+ }
+ 
+ 
+ /* Pause for amount*10 milliseconds */
+ static void     do_pause(ULONG amount)
+ {
+     do
+ 	{
+ 	    udelay(10 * 1000);
+ 	}
+     while (--amount);
+ }
+ 
+ inline static void aralion_make_bus_idle(void)
+ {
+ }
+ 
+ static int      aralion_is_valid_port(int port)
+ {
+ 	return 0;
+ }
+ 
+ static int      aralion_test_loopback(void)
+ {
+     return 0;
+ }
+ 
+ static int      aralion_pci_bios_detect(int *irq)
+ {
+     struct pci_dev *pdev = NULL;
+ 
+     if (!pci_present())
+ 		return 0;
+ 
+ 	memset(BoardInfo,0,sizeof(BoardInfo));
+ 	
+ 	do {
+ 	    if ((pdev = pci_find_device(ARALION_VENDOR, ULTIMA_DEVICE, pdev)) != NULL) {
+ #ifdef KERNEL240
+ 		    BoardInfo[gBoardCount].PrimaryIO 
+ 				= (ULONG) pci_resource_start(pdev,0);
+ 		    BoardInfo[gBoardCount].SecondaryIO 
+ 				= (ULONG) pci_resource_start(pdev,1);
+ 			BoardInfo[gBoardCount].PrimaryDmaIO 
+ 				= (ULONG) pci_resource_start(pdev,2);
+ 			BoardInfo[gBoardCount].SecondaryDmaIO 
+ 				= (ULONG) pci_resource_start(pdev,3);
+ 			BoardInfo[gBoardCount].ControlRegister 
+ 				= (ULONG) pci_resource_start(pdev,4);
+ #else
+ 		    BoardInfo[gBoardCount].PrimaryIO 
+ 				= (ULONG) pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+ 		    BoardInfo[gBoardCount].SecondaryIO 
+ 				= (ULONG) pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
+ 			BoardInfo[gBoardCount].PrimaryDmaIO 
+ 				= (ULONG) pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
+ 			BoardInfo[gBoardCount].SecondaryDmaIO 
+ 				= (ULONG) pdev->base_address[3] & PCI_BASE_ADDRESS_IO_MASK;
+ 			BoardInfo[gBoardCount].ControlRegister 
+ 				= (ULONG) pdev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+ #endif
+             BoardInfo[gBoardCount].interrupt_level = pdev->irq;
+ 
+ 		    request_region(BoardInfo[gBoardCount].PrimaryIO, 0x10, "aralion");
+ 		    request_region(BoardInfo[gBoardCount].SecondaryIO, 0x10, "aralion");
+ 		    request_region(BoardInfo[gBoardCount].PrimaryDmaIO, 0x10, "aralion");
+ 		    request_region(BoardInfo[gBoardCount].SecondaryDmaIO, 0x10, "aralion");
+ 		    request_region(BoardInfo[gBoardCount].ControlRegister, 0x10, "aralion");
+ 			if (!gBoardCount)
+ 			    *irq = pdev->irq;
+ 
+ 		    gBoardCount++;
+ 		}
+     } while(pdev != NULL);
+ 
+ 
+ 	if (!gBoardCount) {
+ 		printk("Ultima Board not found\n");
+ 		return 0;
+ 	}
+ 
+ 	interrupt_level = BoardInfo[0].interrupt_level;
+ 	
+ //	printk("%d's Board found :",gBoardCount);
+ 	
+     return 1;
+ }
+ 
+  ULONG	GetBlockCount(int BoardID,int channel,int drive)
+ {
+ 	int i;
+ 	ULONG nCount;
+ 	UCHAR *p;
+ 	p = (char *) &(DiskIdentifyData[BoardID][channel][drive]);
+ 	if(DiskIdentifyData[BoardID][channel][drive].BIT48 & 0x0400)
+ 		nCount = *((ULONG *) (p + 200));
+ 	else
+ 		nCount = *((ULONG *) (p + 120));
+ //	printk("BCD=%d,%d,%d Size = %u \n",BoardID,channel,drive,nCount);
+ 	return nCount;
+ }
+ 
+ 
+ void SetBlockCount(int BoardID,int channel,int drive,ULONG nCount)
+ {
+ 	UCHAR *p;
+ 	
+ 	p = (char *) &(DiskIdentifyData[BoardID][channel][drive]);
+ 	if(DiskIdentifyData[BoardID][channel][drive].BIT48 & 0x0400)
+ 		 *((ULONG *) (p + 200)) = nCount;
+ 	else
+ 		*((ULONG *) (p + 120)) = nCount;
+ }
+ 
+ //////////////////
+ int	RequestAllIrq(void) 
+ {
+ 	int			i;
+ 	int			irq;
+ 	int			retcode;
+ 	
+ 	for(i=0;i<gBoardCount;i++) {
+ 		irq = BoardInfo[i].interrupt_level;
+ 		
+ 		if (!IrqFlag[irq]) {
+ 			IrqFlag[irq] = 1;
+ 			memset(ultimaID[i].signature,0,8);
+ 			memcpy(ultimaID[i].signature,"Ultima",6);
+ 			ultimaID[i].IOPort1 = BoardInfo[i].PrimaryDmaIO;
+ 			ultimaID[i].irq = irq;
+ 
+ //			if (i == 0) 
+ 			{
+ //				printk("Int = %d\n",irq);
+ 			    retcode = request_irq(irq,
+ 						  do_ultima_intr, 
+ 						  SA_INTERRUPT | SA_SHIRQ, 
+ 						  "aralion", 
+ 						  &ultimaID[i]);
+ 			}
+ #ifdef DEBUG											  
+ //    		printk("retcode = %d,%d\n", i,retcode);
+ #endif
+ 		    if (retcode < 0)
+ 			{
+ 				printk("%d's Board IRQ Failure\n",i);
+ 				
+ 			    if (retcode == -EINVAL)	{
+ 				    printk("scsi: <aralion> IRQ %d is bad!\n", irq);
+ 				    printk("                This shouldn't happen!\n");
+ 				    printk("                Send mail to faith@acm.org\n");
+ 			    } else if (retcode == -EBUSY) {
+ 				    printk("scsi: <aralion> IRQ %d is already in use!\n",irq);
+ 				    printk("                Please use another IRQ!\n");
+ 			    } else {
+ 				    printk("scsi: <aralion> Error getting IRQ %d\n",irq);
+ 				    printk("                This shouldn't happen!\n");
+ 				    printk("                Send mail to faith@acm.org\n");
+ 				}
+ 			    printk("scsi: <aralion> Detected, but driver not loaded (IRQ)\n");
+ 
+ 			    return retcode;
+ 			}
+ 		}
+ 	}
+ 	return 0;
+ }
+ 
+ 
+ int             ultima_detect(Scsi_Host_Template * tpnt)
+ {
+     int             retcode;
+     struct Scsi_Host *shpnt;
+     int             i, j;
+     int             flag = 0;
+ 
+     tpnt->proc_dir = &proc_scsi_aralion;
+ 
+     flag = aralion_pci_bios_detect(&interrupt_level);
+ 
+ 	if (!flag) {
+ 		printk("scsi: Ultima not found\n");
+ 		return 0;
+ 	}
+ 
+ 	
+ 	memset(&DiskID,0,sizeof(DiskID));
+ 	memset(&DiskRWInfo,0,sizeof(DiskRWInfo));
+ 	memset(&DiskIdentifyData,0,sizeof(DiskIdentifyData));
+ 	DiskCount = 0;
+ 
+ 
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		gResetFlag = 1;
+ 		DisableInterrupt(i);
+ 		ultima_1cardreset(i);
+ 		for(j=0;j<4;j++)
+ 		{
+ 			if(IdentifyDisk(i,j/2,j%2,&DiskIdentifyData[i][j/2][j%2]) == 1)
+ 			{	
+ 				DiskID[DiskCount].DiskStatus.BoardID = i;
+ 				DiskID[DiskCount].DiskStatus.Channel = j/2;
+ 				DiskID[DiskCount].DiskStatus.Drive = j%2;
+ 				DiskID[DiskCount].DiskStatus.Size = GetBlockCount(i,j/2,j%2);
+ 				DiskID[DiskCount].RaidStatus = NORMALIDE;
+ 				DiskCount++;
+ 			}
+ 		}
+ 		mdelay(100);
+ 		EnableInterrupt(i);
+ 		gResetFlag = 0;
+ 	}
+ 
+ ////////////////////////////////////////////////////////////////////////////
+ 	
+ 	DriverInit = 1;
+ 
+     tpnt->this_id = (this_id & 0x1f);
+ 
+     /* Print out a banner here in case we can't
+        get resources.  */
+     shpnt = scsi_register(tpnt, 0);
+     shpnt->irq = interrupt_level;
+     shpnt->io_port = BoardInfo[0].ControlRegister;
+     shpnt->n_io_port = 0x10;
+ //    print_banner(shpnt);
+ 
+     if (!interrupt_level)
+ 	{
+ 	    printk("scsi: <aralion>"
+ 		   " Card Detected, but driver not loaded (no IRQ)\n");
+ 	    return 0;
+     } else
+ 	{
+ 	    /* Register the IRQ with the kernel */
+ 		if (RequestAllIrq())
+ 			return 0;
+ 	}
+ 	DriverInit = 0;
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		BoardInfo[i].PriScatterList = kmalloc(SCATTERLISTSIZE,GFP_ATOMIC);
+ 		BoardInfo[i].SecScatterList = kmalloc(SCATTERLISTSIZE,GFP_ATOMIC);
+ 	}			
+ //	printk("ultima_detect End..\n");
+ 	return 1;			/* Maximum of one adapter will be detected. */
+ }
+ 
+ int             ultima_release(struct Scsi_Host * tpnt)
+ {
+ 	int		i;
+ 	int		irq;
+ 	
+ 	for(i=0;i<gBoardCount;i++) {
+ 		irq = BoardInfo[i].interrupt_level;
+ 		if (IrqFlag[irq]) {
+ 			free_irq(irq,&ultimaID[i]);
+ 			IrqFlag[irq] = 0;
+ 		}
+ 		release_region(BoardInfo[i].PrimaryIO,0x10);
+ 		release_region(BoardInfo[i].SecondaryIO,0x10);
+ 		release_region(BoardInfo[i].PrimaryDmaIO,0x10);
+ 		release_region(BoardInfo[i].SecondaryDmaIO,0x10);
+ 		release_region(BoardInfo[i].ControlRegister,0x10);
+ 
+ 		kfree(BoardInfo[i].PriScatterList);
+ 		kfree(BoardInfo[i].SecScatterList);
+ 	}
+ 	scsi_unregister(tpnt);
+ 	
+ 	return 0;
+ }
+ 
+ #ifdef DEBUG
+  void printDMARegister(int BoardID)
+ {
+ 	int i;
+ 	USHORT d1;
+ 
+ 	for(i=0;i<0x10;i++) {
+ 		d1 = inw(BoardInfo[BoardID].ControlRegister + i*2);
+ 		printk("<%02x:%04x> ",i,d1);
+ 	}
+ 	printk("\n");
+ }
+ #endif
+ 
+ inline DISKRWINFO *GetRWInfoPointer(DISKLIST *pDiskList)
+ {
+ 	return (DISKRWINFO *) &DiskRWInfo[pDiskList->BoardID][pDiskList->Channel][pDiskList->Drive];
+ }
+ 			
+ void PutLBAvalue(ULONG IOPort1,ULONG lba,ULONG numsectors,
+ 				ULONG DriveSelect)
+ {
+ 	UCHAR	Data[4];
+ 	if(lba >= 0x10000000){
+ 		Data[0] = (lba & 0xff000000 ) >> 24;
+ 		Data[1] = 0;
+ 		Data[2] = 0;
+ 		outb(0,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		Data[0] = (lba & 0x000000ff);
+ 		Data[1] = (lba & 0x0000ff00) >> 8;
+ 		Data[2] = (lba & 0x00ff0000) >> 16;
+ 		Data[3] = (DriveSelect << 4) | 0xe0;
+ 		outb(numsectors,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		outb(Data[3],IOPort1 + DriveSelectPort);
+ 	}
+ 	else{
+ 		Data[0] = (lba & 0x000000ff);
+ 		Data[1] = (lba & 0x0000ff00) >> 8;
+ 		Data[2] = (lba & 0x00ff0000) >> 16;
+ 		Data[3] = (lba & 0x0f000000) >> 24;
+ 		Data[3] = Data[3] | 0x40 | (DriveSelect << 4) | 0xa0;
+ 
+ 		outb(numsectors,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		outb(Data[3],IOPort1 + DriveSelectPort);
+ 	}
+ }
+ 
+  void DisableInterrupt(int BoardID)
+ {
+ 	USHORT		Intena;
+ 	Intena = 0;
+ 	outw(Intena,BoardInfo[BoardID].ControlRegister + INTENA);
+ }
+ 
+  void EnableInterrupt(int BoardID)
+ {
+ 	USHORT		Intena;
+ 	Intena = 0x03;		
+ 	outw(Intena,BoardInfo[BoardID].ControlRegister + INTENA);
+ }
+ 
+  ULONG SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status)
+ {
+ 	ULONG	TempStatus;
+ 	
+ 	if (BoardInfo[BoardID].InterruptFlag[Channel] & Status) {
+ 		TempStatus = BoardInfo[BoardID].InterruptFlag[Channel] & 0x00001111;
+ 		if(TempStatus & 0x00001100){
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00001000;
+ 			return 0x00001000;
+ 		}
+ 		else if(TempStatus & 0x00000010){
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00000100;
+ 			return 0x00000100;
+ 		}
+ 		else {
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00000010;
+ 			return 0x000000010;
+ 		}
+ 		
+ 
+ #ifdef DEBUG1
+ 		printk("SL:[%d,%d] - %08x ",
+ 			BoardID,Channel,
+ 			BoardInfo[BoardID].InterruptFlag[Channel]);
+ #endif
+ 	}
+ 	else {
+ 		BoardInfo[BoardID].InterruptFlag[Channel] = (Status | ORDER_ONE);
+ 
+ #ifdef DEBUG1
+ 		printk("SF:[%d,%d] - %08x ",
+ 			BoardID,Channel,
+ 			BoardInfo[BoardID].InterruptFlag[Channel]);
+ #endif
+ 		return 0;
+ 	}
+ }
+ 
+ ULONG SetScatterList(	Scsi_Cmnd * SCpnt,
+ 						ULONG lba,
+ 						ULONG numsectors,
+ 						ULONG	ReadWrite)
+ {
+ 	struct scatterlist 	*slp;
+ 	int					i,j;
+ 	PPDT_TABLE 			pPDTTable;
+ 	DISKRWINFO			*pRWInfo,*pRWInfo2;
+ 	int					tid = SCpnt->target;
+ 	DWORD				RaidStatus;
+ 	ULONG	TempFlag;
+ 
+ 	RaidStatus = RAID(tid);
+ 
+ 	pRWInfo = (DISKRWINFO *) &DiskRWInfo[S_BOARD(tid)][S_CHAN(tid)][S_DRV(tid)];
+ 	pRWInfo->StartLba = lba;
+ 	pRWInfo->ListCount = 0;
+ 	pRWInfo->NumSectors = 0;
+ 	pPDTTable = pRWInfo->ScatterList;
+ 
+ 	if (SCpnt->use_sg)
+ 	{
+ 		slp = (struct scatterlist *) SCpnt->request_buffer;
+ 		for(i=0;i<SCpnt->use_sg;i++,slp++) {
+ 			pPDTTable[i].address = virt_to_bus(slp->address);
+ 			pPDTTable[i].length = slp->length;
+ 			pPDTTable[i].EndOfChain = 0;
+ 			pRWInfo->NumSectors += slp->length;
+ 		}
+ 		pPDTTable[i - 1].EndOfChain = 0x80;
+ 		pRWInfo->ListCount = SCpnt->use_sg;
+ 	}
+ 	else 
+ 	{
+ 		pPDTTable[0].address = virt_to_bus(SCpnt->request_buffer);
+ 		pPDTTable[0].length = SCpnt->request_bufflen;
+ 		pPDTTable[0].EndOfChain = 0x80;
+ 		pRWInfo->NumSectors = SCpnt->request_bufflen;
+ 		pRWInfo->ListCount = 1;
+ 	}
+ 
+ 	pRWInfo->NumSectors /= 512;
+ 
+ 	pRWInfo->InterruptFlag = ReadWrite | ORDER_ONE;
+ 	SetBoardInterruptFlag(S_BOARD(tid),S_CHAN(tid),ReadWrite);
+ 
+ }
+ 
+  void PrintPDT(PPDT_TABLE  pPDTTable,int count)
+ {
+ 	int i;
+ 
+ 	for(i=0;i<count;i++) {
+ 		printk("%04d : [%08x,%04x,%02x]\n",i,
+ 				pPDTTable[i].address,
+ 				pPDTTable[i].length,
+ 				pPDTTable[i].EndOfChain);
+ 	}	
+ }
+ 
+  void SetIOPort(DISKLIST *pList,USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	USHORT		AddressLow,AddressHi;
+ 	PPDT_TABLE  pPDTTable;
+ 	long		i;
+ 	DISKRWINFO	*pRWInfo;
+ 	ULONG		BoardID,Channel,Drive;
+ 	ULONG		IOPort1,DmaIO;
+ 
+ 	BoardID = pList->BoardID;
+ 	Channel = pList->Channel;
+ 	Drive = pList->Drive;
+ 
+ 	pRWInfo = (DISKRWINFO *) &DiskRWInfo[pList->BoardID][pList->Channel][pList->Drive];
+ 
+ 
+ #ifdef DEBUG1
+ /*
+ 	printk("SetIOPort : [B:%d,C:%d,D:%d,F:%08x,O:%08x]\n",
+ 				BoardID,
+ 				Channel,
+ 				Drive,
+ 				pRWInfo->InterruptFlag,
+ 				OrderFlag);
+ */
+ #endif
+ 
+ 
+ 	if (!(OrderFlag & pRWInfo->InterruptFlag)) {
+ #ifdef DEBUG1
+ 		printk("Order Invalid\n");
+ #endif
+ 		return ;
+ 	}
+ 
+ 	if (Channel == 0) 
+ 	{
+ 		pPDTTable = BoardInfo[BoardID].PriScatterList;
+ 		IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 		DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	}
+ 	else 
+ 	{
+ 		pPDTTable = BoardInfo[BoardID].SecScatterList;
+ 		IOPort1 = BoardInfo[BoardID].SecondaryIO;
+ 		DmaIO = BoardInfo[BoardID].SecondaryDmaIO;
+ 	}
+ 	memcpy(pPDTTable,pRWInfo->ScatterList,pRWInfo->ListCount * sizeof(PDT_TABLE));
+ 	BoardInfo[BoardID].ListCount 		= pRWInfo->ListCount;
+ 	BoardInfo[BoardID].NumSectors       = pRWInfo->NumSectors;
+ 	BoardInfo[BoardID].StartLba         = pRWInfo->StartLba;
+ 
+ 	AddressLow = virt_to_bus(pPDTTable) & 0x0000ffff;
+ 	AddressHi = (virt_to_bus(pPDTTable) & 0xffff0000) >> 16;
+ 
+ 	outw(AddressLow,DmaIO + PDTLAR);
+ 	outw(AddressHi,DmaIO + PDTHAR);
+ 	PutLBAvalue(
+ 			IOPort1,
+ 			BoardInfo[BoardID].StartLba,
+ 			BoardInfo[BoardID].NumSectors,
+ 			Drive);
+ 
+ }
+ 
+ void SetIOInformation(int tid,USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	struct scatterlist 	*slp;
+ 	int					i,j,k;
+ 	PPDT_TABLE 			pPDTTable;
+ 	DISKRWINFO 	*pRWInfo = GetRWInfoPointer(&DiskID[tid].DiskStatus);
+ 	if (pRWInfo->ListCount) {
+ 		SetIOPort(&DiskID[tid].DiskStatus,DmaRW,OrderFlag);
+ 	}
+ 	
+ }
+ 
+  void SetIDECommand(DWORD Command, DWORD OrderFlag)
+ {
+ 	int i,j;
+ 	
+ 	for(i=0;i<MAXBOARD;i++) {
+ 		if (BoardInfo[i].InterruptFlag[0] & OrderFlag) {
+ 			if(BoardInfo[i].StartLba >= 0x10000000)
+ 				Command=BigDiskCommand(Command);
+ 			outb(Command,BoardInfo[i].PrimaryIO + CommandPort);
+ 		}
+ 		if (BoardInfo[i].InterruptFlag[1] & OrderFlag) {
+ 			if(BoardInfo[i].StartLba >= 0x10000000)
+ 				Command=BigDiskCommand(Command);
+ 			outb(Command,BoardInfo[i].SecondaryIO + CommandPort);
+ 		}
+ 		
+ 	}
+ }
+ 
+  DWORD	BigDiskCommand (DWORD cmnd)
+ {
+ 	switch(cmnd){
+ 		case	IDE_COMMAND_READ_DMA:
+ 			return IDE_COMMAND_READ_DMA_EXT;
+ 		case	IDE_COMMAND_WRITE_DMA:
+ 			return IDE_COMMAND_WRITE_DMA_EXT;
+ 	}
+ }
+ 
+  void SetDMACommand(USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	ULONG		DmaIO;
+     int         i,j,k;
+ 
+     for(i=0;i<gBoardCount;i++) {
+         for(j=0;j<2;j++) {
+             for(k=0;k<2;k++) {
+                 if ((OrderFlag & DiskRWInfo[i][j][k].InterruptFlag)) 
+ 				{
+                     if (j == 0) 
+ 					{
+ 						DmaIO = BoardInfo[i].PrimaryDmaIO;
+ 					}
+ 					else 
+ 					{
+ 						DmaIO = BoardInfo[i].SecondaryDmaIO;
+ 					}
+                 	outw(DmaRW,DmaIO + CMDR);
+                  }
+             }
+         }
+     }
+ }
+ 
+ 
+ static int			ReadDMA(
+ 						Scsi_Cmnd * SCpnt,
+ 						ULONG lba,
+ 						ULONG numsectors)
+  {
+ 	int 			i;
+ 	unsigned long	flags;
+ 
+ 	if (numsectors == 0) {
+     	my_done(DID_ABORT << 16);
+ 		return ERROR_INVALID_SECTORCOUNT;
+ 	}
+ 	//switch(RaidStatus) {
+ 	switch(DiskID[SCpnt->target].RaidStatus) {
+ 		case NORMALIDE:
+ 			SetScatterList(SCpnt,lba,numsectors,READ_STATUS);
+ 			break;
+ 		default:
+ 			printk("Not Supported Mode!!\n");
+ 			return -1;
+ 	}
+ 	SetIOInformation(SCpnt->target,DMA_READ,ORDER_ONE);
+ 	RWStatus = READ_STATUS;
+ 	OrderStatus = ORDER_ONE;
+ 	SetIDECommand(IDE_COMMAND_READ_DMA,ORDER_ONE);
+    	SetDMACommand(DMA_READ,ORDER_ONE);
+ 	return 0;	
+ }
+ 
+ static int			WriteDMA(
+ 						Scsi_Cmnd * SCpnt,
+ 						ULONG lba,
+ 						ULONG numsectors)
+  {
+ 	int 		i;
+ 	unsigned long	flags;
+ 
+ 	if (numsectors == 0) {
+     	my_done(DID_ABORT << 16);
+ 		return ERROR_INVALID_SECTORCOUNT;
+ 	}
+ 
+ 	switch(DiskID[SCpnt->target].RaidStatus) {
+ 		case NORMALIDE:
+ 			SetScatterList(SCpnt,lba,numsectors,WRITE_STATUS);
+ 			break;
+ 		default:
+ 			printk("Not Supported Mode!!\n");
+ 			return -1;
+ 
+ 	}
+ 	SetIOInformation(SCpnt->target,DMA_WRITE,ORDER_ONE);
+ 	RWStatus = WRITE_STATUS;
+ 	OrderStatus = ORDER_ONE;
+ 	SetIDECommand(IDE_COMMAND_WRITE_DMA,ORDER_ONE);
+    	SetDMACommand(DMA_WRITE,ORDER_ONE);
+ 	return 0;	
+ }
+ 
+  void GetUDMAMode(USHORT *mode,USHORT *Timing,
+ 				IDENTIFY_DATA * IdentifyData)
+  {
+ 
+ 	if(IdentifyData->UDMASupport & 0x20){ 
+ 		*mode = 0x45; // mode 5
+ 		*Timing = 0xff22; // mode 5
+ 	}
+ 	else if(IdentifyData->UDMASupport & 0x10){ 
+ 		*mode = 0x44; // mode 4
+ 		*Timing = 0xff33; // mode 4
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x08){ 
+ 		*mode = 0x43; // mode 3
+ 		*Timing = 0xff55; // mode 3
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x04){ 
+ 		*mode = 0x42; // mode 2
+ 		*Timing = 0xff66; // mode 2
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x02){ 
+ 		*mode = 0x41; // mode 1
+ 		*Timing = 0xff88; // mode 1
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x01){ 
+ 		*mode = 0x40; // mode 0
+ 		*Timing = 0xffcc; // mode 0
+ 	} 
+ #ifdef _7878_
+ 	*mode = 0x44; // mode 4
+ 	*Timing = 0x7878; // safe mode
+ #endif
+ }
+ 
+  void SetUDMAMode(	int BoardID,
+ 					int Channel, 
+ 					int DriveSelect, 
+ 					IDENTIFY_DATA * IdentifyData)
+ {
+ 	USHORT 		mode[2],Timing[2];
+ 	ULONG    	IOPort1;
+ 	ULONG		DmaIO;
+ 	char		statusByte;
+ 	int i;	
+ 	if (Channel == 0) {
+ 		IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 		DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	}
+ 	else {
+ 		IOPort1 = BoardInfo[BoardID].SecondaryIO;
+ 		DmaIO = BoardInfo[BoardID].SecondaryDmaIO;
+ 	}
+ 	outb(0x03,IOPort1 + ErrorPort);
+ 
+ 	for(i=0;i<4;i++)
+ 	{
+ 		mode[i] = 0xffff;
+ 	}
+ 
+ 	if (HddConnected[BoardID][Channel][0])
+ 		GetUDMAMode(&mode[0],&Timing[0],&DiskIdentifyData[BoardID][Channel][0]);
+ 	if (HddConnected[BoardID][Channel][1])
+ 		GetUDMAMode(&mode[1],&Timing[1],&DiskIdentifyData[BoardID][Channel][1]);
+ 	if(mode[0] > mode[1])
+ 	{
+ 			mode[0] = mode[1];
+ 			Timing[0] = Timing[1];
+ 	}
+ 			
+ 	outw(0x0001,DmaIO + DMAMODE);
+ 
+ 	outb(mode[0],IOPort1 + BlockCountPort);
+ 	if (HddConnected[BoardID][Channel][0])
+ 	{		
+ 		outb(0xA0,IOPort1 + DriveSelectPort);
+ 		outb(IDE_COMMAND_ENABLE_MEDIA_STATUS,IOPort1 + CommandPort);
+ 		outw(Timing[0],DmaIO + UDM_TIM);
+ 	}
+ 	if (HddConnected[BoardID][Channel][1])
+ 	{
+ 		outb(0xB0,IOPort1 + DriveSelectPort);
+ 		outb(IDE_COMMAND_ENABLE_MEDIA_STATUS,IOPort1 + CommandPort);
+ 		outw(Timing[0],DmaIO + UDM_TIM);
+ 	}
+ 
+ 	statusByte = 0;
+ 	mdelay(5);
+ 	while(!(statusByte & IDE_STATUS_IDLE))
+ 	{
+    		GetBaseStatus(IOPort1, statusByte);
+ 	}
+ }
+ 
+ static int	IdentifyDisk( 
+ 				int BoardID,
+ 				int Channel, 
+ 				int DriveSelect, 
+ 				IDENTIFY_DATA * IdentifyData)
+ {
+     ULONG    	IOPort1,DmaIO,ControlRegister;
+     UCHAR   	statusByte;
+     USHORT 		*pIdentifyData;
+     int             i, j;
+ 	int			flag = 0;
+ 
+ 	HddConnected[BoardID][Channel][DriveSelect] = 0;
+ 	mdelay(100);
+ 
+     if (Channel == 0)
+ 	{
+ 	    IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 		DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	} 
+ 	else
+ 	{
+ 		IOPort1 = BoardInfo[BoardID].SecondaryIO;
+ 		DmaIO = BoardInfo[BoardID].SecondaryDmaIO;
+ 	}
+ 
+ 	ControlRegister = BoardInfo[BoardID].ControlRegister;
+ 
+    	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 
+ 	for (i=0;i<100;i++) {
+ 		udelay(10);
+ 		GetBaseStatus(IOPort1, statusByte);
+ 
+ 		if (!(statusByte & 0x80))
+ 			break;
+ 	}
+     outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+ 	GetBaseStatus(IOPort1, statusByte);
+ 	
+     outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+     GetBaseStatus(IOPort1, statusByte);
+ 
+     outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+     GetBaseStatus(IOPort1, statusByte);
+ 	mdelay(50);
+ 	if(statusByte != 0x50)
+ 	{
+ 		if((statusByte & 0xF0) != 0x50)
+ 			return 0;
+ 		outb(0x08,IOPort1+CommandPort);
+ 		mdelay(100);
+     	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+     	GetBaseStatus(IOPort1, statusByte);
+ 		for(i=0;i<3;i++)
+ 		{
+ 			mdelay(100);
+ 			outb(0x04, IOPort1 + 0x0E);
+ 			mdelay(100);
+ 			outb(0x00, IOPort1 + 0x0E);
+     		GetBaseStatus(IOPort1, statusByte);
+ 			if(statusByte == 0x50)
+ 				break;
+ 		}
+ 		if(i >= 3)
+ 			return 0;
+ 	}
+ 			
+ 	
+     statusByte = statusByte & 0xc9;
+ 
+ //    printk("Identify: After Masking with 0xC9! Status == %x\n",
+ //	   statusByte);
+ 
+     if (statusByte != IDE_STATUS_DRDY)
+ 	{
+ //	    printk(" ---- Identify: DRDY is NOT asserted!\n");
+ //	    printk(" ---- Identify: return FALSE.\n");
+ //		printk("IdentifyDisk Fail bd=%d,ch=%d, drv=%d :\n",BoardID,Channel,DriveSelect);
+ 		return 0;
+ 	}
+ 
+ 
+ label1:
+     for (j = 0; j < 2; j++)
+ 	{
+ 
+ 	    outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 		mdelay(10);
+    		GetBaseStatus(IOPort1, statusByte);
+ 
+ //	    printk("Status3 = %x\n", (UCHAR) statusByte);
+ 
+ 	    WaitOnBusy(IOPort1, statusByte);
+ 	    outb(IDE_COMMAND_IDENTIFY, IOPort1 + CommandPort);
+ 
+ 	    for (i = 0; i < 4; i++)
+ 		{
+ 		    WaitForDrq(IOPort1, statusByte);
+ 		    if (statusByte & IDE_STATUS_DRQ)
+ 			{
+ 			    // Read status to acknowledge any interrupts generated.
+ 			    GetBaseStatus(IOPort1, statusByte);
+ 			    break;
+ 			}
+ 
+ 		    WaitOnBusy(IOPort1, statusByte);
+ 		}		// end of for (i = 0; i < 4; i++)
+ 
+ 	    if (i == 4 && j == 0)
+ 		{
+ //		    printk(" ---- Identify: DRQ never asserted (%x). Error reg (%x)\n",
+ //			 statusByte, inb(IOPort1 + 1));
+ //		    printk(" ---- Identify: return FALSE.\n");
+ 		    return 0;
+ 	    } else
+ 		{
+ 		    break;
+ 		}
+ 	}			// end of for (j = 0; j < 2; j++)
+ 
+ 
+     if (statusByte & IDE_STATUS_ERROR)
+ 	{
+ //	    printk(" ---- Identify: Status %x\n", statusByte);
+ //	    printk(" ---- Identify: return FALSE.\n");
+ 	    return 0;
+ 	}
+ 
+     WaitOnBusy(IOPort1, statusByte);
+ 
+ 
+     if (!(statusByte & IDE_STATUS_DRQ))
+ 	{
+ //	    printk(" ---- Identify: DRQ is NOT asserted!\n");
+ //	    printk(" ---- Identify: return FALSE.\n");
+ 	    return 0;
+ 	}
+ 
+ //	DiskPresent |= (1 << (Channel * 2 + DriveSelect + 4));
+     pIdentifyData = (USHORT *) IdentifyData;
+ 
+     outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+     GetBaseStatus(IOPort1, statusByte);
+ //	printk("S3=%02x ", (UCHAR) statusByte);
+ //	printk("IdentifyDisk bd=%d,ch=%d, drv=%d \n",BoardID,Channel,DriveSelect);
+     for (i = 0; i < 256; i++)
+ 	{
+ 	    pIdentifyData[i] = inw(IOPort1 + DataPort);
+ 	}
+ 	
+ //		printk("\n");
+ 
+ 	for(i=0; i<256; i++)
+ 	{
+ //		printk("%0.4x ",pIdentifyData[i]);
+ 	}
+ //		printk("\n");
+ 
+     {
+ 		char           *p,c;
+ 		p = (char *) &(IdentifyData->VendorUnique1);
+ 	
+ 		for (i = 0; i < 26; i+=2)
+ 	    {
+ 			c = p[i];
+ 			p[i] = p[i+1];
+ 			p[i+1] = c;
+ //			printk("[%02x]<%02x>",(unsigned char)p[i],(unsigned char)p[i+1]);
+ 	    }
+ //		printk("\n");
+ 	
+ 		p = (char *) &(IdentifyData->ModelNumber);
+ 	
+ 		for (i = 0; i < 40; i+=2)
+ 	    {
+ 			c = p[i];
+ 			p[i] = p[i+1];
+ 			p[i+1] = c;
+ //			printk("%c",c);
+ 	    }
+ 	}
+ 	HddConnected[BoardID][Channel][DriveSelect] = 1;
+ 	SetUDMAMode(BoardID,Channel,DriveSelect,IdentifyData);
+ 
+ 	{
+ 		int mm = 0;
+ 
+ 	    for (i = 0; i < 0x1000; i++)
+ 		{
+ 	
+ 		    GetStatus(IOPort1, statusByte);
+ 
+ 		    if ((statusByte & IDE_STATUS_DRQ)
+ 				 || (statusByte & IDE_STATUS_BUSY)
+ 				|| (statusByte & 1) )
+ 			{
+ 			    inw(IOPort1 + DataPort);
+ 		    } else
+ 			    break;
+ 		}			// end of for
+ 	}
+ //	printk("IdentifyDisk Success!\n");
+     return 1;
+ }
+ 
+  char     *ultima_info(struct Scsi_Host *ignore)
+ {
+     static char     buffer[128];
+     char           *pt;
+ 
+ //	printk("[ ultima_info ]\n");
+     strcpy(buffer, "Aralion Ultima ATA100 IDE RAID MultiCard Driver Version");
+     if (strchr(VERSION, ':'))
+ 	{			/* Assume VERSION is an RCS Revision string */
+ 	    strcat(buffer, strchr(VERSION, ':') + 1);
+ 	    pt = strrchr(buffer, '$') - 1;
+ 	    if (!pt)		/* Stripped RCS Revision string? */
+ 		pt = buffer + strlen(buffer) - 1;
+ 	    if (*pt != ' ')
+ 		++pt;
+ 	    *pt = '\0';
+     } else
+ 	{			/* Assume VERSION is a number */
+ 	    strcat(buffer, " " VERSION);
+ 	}
+ 
+     return buffer;
+ }
+ 
+ 
+ 
+ int ultima_ioctl (Scsi_Device *dev, int cmd, void *arg)
+ {
+ 		return 0;
+ }
+ 
+ int init_module(void) {
+     driver_template.module = &__this_module;
+     scsi_register_module(MODULE_SCSI_HA, &driver_template);
+     if (driver_template.present) {
+ 		return 0;
+ 	}
+ 
+     scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+     return -1;
+ }
+ 
+ void cleanup_module( void) {
+     scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ }
+ 				/* First pass at /proc information routine. */
+ 
+ int             ultima_proc_info(char *buffer, char **start, off_t offset,
+ 				 int length, int hostno, int inout)
+ {
+     const char     *info = ultima_info(NULL);
+     int             len;
+     int             pos;
+     int             begin;
+  
+     if (inout)
+ 	return (-ENOSYS);
+ 
+     begin = 0;
+     strcpy(buffer, info);
+     strcat(buffer, "\n");
+ 
+     pos = len = strlen(buffer);
+ 
+     if (pos < offset)
+ 	{
+ 	    len = 0;
+ 	    begin = pos;
+ 	}
+ 
+     *start = buffer + (offset - begin);	/* Start of wanted data */
+     len -= (offset - begin);
+     if (len > length)
+ 	len = length;
+ 
+     return (len);
+ }
+ 
+ static int      aralion_arbitrate(void)
+ {
+     int             status = 0;
+     ULONG   timeout;
+ 
+ 	printk("[ aralion_arbitrate ]\n");
+ 
+ 	return 0;
+ }
+ 
+ static int      aralion_select(int target)
+ {
+     int             status;
+     ULONG   timeout;
+     static int      flag = 0;
+ 
+ 
+ 	printk("[ aralion_select - %d ]\n",target);
+ 	return 0;
+ }
+ 
+ static void            my_done(int error)
+ {
+     if (in_command)
+ 	{
+ 	    in_command = 0;
+ //		printk("{C}");
+ 		if (test_and_clear_bit(IOCTL_LOCK,&LockValue) == 0)
+ 			printk("misc clear...\n");
+ 	    current_SC->result = error;
+ 	    if (current_SC->scsi_done) {
+ 			current_SC->scsi_done(current_SC);
+ 		}
+ 	    else
+ 			panic("scsi: <aralion> current_SC->scsi_done() == NULL");
+     } else
+ 	{
+ 	    panic("scsi: <aralion> my_done() called outside of command\n");
+ 	}
+ }
+ 
+ int	CheckScsiError(ULONG Channel,ULONG IOPort1,UCHAR statusByte)
+ {
+ 	ULONG 	lba;
+ 	UCHAR 	Data[4];
+ 	UCHAR	errorByte;
+ 	ULONG 	scsiStatus = 0;
+ 	
+ 	if (statusByte & 0x1) {
+ 
+         errorByte = inb(IOPort1 + ErrorPort);
+ 
+ 		if (errorByte & IDE_ERROR_BAD_BLOCK)
+ 			scsiStatus = DID_PARITY;
+ 		else if (errorByte & IDE_ERROR_DATA_ERROR)
+ 			scsiStatus = DID_ERROR;
+ 		else if (errorByte & IDE_ERROR_ID_NOT_FOUND)
+ 			scsiStatus = DID_NO_CONNECT;
+ 		else if (errorByte & IDE_ERROR_COMMAND_ABORTED)
+ 			scsiStatus = DID_ABORT;
+ 		else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH )
+ 			scsiStatus = DID_ERROR;
+ 
+ 		Data[3] = inb(IOPort1 + BlockNumberPort);
+ 		Data[2] = inb(IOPort1 + CylinderLowPort);
+ 		Data[1] = inb(IOPort1 + CylinderHighPort);
+ 		Data[0] = inb(IOPort1 + DriveSelectPort) & 0x0f;
+ 
+ 		lba = (Data[0] << 24) + (Data[1] << 16)
+ 				+ (Data[2] << 8) + Data[0];
+ 
+ 		LastErrorBlock = lba;
+ 		LastErrorCode = errorByte & 0x000f;
+ 
+ 		printk("Error! Ch:%d, %02x , %0d\n",Channel,
+ 				(UCHAR) errorByte,lba);
+ 
+ //    	my_done(scsiStatus << 16);
+ 		return scsiStatus;
+ 	}
+ 	else
+ 		return 0;
+ }
+ 
+  void CheckJobFinished(ULONG BoardID,ULONG Channel)
+ {
+ 	ULONG DmaIO;
+ 	USHORT Stat;
+ 	DWORD	i = 0;
+ 
+ //	printk("CheckJobFinished <BoardID,Channel> = <%d,%d>\n",BoardID,Channel);
+ 	
+ 	if (Channel == 1) {
+ 		DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	}
+ 	else 
+ 		DmaIO = BoardInfo[BoardID].SecondaryDmaIO;
+ 	
+ 	do {
+ 		Stat = inw(DmaIO + CONSR);
+ 		i++;
+ 	} while ((Stat & 0x01) && (i < 80000000));
+ //	printk("Check End : %u\n",i);
+ }
+  void ClearAllIrq(void)
+ {
+ 	ULONG	Channel;
+     UCHAR   statusByte = 0;
+     UCHAR   statusByte2 = 0;
+     ULONG   IOPort1,IOPort2;
+ 	ULONG 	scsiStatus = 0;
+ 	int		i;
+ 
+ 	for(i=0;i<gBoardCount;i++) 
+ 	{
+ 		Channel = inw(BoardInfo[i].ControlRegister + INTSRC) & 0x03;
+ //		printk("I:[%d,%x]",i,Channel);
+ 
+ 		if (Channel == 0) 
+ 			continue;
+ 
+ 		statusByte = statusByte2 = 0;
+ 		
+ 		if (Channel != 3 && 
+ 			( (BoardInfo[i].InterruptFlag[0] & OrderStatus) &
+ 			  (BoardInfo[i].InterruptFlag[1] & OrderStatus)
+ 			)
+ 		   )	
+ 			continue;
+ 		if (Channel & 1) 
+ 		{
+ 			IOPort1 = BoardInfo[i].PrimaryIO;
+ 			CheckJobFinished(i,1);
+ 	   		GetBaseStatus(IOPort1, statusByte);
+ 			BoardInfo[i].InterruptFlag[0] &= (~OrderStatus);
+ 		}
+ 		if (Channel & 2) 
+ 		{
+ 			IOPort2 = BoardInfo[i].SecondaryIO;
+ 			CheckJobFinished(i,2);
+ 			GetBaseStatus(IOPort2, statusByte2);
+ 			BoardInfo[i].InterruptFlag[1] &= (~OrderStatus);
+ 		}
+ 	}
+ }
+ 
+  void            do_ultima_intr(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ 	ULONG	Channel;
+     UCHAR   statusByte = 0;
+     UCHAR   statusByte2 = 0;
+     ULONG   IOPort1,IOPort2;
+ 	ULONG 	scsiStatus = 0;
+ 	IrqID	*pIntID;
+ 	int		i,j,flag;
+     int     ClearFlag = 0;
+ 	int		InterruptCount;
+ 	unsigned long flags;
+ 									
+ 	spin_lock_irqsave(&io_request_lock, flags);
+ 	pIntID = (IrqID *) dev_id;
+ 
+ //	printk("< intr >\n");	
+ 
+ 	if (!pIntID) {
+ #ifdef DEBUG		
+ 		printk("It is not ultima_irq1\n");	
+ #endif		
+ 		spin_unlock_irqrestore(&io_request_lock, flags);
+ 		return ;
+ 	}
+ 
+ 	if (gResetFlag) {
+ 		for (i=0;i<gBoardCount;i++) {
+ 			USHORT		Intena;
+ 
+ 			Channel = inw(BoardInfo[i].ControlRegister + INTSRC);
+ 			Intena = inw(BoardInfo[i].ControlRegister + INTENA);
+ 			IOPort1 = BoardInfo[i].PrimaryIO;
+ 			IOPort2 = BoardInfo[i].SecondaryIO;
+ 			if (Channel & 1) {
+ 				CheckJobFinished(i,1);
+ 		   		GetBaseStatus(IOPort1, statusByte);
+ 			}
+ 			if (Channel & 2) {
+ 				CheckJobFinished(i,2);
+ 		   		GetBaseStatus(IOPort2, statusByte2);
+ 			}
+ 			if (statusByte & 0x1) 
+ 				scsiStatus = CheckScsiError(Channel,IOPort1,statusByte);
+ 	   		GetBaseStatus(IOPort1, statusByte);//KHG
+ 
+ 			if (statusByte2 & 0x1)
+ 				scsiStatus = CheckScsiError(Channel,IOPort2,statusByte);
+ 	   		GetBaseStatus(IOPort2, statusByte2);//KHG
+ 		}
+ 		spin_unlock_irqrestore(&io_request_lock, flags);
+ 		return ;
+ 
+ 	}
+ 
+ 	if (!in_command) {
+  		ClearAllIrq();
+ 		spin_unlock_irqrestore(&io_request_lock, flags);
+ 		return ;
+ 	}
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		Channel = inw(BoardInfo[i].ControlRegister + INTSRC) & 0x03;
+ 		if (Channel == 0) 
+ 			continue;
+ 
+ 		flag = 0;
+ 		statusByte = statusByte2 = 0;
+ 		
+ 		if (Channel != 3 && 
+ 			( (BoardInfo[i].InterruptFlag[0] & OrderStatus) &
+ 			  (BoardInfo[i].InterruptFlag[1] & OrderStatus)
+ 			)
+ 		   )	
+ 			continue;
+ 
+ 		if (Channel & 1) {
+ 			IOPort1 = BoardInfo[i].PrimaryIO;
+ 			CheckJobFinished(i,1);
+ 	   		GetBaseStatus(IOPort1, statusByte);
+ 			BoardInfo[i].InterruptFlag[0] &= (~OrderStatus);
+ 		}
+ 		if (Channel & 2) {
+ 			IOPort2 = BoardInfo[i].SecondaryIO;
+ 			CheckJobFinished(i,2);
+ 	   		GetBaseStatus(IOPort2, statusByte2);
+ 			BoardInfo[i].InterruptFlag[1] &= (~OrderStatus);
+ 		}
+ 
+ 		if (statusByte & 0x1) 
+ 			scsiStatus = CheckScsiError(Channel,IOPort1,statusByte);
+ 
+ 		if (statusByte2 & 0x1) 
+ 			scsiStatus = CheckScsiError(Channel,IOPort2,statusByte);
+ 	}
+ 
+ 	if (OrderStatus != ORDER_FOUR) {
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if (BoardInfo[i].InterruptFlag[0] & OrderStatus || BoardInfo[i].InterruptFlag[1] & OrderStatus) {
+ 				spin_unlock_irqrestore(&io_request_lock, flags);
+ 				return ;
+ 			}
+ 		}	
+ 		flag = 0;
+ 		
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_TWO || BoardInfo[i].InterruptFlag[1] & ORDER_TWO) && (OrderStatus == ORDER_ONE)) {
+ 				flag = 1;
+ 			}
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_THREE || BoardInfo[i].InterruptFlag[1] & ORDER_THREE) && (OrderStatus == ORDER_TWO)) {
+ 				flag = 1;
+ 			}
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_FOUR || BoardInfo[i].InterruptFlag[1] & ORDER_FOUR) && (OrderStatus == ORDER_THREE)) {
+ 				flag = 1;
+ 			}
+ 		}	
+ 		
+ 		if (flag) {
+ 			OrderStatus <<= 4;
+ 			if (RWStatus == READ_STATUS) {
+ 				SetIOInformation(CurrentDisk,DMA_READ,OrderStatus);
+ 				SetIDECommand(IDE_COMMAND_READ_DMA,OrderStatus);
+    				SetDMACommand(DMA_READ,OrderStatus);
+ 			}
+ 			else {
+ 				SetIOInformation(CurrentDisk,DMA_WRITE,OrderStatus);
+ 				SetIDECommand(IDE_COMMAND_WRITE_DMA,OrderStatus);
+    				SetDMACommand(DMA_WRITE,OrderStatus);
+ 			}
+ 			spin_unlock_irqrestore(&io_request_lock, flags);
+ 			return ;
+ 		}
+ 		else {
+ 
+ 			my_done(scsiStatus << 16);
+ 			spin_unlock_irqrestore(&io_request_lock, flags);
+ 			return ;
+ 		}
+ 	}
+ 	else {
+ 		for(i=0;i<gBoardCount;i++) {
+ 	
+ 			if (BoardInfo[i].InterruptFlag[0] & ORDER_FOUR || BoardInfo[i].InterruptFlag[1] & ORDER_FOUR) {
+ 				spin_unlock_irqrestore(&io_request_lock, flags);
+ 				return ;
+ 			}
+ 		}	
+ 	}
+ 	my_done(scsiStatus << 16);
+ 	spin_unlock_irqrestore(&io_request_lock, flags);
+ 	
+ 	return;
+ }
+ 
+ void     internal_done(Scsi_Cmnd * SCpnt)
+ {
+     internal_done_errcode = SCpnt->result;
+     ++internal_done_flag;
+ }
+ 
+  int IsSplitter(char c)
+ {
+  	if (c == ' ' || c == '-' || c == '_')
+ 		return 1;
+ 	else if (c >= '0' && c <= '9')
+ 		return 1;
+ 	
+ 	return 0;
+ }
+ 
+ int             ultima_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+ {
+ 	char 			*buf;
+ 	int	 			board,channel,drive;
+ 	ULONG			result;
+ /*
+ 	printk("[c=%x : %s,I=%x],DiskCount = %d\n",
+ 			(UCHAR) SCpnt->cmnd[0],
+ 			GetCmdName((UCHAR) SCpnt->cmnd[0]),
+ 			SCpnt->target,
+ 			DiskCount);
+ */
+ 	if (in_command) {
+ 		printk("[ ultima_queue c=%x : %s,I=%x]\n",
+ 				(UCHAR) SCpnt->cmnd[0],
+ 				GetCmdName((UCHAR) SCpnt->cmnd[0]),
+ 				SCpnt->target);
+ 		panic("Error! in_command == 1\n");
+ 		return ;
+ 	}
+ 
+ 	while(test_and_set_bit(IOCTL_LOCK,&LockValue) != 0) {
+ 		printk("QW ");
+ 		schedule();
+ 		udelay(1);
+ 	}
+ 	while(in_ioctl) {
+ //		printk("in_ioctl = 1\n");
+ 		udelay(1);
+ 	}
+ 	in_command = 1;
+ 	current_SC = SCpnt;
+ 	current_SC->scsi_done = done;
+ 
+ 	current_SC->SCp.Status              = 0;
+ 	current_SC->SCp.Message             = 0;
+ 	current_SC->SCp.have_data_in        = 0;
+ 	current_SC->SCp.sent_command        = 0;
+ 	current_SC->SCp.phase               = in_arbitration;
+ 
+ 	if ( SCpnt->lun > 0) {
+     	my_done(DID_ABORT << 16);
+ 		return 0;
+ 	}
+ 	board = DiskID[current_SC->target].DiskStatus.BoardID;
+ 	channel = DiskID[current_SC->target].DiskStatus.Channel;
+ 	drive = DiskID[current_SC->target].DiskStatus.Drive;
+ 
+ 
+ 	switch(current_SC->cmnd[0]) {
+ 		case TEST_UNIT_READY:
+ 		case REQUEST_SENSE :
+ 					my_done(0);
+ 					return 0;
+ 
+ 		case MODE_SENSE :
+ 					buf = (char *) current_SC->buffer;
+ 					buf[2] = 0x0;
+ 					my_done(0);
+ 					break;
+ 
+ 	   	case INQUIRY :
+ 					if(hotplug_check(current_SC->target) == 0)
+ 					{
+     					my_done(DID_ABORT << 16);
+ 						return 0;
+ 					}
+ 					
+ 					board = DiskID[current_SC->target].DiskStatus.BoardID;
+ 					channel = DiskID[current_SC->target].DiskStatus.Channel;
+ 					drive = DiskID[current_SC->target].DiskStatus.Drive;
+ 					buf = (char *) current_SC->buffer;
+ 					{
+ 						PINQUIRYDATA    inquiryData
+ 							= (PINQUIRYDATA) current_SC->buffer;
+ 						PIDENTIFY_DATA identifyData =
+ 						   	&DiskIdentifyData[board][channel][drive];
+ 						int i;
+ 
+ 						memset(buf,0,current_SC->bufflen);
+ 						
+ 						buf[4] = sizeof(INQUIRYDATA);
+ 
+ 						//
+ 						// Standard IDE interface only supports disks.
+ 						inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+ 						
+ 						//
+ 						// Fill in vendor identification fields.
+ 						{
+ 							unsigned char *p;
+ 							int	i,j;
+ 
+ 							for (i = 0; i < 24; i ++) {  
+ 								inquiryData->VendorId[i] = 0;
+ 							}
+ 							p = (UCHAR *) identifyData->ModelNumber;
+ 							i = 0;
+ 
+ 							while(!IsSplitter(p[i])) {
+ 								inquiryData->VendorId[i] = p[i++];
+ 							}
+ 							inquiryData->VendorId[i] = 0;
+ 
+ 							i++;
+ 							j = 0;
+ 							while (p[i] != ' ' && i < 24) 
+ 								inquiryData->ProductId[j++] = p[i++];
+ 							inquiryData->ProductId[j] = 0;
+ 
+ 						}
+ 						//
+ 						// Initialize unused portion of product id.
+ 						for (i = 0; i < 4; i++) {
+ 							inquiryData->ProductId[12+i] = ' ';
+ 						}
+ 						
+ 						//
+ 						// Move firmware revision from IDENTIFY data to
+ 						// product revision in INQUIRY data.
+ 						for (i = 0; i < 4; i += 2) {
+ 							inquiryData->ProductRevisionLevel[i] =
+ 								((UCHAR *)identifyData->FirmwareRevision)[i+1];
+ 							inquiryData->ProductRevisionLevel[i+1] =
+ 								((UCHAR *)identifyData->FirmwareRevision)[i];
+ 						}
+ 					}
+ //					printk("Inquiry Success!");
+ 					my_done(0);
+ 					break;
+ 		case READ_6 : 
+ 		case READ_10 :
+ 		case WRITE_6 : 	
+ 		case WRITE_10 :
+ 
+ 					{
+ 						ULONG numsectors,lba,i ;
+ 
+ //						SDptr->disconnect = 0;
+ 						if (*current_SC->cmnd == READ_6 || *current_SC->cmnd == WRITE_6) {
+ 							numsectors = (u_long) current_SC->cmnd[4];
+ 							lba = ((u_long) current_SC->cmnd[1] << 16) |
+ 								((u_long) current_SC->cmnd[2] << 8) |
+ 								(u_long) current_SC->cmnd[3];
+ 							lba &= 0x1FFFFF;
+ 						}
+ 						if (*current_SC->cmnd == READ_10 || *current_SC->cmnd == WRITE_10) {
+ 							numsectors = (u_long) current_SC->cmnd[8] |
+ 								((u_long) current_SC->cmnd[7] << 8);
+ 							lba = ((u_long) current_SC->cmnd[2] << 24) |
+ 								((u_long) current_SC->cmnd[3] << 16) |
+ 								((u_long) current_SC->cmnd[4] << 8) |
+ 								(u_long) current_SC->cmnd[5];
+ 						}
+ 
+ 						memset(DiskRWInfo,0,sizeof(DiskRWInfo));
+ 						for(i=0;i<gBoardCount;i++) {
+ 							BoardInfo[i].InterruptFlag[0] = 0;
+ 							BoardInfo[i].InterruptFlag[1] = 0;
+ 						}
+ 						CurrentDisk = current_SC->target;
+ 						
+ 						if (*current_SC->cmnd == READ_6 || *current_SC->cmnd == READ_10) {
+ 
+ //							printk("R:[%03d,%08x]", numsectors,lba);
+ 							ReadDMA(current_SC,lba,numsectors);
+ 						}
+ 						else {
+ //							printk("W:[%03d,%08x]", numsectors,lba);
+ 							WriteDMA(current_SC,lba,numsectors);
+ 						}
+ 					}	
+ //					printk("RW Success!\n");
+ 					break;
+ 
+ 		case READ_CAPACITY :
+ 				{
+ 					ULONG block,size;
+ 				    IDENTIFY_DATA * IdentifyData;
+ 				    
+ 					block = DiskID[current_SC->target].DiskStatus.Size;
+ //					printk("Block Size = %x\n",block);
+ 					buf = (char *) current_SC->buffer;
+ 					size = 512; 
+ 
+ 		            *((ULONG *) buf)  = htonl(block - 1);
+ 		            *((ULONG *) (buf + 4))  = htonl(size);
+ 				}
+ 
+ 				my_done(0);
+ //				printk("Read_Cap Success!\n");
+ 				break;
+ 		default:
+ 				my_done(0);
+ 				break;
+ 
+ 	}
+     return 0;
+ }
+ 
+ 
+ void FillDump(	Scsi_Cmnd * SCpnt)
+ {
+ 	struct scatterlist 	*slp;
+ 	int					i,j;
+ 	ULONG	TempFlag;
+ 
+ 	if (SCpnt->use_sg)
+ 	{
+ 		slp = (struct scatterlist *) SCpnt->request_buffer;
+ 		for(i=0;i<SCpnt->use_sg;i++,slp++) {
+ 			memset(&(slp->address),0,slp->length);
+ 		}
+ 	}
+ 	else 
+ 	{
+ 		memset(&(slp->address),0,SCpnt->request_bufflen);
+ 	}
+ }
+ 
+ int	hotplug_check(int target)
+ {
+ 	int i, j, k;
+ 	UCHAR statusByte;
+ 	ULONG IOPort1;
+ //	printk("targetID=%d, DiskCount=%d\n",target,DiskCount);
+ 	if(target == DiskCount)
+ 	{
+ 		for(i=0;i<gBoardCount;i++)
+ 		{
+ 			for(j=0; j<4; j++)
+ 			{
+ 				if((HddConnected[i][j/2][0] == 0) 
+ 						&& (HddConnected[i][j/2][1] ==0))
+ 				{
+ 					if(j/2)
+ 						IOPort1 = BoardInfo[i].SecondaryIO;
+ 					else
+ 						IOPort1 = BoardInfo[i].PrimaryIO;
+ 					gResetFlag = 1;
+ 					HddConnected[i][j/2][j%2] = 1;
+ 					DisableInterrupt(i);
+ 	 				ultima_1channelreset(i,j/2);
+ 					if(IdentifyDisk(i,j/2,j%2,&DiskIdentifyData[i][j/2][j%2]) == 1)
+ 					{
+ 						DiskID[DiskCount].DiskStatus.BoardID = i;
+ 						DiskID[DiskCount].DiskStatus.Channel = j/2;
+ 						DiskID[DiskCount].DiskStatus.Drive = j%2;
+ 						DiskID[DiskCount].DiskStatus.Size = GetBlockCount(i,j/2,j%2);
+ 						DiskID[DiskCount].RaidStatus = NORMALIDE;
+ 						DiskCount++;
+ 						EnableInterrupt(i);
+ 						mdelay(200);
+ 						gResetFlag = 0;
+ 						return 1;
+ 					}
+ 					EnableInterrupt(i);
+ 					mdelay(200);
+ 					gResetFlag = 0;
+ 				}
+ 			}
+ 		}
+ 		return 0;
+ 	}
+ 	else if(target < DiskCount)
+ 	{
+ 		i = DiskID[target].DiskStatus.BoardID;
+ 		j = DiskID[target].DiskStatus.Channel;
+ 		k = DiskID[target].DiskStatus.Drive;
+ 		if(j == 0)
+ 			IOPort1 = BoardInfo[i].PrimaryIO;
+ 		else
+ 			IOPort1 = BoardInfo[i].SecondaryIO;
+ 		if(HddConnected[i][j][(k+1)%2] == 0) 
+ 		{
+ 			gResetFlag = 1;
+ 			DisableInterrupt(i);
+ 			ultima_1channelreset(i,j);
+ 			if(IdentifyDisk(i,j,k, &DiskIdentifyData[i][j][k]))
+ 			{
+ 				EnableInterrupt(i);
+ 				mdelay(200);
+ 				gResetFlag = 0;
+ 				DiskID[target].DiskStatus.Size = GetBlockCount(i,j,k);
+ 				return 1;
+ 			}
+ 			else
+ 			{
+ 				EnableInterrupt(i);
+ 				mdelay(200);
+ 				gResetFlag = 0;
+ 				return 0;
+ 			}
+ 		}
+ 		else return 1;
+ 	}
+ 	else return 0;
+ }
+ //
+ //
+ //
+ int             ultima_command(Scsi_Cmnd * SCpnt)
+ {
+     ultima_queue(SCpnt, internal_done);
+ 
+     while (!internal_done_flag)
+ 	;
+     internal_done_flag = 0;
+     return internal_done_errcode;
+ }
+ 
+ /* End of code derived from Tommy Thorn's work. */
+ 
+ void            print_info(Scsi_Cmnd * SCpnt)
+ {
+     ULONG    imr;
+     ULONG    irr;
+     ULONG    isr;
+ 
+ //	printk("[ print_info ]\n");
+ 
+     if (!SCpnt || !SCpnt->host)
+ 	{
+ 	    printk("scsi: <aralion> Cannot provide detailed information\n");
+ 	    return;
+ 	}
+ 
+     printk("%s\n", ultima_info(SCpnt->host));
+ 	return ;
+     print_banner(SCpnt->host);
+ 
+     printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+ 	   SCpnt->SCp.phase,
+ 	   SCpnt->target,
+ 	   *(UCHAR *) SCpnt->cmnd,
+ 	   SCpnt->use_sg, SCpnt->request_bufflen);
+     printk("sent_command = %d, have_data_in = %d, timeout = %d\n",
+ 	   SCpnt->SCp.sent_command,
+ 	   SCpnt->SCp.have_data_in, SCpnt->timeout);
+ }
+ 
+  int             ultima_handle(Scsi_Cmnd * SCpnt)
+ {
+ //	printk("<ultima_handle>\n");
+ }
+ 
+  int             ultima_abort(Scsi_Cmnd * SCpnt)
+ {
+     ULONG   flags;
+ 
+ //	printk("ultima_abort ---- \n");
+     if (!in_command)
+ 	{
+ 	    return SCSI_ABORT_NOT_RUNNING;
+     }
+     ultima_cardreset();
+ 
+ //#if DEBUG
+     print_info(SCpnt);
+ //#endif
+ 
+     current_SC->SCp.phase |= aborted;
+ 
+     current_SC->result = DID_ABORT << 16;
+ //    current_SC->result = DID_BUS_BUSY << 16;
+ 
+     /* Aborts are not done well. . . */
+ 	if (in_command)
+ 	    my_done(DID_ABORT << 16);
+ //	    my_done(DID_BUS_BUSY << 16);
+ 
+     return SCSI_ABORT_SUCCESS;
+ }
+ 
+  int             ultima_reset(Scsi_Cmnd * SCpnt, unsigned int ignored)
+ {
+ //	printk("ultima_reset ---- \n");
+ 	ultima_cardreset();
+ 
+ 	return SCSI_RESET_WAKEUP;
+ }
+ 
+ //
+ //		KHG-20020719
+ //
+ 
+ int  ultima_1channelreset(int BoardID, int Channel)
+ {
+ 	int		i;
+ 	UCHAR	statusByte,statusByte2;
+ //	printk("%d board reset\n",BoardID);
+ 	if(Channel == 0)
+ 	{
+ 		outw(0x8000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 		mdelay(20);
+ 		outw(0x4000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 		mdelay(20);
+ 		outw(0x0,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 		mdelay(20);
+ 		outw(0xff8f,BoardInfo[BoardID].ControlRegister + 0x0c);
+ /*
+ 		for (i=0;i<200;i++) 
+ 		{
+ 			mdelay(5);
+ 			outb(0xA0, BoardInfo[BoardID].PrimaryIO + DriveSelectPort);
+    			GetBaseStatus(BoardInfo[BoardID].PrimaryIO, statusByte);
+ 			outb(0xB0, BoardInfo[BoardID].PrimaryIO + DriveSelectPort);
+ 			GetBaseStatus(BoardInfo[BoardID].PrimaryIO, statusByte2);
+ 			if (!(statusByte & 0x80) && !(statusByte2 & 0x80)) 
+ 				break;
+ 		}
+ */
+ 	}
+ 	else
+ 	{
+ 		outw(0x8000,BoardInfo[BoardID].SecondaryDmaIO + 0x0e);
+ 		mdelay(20);
+ 		outw(0x4000,BoardInfo[BoardID].SecondaryDmaIO + 0x0e);
+ 		mdelay(20);
+ 		outw(0x0,BoardInfo[BoardID].SecondaryDmaIO + 0x0e);
+ 		mdelay(20);
+ 		outw(0xff8f,BoardInfo[BoardID].ControlRegister + 0x0e);
+ /*
+ 		for (i=0;i<200;i++) 
+ 		{
+ 			mdelay(5);
+ 			outb(0xA0, BoardInfo[BoardID].SecondaryIO + DriveSelectPort);
+    			GetBaseStatus(BoardInfo[BoardID].SecondaryIO, statusByte);
+ 			outb(0xB0, BoardInfo[BoardID].SecondaryIO + DriveSelectPort);
+ 			GetBaseStatus(BoardInfo[BoardID].SecondaryIO, statusByte2);
+ 			if (!(statusByte & 0x80) && !(statusByte2 & 0x80)) 
+ 				break;
+ 		}
+ */
+ 	}
+ 	for(i=0;i<125;i++)
+ 	{
+ 		mdelay(10);
+ 	}
+ }
+ 
+ int             ultima_1cardreset(int BoardID)
+ {
+ 	int		i,j;
+ 	UCHAR	statusByte,statusByte2;
+ 	UCHAR	statusByte3,statusByte4;
+ 
+ 	mdelay(20);
+ 	outw(0x8000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x4000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x0,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x8000,BoardInfo[BoardID].SecondaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x4000,BoardInfo[BoardID].SecondaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x0,BoardInfo[BoardID].SecondaryDmaIO + 0x0e);
+ 	for(i=0;i<125;i++)
+ 	{
+ 		mdelay(20);
+ 	}
+ }
+ 
+ 
+ int             ultima_cardreset(void)
+ {
+ 	int		i,j,k;
+ 
+ 	RWStatus = RESET_STATUS;
+ //	printk("ultima cardreset\n");
+ 	gResetFlag = 1;
+ 	for(i=0;i<gBoardCount;i++) {
+ 		DisableInterrupt(i);
+ 		ultima_1cardreset(i);
+ 		for(j=0;j<4;j++)
+ 		{
+ 			IdentifyDisk(i,j/2,j%2,&DiskIdentifyData[i][j/2][j%2]); 
+ 		}
+ 		EnableInterrupt(i);
+ 	}
+ 	gResetFlag = 0;
+ 
+     return SCSI_RESET_WAKEUP;
+ }
+ 
+ 
+ int             ultima_biosparam(Scsi_Disk * disk, kdev_t dev,
+ 				 int *info_array)
+ {
+ 	int				size;
+ 	int				target;
+ 
+     if (MAJOR(dev) != SCSI_DISK0_MAJOR)
+ 	{
+ 	    printk("scsi: aralion ultima_biosparam: too many disks");
+ 	    return 0;
+ 	}
+ 
+     target = MINOR(dev) >> 4;
+ //	printk("BiosParam = %d,%d\n",board,channel);
+ 
+     info_array[0] = 16;
+     info_array[1] = 63;
+ 
+ //	size = info_array[0] * info_array[1] * info_array[2];
+ 
+ 	size = DiskID[target].DiskStatus.Size;
+     info_array[2] = size / (info_array[0] * info_array[1]);
+ 	
+ 	if (info_array[2] > 1024) { 
+     	info_array[0] = 0xff;
+ 	    info_array[2] =
+ 		(ULONG) size / (info_array[0] * info_array[1]);
+ 	}
+ 
+ 	return 0;
+ }
+ 
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid100/ultima.h linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/ultima.h
*** linux-2.4.22/drivers/scsi/ultimaraid100/ultima.h	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid100/ultima.h	2003-12-09 11:52:22.000000000 +0900
***************
*** 0 ****
--- 1,248 ----
+ #ifndef _ULTIMA_H
+ #define _ULTIMA_H
+ 
+ #ifndef UCHAR 
+ #define UCHAR 	unsigned char
+ #define USHORT	unsigned short
+ #define	ULONG	unsigned long
+ #define DWORD	unsigned long
+ #define BYTE	unsigned char
+ #define	WORD	unsigned short
+ #endif 
+ 
+ #define		ARALION_VENDOR		0x1538
+ #define		ULTIMA_DEVICE		0x0301
+ 
+ #define		READ_STATUS			0x10000000
+ #define		WRITE_STATUS		0x20000000
+ #define		RESET_STATUS		0x40000000
+ #define 	REBUILD_STATUS		0x80000000
+ #define		MIRRORWRITE_STATUS	0x01000000
+ /*
+ #define 	ORDER_FIRST			0x00000001
+ #define 	ORDER_LAST			0x00000010
+ */
+ 
+ #define 	ORDER_ONE			0x00000001
+ #define 	ORDER_TWO			0x00000010
+ #define 	ORDER_THREE			0x00000100
+ #define 	ORDER_FOUR			0x00001000
+ 
+ 
+ #define DataPort          		0x00
+ #define ErrorPort         		0x01
+ #define BlockCountPort    		0x02
+ #define BlockNumberPort   		0x03
+ #define CylinderLowPort   		0x04
+ #define CylinderHighPort  		0x05
+ #define DriveSelectPort   		0x06 
+ #define CommandPort       		0x07   
+ #define AlternateStatusPort 	0x0E
+ 
+ #define FLASH_ADDRESS			0x02
+ #define FLASH_COMMAND			0x04
+ #define FLASH_STATUS			0x06
+ 
+ #define	SCATTERLISTSIZE			4096
+ 
+ #define	NODISK						0x00000000
+ #define NORMALIDE					0x00000001
+ #define STRIPING_2S					0x00000002
+ #define STRIPING_4S					0x00000003
+ #define MIRRORING					0x00000004
+ #define STRIPMIRRORING_2S			0x00000005
+ #define STRIPMIRRORING_4S			0x00000006
+ #define JBOD						0x00000007
+ //#define STRIPMIRRORING2				
+ 
+ #define NOTAVAILABLE				0x0000ffff
+ #define	ERROR_INVALID_SECTORCOUNT 	0x00000001
+ #define	ERROR_DISK_NOTAVAILABLE		0x00000002
+ #define	ERROR_INVALID_CHANNEL		0x00000003
+ 
+ #define		MAXBOARD				4
+ 
+ #define	NORMALSTATUS				0x00000000
+ #define DISKSWAPPED					0x00000001
+ #define MIRRORDISABLED				0x00000002
+ #define REBUILDING					0x00000010
+ #define	REBUILDED					0x00000020
+ #define	DISKNOTAVAILABLE			0x80000000
+ 
+ extern int        	ultima_detect( Scsi_Host_Template * );
+ extern int        	ultima_release( struct Scsi_Host * tpnt);
+ extern int        	ultima_command( Scsi_Cmnd * );
+ extern int        	ultima_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
+ extern int        	ultima_abort( Scsi_Cmnd * );
+ extern int        	ultima_reset( Scsi_Cmnd *, unsigned int ); 
+ extern int        	ultima_biosparam( Disk *, kdev_t, int * );
+ extern int        	ultima_handle( Scsi_Cmnd * );
+ extern char * 		ultima_info( struct Scsi_Host * );
+ extern int          ultima_cardreset(void);
+ extern int        	ultima_proc_info( char *buffer, char **start, off_t offset,
+ 				   					int length, int hostno, int inout );
+ extern int 			ultima_ioctl(Scsi_Device *dev, int cmd, void *arg);
+ 
+ extern struct proc_dir_entry proc_scsi_aralion;
+ 
+ #define ULTIMA_REVID "Aralion ATA133 IDE Raid Controller driver; Revision: LH1.00BCS"
+ 
+ #define ULTIMA_DMA100 { 										\
+ 			next:		NULL,						\
+ 			module:		NULL,						\
+ 			proc_dir: 	NULL,						\
+ 			proc_name:	"Aralion", \
+ 			proc_info:     		ultima_proc_info,           \
+ 			name: "Ultima RAID 100",						\
+ 			detect:    			ultima_detect,              \
+ 			release: 			ultima_release,				\
+ 			info	:			NULL,	\
+ 			ioctl:				ultima_ioctl,				\
+ 		    command:        	NULL,             \
+ 		    queuecommand:   	ultima_queue,               \
+ 		    abort:          	ultima_abort,               \
+ 			reset:				ultima_reset,				\
+ 			slave_attach:		NULL, \
+ 		    bios_param:     	ultima_biosparam,           \
+ 		    can_queue:      	1, 			 				\
+ 		    this_id:        	15, 			 			\
+ 			present:	0, \
+ 		    sg_tablesize:   	16, 			 			\
+ 			cmd_per_lun: 		0,		/* cmds per lun		      */\
+ 		    use_clustering: 	DISABLE_CLUSTERING, 			\
+     		use_new_eh_code: 	0};						
+ 
+ typedef struct 
+ {
+  char *buffer;
+  unsigned long bufferlen;
+ } IoctlParam;
+ 
+ typedef struct
+ {
+ 	char signature[8];
+ 	unsigned long IOPort1;
+ 	unsigned long irq;
+ } IrqID;
+ 
+ typedef struct {
+ 	DWORD	BoardID;
+ 	DWORD	Channel;
+ 	DWORD	Drive;	
+ 	DWORD	Size;
+ } DISKLIST;
+ 
+ typedef struct {
+ 	DWORD		RaidStatus;
+ 	DWORD		BlockSize;
+ 	DISKLIST	DiskStatus;
+ } _DiskIDTable;
+ 
+ typedef struct _PDT_TABLE {
+ 	ULONG  address;   
+ 	USHORT length;   
+ 	UCHAR  Reserved;
+ 	UCHAR  EndOfChain;
+ } PDT_TABLE, *PPDT_TABLE;
+ 
+ typedef struct
+ {
+ 	PDT_TABLE	ScatterList[128];
+ 	ULONG		ListCount;
+ 	ULONG		NumSectors;
+ 	ULONG		StartLba;
+ 	ULONG		InterruptFlag;
+ } DISKRWINFO;
+ 
+ typedef struct _BOARDTABLE {
+     ULONG 		PrimaryIO;
+     ULONG 		SecondaryIO;
+ 	ULONG 		PrimaryDmaIO;
+ 	ULONG 		SecondaryDmaIO;
+ 	ULONG 		ControlRegister;
+ 	ULONG		FlashMemory;
+ 	ULONG 		interrupt_level;
+ 	
+ 	PPDT_TABLE	PriScatterList;
+ 	PPDT_TABLE	SecScatterList;
+ 
+ 	ULONG		ListCount;
+ 	ULONG		NumSectors;
+ 	ULONG		StartLba;
+ 	ULONG		InterruptFlag[2];
+ } BOARDTABLE,*PBOARDsTABLE;
+ 
+ typedef struct _V6BDISKINFO
+ {
+ 	UCHAR Mode;
+ 	UCHAR PhysicalDrive;
+ 	UCHAR Order;
+ }V6BDISKINFO,*PV6BDISK;
+ 
+ typedef struct _V6InterfaceB
+ {
+ 	ULONG TagField;
+ 	USHORT Version;
+ 	UCHAR Reserved;
+ 	UCHAR StructSize;
+ 	USHORT RebuildBit;
+ 	UCHAR Mode;
+ 	UCHAR IsSafeMode;
+ 	ULONG Reserved1;
+ 	ULONG BaseHddSize[8];
+ 	V6BDISKINFO DiskInfo[4][4];
+ 	UCHAR Reserved2[5];
+ 	UCHAR ProcInfo[4];
+ 	UCHAR Reserved3[151];
+ }V6INTERFACEB,*PV6INTERFACEB;
+ 
+ typedef struct _REBUILDBUFFER
+ {
+ 	UCHAR 	*buffer;
+ 	ULONG 	physicalbuffer;
+ } REBUILDBUFFER;
+ 
+ 
+ #define GetStatus(BaseIoAddress, Status) Status = inb((BaseIoAddress) + AlternateStatusPort);
+ 
+ #define GetBaseStatus(BaseIoAddress, Status) \
+ 	    Status = inb(BaseIoAddress + CommandPort);
+ 
+ #define Delayed_Time(delay) { \
+ 	ULONG j = jiffies + delay * HZ; \
+ 	struct wait_queue *wait = NULL; \
+ 	current->timeout = j; \
+ 	interruptible_sleep_on(&wait); }
+ 
+ #define WaitOnBusy(BaseIoAddress, Status) {ULONG i; \
+ 	for (i=0; i<5; i++) { \
+ 		GetStatus((BaseIoAddress), Status); \
+ 			if (Status & IDE_STATUS_BUSY) { \
+ 				udelay(1); \
+ 				continue; \
+ 			} else { \
+ 				break; \
+ 			} \
+ 	} \
+ }
+ 
+ #define WaitForDrq(BaseIoAddress, Status) \
+ { \
+ 	ULONG i; \
+ 	for (i=0; i<1000; i++) { \
+ 		GetStatus(BaseIoAddress, Status); \
+ 			if (Status & IDE_STATUS_BUSY) { \
+ 				udelay(150); \
+ 			} else if (Status & IDE_STATUS_DRQ) { \
+ 				break; \
+ 			} else { \
+ 				udelay(200); \
+ 			} \
+ 	} \
+ }
+ 
+ #endif
+ 
+ #define SelectFirstChannel(BoardID) outb(0xA0,BoardInfo[BoardID].SecondaryIO+DriveSelectPort);
+ #define SelectSecondChannel(BoardID) outb(0xB0,BoardInfo[BoardID].SecondaryIO+DriveSelectPort);
+ 	
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/Makefile linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/Makefile
*** linux-2.4.22/drivers/scsi/ultimaraid133/Makefile	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/Makefile	2003-12-17 20:09:03.000000000 +0900
***************
*** 0 ****
--- 1,19 ----
+ # File: drivers/ultimaraid133/Makefile
+ # Makefile for the Ultima RAID 133 PCI controllers driver.
+ 
+ list-multi := ultimaraid133.o
+ ultima133-objs := ultima.o
+ obj-$(CONFIG_SCSI_ULTIMARAID133) := ultimaraid133.o
+ 
+ EXTRA_CFLAGS += -I.
+ ifeq ($(CONFIG_SCSI_ULTIMARAID133_OLDDETECT),y)
+ EXTRA_CFLAGS += -DOLDDETECT
+ endif
+ 
+ ultimaraid133.o: $(ultima133-objs)
+ 	$(LD) -r -o $@ $(ultima133-objs)
+ 
+ include $(TOPDIR)/Rules.make
+ 
+ clean:
+ 	rm -f *.o
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/README linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/README
*** linux-2.4.22/drivers/scsi/ultimaraid133/README	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/README	2003-12-09 11:52:22.000000000 +0900
***************
*** 0 ****
--- 1,25 ----
+ Ultima RAID 133 Driver for Linux
+ 
+ Introduction
+ -------------------------
+ Original Driver was supported by Aralion(http://www.aralion.co.kr)
+ 
+ Supported Cards/Chipsets
+ -------------------------
+ 	Ultima RAID 133(ARS0303S)
+ 
+ People
+ -------------------------
+ Aralion Linux Dev. <www.aralion.co.kr>	(Original ATA ONLY Driver source)
+ Ashuaria Lee <ashuaria@intizen.com>	(Patch for Linux Kernel Tree)
+ 
+ Original Driver
+ -------------------------
+ Aralion Linux Development
+ 
+ Mailing List
+ -------------------------
+ mailto:aralion0303-user@lists.kldp.net
+ mailto:aralion0303-news@lists.kldp.net
+ mailto:aralion0303-develop@lists.kldp.net
+ mailto:aralion0303-tester@lists.kldp.net
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/TODO linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/TODO
*** linux-2.4.22/drivers/scsi/ultimaraid133/TODO	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/TODO	2003-12-09 11:52:22.000000000 +0900
***************
*** 0 ****
--- 1,3 ----
+ o	Testing
+ o	More testing
+ o	Many more
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/atapi.h linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/atapi.h
*** linux-2.4.22/drivers/scsi/ultimaraid133/atapi.h	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/atapi.h	2003-12-17 17:18:00.000000000 +0900
***************
*** 0 ****
--- 1,301 ----
+ #ifndef _ATAPI_H
+ #define _ATAPI_H
+ 
+ #ifndef UCHAR 
+ #define UCHAR 	unsigned char
+ #define USHORT	unsigned short
+ #define	ULONG	unsigned long
+ #endif 
+ 
+ #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  
+ 
+ 
+ #define IDE_ERROR_BAD_BLOCK          0x80  // ICRC  :Crc error
+ #define IDE_ERROR_DATA_ERROR         0x40  // UNC   :data error
+ #define IDE_ERROR_MEDIA_CHANGE       0x20   
+ #define IDE_ERROR_ID_NOT_FOUND       0x10  // IDNF  :sector's ID field error
+ #define IDE_ERROR_MEDIA_CHANGE_REQ   0x08   
+ #define IDE_ERROR_COMMAND_ABORTED    0x04  // ABRT  :command error 
+ #define IDE_ERROR_END_OF_MEDIA       0x02  
+ #define IDE_ERROR_ILLEGAL_LENGTH     0x01
+ //
+ // IDE command definitions
+ //
+ #define IDE_COMMAND_ATAPI_RESET           0x08  // Don't use!
+ #define IDE_COMMAND_RECALIBRATE           0x10
+ #define IDE_COMMAND_READ                  0x20  // <---
+ #define IDE_COMMAND_WRITE                 0x30  // <---
+ #define IDE_COMMAND_VERIFY                0x40  // <---
+ #define IDE_COMMAND_SEEK                  0x70
+ #define IDE_COMMAND_SET_DRIVE_PARAMETERS  0x91
+ #define IDE_COMMAND_ATAPI_PACKET          0xA0  // Don't use!
+ #define IDE_COMMAND_ATAPI_IDENTIFY        0xA1  // Don't use!
+ #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  // Feature Set 
+ #define IDE_COMMAND_IDENTIFY              0xEC  // <---
+ #define IDE_COMMAND_MEDIA_EJECT           0xED
+ 
+ 
+ //////////////////////////////////KHG133s_Big//////////////////////////////////////
+ #define IDE_COMMAND_READ_DMA_EXT	  0x25
+ #define IDE_COMMAND_WRITE_DMA_EXT	  0x35
+ #define IDE_COMMAND_READ_SECTORS	  0x20
+ #define IDE_COMMAND_WRITE_SECTORS	  0x30
+ #define IDE_COMMAND_READ_SECTORS_EXT	  0x24
+ #define IDE_COMMAND_WRITE_SECTORS_EXT	  0x34
+ ///////////////////////////////////////////////////////////////////////////////////
+ //
+ //DmaCommand bits definition
+ //
+ #define DMA_READ     0x07
+ #define DMA_WRITE    0x06
+ 
+ //
+ // Mode Register bit definotion
+ //
+ #define MODE_PIO        0x00
+ #define MODE_DMA        0x01
+ #define MODE_UDMA       0x03
+ 
+ //
+ // HDD DMA Mode Support
+ //
+ #define DMA_0           0x01
+ #define DMA_1           0x03
+ #define DMA_2           0x07
+ #define UDMA_0          0x08
+ #define UDMA_1          0x18
+ #define UDMA_2          0x38
+ 
+ //
+ // Multiple sector setting is valid by HBA.
+ //
+ #define MULTIPLE_SET    0x0100
+ 
+ //
+ // Device Extension Device Flags
+ //
+ #define DFLAGS_DEVICE_PRESENT        0x0001    // Indicates that some device is present.
+ #define DFLAGS_DMA_DEVICE            0x0002    // Device is a DMA or UDMA device.
+ #define DFLAGS_PIO_DEVICE            0x0004    // Device is a PIO device.
+ 
+ //
+ // Used to disable 'advanced' features.
+ //
+ #define MAX_ERRORS                     4       // FOR IDE ERROR in MapError()
+ 
+ #ifdef XXX
+ 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[11];                   //     75-126
+ 	USHORT DmaMode[6];
+ 	USHORT Reserved7[33];                   //     75-126
+ 	USHORT SpecialFunctionsEnabled;         //     127
+ 	USHORT Reserved8[128];                  //     128-255
+ } IDENTIFY_DATA, *PIDENTIFY_DATA;
+ #endif
+ 
+ //
+ // 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
+     
+ 	UCHAR  TranslationFieldsValid;          // 6A  53
+     UCHAR  Reserved3;
+ 	/*
+ 	USHORT TranslationFieldsValid:3;        // 6A  53
+     USHORT Reserved3:13;
+     */
+ 
+     USHORT NumberOfCurrentCylinders;        // 6C  54
+     USHORT NumberOfCurrentHeads;            // 6E  55
+     USHORT CurrentSectorsPerTrack;          // 70  56
+     USHORT CurrentSectorCapacity[2];        // 72  57-58
+ 
+ 	/////// Out of spec! //////////// 
+     USHORT CurrentMultiSectorSetting;       //     59
+     USHORT UserAddressableSectors[2];          //     60-61
+ 
+     UCHAR  SingleWordDMASupport;            //     62  Low
+     UCHAR  SingleWordDMAActive;             //         High
+ 	/*
+     USHORT SingleWordDMASupport:8;          //     62  Low
+     USHORT SingleWordDMAActive:8;           //         High
+     */
+ 
+ 	UCHAR  MultiWordDMASupport;             //     63  Low
+     UCHAR  MultiWordDMAActive;              //         High
+ 	/*
+ 	USHORT MultiWordDMASupport:3;           //     63  Low
+     USHORT MultiWordDMAActive:13;           //         High
+     */
+ 
+ 	UCHAR  AdvancedPIOModes;                //     64
+     UCHAR  Reserved4;
+     /*
+ 	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
+ 
+ //////////////////////////////////KHG-133s_Big////////////////////////////////	
+ 	USHORT Reserved6[8];                   //     75-82
+ 	USHORT BIT48;                  		 //     83
+ 	USHORT Reserved6_1[4];                   //     84-87
+ ////////////////////////////////////////////////////////////////////////////// 
+ 	
+ 	UCHAR  UDMASupport;                     //     88
+ 	UCHAR  UDMASelected;                    //
+ 	/*
+ 	USHORT UDMASupport:3;                   //     88
+ 	USHORT UDMASelected:13;                 //
+     */
+ 
+ 	USHORT Reserved7[38];                   //     89-126
+     USHORT SpecialFunctionsEnabled;         //     127
+     USHORT Reserved8[128];                  //     128-255
+ } IDENTIFY_DATA, *PIDENTIFY_DATA;
+ 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
+ #define SEQUENTIAL_ACCESS_DEVICE        0x01    // tapes
+ #define PRINTER_DEVICE                  0x02    // printers
+ #define PROCESSOR_DEVICE                0x03    // scanners, printers, etc
+ #define WRITE_ONCE_READ_MULTIPLE_DEVICE 0x04    // worms
+ #define READ_ONLY_DIRECT_ACCESS_DEVICE  0x05    // cdroms
+ #define SCANNER_DEVICE                  0x06    // scanners
+ #define OPTICAL_DEVICE                  0x07    // optical disks
+ #define MEDIUM_CHANGER                  0x08    // jukebox
+ #define COMMUNICATION_DEVICE            0x09    // network
+ #define LOGICAL_UNIT_NOT_PRESENT_DEVICE 0x7F
+ #define DEVICE_QUALIFIER_NOT_SUPPORTED  0x03
+ 
+ #define PDTLAR						0X00
+ #define PDTHAR						0x02
+ #define CMDR						0x04
+ #define DMAMODE						0x06
+ #define PIO_TIM						0x08
+ #define MDM_TIM						0x0a
+ #define UDM_TIM						0x0c
+ #define CONSR						0x0e
+ 
+ // ControlRegister + Followings
+ #define INTSRC						0x00
+ #define CBL_ID						0x02
+ #define INTENA						0x04
+ #define RAIDSTAT					0x06
+ 
+ #endif
+ 
+ 
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/flash.h linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/flash.h
*** linux-2.4.22/drivers/scsi/ultimaraid133/flash.h	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/flash.h	2003-12-17 19:07:36.000000000 +0900
***************
*** 0 ****
--- 1,68 ----
+ #ifndef __FLASH_H__
+ #define __FLASH_H__
+ 
+ #define   VID	     0x1538
+ #define 	DID133	0x0303
+ #define 	DID100    0x0301
+ 
+ #define    F_DATA	   F_BASE + 0
+ #define    F_ADDR	   F_BASE + 2
+ #define    F_CMDR	   F_BASE + 4
+ #define    F_STAT	   F_BASE + 6
+ 
+ #define    FCMD_RD	   0x86
+ #define    FCMD_WR	   0x87
+ 
+ #define    FST_SIG	   0xAA
+ #define    SND_SIG	   0x55
+ #define    TRD_SIG	   0xA0
+ #define    FTH_SIG	   0xf0
+ 
+ #define    FST_ADR	   0x0555    /*0x5555 */
+ #define    SND_ADR	   0x0AAA    /*0x2aaa */
+ #define    TRD_ADR	   0x0555
+ 
+ #define    SECTORCNT	   512
+ #define    BUFFERCNT	   128
+ 
+ #define    MXMANUFAC	   0xC2
+ #define    MXDEVIC	        0x19      /* 29F001B */
+ #define    MXDEVIC1	        0x18      /* 29F001T */
+ 
+ #define    SMMANUFAC	   0x40
+ #define    SMDEVIC	        0x01      /* F295001T */
+ #define    SMDEVIC1	        0xA1      /* F295001B */  /* must be lock or unlock */
+ 
+ #define    AMICMANUFAC      0x37
+ #define    AMICDEVICE       0xa1
+ //#define    AMICDEVICE      0xa1
+ 
+ #define    MPFMANUFAC       0xbf
+ #define    MPFDEVICE1       0xb6       /*SST39SF020A*/
+ #define    MPFDEVICE        0xb5       /*SST39SF010*/
+ 
+ #define    AMDMANUFAC       0x01
+ #define    AMDDEVICE	   0x20      /* AM29F010B  */
+ 
+ 
+ #define    ATMANUFAC	   0x1F
+ #define    ATDEVIC	        0x5D      /* AT29C512  */
+ #define    ATDEVIC1	   	   0x3D      /* AT29LV512 */
+ #define    ATDEVIC2	 	   0xD5      /* AT29C001  */
+ #define    ATDEVIC3	        0x35      /* AT29LV001 */
+ #define    ATDEVIC4	        0xDC      /* AT29C256  */
+ 
+ #define    WIMANUFAC        0xDA
+ #define    WIDEVIC	        0xc8      /* W29C512   */
+ #define    WIDEVIC1	        0xC1      /* W29C010   */
+ #define    WIDEVIC2	        0x45      /* W29C020   */
+ 
+ //////////////////////////////////////////////////////////////////
+ // ControlRegister Port
+ // inw(BoardInfo[].ControlRegister + XXXX
+ #define RAIDTYPE  0x06
+ #define CARDCOUNT 0X08
+ //////////////////////////////////////////////////////////////////
+ 
+ #endif
+ 
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/iocontrol.h linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/iocontrol.h
*** linux-2.4.22/drivers/scsi/ultimaraid133/iocontrol.h	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/iocontrol.h	2003-12-09 11:52:22.000000000 +0900
***************
*** 0 ****
--- 1,146 ----
+ ///////////////////////// Ioctl start
+ /*	IoControl.h	*/
+ /* 
+ 	This header is defined for RAID monitor Util and 
+ 	should be shared with the App's header. 
+ */
+ 
+ // REQUESTs to ULTIMA from GUI.
+ #define IOCTL_ULTIMA_PRESENT	0x80018001 // ~ ~ ~ ~ 1000 0000 0000 0001
+ #define IOCTL_GET_ULTIMA_STATUS	0x80018002 // ~ ~ ~ ~ 1000 0000 0000 0010
+ #define IOCTL_EXECUTIVE_COMMAND	0x80018004 // ~ ~ ~ ~ 1000 0000 0000 0100
+ #define IOCTL_GET_HDD_FLAGS		0x80018008 // ~ ~ ~ ~ 1000 0000 0000 1000
+ #define IOCTL_ULTIMA_RESET		0x80018010 // ~ ~ ~ ~ 1000 0000 0001 0000
+ #define IOCTL_GET_ERROR_STATUS	0x80018020 // ~ ~ ~ ~ 1000 0000 0010 0000
+ #define IOCTL_UPDATE_IDENTIFY	0x80018040 // ~ ~ ~ ~ 1000 0000 0010 0000 ~~ 2000/06/20
+ #define IOCTL_ULTIMA_REBUILD_COMPLETE	0x80018080 // ~~2000/08/02
+ #define	IOCTL_ULTIMA_REBUILD_CANCEL     0x80018100 // ~~2000/08/11
+ #define	IOCTL_ULTIMA_MOVE_DATA     0x80018101 // ~~2000/08/11
+ #define	IOCTL_FLASH_READ		0x80018200 // ~~2000/08/11
+ #define	IOCTL_FLASH_WRITE		0x80018400 // ~~2000/08/11
+ #define IOCTL_TEST_EVENT        0x80018800
+ 
+ 
+ typedef struct _SRB_IO_CONTROL {
+         ULONG HeaderLength; 
+         UCHAR Signature[8];
+         ULONG Timeout;
+         ULONG ControlCode;
+         ULONG ReturnCode;
+         ULONG Length;
+ } SRB_IO_CONTROL, *PSRB_IO_CONTROL;
+ 
+ typedef struct _SRB_BUFFER {
+     SRB_IO_CONTROL sic;
+     UCHAR          ucDataBuffer[512]; // Extended DATA BUFFER
+ } SRB_BUFFER, *PSRB_BUFFER;
+ 
+ typedef struct _REBUILDSIZE {
+ 	DWORD	DiskID;
+ 	DWORD	Size;	
+ } REBUILDSIZE;
+ 
+ typedef struct _HDD_STATUS {
+ 	
+ 	USHORT NumberOfCylinders;
+ 	USHORT NumberOfHeads;    
+ 	USHORT SectorsPerTrack;  
+ 	USHORT VendorUnique1[3]; 
+ 	USHORT SerialNumber[10]; 
+ 	USHORT FirmwareRevision[4];
+ 	USHORT ModelNumber[20];    
+ //	USHORT UserAddressableSectors[2];
+ 	DWORD  BlockSize; 
+ 	UCHAR  UDMASupport;              
+ 	UCHAR  UDMAPresentMode;
+ 	
+ } HDD_STATUS, *PHDD_STATUS;
+ 
+ typedef struct 	_GUI_INTERFACE_B
+ {
+ 	V6INTERFACEB Interface;
+ 	HDD_STATUS	HddStatus[4][4];
+ 	UCHAR BiosDeviceNum;
+ 	UCHAR BiosManufacNum;
+ } GuiInterface, *PGuiInterface;
+ 
+ 
+ typedef struct 	_GUI_INTERFACE_B2
+ {
+ 	SRB_IO_CONTROL sic;
+ 	V6INTERFACEB Interface;
+ 	HDD_STATUS	HddStatus[4][4];
+ 	UCHAR BiosDeviceNum;
+ 	UCHAR BiosManufacNum;
+ 
+ } GuiInterface2, *PGuiInterface2;
+ 
+ typedef struct _GUI_FLAG
+ {
+ 	UCHAR IsActingHdd[4][2][2];
+ 	UCHAR IsHereHdd[4][2][2];
+ 	UCHAR RemovedHdd[4][2][2];
+ 	UCHAR RebuildHdd[4][2][2];
+ 	UCHAR SourceHdd[4][2][2];
+ 	ULONG DiskID[4][2][2];
+ 	ULONG Order[4][2][2];
+ 	ULONG RunRebuildTime[16];
+ 	ULONG Reserved;
+ } GUI_FLAG,*PGUI_FLAG;
+ 
+ /*
+ UI Interface�� �� ����ü�� �����մϴ�.(1�ʸ��� ����)
+ 
+  UCHAR IsActingHdd[CardNumber][TargerId] : Hdd Read/Write Working status
+  UCHAR IsHereHdd[CardNumber][TargerId] : Hdd ���� ���� �÷���.
+  UCHAR RebuildHdd[CardNumber][TargerId] : Rebuild���ϴ� Hdd
+  UCHAR SourceHdd[CardNumber][TargerId] : Source Hdd
+  ULONG RunRebuildTime; : Rebuild�ؾ��� ������ TRUE����.
+ */
+ 
+ 
+ typedef struct _GUI_FLAG2
+ {
+ 	SRB_IO_CONTROL sic;
+ 	UCHAR IsActingHdd[4][4];
+ 	UCHAR IsHereHdd[4][4];
+ 	UCHAR RebuildHdd[4][4];
+ 	UCHAR SourceHdd[4][4];
+ 	ULONG RunRebuildTime;
+ 	ULONG Reserved;
+ } GUI_FLAG2,*PGUI_FLAG2;
+ 
+ typedef struct _MOVEDATA_
+ {
+ 	DWORD DiskID;
+ 	UCHAR SourceCard;
+ 	UCHAR SourceTargetId;
+ 	UCHAR TargetCard;
+ 	UCHAR TargetTargetId;
+ 	ULONG LbaAddress;
+ 	ULONG Size;
+ }MOVEDATA,*PMOVEDATA;
+ 
+ 
+ //
+ // Define SCSI maximum configuration parameters.
+ //
+ 
+ #define SCSI_MAXIMUM_LOGICAL_UNITS 8
+ #define SCSI_MAXIMUM_TARGETS_PER_BUS 32
+ #define SCSI_MAXIMUM_BUSES 8
+ #define SCSI_MINIMUM_PHYSICAL_BREAKS  16
+ #define SCSI_MAXIMUM_PHYSICAL_BREAKS 255
+ 
+ //
+ // This constant is for backward compatibility.
+ // This use to be the maximum number of targets supported.
+ //
+ 
+ #define SCSI_MAXIMUM_TARGETS 8
+ 
+ // begin_ntminitape
+ 
+ #define MAXIMUM_CDB_SIZE 12
+ 
+ // end_ntminitape
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/makei linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/makei
*** linux-2.4.22/drivers/scsi/ultimaraid133/makei	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/makei	2003-12-19 15:32:17.000000000 +0900
***************
*** 0 ****
--- 1 ----
+ gcc -D__KERNEL__ -I/root/temp/linux-2.4.22-ashuariadevel/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fomit-frame-pointer -pipe -mpreferred-stack-boundary=2 -march=pentium4 -DMODULE -DMODVERSIONS -include /root/temp/linux-2.4.22-ashuariadevel/include/linux/modversions.h -I. -nostdinc -iwithprefix include -DKBUILD_BASENAME=ultima  -E -o ultima.i ultima.c
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/ultima.c linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/ultima.c
*** linux-2.4.22/drivers/scsi/ultimaraid133/ultima.c	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/ultima.c	2004-01-11 02:28:10.000000000 +0900
***************
*** 0 ****
--- 1,2275 ----
+ /*******************************************************************
+ 
+   Aralion Ultima ATA133 IDE Raid Controller
+   Linux Device Driver source, programmed by soonsoo@hitel.net
+   Modified by Ashuaria Lee (ashuaria@intizen.com)
+ 
+  *******************************************************************/
+ //#define  __BOOT_KERNEL_BOOT	1
+ 
+ //#define	DEBUG1	1
+ //#define	DEBUG2	1
+ //#define	DEBUG3	1
+ //#define	DEBUG4	1
+ 
+ #include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/stddef.h>
+ #include <linux/string.h>
+ #include <linux/sched.h>
+ #include <linux/kernel.h>
+ #include <linux/ioport.h>
+ #include <linux/delay.h>
+ #include <linux/proc_fs.h>
+ #include <linux/spinlock.h>
+ #include <asm/io.h>
+ #include <asm/bitops.h>
+ #include <asm/system.h>
+ #include <asm/dma.h>
+ #include <linux/blk.h>
+ #include "../scsi.h"
+ #include "../hosts.h"
+ #include "../sd.h"
+ #include "ultima.h"
+ #include "atapi.h"
+ #include <linux/errno.h>
+ #include <linux/pci.h>
+ #include <linux/stat.h>
+ #include <linux/config.h>	/* for CONFIG_PCI */
+ #include <linux/fs.h>
+ #include <asm/segment.h> /* for put_user_byte */
+ #include <asm/uaccess.h>
+ #include <asm/atomic.h>
+ #include "iocontrol.h"
+ #include "flash.h"
+ 
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ #define KERNEL240
+ #else
+ #define KERNEL220
+ #endif
+ 
+ // S_BOARD(targetid, volumemember) selects the RAID card from SCSI Target ID
+ #define S_BOARD(x,y) (LDiskID[DiskID[x].LogicalDisk].PhysicalDisk[y].BoardID)
+ // S_BOARD(targetid, volumemember) selects the Channel from SCSI Target ID
+ #define S_CHAN(x,y) (LDiskID[DiskID[x].LogicalDisk].PhysicalDisk[y].Channel)
+ // S_BOARD(targetid, volumemember) selects the Master/Slave from SCSI Target ID
+ #define S_DRV(x,y) (LDiskID[DiskID[x].LogicalDisk].PhysicalDisk[y].Drive)
+ // S_BOARD(targetid, volumemember) selects the DiskList itself
+ #define S_DISKLIST(x,y) (LDiskID[DiskID[x].LogicalDisk].PhysicalDisk[y])
+ #define RAID(x) (DiskID[x].RaidStatus)
+ #define DEG	printk("<1> "__FUNCTION__": %d\n",__LINE__)
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+ static void	print_banner(struct Scsi_Host *shpnt);
+ char *		GetCmdName(char code);
+ // static void	print_banner(struct Scsi_Host *shpnt);
+ static void	do_pause(ULONG amount);
+ static int	aralion_pci_bios_detect(int *irq);
+ ULONG		GetBlockCount(int BoardID,int channel,int drive);
+ int		RequestAllIrq(void);
+ // New code from dual driver. by ashuaria 2003/12/17
+ UCHAR 		FlashRead(USHORT Address);
+ void		FlashWrite(USHORT Address,USHORT Data);
+ void		FlashReset (void);
+ void		GetChipIDInit(void);
+ int		GetFlashRomData(void);
+ // Addition end.
+ void 		PutLBAvalue(ULONG IOPort1,
+ 			    ULONG lba,
+ 			    ULONG numsectors,
+ 			    ULONG DriveSelect);
+ void		DisableInterrupt(int BoardID);
+ void		EnableInterrupt(int BoardID);
+ ULONG		SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status);
+ ULONG 		SetScatterList(Scsi_Cmnd *SCpnt,
+ 			    ULONG lba,
+ 			    ULONG numsectors,
+ 			    ULONG ReadWrite);
+ void 		SetIOPort(DISKLIST *pList,USHORT DmaRW,DWORD OrderFlag);
+ void 		SetIOInformation(int tid,USHORT DmaRW,DWORD OrderFlag);
+ ULONG 		PutOneScatterList(ULONG	CurrentID,
+ 			    DWORD PrimaryDiskArrayCount,
+ 			    DISKLIST *PrimaryDiskArray,
+ 			    ULONG lba,
+ 			    ULONG buffer,
+ 			    USHORT length);
+ void		SetIDECommand(DWORD Command, DWORD order);
+ DWORD		BigDiskCommand (DWORD cmnd);
+ void		SetDMACommand(USHORT DmaRW,DWORD OrderFlag);
+ static int	ReadDMA(Scsi_Cmnd * SCpnt,
+ 			    ULONG lba,
+ 			    ULONG numsectors);
+ static int	WriteDMA(Scsi_Cmnd * SCpnt,
+ 			    ULONG lba,
+ 			    ULONG numsectors);
+ void		GetUDMAMode(USHORT *mode,
+ 			    USHORT *Timing,
+ 			    IDENTIFY_DATA * IdentifyData);
+ void		SetUDMAMode(int BoardID, int Channel, int Drive);
+ static int	IdentifyDisk(int BoardID,
+ 			    int Channel, 
+ 			    int DriveSelect, 
+ 			    IDENTIFY_DATA * IdentifyData);
+ static void	my_done(int error);
+ int		CheckScsiError(ULONG Channel,ULONG IOPort1,UCHAR statusByte);
+ void		CheckJobFinished(ULONG BoardID,ULONG Channel);
+ int 		IsSplitter(char c);
+ int            	ultima_1cardreset(int BoardID);
+ int            	ultima_cardreset(void);
+ void 		do_ultima_intr(int irq, void *dev_id, struct pt_regs *regs);
+ void		internal_done(Scsi_Cmnd * SCpnt);
+ void          	print_info(Scsi_Cmnd * SCpnt);
+ void		printFlashMemory(int BoardID);
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+ struct proc_dir_entry proc_scsi_aralion = {
+ 	0x10, 7, "aralion",
+ 	S_IFDIR | S_IRUGO | S_IXUGO, 2
+ };
+ 
+ Scsi_Host_Template driver_template = ULTIMA_DMA133;
+ 
+ #define VERSION          "$Revision: LH 1.11BCS $"
+ 
+ enum {
+ 	in_arbitration = 0x02,
+ 	in_selection = 0x04,
+ 	in_other = 0x08,
+ 	disconnect = 0x10,
+ 	aborted = 0x20,
+ 	sent_ident = 0x40,
+ };
+ 
+ typedef struct {
+ 	char name[23];
+ 	char code;
+ } CMDNAME;
+ 
+ CMDNAME CmdName[] =
+ {
+ 	{"TEST_UNIT_READY",0x00},
+ 	{"REZERO_UNIT",0x01},
+ 	{"REQUEST_SENSE",0x03},
+ 	{"FORMAT_UNIT",0x04},
+ 	{"READ_BLOCK_LIMITS",0x05},
+ 	{"REASSIGN_BLOCKS",0x07},
+ 	{"READ_6",0x08},
+ 	{"WRITE_6",0x0a},
+ 	{"SEEK_6",0x0b},
+ 	{"READ_REVERSE",0x0f},
+ 	{"WRITE_FILEMARKS",0x10},
+ 	{"SPACE",0x11},
+ 	{"INQUIRY",0x12},
+ 	{"RECOVER_BUFFERED_DATA",0x14},
+ 	{"MODE_SELECT",0x15},
+ 	{"RESERVE",0x16},
+ 	{"RELEASE",0x17},
+ 	{"COPY",0x18},
+ 	{"ERASE",0x19},
+ 	{"MODE_SENSE",0x1a},
+ 	{"START_STOP",0x1b},
+ 	{"RECEIVE_DIAGNOSTIC",0x1c},
+ 	{"SEND_DIAGNOSTIC",0x1d},
+ 	{"ALLOW_MEDIUM_REMOVAL",0x1e},
+ 	{"SET_WINDOW",0x24},
+ 	{"READ_CAPACITY",0x25},
+ 	{"READ_10",0x28},
+ 	{"WRITE_10",0x2a},
+ 	{"SEEK_10",0x2b},
+ 	{"WRITE_VERIFY",0x2e},
+ 	{"VERIFY",0x2f},
+ 	{"SEARCH_HIGH",0x30},
+ 	{"SEARCH_EQUAL",0x31},
+ 	{"SEARCH_LOW",0x32},
+ 	{"SET_LIMITS",0x33},
+ 	{"PRE_FETCH",0x34},
+ 	{"READ_POSITION",0x34},
+ 	{"SYNCHRONIZE_CACHE",0x35},
+ 	{"LOCK_UNLOCK_CACHE",0x36},
+ 	{"READ_DEFECT_DATA",0x37},
+ 	{"MEDIUM_SCAN",0x38},
+ 	{"COMPARE",0x39},
+ 	{"COPY_VERIFY",0x3a},
+ 	{"WRITE_BUFFER",0x3b},
+ 	{"READ_BUFFER",0x3c},
+ 	{"UPDATE_BLOCK",0x3d},
+ 	{"READ_LONG",0x3e},
+ 	{"WRITE_LONG",0x3f},
+ 	{"CHANGE_DEFINITION",0x40},
+ 	{"WRITE_SAME",0x41},
+ 	{"READ_TOC",0x43},
+ 	{"LOG_SELECT",0x4c},
+ 	{"LOG_SENSE",0x4d},
+ 	{"MODE_SELECT_10",0x55},
+ 	{"RESERVE_10",0x56},
+ 	{"RELEASE_10",0x57},
+ 	{"MODE_SENSE_10",0x5a},
+ 	{"PERSISTENT_RESERVE_IN",0x5e},
+ 	{"PERSISTENT_RESERVE_OUT",0x5f},
+ 	{"MOVE_MEDIUM",0xa5},
+ 	{"READ_12",0xa8},
+ 	{"WRITE_12",0xaa},
+ 	{"WRITE_VERIFY_12",0xae},
+ 	{"SEARCH_HIGH_12",0xb0},
+ 	{"SEARCH_EQUAL_12",0xb1},
+ 	{"SEARCH_LOW_12",0xb2},
+ 	{"READ_ELEMENT_STATUS",0xb8},
+ 	{"SEND_VOLUME_TAG",0xb6},
+ 	{"WRITE_LONG_2",0xea}
+ };
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ static volatile int 		internal_done_flag = 0;
+ static volatile int 		internal_done_errcode = 0;
+ static Scsi_Cmnd 		*current_SC = NULL;
+ static int      		this_id = 31;
+ V6INTERFACEB 			V6;
+ // Physical disk table
+ static _DiskIDTable		DiskID[MAXDISK];
+ // Logical disk table
+ LDISKLIST			LDiskID[MAXLDISK];
+ static DISKRWINFO		DiskRWInfo[MAXBOARD][2][2];
+ static IDENTIFY_DATA 		DiskIdentifyData[MAXBOARD][2][2];
+ static int			gBoardCount = 0;
+ IrqID				ultimaID[MAXBOARD];
+ BOARDTABLE			BoardInfo[MAXBOARD];
+ static int			IrqFlag[32] = {0,};
+ static int			DiskCount = 0;
+ ULONG				LastErrorBlock,LastErrorCode;
+ static ULONG			RWStatus;
+ static ULONG			OrderStatus;
+ static ULONG			CurrentDisk;
+ static int      		interrupt_level = 0;
+ static int			HddConnected[MAXBOARD][2][2];
+ static int			HddSupportMode[MAXBOARD][2][2];
+ 
+ /////////////////////////////////////////////////
+ #define IOCTL_LOCK	1
+ static int 			in_ioctl = 0;
+ static int 			in_command = 0;
+ unsigned long 			LockValue = 0;
+ static DECLARE_WAIT_QUEUE_HEAD (WaitingQ);
+ 
+ /////////////////////////////////////////////////
+ UCHAR 				BiosManufacture = 0;
+ UCHAR				cDeviceCode = 0;
+ UCHAR   			cFlashFlag = 0;
+ UCHAR				*Buffer;
+ 
+ char *GetCmdName(char code)
+ {
+ 	int i;
+ 	int count;
+ 	char *s = "unknown function";
+ 
+ 	count = sizeof(CmdName) / sizeof(CMDNAME);
+ 
+ 	for(i=0;i<count;i++) {
+ 		if (CmdName[i].code == code)
+ 			return CmdName[i].name;
+ 	}
+ 	return s;
+ }
+ 
+ static void		print_banner(struct Scsi_Host *shpnt)
+ {
+ 	if (!shpnt)
+ 		return;			/* This won't ever happen */
+ 
+ 	printk("using scsi id %d\n", shpnt->this_id);
+ 
+ 	if (interrupt_level)
+ 		printk(" int %d", interrupt_level);
+ 	else
+ 		printk("<none>");
+ 
+ 	printk("\n");
+ }
+ 
+ static void		aralion_setup(char *str, int *ints)
+ {
+ 	this_id = 31;
+ }
+ 
+ 
+ /* Pause for amount*10 milliseconds */
+ static void		do_pause(ULONG amount)
+ {
+ 	do
+ 	{
+ 		udelay(10 * 1000);
+ 	}
+ 	while (--amount);
+ }
+ 
+ inline static void aralion_make_bus_idle(void)
+ {
+ }
+ 
+ static int      aralion_is_valid_port(int port)
+ {
+ 	return 0;
+ }
+ 
+ static int      aralion_test_loopback(void)
+ {
+ 	return 0;
+ }
+ 
+ static int      aralion_pci_bios_detect(int *irq)
+ {
+ 	struct pci_dev *pdev = NULL;
+ 
+ 	if (!pci_present())
+ 		return 0;
+ 
+ 	memset(BoardInfo,0,sizeof(BoardInfo));
+ 
+ 	do {
+ 		if ((pdev = pci_find_device(ARALION_VENDOR, ULTIMA_DEVICE, pdev)) != NULL) {
+ 			printk("Find %d device\n",gBoardCount);
+ 			//			BoardInfo[gBoardCount].BoardExist = 1;
+ 
+ #ifdef KERNEL240
+ 			BoardInfo[gBoardCount].PrimaryIO 
+ 				= (ULONG) pci_resource_start(pdev,0);
+ 			printk("[%d] Primary IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].PrimaryIO);
+ 			BoardInfo[gBoardCount].SecondaryIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x10; 
+ 			printk("[%d] Secondary IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].SecondaryIO);
+ 			BoardInfo[gBoardCount].PrimaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x20; 
+ 			printk("[%d] Primary DMA IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].PrimaryDmaIO);
+ 			BoardInfo[gBoardCount].SecondaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x30; 
+ 			printk("[%d] Secondary DMA IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].SecondaryDmaIO);
+ 			BoardInfo[gBoardCount].ControlRegister 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x40; 
+ 			printk("[%d] Control Register=%ld\n",gBoardCount,BoardInfo[gBoardCount].ControlRegister);
+ 			BoardInfo[gBoardCount].FlashMemory
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x50; 
+ 			printk("[%d] Flash Memory=%ld\n",gBoardCount,BoardInfo[gBoardCount].FlashMemory);
+ #else
+ 			BoardInfo[gBoardCount].PrimaryIO 
+ 				= (ULONG) pdev->base_address[0] & PCI_BASE_SDDRESS_IO_MASK;
+ 			BoardInfo[gBoardCount].SecondaryIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x10; 
+ 			BoardInfo[gBoardCount].PrimaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x20; 
+ 			BoardInfo[gBoardCount].SecondaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x30; 
+ 			BoardInfo[gBoardCount].ControlRegister 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x40; 
+ 			BoardInfo[gBoardCount].FlashMemory
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x50; 
+ #endif
+ 
+ 			BoardInfo[gBoardCount].interrupt_level = pdev->irq;
+ 			printk("[%d] Interrupt level=%ld\n",gBoardCount,BoardInfo[gBoardCount].interrupt_level);
+ 
+ 			request_region(BoardInfo[gBoardCount].PrimaryIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].SecondaryIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].PrimaryDmaIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].SecondaryDmaIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].ControlRegister, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].FlashMemory,0x8, "aralion");
+ 
+ 			if (!gBoardCount)
+ 				*irq = pdev->irq;
+ 
+ 			gBoardCount++;
+ 		}
+ 	} while(pdev != NULL);
+ 
+ 
+ 	if (!gBoardCount) {
+ 		printk("Ultima Board not found\n");
+ 		return 0;
+ 	}
+ 
+ 	interrupt_level = BoardInfo[0].interrupt_level;
+ 	return 1;
+ }
+ 
+ ULONG	GetBlockCount(int BoardID,int channel,int drive)
+ {
+ 	int i;
+ 	ULONG nCount;
+ 	UCHAR *p;
+ 	p = (char *) &(DiskIdentifyData[BoardID][channel][drive]);
+ 	if(DiskIdentifyData[BoardID][channel][drive].BIT48 & 0x0400)
+ 		nCount = *((ULONG *) (p + 200));
+ 	else
+ 		nCount = *((ULONG *) (p + 120));
+ 	return nCount;
+ }
+ 
+ int	RequestAllIrq(void) 
+ {
+ 	int			i;
+ 	int			irq;
+ 	int			retcode;
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		irq = BoardInfo[i].interrupt_level;
+ 
+ 		if (!IrqFlag[irq]) {
+ 			IrqFlag[irq] = 1;
+ 			memset(ultimaID[i].signature,0,8);
+ 			memcpy(ultimaID[i].signature,"Ultima",6);
+ 			ultimaID[i].IOPort1 = BoardInfo[i].PrimaryDmaIO;
+ 			ultimaID[i].irq = irq;
+ 
+ 			retcode = request_irq(irq,
+ 					do_ultima_intr, 
+ 					SA_INTERRUPT | SA_SHIRQ, 
+ 					"aralion", 
+ 					&ultimaID[i]);
+ 			if (retcode < 0)
+ 			{
+ 				printk("%d's Board IRQ Failure\n",i);
+ 
+ 				if (retcode == -EINVAL)	{
+ 					printk("scsi: <aralion> IRQ %d is bad!\n", irq);
+ 					printk("                This shouldn't happen!\n");
+ 					printk("                Send mail to faith@acm.org\n");
+ 				}
+ 				else if (retcode == -EBUSY) {
+ 					printk("scsi: <aralion> IRQ %d is already in use!\n",irq);
+ 					printk("                Please use another IRQ!\n");
+ 				}
+ 				else {
+ 					printk("scsi: <aralion> Error getting IRQ %d\n",irq);
+ 					printk("                This shouldn't happen!\n");
+ 					printk("                Send mail to faith@acm.org\n");
+ 				}
+ 				printk("scsi: <aralion> Detected, but driver not loaded (IRQ)\n");
+ 
+ 				return retcode;
+ 			}
+ 		}
+ 	}
+ 	return 0;
+ }
+ 
+ // Flash Read . Get data of address
+ UCHAR		FlashRead(USHORT Address)
+ {
+ 	USHORT Data;
+ 	UCHAR Data2,i,Status;
+ 
+ 	for(i = 0; i< 10000;i++)
+ 	{
+ 		Status = inw(BoardInfo[0].FlashMemory + FLASH_STATUS);
+ 		if(!(Status & 0x1))
+ 			break; 
+ 	}
+ 
+ 	outw(Address,BoardInfo[0].FlashMemory + FLASH_ADDRESS);
+ 	outw(0xF6F6,BoardInfo[0].FlashMemory + FLASH_COMMAND);
+ 
+ 	for(i = 0; i< 10000;i++)
+ 	{
+ 		Status = inw(BoardInfo[0].FlashMemory + FLASH_STATUS);
+ 		if(!(Status & 0x1))
+ 			break;
+ 	}
+ 	Data = inw(BoardInfo[0].FlashMemory);
+ 	Data2 = Data & 0xff;
+ 	return Data2;
+ }
+ 
+ void		FlashWrite(USHORT Address,USHORT Data)
+ {
+ 	UCHAR i,Status;
+ 	for(i = 0; i< 10000;i++)
+ 	{
+ 		Status = inw(BoardInfo[0].FlashMemory + FLASH_STATUS);
+ 		if(!(Status & 0x1))
+ 			break;
+ 	}
+ 	outw(Data,BoardInfo[0].FlashMemory);
+ 	outw(Address,BoardInfo[0].FlashMemory + FLASH_ADDRESS);
+ 	outw(0xF7F7,BoardInfo[0].FlashMemory + FLASH_COMMAND);
+ 	for(i = 0; i< 10000;i++)
+ 	{
+ 		Status = inw(BoardInfo[0].FlashMemory + FLASH_STATUS);
+ 		if(!(Status & 0x1))
+ 			break;
+ 	}
+ }
+ 
+ void		FlashReset (void)
+ {
+ 	FlashWrite(0x5555,0xAA);
+ 	FlashWrite(0x2AAA,0x55);
+ 	FlashWrite(0x5555,0xF0);
+ }
+ 
+ 
+ void		GetChipIDInit(void)
+ {
+ 	FlashWrite(0x5555,0xAA);
+ 	FlashWrite(0x2AAA,0x55);
+ 	FlashWrite(0x5555,0x90);
+ 
+ 	BiosManufacture = FlashRead(0x0000);   /* read manufacture code */
+ 	cDeviceCode = FlashRead(0x0001);     /* read device code */
+ 
+ 	mdelay(40);
+ 
+ 	FlashReset();	 /* for Nomal operaton */
+ 	mdelay(40);
+ }
+ 
+ int GetFlashRomData(void)
+ {
+ 	USHORT FlashAddress;
+ 	UCHAR RomPosition;
+ 	UCHAR CardCount;
+ 	USHORT PageSize;
+ 	int		i, BoardID, Channel, Drive, DiskPosition;
+ 	char	CheckSum = 0;
+ 	ULONG	Lba;
+ 
+ 	memset(&V6,0,sizeof(V6INTERFACEB));
+ 
+ 	FlashAddress = inw(BoardInfo[0].ControlRegister + RAIDTYPE); // offset +6
+ 
+ 	CardCount = inb(BoardInfo[0].ControlRegister + CARDCOUNT);   //offset +8
+ 	CardCount = CardCount & 0x3;
+ 
+ 	RomPosition = (UCHAR) (FlashAddress & 0xF);
+ 	FlashAddress = FlashAddress & 0xFFF0;
+ 
+ 	PageSize = FlashRead((USHORT)(FlashAddress+7));
+ 
+ 	//	printk("PageSize = %u,%u\n",PageSize,sizeof(V6));
+ 
+ 	for(i=0;i<PageSize;i++)
+ 	{
+ 		UCHAR *pData = (UCHAR *)&V6 + i;
+ 		*pData = FlashRead((USHORT)(FlashAddress+i));
+ 		CheckSum += *pData;
+ 		//		printk("%02x ",*pData);
+ 	}
+ 
+ 	//	printk("\n");
+ 
+ 	if (memcmp(&V6,"@^^A",4)) {
+ 		printk("incorrect header\n");
+ 		return 0;
+ 	}
+ 	if (CheckSum != 0) {
+ 		printk("incorrect checksum\n");
+ 		return 0;
+ 	}
+ 	return 1;
+ }
+ 
+ int             ultima_detect(Scsi_Host_Template * tpnt)
+ {
+ 	int             retcode;
+ 	struct Scsi_Host *shpnt;
+ 	int             i, j, statusByte;
+ 	int             flag = 0;
+ 	ULONG			IOPort;
+ 
+ 	tpnt->proc_dir = &proc_scsi_aralion;
+ 	flag = aralion_pci_bios_detect(&interrupt_level);
+ 
+ 	if (!flag) {
+ 		printk("scsi: Ultima not found\n");
+ 		return 0;
+ 	}
+ 
+ 	GetChipIDInit();
+ 	memset(&DiskID,0,sizeof(DiskID));
+ 	memset(&LDiskID,0,sizeof(LDiskID));
+ 	memset(&DiskRWInfo,0,sizeof(DiskRWInfo));
+ 	memset(&DiskIdentifyData,0,sizeof(DiskIdentifyData));
+ 	DiskCount = 0;
+ 
+ 	if(!GetFlashRomData())
+ 		return 0;
+ 	// ultima card reset for each board.
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		DisableInterrupt(i);
+ 		ultima_1cardreset(i);
+ 		EnableInterrupt(i);
+ 	}
+ 
+ #ifdef OLDDETECT
+ 	// Get connected HDD information by IOPort
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		IOPort = BoardInfo[i].PrimaryIO;
+ 		
+ 		// Primary
+ 		SelectFirstChannel(i);
+ 		// Primary Master
+ 		outb(0xA0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		// GetBaseStatus is not known yet.
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][0][0] = 1;
+ 		else
+ 			HddConnected[i][0][0] = 0;
+ 			
+ 		// Primary Slave
+ 		outb(0xB0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][0][1] = 1;
+ 		else
+ 			HddConnected[i][0][1] = 0;
+ 		
+ 		// Secondary
+ 		SelectSecondChannel(i);
+ 		// Secondary Master
+ 		outb(0xA0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][1][0] = 1;
+ 		else
+ 			HddConnected[i][1][0] = 0;
+ 		// Secondary Slave
+ 		outb(0xB0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][1][1] = 1;
+ 		else
+ 			HddConnected[i][1][1] = 0;
+ 	}
+ 
+ #else
+ 	// Get connected HDD information by V6 Information.
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		for(j=0;j<4;j++)
+ 		{
+ 			if(V6.DiskInfo[i][j].PhysicalDrive != 0xFF)
+ 			{
+ 				HddConnected[i][j/2][j%2] = 1;
+ 			}
+ 			else
+ 			{
+ 				HddConnected[i][j/2][j%2] = 0;
+ 			}
+ 			HddSupportMode[i][j/2][j%2] = 0xffff;
+ //			CommandCount[i][j/2] = 0;
+ 		}
+ 	}
+ #endif
+ 	// print the connected HDDs
+ 	for(j=0;j<4;j++)
+ 		printk("HDD:[%d]=%d\n",j,HddConnected[0][j/2][j%2]);
+ 
+ 	// Set DiskID[] information, Identify Disk, Set UDMA mode, Set Disksize.
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		DisableInterrupt(i);
+ 		for(j=0;j<4;j++)
+ 		{
+ 			if(HddConnected[i][j/2][j%2])
+ 			{	
+ 				IdentifyDisk(i,j/2,j%2,&DiskIdentifyData[i][j/2][j%2]);
+ 				SetUDMAMode(i,j/2,j%2);
+ 				DiskID[DiskCount].DiskStatus.BoardID = i;
+ 				DiskID[DiskCount].DiskStatus.Channel = j/2;
+ 				DiskID[DiskCount].DiskStatus.Drive = j%2;
+ 				DiskID[DiskCount].RaidStatus = V6.DiskInfo[i][j].Mode;
+ 				DiskID[DiskCount].DiskStatus.Size = GetBlockCount(i,j/2,j%2);
+ 				LDiskID[V6.DiskInfo[i][j].PhysicalDrive].PhysicalDisk[V6.DiskInfo[i][j].Order].BoardID = i;
+ 				LDiskID[V6.DiskInfo[i][j].PhysicalDrive].PhysicalDisk[V6.DiskInfo[i][j].Order].Channel = j/2;
+ 				LDiskID[V6.DiskInfo[i][j].PhysicalDrive].PhysicalDisk[V6.DiskInfo[i][j].Order].Drive = j%2;
+ 				LDiskID[V6.DiskInfo[i][j].PhysicalDrive].PhysicalDisk[V6.DiskInfo[i][j].Order].Size = GetBlockCount(i,j/2,j%2);
+ 				if(V6.DiskInfo[i][j].Order == 0)
+ 				{
+ 				    LDiskID[V6.DiskInfo[i][j].PhysicalDrive].RaidStatus = V6.DiskInfo[i][j].Mode;
+ 				    // Just to make sure that Diskcount and V6.DiskInfo[i][j].PhysicalDrive doesn't match.
+ 				    DiskID[DiskCount].LogicalDisk = V6.DiskInfo[i][j].PhysicalDrive;
+ 				    DiskCount++;
+ 				}
+ 				printk("Logical Disk Info[%d][%d] diskcount[%d] mode=%d physicaldrive=%d Order=%d\n", 
+ 					i, j, DiskCount, 
+ 					LDiskID[V6.DiskInfo[i][j].PhysicalDrive].RaidStatus, 
+ 					DiskID[DiskCount].LogicalDisk, 
+ 					V6.DiskInfo[i][j].Order
+ 					);
+ 			}
+ 		}
+ 		EnableInterrupt(i);
+ 	}
+ 
+ 
+ 	tpnt->this_id = (this_id & 0x1f);
+ 
+ 	/* Print out a banner here in case we can't
+ 	   get resources.  */
+ 	shpnt = scsi_register(tpnt, 0);
+ 	shpnt->irq = interrupt_level;
+ 	shpnt->io_port = BoardInfo[0].ControlRegister;
+ 	shpnt->n_io_port = 0x10;
+ 	// print_banner(shpnt);
+ 
+ 	if (!interrupt_level)
+ 	{
+ 		printk("scsi: <aralion>"
+ 				" Card Detected, but driver not loaded (no IRQ)\n");
+ 		return 0;
+ 	}
+ 	else
+ 	{
+ 		/* Register the IRQ with the kernel */
+ 		if (RequestAllIrq())
+ 			return 0;
+ 	}
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		BoardInfo[i].PriScatterList = kmalloc(SCATTERLISTSIZE,GFP_ATOMIC);
+ 		BoardInfo[i].SecScatterList = kmalloc(SCATTERLISTSIZE,GFP_ATOMIC);
+ 	}			
+ 	return 1;
+ }
+ 
+ 
+ int             ultima_release(struct Scsi_Host * tpnt)
+ {
+ 	int		i;
+ 	int		irq;
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		irq = BoardInfo[i].interrupt_level;
+ 		if (IrqFlag[irq]) {
+ 			free_irq(irq,&ultimaID[i]);
+ 			IrqFlag[irq] = 0;
+ 		}
+ 		release_region(BoardInfo[i].PrimaryIO,0x10);
+ 		release_region(BoardInfo[i].SecondaryIO,0x10);
+ 		release_region(BoardInfo[i].PrimaryDmaIO,0x10);
+ 		release_region(BoardInfo[i].SecondaryDmaIO,0x10);
+ 		release_region(BoardInfo[i].ControlRegister,0x10);
+ 		release_region(BoardInfo[i].FlashMemory,0x8);
+ 
+ 		kfree(BoardInfo[i].PriScatterList);
+ 		kfree(BoardInfo[i].SecScatterList);
+ 	}
+ 	scsi_unregister(tpnt);
+ 
+ 	return 0;
+ }
+ 
+ // #ifdef DEBUG
+ #if 1
+ void printDMARegister(int BoardID)
+ {
+ 	int i;
+ 	USHORT d1;
+ 
+ 	for(i=0;i<0x10;i++) {
+ 		d1 = inw(BoardInfo[BoardID].ControlRegister + i*2);
+ 		printk("<%02x:%04x> ",i,d1);
+ 	}
+ 	printk("\n");
+ }
+ 
+ void printFlashMemory(int BoardID)
+ {
+ 	int i;
+ 	USHORT d1;
+ 
+ 	for(i=0;i<0x08;i++) {
+ 		d1 = inw(BoardInfo[BoardID].FlashMemory + i*2);
+ 		printk("<%02x:%04x> ",i,d1);
+ 	}
+ 	printk("\n");
+ 	for(i=0;i<0x08;i++) {
+ 		d1 = inb(BoardInfo[BoardID].FlashMemory + i);
+ 		printk("<%02x:%04x> ",i,d1);
+ 	}
+ 	printk("\n");
+ }
+ #endif
+ 
+ inline DISKRWINFO *GetRWInfoPointer(DISKLIST *pDiskList)
+ {
+ 	return (DISKRWINFO *) &DiskRWInfo[pDiskList->BoardID][pDiskList->Channel][pDiskList->Drive];
+ }
+ 
+ void PutLBAvalue(ULONG IOPort1,ULONG lba,ULONG numsectors,
+ 		ULONG DriveSelect)
+ {
+ 	UCHAR	Data[4];
+ 	/////////////////////////////KHG-133s_Big////////////////////////////////	
+ 	if(lba >= 0x10000000){
+ 		Data[0] = (lba & 0xff000000 ) >> 24;
+ 		Data[1] = 0;
+ 		Data[2] = 0;
+ 		outb(0,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		Data[0] = (lba & 0x000000ff);
+ 		Data[1] = (lba & 0x0000ff00) >> 8;
+ 		Data[2] = (lba & 0x00ff0000) >> 16;
+ 		Data[3] = (DriveSelect << 4) | 0xe0;
+ 		outb(numsectors,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		outb(Data[3],IOPort1 + DriveSelectPort);
+ 	}
+ 	else{
+ 		Data[0] = (lba & 0x000000ff);
+ 		Data[1] = (lba & 0x0000ff00) >> 8;
+ 		Data[2] = (lba & 0x00ff0000) >> 16;
+ 		Data[3] = (lba & 0x0f000000) >> 24;
+ 		Data[3] = Data[3] | 0x40 | (DriveSelect << 4) | 0xa0;
+ 
+ 		outb(numsectors,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		outb(Data[3],IOPort1 + DriveSelectPort);
+ 	}
+ 	/////////////////////////////////////////////////////////////////////////
+ }
+ 
+ void DisableInterrupt(int BoardID)
+ {
+ 	USHORT		Intena;
+ 
+ 	//	Intena = inw(BoardInfo[BoardID].ControlRegister + INTENA);
+ 	//	Intena = Intena & 0xfe;
+ 	Intena = 0;
+ 
+ 	printk("Disable Interrupt : %d\n",BoardID);
+ 	outw(Intena,BoardInfo[BoardID].ControlRegister + INTENA);
+ }
+ 
+ void EnableInterrupt(int BoardID)
+ {
+ 	USHORT		Intena;
+ 
+ 	//	Intena = inw(BoardInfo[BoardID].ControlRegister + INTENA);
+ 	//	Intena = Intena | 0x01;
+ 	Intena = 0x03;		//KHG
+ 
+ 	printk("Enable Interrupt : %d\n",BoardID);
+ 	outw(Intena,BoardInfo[BoardID].ControlRegister + INTENA);
+ 	//	printk("EI2 : %d\n",BoardID);
+ }
+ 
+ // int SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status)
+ ULONG SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status)
+ {
+ 	////////////////////////////////////KHG-133s////////////////////////////////////
+ 	ULONG	TempStatus;
+ 	Channel = 0;
+ 
+ 	if (BoardInfo[BoardID].InterruptFlag[Channel] & Status) {
+ 		TempStatus = BoardInfo[BoardID].InterruptFlag[Channel] & 0x00001111;
+ 		if(TempStatus & 0x00001100){
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00001000;
+ 			return 0x00001000;
+ 		}
+ 		else if(TempStatus & 0x00000010){
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00000100;
+ 			return 0x00000100;
+ 		}
+ 		else {
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00000010;
+ 			return 0x000000010;
+ 		}
+ 	}
+ 	else {
+ 		BoardInfo[BoardID].InterruptFlag[Channel] = (Status | ORDER_ONE);
+ 		return 0;
+ 	}
+ }
+ 
+ ULONG SetScatterList( Scsi_Cmnd * SCpnt, ULONG lba, ULONG numsectors, ULONG	ReadWrite)
+ {
+ 	struct scatterlist 	*slp;
+ 	int			i,j;
+ 	PPDT_TABLE 		pPDTTable;
+ 	DISKRWINFO		*pRWInfo,*pRWInfo2;
+ 	int			tid = SCpnt->target;
+ 	DWORD			RaidStatus;
+ 	ULONG			TempFlag;
+ 
+ 	// _DiskIDTable { RaidStatus, DISKLIST }
+ 	// this raid status was already set by ultima_detect!!
+ 	RaidStatus = RAID(tid); // Get raid data fron target id
+ 	printk("SetScatterList: RaidStatus = %x\n", RaidStatus);
+ 	
+ 	switch(RaidStatus)
+ 	{
+ #if 1
+ //#if SECERT_IS_SOLVED
+ 	    case MIRRORING:
+ 		// Setting the Two Drives Same.
+ 		for(j = 0; j < 2; j++)
+ 		{
+ 			pRWInfo = (DISKRWINFO *) &DiskRWInfo[S_BOARD(tid,j)][S_CHAN(tid,j)][S_DRV(tid,j)];
+ 			printk("SetScatterList: [%x] S_BOARD[%x] S_CHAN[%x] S_DRV[%x]\n", j, S_BOARD(tid,j), S_CHAN(tid,j), S_DRV(tid,j));
+ 			
+ 			pRWInfo->StartLba = lba;
+ 			pRWInfo->ListCount = 0;
+ 			pRWInfo->NumSectors = 0;
+ 			pPDTTable = pRWInfo->ScatterList;
+ 			if (SCpnt->use_sg) {
+ 				slp = (struct scatterlist *) SCpnt->request_buffer;
+ 				for(i=0;i<SCpnt->use_sg;i++,slp++) {
+ 					pPDTTable[i].address = virt_to_bus(slp->address);
+ 					pPDTTable[i].length = slp->length;
+ 					pPDTTable[i].EndOfChain = 0;
+ 					pRWInfo->NumSectors += slp->length;
+ 				}
+ 				pPDTTable[i - 1].EndOfChain = 0x80;
+ 				pRWInfo->ListCount = SCpnt->use_sg;
+ 			}
+ 			else {
+ 				pPDTTable[0].address = virt_to_bus(SCpnt->request_buffer);
+ 				pPDTTable[0].length = SCpnt->request_bufflen;
+ 				pPDTTable[0].EndOfChain = 0x80;
+ 				pRWInfo->NumSectors = SCpnt->request_bufflen;
+ 				pRWInfo->ListCount = 1;
+ 			}
+ 		
+ 			pRWInfo->NumSectors /= 512;
+ 			
+ 			if(j == 0)
+ 			{
+ 			    pRWInfo->InterruptFlag = ReadWrite | ORDER_ONE;
+ 			}
+ 			else
+ 			{
+ 			    pRWInfo->InterruptFlag = ReadWrite | ORDER_TWO;
+ 			}
+ 			SetBoardInterruptFlag(S_BOARD(tid,j),S_CHAN(tid,j),ReadWrite);
+ 		}
+ 		break;
+ #endif
+ 	    default:
+ 		pRWInfo = (DISKRWINFO *) &DiskRWInfo[S_BOARD(tid,0)][S_CHAN(tid,0)][S_DRV(tid,0)];
+ 		printk("SetScatterList: S_BOARD(%x,0) S_CHAN(%x,0) S_DRV(%x,0)\n", S_BOARD(tid,0), S_CHAN(tid,0), S_DRV(tid,0));
+ 	
+ 		pRWInfo->StartLba = lba;
+ 		pRWInfo->ListCount = 0;
+ 		pRWInfo->NumSectors = 0;
+ 		pPDTTable = pRWInfo->ScatterList;
+ 		if (SCpnt->use_sg) {
+ 			slp = (struct scatterlist *) SCpnt->request_buffer;
+ 			for(i=0;i<SCpnt->use_sg;i++,slp++) {
+ 				pPDTTable[i].address = virt_to_bus(slp->address);
+ 				pPDTTable[i].length = slp->length;
+ 				pPDTTable[i].EndOfChain = 0;
+ 				pRWInfo->NumSectors += slp->length;
+ 			}
+ 			pPDTTable[i - 1].EndOfChain = 0x80;
+ 			pRWInfo->ListCount = SCpnt->use_sg;
+ 		}
+ 		else {
+ 			pPDTTable[0].address = virt_to_bus(SCpnt->request_buffer);
+ 			pPDTTable[0].length = SCpnt->request_bufflen;
+ 			pPDTTable[0].EndOfChain = 0x80;
+ 			pRWInfo->NumSectors = SCpnt->request_bufflen;
+ 			pRWInfo->ListCount = 1;
+ 		}
+ 	
+ 		pRWInfo->NumSectors /= 512;
+ 	
+ 		pRWInfo->InterruptFlag = ReadWrite | ORDER_ONE;
+ 		#warning hard coded to ORDER_ONE!!!
+ 		SetBoardInterruptFlag(S_BOARD(tid,0),S_CHAN(tid,0),ReadWrite);
+ 	}
+ 	printk("SetScatterList Done.\n");
+ 	return j; // return order number.
+ }
+ 
+ void PrintPDT(PPDT_TABLE  pPDTTable,int count)
+ {
+ 	int i;
+ 
+ 	for(i=0;i<count;i++) {
+ 		printk("%04d : [%08x,%04x,%02x]\n",i,
+ 				pPDTTable[i].address,
+ 				pPDTTable[i].length,
+ 				pPDTTable[i].EndOfChain);
+ 	}	
+ }
+ 
+ void SetIOPort(DISKLIST *pList,USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	USHORT		AddressLow,AddressHi;
+ 	PPDT_TABLE	pPDTTable;
+ 	long		i;
+ 	DISKRWINFO	*pRWInfo;
+ 	ULONG		BoardID,Channel,Drive;
+ 	ULONG		IOPort1,DmaIO;
+ 
+ 	BoardID = pList->BoardID;
+ 	Channel = pList->Channel;
+ 	Drive = pList->Drive;
+ 
+ 	pRWInfo = (DISKRWINFO *) &DiskRWInfo[pList->BoardID][pList->Channel][pList->Drive];
+ 	if (!(OrderFlag & pRWInfo->InterruptFlag)) {
+ 		return ;
+ 	}
+ 
+ 	if(Channel == 0)
+ 	{
+ 		SelectFirstChannel(BoardID);
+ 	}
+ 	else
+ 	{
+ 		SelectSecondChannel(BoardID);
+ 	}
+ 	pPDTTable = BoardInfo[BoardID].PriScatterList;
+ 	IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 	DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	memcpy(pPDTTable,pRWInfo->ScatterList,pRWInfo->ListCount * sizeof(PDT_TABLE));
+ 	BoardInfo[BoardID].ListCount 		= pRWInfo->ListCount;
+ 	BoardInfo[BoardID].NumSectors       = pRWInfo->NumSectors;
+ 	BoardInfo[BoardID].StartLba         = pRWInfo->StartLba;
+ 
+ 	AddressLow = virt_to_bus(pPDTTable) & 0x0000ffff;
+ 	AddressHi = (virt_to_bus(pPDTTable) & 0xffff0000) >> 16;
+ 
+ 	outw(AddressLow,DmaIO + PDTLAR);
+ 	outw(AddressHi,DmaIO + PDTHAR);
+ 
+ 	PutLBAvalue(
+ 			IOPort1,
+ 			BoardInfo[BoardID].StartLba,
+ 			BoardInfo[BoardID].NumSectors,
+ 			Drive);
+ }
+ 
+ void SetIOInformation(int tid,USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	DWORD		RaidStatus;
+ 	int		i;
+ 
+ 	RaidStatus = RAID(tid); // Get raid data fron target id
+ 	switch(RaidStatus)
+ 	{
+ #if 1
+ //#if SECERT_IS_SOLVED
+ 	    case MIRRORING:
+ 		// Setting the Two Drives Same.
+ 		for(i = 0; i < 2; i++)
+ 		{
+ 			DISKRWINFO 	*pRWInfo = GetRWInfoPointer(&S_DISKLIST(tid,i));
+ 			if (pRWInfo->ListCount) {
+ 				SetIOPort(&S_DISKLIST(tid,i),DmaRW,OrderFlag);
+ 			}
+ 		}
+ 		break;
+ #endif
+ 	    default:
+ 		{
+ 			DISKRWINFO 	*pRWInfo = GetRWInfoPointer(&DiskID[tid].DiskStatus);
+ 			if (pRWInfo->ListCount) {
+ 				SetIOPort(&DiskID[tid].DiskStatus,DmaRW,OrderFlag);
+ 			}
+ 		}
+ 		break;
+ 	}
+ 
+ }
+ 
+ 
+ void SetIDECommand(DWORD Command, DWORD OrderFlag)
+ {
+ 	int i,j;
+ 
+ 	for(i=0;i<MAXBOARD;i++) {
+ 		if (BoardInfo[i].InterruptFlag[0] & OrderFlag) {
+ 			if(BoardInfo[i].StartLba >= 0x10000000)
+ 				Command=BigDiskCommand(Command);
+ 			outb(Command,BoardInfo[i].PrimaryIO + CommandPort);
+ 		}
+ 		if (BoardInfo[i].InterruptFlag[1] & OrderFlag) {
+ 			if(BoardInfo[i].StartLba >= 0x10000000)
+ 				Command=BigDiskCommand(Command);
+ 			outb(Command,BoardInfo[i].SecondaryIO + CommandPort);
+ 		}
+ 	}
+ }
+ 
+ DWORD	BigDiskCommand (DWORD cmnd)
+ {
+ 	switch(cmnd){
+ 		case	IDE_COMMAND_READ_DMA:
+ 			return IDE_COMMAND_READ_DMA_EXT;
+ 		case	IDE_COMMAND_WRITE_DMA:
+ 			return IDE_COMMAND_WRITE_DMA_EXT;
+ 	}
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+ 	return cmnd;
+ }
+ 
+ void SetDMACommand(USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	ULONG		DmaIO;
+ 	int         i,j,k;
+ 
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		for(j=0;j<2;j++)
+ 		{
+ 			for(k=0;k<2;k++)
+ 			{
+ 				if ((OrderFlag & DiskRWInfo[i][j][k].InterruptFlag))
+ 				{
+ 					DmaIO = BoardInfo[i].PrimaryDmaIO;
+ 					outw((0xff00 | HddSupportMode[i][j][k]), DmaIO + UDM_TIM);
+ 					outw(1, DmaIO + DMAMODE);		
+ 					outw(DmaRW,DmaIO + CMDR);
+ 				}
+ 			}
+ 		}
+ 	}
+ }
+ 
+ 
+ static int			ReadDMA(
+ 		Scsi_Cmnd * SCpnt,
+ 		ULONG lba,
+ 		ULONG numsectors)
+ {
+ 	int 			i;
+ 	unsigned long	flags;
+ 	DWORD		RaidStatus;
+ 
+ 	RaidStatus = RAID(SCpnt->target); // Get raid data fron target id
+ 	switch(RaidStatus)
+ 	{
+ 	    case MIRRORING:
+ 		// need to make some algorithm to use two HDD optimized to speed.
+ 		if (numsectors == 0) {
+ 			my_done(DID_ABORT << 16);
+ 			return ERROR_INVALID_SECTORCOUNT;
+ 		}
+ 		i = SetScatterList(SCpnt,lba,numsectors,READ_STATUS);
+ 		if(i = 2)
+ 		{
+ 		    OrderStatus = ORDER_ONE | ORDER_TWO;
+ 		}
+ 		else
+ 		{
+ 		    OrderStatus = ORDER_ONE;
+ 		}
+ 		SetIOInformation(SCpnt->target,DMA_READ,OrderStatus);
+ 		RWStatus = READ_STATUS;
+ 		SetIDECommand(IDE_COMMAND_READ_DMA,OrderStatus);
+ 		SetDMACommand(DMA_READ,OrderStatus);
+ 		return 0;
+ 		break;
+ 	    default:
+ 		if (numsectors == 0) {
+ 			my_done(DID_ABORT << 16);
+ 			return ERROR_INVALID_SECTORCOUNT;
+ 		}
+ 		SetScatterList(SCpnt,lba,numsectors,READ_STATUS);
+ 		SetIOInformation(SCpnt->target,DMA_READ,ORDER_ONE);
+ 		RWStatus = READ_STATUS;
+ 		OrderStatus = ORDER_ONE;
+ 		SetIDECommand(IDE_COMMAND_READ_DMA,ORDER_ONE);
+ 		SetDMACommand(DMA_READ,ORDER_ONE);
+ 		return 0;	
+ 		break;
+ 	}
+ 
+ }
+ 
+ static int			WriteDMA(
+ 		Scsi_Cmnd * SCpnt,
+ 		ULONG lba,
+ 		ULONG numsectors)
+ {
+ 	int 		i;
+ 	unsigned long	flags;
+ 	DWORD		RaidStatus;
+ 
+ 	RaidStatus = RAID(SCpnt->target); // Get raid data fron target id
+ 	printk("WriteDMA raid status %d\n", RaidStatus);
+ 	switch(RaidStatus)
+ 	{
+ 	    case MIRRORING:
+ 		// write same data to HDD.
+ 		if (numsectors == 0) {
+ 			my_done(DID_ABORT << 16);
+ 			return ERROR_INVALID_SECTORCOUNT;
+ 		}
+ 		i = SetScatterList(SCpnt,lba,numsectors,WRITE_STATUS);
+ 		printk("SetScatterList return %d\n", i);
+ 		if(i = 2)
+ 		{
+ 		    OrderStatus = ORDER_ONE | ORDER_TWO;
+ 		}
+ 		else
+ 		{
+ 		    OrderStatus = ORDER_ONE;
+ 		}
+ 		SetIOInformation(SCpnt->target,DMA_WRITE,OrderStatus);
+ 		RWStatus = WRITE_STATUS;
+ 		SetIDECommand(IDE_COMMAND_WRITE_DMA,OrderStatus);
+ 		SetDMACommand(DMA_WRITE,OrderStatus);
+ 		return 0;	
+ 		break;
+ 	    default:
+ 		if (numsectors == 0) {
+ 			my_done(DID_ABORT << 16);
+ 			return ERROR_INVALID_SECTORCOUNT;
+ 		}
+ 		SetScatterList(SCpnt,lba,numsectors,WRITE_STATUS);
+ 		SetIOInformation(SCpnt->target,DMA_WRITE,ORDER_ONE);
+ 		RWStatus = WRITE_STATUS;
+ 		OrderStatus = ORDER_ONE;
+ 		SetIDECommand(IDE_COMMAND_WRITE_DMA,ORDER_ONE);
+ 		SetDMACommand(DMA_WRITE,ORDER_ONE);
+ 		return 0;	
+ 		break;
+ 	}
+ 
+ }
+ 
+ void GetUDMAMode(USHORT *mode,USHORT *Timing,
+ 		IDENTIFY_DATA * IdentifyData)
+ {
+ 
+ 	if(IdentifyData->UDMASupport & 0x40){ 
+ 		*mode = 0x46; // mode 6
+ 		*Timing = 0xff22; // mode 6
+ 	}
+ 	else if(IdentifyData->UDMASupport & 0x20){ 
+ 		*mode = 0x45; // mode 5
+ 		*Timing = 0xff33; // mode 5
+ 	}
+ 	else if(IdentifyData->UDMASupport & 0x10){ 
+ 		*mode = 0x44; // mode 4
+ 		*Timing = 0xff44; // mode 4
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x08){ 
+ 		*mode = 0x43; // mode 3
+ 		*Timing = 0xff55; // mode 3
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x04){ 
+ 		*mode = 0x42; // mode 2
+ 		*Timing = 0xff66; // mode 2
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x02){ 
+ 		*mode = 0x41; // mode 1
+ 		*Timing = 0xff77; // mode 1
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x01){ 
+ 		*mode = 0x40; // mode 0
+ 		*Timing = 0xff88; // mode 0
+ 	} 
+ #ifdef _7878_
+ 	*mode = 0x44; // mode 4
+ 	*Timing = 0x7878; // safe mode
+ #endif
+ }
+ 
+ void SetUDMAMode(int BoardID, int Channel, int Drive)
+ {
+ 	USHORT 		mode[3],Timing[3];
+ 	ULONG    	IOPort1;
+ 	ULONG		DmaIO;
+ 	char		statusByte=0;
+ 	int i;	
+ 
+ 	if(Channel == 0)
+ 	{
+ 		SelectFirstChannel(BoardID);
+ 	}
+ 	else
+ 	{
+ 		SelectSecondChannel(BoardID);
+ 	}
+ 	IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 	DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	
+ 	
+ 	if(HddConnected[BoardID][Channel][Drive]>0)
+ 	{
+ 		mode[0] = 0xffff;
+ 		Timing[0] = 0xffff;
+ 		GetUDMAMode(&mode[0],&Timing[0],&DiskIdentifyData[BoardID][Channel][Drive]);
+ 		printk("udma mode value = %x\n",mode[0]);
+ 		if(mode[0] == 0xffff)
+ 			return;
+ 		outb(0xA0 + (Drive << 4),IOPort1 + DriveSelectPort);
+ 		for(i=0;i<10000;i++)
+ 		{		
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			udelay(100);	
+ 			if(statusByte & IDE_STATUS_BUSY)
+ 				continue;
+ 			else
+ 				break;	
+ 		}
+ 		outb(0xA0 + (Drive << 4),IOPort1 + DriveSelectPort);
+ 		outb(mode[0],IOPort1 + BlockCountPort);
+ 		outb(0x03,IOPort1 + ErrorPort);
+ 		outb(IDE_COMMAND_ENABLE_MEDIA_STATUS,IOPort1 + CommandPort);
+ 		for(i=0;i<10000;i++)
+ 		{		
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			udelay(100);	
+ 			if(statusByte & IDE_STATUS_BUSY)
+ 				continue;
+ 			else
+ 				break;	
+ 		}
+ 		if(statusByte == 0x50 || statusByte == 0x40)		
+ 		{
+ 			HddSupportMode[BoardID][Channel][Drive] = (((mode[0] << 8) | 0xff) & Timing[0]);
+ 			printk("SetUDMA: SupportMode = %0.4x\n", HddSupportMode[BoardID][Channel][Drive]);
+ 		}
+ 	}
+ 	mdelay(5);
+ 	for(i=0;i<10;i++)
+ 	{
+ 		GetBaseStatus(IOPort1, statusByte);
+ 		if(statusByte & IDE_STATUS_IDLE)
+ 			break;
+ 		else
+ 			mdelay(2);
+ 	}
+ }
+ 
+ static int	IdentifyDisk( 
+ 		int BoardID,
+ 		int Channel, 
+ 		int DriveSelect, 
+ 		IDENTIFY_DATA * IdentifyData)
+ {
+ 	ULONG    	IOPort1,DmaIO,ControlRegister;
+ 	UCHAR   	statusByte;
+ 	USHORT 		*pIdentifyData;
+ 	int             i, j;
+ 	int			flag = 0;
+ 
+ 	if(Channel == 0)
+ 	{
+ 		SelectFirstChannel(BoardID);
+ 	}
+ 	else
+ 	{
+ 		SelectSecondChannel(BoardID);
+ 	}
+ 	IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 	DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	ControlRegister = BoardInfo[BoardID].ControlRegister;
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 
+ 	for (i=0;i<1000;i++)
+ 	{
+ 		udelay(10);
+ 		GetBaseStatus(IOPort1, statusByte);
+ 		if (!(statusByte & IDE_STATUS_BUSY))
+ 			break;
+ 	}
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+ 	GetBaseStatus(IOPort1, statusByte);
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+ 	GetBaseStatus(IOPort1, statusByte);
+ 	if(statusByte != IDE_STATUS_IDLE)
+ 	{
+ 		outb(IDE_COMMAND_ATAPI_RESET, IOPort1 + CommandPort); //Device reset
+ 		for(i=0; i<3; i++)	//	KHG_20020731
+ 		{
+ 			mdelay(100);
+ 			outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort); 
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			if(statusByte != IDE_STATUS_IDLE)
+ 			{
+ 				outb(0x04, IOPort1 + AlternateStatusPort);
+ 				mdelay(100);
+ 				outb(0x00, IOPort1 + AlternateStatusPort);
+ 			}
+ 			else
+ 			{
+ 				break;
+ 			}
+ 		}
+ 	}
+ 	mdelay(50);
+ 	statusByte = statusByte & 0xc9;
+ 	if (statusByte != IDE_STATUS_DRDY)
+ 	{
+ 		return 0;
+ 	}
+ 
+ 
+ label1:
+ 	for (j = 0; j < 2; j++)
+ 	{
+ 		WaitOnBusy(IOPort1, statusByte);
+ 		outb(IDE_COMMAND_IDENTIFY, IOPort1 + CommandPort);
+ 
+ 		for (i = 0; i < 4; i++)
+ 		{
+ 			WaitForDrq(IOPort1, statusByte);
+ 			if (statusByte & IDE_STATUS_DRQ)
+ 			{
+ 				GetBaseStatus(IOPort1, statusByte);
+ 				break;
+ 			}
+ 			WaitOnBusy(IOPort1, statusByte);
+ 		}
+ 		if (i == 4 && j == 0)
+ 		{
+ 			return 0;
+ 		}
+ 		else
+ 		{
+ 			break;
+ 		}
+ 	}			// end of for (j = 0; j < 2; j++)
+ 
+ 
+ 	if (statusByte & IDE_STATUS_ERROR)
+ 	{
+ 		return 0;
+ 	}
+ 
+ 	WaitOnBusy(IOPort1, statusByte);
+ 
+ 
+ 	if (!(statusByte & IDE_STATUS_DRQ))
+ 	{
+ 		return 0;
+ 	}
+ 
+ 	pIdentifyData = (USHORT *) IdentifyData;
+ 
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+ 	GetBaseStatus(IOPort1, statusByte);
+ 	for (i = 0; i < 256; i++)
+ 	{
+ 		pIdentifyData[i] = inw(IOPort1 + DataPort);
+ 	}
+ 	{
+ 		char           *p,c;
+ 		p = (char *) &(IdentifyData->VendorUnique1);
+ 
+ 		for (i = 0; i < 26; i+=2)
+ 		{
+ 			c = p[i];
+ 			p[i] = p[i+1];
+ 			p[i+1] = c;
+ 		}
+ 		p = (char *) &(IdentifyData->ModelNumber);
+ 
+ 		for (i = 0; i < 40; i+=2)
+ 		{
+ 			c = p[i];
+ 			p[i] = p[i+1];
+ 			p[i+1] = c;
+ 		}
+ 	}
+ 
+ 	{
+ 		int mm = 0;
+ 
+ 		for (i = 0; i < 0x1000; i++)
+ 		{
+ 
+ 			GetStatus(IOPort1, statusByte);
+ 
+ 			if ((statusByte & IDE_STATUS_DRQ)
+ 					|| (statusByte & IDE_STATUS_BUSY)
+ 					|| (statusByte & 1) )
+ 			{
+ 				inw(IOPort1 + DataPort);
+ 			}
+ 			else
+ 			{
+ 				break;
+ 			}
+ 		}			// end of for
+ 	}
+ 	return 1;
+ }
+ 
+ char     *ultima_info(struct Scsi_Host *ignore)
+ {
+ 	static char     buffer[128];
+ 	char           *pt;
+ 
+ 	strcpy(buffer, "Aralion Ultima ATA133 IDE RAID MultiCard Driver Version");
+ 	if (strchr(VERSION, ':'))
+ 	{			/* Assume VERSION is an RCS Revision string */
+ 		strcat(buffer, strchr(VERSION, ':') + 1);
+ 		pt = strrchr(buffer, '$') - 1;
+ 		if (!pt)		/* Stripped RCS Revision string? */
+ 			pt = buffer + strlen(buffer) - 1;
+ 		if (*pt != ' ')
+ 			++pt;
+ 		*pt = '\0';
+ 	}
+ 	else
+ 	{			/* Assume VERSION is a number */
+ 		strcat(buffer, " " VERSION);
+ 	}
+ 
+ 	return buffer;
+ }
+ 
+ 
+ int init_module(void) {
+ 	driver_template.module = &__this_module;
+ 	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+ 	if (driver_template.present) {
+ 		return 0;
+ 	}
+ 
+ 	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ 	return -1;
+ }
+ 
+ void cleanup_module( void) {
+ 	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ }
+ 
+ int             ultima_proc_info(char *buffer, char **start, off_t offset,
+ 		int length, int hostno, int inout)
+ {
+ 	const char     *info = ultima_info(NULL);
+ 	int             len;
+ 	int             pos;
+ 	int             begin;
+ 
+ 	if (inout)
+ 		return (-ENOSYS);
+ 
+ 	begin = 0;
+ 	strcpy(buffer, info);
+ 	strcat(buffer, "\n");
+ 
+ 	pos = len = strlen(buffer);
+ 
+ 	if (pos < offset)
+ 	{
+ 		len = 0;
+ 		begin = pos;
+ 	}
+ 
+ 	*start = buffer + (offset - begin);	/* Start of wanted data */
+ 	len -= (offset - begin);
+ 	if (len > length)
+ 		len = length;
+ 
+ 	return (len);
+ }
+ 
+ static int      aralion_arbitrate(void)
+ {
+ 	int             status = 0;
+ 	ULONG   timeout;
+ 
+ 	printk("[ aralion_arbitrate ]\n");
+ 
+ 	return 0;
+ }
+ 
+ static int      aralion_select(int target)
+ {
+ 	int             status;
+ 	ULONG   timeout;
+ 	static int      flag = 0;
+ 
+ 
+ 	printk("[ aralion_select - %d ]\n",target);
+ 	return 0;
+ }
+ 
+ static void            my_done(int error)
+ {
+ 	if (in_command)
+ 	{
+ 		in_command = 0;
+ 		//		printk("my_done\n");
+ 		if (test_and_clear_bit(IOCTL_LOCK,&LockValue) == 0)
+ 			printk("misc clear...\n");
+ 		current_SC->result = error;
+ 		if (current_SC->scsi_done) {
+ 			current_SC->scsi_done(current_SC);
+ 		}
+ 		else
+ 			panic("scsi: <aralion> current_SC->scsi_done() == NULL");
+ 	}
+ 	else
+ 	{
+ 		panic("scsi: <aralion> my_done() called outside of command\n");
+ 	}
+ }
+ 
+ int	CheckScsiError(ULONG Channel,ULONG IOPort1,UCHAR statusByte)
+ {
+ 	ULONG 	lba;
+ 	UCHAR 	Data[4];
+ 	UCHAR	errorByte;
+ 	ULONG 	scsiStatus = 0;
+ 
+ 	if (statusByte & 0x1) {
+ 
+ 		errorByte = inb(IOPort1 + ErrorPort);
+ 		printk("error byte = %x",ErrorPort);
+ 		if (errorByte & IDE_ERROR_BAD_BLOCK)
+ 			scsiStatus = DID_PARITY;
+ 		else if (errorByte & IDE_ERROR_DATA_ERROR)
+ 			scsiStatus = DID_ERROR;
+ 		else if (errorByte & IDE_ERROR_ID_NOT_FOUND)
+ 			scsiStatus = DID_NO_CONNECT;
+ 		else if (errorByte & IDE_ERROR_COMMAND_ABORTED)
+ 			scsiStatus = DID_ABORT;
+ 		else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH )
+ 			scsiStatus = DID_ERROR;
+ 
+ 		Data[3] = inb(IOPort1 + BlockNumberPort);
+ 		Data[2] = inb(IOPort1 + CylinderLowPort);
+ 		Data[1] = inb(IOPort1 + CylinderHighPort);
+ 		Data[0] = inb(IOPort1 + DriveSelectPort) & 0x0f;
+ 
+ 		lba = (Data[0] << 24) + (Data[1] << 16)
+ 			+ (Data[2] << 8) + Data[0];
+ 
+ 		LastErrorBlock = lba;
+ 		LastErrorCode = errorByte & 0x000f;
+ 
+ 		printk("Error! Ch:%d, %02x , %0d\n",Channel,
+ 				(UCHAR) errorByte,lba);
+ 		return scsiStatus;
+ 	}
+ 	else
+ 		return 0;
+ }
+ 
+ void CheckJobFinished(ULONG BoardID,ULONG Channel)
+ {
+ 	ULONG DmaIO;
+ 	USHORT Stat;
+ 	DWORD	i = 0;
+ 
+ 	if (Channel == 1) {
+ 		DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	}
+ 	else
+ 	{	
+ 		DmaIO = BoardInfo[BoardID].SecondaryDmaIO;
+ 	}
+ 	do {
+ 		Stat = inw(DmaIO + CONSR);
+ 		i++;
+ 	} while ((Stat & 0x01) && (i < 1000));
+ 	if(i>100)
+ 	{
+ 	    printk("CheckJobFinished Error\n");
+ 	}
+ }
+ 
+ void ClearAllIrq(void)
+ {
+ 	ULONG	Channel;
+ 	UCHAR   statusByte = 0;
+ 	UCHAR   statusByte2 = 0;
+ 	ULONG   IOPort1,IOPort2;
+ 	ULONG 	scsiStatus = 0;
+ 	int		i;
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		Channel = inw(BoardInfo[i].ControlRegister + INTSRC) & 0x03;
+ 
+ 		if (Channel == 0) 
+ 			continue;
+ 
+ 		statusByte = statusByte2 = 0;
+ 
+ 		if (Channel != 3 && 
+ 				( (BoardInfo[i].InterruptFlag[0] & OrderStatus) &
+ 				  (BoardInfo[i].InterruptFlag[1] & OrderStatus)
+ 				)
+ 		   )	
+ 			continue;
+ 		if (Channel & 1) {
+ 			IOPort1 = BoardInfo[i].PrimaryIO;
+ 			CheckJobFinished(i,1);
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			BoardInfo[i].InterruptFlag[0] &= (~OrderStatus);
+ 		}
+ 	}
+ }
+ 
+ void            do_ultima_intr(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ 	ULONG	Channel;
+ 	UCHAR   statusByte = 0;
+ 	UCHAR   statusByte2 = 0;
+ 	ULONG   IOPort1,IOPort2;
+ 	ULONG 	scsiStatus = 0;
+ 	IrqID	*pIntID;
+ 	int		i,j,flag;
+ 	int     ClearFlag = 0;
+ 	int		InterruptCount;
+ 	unsigned long flags;
+ 
+ 	spin_lock_irqsave(&io_request_lock, flags);
+ 	pIntID = (IrqID *) dev_id;
+ 
+ 	//	printk("< intr >\n");	
+ 
+ 	if (!pIntID) {
+ 		spin_unlock_irqrestore(&io_request_lock, flags);
+ 		return ;
+ 	}
+ 	/*
+ 	   if (gResetFlag) {
+ 	   for (i=0;i<gBoardCount;i++) {
+ 	   USHORT		Intena;
+ 
+ 	   Channel = inw(BoardInfo[i].ControlRegister + INTSRC);
+ 	   Intena = inw(BoardInfo[i].ControlRegister + INTENA);
+ 	   IOPort1 = BoardInfo[i].PrimaryIO;
+ 	   IOPort2 = BoardInfo[i].SecondaryIO;
+ 	   if (Channel & 1) {
+ 	   CheckJobFinished(i,1);
+ 	   GetBaseStatus(IOPort1, statusByte);
+ 	   }
+ 	   if (Channel & 2) {
+ 	   CheckJobFinished(i,2);
+ 	   GetBaseStatus(IOPort2, statusByte2);
+ 	   }
+ 	   if (statusByte & 0x1) 
+ 	   scsiStatus = CheckScsiError(Channel,IOPort1,statusByte);
+ 
+ 	   if (statusByte2 & 0x1)
+ 	   scsiStatus = CheckScsiError(Channel,IOPort2,statusByte);
+ 	   }
+ 	   spin_unlock_irqrestore(&io_request_lock, flags);
+ 	   return ;
+ 
+ 	   }
+ 	 */
+ 	if (!in_command) {
+ 		ClearAllIrq();
+ 		spin_unlock_irqrestore(&io_request_lock, flags);
+ 		return ;
+ 	}
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		Channel = inw(BoardInfo[i].ControlRegister + INTSRC) & 0x03;
+ 
+ 		if (Channel == 0) 
+ 			continue;
+ 
+ 		flag = 0;
+ 		statusByte = statusByte2 = 0;
+ 
+ 		if (Channel != 3 && 
+ 				( (BoardInfo[i].InterruptFlag[0] & OrderStatus) &
+ 				  (BoardInfo[i].InterruptFlag[1] & OrderStatus)
+ 				)
+ 		   )	
+ 			continue;
+ 		if (Channel & 1) {
+ 			IOPort1 = BoardInfo[i].PrimaryIO;
+ 			CheckJobFinished(i,1);
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			BoardInfo[i].InterruptFlag[0] &= (~OrderStatus);
+ 		}
+ 		if (Channel & 2) {
+ 			IOPort2 = BoardInfo[i].SecondaryIO;
+ 			CheckJobFinished(i,2);
+ 			GetBaseStatus(IOPort2, statusByte2);
+ 			BoardInfo[i].InterruptFlag[1] &= (~OrderStatus);
+ 		}
+ 		if (statusByte & 0x1) 
+ 			scsiStatus = CheckScsiError(Channel,IOPort1,statusByte);
+ 
+ 		if (statusByte2 & 0x1) 
+ 			scsiStatus = CheckScsiError(Channel,IOPort2,statusByte2);
+ 	}
+ 	if (OrderStatus != ORDER_FOUR) {
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if (BoardInfo[i].InterruptFlag[0] & OrderStatus || BoardInfo[i].InterruptFlag[1] & OrderStatus) {
+ 				spin_unlock_irqrestore(&io_request_lock, flags);
+ 				return ;
+ 			}
+ 		}	
+ 		flag = 0;
+ 
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_TWO || BoardInfo[i].InterruptFlag[1] & ORDER_TWO) && (OrderStatus == ORDER_ONE)) {
+ 				flag = 1;
+ 			}
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_THREE || BoardInfo[i].InterruptFlag[1] & ORDER_THREE) && (OrderStatus == ORDER_TWO)) {
+ 				flag = 1;
+ 			}
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_FOUR || BoardInfo[i].InterruptFlag[1] & ORDER_FOUR) && (OrderStatus == ORDER_THREE)) {
+ 				flag = 1;
+ 			}
+ 		}	
+ 
+ 		if (flag) {
+ 			OrderStatus <<= 4;
+ 
+ 			if (RWStatus == READ_STATUS) {
+ 				SetIOInformation(CurrentDisk,DMA_READ,OrderStatus);
+ 				SetIDECommand(IDE_COMMAND_READ_DMA,OrderStatus);
+ 				SetDMACommand(DMA_READ,OrderStatus);
+ 			}
+ 			else {
+ 				SetIOInformation(CurrentDisk,DMA_WRITE,OrderStatus);
+ 				SetIDECommand(IDE_COMMAND_WRITE_DMA,OrderStatus);
+ 				SetDMACommand(DMA_WRITE,OrderStatus);
+ 			}
+ 			spin_unlock_irqrestore(&io_request_lock, flags);
+ 			return ;
+ 		}
+ 		else {
+ 
+ 			my_done(scsiStatus << 16);
+ 			spin_unlock_irqrestore(&io_request_lock, flags);
+ 			return ;
+ 		}
+ 	}
+ 	else {
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if (BoardInfo[i].InterruptFlag[0] & ORDER_FOUR || BoardInfo[i].InterruptFlag[1] & ORDER_FOUR) {
+ 				spin_unlock_irqrestore(&io_request_lock, flags);
+ 				return ;
+ 			}
+ 		}	
+ 	}
+ 	my_done(scsiStatus << 16);
+ 	spin_unlock_irqrestore(&io_request_lock, flags);
+ 
+ 	return;
+ }
+ 
+ void     internal_done(Scsi_Cmnd * SCpnt)
+ {
+ 	internal_done_errcode = SCpnt->result;
+ 	++internal_done_flag;
+ }
+ 
+ int IsSplitter(char c)
+ {
+ 	if (c == ' ' || c == '-' || c == '_')
+ 		return 1;
+ 	else if (c >= '0' && c <= '9')
+ 		return 1;
+ 
+ 	return 0;
+ }
+ 
+ int             ultima_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+ {
+ 	char 			*buf;
+ 	int	 		board,channel,drive,raidmode;
+ 	ULONG			result;
+ 	/*
+ 	   printk("[c=%x : %s,I=%x]\n",
+ 	   (UCHAR) SCpnt->cmnd[0],
+ 	   GetCmdName((UCHAR) SCpnt->cmnd[0]),
+ 	   SCpnt->target);
+ 	 */
+ 	if (in_command) {
+ 		printk("[ ultima_queue c=%x : %s,I=%x]\n",
+ 				(UCHAR) SCpnt->cmnd[0],
+ 				GetCmdName((UCHAR) SCpnt->cmnd[0]),
+ 				SCpnt->target);
+ 		panic("Error! in_command == 1\n");
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+ 		return -1;
+ 	}
+ 	while(test_and_set_bit(IOCTL_LOCK,&LockValue) != 0) {
+ 		//		printk("QW ");
+ 		schedule();
+ 		udelay(1);
+ 	}
+ 	while(in_ioctl) {
+ 		printk("in_ioctl = 1\n");
+ 		udelay(1);
+ 	}
+ 	in_command = 1;
+ 	current_SC = SCpnt;
+ 	current_SC->scsi_done = done;
+ 
+ 	current_SC->SCp.Status              = 0;
+ 	current_SC->SCp.Message             = 0;
+ 	current_SC->SCp.have_data_in        = 0;
+ 	current_SC->SCp.sent_command        = 0;
+ 	current_SC->SCp.phase               = in_arbitration;
+ 
+ 	if (SCpnt->target >= DiskCount || SCpnt->lun > 0) {
+ 		my_done(DID_ABORT << 16);
+ 		return 0;
+ 	}
+ 
+ 	if (SCpnt->target >= DiskCount) {
+ 		my_done(DID_ABORT << 16);
+ 		return 0;
+ 	}
+ 
+ 	board = DiskID[current_SC->target].DiskStatus.BoardID;
+ 	channel = DiskID[current_SC->target].DiskStatus.Channel;
+ 	drive = DiskID[current_SC->target].DiskStatus.Drive;
+ 	raidmode = DiskID[current_SC->target].RaidStatus;
+ 	switch(current_SC->cmnd[0]) {
+ 		case TEST_UNIT_READY:
+ 		case REQUEST_SENSE :
+ 			my_done(0);
+ 			return 0;
+ 
+ 		case MODE_SENSE :
+ 			buf = (char *) current_SC->buffer;
+ 			buf[2] = 0x0;
+ 			my_done(0);
+ 			break;
+ 
+ 		case INQUIRY :
+ 			buf = (char *) current_SC->buffer;
+ 			{
+ 				PINQUIRYDATA    inquiryData
+ 					= (PINQUIRYDATA) current_SC->buffer;
+ 				PIDENTIFY_DATA identifyData =
+ 					&DiskIdentifyData[board][channel][drive];
+ 				int i;
+ 
+ 				memset(buf,0,current_SC->bufflen);
+ 
+ 				buf[4] = sizeof(INQUIRYDATA);
+ 
+ 				//
+ 				// Standard IDE interface only supports disks.
+ 				inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+ 
+ 				//
+ 				// Fill in vendor identification fields.
+ 				{
+ 					unsigned char *p;
+ 					int	i,j;
+ 
+ 					for (i = 0; i < 24; i ++) {  
+ 						inquiryData->VendorId[i] = 0;
+ 					}
+ 					p = (UCHAR *) identifyData->ModelNumber;
+ 					i = 0;
+ 
+ 					while(!IsSplitter(p[i])) {
+ 						inquiryData->VendorId[i] = p[i++];
+ 					}
+ 					inquiryData->VendorId[i] = 0;
+ 
+ 					i++;
+ 					j = 0;
+ 					while (p[i] != ' ' && i < 24) 
+ 						inquiryData->ProductId[j++] = p[i++];
+ 					inquiryData->ProductId[j] = 0;
+ 
+ 				}
+ 				//
+ 				// Initialize unused portion of product id.
+ 				for (i = 0; i < 4; i++) {
+ 					inquiryData->ProductId[12+i] = ' ';
+ 				}
+ 
+ 				//
+ 				// Move firmware revision from IDENTIFY data to
+ 				// product revision in INQUIRY data.
+ 				for (i = 0; i < 4; i += 2) {
+ 					inquiryData->ProductRevisionLevel[i] =
+ 						((UCHAR *)identifyData->FirmwareRevision)[i+1];
+ 					inquiryData->ProductRevisionLevel[i+1] =
+ 						((UCHAR *)identifyData->FirmwareRevision)[i];
+ 				}
+ 			}
+ 			//					printk("Inquiry Success!");
+ 			my_done(0);
+ 			break;
+ 		case READ_6 : 
+ 		case READ_10 :
+ 		case WRITE_6 : 	
+ 		case WRITE_10 :
+ 			{
+ 				ULONG numsectors,lba,i ;
+ 
+ 				if (*current_SC->cmnd == READ_6 || *current_SC->cmnd == WRITE_6) {
+ 					numsectors = (u_long) current_SC->cmnd[4];
+ 					lba = ((u_long) current_SC->cmnd[1] << 16) |
+ 						((u_long) current_SC->cmnd[2] << 8) |
+ 						(u_long) current_SC->cmnd[3];
+ 					lba &= 0x1FFFFF;
+ 				}
+ 				if (*current_SC->cmnd == READ_10 || *current_SC->cmnd == WRITE_10) {
+ 					numsectors = (u_long) current_SC->cmnd[8] |
+ 						((u_long) current_SC->cmnd[7] << 8);
+ 					lba = ((u_long) current_SC->cmnd[2] << 24) |
+ 						((u_long) current_SC->cmnd[3] << 16) |
+ 						((u_long) current_SC->cmnd[4] << 8) |
+ 						(u_long) current_SC->cmnd[5];
+ 				}
+ 
+ 				memset(DiskRWInfo,0,sizeof(DiskRWInfo));
+ 				for(i=0;i<gBoardCount;i++) {
+ 					BoardInfo[i].InterruptFlag[0] = 0;
+ 					BoardInfo[i].InterruptFlag[1] = 0;
+ 				}
+ 				CurrentDisk = current_SC->target;
+ 
+ 				if (*current_SC->cmnd == READ_6 || *current_SC->cmnd == READ_10) {
+ 
+ //					printk("R:[%03d,%08x]\n", numsectors,lba);
+ 					ReadDMA(current_SC,lba,numsectors);
+ 				}
+ 				else {
+ //					printk("W:[%03d,%08x]\n", numsectors,lba);
+ 					WriteDMA(current_SC,lba,numsectors);
+ 				}
+ 			}	
+ 			break;
+ 
+ 		case READ_CAPACITY :
+ 			{
+ 				ULONG block,size;
+ 				IDENTIFY_DATA * IdentifyData;
+ 
+ 				block = DiskID[current_SC->target].DiskStatus.Size;
+ 				buf = (char *) current_SC->buffer;
+ 				size = 512; 
+ 
+ 				*((ULONG *) buf)  = htonl(block - 1);
+ 				*((ULONG *) (buf + 4))  = htonl(size);
+ 			}
+ 
+ 			my_done(0);
+ 			break;
+ 		default:
+ 			my_done(0);
+ 			break;
+ 
+ 	}
+ 	return 0;
+ }
+ 
+ int             ultima_command(Scsi_Cmnd * SCpnt)
+ {
+ 	ultima_queue(SCpnt, internal_done);
+ 	while (!internal_done_flag)
+ 		;
+ 	internal_done_flag = 0;
+ 	return internal_done_errcode;
+ }
+ 
+ 
+ void            print_info(Scsi_Cmnd * SCpnt)
+ {
+ 	ULONG    imr;
+ 	ULONG    irr;
+ 	ULONG    isr;
+ 
+ 
+ 	if (!SCpnt || !SCpnt->host)
+ 	{
+ 		printk("scsi: <aralion> Cannot provide detailed information\n");
+ 		return;
+ 	}
+ 
+ 	printk("%s\n", ultima_info(SCpnt->host));
+ 	return ;
+ 	print_banner(SCpnt->host);
+ 
+ 	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+ 			SCpnt->SCp.phase,
+ 			SCpnt->target,
+ 			*(UCHAR *) SCpnt->cmnd,
+ 			SCpnt->use_sg, SCpnt->request_bufflen);
+ 	printk("sent_command = %d, have_data_in = %d, timeout = %d\n",
+ 			SCpnt->SCp.sent_command,
+ 			SCpnt->SCp.have_data_in, SCpnt->timeout);
+ }
+ 
+ int             ultima_handle(Scsi_Cmnd * SCpnt)
+ {
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+     return 0;
+ }
+ 
+ int             ultima_abort(Scsi_Cmnd * SCpnt)
+ {
+ 	ULONG   flags;
+ 
+ 	if (!in_command)
+ 	{
+ 		return SCSI_ABORT_NOT_RUNNING;
+ 	}
+ 	ultima_cardreset();
+ 	print_info(SCpnt);
+ 	current_SC->SCp.phase |= aborted;
+ 	current_SC->result = DID_ABORT << 16;
+ 
+ 	/* Aborts are not done well. . . */
+ 	if (in_command)
+ 		my_done(DID_ABORT << 16);
+ 
+ 	return SCSI_ABORT_SUCCESS;
+ }
+ 
+ int             ultima_reset(Scsi_Cmnd * SCpnt, unsigned int ignored)
+ {
+ 	ultima_cardreset();
+ 	return SCSI_RESET_WAKEUP;
+ }
+ 
+ int             ultima_1cardreset(int BoardID)
+ {
+ 	int		i,k;
+ 	UCHAR	statusByte,statusByte2;
+ 
+ 
+ 	SelectFirstChannel(BoardID);	
+ 	mdelay(20);
+ 	outw(0x8000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x4000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x0,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 
+ 	SelectSecondChannel(BoardID);
+ 	outw(0x8000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x4000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x0,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	   for (i=0;i<200;i++) 
+ 	   {
+ 	   SelectFirstChannel(BoardID);	
+ 	   mdelay(1);
+ 	   outb(0xA0, BoardInfo[BoardID].PrimaryIO + DriveSelectPort);
+ 	   mdelay(5);
+ 	   GetBaseStatus(BoardInfo[BoardID].PrimaryIO, statusByte);
+ 	   mdelay(5);
+ 
+ 	   SelectSecondChannel(BoardID);
+ 	   mdelay(1);
+ 	   outb(0xA0, BoardInfo[BoardID].PrimaryIO + DriveSelectPort);
+ 	   mdelay(5);
+ 	   GetBaseStatus(BoardInfo[BoardID].PrimaryIO, statusByte2);
+ 	   mdelay(5);
+ 
+ 	   if (!(statusByte & 0x80) && !(statusByte2 & 0x80))
+ 	   break;
+ 	   }
+ 
+ 	   for (i=0;i<500;i++) {
+ 	   mdelay(1);
+ 	   }
+ 	for (i=0;i<200;i++) {
+ 		mdelay(20);
+ 	}
+ 	if (HddConnected[BoardID][0][0]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				0,
+ 				0,
+ 				&DiskIdentifyData[BoardID][0][0]);
+ 	}
+ 	if (HddConnected[BoardID][0][1]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				0,
+ 				1,
+ 				&DiskIdentifyData[BoardID][0][1]);
+ 	}
+ 	if (HddConnected[BoardID][1][0]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				1,
+ 				0,
+ 				&DiskIdentifyData[BoardID][1][0]);
+ 	}
+ 	if (HddConnected[BoardID][1][1]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				1,
+ 				1,
+ 				&DiskIdentifyData[BoardID][1][1]);
+ 	}
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+     return 0;
+ }
+ 
+ 
+ int             ultima_cardreset(void)
+ {
+ 	int		i,j;
+ 
+ 	RWStatus = RESET_STATUS;
+ 
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		DisableInterrupt(i);
+ 		ultima_1cardreset(i);
+ 		for(j=0;j<4;j++)
+ 		{
+ 			if(HddConnected[i][j/2][j%2]) 
+ 			{
+ 				IdentifyDisk(i,j/2,j%2,&DiskIdentifyData[i][j/2][j%2]);
+ 				SetUDMAMode(i,j/2,j%2);
+ 			}
+ 		}
+ 		EnableInterrupt(i);
+ 	}
+ 	return SCSI_RESET_WAKEUP;
+ }
+ 
+ 
+ int             ultima_biosparam(Scsi_Disk * disk, kdev_t dev,
+ 		int *info_array)
+ {
+ 	int				size;
+ 	int				target;
+ 
+ 	if (MAJOR(dev) != SCSI_DISK0_MAJOR)
+ 	{
+ 		printk("scsi: aralion ultima_biosparam: too many disks");
+ 		return 0;
+ 	}
+ 
+ 	target = MINOR(dev) >> 4;
+ 
+ 	info_array[0] = 16;
+ 	info_array[1] = 63;
+ 
+ 	size = DiskID[target].DiskStatus.Size;
+ 	info_array[2] = size / (info_array[0] * info_array[1]);
+ 
+ 	if (info_array[2] > 1024) { 
+ 		info_array[0] = 0xff;
+ 		info_array[2] =
+ 			(ULONG) size / (info_array[0] * info_array[1]);
+ 	}
+ 	return 0;
+ }
+ 
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/ultima.c.old linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/ultima.c.old
*** linux-2.4.22/drivers/scsi/ultimaraid133/ultima.c.old	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/ultima.c.old	2003-12-09 15:22:22.000000000 +0900
***************
*** 0 ****
--- 1,1942 ----
+ /*******************************************************************
+ 
+   Aralion Ultima ATA133 IDE Raid Controller
+   Linux Device Driver source, programmed by soonsoo@hitel.net
+   Modified by Ashuaria Lee (ashuaria@intizen.com)
+ 
+  *******************************************************************/
+ //#define  __BOOT_KERNEL_BOOT	1
+ 
+ //#define	DEBUG1	1
+ //#define	DEBUG2	1
+ //#define	DEBUG3	1
+ //#define	DEBUG4	1
+ 
+ #include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/stddef.h>
+ #include <linux/string.h>
+ #include <linux/sched.h>
+ #include <linux/kernel.h>
+ #include <linux/ioport.h>
+ #include <linux/delay.h>
+ #include <linux/proc_fs.h>
+ #include <linux/spinlock.h>
+ #include <asm/io.h>
+ #include <asm/bitops.h>
+ #include <asm/system.h>
+ #include <asm/dma.h>
+ #include <linux/blk.h>
+ #include "../scsi.h"
+ #include "../hosts.h"
+ #include "../sd.h"
+ #include "ultima.h"
+ #include "atapi.h"
+ #include <linux/errno.h>
+ #include <linux/pci.h>
+ #include <linux/stat.h>
+ #include <linux/config.h>	/* for CONFIG_PCI */
+ #include <linux/fs.h>
+ #include <asm/segment.h> /* for put_user_byte */
+ #include <asm/uaccess.h>
+ #include <asm/atomic.h>
+ #include "iocontrol.h"
+ #include "flash.h"
+ 
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ #define KERNEL240
+ #else
+ #define KERNEL220
+ #endif
+ 
+ #define S_BOARD(x,y) (DiskID[x].DiskStatus.BoardID)
+ #define S_CHAN(x,y) (DiskID[x].DiskStatus.Channel)
+ #define S_DRV(x,y) (DiskID[x].DiskStatus.Drive)
+ #define RAID(x) (DiskID[x].RaidStatus)
+ #define DEG	printk("<1> "__FUNCTION__": %d\n",__LINE__)
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+ static void     print_banner(struct Scsi_Host *shpnt);
+ char * 		GetCmdName(char code);
+ static void    print_banner(struct Scsi_Host *shpnt);
+ static void    do_pause(ULONG amount);
+ static int     aralion_pci_bios_detect(int *irq);
+ ULONG			GetBlockCount(int BoardID,int channel,int drive);
+ int			RequestAllIrq(void);
+ void 			PutLBAvalue(ULONG IOPort1,
+ 		ULONG lba,
+ 		ULONG numsectors,
+ 		ULONG DriveSelect);
+ void			DisableInterrupt(int BoardID);
+ void			EnableInterrupt(int BoardID);
+ ULONG			SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status);
+ ULONG 			SetScatterList(Scsi_Cmnd *SCpnt,
+ 		ULONG lba,
+ 		ULONG numsectors,
+ 		ULONG ReadWrite);
+ void 			SetIOPort(DISKLIST *pList,USHORT DmaRW,DWORD OrderFlag);
+ void 			SetIOInformation(int tid,USHORT DmaRW,DWORD OrderFlag);
+ ULONG 			PutOneScatterList(ULONG	CurrentID,
+ 		DWORD PrimaryDiskArrayCount,
+ 		DISKLIST *PrimaryDiskArray,
+ 		ULONG lba,
+ 		ULONG buffer,
+ 		USHORT length);
+ void			SetIDECommand(DWORD Command, DWORD order);
+ DWORD			BigDiskCommand (DWORD cmnd);
+ void			SetDMACommand(USHORT DmaRW,DWORD OrderFlag);
+ static int		ReadDMA(Scsi_Cmnd * SCpnt,
+ 		ULONG lba,
+ 		ULONG numsectors);
+ static int		WriteDMA(Scsi_Cmnd * SCpnt,
+ 		ULONG lba,
+ 		ULONG numsectors);
+ void		GetUDMAMode(USHORT *mode,
+ 		USHORT *Timing,
+ 		IDENTIFY_DATA * IdentifyData);
+ void		SetUDMAMode(int BoardID, int Channel, int Drive);
+ static int	IdentifyDisk(int BoardID,
+ 		int Channel, 
+ 		int DriveSelect, 
+ 		IDENTIFY_DATA * IdentifyData);
+ static void		my_done(int error);
+ int				CheckScsiError(ULONG Channel,ULONG IOPort1,UCHAR statusByte);
+ void			CheckJobFinished(ULONG BoardID,ULONG Channel);
+ int 			IsSplitter(char c);
+ int            	ultima_1cardreset(int BoardID);
+ int            	ultima_cardreset(void);
+ void 			do_ultima_intr(int irq, void *dev_id, struct pt_regs *regs);
+ void			internal_done(Scsi_Cmnd * SCpnt);
+ void          	print_info(Scsi_Cmnd * SCpnt);
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+ struct proc_dir_entry proc_scsi_aralion = {
+ 	0x10, 7, "aralion",
+ 	S_IFDIR | S_IRUGO | S_IXUGO, 2
+ };
+ 
+ Scsi_Host_Template driver_template = ULTIMA_DMA133;
+ 
+ #define VERSION          "$Revision: LH 1.11BCS $"
+ 
+ enum {
+ 	in_arbitration = 0x02,
+ 	in_selection = 0x04,
+ 	in_other = 0x08,
+ 	disconnect = 0x10,
+ 	aborted = 0x20,
+ 	sent_ident = 0x40,
+ };
+ 
+ typedef struct {
+ 	char name[23];
+ 	char code;
+ } CMDNAME;
+ 
+ CMDNAME CmdName[] =
+ {
+ 	{"TEST_UNIT_READY",0x00},
+ 	{"REZERO_UNIT",0x01},
+ 	{"REQUEST_SENSE",0x03},
+ 	{"FORMAT_UNIT",0x04},
+ 	{"READ_BLOCK_LIMITS",0x05},
+ 	{"REASSIGN_BLOCKS",0x07},
+ 	{"READ_6",0x08},
+ 	{"WRITE_6",0x0a},
+ 	{"SEEK_6",0x0b},
+ 	{"READ_REVERSE",0x0f},
+ 	{"WRITE_FILEMARKS",0x10},
+ 	{"SPACE",0x11},
+ 	{"INQUIRY",0x12},
+ 	{"RECOVER_BUFFERED_DATA",0x14},
+ 	{"MODE_SELECT",0x15},
+ 	{"RESERVE",0x16},
+ 	{"RELEASE",0x17},
+ 	{"COPY",0x18},
+ 	{"ERASE",0x19},
+ 	{"MODE_SENSE",0x1a},
+ 	{"START_STOP",0x1b},
+ 	{"RECEIVE_DIAGNOSTIC",0x1c},
+ 	{"SEND_DIAGNOSTIC",0x1d},
+ 	{"ALLOW_MEDIUM_REMOVAL",0x1e},
+ 	{"SET_WINDOW",0x24},
+ 	{"READ_CAPACITY",0x25},
+ 	{"READ_10",0x28},
+ 	{"WRITE_10",0x2a},
+ 	{"SEEK_10",0x2b},
+ 	{"WRITE_VERIFY",0x2e},
+ 	{"VERIFY",0x2f},
+ 	{"SEARCH_HIGH",0x30},
+ 	{"SEARCH_EQUAL",0x31},
+ 	{"SEARCH_LOW",0x32},
+ 	{"SET_LIMITS",0x33},
+ 	{"PRE_FETCH",0x34},
+ 	{"READ_POSITION",0x34},
+ 	{"SYNCHRONIZE_CACHE",0x35},
+ 	{"LOCK_UNLOCK_CACHE",0x36},
+ 	{"READ_DEFECT_DATA",0x37},
+ 	{"MEDIUM_SCAN",0x38},
+ 	{"COMPARE",0x39},
+ 	{"COPY_VERIFY",0x3a},
+ 	{"WRITE_BUFFER",0x3b},
+ 	{"READ_BUFFER",0x3c},
+ 	{"UPDATE_BLOCK",0x3d},
+ 	{"READ_LONG",0x3e},
+ 	{"WRITE_LONG",0x3f},
+ 	{"CHANGE_DEFINITION",0x40},
+ 	{"WRITE_SAME",0x41},
+ 	{"READ_TOC",0x43},
+ 	{"LOG_SELECT",0x4c},
+ 	{"LOG_SENSE",0x4d},
+ 	{"MODE_SELECT_10",0x55},
+ 	{"RESERVE_10",0x56},
+ 	{"RELEASE_10",0x57},
+ 	{"MODE_SENSE_10",0x5a},
+ 	{"PERSISTENT_RESERVE_IN",0x5e},
+ 	{"PERSISTENT_RESERVE_OUT",0x5f},
+ 	{"MOVE_MEDIUM",0xa5},
+ 	{"READ_12",0xa8},
+ 	{"WRITE_12",0xaa},
+ 	{"WRITE_VERIFY_12",0xae},
+ 	{"SEARCH_HIGH_12",0xb0},
+ 	{"SEARCH_EQUAL_12",0xb1},
+ 	{"SEARCH_LOW_12",0xb2},
+ 	{"READ_ELEMENT_STATUS",0xb8},
+ 	{"SEND_VOLUME_TAG",0xb6},
+ 	{"WRITE_LONG_2",0xea}
+ };
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ static volatile int 		internal_done_flag = 0;
+ static volatile int 		internal_done_errcode = 0;
+ static Scsi_Cmnd 			*current_SC = NULL;
+ static int      			this_id = 31;
+ V6INTERFACEB 				V6;
+ static _DiskIDTable			DiskID[16];
+ static DISKRWINFO			DiskRWInfo[MAXBOARD][2][2];
+ static IDENTIFY_DATA 		DiskIdentifyData[MAXBOARD][2][2];
+ static int					gBoardCount = 0;
+ IrqID						ultimaID[MAXBOARD];
+ BOARDTABLE					BoardInfo[MAXBOARD];
+ static int					IrqFlag[32] = {0,};
+ static int					DiskCount = 0;
+ ULONG						LastErrorBlock,LastErrorCode;
+ static ULONG				RWStatus;
+ static ULONG				OrderStatus;
+ static ULONG				CurrentDisk;
+ static int      			interrupt_level = 0;
+ static int					HddConnected[MAXBOARD][2][2];
+ static int					HddSupportMode[MAXBOARD][2][2];
+ 
+ /////////////////////////////////////////////////
+ #define IOCTL_LOCK	1
+ static int 					in_ioctl = 0;
+ static int 					in_command = 0;
+ unsigned long 				LockValue = 0;
+ static DECLARE_WAIT_QUEUE_HEAD (WaitingQ);
+ 
+ /////////////////////////////////////////////////
+ UCHAR 						BiosManufacture = 0;
+ UCHAR						cDeviceCode = 0;
+ UCHAR   					cFlashFlag = 0;
+ UCHAR						*Buffer;
+ char *GetCmdName(char code)
+ {
+ 	int i;
+ 	int count;
+ 	char *s = "unknown function";
+ 
+ 	count = sizeof(CmdName) / sizeof(CMDNAME);
+ 
+ 	for(i=0;i<count;i++) {
+ 		if (CmdName[i].code == code)
+ 			return CmdName[i].name;
+ 	}
+ 	return s;
+ }
+ 
+ static void		print_banner(struct Scsi_Host *shpnt)
+ {
+ 	if (!shpnt)
+ 		return;			/* This won't ever happen */
+ 
+ 	printk("using scsi id %d\n", shpnt->this_id);
+ 
+ 	if (interrupt_level)
+ 		printk(" int %d", interrupt_level);
+ 	else
+ 		printk("<none>");
+ 
+ 	printk("\n");
+ }
+ 
+ static void		aralion_setup(char *str, int *ints)
+ {
+ 	this_id = 31;
+ }
+ 
+ 
+ /* Pause for amount*10 milliseconds */
+ static void		do_pause(ULONG amount)
+ {
+ 	do
+ 	{
+ 		udelay(10 * 1000);
+ 	}
+ 	while (--amount);
+ }
+ 
+ inline static void aralion_make_bus_idle(void)
+ {
+ }
+ 
+ static int      aralion_is_valid_port(int port)
+ {
+ 	return 0;
+ }
+ 
+ static int      aralion_test_loopback(void)
+ {
+ 	return 0;
+ }
+ 
+ static int      aralion_pci_bios_detect(int *irq)
+ {
+ 	struct pci_dev *pdev = NULL;
+ 
+ 	if (!pci_present())
+ 		return 0;
+ 
+ 	memset(BoardInfo,0,sizeof(BoardInfo));
+ 
+ 	do {
+ 		if ((pdev = pci_find_device(ARALION_VENDOR, ULTIMA_DEVICE, pdev)) != NULL) {
+ 			printk("Find %d device\n",gBoardCount);
+ 			//			BoardInfo[gBoardCount].BoardExist = 1;
+ 
+ #ifdef KERNEL240
+ 			BoardInfo[gBoardCount].PrimaryIO 
+ 				= (ULONG) pci_resource_start(pdev,0);
+ 			printk("[%d] Primary IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].PrimaryIO);
+ 			BoardInfo[gBoardCount].SecondaryIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x10; 
+ 			printk("[%d] Secondary IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].SecondaryIO);
+ 			BoardInfo[gBoardCount].PrimaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x20; 
+ 			printk("[%d] Primary DMA IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].PrimaryDmaIO);
+ 			BoardInfo[gBoardCount].SecondaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x30; 
+ 			printk("[%d] Secondary DMA IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].SecondaryDmaIO);
+ 			BoardInfo[gBoardCount].ControlRegister 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x40; 
+ 			printk("[%d] Control Register=%ld\n",gBoardCount,BoardInfo[gBoardCount].ControlRegister);
+ 			BoardInfo[gBoardCount].FlashMemory
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x50; 
+ 			printk("[%d] Flash Memory=%ld\n",gBoardCount,BoardInfo[gBoardCount].FlashMemory);
+ #else
+ 			BoardInfo[gBoardCount].PrimaryIO 
+ 				= (ULONG) pdev->base_address[0] & PCI_BASE_SDDRESS_IO_MASK;
+ 			BoardInfo[gBoardCount].SecondaryIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x10; 
+ 			BoardInfo[gBoardCount].PrimaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x20; 
+ 			BoardInfo[gBoardCount].SecondaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x30; 
+ 			BoardInfo[gBoardCount].ControlRegister 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x40; 
+ 			BoardInfo[gBoardCount].FlashMemory
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x50; 
+ #endif
+ 
+ 			BoardInfo[gBoardCount].interrupt_level = pdev->irq;
+ 			printk("[%d] Interrupt level=%ld\n",gBoardCount,BoardInfo[gBoardCount].interrupt_level);
+ 
+ 			request_region(BoardInfo[gBoardCount].PrimaryIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].SecondaryIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].PrimaryDmaIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].SecondaryDmaIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].ControlRegister, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].FlashMemory,0x8, "aralion");
+ 
+ 			if (!gBoardCount)
+ 				*irq = pdev->irq;
+ 
+ 			gBoardCount++;
+ 		}
+ 	} while(pdev != NULL);
+ 
+ 
+ 	if (!gBoardCount) {
+ 		printk("Ultima Board not found\n");
+ 		return 0;
+ 	}
+ 
+ 	interrupt_level = BoardInfo[0].interrupt_level;
+ 	return 1;
+ }
+ 
+ ULONG	GetBlockCount(int BoardID,int channel,int drive)
+ {
+ 	int i;
+ 	ULONG nCount;
+ 	UCHAR *p;
+ 	p = (char *) &(DiskIdentifyData[BoardID][channel][drive]);
+ 	if(DiskIdentifyData[BoardID][channel][drive].BIT48 & 0x0400)
+ 		nCount = *((ULONG *) (p + 200));
+ 	else
+ 		nCount = *((ULONG *) (p + 120));
+ 	return nCount;
+ }
+ 
+ int	RequestAllIrq(void) 
+ {
+ 	int			i;
+ 	int			irq;
+ 	int			retcode;
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		irq = BoardInfo[i].interrupt_level;
+ 
+ 		if (!IrqFlag[irq]) {
+ 			IrqFlag[irq] = 1;
+ 			memset(ultimaID[i].signature,0,8);
+ 			memcpy(ultimaID[i].signature,"Ultima",6);
+ 			ultimaID[i].IOPort1 = BoardInfo[i].PrimaryDmaIO;
+ 			ultimaID[i].irq = irq;
+ 
+ 			retcode = request_irq(irq,
+ 					do_ultima_intr, 
+ 					SA_INTERRUPT | SA_SHIRQ, 
+ 					"aralion", 
+ 					&ultimaID[i]);
+ 			if (retcode < 0)
+ 			{
+ 				printk("%d's Board IRQ Failure\n",i);
+ 
+ 				if (retcode == -EINVAL)	{
+ 					printk("scsi: <aralion> IRQ %d is bad!\n", irq);
+ 					printk("                This shouldn't happen!\n");
+ 					printk("                Send mail to faith@acm.org\n");
+ 				}
+ 				else if (retcode == -EBUSY) {
+ 					printk("scsi: <aralion> IRQ %d is already in use!\n",irq);
+ 					printk("                Please use another IRQ!\n");
+ 				}
+ 				else {
+ 					printk("scsi: <aralion> Error getting IRQ %d\n",irq);
+ 					printk("                This shouldn't happen!\n");
+ 					printk("                Send mail to faith@acm.org\n");
+ 				}
+ 				printk("scsi: <aralion> Detected, but driver not loaded (IRQ)\n");
+ 
+ 				return retcode;
+ 			}
+ 		}
+ 	}
+ 	return 0;
+ }
+ 
+ int             ultima_detect(Scsi_Host_Template * tpnt)
+ {
+ 	int             retcode;
+ 	struct Scsi_Host *shpnt;
+ 	int             i, j, statusByte;
+ 	int             flag = 0;
+ 	ULONG			IOPort;
+ 
+ 	tpnt->proc_dir = &proc_scsi_aralion;
+ 	flag = aralion_pci_bios_detect(&interrupt_level);
+ 
+ 	if (!flag) {
+ 		printk("scsi: Ultima not found\n");
+ 		return 0;
+ 	}
+ 
+ 	memset(&DiskID,0,sizeof(DiskID));
+ 	memset(&DiskRWInfo,0,sizeof(DiskRWInfo));
+ 	memset(&DiskIdentifyData,0,sizeof(DiskIdentifyData));
+ 	DiskCount = 0;
+ 
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		DisableInterrupt(i);
+ 		ultima_1cardreset(i);
+ 		EnableInterrupt(i);
+ 	}
+ 
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		IOPort = BoardInfo[i].PrimaryIO;
+ 		
+ 		SelectFirstChannel(i);
+ 		outb(0xA0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][0][0] = 1;
+ 		else
+ 			HddConnected[i][0][0] = 0;
+ 			
+ 		outb(0xB0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][0][1] = 1;
+ 		else
+ 			HddConnected[i][0][1] = 0;
+ 		
+ 		SelectSecondChannel(i);
+ 		outb(0xA0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][1][0] = 1;
+ 		else
+ 			HddConnected[i][1][0] = 0;
+ 		outb(0xB0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][1][1] = 1;
+ 		else
+ 			HddConnected[i][1][1] = 0;
+ 	}
+ 
+ 	for(j=0;j<4;j++)
+ 		printk("HDD:[%d]=%d\n",j,HddConnected[0][j/2][j%2]);
+ 
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		DisableInterrupt(i);
+ 		for(j=0;j<4;j++)
+ 		{
+ 			if(HddConnected[i][j/2][j%2])
+ 			{	
+ 				IdentifyDisk(i,j/2,j%2,&DiskIdentifyData[i][j/2][j%2]);
+ 				SetUDMAMode(i,j/2,j%2);
+ 				DiskID[DiskCount].DiskStatus.BoardID = i;
+ 				DiskID[DiskCount].DiskStatus.Channel = j/2;
+ 				DiskID[DiskCount].DiskStatus.Drive = j%2;
+ 				DiskID[DiskCount].RaidStatus = NORMALIDE;
+ 				DiskID[DiskCount].DiskStatus.Size = GetBlockCount(i,j/2,j%2);
+ 				DiskCount++;
+ 			}
+ 		}
+ 		EnableInterrupt(i);
+ 	}
+ 
+ 
+ 	tpnt->this_id = (this_id & 0x1f);
+ 
+ 	/* Print out a banner here in case we can't
+ 	   get resources.  */
+ 	shpnt = scsi_register(tpnt, 0);
+ 	shpnt->irq = interrupt_level;
+ 	shpnt->io_port = BoardInfo[0].ControlRegister;
+ 	shpnt->n_io_port = 0x10;
+ 	//    print_banner(shpnt);
+ 
+ 	if (!interrupt_level)
+ 	{
+ 		printk("scsi: <aralion>"
+ 				" Card Detected, but driver not loaded (no IRQ)\n");
+ 		return 0;
+ 	}
+ 	else
+ 	{
+ 		/* Register the IRQ with the kernel */
+ 		if (RequestAllIrq())
+ 			return 0;
+ 	}
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		BoardInfo[i].PriScatterList = kmalloc(SCATTERLISTSIZE,GFP_ATOMIC);
+ 		BoardInfo[i].SecScatterList = kmalloc(SCATTERLISTSIZE,GFP_ATOMIC);
+ 	}			
+ 	return 1;
+ }
+ 
+ 
+ int             ultima_release(struct Scsi_Host * tpnt)
+ {
+ 	int		i;
+ 	int		irq;
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		irq = BoardInfo[i].interrupt_level;
+ 		if (IrqFlag[irq]) {
+ 			free_irq(irq,&ultimaID[i]);
+ 			IrqFlag[irq] = 0;
+ 		}
+ 		release_region(BoardInfo[i].PrimaryIO,0x10);
+ 		release_region(BoardInfo[i].SecondaryIO,0x10);
+ 		release_region(BoardInfo[i].PrimaryDmaIO,0x10);
+ 		release_region(BoardInfo[i].SecondaryDmaIO,0x10);
+ 		release_region(BoardInfo[i].ControlRegister,0x10);
+ 		release_region(BoardInfo[i].FlashMemory,0x8);
+ 
+ 		kfree(BoardInfo[i].PriScatterList);
+ 		kfree(BoardInfo[i].SecScatterList);
+ 	}
+ 	scsi_unregister(tpnt);
+ 
+ 	return 0;
+ }
+ 
+ // #ifdef DEBUG
+ #if 1
+ void printDMARegister(int BoardID)
+ {
+ 	int i;
+ 	USHORT d1;
+ 
+ 	for(i=0;i<0x10;i++) {
+ 		d1 = inw(BoardInfo[BoardID].ControlRegister + i*2);
+ 		printk("<%02x:%04x> ",i,d1);
+ 	}
+ 	printk("\n");
+ }
+ #endif
+ 
+ inline DISKRWINFO *GetRWInfoPointer(DISKLIST *pDiskList)
+ {
+ 	return (DISKRWINFO *) &DiskRWInfo[pDiskList->BoardID][pDiskList->Channel][pDiskList->Drive];
+ }
+ 
+ void PutLBAvalue(ULONG IOPort1,ULONG lba,ULONG numsectors,
+ 		ULONG DriveSelect)
+ {
+ 	UCHAR	Data[4];
+ 	/////////////////////////////KHG-133s_Big////////////////////////////////	
+ 	if(lba >= 0x10000000){
+ 		Data[0] = (lba & 0xff000000 ) >> 24;
+ 		Data[1] = 0;
+ 		Data[2] = 0;
+ 		outb(0,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		Data[0] = (lba & 0x000000ff);
+ 		Data[1] = (lba & 0x0000ff00) >> 8;
+ 		Data[2] = (lba & 0x00ff0000) >> 16;
+ 		Data[3] = (DriveSelect << 4) | 0xe0;
+ 		outb(numsectors,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		outb(Data[3],IOPort1 + DriveSelectPort);
+ 	}
+ 	else{
+ 		Data[0] = (lba & 0x000000ff);
+ 		Data[1] = (lba & 0x0000ff00) >> 8;
+ 		Data[2] = (lba & 0x00ff0000) >> 16;
+ 		Data[3] = (lba & 0x0f000000) >> 24;
+ 		Data[3] = Data[3] | 0x40 | (DriveSelect << 4) | 0xa0;
+ 
+ 		outb(numsectors,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		outb(Data[3],IOPort1 + DriveSelectPort);
+ 	}
+ 	/////////////////////////////////////////////////////////////////////////
+ }
+ 
+ void DisableInterrupt(int BoardID)
+ {
+ 	USHORT		Intena;
+ 
+ 	//	Intena = inw(BoardInfo[BoardID].ControlRegister + INTENA);
+ 	//	Intena = Intena & 0xfe;
+ 	Intena = 0;
+ 
+ 	printk("Disable Interrupt : %d\n",BoardID);
+ 	outw(Intena,BoardInfo[BoardID].ControlRegister + INTENA);
+ }
+ 
+ void EnableInterrupt(int BoardID)
+ {
+ 	USHORT		Intena;
+ 
+ 	//	Intena = inw(BoardInfo[BoardID].ControlRegister + INTENA);
+ 	//	Intena = Intena | 0x01;
+ 	Intena = 0x03;		//KHG
+ 
+ 	printk("Enable Interrupt : %d\n",BoardID);
+ 	outw(Intena,BoardInfo[BoardID].ControlRegister + INTENA);
+ 	//	printk("EI2 : %d\n",BoardID);
+ }
+ 
+ // int SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status)
+ ULONG SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status)
+ {
+ 	////////////////////////////////////KHG-133s////////////////////////////////////
+ 	ULONG	TempStatus;
+ 	Channel = 0;
+ 
+ 	if (BoardInfo[BoardID].InterruptFlag[Channel] & Status) {
+ 		TempStatus = BoardInfo[BoardID].InterruptFlag[Channel] & 0x00001111;
+ 		if(TempStatus & 0x00001100){
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00001000;
+ 			return 0x00001000;
+ 		}
+ 		else if(TempStatus & 0x00000010){
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00000100;
+ 			return 0x00000100;
+ 		}
+ 		else {
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00000010;
+ 			return 0x000000010;
+ 		}
+ 	}
+ 	else {
+ 		BoardInfo[BoardID].InterruptFlag[Channel] = (Status | ORDER_ONE);
+ 		return 0;
+ 	}
+ }
+ 
+ ULONG SetScatterList(	Scsi_Cmnd * SCpnt,
+ 		ULONG lba,
+ 		ULONG numsectors,
+ 		ULONG	ReadWrite)
+ {
+ 	struct scatterlist 	*slp;
+ 	int					i,j;
+ 	PPDT_TABLE 			pPDTTable;
+ 	DISKRWINFO			*pRWInfo,*pRWInfo2;
+ 	int					tid = SCpnt->target;
+ 	DWORD				RaidStatus;
+ 	ULONG	TempFlag;
+ 
+ 	RaidStatus = RAID(tid);
+ 
+ 	pRWInfo = (DISKRWINFO *) &DiskRWInfo[S_BOARD(tid,0)][S_CHAN(tid,0)][S_DRV(tid,0)];
+ 
+ 	pRWInfo->StartLba = lba;
+ 	pRWInfo->ListCount = 0;
+ 	pRWInfo->NumSectors = 0;
+ 	pPDTTable = pRWInfo->ScatterList;
+ 	if (SCpnt->use_sg) {
+ 		slp = (struct scatterlist *) SCpnt->request_buffer;
+ 		for(i=0;i<SCpnt->use_sg;i++,slp++) {
+ 			pPDTTable[i].address = virt_to_bus(slp->address);
+ 			pPDTTable[i].length = slp->length;
+ 			pPDTTable[i].EndOfChain = 0;
+ 			pRWInfo->NumSectors += slp->length;
+ 		}
+ 		pPDTTable[i - 1].EndOfChain = 0x80;
+ 		pRWInfo->ListCount = SCpnt->use_sg;
+ 	}
+ 	else {
+ 		pPDTTable[0].address = virt_to_bus(SCpnt->request_buffer);
+ 		pPDTTable[0].length = SCpnt->request_bufflen;
+ 		pPDTTable[0].EndOfChain = 0x80;
+ 		pRWInfo->NumSectors = SCpnt->request_bufflen;
+ 		pRWInfo->ListCount = 1;
+ 	}
+ 
+ 	pRWInfo->NumSectors /= 512;
+ 
+ 	pRWInfo->InterruptFlag = ReadWrite | ORDER_ONE;
+ 	SetBoardInterruptFlag(S_BOARD(tid,0),S_CHAN(tid,0),ReadWrite);
+ }
+ 
+ void PrintPDT(PPDT_TABLE  pPDTTable,int count)
+ {
+ 	int i;
+ 
+ 	for(i=0;i<count;i++) {
+ 		printk("%04d : [%08x,%04x,%02x]\n",i,
+ 				pPDTTable[i].address,
+ 				pPDTTable[i].length,
+ 				pPDTTable[i].EndOfChain);
+ 	}	
+ }
+ 
+ void SetIOPort(DISKLIST *pList,USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	USHORT		AddressLow,AddressHi;
+ 	PPDT_TABLE  pPDTTable;
+ 	long		i;
+ 	DISKRWINFO	*pRWInfo;
+ 	ULONG		BoardID,Channel,Drive;
+ 	ULONG		IOPort1,DmaIO;
+ 
+ 	BoardID = pList->BoardID;
+ 	Channel = pList->Channel;
+ 	Drive = pList->Drive;
+ 
+ 	pRWInfo = (DISKRWINFO *) &DiskRWInfo[pList->BoardID][pList->Channel][pList->Drive];
+ 	if (!(OrderFlag & pRWInfo->InterruptFlag)) {
+ 		return ;
+ 	}
+ 
+ 	if(Channel == 0)
+ 	{
+ 		SelectFirstChannel(BoardID);
+ 	}
+ 	else
+ 	{
+ 		SelectSecondChannel(BoardID);
+ 	}
+ 	pPDTTable = BoardInfo[BoardID].PriScatterList;
+ 	IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 	DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	memcpy(pPDTTable,pRWInfo->ScatterList,pRWInfo->ListCount * sizeof(PDT_TABLE));
+ 	BoardInfo[BoardID].ListCount 		= pRWInfo->ListCount;
+ 	BoardInfo[BoardID].NumSectors       = pRWInfo->NumSectors;
+ 	BoardInfo[BoardID].StartLba         = pRWInfo->StartLba;
+ 
+ 	AddressLow = virt_to_bus(pPDTTable) & 0x0000ffff;
+ 	AddressHi = (virt_to_bus(pPDTTable) & 0xffff0000) >> 16;
+ 
+ 	outw(AddressLow,DmaIO + PDTLAR);
+ 	outw(AddressHi,DmaIO + PDTHAR);
+ 
+ 	PutLBAvalue(
+ 			IOPort1,
+ 			BoardInfo[BoardID].StartLba,
+ 			BoardInfo[BoardID].NumSectors,
+ 			Drive);
+ }
+ 
+ void SetIOInformation(int tid,USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	DISKRWINFO 	*pRWInfo = GetRWInfoPointer(&DiskID[tid].DiskStatus);
+ 	if (pRWInfo->ListCount) {
+ 		SetIOPort(&DiskID[tid].DiskStatus,DmaRW,OrderFlag);
+ 	}
+ }
+ 
+ 
+ void SetIDECommand(DWORD Command, DWORD OrderFlag)
+ {
+ 	int i,j;
+ 
+ 	for(i=0;i<MAXBOARD;i++) {
+ 		if (BoardInfo[i].InterruptFlag[0] & OrderFlag) {
+ 			if(BoardInfo[i].StartLba >= 0x10000000)
+ 				Command=BigDiskCommand(Command);
+ 			outb(Command,BoardInfo[i].PrimaryIO + CommandPort);
+ 		}
+ 		/*		
+ 				if (BoardInfo[i].InterruptFlag[1] & OrderFlag) {
+ 				if(BoardInfo[i].StartLba >= 0x10000000)
+ 				Command=BigDiskCommand(Command);
+ 				outb(Command,BoardInfo[i].SecondaryIO + CommandPort);
+ 				}
+ 		 */
+ 	}
+ }
+ 
+ DWORD	BigDiskCommand (DWORD cmnd)
+ {
+ 	switch(cmnd){
+ 		case	IDE_COMMAND_READ_DMA:
+ 			return IDE_COMMAND_READ_DMA_EXT;
+ 		case	IDE_COMMAND_WRITE_DMA:
+ 			return IDE_COMMAND_WRITE_DMA_EXT;
+ 	}
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+ 	return cmnd;
+ }
+ 
+ void SetDMACommand(USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	ULONG		DmaIO;
+ 	int         i,j,k;
+ 
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		for(j=0;j<2;j++)
+ 		{
+ 			for(k=0;k<2;k++)
+ 			{
+ 				if ((OrderFlag & DiskRWInfo[i][j][k].InterruptFlag))
+ 				{
+ 					DmaIO = BoardInfo[i].PrimaryDmaIO;
+ 					outw((0xff00 | HddSupportMode[i][j][k]), DmaIO + UDM_TIM);
+ 					outw(1, DmaIO + DMAMODE);		
+ 					outw(DmaRW,DmaIO + CMDR);
+ 				}
+ 			}
+ 		}
+ 	}
+ }
+ 
+ 
+ static int			ReadDMA(
+ 		Scsi_Cmnd * SCpnt,
+ 		ULONG lba,
+ 		ULONG numsectors)
+ {
+ 	int 			i;
+ 	unsigned long	flags;
+ 
+ 	if (numsectors == 0) {
+ 		my_done(DID_ABORT << 16);
+ 		return ERROR_INVALID_SECTORCOUNT;
+ 	}
+ 	SetScatterList(SCpnt,lba,numsectors,READ_STATUS);
+ 	SetIOInformation(SCpnt->target,DMA_READ,ORDER_ONE);
+ 	RWStatus = READ_STATUS;
+ 	OrderStatus = ORDER_ONE;
+ 	SetIDECommand(IDE_COMMAND_READ_DMA,ORDER_ONE);
+ 	SetDMACommand(DMA_READ,ORDER_ONE);
+ 	return 0;	
+ }
+ 
+ static int			WriteDMA(
+ 		Scsi_Cmnd * SCpnt,
+ 		ULONG lba,
+ 		ULONG numsectors)
+ {
+ 	int 		i;
+ 	unsigned long	flags;
+ 
+ 	if (numsectors == 0) {
+ 		my_done(DID_ABORT << 16);
+ 		return ERROR_INVALID_SECTORCOUNT;
+ 	}
+ 	SetScatterList(SCpnt,lba,numsectors,WRITE_STATUS);
+ 	SetIOInformation(SCpnt->target,DMA_WRITE,ORDER_ONE);
+ 	RWStatus = WRITE_STATUS;
+ 	OrderStatus = ORDER_ONE;
+ 
+ 	SetIDECommand(IDE_COMMAND_WRITE_DMA,ORDER_ONE);
+ 	SetDMACommand(DMA_WRITE,ORDER_ONE);
+ 
+ 	return 0;	
+ }
+ 
+ void GetUDMAMode(USHORT *mode,USHORT *Timing,
+ 		IDENTIFY_DATA * IdentifyData)
+ {
+ 
+ 	if(IdentifyData->UDMASupport & 0x40){ 
+ 		*mode = 0x46; // mode 6
+ 		*Timing = 0xff22; // mode 6
+ 	}
+ 	else if(IdentifyData->UDMASupport & 0x20){ 
+ 		*mode = 0x45; // mode 5
+ 		*Timing = 0xff33; // mode 5
+ 	}
+ 	else if(IdentifyData->UDMASupport & 0x10){ 
+ 		*mode = 0x44; // mode 4
+ 		*Timing = 0xff44; // mode 4
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x08){ 
+ 		*mode = 0x43; // mode 3
+ 		*Timing = 0xff55; // mode 3
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x04){ 
+ 		*mode = 0x42; // mode 2
+ 		*Timing = 0xff66; // mode 2
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x02){ 
+ 		*mode = 0x41; // mode 1
+ 		*Timing = 0xff77; // mode 1
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x01){ 
+ 		*mode = 0x40; // mode 0
+ 		*Timing = 0xff88; // mode 0
+ 	} 
+ #ifdef _7878_
+ 	*mode = 0x44; // mode 4
+ 	*Timing = 0x7878; // safe mode
+ #endif
+ }
+ 
+ void SetUDMAMode(int BoardID, int Channel, int Drive)
+ {
+ 	USHORT 		mode[3],Timing[3];
+ 	ULONG    	IOPort1;
+ 	ULONG		DmaIO;
+ 	char		statusByte=0;
+ 	int i;	
+ 
+ 	if(Channel == 0)
+ 	{
+ 		SelectFirstChannel(BoardID);
+ 	}
+ 	else
+ 	{
+ 		SelectSecondChannel(BoardID);
+ 	}
+ 	IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 	DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	
+ 	
+ 	if(HddConnected[BoardID][Channel][Drive]>0)
+ 	{
+ 		mode[0] = 0xffff;
+ 		Timing[0] = 0xffff;
+ 		GetUDMAMode(&mode[0],&Timing[0],&DiskIdentifyData[BoardID][Channel][Drive]);
+ 		printk("udma mode value = %x\n",mode[0]);
+ 		if(mode[0] == 0xffff)
+ 			return;
+ 		outb(0xA0 + (Drive << 4),IOPort1 + DriveSelectPort);
+ 		for(i=0;i<10000;i++)
+ 		{		
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			udelay(100);	
+ 			if(statusByte & IDE_STATUS_BUSY)
+ 				continue;
+ 			else
+ 				break;	
+ 		}
+ 		outb(0xA0 + (Drive << 4),IOPort1 + DriveSelectPort);
+ 		outb(mode[0],IOPort1 + BlockCountPort);
+ 		outb(0x03,IOPort1 + ErrorPort);
+ 		outb(IDE_COMMAND_ENABLE_MEDIA_STATUS,IOPort1 + CommandPort);
+ 		for(i=0;i<10000;i++)
+ 		{		
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			udelay(100);	
+ 			if(statusByte & IDE_STATUS_BUSY)
+ 				continue;
+ 			else
+ 				break;	
+ 		}
+ 		if(statusByte == 0x50 || statusByte == 0x40)		
+ 		{
+ 			HddSupportMode[BoardID][Channel][Drive] = (((mode[0] << 8) | 0xff) & Timing[0]);
+ 			printk("SetUDMA: SupportMode = %0.4x\n", HddSupportMode[BoardID][Channel][Drive]);
+ 		}
+ 	}
+ 	mdelay(5);
+ 	for(i=0;i<10;i++)
+ 	{
+ 		GetBaseStatus(IOPort1, statusByte);
+ 		if(statusByte & IDE_STATUS_IDLE)
+ 			break;
+ 		else
+ 			mdelay(2);
+ 	}
+ }
+ 
+ static int	IdentifyDisk( 
+ 		int BoardID,
+ 		int Channel, 
+ 		int DriveSelect, 
+ 		IDENTIFY_DATA * IdentifyData)
+ {
+ 	ULONG    	IOPort1,DmaIO,ControlRegister;
+ 	UCHAR   	statusByte;
+ 	USHORT 		*pIdentifyData;
+ 	int             i, j;
+ 	int			flag = 0;
+ 
+ 	if(Channel == 0)
+ 	{
+ 		SelectFirstChannel(BoardID);
+ 	}
+ 	else
+ 	{
+ 		SelectSecondChannel(BoardID);
+ 	}
+ 	IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 	DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	ControlRegister = BoardInfo[BoardID].ControlRegister;
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 
+ 	for (i=0;i<1000;i++)
+ 	{
+ 		udelay(10);
+ 		GetBaseStatus(IOPort1, statusByte);
+ 		if (!(statusByte & 0x80))
+ 			break;
+ 	}
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+ 	GetBaseStatus(IOPort1, statusByte);
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+ 	GetBaseStatus(IOPort1, statusByte);
+ 	if(statusByte != 0x50)
+ 	{
+ 		outb(0x08, IOPort1 + CommandPort); //Device reset
+ 		for(i=0; i<3; i++)	//	KHG_20020731
+ 		{
+ 			mdelay(100);
+ 			outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort); 
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			if(statusByte != 0x50)
+ 			{
+ 				outb(0x04, IOPort1 + 0x0e);
+ 				mdelay(100);
+ 				outb(0x00, IOPort1 + 0x0e);
+ 			}
+ 			else
+ 			{
+ 				break;
+ 			}
+ 		}
+ 	}
+ 	mdelay(50);
+ 	statusByte = statusByte & 0xc9;
+ 	if (statusByte != IDE_STATUS_DRDY)
+ 	{
+ 		return 0;
+ 	}
+ 
+ 
+ label1:
+ 	for (j = 0; j < 2; j++)
+ 	{
+ 		WaitOnBusy(IOPort1, statusByte);
+ 		outb(IDE_COMMAND_IDENTIFY, IOPort1 + CommandPort);
+ 
+ 		for (i = 0; i < 4; i++)
+ 		{
+ 			WaitForDrq(IOPort1, statusByte);
+ 			if (statusByte & IDE_STATUS_DRQ)
+ 			{
+ 				GetBaseStatus(IOPort1, statusByte);
+ 				break;
+ 			}
+ 			WaitOnBusy(IOPort1, statusByte);
+ 		}
+ 		if (i == 4 && j == 0)
+ 		{
+ 			return 0;
+ 		}
+ 		else
+ 		{
+ 			break;
+ 		}
+ 	}			// end of for (j = 0; j < 2; j++)
+ 
+ 
+ 	if (statusByte & IDE_STATUS_ERROR)
+ 	{
+ 		return 0;
+ 	}
+ 
+ 	WaitOnBusy(IOPort1, statusByte);
+ 
+ 
+ 	if (!(statusByte & IDE_STATUS_DRQ))
+ 	{
+ 		return 0;
+ 	}
+ 
+ 	pIdentifyData = (USHORT *) IdentifyData;
+ 
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+ 	GetBaseStatus(IOPort1, statusByte);
+ 	for (i = 0; i < 256; i++)
+ 	{
+ 		pIdentifyData[i] = inw(IOPort1 + DataPort);
+ 	}
+ 	{
+ 		char           *p,c;
+ 		p = (char *) &(IdentifyData->VendorUnique1);
+ 
+ 		for (i = 0; i < 26; i+=2)
+ 		{
+ 			c = p[i];
+ 			p[i] = p[i+1];
+ 			p[i+1] = c;
+ 		}
+ 		p = (char *) &(IdentifyData->ModelNumber);
+ 
+ 		for (i = 0; i < 40; i+=2)
+ 		{
+ 			c = p[i];
+ 			p[i] = p[i+1];
+ 			p[i+1] = c;
+ 		}
+ 	}
+ 
+ 	{
+ 		int mm = 0;
+ 
+ 		for (i = 0; i < 0x1000; i++)
+ 		{
+ 
+ 			GetStatus(IOPort1, statusByte);
+ 
+ 			if ((statusByte & IDE_STATUS_DRQ)
+ 					|| (statusByte & IDE_STATUS_BUSY)
+ 					|| (statusByte & 1) )
+ 			{
+ 				inw(IOPort1 + DataPort);
+ 			}
+ 			else
+ 			{
+ 				break;
+ 			}
+ 		}			// end of for
+ 	}
+ 	return 1;
+ }
+ 
+ char     *ultima_info(struct Scsi_Host *ignore)
+ {
+ 	static char     buffer[128];
+ 	char           *pt;
+ 
+ 	strcpy(buffer, "Aralion Ultima ATA133 IDE RAID MultiCard Driver Version");
+ 	if (strchr(VERSION, ':'))
+ 	{			/* Assume VERSION is an RCS Revision string */
+ 		strcat(buffer, strchr(VERSION, ':') + 1);
+ 		pt = strrchr(buffer, '$') - 1;
+ 		if (!pt)		/* Stripped RCS Revision string? */
+ 			pt = buffer + strlen(buffer) - 1;
+ 		if (*pt != ' ')
+ 			++pt;
+ 		*pt = '\0';
+ 	}
+ 	else
+ 	{			/* Assume VERSION is a number */
+ 		strcat(buffer, " " VERSION);
+ 	}
+ 
+ 	return buffer;
+ }
+ 
+ 
+ int init_module(void) {
+ 	driver_template.module = &__this_module;
+ 	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+ 	if (driver_template.present) {
+ 		return 0;
+ 	}
+ 
+ 	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ 	return -1;
+ }
+ 
+ void cleanup_module( void) {
+ 	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ }
+ 
+ int             ultima_proc_info(char *buffer, char **start, off_t offset,
+ 		int length, int hostno, int inout)
+ {
+ 	const char     *info = ultima_info(NULL);
+ 	int             len;
+ 	int             pos;
+ 	int             begin;
+ 
+ 	if (inout)
+ 		return (-ENOSYS);
+ 
+ 	begin = 0;
+ 	strcpy(buffer, info);
+ 	strcat(buffer, "\n");
+ 
+ 	pos = len = strlen(buffer);
+ 
+ 	if (pos < offset)
+ 	{
+ 		len = 0;
+ 		begin = pos;
+ 	}
+ 
+ 	*start = buffer + (offset - begin);	/* Start of wanted data */
+ 	len -= (offset - begin);
+ 	if (len > length)
+ 		len = length;
+ 
+ 	return (len);
+ }
+ 
+ static int      aralion_arbitrate(void)
+ {
+ 	int             status = 0;
+ 	ULONG   timeout;
+ 
+ 	printk("[ aralion_arbitrate ]\n");
+ 
+ 	return 0;
+ }
+ 
+ static int      aralion_select(int target)
+ {
+ 	int             status;
+ 	ULONG   timeout;
+ 	static int      flag = 0;
+ 
+ 
+ 	printk("[ aralion_select - %d ]\n",target);
+ 	return 0;
+ }
+ 
+ static void            my_done(int error)
+ {
+ 	if (in_command)
+ 	{
+ 		in_command = 0;
+ 		//		printk("my_done\n");
+ 		if (test_and_clear_bit(IOCTL_LOCK,&LockValue) == 0)
+ 			printk("misc clear...\n");
+ 		current_SC->result = error;
+ 		if (current_SC->scsi_done) {
+ 			current_SC->scsi_done(current_SC);
+ 		}
+ 		else
+ 			panic("scsi: <aralion> current_SC->scsi_done() == NULL");
+ 	}
+ 	else
+ 	{
+ 		panic("scsi: <aralion> my_done() called outside of command\n");
+ 	}
+ }
+ 
+ int	CheckScsiError(ULONG Channel,ULONG IOPort1,UCHAR statusByte)
+ {
+ 	ULONG 	lba;
+ 	UCHAR 	Data[4];
+ 	UCHAR	errorByte;
+ 	ULONG 	scsiStatus = 0;
+ 
+ 	if (statusByte & 0x1) {
+ 
+ 		errorByte = inb(IOPort1 + ErrorPort);
+ 		printk("error byte = %x",ErrorPort);
+ 		if (errorByte & IDE_ERROR_BAD_BLOCK)
+ 			scsiStatus = DID_PARITY;
+ 		else if (errorByte & IDE_ERROR_DATA_ERROR)
+ 			scsiStatus = DID_ERROR;
+ 		else if (errorByte & IDE_ERROR_ID_NOT_FOUND)
+ 			scsiStatus = DID_NO_CONNECT;
+ 		else if (errorByte & IDE_ERROR_COMMAND_ABORTED)
+ 			scsiStatus = DID_ABORT;
+ 		else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH )
+ 			scsiStatus = DID_ERROR;
+ 
+ 		Data[3] = inb(IOPort1 + BlockNumberPort);
+ 		Data[2] = inb(IOPort1 + CylinderLowPort);
+ 		Data[1] = inb(IOPort1 + CylinderHighPort);
+ 		Data[0] = inb(IOPort1 + DriveSelectPort) & 0x0f;
+ 
+ 		lba = (Data[0] << 24) + (Data[1] << 16)
+ 			+ (Data[2] << 8) + Data[0];
+ 
+ 		LastErrorBlock = lba;
+ 		LastErrorCode = errorByte & 0x000f;
+ 
+ 		printk("Error! Ch:%d, %02x , %0d\n",Channel,
+ 				(UCHAR) errorByte,lba);
+ 		return scsiStatus;
+ 	}
+ 	else
+ 		return 0;
+ }
+ 
+ void CheckJobFinished(ULONG BoardID,ULONG Channel)
+ {
+ 	ULONG DmaIO;
+ 	USHORT Stat;
+ 	DWORD	i = 0;
+ 
+ 	if (Channel == 1) {
+ 		DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	}
+ 	else
+ 	{	
+ 		DmaIO = BoardInfo[BoardID].SecondaryDmaIO;
+ 	}
+ 	do {
+ 		Stat = inw(DmaIO + CONSR);
+ 		i++;
+ 	} while ((Stat & 0x01) && (i < 1000));
+ 	if(i>100)
+ 	{
+ 	    printk("CheckJobFinished Error\n");
+ 	}
+ }
+ 
+ void ClearAllIrq(void)
+ {
+ 	ULONG	Channel;
+ 	UCHAR   statusByte = 0;
+ 	UCHAR   statusByte2 = 0;
+ 	ULONG   IOPort1,IOPort2;
+ 	ULONG 	scsiStatus = 0;
+ 	int		i;
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		Channel = inw(BoardInfo[i].ControlRegister + INTSRC) & 0x03;
+ 
+ 		if (Channel == 0) 
+ 			continue;
+ 
+ 		statusByte = statusByte2 = 0;
+ 
+ 		if (Channel != 3 && 
+ 				( (BoardInfo[i].InterruptFlag[0] & OrderStatus) &
+ 				  (BoardInfo[i].InterruptFlag[1] & OrderStatus)
+ 				)
+ 		   )	
+ 			continue;
+ 		if (Channel & 1) {
+ 			IOPort1 = BoardInfo[i].PrimaryIO;
+ 			CheckJobFinished(i,1);
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			BoardInfo[i].InterruptFlag[0] &= (~OrderStatus);
+ 		}
+ 	}
+ }
+ 
+ void            do_ultima_intr(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ 	ULONG	Channel;
+ 	UCHAR   statusByte = 0;
+ 	UCHAR   statusByte2 = 0;
+ 	ULONG   IOPort1,IOPort2;
+ 	ULONG 	scsiStatus = 0;
+ 	IrqID	*pIntID;
+ 	int		i,j,flag;
+ 	int     ClearFlag = 0;
+ 	int		InterruptCount;
+ 	unsigned long flags;
+ 
+ 	spin_lock_irqsave(&io_request_lock, flags);
+ 	pIntID = (IrqID *) dev_id;
+ 
+ 	//	printk("< intr >\n");	
+ 
+ 	if (!pIntID) {
+ 		spin_unlock_irqrestore(&io_request_lock, flags);
+ 		return ;
+ 	}
+ 	/*
+ 	   if (gResetFlag) {
+ 	   for (i=0;i<gBoardCount;i++) {
+ 	   USHORT		Intena;
+ 
+ 	   Channel = inw(BoardInfo[i].ControlRegister + INTSRC);
+ 	   Intena = inw(BoardInfo[i].ControlRegister + INTENA);
+ 	   IOPort1 = BoardInfo[i].PrimaryIO;
+ 	   IOPort2 = BoardInfo[i].SecondaryIO;
+ 	   if (Channel & 1) {
+ 	   CheckJobFinished(i,1);
+ 	   GetBaseStatus(IOPort1, statusByte);
+ 	   }
+ 	   if (Channel & 2) {
+ 	   CheckJobFinished(i,2);
+ 	   GetBaseStatus(IOPort2, statusByte2);
+ 	   }
+ 	   if (statusByte & 0x1) 
+ 	   scsiStatus = CheckScsiError(Channel,IOPort1,statusByte);
+ 
+ 	   if (statusByte2 & 0x1)
+ 	   scsiStatus = CheckScsiError(Channel,IOPort2,statusByte);
+ 	   }
+ 	   spin_unlock_irqrestore(&io_request_lock, flags);
+ 	   return ;
+ 
+ 	   }
+ 	 */
+ 	if (!in_command) {
+ 		ClearAllIrq();
+ 		spin_unlock_irqrestore(&io_request_lock, flags);
+ 		return ;
+ 	}
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		Channel = inw(BoardInfo[i].ControlRegister + INTSRC) & 0x03;
+ 
+ 		if (Channel == 0) 
+ 			continue;
+ 
+ 		flag = 0;
+ 		statusByte = statusByte2 = 0;
+ 
+ 		if (Channel != 3 && 
+ 				( (BoardInfo[i].InterruptFlag[0] & OrderStatus) &
+ 				  (BoardInfo[i].InterruptFlag[1] & OrderStatus)
+ 				)
+ 		   )	
+ 			continue;
+ 		if (Channel & 1) {
+ 			IOPort1 = BoardInfo[i].PrimaryIO;
+ 			CheckJobFinished(i,1);
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			BoardInfo[i].InterruptFlag[0] &= (~OrderStatus);
+ 		}
+ 		if (Channel & 2) {
+ 			IOPort2 = BoardInfo[i].SecondaryIO;
+ 			CheckJobFinished(i,2);
+ 			GetBaseStatus(IOPort2, statusByte2);
+ 			BoardInfo[i].InterruptFlag[1] &= (~OrderStatus);
+ 		}
+ 		if (statusByte & 0x1) 
+ 			scsiStatus = CheckScsiError(Channel,IOPort1,statusByte);
+ 
+ 		if (statusByte2 & 0x1) 
+ 			scsiStatus = CheckScsiError(Channel,IOPort2,statusByte2);
+ 	}
+ 	if (OrderStatus != ORDER_FOUR) {
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if (BoardInfo[i].InterruptFlag[0] & OrderStatus || BoardInfo[i].InterruptFlag[1] & OrderStatus) {
+ 				spin_unlock_irqrestore(&io_request_lock, flags);
+ 				return ;
+ 			}
+ 		}	
+ 		flag = 0;
+ 
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_TWO || BoardInfo[i].InterruptFlag[1] & ORDER_TWO) && (OrderStatus == ORDER_ONE)) {
+ 				flag = 1;
+ 			}
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_THREE || BoardInfo[i].InterruptFlag[1] & ORDER_THREE) && (OrderStatus == ORDER_TWO)) {
+ 				flag = 1;
+ 			}
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_FOUR || BoardInfo[i].InterruptFlag[1] & ORDER_FOUR) && (OrderStatus == ORDER_THREE)) {
+ 				flag = 1;
+ 			}
+ 		}	
+ 
+ 		if (flag) {
+ 			OrderStatus <<= 4;
+ 
+ 			if (RWStatus == READ_STATUS) {
+ 				SetIOInformation(CurrentDisk,DMA_READ,OrderStatus);
+ 				SetIDECommand(IDE_COMMAND_READ_DMA,OrderStatus);
+ 				SetDMACommand(DMA_READ,OrderStatus);
+ 			}
+ 			else {
+ 				SetIOInformation(CurrentDisk,DMA_WRITE,OrderStatus);
+ 				SetIDECommand(IDE_COMMAND_WRITE_DMA,OrderStatus);
+ 				SetDMACommand(DMA_WRITE,OrderStatus);
+ 			}
+ 			spin_unlock_irqrestore(&io_request_lock, flags);
+ 			return ;
+ 		}
+ 		else {
+ 
+ 			my_done(scsiStatus << 16);
+ 			spin_unlock_irqrestore(&io_request_lock, flags);
+ 			return ;
+ 		}
+ 	}
+ 	else {
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if (BoardInfo[i].InterruptFlag[0] & ORDER_FOUR || BoardInfo[i].InterruptFlag[1] & ORDER_FOUR) {
+ 				spin_unlock_irqrestore(&io_request_lock, flags);
+ 				return ;
+ 			}
+ 		}	
+ 	}
+ 	my_done(scsiStatus << 16);
+ 	spin_unlock_irqrestore(&io_request_lock, flags);
+ 
+ 	return;
+ }
+ 
+ void     internal_done(Scsi_Cmnd * SCpnt)
+ {
+ 	internal_done_errcode = SCpnt->result;
+ 	++internal_done_flag;
+ }
+ 
+ int IsSplitter(char c)
+ {
+ 	if (c == ' ' || c == '-' || c == '_')
+ 		return 1;
+ 	else if (c >= '0' && c <= '9')
+ 		return 1;
+ 
+ 	return 0;
+ }
+ 
+ int             ultima_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+ {
+ 	char 			*buf;
+ 	int	 			board,channel,drive;
+ 	ULONG			result;
+ 	/*
+ 	   printk("[c=%x : %s,I=%x]\n",
+ 	   (UCHAR) SCpnt->cmnd[0],
+ 	   GetCmdName((UCHAR) SCpnt->cmnd[0]),
+ 	   SCpnt->target);
+ 	 */
+ 	if (in_command) {
+ 		printk("[ ultima_queue c=%x : %s,I=%x]\n",
+ 				(UCHAR) SCpnt->cmnd[0],
+ 				GetCmdName((UCHAR) SCpnt->cmnd[0]),
+ 				SCpnt->target);
+ 		panic("Error! in_command == 1\n");
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+ 		return -1;
+ 	}
+ 	while(test_and_set_bit(IOCTL_LOCK,&LockValue) != 0) {
+ 		//		printk("QW ");
+ 		schedule();
+ 		udelay(1);
+ 	}
+ 	while(in_ioctl) {
+ 		printk("in_ioctl = 1\n");
+ 		udelay(1);
+ 	}
+ 	in_command = 1;
+ 	current_SC = SCpnt;
+ 	current_SC->scsi_done = done;
+ 
+ 	current_SC->SCp.Status              = 0;
+ 	current_SC->SCp.Message             = 0;
+ 	current_SC->SCp.have_data_in        = 0;
+ 	current_SC->SCp.sent_command        = 0;
+ 	current_SC->SCp.phase               = in_arbitration;
+ 
+ 	if (SCpnt->target >= DiskCount || SCpnt->lun > 0) {
+ 		my_done(DID_ABORT << 16);
+ 		return 0;
+ 	}
+ 
+ 	if (SCpnt->target >= DiskCount) {
+ 		my_done(DID_ABORT << 16);
+ 		return 0;
+ 	}
+ 
+ 	board = DiskID[current_SC->target].DiskStatus.BoardID;
+ 	channel = DiskID[current_SC->target].DiskStatus.Channel;
+ 	drive = DiskID[current_SC->target].DiskStatus.Drive;
+ 	switch(current_SC->cmnd[0]) {
+ 		case TEST_UNIT_READY:
+ 		case REQUEST_SENSE :
+ 			my_done(0);
+ 			return 0;
+ 
+ 		case MODE_SENSE :
+ 			buf = (char *) current_SC->buffer;
+ 			buf[2] = 0x0;
+ 			my_done(0);
+ 			break;
+ 
+ 		case INQUIRY :
+ 			buf = (char *) current_SC->buffer;
+ 			{
+ 				PINQUIRYDATA    inquiryData
+ 					= (PINQUIRYDATA) current_SC->buffer;
+ 				PIDENTIFY_DATA identifyData =
+ 					&DiskIdentifyData[board][channel][drive];
+ 				int i;
+ 
+ 				memset(buf,0,current_SC->bufflen);
+ 
+ 				buf[4] = sizeof(INQUIRYDATA);
+ 
+ 				//
+ 				// Standard IDE interface only supports disks.
+ 				inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+ 
+ 				//
+ 				// Fill in vendor identification fields.
+ 				{
+ 					unsigned char *p;
+ 					int	i,j;
+ 
+ 					for (i = 0; i < 24; i ++) {  
+ 						inquiryData->VendorId[i] = 0;
+ 					}
+ 					p = (UCHAR *) identifyData->ModelNumber;
+ 					i = 0;
+ 
+ 					while(!IsSplitter(p[i])) {
+ 						inquiryData->VendorId[i] = p[i++];
+ 					}
+ 					inquiryData->VendorId[i] = 0;
+ 
+ 					i++;
+ 					j = 0;
+ 					while (p[i] != ' ' && i < 24) 
+ 						inquiryData->ProductId[j++] = p[i++];
+ 					inquiryData->ProductId[j] = 0;
+ 
+ 				}
+ 				//
+ 				// Initialize unused portion of product id.
+ 				for (i = 0; i < 4; i++) {
+ 					inquiryData->ProductId[12+i] = ' ';
+ 				}
+ 
+ 				//
+ 				// Move firmware revision from IDENTIFY data to
+ 				// product revision in INQUIRY data.
+ 				for (i = 0; i < 4; i += 2) {
+ 					inquiryData->ProductRevisionLevel[i] =
+ 						((UCHAR *)identifyData->FirmwareRevision)[i+1];
+ 					inquiryData->ProductRevisionLevel[i+1] =
+ 						((UCHAR *)identifyData->FirmwareRevision)[i];
+ 				}
+ 			}
+ 			//					printk("Inquiry Success!");
+ 			my_done(0);
+ 			break;
+ 		case READ_6 : 
+ 		case READ_10 :
+ 		case WRITE_6 : 	
+ 		case WRITE_10 :
+ 			{
+ 				ULONG numsectors,lba,i ;
+ 
+ 				if (*current_SC->cmnd == READ_6 || *current_SC->cmnd == WRITE_6) {
+ 					numsectors = (u_long) current_SC->cmnd[4];
+ 					lba = ((u_long) current_SC->cmnd[1] << 16) |
+ 						((u_long) current_SC->cmnd[2] << 8) |
+ 						(u_long) current_SC->cmnd[3];
+ 					lba &= 0x1FFFFF;
+ 				}
+ 				if (*current_SC->cmnd == READ_10 || *current_SC->cmnd == WRITE_10) {
+ 					numsectors = (u_long) current_SC->cmnd[8] |
+ 						((u_long) current_SC->cmnd[7] << 8);
+ 					lba = ((u_long) current_SC->cmnd[2] << 24) |
+ 						((u_long) current_SC->cmnd[3] << 16) |
+ 						((u_long) current_SC->cmnd[4] << 8) |
+ 						(u_long) current_SC->cmnd[5];
+ 				}
+ 
+ 				memset(DiskRWInfo,0,sizeof(DiskRWInfo));
+ 				for(i=0;i<gBoardCount;i++) {
+ 					BoardInfo[i].InterruptFlag[0] = 0;
+ 					BoardInfo[i].InterruptFlag[1] = 0;
+ 				}
+ 				CurrentDisk = current_SC->target;
+ 
+ 				if (*current_SC->cmnd == READ_6 || *current_SC->cmnd == READ_10) {
+ 
+ //					printk("R:[%03d,%08x]\n", numsectors,lba);
+ 					ReadDMA(current_SC,lba,numsectors);
+ 				}
+ 				else {
+ //					printk("W:[%03d,%08x]\n", numsectors,lba);
+ 					WriteDMA(current_SC,lba,numsectors);
+ 				}
+ 			}	
+ 			break;
+ 
+ 		case READ_CAPACITY :
+ 			{
+ 				ULONG block,size;
+ 				IDENTIFY_DATA * IdentifyData;
+ 
+ 				block = DiskID[current_SC->target].DiskStatus.Size;
+ 				buf = (char *) current_SC->buffer;
+ 				size = 512; 
+ 
+ 				*((ULONG *) buf)  = htonl(block - 1);
+ 				*((ULONG *) (buf + 4))  = htonl(size);
+ 			}
+ 
+ 			my_done(0);
+ 			break;
+ 		default:
+ 			my_done(0);
+ 			break;
+ 
+ 	}
+ 	return 0;
+ }
+ 
+ int             ultima_command(Scsi_Cmnd * SCpnt)
+ {
+ 	ultima_queue(SCpnt, internal_done);
+ 	while (!internal_done_flag)
+ 		;
+ 	internal_done_flag = 0;
+ 	return internal_done_errcode;
+ }
+ 
+ 
+ void            print_info(Scsi_Cmnd * SCpnt)
+ {
+ 	ULONG    imr;
+ 	ULONG    irr;
+ 	ULONG    isr;
+ 
+ 
+ 	if (!SCpnt || !SCpnt->host)
+ 	{
+ 		printk("scsi: <aralion> Cannot provide detailed information\n");
+ 		return;
+ 	}
+ 
+ 	printk("%s\n", ultima_info(SCpnt->host));
+ 	return ;
+ 	print_banner(SCpnt->host);
+ 
+ 	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+ 			SCpnt->SCp.phase,
+ 			SCpnt->target,
+ 			*(UCHAR *) SCpnt->cmnd,
+ 			SCpnt->use_sg, SCpnt->request_bufflen);
+ 	printk("sent_command = %d, have_data_in = %d, timeout = %d\n",
+ 			SCpnt->SCp.sent_command,
+ 			SCpnt->SCp.have_data_in, SCpnt->timeout);
+ }
+ 
+ int             ultima_handle(Scsi_Cmnd * SCpnt)
+ {
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+     return 0;
+ }
+ 
+ int             ultima_abort(Scsi_Cmnd * SCpnt)
+ {
+ 	ULONG   flags;
+ 
+ 	if (!in_command)
+ 	{
+ 		return SCSI_ABORT_NOT_RUNNING;
+ 	}
+ 	ultima_cardreset();
+ 	print_info(SCpnt);
+ 	current_SC->SCp.phase |= aborted;
+ 	current_SC->result = DID_ABORT << 16;
+ 
+ 	/* Aborts are not done well. . . */
+ 	if (in_command)
+ 		my_done(DID_ABORT << 16);
+ 
+ 	return SCSI_ABORT_SUCCESS;
+ }
+ 
+ int             ultima_reset(Scsi_Cmnd * SCpnt, unsigned int ignored)
+ {
+ 	ultima_cardreset();
+ 	return SCSI_RESET_WAKEUP;
+ }
+ 
+ int             ultima_1cardreset(int BoardID)
+ {
+ 	int		i,k;
+ 	UCHAR	statusByte,statusByte2;
+ 
+ 
+ 	SelectFirstChannel(BoardID);	
+ 	mdelay(20);
+ 	outw(0x8000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x4000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x0,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 
+ 	SelectSecondChannel(BoardID);
+ 	outw(0x8000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x4000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x0,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	/*
+ 	   for (i=0;i<200;i++) 
+ 	   {
+ 	   SelectFirstChannel(BoardID);	
+ 	   mdelay(1);
+ 	   outb(0xA0, BoardInfo[BoardID].PrimaryIO + DriveSelectPort);
+ 	   mdelay(5);
+ 	   GetBaseStatus(BoardInfo[BoardID].PrimaryIO, statusByte);
+ 	   mdelay(5);
+ 
+ 	   SelectSecondChannel(BoardID);
+ 	   mdelay(1);
+ 	   outb(0xA0, BoardInfo[BoardID].PrimaryIO + DriveSelectPort);
+ 	   mdelay(5);
+ 	   GetBaseStatus(BoardInfo[BoardID].PrimaryIO, statusByte2);
+ 	   mdelay(5);
+ 
+ 	   if (!(statusByte & 0x80) && !(statusByte2 & 0x80))
+ 	   break;
+ 	   }
+ 
+ 	   for (i=0;i<500;i++) {
+ 	   mdelay(1);
+ 	   }
+ 	 */
+ 	for (i=0;i<200;i++) {
+ 		mdelay(20);
+ 	}
+ /*
+ 	if (HddConnected[BoardID][0][0]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				0,
+ 				0,
+ 				&DiskIdentifyData[BoardID][0][0]);
+ 	}
+ 	if (HddConnected[BoardID][0][1]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				0,
+ 				1,
+ 				&DiskIdentifyData[BoardID][0][1]);
+ 	}
+ 	if (HddConnected[BoardID][1][0]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				1,
+ 				0,
+ 				&DiskIdentifyData[BoardID][1][0]);
+ 	}
+ 	if (HddConnected[BoardID][1][1]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				1,
+ 				1,
+ 				&DiskIdentifyData[BoardID][1][1]);
+ 	}
+ */
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+     return 0;
+ }
+ 
+ 
+ int             ultima_cardreset(void)
+ {
+ 	int		i,j;
+ 
+ 	RWStatus = RESET_STATUS;
+ 
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		DisableInterrupt(i);
+ 		ultima_1cardreset(i);
+ 		for(j=0;j<4;j++)
+ 		{
+ 			if(HddConnected[i][j/2][j%2]) 
+ 			{
+ 				IdentifyDisk(i,j/2,j%2,&DiskIdentifyData[i][j/2][j%2]);
+ 				SetUDMAMode(i,j/2,j%2);
+ 			}
+ 		}
+ 		EnableInterrupt(i);
+ 	}
+ 	return SCSI_RESET_WAKEUP;
+ }
+ 
+ 
+ int             ultima_biosparam(Scsi_Disk * disk, kdev_t dev,
+ 		int *info_array)
+ {
+ 	int				size;
+ 	int				target;
+ 
+ 	if (MAJOR(dev) != SCSI_DISK0_MAJOR)
+ 	{
+ 		printk("scsi: aralion ultima_biosparam: too many disks");
+ 		return 0;
+ 	}
+ 
+ 	target = MINOR(dev) >> 4;
+ 
+ 	info_array[0] = 16;
+ 	info_array[1] = 63;
+ 
+ 	size = DiskID[target].DiskStatus.Size;
+ 	info_array[2] = size / (info_array[0] * info_array[1]);
+ 
+ 	if (info_array[2] > 1024) { 
+ 		info_array[0] = 0xff;
+ 		info_array[2] =
+ 			(ULONG) size / (info_array[0] * info_array[1]);
+ 	}
+ 	return 0;
+ }
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/ultima.c~ linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/ultima.c~
*** linux-2.4.22/drivers/scsi/ultimaraid133/ultima.c~	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/ultima.c~	2004-01-11 01:06:39.000000000 +0900
***************
*** 0 ****
--- 1,2253 ----
+ /*******************************************************************
+ 
+   Aralion Ultima ATA133 IDE Raid Controller
+   Linux Device Driver source, programmed by soonsoo@hitel.net
+   Modified by Ashuaria Lee (ashuaria@intizen.com)
+ 
+  *******************************************************************/
+ //#define  __BOOT_KERNEL_BOOT	1
+ 
+ //#define	DEBUG1	1
+ //#define	DEBUG2	1
+ //#define	DEBUG3	1
+ //#define	DEBUG4	1
+ 
+ #include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/stddef.h>
+ #include <linux/string.h>
+ #include <linux/sched.h>
+ #include <linux/kernel.h>
+ #include <linux/ioport.h>
+ #include <linux/delay.h>
+ #include <linux/proc_fs.h>
+ #include <linux/spinlock.h>
+ #include <asm/io.h>
+ #include <asm/bitops.h>
+ #include <asm/system.h>
+ #include <asm/dma.h>
+ #include <linux/blk.h>
+ #include "../scsi.h"
+ #include "../hosts.h"
+ #include "../sd.h"
+ #include "ultima.h"
+ #include "atapi.h"
+ #include <linux/errno.h>
+ #include <linux/pci.h>
+ #include <linux/stat.h>
+ #include <linux/config.h>	/* for CONFIG_PCI */
+ #include <linux/fs.h>
+ #include <asm/segment.h> /* for put_user_byte */
+ #include <asm/uaccess.h>
+ #include <asm/atomic.h>
+ #include "iocontrol.h"
+ #include "flash.h"
+ 
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ #define KERNEL240
+ #else
+ #define KERNEL220
+ #endif
+ 
+ // S_BOARD(targetid, volumemember) selects the RAID card from SCSI Target ID
+ #define S_BOARD(x,y) (LDiskID[DiskID[x].LogicalDisk].PhysicalDisk[y].BoardID)
+ // S_BOARD(targetid, volumemember) selects the Channel from SCSI Target ID
+ #define S_CHAN(x,y) (LDiskID[DiskID[x].LogicalDisk].PhysicalDisk[y].Channel)
+ // S_BOARD(targetid, volumemember) selects the Master/Slave from SCSI Target ID
+ #define S_DRV(x,y) (LDiskID[DiskID[x].LogicalDisk].PhysicalDisk[y].Drive)
+ // S_BOARD(targetid, volumemember) selects the DiskList itself
+ #define S_DISKLIST(x,y) (LDiskID[DiskID[x].LogicalDisk].PhysicalDisk[y])
+ #define RAID(x) (DiskID[x].RaidStatus)
+ #define DEG	printk("<1> "__FUNCTION__": %d\n",__LINE__)
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+ static void	print_banner(struct Scsi_Host *shpnt);
+ char *		GetCmdName(char code);
+ // static void	print_banner(struct Scsi_Host *shpnt);
+ static void	do_pause(ULONG amount);
+ static int	aralion_pci_bios_detect(int *irq);
+ ULONG		GetBlockCount(int BoardID,int channel,int drive);
+ int		RequestAllIrq(void);
+ // New code from dual driver. by ashuaria 2003/12/17
+ UCHAR 		FlashRead(USHORT Address);
+ void		FlashWrite(USHORT Address,USHORT Data);
+ void		FlashReset (void);
+ void		GetChipIDInit(void);
+ int		GetFlashRomData(void);
+ // Addition end.
+ void 		PutLBAvalue(ULONG IOPort1,
+ 			    ULONG lba,
+ 			    ULONG numsectors,
+ 			    ULONG DriveSelect);
+ void		DisableInterrupt(int BoardID);
+ void		EnableInterrupt(int BoardID);
+ ULONG		SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status);
+ ULONG 		SetScatterList(Scsi_Cmnd *SCpnt,
+ 			    ULONG lba,
+ 			    ULONG numsectors,
+ 			    ULONG ReadWrite);
+ void 		SetIOPort(DISKLIST *pList,USHORT DmaRW,DWORD OrderFlag);
+ void 		SetIOInformation(int tid,USHORT DmaRW,DWORD OrderFlag);
+ ULONG 		PutOneScatterList(ULONG	CurrentID,
+ 			    DWORD PrimaryDiskArrayCount,
+ 			    DISKLIST *PrimaryDiskArray,
+ 			    ULONG lba,
+ 			    ULONG buffer,
+ 			    USHORT length);
+ void		SetIDECommand(DWORD Command, DWORD order);
+ DWORD		BigDiskCommand (DWORD cmnd);
+ void		SetDMACommand(USHORT DmaRW,DWORD OrderFlag);
+ static int	ReadDMA(Scsi_Cmnd * SCpnt,
+ 			    ULONG lba,
+ 			    ULONG numsectors);
+ static int	WriteDMA(Scsi_Cmnd * SCpnt,
+ 			    ULONG lba,
+ 			    ULONG numsectors);
+ void		GetUDMAMode(USHORT *mode,
+ 			    USHORT *Timing,
+ 			    IDENTIFY_DATA * IdentifyData);
+ void		SetUDMAMode(int BoardID, int Channel, int Drive);
+ static int	IdentifyDisk(int BoardID,
+ 			    int Channel, 
+ 			    int DriveSelect, 
+ 			    IDENTIFY_DATA * IdentifyData);
+ static void	my_done(int error);
+ int		CheckScsiError(ULONG Channel,ULONG IOPort1,UCHAR statusByte);
+ void		CheckJobFinished(ULONG BoardID,ULONG Channel);
+ int 		IsSplitter(char c);
+ int            	ultima_1cardreset(int BoardID);
+ int            	ultima_cardreset(void);
+ void 		do_ultima_intr(int irq, void *dev_id, struct pt_regs *regs);
+ void		internal_done(Scsi_Cmnd * SCpnt);
+ void          	print_info(Scsi_Cmnd * SCpnt);
+ void		printFlashMemory(int BoardID);
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+ struct proc_dir_entry proc_scsi_aralion = {
+ 	0x10, 7, "aralion",
+ 	S_IFDIR | S_IRUGO | S_IXUGO, 2
+ };
+ 
+ Scsi_Host_Template driver_template = ULTIMA_DMA133;
+ 
+ #define VERSION          "$Revision: LH 1.11BCS $"
+ 
+ enum {
+ 	in_arbitration = 0x02,
+ 	in_selection = 0x04,
+ 	in_other = 0x08,
+ 	disconnect = 0x10,
+ 	aborted = 0x20,
+ 	sent_ident = 0x40,
+ };
+ 
+ typedef struct {
+ 	char name[23];
+ 	char code;
+ } CMDNAME;
+ 
+ CMDNAME CmdName[] =
+ {
+ 	{"TEST_UNIT_READY",0x00},
+ 	{"REZERO_UNIT",0x01},
+ 	{"REQUEST_SENSE",0x03},
+ 	{"FORMAT_UNIT",0x04},
+ 	{"READ_BLOCK_LIMITS",0x05},
+ 	{"REASSIGN_BLOCKS",0x07},
+ 	{"READ_6",0x08},
+ 	{"WRITE_6",0x0a},
+ 	{"SEEK_6",0x0b},
+ 	{"READ_REVERSE",0x0f},
+ 	{"WRITE_FILEMARKS",0x10},
+ 	{"SPACE",0x11},
+ 	{"INQUIRY",0x12},
+ 	{"RECOVER_BUFFERED_DATA",0x14},
+ 	{"MODE_SELECT",0x15},
+ 	{"RESERVE",0x16},
+ 	{"RELEASE",0x17},
+ 	{"COPY",0x18},
+ 	{"ERASE",0x19},
+ 	{"MODE_SENSE",0x1a},
+ 	{"START_STOP",0x1b},
+ 	{"RECEIVE_DIAGNOSTIC",0x1c},
+ 	{"SEND_DIAGNOSTIC",0x1d},
+ 	{"ALLOW_MEDIUM_REMOVAL",0x1e},
+ 	{"SET_WINDOW",0x24},
+ 	{"READ_CAPACITY",0x25},
+ 	{"READ_10",0x28},
+ 	{"WRITE_10",0x2a},
+ 	{"SEEK_10",0x2b},
+ 	{"WRITE_VERIFY",0x2e},
+ 	{"VERIFY",0x2f},
+ 	{"SEARCH_HIGH",0x30},
+ 	{"SEARCH_EQUAL",0x31},
+ 	{"SEARCH_LOW",0x32},
+ 	{"SET_LIMITS",0x33},
+ 	{"PRE_FETCH",0x34},
+ 	{"READ_POSITION",0x34},
+ 	{"SYNCHRONIZE_CACHE",0x35},
+ 	{"LOCK_UNLOCK_CACHE",0x36},
+ 	{"READ_DEFECT_DATA",0x37},
+ 	{"MEDIUM_SCAN",0x38},
+ 	{"COMPARE",0x39},
+ 	{"COPY_VERIFY",0x3a},
+ 	{"WRITE_BUFFER",0x3b},
+ 	{"READ_BUFFER",0x3c},
+ 	{"UPDATE_BLOCK",0x3d},
+ 	{"READ_LONG",0x3e},
+ 	{"WRITE_LONG",0x3f},
+ 	{"CHANGE_DEFINITION",0x40},
+ 	{"WRITE_SAME",0x41},
+ 	{"READ_TOC",0x43},
+ 	{"LOG_SELECT",0x4c},
+ 	{"LOG_SENSE",0x4d},
+ 	{"MODE_SELECT_10",0x55},
+ 	{"RESERVE_10",0x56},
+ 	{"RELEASE_10",0x57},
+ 	{"MODE_SENSE_10",0x5a},
+ 	{"PERSISTENT_RESERVE_IN",0x5e},
+ 	{"PERSISTENT_RESERVE_OUT",0x5f},
+ 	{"MOVE_MEDIUM",0xa5},
+ 	{"READ_12",0xa8},
+ 	{"WRITE_12",0xaa},
+ 	{"WRITE_VERIFY_12",0xae},
+ 	{"SEARCH_HIGH_12",0xb0},
+ 	{"SEARCH_EQUAL_12",0xb1},
+ 	{"SEARCH_LOW_12",0xb2},
+ 	{"READ_ELEMENT_STATUS",0xb8},
+ 	{"SEND_VOLUME_TAG",0xb6},
+ 	{"WRITE_LONG_2",0xea}
+ };
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ static volatile int 		internal_done_flag = 0;
+ static volatile int 		internal_done_errcode = 0;
+ static Scsi_Cmnd 		*current_SC = NULL;
+ static int      		this_id = 31;
+ V6INTERFACEB 			V6;
+ // Physical disk table
+ static _DiskIDTable		DiskID[MAXDISK];
+ // Logical disk table
+ LDISKLIST			LDiskID[MAXLDISK];
+ static DISKRWINFO		DiskRWInfo[MAXBOARD][2][2];
+ static IDENTIFY_DATA 		DiskIdentifyData[MAXBOARD][2][2];
+ static int			gBoardCount = 0;
+ IrqID				ultimaID[MAXBOARD];
+ BOARDTABLE			BoardInfo[MAXBOARD];
+ static int			IrqFlag[32] = {0,};
+ static int			DiskCount = 0;
+ ULONG				LastErrorBlock,LastErrorCode;
+ static ULONG			RWStatus;
+ static ULONG			OrderStatus;
+ static ULONG			CurrentDisk;
+ static int      		interrupt_level = 0;
+ static int			HddConnected[MAXBOARD][2][2];
+ static int			HddSupportMode[MAXBOARD][2][2];
+ 
+ /////////////////////////////////////////////////
+ #define IOCTL_LOCK	1
+ static int 			in_ioctl = 0;
+ static int 			in_command = 0;
+ unsigned long 			LockValue = 0;
+ static DECLARE_WAIT_QUEUE_HEAD (WaitingQ);
+ 
+ /////////////////////////////////////////////////
+ UCHAR 				BiosManufacture = 0;
+ UCHAR				cDeviceCode = 0;
+ UCHAR   			cFlashFlag = 0;
+ UCHAR				*Buffer;
+ 
+ char *GetCmdName(char code)
+ {
+ 	int i;
+ 	int count;
+ 	char *s = "unknown function";
+ 
+ 	count = sizeof(CmdName) / sizeof(CMDNAME);
+ 
+ 	for(i=0;i<count;i++) {
+ 		if (CmdName[i].code == code)
+ 			return CmdName[i].name;
+ 	}
+ 	return s;
+ }
+ 
+ static void		print_banner(struct Scsi_Host *shpnt)
+ {
+ 	if (!shpnt)
+ 		return;			/* This won't ever happen */
+ 
+ 	printk("using scsi id %d\n", shpnt->this_id);
+ 
+ 	if (interrupt_level)
+ 		printk(" int %d", interrupt_level);
+ 	else
+ 		printk("<none>");
+ 
+ 	printk("\n");
+ }
+ 
+ static void		aralion_setup(char *str, int *ints)
+ {
+ 	this_id = 31;
+ }
+ 
+ 
+ /* Pause for amount*10 milliseconds */
+ static void		do_pause(ULONG amount)
+ {
+ 	do
+ 	{
+ 		udelay(10 * 1000);
+ 	}
+ 	while (--amount);
+ }
+ 
+ inline static void aralion_make_bus_idle(void)
+ {
+ }
+ 
+ static int      aralion_is_valid_port(int port)
+ {
+ 	return 0;
+ }
+ 
+ static int      aralion_test_loopback(void)
+ {
+ 	return 0;
+ }
+ 
+ static int      aralion_pci_bios_detect(int *irq)
+ {
+ 	struct pci_dev *pdev = NULL;
+ 
+ 	if (!pci_present())
+ 		return 0;
+ 
+ 	memset(BoardInfo,0,sizeof(BoardInfo));
+ 
+ 	do {
+ 		if ((pdev = pci_find_device(ARALION_VENDOR, ULTIMA_DEVICE, pdev)) != NULL) {
+ 			printk("Find %d device\n",gBoardCount);
+ 			//			BoardInfo[gBoardCount].BoardExist = 1;
+ 
+ #ifdef KERNEL240
+ 			BoardInfo[gBoardCount].PrimaryIO 
+ 				= (ULONG) pci_resource_start(pdev,0);
+ 			printk("[%d] Primary IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].PrimaryIO);
+ 			BoardInfo[gBoardCount].SecondaryIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x10; 
+ 			printk("[%d] Secondary IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].SecondaryIO);
+ 			BoardInfo[gBoardCount].PrimaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x20; 
+ 			printk("[%d] Primary DMA IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].PrimaryDmaIO);
+ 			BoardInfo[gBoardCount].SecondaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x30; 
+ 			printk("[%d] Secondary DMA IO=%ld\n",gBoardCount,BoardInfo[gBoardCount].SecondaryDmaIO);
+ 			BoardInfo[gBoardCount].ControlRegister 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x40; 
+ 			printk("[%d] Control Register=%ld\n",gBoardCount,BoardInfo[gBoardCount].ControlRegister);
+ 			BoardInfo[gBoardCount].FlashMemory
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x50; 
+ 			printk("[%d] Flash Memory=%ld\n",gBoardCount,BoardInfo[gBoardCount].FlashMemory);
+ #else
+ 			BoardInfo[gBoardCount].PrimaryIO 
+ 				= (ULONG) pdev->base_address[0] & PCI_BASE_SDDRESS_IO_MASK;
+ 			BoardInfo[gBoardCount].SecondaryIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x10; 
+ 			BoardInfo[gBoardCount].PrimaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x20; 
+ 			BoardInfo[gBoardCount].SecondaryDmaIO 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x30; 
+ 			BoardInfo[gBoardCount].ControlRegister 
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x40; 
+ 			BoardInfo[gBoardCount].FlashMemory
+ 				= (ULONG) (BoardInfo[gBoardCount].PrimaryIO)+0x50; 
+ #endif
+ 
+ 			BoardInfo[gBoardCount].interrupt_level = pdev->irq;
+ 			printk("[%d] Interrupt level=%ld\n",gBoardCount,BoardInfo[gBoardCount].interrupt_level);
+ 
+ 			request_region(BoardInfo[gBoardCount].PrimaryIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].SecondaryIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].PrimaryDmaIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].SecondaryDmaIO, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].ControlRegister, 0x10, "aralion");
+ 			request_region(BoardInfo[gBoardCount].FlashMemory,0x8, "aralion");
+ 
+ 			if (!gBoardCount)
+ 				*irq = pdev->irq;
+ 
+ 			gBoardCount++;
+ 		}
+ 	} while(pdev != NULL);
+ 
+ 
+ 	if (!gBoardCount) {
+ 		printk("Ultima Board not found\n");
+ 		return 0;
+ 	}
+ 
+ 	interrupt_level = BoardInfo[0].interrupt_level;
+ 	return 1;
+ }
+ 
+ ULONG	GetBlockCount(int BoardID,int channel,int drive)
+ {
+ 	int i;
+ 	ULONG nCount;
+ 	UCHAR *p;
+ 	p = (char *) &(DiskIdentifyData[BoardID][channel][drive]);
+ 	if(DiskIdentifyData[BoardID][channel][drive].BIT48 & 0x0400)
+ 		nCount = *((ULONG *) (p + 200));
+ 	else
+ 		nCount = *((ULONG *) (p + 120));
+ 	return nCount;
+ }
+ 
+ int	RequestAllIrq(void) 
+ {
+ 	int			i;
+ 	int			irq;
+ 	int			retcode;
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		irq = BoardInfo[i].interrupt_level;
+ 
+ 		if (!IrqFlag[irq]) {
+ 			IrqFlag[irq] = 1;
+ 			memset(ultimaID[i].signature,0,8);
+ 			memcpy(ultimaID[i].signature,"Ultima",6);
+ 			ultimaID[i].IOPort1 = BoardInfo[i].PrimaryDmaIO;
+ 			ultimaID[i].irq = irq;
+ 
+ 			retcode = request_irq(irq,
+ 					do_ultima_intr, 
+ 					SA_INTERRUPT | SA_SHIRQ, 
+ 					"aralion", 
+ 					&ultimaID[i]);
+ 			if (retcode < 0)
+ 			{
+ 				printk("%d's Board IRQ Failure\n",i);
+ 
+ 				if (retcode == -EINVAL)	{
+ 					printk("scsi: <aralion> IRQ %d is bad!\n", irq);
+ 					printk("                This shouldn't happen!\n");
+ 					printk("                Send mail to faith@acm.org\n");
+ 				}
+ 				else if (retcode == -EBUSY) {
+ 					printk("scsi: <aralion> IRQ %d is already in use!\n",irq);
+ 					printk("                Please use another IRQ!\n");
+ 				}
+ 				else {
+ 					printk("scsi: <aralion> Error getting IRQ %d\n",irq);
+ 					printk("                This shouldn't happen!\n");
+ 					printk("                Send mail to faith@acm.org\n");
+ 				}
+ 				printk("scsi: <aralion> Detected, but driver not loaded (IRQ)\n");
+ 
+ 				return retcode;
+ 			}
+ 		}
+ 	}
+ 	return 0;
+ }
+ 
+ // Flash Read . Get data of address
+ UCHAR		FlashRead(USHORT Address)
+ {
+ 	USHORT Data;
+ 	UCHAR Data2,i,Status;
+ 
+ 	for(i = 0; i< 10000;i++)
+ 	{
+ 		Status = inw(BoardInfo[0].FlashMemory + FLASH_STATUS);
+ 		if(!(Status & 0x1))
+ 			break; 
+ 	}
+ 
+ 	outw(Address,BoardInfo[0].FlashMemory + FLASH_ADDRESS);
+ 	outw(0xF6F6,BoardInfo[0].FlashMemory + FLASH_COMMAND);
+ 
+ 	for(i = 0; i< 10000;i++)
+ 	{
+ 		Status = inw(BoardInfo[0].FlashMemory + FLASH_STATUS);
+ 		if(!(Status & 0x1))
+ 			break;
+ 	}
+ 	Data = inw(BoardInfo[0].FlashMemory);
+ 	Data2 = Data & 0xff;
+ 	return Data2;
+ }
+ 
+ void		FlashWrite(USHORT Address,USHORT Data)
+ {
+ 	UCHAR i,Status;
+ 	for(i = 0; i< 10000;i++)
+ 	{
+ 		Status = inw(BoardInfo[0].FlashMemory + FLASH_STATUS);
+ 		if(!(Status & 0x1))
+ 			break;
+ 	}
+ 	outw(Data,BoardInfo[0].FlashMemory);
+ 	outw(Address,BoardInfo[0].FlashMemory + FLASH_ADDRESS);
+ 	outw(0xF7F7,BoardInfo[0].FlashMemory + FLASH_COMMAND);
+ 	for(i = 0; i< 10000;i++)
+ 	{
+ 		Status = inw(BoardInfo[0].FlashMemory + FLASH_STATUS);
+ 		if(!(Status & 0x1))
+ 			break;
+ 	}
+ }
+ 
+ void		FlashReset (void)
+ {
+ 	FlashWrite(0x5555,0xAA);
+ 	FlashWrite(0x2AAA,0x55);
+ 	FlashWrite(0x5555,0xF0);
+ }
+ 
+ 
+ void		GetChipIDInit(void)
+ {
+ 	FlashWrite(0x5555,0xAA);
+ 	FlashWrite(0x2AAA,0x55);
+ 	FlashWrite(0x5555,0x90);
+ 
+ 	BiosManufacture = FlashRead(0x0000);   /* read manufacture code */
+ 	cDeviceCode = FlashRead(0x0001);     /* read device code */
+ 
+ 	mdelay(40);
+ 
+ 	FlashReset();	 /* for Nomal operaton */
+ 	mdelay(40);
+ }
+ 
+ int GetFlashRomData(void)
+ {
+ 	USHORT FlashAddress;
+ 	UCHAR RomPosition;
+ 	UCHAR CardCount;
+ 	USHORT PageSize;
+ 	int		i, BoardID, Channel, Drive, DiskPosition;
+ 	char	CheckSum = 0;
+ 	ULONG	Lba;
+ 
+ 	memset(&V6,0,sizeof(V6INTERFACEB));
+ 
+ 	FlashAddress = inw(BoardInfo[0].ControlRegister + RAIDTYPE); // offset +6
+ 
+ 	CardCount = inb(BoardInfo[0].ControlRegister + CARDCOUNT);   //offset +8
+ 	CardCount = CardCount & 0x3;
+ 
+ 	RomPosition = (UCHAR) (FlashAddress & 0xF);
+ 	FlashAddress = FlashAddress & 0xFFF0;
+ 
+ 	PageSize = FlashRead((USHORT)(FlashAddress+7));
+ 
+ 	//	printk("PageSize = %u,%u\n",PageSize,sizeof(V6));
+ 
+ 	for(i=0;i<PageSize;i++)
+ 	{
+ 		UCHAR *pData = (UCHAR *)&V6 + i;
+ 		*pData = FlashRead((USHORT)(FlashAddress+i));
+ 		CheckSum += *pData;
+ 		//		printk("%02x ",*pData);
+ 	}
+ 
+ 	//	printk("\n");
+ 
+ 	if (memcmp(&V6,"@^^A",4)) {
+ 		printk("incorrect header\n");
+ 		return 0;
+ 	}
+ 	if (CheckSum != 0) {
+ 		printk("incorrect checksum\n");
+ 		return 0;
+ 	}
+ 	return 1;
+ }
+ 
+ int             ultima_detect(Scsi_Host_Template * tpnt)
+ {
+ 	int             retcode;
+ 	struct Scsi_Host *shpnt;
+ 	int             i, j, statusByte;
+ 	int             flag = 0;
+ 	ULONG			IOPort;
+ 
+ 	tpnt->proc_dir = &proc_scsi_aralion;
+ 	flag = aralion_pci_bios_detect(&interrupt_level);
+ 
+ 	if (!flag) {
+ 		printk("scsi: Ultima not found\n");
+ 		return 0;
+ 	}
+ 
+ 	GetChipIDInit();
+ 	memset(&DiskID,0,sizeof(DiskID));
+ 	memset(&LDiskID,0,sizeof(LDiskID));
+ 	memset(&DiskRWInfo,0,sizeof(DiskRWInfo));
+ 	memset(&DiskIdentifyData,0,sizeof(DiskIdentifyData));
+ 	DiskCount = 0;
+ 
+ 	if(!GetFlashRomData())
+ 		return 0;
+ 	// ultima card reset for each board.
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		DisableInterrupt(i);
+ 		ultima_1cardreset(i);
+ 		EnableInterrupt(i);
+ 	}
+ 
+ #ifdef OLDDETECT
+ 	// Get connected HDD information by IOPort
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		IOPort = BoardInfo[i].PrimaryIO;
+ 		
+ 		// Primary
+ 		SelectFirstChannel(i);
+ 		// Primary Master
+ 		outb(0xA0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		// GetBaseStatus is not known yet.
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][0][0] = 1;
+ 		else
+ 			HddConnected[i][0][0] = 0;
+ 			
+ 		// Primary Slave
+ 		outb(0xB0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][0][1] = 1;
+ 		else
+ 			HddConnected[i][0][1] = 0;
+ 		
+ 		// Secondary
+ 		SelectSecondChannel(i);
+ 		// Secondary Master
+ 		outb(0xA0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][1][0] = 1;
+ 		else
+ 			HddConnected[i][1][0] = 0;
+ 		// Secondary Slave
+ 		outb(0xB0 ,IOPort + DriveSelectPort);
+ 		GetBaseStatus(IOPort, statusByte);
+ 		if(statusByte == 0x50)
+ 			HddConnected[i][1][1] = 1;
+ 		else
+ 			HddConnected[i][1][1] = 0;
+ 	}
+ 
+ #else
+ 	// Get connected HDD information by V6 Information.
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		for(j=0;j<4;j++)
+ 		{
+ 			if(V6.DiskInfo[i][j].PhysicalDrive != 0xFF)
+ 			{
+ 				HddConnected[i][j/2][j%2] = 1;
+ 			}
+ 			else
+ 			{
+ 				HddConnected[i][j/2][j%2] = 0;
+ 			}
+ 			HddSupportMode[i][j/2][j%2] = 0xffff;
+ //			CommandCount[i][j/2] = 0;
+ 		}
+ 	}
+ #endif
+ 	// print the connected HDDs
+ 	for(j=0;j<4;j++)
+ 		printk("HDD:[%d]=%d\n",j,HddConnected[0][j/2][j%2]);
+ 
+ 	// Set DiskID[] information, Identify Disk, Set UDMA mode, Set Disksize.
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		DisableInterrupt(i);
+ 		for(j=0;j<4;j++)
+ 		{
+ 			if(HddConnected[i][j/2][j%2])
+ 			{	
+ 				IdentifyDisk(i,j/2,j%2,&DiskIdentifyData[i][j/2][j%2]);
+ 				SetUDMAMode(i,j/2,j%2);
+ 				DiskID[DiskCount].DiskStatus.BoardID = i;
+ 				DiskID[DiskCount].DiskStatus.Channel = j/2;
+ 				DiskID[DiskCount].DiskStatus.Drive = j%2;
+ 				DiskID[DiskCount].RaidStatus = V6.DiskInfo[i][j].Mode;
+ 				DiskID[DiskCount].DiskStatus.Size = GetBlockCount(i,j/2,j%2);
+ 				LDiskID[V6.DiskInfo[i][j].PhysicalDrive].PhysicalDisk[V6.DiskInfo[i][j].Order].BoardID = i;
+ 				LDiskID[V6.DiskInfo[i][j].PhysicalDrive].PhysicalDisk[V6.DiskInfo[i][j].Order].Channel = j/2;
+ 				LDiskID[V6.DiskInfo[i][j].PhysicalDrive].PhysicalDisk[V6.DiskInfo[i][j].Order].Drive = j%2;
+ 				LDiskID[V6.DiskInfo[i][j].PhysicalDrive].PhysicalDisk[V6.DiskInfo[i][j].Order].Size = GetBlockCount(i,j/2,j%2);
+ 				if(V6.DiskInfo[i][j].Order == 0)
+ 				{
+ 				    LDiskID[V6.DiskInfo[i][j].PhysicalDrive].RaidStatus = V6.DiskInfo[i][j].Mode;
+ 				    // Just to make sure that Diskcount and V6.DiskInfo[i][j].PhysicalDrive doesn't match.
+ 				    DiskID[DiskCount].LogicalDisk = V6.DiskInfo[i][j].PhysicalDrive;
+ 				    DiskCount++;
+ 				}
+ 				printk("Logical Disk Info[%d][%d] diskcount[%d] mode=%d physicaldrive=%d Order=%d\n", 
+ 					i, j, DiskCount, 
+ 					LDiskID[V6.DiskInfo[i][j].PhysicalDrive].RaidStatus, 
+ 					DiskID[DiskCount].LogicalDisk, 
+ 					V6.DiskInfo[i][j].Order
+ 					);
+ 			}
+ 		}
+ 		EnableInterrupt(i);
+ 	}
+ 
+ 
+ 	tpnt->this_id = (this_id & 0x1f);
+ 
+ 	/* Print out a banner here in case we can't
+ 	   get resources.  */
+ 	shpnt = scsi_register(tpnt, 0);
+ 	shpnt->irq = interrupt_level;
+ 	shpnt->io_port = BoardInfo[0].ControlRegister;
+ 	shpnt->n_io_port = 0x10;
+ 	// print_banner(shpnt);
+ 
+ 	if (!interrupt_level)
+ 	{
+ 		printk("scsi: <aralion>"
+ 				" Card Detected, but driver not loaded (no IRQ)\n");
+ 		return 0;
+ 	}
+ 	else
+ 	{
+ 		/* Register the IRQ with the kernel */
+ 		if (RequestAllIrq())
+ 			return 0;
+ 	}
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		BoardInfo[i].PriScatterList = kmalloc(SCATTERLISTSIZE,GFP_ATOMIC);
+ 		BoardInfo[i].SecScatterList = kmalloc(SCATTERLISTSIZE,GFP_ATOMIC);
+ 	}			
+ 	return 1;
+ }
+ 
+ 
+ int             ultima_release(struct Scsi_Host * tpnt)
+ {
+ 	int		i;
+ 	int		irq;
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		irq = BoardInfo[i].interrupt_level;
+ 		if (IrqFlag[irq]) {
+ 			free_irq(irq,&ultimaID[i]);
+ 			IrqFlag[irq] = 0;
+ 		}
+ 		release_region(BoardInfo[i].PrimaryIO,0x10);
+ 		release_region(BoardInfo[i].SecondaryIO,0x10);
+ 		release_region(BoardInfo[i].PrimaryDmaIO,0x10);
+ 		release_region(BoardInfo[i].SecondaryDmaIO,0x10);
+ 		release_region(BoardInfo[i].ControlRegister,0x10);
+ 		release_region(BoardInfo[i].FlashMemory,0x8);
+ 
+ 		kfree(BoardInfo[i].PriScatterList);
+ 		kfree(BoardInfo[i].SecScatterList);
+ 	}
+ 	scsi_unregister(tpnt);
+ 
+ 	return 0;
+ }
+ 
+ // #ifdef DEBUG
+ #if 1
+ void printDMARegister(int BoardID)
+ {
+ 	int i;
+ 	USHORT d1;
+ 
+ 	for(i=0;i<0x10;i++) {
+ 		d1 = inw(BoardInfo[BoardID].ControlRegister + i*2);
+ 		printk("<%02x:%04x> ",i,d1);
+ 	}
+ 	printk("\n");
+ }
+ 
+ void printFlashMemory(int BoardID)
+ {
+ 	int i;
+ 	USHORT d1;
+ 
+ 	for(i=0;i<0x08;i++) {
+ 		d1 = inw(BoardInfo[BoardID].FlashMemory + i*2);
+ 		printk("<%02x:%04x> ",i,d1);
+ 	}
+ 	printk("\n");
+ 	for(i=0;i<0x08;i++) {
+ 		d1 = inb(BoardInfo[BoardID].FlashMemory + i);
+ 		printk("<%02x:%04x> ",i,d1);
+ 	}
+ 	printk("\n");
+ }
+ #endif
+ 
+ inline DISKRWINFO *GetRWInfoPointer(DISKLIST *pDiskList)
+ {
+ 	return (DISKRWINFO *) &DiskRWInfo[pDiskList->BoardID][pDiskList->Channel][pDiskList->Drive];
+ }
+ 
+ void PutLBAvalue(ULONG IOPort1,ULONG lba,ULONG numsectors,
+ 		ULONG DriveSelect)
+ {
+ 	UCHAR	Data[4];
+ 	/////////////////////////////KHG-133s_Big////////////////////////////////	
+ 	if(lba >= 0x10000000){
+ 		Data[0] = (lba & 0xff000000 ) >> 24;
+ 		Data[1] = 0;
+ 		Data[2] = 0;
+ 		outb(0,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		Data[0] = (lba & 0x000000ff);
+ 		Data[1] = (lba & 0x0000ff00) >> 8;
+ 		Data[2] = (lba & 0x00ff0000) >> 16;
+ 		Data[3] = (DriveSelect << 4) | 0xe0;
+ 		outb(numsectors,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		outb(Data[3],IOPort1 + DriveSelectPort);
+ 	}
+ 	else{
+ 		Data[0] = (lba & 0x000000ff);
+ 		Data[1] = (lba & 0x0000ff00) >> 8;
+ 		Data[2] = (lba & 0x00ff0000) >> 16;
+ 		Data[3] = (lba & 0x0f000000) >> 24;
+ 		Data[3] = Data[3] | 0x40 | (DriveSelect << 4) | 0xa0;
+ 
+ 		outb(numsectors,IOPort1 + BlockCountPort);
+ 		outb(Data[0],IOPort1 + BlockNumberPort);
+ 		outb(Data[1],IOPort1 + CylinderLowPort);
+ 		outb(Data[2],IOPort1 + CylinderHighPort);
+ 		outb(Data[3],IOPort1 + DriveSelectPort);
+ 	}
+ 	/////////////////////////////////////////////////////////////////////////
+ }
+ 
+ void DisableInterrupt(int BoardID)
+ {
+ 	USHORT		Intena;
+ 
+ 	//	Intena = inw(BoardInfo[BoardID].ControlRegister + INTENA);
+ 	//	Intena = Intena & 0xfe;
+ 	Intena = 0;
+ 
+ 	printk("Disable Interrupt : %d\n",BoardID);
+ 	outw(Intena,BoardInfo[BoardID].ControlRegister + INTENA);
+ }
+ 
+ void EnableInterrupt(int BoardID)
+ {
+ 	USHORT		Intena;
+ 
+ 	//	Intena = inw(BoardInfo[BoardID].ControlRegister + INTENA);
+ 	//	Intena = Intena | 0x01;
+ 	Intena = 0x03;		//KHG
+ 
+ 	printk("Enable Interrupt : %d\n",BoardID);
+ 	outw(Intena,BoardInfo[BoardID].ControlRegister + INTENA);
+ 	//	printk("EI2 : %d\n",BoardID);
+ }
+ 
+ // int SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status)
+ ULONG SetBoardInterruptFlag(int BoardID,int Channel,DWORD Status)
+ {
+ 	////////////////////////////////////KHG-133s////////////////////////////////////
+ 	ULONG	TempStatus;
+ 	Channel = 0;
+ 
+ 	if (BoardInfo[BoardID].InterruptFlag[Channel] & Status) {
+ 		TempStatus = BoardInfo[BoardID].InterruptFlag[Channel] & 0x00001111;
+ 		if(TempStatus & 0x00001100){
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00001000;
+ 			return 0x00001000;
+ 		}
+ 		else if(TempStatus & 0x00000010){
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00000100;
+ 			return 0x00000100;
+ 		}
+ 		else {
+ 			BoardInfo[BoardID].InterruptFlag[Channel] |= 0x00000010;
+ 			return 0x000000010;
+ 		}
+ 	}
+ 	else {
+ 		BoardInfo[BoardID].InterruptFlag[Channel] = (Status | ORDER_ONE);
+ 		return 0;
+ 	}
+ }
+ 
+ ULONG SetScatterList( Scsi_Cmnd * SCpnt, ULONG lba, ULONG numsectors, ULONG	ReadWrite)
+ {
+ 	struct scatterlist 	*slp;
+ 	int			i,j;
+ 	PPDT_TABLE 		pPDTTable;
+ 	DISKRWINFO		*pRWInfo,*pRWInfo2;
+ 	int			tid = SCpnt->target;
+ 	DWORD			RaidStatus;
+ 	ULONG			TempFlag;
+ 
+ 	// _DiskIDTable { RaidStatus, DISKLIST }
+ 	// this raid status was already set by ultima_detect!!
+ 	RaidStatus = RAID(tid); // Get raid data fron target id
+ 	printk("SetScatterList: RaidStatus = %x\n", RaidStatus);
+ 	
+ 	switch(RaidStatus)
+ 	{
+ #if SECERT_IS_SOLVED
+ 	    case MIRRORING:
+ 		// Setting the Two Drives Same.
+ 		for(j = 0; j < 2; j++)
+ 		{
+ 			pRWInfo = (DISKRWINFO *) &DiskRWInfo[S_BOARD(tid,j)][S_CHAN(tid,j)][S_DRV(tid,j)];
+ 			printk("SetScatterList: [%x] S_BOARD[%x] S_CHAN[%x] S_DRV[%x]\n", j, S_BOARD(tid,j), S_CHAN(tid,j), S_DRV(tid,j));
+ 			
+ 			pRWInfo->StartLba = lba;
+ 			pRWInfo->ListCount = 0;
+ 			pRWInfo->NumSectors = 0;
+ 			pPDTTable = pRWInfo->ScatterList;
+ 			if (SCpnt->use_sg) {
+ 				slp = (struct scatterlist *) SCpnt->request_buffer;
+ 				for(i=0;i<SCpnt->use_sg;i++,slp++) {
+ 					pPDTTable[i].address = virt_to_bus(slp->address);
+ 					pPDTTable[i].length = slp->length;
+ 					pPDTTable[i].EndOfChain = 0;
+ 					pRWInfo->NumSectors += slp->length;
+ 				}
+ 				pPDTTable[i - 1].EndOfChain = 0x80;
+ 				pRWInfo->ListCount = SCpnt->use_sg;
+ 			}
+ 			else {
+ 				pPDTTable[0].address = virt_to_bus(SCpnt->request_buffer);
+ 				pPDTTable[0].length = SCpnt->request_bufflen;
+ 				pPDTTable[0].EndOfChain = 0x80;
+ 				pRWInfo->NumSectors = SCpnt->request_bufflen;
+ 				pRWInfo->ListCount = 1;
+ 			}
+ 		
+ 			pRWInfo->NumSectors /= 512;
+ 		
+ 			pRWInfo->InterruptFlag = ReadWrite | ORDER_ONE;
+ 			#warning hard coded to ORDER_ONE!!!
+ 			SetBoardInterruptFlag(S_BOARD(tid,j),S_CHAN(tid,j),ReadWrite);
+ 		}
+ 		break;
+ #endif
+ 	    default:
+ 		pRWInfo = (DISKRWINFO *) &DiskRWInfo[S_BOARD(tid,0)][S_CHAN(tid,0)][S_DRV(tid,0)];
+ 		printk("SetScatterList: S_BOARD(%x,0) S_CHAN(%x,0) S_DRV(%x,0)\n", S_BOARD(tid,0), S_CHAN(tid,0), S_DRV(tid,0));
+ 	
+ 		pRWInfo->StartLba = lba;
+ 		pRWInfo->ListCount = 0;
+ 		pRWInfo->NumSectors = 0;
+ 		pPDTTable = pRWInfo->ScatterList;
+ 		if (SCpnt->use_sg) {
+ 			slp = (struct scatterlist *) SCpnt->request_buffer;
+ 			for(i=0;i<SCpnt->use_sg;i++,slp++) {
+ 				pPDTTable[i].address = virt_to_bus(slp->address);
+ 				pPDTTable[i].length = slp->length;
+ 				pPDTTable[i].EndOfChain = 0;
+ 				pRWInfo->NumSectors += slp->length;
+ 			}
+ 			pPDTTable[i - 1].EndOfChain = 0x80;
+ 			pRWInfo->ListCount = SCpnt->use_sg;
+ 		}
+ 		else {
+ 			pPDTTable[0].address = virt_to_bus(SCpnt->request_buffer);
+ 			pPDTTable[0].length = SCpnt->request_bufflen;
+ 			pPDTTable[0].EndOfChain = 0x80;
+ 			pRWInfo->NumSectors = SCpnt->request_bufflen;
+ 			pRWInfo->ListCount = 1;
+ 		}
+ 	
+ 		pRWInfo->NumSectors /= 512;
+ 	
+ 		pRWInfo->InterruptFlag = ReadWrite | ORDER_ONE;
+ 		#warning hard coded to ORDER_ONE!!!
+ 		SetBoardInterruptFlag(S_BOARD(tid,0),S_CHAN(tid,0),ReadWrite);
+ 	}
+ 	printk("SetScatterList Done.\n");
+ 	return 0;
+ }
+ 
+ void PrintPDT(PPDT_TABLE  pPDTTable,int count)
+ {
+ 	int i;
+ 
+ 	for(i=0;i<count;i++) {
+ 		printk("%04d : [%08x,%04x,%02x]\n",i,
+ 				pPDTTable[i].address,
+ 				pPDTTable[i].length,
+ 				pPDTTable[i].EndOfChain);
+ 	}	
+ }
+ 
+ void SetIOPort(DISKLIST *pList,USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	USHORT		AddressLow,AddressHi;
+ 	PPDT_TABLE	pPDTTable;
+ 	long		i;
+ 	DISKRWINFO	*pRWInfo;
+ 	ULONG		BoardID,Channel,Drive;
+ 	ULONG		IOPort1,DmaIO;
+ 
+ 	BoardID = pList->BoardID;
+ 	Channel = pList->Channel;
+ 	Drive = pList->Drive;
+ 
+ 	pRWInfo = (DISKRWINFO *) &DiskRWInfo[pList->BoardID][pList->Channel][pList->Drive];
+ 	if (!(OrderFlag & pRWInfo->InterruptFlag)) {
+ 		return ;
+ 	}
+ 
+ 	if(Channel == 0)
+ 	{
+ 		SelectFirstChannel(BoardID);
+ 	}
+ 	else
+ 	{
+ 		SelectSecondChannel(BoardID);
+ 	}
+ 	pPDTTable = BoardInfo[BoardID].PriScatterList;
+ 	IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 	DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	memcpy(pPDTTable,pRWInfo->ScatterList,pRWInfo->ListCount * sizeof(PDT_TABLE));
+ 	BoardInfo[BoardID].ListCount 		= pRWInfo->ListCount;
+ 	BoardInfo[BoardID].NumSectors       = pRWInfo->NumSectors;
+ 	BoardInfo[BoardID].StartLba         = pRWInfo->StartLba;
+ 
+ 	AddressLow = virt_to_bus(pPDTTable) & 0x0000ffff;
+ 	AddressHi = (virt_to_bus(pPDTTable) & 0xffff0000) >> 16;
+ 
+ 	outw(AddressLow,DmaIO + PDTLAR);
+ 	outw(AddressHi,DmaIO + PDTHAR);
+ 
+ 	PutLBAvalue(
+ 			IOPort1,
+ 			BoardInfo[BoardID].StartLba,
+ 			BoardInfo[BoardID].NumSectors,
+ 			Drive);
+ }
+ 
+ void SetIOInformation(int tid,USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	DWORD		RaidStatus;
+ 	int		i;
+ 
+ 	RaidStatus = RAID(tid); // Get raid data fron target id
+ 	switch(RaidStatus)
+ 	{
+ #if SECERT_IS_SOLVED
+ 	    case MIRRORING:
+ 		// Setting the Two Drives Same.
+ 		for(i = 0; i < 2; i++)
+ 		{
+ 			DISKRWINFO 	*pRWInfo = GetRWInfoPointer(&S_DISKLIST(tid,i));
+ 			if (pRWInfo->ListCount) {
+ 				SetIOPort(&S_DISKLIST(tid,i),DmaRW,OrderFlag);
+ 			}
+ 		}
+ 		break;
+ #endif
+ 	    default:
+ 		{
+ 			DISKRWINFO 	*pRWInfo = GetRWInfoPointer(&DiskID[tid].DiskStatus);
+ 			if (pRWInfo->ListCount) {
+ 				SetIOPort(&DiskID[tid].DiskStatus,DmaRW,OrderFlag);
+ 			}
+ 		}
+ 		break;
+ 	}
+ 
+ }
+ 
+ 
+ void SetIDECommand(DWORD Command, DWORD OrderFlag)
+ {
+ 	int i,j;
+ 
+ 	for(i=0;i<MAXBOARD;i++) {
+ 		if (BoardInfo[i].InterruptFlag[0] & OrderFlag) {
+ 			if(BoardInfo[i].StartLba >= 0x10000000)
+ 				Command=BigDiskCommand(Command);
+ 			outb(Command,BoardInfo[i].PrimaryIO + CommandPort);
+ 		}
+ 		/*		
+ 				if (BoardInfo[i].InterruptFlag[1] & OrderFlag) {
+ 				if(BoardInfo[i].StartLba >= 0x10000000)
+ 				Command=BigDiskCommand(Command);
+ 				outb(Command,BoardInfo[i].SecondaryIO + CommandPort);
+ 				}
+ 		 */
+ 	}
+ }
+ 
+ DWORD	BigDiskCommand (DWORD cmnd)
+ {
+ 	switch(cmnd){
+ 		case	IDE_COMMAND_READ_DMA:
+ 			return IDE_COMMAND_READ_DMA_EXT;
+ 		case	IDE_COMMAND_WRITE_DMA:
+ 			return IDE_COMMAND_WRITE_DMA_EXT;
+ 	}
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+ 	return cmnd;
+ }
+ 
+ void SetDMACommand(USHORT DmaRW,DWORD OrderFlag)
+ {
+ 	ULONG		DmaIO;
+ 	int         i,j,k;
+ 
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		for(j=0;j<2;j++)
+ 		{
+ 			for(k=0;k<2;k++)
+ 			{
+ 				if ((OrderFlag & DiskRWInfo[i][j][k].InterruptFlag))
+ 				{
+ 					DmaIO = BoardInfo[i].PrimaryDmaIO;
+ 					outw((0xff00 | HddSupportMode[i][j][k]), DmaIO + UDM_TIM);
+ 					outw(1, DmaIO + DMAMODE);		
+ 					outw(DmaRW,DmaIO + CMDR);
+ 				}
+ 			}
+ 		}
+ 	}
+ }
+ 
+ 
+ static int			ReadDMA(
+ 		Scsi_Cmnd * SCpnt,
+ 		ULONG lba,
+ 		ULONG numsectors)
+ {
+ 	int 			i;
+ 	unsigned long	flags;
+ 	DWORD		RaidStatus;
+ 
+ 	RaidStatus = RAID(SCpnt->target); // Get raid data fron target id
+ 	switch(RaidStatus)
+ 	{
+ 	    case MIRRORING:
+ 		// need to make some algorithm to use two HDD optimized to speed.
+ 		if (numsectors == 0) {
+ 			my_done(DID_ABORT << 16);
+ 			return ERROR_INVALID_SECTORCOUNT;
+ 		}
+ 		SetScatterList(SCpnt,lba,numsectors,READ_STATUS);
+ 		SetIOInformation(SCpnt->target,DMA_READ,ORDER_ONE);
+ 		RWStatus = READ_STATUS;
+ 		OrderStatus = ORDER_ONE;
+ 		SetIDECommand(IDE_COMMAND_READ_DMA,ORDER_ONE);
+ 		SetDMACommand(DMA_READ,ORDER_ONE);
+ 		return 0;	
+ 		break;
+ 	    default:
+ 		if (numsectors == 0) {
+ 			my_done(DID_ABORT << 16);
+ 			return ERROR_INVALID_SECTORCOUNT;
+ 		}
+ 		SetScatterList(SCpnt,lba,numsectors,READ_STATUS);
+ 		SetIOInformation(SCpnt->target,DMA_READ,ORDER_ONE);
+ 		RWStatus = READ_STATUS;
+ 		OrderStatus = ORDER_ONE;
+ 		SetIDECommand(IDE_COMMAND_READ_DMA,ORDER_ONE);
+ 		SetDMACommand(DMA_READ,ORDER_ONE);
+ 		return 0;	
+ 		break;
+ 	}
+ 
+ }
+ 
+ static int			WriteDMA(
+ 		Scsi_Cmnd * SCpnt,
+ 		ULONG lba,
+ 		ULONG numsectors)
+ {
+ 	int 		i;
+ 	unsigned long	flags;
+ 	DWORD		RaidStatus;
+ 
+ 	RaidStatus = RAID(SCpnt->target); // Get raid data fron target id
+ 	switch(RaidStatus)
+ 	{
+ 	    case MIRRORING:
+ 		// write same data to HDD.
+ 		if (numsectors == 0) {
+ 			my_done(DID_ABORT << 16);
+ 			return ERROR_INVALID_SECTORCOUNT;
+ 		}
+ 		SetScatterList(SCpnt,lba,numsectors,WRITE_STATUS);
+ 		SetIOInformation(SCpnt->target,DMA_WRITE,ORDER_ONE);
+ 		RWStatus = WRITE_STATUS;
+ 		OrderStatus = ORDER_ONE;
+ 		SetIDECommand(IDE_COMMAND_WRITE_DMA,ORDER_ONE);
+ 		SetDMACommand(DMA_WRITE,ORDER_ONE);
+ 		return 0;	
+ 		break;
+ 	    default:
+ 		if (numsectors == 0) {
+ 			my_done(DID_ABORT << 16);
+ 			return ERROR_INVALID_SECTORCOUNT;
+ 		}
+ 		SetScatterList(SCpnt,lba,numsectors,WRITE_STATUS);
+ 		SetIOInformation(SCpnt->target,DMA_WRITE,ORDER_ONE);
+ 		RWStatus = WRITE_STATUS;
+ 		OrderStatus = ORDER_ONE;
+ 		SetIDECommand(IDE_COMMAND_WRITE_DMA,ORDER_ONE);
+ 		SetDMACommand(DMA_WRITE,ORDER_ONE);
+ 		return 0;	
+ 		break;
+ 	}
+ 
+ }
+ 
+ void GetUDMAMode(USHORT *mode,USHORT *Timing,
+ 		IDENTIFY_DATA * IdentifyData)
+ {
+ 
+ 	if(IdentifyData->UDMASupport & 0x40){ 
+ 		*mode = 0x46; // mode 6
+ 		*Timing = 0xff22; // mode 6
+ 	}
+ 	else if(IdentifyData->UDMASupport & 0x20){ 
+ 		*mode = 0x45; // mode 5
+ 		*Timing = 0xff33; // mode 5
+ 	}
+ 	else if(IdentifyData->UDMASupport & 0x10){ 
+ 		*mode = 0x44; // mode 4
+ 		*Timing = 0xff44; // mode 4
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x08){ 
+ 		*mode = 0x43; // mode 3
+ 		*Timing = 0xff55; // mode 3
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x04){ 
+ 		*mode = 0x42; // mode 2
+ 		*Timing = 0xff66; // mode 2
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x02){ 
+ 		*mode = 0x41; // mode 1
+ 		*Timing = 0xff77; // mode 1
+ 	} 
+ 	else if(IdentifyData->UDMASupport & 0x01){ 
+ 		*mode = 0x40; // mode 0
+ 		*Timing = 0xff88; // mode 0
+ 	} 
+ #ifdef _7878_
+ 	*mode = 0x44; // mode 4
+ 	*Timing = 0x7878; // safe mode
+ #endif
+ }
+ 
+ void SetUDMAMode(int BoardID, int Channel, int Drive)
+ {
+ 	USHORT 		mode[3],Timing[3];
+ 	ULONG    	IOPort1;
+ 	ULONG		DmaIO;
+ 	char		statusByte=0;
+ 	int i;	
+ 
+ 	if(Channel == 0)
+ 	{
+ 		SelectFirstChannel(BoardID);
+ 	}
+ 	else
+ 	{
+ 		SelectSecondChannel(BoardID);
+ 	}
+ 	IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 	DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	
+ 	
+ 	if(HddConnected[BoardID][Channel][Drive]>0)
+ 	{
+ 		mode[0] = 0xffff;
+ 		Timing[0] = 0xffff;
+ 		GetUDMAMode(&mode[0],&Timing[0],&DiskIdentifyData[BoardID][Channel][Drive]);
+ 		printk("udma mode value = %x\n",mode[0]);
+ 		if(mode[0] == 0xffff)
+ 			return;
+ 		outb(0xA0 + (Drive << 4),IOPort1 + DriveSelectPort);
+ 		for(i=0;i<10000;i++)
+ 		{		
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			udelay(100);	
+ 			if(statusByte & IDE_STATUS_BUSY)
+ 				continue;
+ 			else
+ 				break;	
+ 		}
+ 		outb(0xA0 + (Drive << 4),IOPort1 + DriveSelectPort);
+ 		outb(mode[0],IOPort1 + BlockCountPort);
+ 		outb(0x03,IOPort1 + ErrorPort);
+ 		outb(IDE_COMMAND_ENABLE_MEDIA_STATUS,IOPort1 + CommandPort);
+ 		for(i=0;i<10000;i++)
+ 		{		
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			udelay(100);	
+ 			if(statusByte & IDE_STATUS_BUSY)
+ 				continue;
+ 			else
+ 				break;	
+ 		}
+ 		if(statusByte == 0x50 || statusByte == 0x40)		
+ 		{
+ 			HddSupportMode[BoardID][Channel][Drive] = (((mode[0] << 8) | 0xff) & Timing[0]);
+ 			printk("SetUDMA: SupportMode = %0.4x\n", HddSupportMode[BoardID][Channel][Drive]);
+ 		}
+ 	}
+ 	mdelay(5);
+ 	for(i=0;i<10;i++)
+ 	{
+ 		GetBaseStatus(IOPort1, statusByte);
+ 		if(statusByte & IDE_STATUS_IDLE)
+ 			break;
+ 		else
+ 			mdelay(2);
+ 	}
+ }
+ 
+ static int	IdentifyDisk( 
+ 		int BoardID,
+ 		int Channel, 
+ 		int DriveSelect, 
+ 		IDENTIFY_DATA * IdentifyData)
+ {
+ 	ULONG    	IOPort1,DmaIO,ControlRegister;
+ 	UCHAR   	statusByte;
+ 	USHORT 		*pIdentifyData;
+ 	int             i, j;
+ 	int			flag = 0;
+ 
+ 	if(Channel == 0)
+ 	{
+ 		SelectFirstChannel(BoardID);
+ 	}
+ 	else
+ 	{
+ 		SelectSecondChannel(BoardID);
+ 	}
+ 	IOPort1 = BoardInfo[BoardID].PrimaryIO;
+ 	DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	ControlRegister = BoardInfo[BoardID].ControlRegister;
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 
+ 	for (i=0;i<1000;i++)
+ 	{
+ 		udelay(10);
+ 		GetBaseStatus(IOPort1, statusByte);
+ 		if (!(statusByte & IDE_STATUS_BUSY))
+ 			break;
+ 	}
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+ 	GetBaseStatus(IOPort1, statusByte);
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+ 	GetBaseStatus(IOPort1, statusByte);
+ 	if(statusByte != IDE_STATUS_IDLE)
+ 	{
+ 		outb(IDE_COMMAND_ATAPI_RESET, IOPort1 + CommandPort); //Device reset
+ 		for(i=0; i<3; i++)	//	KHG_20020731
+ 		{
+ 			mdelay(100);
+ 			outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort); 
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			if(statusByte != IDE_STATUS_IDLE)
+ 			{
+ 				outb(0x04, IOPort1 + AlternateStatusPort);
+ 				mdelay(100);
+ 				outb(0x00, IOPort1 + AlternateStatusPort);
+ 			}
+ 			else
+ 			{
+ 				break;
+ 			}
+ 		}
+ 	}
+ 	mdelay(50);
+ 	statusByte = statusByte & 0xc9;
+ 	if (statusByte != IDE_STATUS_DRDY)
+ 	{
+ 		return 0;
+ 	}
+ 
+ 
+ label1:
+ 	for (j = 0; j < 2; j++)
+ 	{
+ 		WaitOnBusy(IOPort1, statusByte);
+ 		outb(IDE_COMMAND_IDENTIFY, IOPort1 + CommandPort);
+ 
+ 		for (i = 0; i < 4; i++)
+ 		{
+ 			WaitForDrq(IOPort1, statusByte);
+ 			if (statusByte & IDE_STATUS_DRQ)
+ 			{
+ 				GetBaseStatus(IOPort1, statusByte);
+ 				break;
+ 			}
+ 			WaitOnBusy(IOPort1, statusByte);
+ 		}
+ 		if (i == 4 && j == 0)
+ 		{
+ 			return 0;
+ 		}
+ 		else
+ 		{
+ 			break;
+ 		}
+ 	}			// end of for (j = 0; j < 2; j++)
+ 
+ 
+ 	if (statusByte & IDE_STATUS_ERROR)
+ 	{
+ 		return 0;
+ 	}
+ 
+ 	WaitOnBusy(IOPort1, statusByte);
+ 
+ 
+ 	if (!(statusByte & IDE_STATUS_DRQ))
+ 	{
+ 		return 0;
+ 	}
+ 
+ 	pIdentifyData = (USHORT *) IdentifyData;
+ 
+ 	outb(((DriveSelect << 4) | 0xA0), IOPort1 + DriveSelectPort);
+ 	mdelay(50);
+ 	GetBaseStatus(IOPort1, statusByte);
+ 	for (i = 0; i < 256; i++)
+ 	{
+ 		pIdentifyData[i] = inw(IOPort1 + DataPort);
+ 	}
+ 	{
+ 		char           *p,c;
+ 		p = (char *) &(IdentifyData->VendorUnique1);
+ 
+ 		for (i = 0; i < 26; i+=2)
+ 		{
+ 			c = p[i];
+ 			p[i] = p[i+1];
+ 			p[i+1] = c;
+ 		}
+ 		p = (char *) &(IdentifyData->ModelNumber);
+ 
+ 		for (i = 0; i < 40; i+=2)
+ 		{
+ 			c = p[i];
+ 			p[i] = p[i+1];
+ 			p[i+1] = c;
+ 		}
+ 	}
+ 
+ 	{
+ 		int mm = 0;
+ 
+ 		for (i = 0; i < 0x1000; i++)
+ 		{
+ 
+ 			GetStatus(IOPort1, statusByte);
+ 
+ 			if ((statusByte & IDE_STATUS_DRQ)
+ 					|| (statusByte & IDE_STATUS_BUSY)
+ 					|| (statusByte & 1) )
+ 			{
+ 				inw(IOPort1 + DataPort);
+ 			}
+ 			else
+ 			{
+ 				break;
+ 			}
+ 		}			// end of for
+ 	}
+ 	return 1;
+ }
+ 
+ char     *ultima_info(struct Scsi_Host *ignore)
+ {
+ 	static char     buffer[128];
+ 	char           *pt;
+ 
+ 	strcpy(buffer, "Aralion Ultima ATA133 IDE RAID MultiCard Driver Version");
+ 	if (strchr(VERSION, ':'))
+ 	{			/* Assume VERSION is an RCS Revision string */
+ 		strcat(buffer, strchr(VERSION, ':') + 1);
+ 		pt = strrchr(buffer, '$') - 1;
+ 		if (!pt)		/* Stripped RCS Revision string? */
+ 			pt = buffer + strlen(buffer) - 1;
+ 		if (*pt != ' ')
+ 			++pt;
+ 		*pt = '\0';
+ 	}
+ 	else
+ 	{			/* Assume VERSION is a number */
+ 		strcat(buffer, " " VERSION);
+ 	}
+ 
+ 	return buffer;
+ }
+ 
+ 
+ int init_module(void) {
+ 	driver_template.module = &__this_module;
+ 	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+ 	if (driver_template.present) {
+ 		return 0;
+ 	}
+ 
+ 	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ 	return -1;
+ }
+ 
+ void cleanup_module( void) {
+ 	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ }
+ 
+ int             ultima_proc_info(char *buffer, char **start, off_t offset,
+ 		int length, int hostno, int inout)
+ {
+ 	const char     *info = ultima_info(NULL);
+ 	int             len;
+ 	int             pos;
+ 	int             begin;
+ 
+ 	if (inout)
+ 		return (-ENOSYS);
+ 
+ 	begin = 0;
+ 	strcpy(buffer, info);
+ 	strcat(buffer, "\n");
+ 
+ 	pos = len = strlen(buffer);
+ 
+ 	if (pos < offset)
+ 	{
+ 		len = 0;
+ 		begin = pos;
+ 	}
+ 
+ 	*start = buffer + (offset - begin);	/* Start of wanted data */
+ 	len -= (offset - begin);
+ 	if (len > length)
+ 		len = length;
+ 
+ 	return (len);
+ }
+ 
+ static int      aralion_arbitrate(void)
+ {
+ 	int             status = 0;
+ 	ULONG   timeout;
+ 
+ 	printk("[ aralion_arbitrate ]\n");
+ 
+ 	return 0;
+ }
+ 
+ static int      aralion_select(int target)
+ {
+ 	int             status;
+ 	ULONG   timeout;
+ 	static int      flag = 0;
+ 
+ 
+ 	printk("[ aralion_select - %d ]\n",target);
+ 	return 0;
+ }
+ 
+ static void            my_done(int error)
+ {
+ 	if (in_command)
+ 	{
+ 		in_command = 0;
+ 		//		printk("my_done\n");
+ 		if (test_and_clear_bit(IOCTL_LOCK,&LockValue) == 0)
+ 			printk("misc clear...\n");
+ 		current_SC->result = error;
+ 		if (current_SC->scsi_done) {
+ 			current_SC->scsi_done(current_SC);
+ 		}
+ 		else
+ 			panic("scsi: <aralion> current_SC->scsi_done() == NULL");
+ 	}
+ 	else
+ 	{
+ 		panic("scsi: <aralion> my_done() called outside of command\n");
+ 	}
+ }
+ 
+ int	CheckScsiError(ULONG Channel,ULONG IOPort1,UCHAR statusByte)
+ {
+ 	ULONG 	lba;
+ 	UCHAR 	Data[4];
+ 	UCHAR	errorByte;
+ 	ULONG 	scsiStatus = 0;
+ 
+ 	if (statusByte & 0x1) {
+ 
+ 		errorByte = inb(IOPort1 + ErrorPort);
+ 		printk("error byte = %x",ErrorPort);
+ 		if (errorByte & IDE_ERROR_BAD_BLOCK)
+ 			scsiStatus = DID_PARITY;
+ 		else if (errorByte & IDE_ERROR_DATA_ERROR)
+ 			scsiStatus = DID_ERROR;
+ 		else if (errorByte & IDE_ERROR_ID_NOT_FOUND)
+ 			scsiStatus = DID_NO_CONNECT;
+ 		else if (errorByte & IDE_ERROR_COMMAND_ABORTED)
+ 			scsiStatus = DID_ABORT;
+ 		else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH )
+ 			scsiStatus = DID_ERROR;
+ 
+ 		Data[3] = inb(IOPort1 + BlockNumberPort);
+ 		Data[2] = inb(IOPort1 + CylinderLowPort);
+ 		Data[1] = inb(IOPort1 + CylinderHighPort);
+ 		Data[0] = inb(IOPort1 + DriveSelectPort) & 0x0f;
+ 
+ 		lba = (Data[0] << 24) + (Data[1] << 16)
+ 			+ (Data[2] << 8) + Data[0];
+ 
+ 		LastErrorBlock = lba;
+ 		LastErrorCode = errorByte & 0x000f;
+ 
+ 		printk("Error! Ch:%d, %02x , %0d\n",Channel,
+ 				(UCHAR) errorByte,lba);
+ 		return scsiStatus;
+ 	}
+ 	else
+ 		return 0;
+ }
+ 
+ void CheckJobFinished(ULONG BoardID,ULONG Channel)
+ {
+ 	ULONG DmaIO;
+ 	USHORT Stat;
+ 	DWORD	i = 0;
+ 
+ 	if (Channel == 1) {
+ 		DmaIO = BoardInfo[BoardID].PrimaryDmaIO;
+ 	}
+ 	else
+ 	{	
+ 		DmaIO = BoardInfo[BoardID].SecondaryDmaIO;
+ 	}
+ 	do {
+ 		Stat = inw(DmaIO + CONSR);
+ 		i++;
+ 	} while ((Stat & 0x01) && (i < 1000));
+ 	if(i>100)
+ 	{
+ 	    printk("CheckJobFinished Error\n");
+ 	}
+ }
+ 
+ void ClearAllIrq(void)
+ {
+ 	ULONG	Channel;
+ 	UCHAR   statusByte = 0;
+ 	UCHAR   statusByte2 = 0;
+ 	ULONG   IOPort1,IOPort2;
+ 	ULONG 	scsiStatus = 0;
+ 	int		i;
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		Channel = inw(BoardInfo[i].ControlRegister + INTSRC) & 0x03;
+ 
+ 		if (Channel == 0) 
+ 			continue;
+ 
+ 		statusByte = statusByte2 = 0;
+ 
+ 		if (Channel != 3 && 
+ 				( (BoardInfo[i].InterruptFlag[0] & OrderStatus) &
+ 				  (BoardInfo[i].InterruptFlag[1] & OrderStatus)
+ 				)
+ 		   )	
+ 			continue;
+ 		if (Channel & 1) {
+ 			IOPort1 = BoardInfo[i].PrimaryIO;
+ 			CheckJobFinished(i,1);
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			BoardInfo[i].InterruptFlag[0] &= (~OrderStatus);
+ 		}
+ 	}
+ }
+ 
+ void            do_ultima_intr(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ 	ULONG	Channel;
+ 	UCHAR   statusByte = 0;
+ 	UCHAR   statusByte2 = 0;
+ 	ULONG   IOPort1,IOPort2;
+ 	ULONG 	scsiStatus = 0;
+ 	IrqID	*pIntID;
+ 	int		i,j,flag;
+ 	int     ClearFlag = 0;
+ 	int		InterruptCount;
+ 	unsigned long flags;
+ 
+ 	spin_lock_irqsave(&io_request_lock, flags);
+ 	pIntID = (IrqID *) dev_id;
+ 
+ 	//	printk("< intr >\n");	
+ 
+ 	if (!pIntID) {
+ 		spin_unlock_irqrestore(&io_request_lock, flags);
+ 		return ;
+ 	}
+ 	/*
+ 	   if (gResetFlag) {
+ 	   for (i=0;i<gBoardCount;i++) {
+ 	   USHORT		Intena;
+ 
+ 	   Channel = inw(BoardInfo[i].ControlRegister + INTSRC);
+ 	   Intena = inw(BoardInfo[i].ControlRegister + INTENA);
+ 	   IOPort1 = BoardInfo[i].PrimaryIO;
+ 	   IOPort2 = BoardInfo[i].SecondaryIO;
+ 	   if (Channel & 1) {
+ 	   CheckJobFinished(i,1);
+ 	   GetBaseStatus(IOPort1, statusByte);
+ 	   }
+ 	   if (Channel & 2) {
+ 	   CheckJobFinished(i,2);
+ 	   GetBaseStatus(IOPort2, statusByte2);
+ 	   }
+ 	   if (statusByte & 0x1) 
+ 	   scsiStatus = CheckScsiError(Channel,IOPort1,statusByte);
+ 
+ 	   if (statusByte2 & 0x1)
+ 	   scsiStatus = CheckScsiError(Channel,IOPort2,statusByte);
+ 	   }
+ 	   spin_unlock_irqrestore(&io_request_lock, flags);
+ 	   return ;
+ 
+ 	   }
+ 	 */
+ 	if (!in_command) {
+ 		ClearAllIrq();
+ 		spin_unlock_irqrestore(&io_request_lock, flags);
+ 		return ;
+ 	}
+ 
+ 	for(i=0;i<gBoardCount;i++) {
+ 		Channel = inw(BoardInfo[i].ControlRegister + INTSRC) & 0x03;
+ 
+ 		if (Channel == 0) 
+ 			continue;
+ 
+ 		flag = 0;
+ 		statusByte = statusByte2 = 0;
+ 
+ 		if (Channel != 3 && 
+ 				( (BoardInfo[i].InterruptFlag[0] & OrderStatus) &
+ 				  (BoardInfo[i].InterruptFlag[1] & OrderStatus)
+ 				)
+ 		   )	
+ 			continue;
+ 		if (Channel & 1) {
+ 			IOPort1 = BoardInfo[i].PrimaryIO;
+ 			CheckJobFinished(i,1);
+ 			GetBaseStatus(IOPort1, statusByte);
+ 			BoardInfo[i].InterruptFlag[0] &= (~OrderStatus);
+ 		}
+ 		if (Channel & 2) {
+ 			IOPort2 = BoardInfo[i].SecondaryIO;
+ 			CheckJobFinished(i,2);
+ 			GetBaseStatus(IOPort2, statusByte2);
+ 			BoardInfo[i].InterruptFlag[1] &= (~OrderStatus);
+ 		}
+ 		if (statusByte & 0x1) 
+ 			scsiStatus = CheckScsiError(Channel,IOPort1,statusByte);
+ 
+ 		if (statusByte2 & 0x1) 
+ 			scsiStatus = CheckScsiError(Channel,IOPort2,statusByte2);
+ 	}
+ 	if (OrderStatus != ORDER_FOUR) {
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if (BoardInfo[i].InterruptFlag[0] & OrderStatus || BoardInfo[i].InterruptFlag[1] & OrderStatus) {
+ 				spin_unlock_irqrestore(&io_request_lock, flags);
+ 				return ;
+ 			}
+ 		}	
+ 		flag = 0;
+ 
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_TWO || BoardInfo[i].InterruptFlag[1] & ORDER_TWO) && (OrderStatus == ORDER_ONE)) {
+ 				flag = 1;
+ 			}
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_THREE || BoardInfo[i].InterruptFlag[1] & ORDER_THREE) && (OrderStatus == ORDER_TWO)) {
+ 				flag = 1;
+ 			}
+ 			if ((BoardInfo[i].InterruptFlag[0] & ORDER_FOUR || BoardInfo[i].InterruptFlag[1] & ORDER_FOUR) && (OrderStatus == ORDER_THREE)) {
+ 				flag = 1;
+ 			}
+ 		}	
+ 
+ 		if (flag) {
+ 			OrderStatus <<= 4;
+ 
+ 			if (RWStatus == READ_STATUS) {
+ 				SetIOInformation(CurrentDisk,DMA_READ,OrderStatus);
+ 				SetIDECommand(IDE_COMMAND_READ_DMA,OrderStatus);
+ 				SetDMACommand(DMA_READ,OrderStatus);
+ 			}
+ 			else {
+ 				SetIOInformation(CurrentDisk,DMA_WRITE,OrderStatus);
+ 				SetIDECommand(IDE_COMMAND_WRITE_DMA,OrderStatus);
+ 				SetDMACommand(DMA_WRITE,OrderStatus);
+ 			}
+ 			spin_unlock_irqrestore(&io_request_lock, flags);
+ 			return ;
+ 		}
+ 		else {
+ 
+ 			my_done(scsiStatus << 16);
+ 			spin_unlock_irqrestore(&io_request_lock, flags);
+ 			return ;
+ 		}
+ 	}
+ 	else {
+ 		for(i=0;i<gBoardCount;i++) {
+ 			if (BoardInfo[i].InterruptFlag[0] & ORDER_FOUR || BoardInfo[i].InterruptFlag[1] & ORDER_FOUR) {
+ 				spin_unlock_irqrestore(&io_request_lock, flags);
+ 				return ;
+ 			}
+ 		}	
+ 	}
+ 	my_done(scsiStatus << 16);
+ 	spin_unlock_irqrestore(&io_request_lock, flags);
+ 
+ 	return;
+ }
+ 
+ void     internal_done(Scsi_Cmnd * SCpnt)
+ {
+ 	internal_done_errcode = SCpnt->result;
+ 	++internal_done_flag;
+ }
+ 
+ int IsSplitter(char c)
+ {
+ 	if (c == ' ' || c == '-' || c == '_')
+ 		return 1;
+ 	else if (c >= '0' && c <= '9')
+ 		return 1;
+ 
+ 	return 0;
+ }
+ 
+ int             ultima_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+ {
+ 	char 			*buf;
+ 	int	 		board,channel,drive,raidmode;
+ 	ULONG			result;
+ 	/*
+ 	   printk("[c=%x : %s,I=%x]\n",
+ 	   (UCHAR) SCpnt->cmnd[0],
+ 	   GetCmdName((UCHAR) SCpnt->cmnd[0]),
+ 	   SCpnt->target);
+ 	 */
+ 	if (in_command) {
+ 		printk("[ ultima_queue c=%x : %s,I=%x]\n",
+ 				(UCHAR) SCpnt->cmnd[0],
+ 				GetCmdName((UCHAR) SCpnt->cmnd[0]),
+ 				SCpnt->target);
+ 		panic("Error! in_command == 1\n");
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+ 		return -1;
+ 	}
+ 	while(test_and_set_bit(IOCTL_LOCK,&LockValue) != 0) {
+ 		//		printk("QW ");
+ 		schedule();
+ 		udelay(1);
+ 	}
+ 	while(in_ioctl) {
+ 		printk("in_ioctl = 1\n");
+ 		udelay(1);
+ 	}
+ 	in_command = 1;
+ 	current_SC = SCpnt;
+ 	current_SC->scsi_done = done;
+ 
+ 	current_SC->SCp.Status              = 0;
+ 	current_SC->SCp.Message             = 0;
+ 	current_SC->SCp.have_data_in        = 0;
+ 	current_SC->SCp.sent_command        = 0;
+ 	current_SC->SCp.phase               = in_arbitration;
+ 
+ 	if (SCpnt->target >= DiskCount || SCpnt->lun > 0) {
+ 		my_done(DID_ABORT << 16);
+ 		return 0;
+ 	}
+ 
+ 	if (SCpnt->target >= DiskCount) {
+ 		my_done(DID_ABORT << 16);
+ 		return 0;
+ 	}
+ 
+ 	board = DiskID[current_SC->target].DiskStatus.BoardID;
+ 	channel = DiskID[current_SC->target].DiskStatus.Channel;
+ 	drive = DiskID[current_SC->target].DiskStatus.Drive;
+ 	raidmode = DiskID[current_SC->target].RaidStatus;
+ 	switch(current_SC->cmnd[0]) {
+ 		case TEST_UNIT_READY:
+ 		case REQUEST_SENSE :
+ 			my_done(0);
+ 			return 0;
+ 
+ 		case MODE_SENSE :
+ 			buf = (char *) current_SC->buffer;
+ 			buf[2] = 0x0;
+ 			my_done(0);
+ 			break;
+ 
+ 		case INQUIRY :
+ 			buf = (char *) current_SC->buffer;
+ 			{
+ 				PINQUIRYDATA    inquiryData
+ 					= (PINQUIRYDATA) current_SC->buffer;
+ 				PIDENTIFY_DATA identifyData =
+ 					&DiskIdentifyData[board][channel][drive];
+ 				int i;
+ 
+ 				memset(buf,0,current_SC->bufflen);
+ 
+ 				buf[4] = sizeof(INQUIRYDATA);
+ 
+ 				//
+ 				// Standard IDE interface only supports disks.
+ 				inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+ 
+ 				//
+ 				// Fill in vendor identification fields.
+ 				{
+ 					unsigned char *p;
+ 					int	i,j;
+ 
+ 					for (i = 0; i < 24; i ++) {  
+ 						inquiryData->VendorId[i] = 0;
+ 					}
+ 					p = (UCHAR *) identifyData->ModelNumber;
+ 					i = 0;
+ 
+ 					while(!IsSplitter(p[i])) {
+ 						inquiryData->VendorId[i] = p[i++];
+ 					}
+ 					inquiryData->VendorId[i] = 0;
+ 
+ 					i++;
+ 					j = 0;
+ 					while (p[i] != ' ' && i < 24) 
+ 						inquiryData->ProductId[j++] = p[i++];
+ 					inquiryData->ProductId[j] = 0;
+ 
+ 				}
+ 				//
+ 				// Initialize unused portion of product id.
+ 				for (i = 0; i < 4; i++) {
+ 					inquiryData->ProductId[12+i] = ' ';
+ 				}
+ 
+ 				//
+ 				// Move firmware revision from IDENTIFY data to
+ 				// product revision in INQUIRY data.
+ 				for (i = 0; i < 4; i += 2) {
+ 					inquiryData->ProductRevisionLevel[i] =
+ 						((UCHAR *)identifyData->FirmwareRevision)[i+1];
+ 					inquiryData->ProductRevisionLevel[i+1] =
+ 						((UCHAR *)identifyData->FirmwareRevision)[i];
+ 				}
+ 			}
+ 			//					printk("Inquiry Success!");
+ 			my_done(0);
+ 			break;
+ 		case READ_6 : 
+ 		case READ_10 :
+ 		case WRITE_6 : 	
+ 		case WRITE_10 :
+ 			{
+ 				ULONG numsectors,lba,i ;
+ 
+ 				if (*current_SC->cmnd == READ_6 || *current_SC->cmnd == WRITE_6) {
+ 					numsectors = (u_long) current_SC->cmnd[4];
+ 					lba = ((u_long) current_SC->cmnd[1] << 16) |
+ 						((u_long) current_SC->cmnd[2] << 8) |
+ 						(u_long) current_SC->cmnd[3];
+ 					lba &= 0x1FFFFF;
+ 				}
+ 				if (*current_SC->cmnd == READ_10 || *current_SC->cmnd == WRITE_10) {
+ 					numsectors = (u_long) current_SC->cmnd[8] |
+ 						((u_long) current_SC->cmnd[7] << 8);
+ 					lba = ((u_long) current_SC->cmnd[2] << 24) |
+ 						((u_long) current_SC->cmnd[3] << 16) |
+ 						((u_long) current_SC->cmnd[4] << 8) |
+ 						(u_long) current_SC->cmnd[5];
+ 				}
+ 
+ 				memset(DiskRWInfo,0,sizeof(DiskRWInfo));
+ 				for(i=0;i<gBoardCount;i++) {
+ 					BoardInfo[i].InterruptFlag[0] = 0;
+ 					BoardInfo[i].InterruptFlag[1] = 0;
+ 				}
+ 				CurrentDisk = current_SC->target;
+ 
+ 				if (*current_SC->cmnd == READ_6 || *current_SC->cmnd == READ_10) {
+ 
+ //					printk("R:[%03d,%08x]\n", numsectors,lba);
+ 					ReadDMA(current_SC,lba,numsectors);
+ 				}
+ 				else {
+ //					printk("W:[%03d,%08x]\n", numsectors,lba);
+ 					WriteDMA(current_SC,lba,numsectors);
+ 				}
+ 			}	
+ 			break;
+ 
+ 		case READ_CAPACITY :
+ 			{
+ 				ULONG block,size;
+ 				IDENTIFY_DATA * IdentifyData;
+ 
+ 				block = DiskID[current_SC->target].DiskStatus.Size;
+ 				buf = (char *) current_SC->buffer;
+ 				size = 512; 
+ 
+ 				*((ULONG *) buf)  = htonl(block - 1);
+ 				*((ULONG *) (buf + 4))  = htonl(size);
+ 			}
+ 
+ 			my_done(0);
+ 			break;
+ 		default:
+ 			my_done(0);
+ 			break;
+ 
+ 	}
+ 	return 0;
+ }
+ 
+ int             ultima_command(Scsi_Cmnd * SCpnt)
+ {
+ 	ultima_queue(SCpnt, internal_done);
+ 	while (!internal_done_flag)
+ 		;
+ 	internal_done_flag = 0;
+ 	return internal_done_errcode;
+ }
+ 
+ 
+ void            print_info(Scsi_Cmnd * SCpnt)
+ {
+ 	ULONG    imr;
+ 	ULONG    irr;
+ 	ULONG    isr;
+ 
+ 
+ 	if (!SCpnt || !SCpnt->host)
+ 	{
+ 		printk("scsi: <aralion> Cannot provide detailed information\n");
+ 		return;
+ 	}
+ 
+ 	printk("%s\n", ultima_info(SCpnt->host));
+ 	return ;
+ 	print_banner(SCpnt->host);
+ 
+ 	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+ 			SCpnt->SCp.phase,
+ 			SCpnt->target,
+ 			*(UCHAR *) SCpnt->cmnd,
+ 			SCpnt->use_sg, SCpnt->request_bufflen);
+ 	printk("sent_command = %d, have_data_in = %d, timeout = %d\n",
+ 			SCpnt->SCp.sent_command,
+ 			SCpnt->SCp.have_data_in, SCpnt->timeout);
+ }
+ 
+ int             ultima_handle(Scsi_Cmnd * SCpnt)
+ {
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+     return 0;
+ }
+ 
+ int             ultima_abort(Scsi_Cmnd * SCpnt)
+ {
+ 	ULONG   flags;
+ 
+ 	if (!in_command)
+ 	{
+ 		return SCSI_ABORT_NOT_RUNNING;
+ 	}
+ 	ultima_cardreset();
+ 	print_info(SCpnt);
+ 	current_SC->SCp.phase |= aborted;
+ 	current_SC->result = DID_ABORT << 16;
+ 
+ 	/* Aborts are not done well. . . */
+ 	if (in_command)
+ 		my_done(DID_ABORT << 16);
+ 
+ 	return SCSI_ABORT_SUCCESS;
+ }
+ 
+ int             ultima_reset(Scsi_Cmnd * SCpnt, unsigned int ignored)
+ {
+ 	ultima_cardreset();
+ 	return SCSI_RESET_WAKEUP;
+ }
+ 
+ int             ultima_1cardreset(int BoardID)
+ {
+ 	int		i,k;
+ 	UCHAR	statusByte,statusByte2;
+ 
+ 
+ 	SelectFirstChannel(BoardID);	
+ 	mdelay(20);
+ 	outw(0x8000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x4000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x0,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 
+ 	SelectSecondChannel(BoardID);
+ 	outw(0x8000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x4000,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	outw(0x0,BoardInfo[BoardID].PrimaryDmaIO + 0x0e);
+ 	mdelay(20);
+ 	   for (i=0;i<200;i++) 
+ 	   {
+ 	   SelectFirstChannel(BoardID);	
+ 	   mdelay(1);
+ 	   outb(0xA0, BoardInfo[BoardID].PrimaryIO + DriveSelectPort);
+ 	   mdelay(5);
+ 	   GetBaseStatus(BoardInfo[BoardID].PrimaryIO, statusByte);
+ 	   mdelay(5);
+ 
+ 	   SelectSecondChannel(BoardID);
+ 	   mdelay(1);
+ 	   outb(0xA0, BoardInfo[BoardID].PrimaryIO + DriveSelectPort);
+ 	   mdelay(5);
+ 	   GetBaseStatus(BoardInfo[BoardID].PrimaryIO, statusByte2);
+ 	   mdelay(5);
+ 
+ 	   if (!(statusByte & 0x80) && !(statusByte2 & 0x80))
+ 	   break;
+ 	   }
+ 
+ 	   for (i=0;i<500;i++) {
+ 	   mdelay(1);
+ 	   }
+ 	for (i=0;i<200;i++) {
+ 		mdelay(20);
+ 	}
+ 	if (HddConnected[BoardID][0][0]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				0,
+ 				0,
+ 				&DiskIdentifyData[BoardID][0][0]);
+ 	}
+ 	if (HddConnected[BoardID][0][1]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				0,
+ 				1,
+ 				&DiskIdentifyData[BoardID][0][1]);
+ 	}
+ 	if (HddConnected[BoardID][1][0]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				1,
+ 				0,
+ 				&DiskIdentifyData[BoardID][1][0]);
+ 	}
+ 	if (HddConnected[BoardID][1][1]) 
+ 	{
+ 		IdentifyDisk(BoardID,
+ 				1,
+ 				1,
+ 				&DiskIdentifyData[BoardID][1][1]);
+ 	}
+ // Added 2003/11/09 by Ashuaria Lee
+ #warning I dont know what to do...
+     return 0;
+ }
+ 
+ 
+ int             ultima_cardreset(void)
+ {
+ 	int		i,j;
+ 
+ 	RWStatus = RESET_STATUS;
+ 
+ 	for(i=0;i<gBoardCount;i++)
+ 	{
+ 		DisableInterrupt(i);
+ 		ultima_1cardreset(i);
+ 		for(j=0;j<4;j++)
+ 		{
+ 			if(HddConnected[i][j/2][j%2]) 
+ 			{
+ 				IdentifyDisk(i,j/2,j%2,&DiskIdentifyData[i][j/2][j%2]);
+ 				SetUDMAMode(i,j/2,j%2);
+ 			}
+ 		}
+ 		EnableInterrupt(i);
+ 	}
+ 	return SCSI_RESET_WAKEUP;
+ }
+ 
+ 
+ int             ultima_biosparam(Scsi_Disk * disk, kdev_t dev,
+ 		int *info_array)
+ {
+ 	int				size;
+ 	int				target;
+ 
+ 	if (MAJOR(dev) != SCSI_DISK0_MAJOR)
+ 	{
+ 		printk("scsi: aralion ultima_biosparam: too many disks");
+ 		return 0;
+ 	}
+ 
+ 	target = MINOR(dev) >> 4;
+ 
+ 	info_array[0] = 16;
+ 	info_array[1] = 63;
+ 
+ 	size = DiskID[target].DiskStatus.Size;
+ 	info_array[2] = size / (info_array[0] * info_array[1]);
+ 
+ 	if (info_array[2] > 1024) { 
+ 		info_array[0] = 0xff;
+ 		info_array[2] =
+ 			(ULONG) size / (info_array[0] * info_array[1]);
+ 	}
+ 	return 0;
+ }
+ 
diff -Ncr linux-2.4.22/drivers/scsi/ultimaraid133/ultima.h linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/ultima.h
*** linux-2.4.22/drivers/scsi/ultimaraid133/ultima.h	1970-01-01 09:00:00.000000000 +0900
--- linux-2.4.22-ashuariadevel/drivers/scsi/ultimaraid133/ultima.h	2003-12-19 20:37:08.000000000 +0900
***************
*** 0 ****
--- 1,272 ----
+ #ifndef _ULTIMA_H
+ #define _ULTIMA_H
+ #include <linux/kdev_t.h>
+ 
+ #ifndef UCHAR 
+ #define UCHAR 	unsigned char
+ #define USHORT	unsigned short
+ #define	ULONG	unsigned long
+ #define DWORD	unsigned long
+ #define BYTE	unsigned char
+ #define	WORD	unsigned short
+ #endif 
+ 
+ #define		ARALION_VENDOR		0x1538
+ #define		ULTIMA_DEVICE		0x0303
+ 
+ #define		READ_STATUS		0x10000000
+ #define		WRITE_STATUS		0x20000000
+ #define		RESET_STATUS		0x40000000
+ #define 	REBUILD_STATUS		0x80000000
+ #define		MIRRORWRITE_STATUS	0x01000000
+ /*
+ #define 	ORDER_FIRST			0x00000001
+ #define 	ORDER_LAST			0x00000010
+ */
+ 
+ #define ORDER_ONE			0x00000001
+ #define ORDER_TWO			0x00000010
+ #define ORDER_THREE			0x00000100
+ #define ORDER_FOUR			0x00001000
+ 
+ 
+ #define DataPort          		0x00
+ #define ErrorPort         		0x01
+ #define BlockCountPort    		0x02
+ #define BlockNumberPort   		0x03
+ #define CylinderLowPort   		0x04
+ #define CylinderHighPort  		0x05
+ #define DriveSelectPort   		0x06 
+ #define CommandPort       		0x07   
+ #define AlternateStatusPort 		0x0E
+ 
+ //////////////////////////////////////////////////////////////////////
+ // FlashMemory Port
+ // outw(Address, BoardInfo[].FlashMemory + FLASH_ADDRESS)
+ #define FLASH_ADDRESS			0x02
+ // outw(Command, BoardInfo[].FlashMemory + FLASH_COMMAND)
+ #define FLASH_COMMAND			0x04
+ // inw(BoardInfo[].FlashMemory + FLASH_STATUS)
+ #define FLASH_STATUS			0x06
+ //
+ // FLASH_COMMAND
+ #define FLASH_COMMAND_READ		0xF6F6
+ #define FLASH_COMMAND_WRITE		0xF7F7
+ //
+ // FLASH_STATUS
+ #define FLASH_STATUS_READY		0x01
+ //////////////////////////////////////////////////////////////////////
+ 
+ #define	SCATTERLISTSIZE			4096
+ 
+ #define	NODISK				0x00000000
+ #define NORMALIDE			0x00000001
+ #define STRIPING_2S			0x00000002
+ #define STRIPING_4S			0x00000003
+ #define MIRRORING			0x00000004
+ #define STRIPMIRRORING_2S		0x00000005
+ #define STRIPMIRRORING_4S		0x00000006
+ #define JBOD				0x00000007
+ //#define STRIPMIRRORING2				
+ 
+ #define NOTAVAILABLE			0x0000ffff
+ #define	ERROR_INVALID_SECTORCOUNT 	0x00000001
+ #define	ERROR_DISK_NOTAVAILABLE		0x00000002
+ #define	ERROR_INVALID_CHANNEL		0x00000003
+ 
+ #define	MAXBOARD			4
+ // MAX number of disk that can be connected
+ #define MAXDISK				16
+ // MAX number of disk that can be included to logical disk
+ #define MAXPDISK			8
+ // MAX number of logicaldisk that can be created(NO RAID may be maximum)
+ #define MAXLDISK			16
+ 
+ 
+ #define	NORMALSTATUS			0x00000000
+ #define DISKSWAPPED			0x00000001
+ #define MIRRORDISABLED			0x00000002
+ #define REBUILDING			0x00000010
+ #define	REBUILDED			0x00000020
+ #define	DISKNOTAVAILABLE		0x80000000
+ 
+ extern int        	ultima_detect( Scsi_Host_Template * );
+ extern int        	ultima_release( struct Scsi_Host * tpnt);
+ extern int        	ultima_command( Scsi_Cmnd * );
+ extern int        	ultima_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
+ extern int        	ultima_abort( Scsi_Cmnd * );
+ extern int        	ultima_reset( Scsi_Cmnd *, unsigned int ); 
+ extern int        	ultima_biosparam( Disk *, kdev_t, int * );
+ extern int        	ultima_handle( Scsi_Cmnd * );
+ extern char * 		ultima_info( struct Scsi_Host * );
+ extern int		ultima_cardreset( void );
+ extern int        	ultima_proc_info( char *buffer, char **start, off_t offset,
+ 				   					int length, int hostno, int inout );
+ 
+ extern struct proc_dir_entry proc_scsi_aralion;
+ 
+ #define ULTIMA_REVID "Aralion ATA133 IDE Raid Controller driver; Revision: LH1.00BCS"
+ 
+ #define ULTIMA_DMA133 { 								\
+ 			next:		NULL,						\
+ 			module:		NULL,						\
+ 			proc_dir: 	NULL,						\
+ 			proc_name:	"Aralion", 					\
+ 			proc_info:     		ultima_proc_info,           		\
+ 			name: "Ultima RAID 133",					\
+ 			detect:    			ultima_detect,			\
+ 			release: 			ultima_release,			\
+ 			info	:			NULL,				\
+ 			ioctl:				NULL,				\
+ 		    command:        	NULL,             				\
+ 		    queuecommand:   	ultima_queue,               			\
+ 		    abort:          	ultima_abort,               			\
+ 			reset:				ultima_reset,			\
+ 			slave_attach:		NULL, 					\
+ 		    bios_param:     	ultima_biosparam,           			\
+ 		    can_queue:      	1, 			 			\
+ 		    this_id:        	15, 			 			\
+ 			present:	0, 						\
+ 		    sg_tablesize:   	16, 			 			\
+ 			cmd_per_lun: 		0,		/* cmds per lun */	\
+ 		    use_clustering: 	DISABLE_CLUSTERING, 				\
+     		use_new_eh_code: 	0};						
+ 
+ typedef struct 
+ {
+ 	char *		buffer;
+ 	unsigned long 	bufferlen;
+ } IoctlParam;
+ 
+ typedef struct
+ {
+ 	char 		signature[8];
+ 	unsigned long 	IOPort1;
+ 	unsigned long 	irq;
+ } IrqID;
+ 
+ typedef struct
+ {
+ 	DWORD		BoardID;
+ 	DWORD		Channel;
+ 	DWORD		Drive;	
+ 	DWORD		Size;
+ } DISKLIST;
+ 
+ typedef struct
+ {
+ 	DWORD		RaidStatus;
+ 	DISKLIST	PhysicalDisk[MAXPDISK];
+ } LDISKLIST;
+ 
+ typedef struct 
+ {
+ 	DWORD		RaidStatus;
+ 	DWORD		LogicalDisk;
+ 	DISKLIST	DiskStatus;
+ } _DiskIDTable;
+ 
+ typedef struct _PDT_TABLE
+ {
+ 	ULONG  		address;   
+ 	USHORT 		length;   
+ 	UCHAR  		Reserved;
+ 	UCHAR  		EndOfChain;
+ } PDT_TABLE, *PPDT_TABLE;
+ 
+ typedef struct
+ {
+ 	PDT_TABLE	ScatterList[128];
+ 	ULONG		ListCount;
+ 	ULONG		NumSectors;
+ 	ULONG		StartLba;
+ 	ULONG		InterruptFlag;
+ } DISKRWINFO;
+ 
+ typedef struct _BOARDTABLE
+ {
+ 	ULONG 		PrimaryIO;
+ 	ULONG 		SecondaryIO;
+ 	ULONG 		PrimaryDmaIO;
+ 	ULONG 		SecondaryDmaIO;
+ 	ULONG 		ControlRegister;
+ 	ULONG		FlashMemory;
+ 	ULONG 		interrupt_level;
+ 	
+ 	PPDT_TABLE	PriScatterList;
+ 	PPDT_TABLE	SecScatterList;
+ 
+ 	ULONG		ListCount;
+ 	ULONG		NumSectors;
+ 	ULONG		StartLba;
+ 	ULONG		InterruptFlag[2];
+ } BOARDTABLE,*PBOARDsTABLE;
+ 
+ typedef struct _V6BDISKINFO
+ {
+ 	UCHAR 		Mode;
+ 	UCHAR 		PhysicalDrive;
+ 	UCHAR 		Order;
+ }V6BDISKINFO,*PV6BDISK;
+ 
+ typedef struct _V6InterfaceB
+ {
+ 	ULONG 		TagField;
+ 	USHORT 		Version;
+ 	UCHAR 		Reserved;
+ 	UCHAR 		StructSize;
+ 	USHORT 		RebuildBit;
+ 	UCHAR 		Mode;
+ 	UCHAR 		IsSafeMode;
+ 	ULONG 		Reserved1;
+ 	ULONG 		BaseHddSize[8];
+ 	V6BDISKINFO 	DiskInfo[4][4];
+ 	UCHAR 		Reserved2[5];
+ 	UCHAR 		ProcInfo[4];
+ 	UCHAR 		Reserved3[151];
+ }V6INTERFACEB,*PV6INTERFACEB;
+ 
+ // GetStatus gets IDE_STATUS_XXX
+ #define GetStatus(BaseIoAddress, Status) Status = inb((BaseIoAddress) + AlternateStatusPort);
+ 
+ // GetBaseStatus gets IDE_????
+ #define GetBaseStatus(BaseIoAddress, Status) \
+ 	    Status = inb(BaseIoAddress + CommandPort);
+ 
+ #define Delayed_Time(delay) { \
+ 	ULONG j = jiffies + delay * HZ; \
+ 	struct wait_queue *wait = NULL; \
+ 	current->timeout = j; \
+ 	interruptible_sleep_on(&wait); }
+ 
+ #define WaitOnBusy(BaseIoAddress, Status) {ULONG i; \
+ 	for (i=0; i<5; i++) { \
+ 		GetStatus((BaseIoAddress), Status); \
+ 			if (Status & IDE_STATUS_BUSY) { \
+ 				udelay(1); \
+ 				continue; \
+ 			} else { \
+ 				break; \
+ 			} \
+ 	} \
+ }
+ 
+ #define WaitForDrq(BaseIoAddress, Status) \
+ { \
+ 	ULONG i; \
+ 	for (i=0; i<1000; i++) { \
+ 		GetStatus(BaseIoAddress, Status); \
+ 			if (Status & IDE_STATUS_BUSY) { \
+ 				udelay(150); \
+ 			} else if (Status & IDE_STATUS_DRQ) { \
+ 				break; \
+ 			} else { \
+ 				udelay(200); \
+ 			} \
+ 	} \
+ }
+ 
+ #endif
+ #define SelectFirstChannel(BoardID) outb(0xA0,BoardInfo[BoardID].SecondaryIO+DriveSelectPort);
+ #define SelectSecondChannel(BoardID) outb(0xB0,BoardInfo[BoardID].SecondaryIO+DriveSelectPort);
+ 	
