[root@proxy ftsrc]# cat fasttrak.c /********************************************************************* * fasttrak.c * * Copyright (C) 1999-2002 Promise Technology, Inc. * May be copied or modified under the terms of the * GNU Lesser General Public License * *********************************************************************/ #include // Ryan Mod #include #include // Ryan Mod // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #include // #include // #include // #include // #include // #include #include "global.h" #include "fasttrak.h" #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #define KERNEL_VERSION_24x #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) MODULE_LICENSE("GPL"); //Actually LGPL #endif unchar bResetController; struct timer_list submit_timer ; // for submit_timer struct timer_list error_timer_ch0 ; // for error_handler struct timer_list error_timer_ch1 ; // for error_handler struct timer_list error_timer_ch2 ; // for error_handler struct timer_list error_timer_ch3 ; // for error_handler struct timer_list Init_Timer; #ifdef KERNEL_VERSION_24x static DECLARE_WAIT_QUEUE_HEAD(Wait24); #else static struct wait_queue *Wait22=NULL; #endif ulong InitTime = 5000 ; // 5 sec unchar *ENGINE ; unchar *P_BVIR ; ScsiEngReq_p CurScsiReq; extern void ft_handler_wrapper(int irq, void *dev_id, struct pt_regs *regs); extern void submit_timer_handler(ulong data); // Support Controller of Device ID // ----------------------------------------------- struct proc_dir_entry proc_scsi_fasttrak = { #ifdef KERNEL_VERSION_24x 0, // PROC_SCSI_FASTTRAK, #else PROC_SCSI_NOT_PRESENT, // PROC_SCSI_FASTTRAK, #endif 8, // length of "FastTrak" "FastTrak", // name of directory entry S_IFDIR | S_IRUGO | S_IXUGO, 2, }; /********************************************************************* * Function: unchar InitGDS( void ) * Description: Initial Global Data Structure * ft_adapter[FT_Max_Ada] * ft_channel[FT_Max_Ch] * ft_drive[FT_Max_Dev] ********************************************************************/ unchar InitGDS( void ) { unchar uc; // initialize ft_adapter[ada] for( uc=0 ; uc < FT_Max_Ada ; uc++ ) { memset(&ft_adapter[uc],0,sizeof(ft_adapter_t)); ft_adapter[uc].id = uc ; ft_adapter[uc].pchannel[0] = (ft_channel_t *)&ft_channel[uc*2+0]; ft_adapter[uc].pchannel[1] = &ft_channel[uc*2+1]; spin_lock_init( &ft_adapter[uc].ft_lock ); } // initialize ft_channel[ch] for( uc=0 ; uc < FT_Max_Ch ; uc++ ) { memset(&ft_channel[uc],0,sizeof(ft_channel_t)); ft_channel[uc].id = uc ; ft_channel[uc].padapter = &ft_adapter[uc/2]; ft_channel[uc].pdrive[0] = &ft_drive[uc*2+0]; ft_channel[uc].pdrive[1] = &ft_drive[uc*2+1]; } // initialize ft_drive[dev] for( uc=0 ; uc < FT_Max_Dev ; uc++ ) { memset(&ft_drive[uc],0,sizeof(ft_drive_t)); ft_drive[uc].id = uc ; ft_drive[uc].pchannel = &ft_channel[uc/2]; ft_drive[uc].select = uc%2 ? 0xB0 : 0xA0 ; } // By Bennett, Initial FastCheck event variable. EventPtr = 0; EventIoctlPtr = 0; return(0); } /********************************************************************* * Function: * int TX4ImprovePerformance(void) * * Description: * To improve TX4 performance by fixing conflict between Intel chip * on TX4 with Intel ChipSets as bellow , * (1) Intel ChipSet Device ID : 0x2440 0x244C 0x2410 0x2420 * solution: PCI configuration offset 0xFF bit 2 , set to 1 * (2) Intel ChipSet Device ID = 0x2418 0x2428 0x244E 0x2448 * solution: PCI configuration offset 0x50 bit 2 , set to 1 *********************************************************************/ void TX4ImprovePerformance(void) { ushort TX4_compatible_1[5] = { 0x2440, 0x244C, 0x2410, 0x2420, 0 } ; ushort TX4_compatible_2[5] = { 0x2418, 0x2428, 0x244E, 0x2448, 0 } ; unchar class ; unchar value ; #ifdef KERNEL_VERSION_24x struct pci_dev *intel_chip_pci_dev = NULL ; #else struct pci_dev *intel_chip_pci_dev = pci_devices ; #endif class = 0 ; while( TX4_compatible_1[class] ) { while( (intel_chip_pci_dev = pci_find_device(PCI_VENDOR_ID_INTEL,TX4_compatible_1[class],intel_chip_pci_dev)) ) { DEB(printk("TX4ImprovePerformance : TX4_compatible_1 : find[%x] %x:%x \n",class,PCI_VENDOR_ID_INTEL,TX4_compatible_1[class]);); pci_read_config_byte(intel_chip_pci_dev,0xFF,&value); pci_write_config_byte( intel_chip_pci_dev,0xFF,value|(1<<2) ); } class++; } // End of while( TX4_compatible_1[class] ) class = 0 ; while( TX4_compatible_2[class] ) { while( (intel_chip_pci_dev = pci_find_device(PCI_VENDOR_ID_INTEL,TX4_compatible_2[class],intel_chip_pci_dev)) ) { DEB(printk("TX4ImprovePerformance : TX4_compatible_2 : find[%x] %x:%x \n",class,PCI_VENDOR_ID_INTEL,TX4_compatible_2[class]);); pci_read_config_byte(intel_chip_pci_dev,0x50,&value); pci_write_config_byte( intel_chip_pci_dev,0x50,value|(1<<2) ); } class++; } // End of while( TX4_compatible_2[class] ) return; } // ----------------------------------------------- unchar init_ioports( unchar ada ) { unchar uc; ft_adapter_t *adapter = &ft_adapter[ada] ; struct pci_dev *ft_pci_dev = adapter->ft_pci_dev; ushort deviceid= ft_pci_dev->device; ushort command ; uint base[6]; for( uc = 0 ; uc < 5 ; uc++ ) { pci_read_config_dword(ft_pci_dev,PCI_BASE_ADDRESS_0+4*uc,&base[uc]); base[uc] = base[uc] & PCI_BASE_ADDRESS_IO_MASK ; if(uc%2) base[uc] += 2 ; // DEB(printk("FastTrak : io_base[%d]:%#x\n",i,temp_p->io_base[i])); } adapter->pchannel[0]->base = base[0] ; adapter->pchannel[0]->ctrl = base[1] ; adapter->pchannel[1]->base = base[2] ; adapter->pchannel[1]->ctrl = base[3] ; adapter->pchannel[0]->bm = base[4] ; adapter->pchannel[1]->bm = base[4] + 8 ; pci_read_config_word(ft_pci_dev,PCI_COMMAND,&command); command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; pci_write_config_word(ft_pci_dev,PCI_COMMAND,command); pci_read_config_dword(ft_pci_dev,0x30,&adapter->rom_base); if( ! ( adapter->pchannel[0]->bm &= 0xFFF0 ) ) return(2); for( uc=0 ; uc < ChPAda ; uc++ ) { // ch per adapter : 2 if( ! check_region(adapter->pchannel[uc]->base,8) ) request_region(adapter->pchannel[uc]->base,8,"FT(base)"); if( ! check_region(adapter->pchannel[uc]->ctrl,1) ) request_region(adapter->pchannel[uc]->ctrl,1,"FT(ctrl)"); if( ! check_region(adapter->pchannel[uc]->bm,8) ) request_region(adapter->pchannel[uc]->bm,8,"FT(BM)"); } // fix-me : if different adapters use same irq - not error if( (ada == 1) && (ft_adapter[0].ft_pci_dev->irq == ft_pci_dev->irq) ) DEB(printk("Two FT adapters request same irq number\n");); else { if( request_irq(ft_pci_dev->irq,ft_handler_wrapper, SA_INTERRUPT | SA_SHIRQ,"FastTrak",&ft_adapter[0])) { printk("FastTrak : adapter%d request_irq() error.\n",ada); return(2); } } if( DID27x(deviceid) ) return(0); // Allow byte alignment for ... , such as PRD Table ... outb( 1 , adapter->pchannel[0]->bm + 0x1A ); outb( 1 , adapter->pchannel[0]->bm + 0x1B ); // Select External Clock if( (deviceid == DID265) || (deviceid == DID267) ) { unchar ctrl_init_sta, uata_clock; ushort sys_ctrl_reg_1F_port = adapter->pchannel[0]->bm + 0x1F ; ushort sys_ctrl_reg_1C_port = adapter->pchannel[0]->bm + 0x1C ; unchar sys_ctrl_reg_1F_data,sys_ctrl_reg_1C_data, outdata; pci_read_config_byte(ft_pci_dev,0x50,&ctrl_init_sta); uata_clock = ( ctrl_init_sta & 0x40 ) << 1 ; sys_ctrl_reg_1F_data = inb(sys_ctrl_reg_1F_port); sys_ctrl_reg_1C_data = inb(sys_ctrl_reg_1C_port); outdata = ( sys_ctrl_reg_1F_data & 0x3F ) | uata_clock ; outb( outdata | 1 , sys_ctrl_reg_1F_port ); // burst outb( sys_ctrl_reg_1C_data | 0x03 , sys_ctrl_reg_1C_port ); DEB( printk("sys_ctrl_reg_1F_port = %p\n",sys_ctrl_reg_1F_port); printk("ctrl_init_sta = %#x\n",ctrl_init_sta); printk("uata_clock = %#x\n",uata_clock); printk("sys_ctrl_reg_1F_data = %#x\n",sys_ctrl_reg_1F_data); printk("outdata = %#x\n",outdata); ); } return(0); } // ------------------------------------------------------------------- int input_data(unchar dev,void *buffer,unsigned wcount) { ushort *ptr=(ushort *)buffer; while(wcount--) { *ptr++=inw(ft_drive[dev].pchannel->base); } return(0); } /********************************************************************* * Function: * unchar identify_device(unchar dev,void *id) * * Return: * 0 success * 1 select time out * 2 identify time out * #3 request_irq() fail *********************************************************************/ unchar identify_device(unchar dev,void *id) { ulong flags; unchar error; ft_channel_t *p = ft_drive[dev].pchannel ; ushort base = p->base ; ushort ctrl = p->ctrl ; ft_drive_t *drive=&ft_drive[dev]; DebFtFun(printk("DebFtFun : identify_device(dev=%d).\n",dev);); if( Check1F7(dev,3*1000,0,BSY) ) return(1); // drive[] busy outb( drive->select , base+6 ) ; outb( drive->select , base+6 ) ; // for 277 if( Check1F7(dev,3,DRDY|SEEK,BSY|DF) ) return(1); // drive[] not exist save_flags(flags); cli(); // free_irq(p->padapter->irq,"FT_IRQ"); // for some special HDDs outb( 2 , ctrl ) ; // disable nIEN outb( drive->select , base+6 ) ; outb( drive->select , base+6 ) ; // for 277 outb( 0xEC , base+7 ) ; error = Check1F7(dev,10*1000,DRDY|SEEK|DRQ,BSY|DF) ; inb(base+7) ; if( error ) error = 2 ; // drive[] not exist else { struct ft_driveid *p_id = (struct ft_driveid *)id; input_data(dev,id,512/2); drive->present = 1 ; drive->LBA_48bit = 0 ; if( (p_id->cmd_set[1] & (1<<10)) && (p_id->cfs[2] & (1<<10)) ) drive->LBA_48bit = 1 ; outb( 0 , ctrl ) ; // Enable nIEN } // if(request_irq(p->padapter->ft_pci_dev->irq,ft_handler_wrapper,SA_INTERRUPT|SA_SHIRQ, // "FastTrak","FT_IRQ")) { // error = 3 ; // printk("FastTrak : request_irq() error in identify.\n"); // } restore_flags(flags); DEB(printk("in identify:dev/error=%d/%#x\n",dev,error);); return(error); } // ------------------------------------------------------------------- int set_feature(unchar dev,unchar *pio_mode,unchar *dma_mode,unchar *udma_mode) { ft_drive_t *drive = &ft_drive[dev]; struct ft_driveid *id = drive->identify; struct pci_dev *ft_pci_dev = drive->pchannel->padapter->ft_pci_dev; ushort deviceid= ft_pci_dev->device ; ushort base = drive->pchannel->base; ushort bm = drive->pchannel->bm; ushort IndexReg= bm + 1 ; ushort DataReg = bm + 3 ; ushort cycle_time, mode, Pin40; unchar xfermode=0, IORDYp; ulong flags; unchar ret, error; if( Check1F7(dev,3*1000,0,BSY) ) return(1); // drive[] busy // --- UDMA & DMA transfer mode if( id->capability & 1) { if( (id->field_valid & 2) && (mode=(id->dma_mword & 0x000F)) ) { xfermode = 0; mode=mode>>1; while(mode) { // --- MDMA transfer mode xfermode++; mode=mode>>1; } *dma_mode = xfermode ; xfermode = 0x20 | *dma_mode ; } if( (id->field_valid & 4) && (mode=(id->dma_ultra & 0x00FF)) ) { xfermode = 0; mode=mode>>1; while(mode) { // --- UDMA transfer mode xfermode++; mode=mode>>1; } if ( drive->downmode && (drive->xfermode & 0x40) ) { xfermode = (drive->xfermode & 0x07) - 1 ; // e.g. ECC drive->downmode = 0 ; } #ifndef Linux_Intel_0140 else if( (deviceid == DID262) && (xfermode > 4) ) xfermode = 4 ; // PDC20262 only supports to UDMA4 else if( DID26x(deviceid) && (xfermode > 5) ) xfermode = 5 ; // PDC20265/267 only support to UDMA5 else if( (deviceid == DID270) && (xfermode > 5) ) xfermode = 5 ; // PDC20270 only support to UDMA5 #else // modify for Intel v2.30.0140.1 else if( (deviceid == DID267) && (xfermode > 5) ) xfermode = 5 ; // PDC20267 only support to UDMA5 else if( (deviceid == DID277) && (xfermode > 5) ) xfermode = 5 ; // PDC20277 support UDMA5 instead of UDMA6 #endif *udma_mode = xfermode ; xfermode = 0x40 | *udma_mode ; } } // Get PIO transfer mode & Check Cable Status (80/40pins) if( DID27x(deviceid) ) { outb( (( drive->select == 0xA0 ) ? 0x13 : 0x1B) , IndexReg ); IORDYp = inb( DataReg ) & ( 1<<2 ) ; outb( 0x0B , IndexReg ); Pin40 = inb( DataReg ) & ( 1<<3 ) ; } else { // PIO Mode on PDC20262/265/267 unchar C_REG , offset; ushort State ; // Controller Initial State offset = ( dev % 4 < 2 ) ? 0x62 : 0x6A ; pci_read_config_byte(ft_pci_dev, offset, &C_REG); IORDYp = C_REG & ( 1<<6 ) ; pci_read_config_word(ft_pci_dev, 0x50, &State); Pin40 = ( dev % 4 >= 2 ) ? State & (1<<11) : State & (1<<10) ; } if( IORDYp ) cycle_time=id->eide_pio_iordy; else cycle_time=id->eide_pio; if (cycle_time > 383) *pio_mode=0; else if(cycle_time > 240) *pio_mode=1; else if(cycle_time > 180) *pio_mode=2; else if(cycle_time > 120) *pio_mode=3; else *pio_mode=4; if( *udma_mode == 0xFF && *dma_mode == 0xFF ) xfermode = 0x08 | *pio_mode ; if( (*udma_mode != 0xFF) && (*udma_mode > 2) && Pin40 ) { printk("Warning: PROMISE IDE%d ",drive->pchannel->id+1); printk("needs 80-pin cable for UDMA%d .\n",*udma_mode); *udma_mode = 2; xfermode = 0x40 | *udma_mode ; printk("Warning: Drive%d Set Feature To UDMA2 \n",dev+1) ; } if( Check1F7(dev,3*1000,0,BSY) ) return(2); // drive[] busy save_flags(flags); cli(); outb( 0x03, base+1 ); outb( xfermode, base+2 ); outb( drive->select, base+6 ); outb( drive->select, base+6 ); // for 277 outb( 0xEF, base+7 ); DEB(printk("xfermode=%#x,select=%#x\n",xfermode,drive->select);); error = Check1F7(dev,3*1000,0,BSY) ; // Setting tHOLD bit to 0 if using UDMA mode 2 if( DID27x(deviceid) && (*udma_mode == 2) ) { outb( 0x10 , IndexReg ); outb( inb(DataReg)&(~(1<<7)) , DataReg ); } restore_flags(flags); if( error ) { printk("FastTrak : PROMISE Set_Feature time out.\n"); return(3); } ft_drive[dev].xfermode = xfermode ; // get new inquiry data after set feature for data structure if( (ret=identify_device(dev,ft_drive[dev].identify)) ) { printk("FastTrak: SF Identify(DEV%d) Error(%d)\n",dev+1,ret); return(4); } return(0); } // ------------------------------------------------------------------- int speed_27x(unchar dev, unchar pio_mode, unchar dma_mode, unchar udma_mode) { ft_drive_t *drive = &ft_drive[dev]; ushort IndexReg = drive->pchannel->bm + 1 ; ushort DataReg = drive->pchannel->bm + 3 ; unchar DataValPIO[5][3] = {{0xFB,0x2B,0xAC},{0x46,0x29,0xA4},{0x23,0x26,0x64},{0x27,0x0D,0x35},{0x23,0x09,0x25}} ; unchar DataValDMA[3][2] = {{0xDF,0x5F},{0x6B,0x27},{0x69,0x25}} ; unchar DataValUDMA[7][3] = {{0x4A,0x0F,0xD5},{0x3A,0x0A,0xD0},{0x2A,0x07,0xCD},{0x1A,0x05,0xCD},{0x1A,0x03,0xCD},{0x1A,0x02,0xCB},{0x1A,0x01,0xCB}} ; unchar IndexVal = (drive->id % 2) ? 0x14 : 0x0C ; unchar ui; // PIO mode for( ui=0 ; ui<2 ; ui++ ) { outb( IndexVal+ui , IndexReg ); outb( DataValPIO[pio_mode][ui] , DataReg ); // printk("PIO - %#x/%#x - %#x/%#x\n",IndexReg,IndexVal+ui,DataReg,DataValPIO[pio_mode][ui]); } outb( IndexVal+7 , IndexReg ); outb( DataValPIO[pio_mode][2] , DataReg ); // printk("PIO - %#x/%#x - %#x/%#x\n",IndexReg,IndexVal+7,DataReg,DataValPIO[pio_mode][2]); // MDMA mode for( ui=0 ; ui<2 ; ui++ ) { outb( IndexVal+2+ui , IndexReg ); outb( DataValDMA[dma_mode][ui] , DataReg ); // printk("DMA - %#x/%#x - %#x/%#x\n",IndexReg,IndexVal+2+ui,DataReg,DataValDMA[dma_mode][ui]); } // UDMA mode for( ui=0 ; ui<3 ; ui++ ) { outb( IndexVal+4+ui , IndexReg ); outb( DataValUDMA[udma_mode][ui] , DataReg ); // printk("UDMA - %#x/%#x - %#x/%#x\n",IndexReg,IndexVal+4+ui,DataReg,DataValUDMA[udma_mode][ui]); } return(0); } // ------------------------------------------------------------------- int speed_26x(unchar dev, unchar pio_mode, unchar dma_mode, unchar udma_mode) { ft_drive_t *drive = &ft_drive[dev]; struct pci_dev *ft_pci_dev = drive->pchannel->padapter->ft_pci_dev; unchar PA=0,PB=0,MB=0,MC=0; unchar A_REG,B_REG,C_REG; unchar offset; switch(pio_mode) { case 0: PA=0x09; PB=0x13; break; case 1: PA=0x05; PB=0x0C; break; case 2: PA=0x03; PB=0x08; break; case 3: PA=0x02; PB=0x06; break; case 4: PA=0x01; PB=0x04; break; } switch(dma_mode) { case 0: MB=0x07; MC=0x0F; break; case 1: MB=0x03; MC=0x04; break; case 2: MB=0x03; MC=0x03; break; } switch(udma_mode) { case 0: MB=0x03; MC=0x03; break; case 1: MB=0x02; MC=0x02; break; case 2: MB=0x01; MC=0x01; break; case 3: MB=0x02; MC=0x02; break; case 4: case 5: MB=0x01; MC=0x01; break; } offset = ( dev % 4 ) * 4 ; if( drive->select == 0xA0 ) A_REG = ( pio_mode >= 3 ) ? 0xF0|PA : 0xD0|PA ; // master drive else A_REG = ( pio_mode >= 3 ) ? 0x70|PA : 0x50|PA ; // slave drive B_REG=MB<<5|PB; C_REG=MC; pci_write_config_byte(ft_pci_dev, 0x60+offset, A_REG); pci_write_config_byte(ft_pci_dev, 0x61+offset, B_REG); pci_write_config_byte(ft_pci_dev, 0x62+offset, C_REG); DEB(printk("bus=%#x,fn=%#x,offset=%d",bus,fn,offset)); DEB(printk("Register:A/B/C=%#x/%#x/%#x\n",A_REG,B_REG,C_REG)); return(0); } // ------------------------------------------------------------------- int set_speed(unchar dev, unchar pio, unchar dma, unchar udma) { ushort deviceid = ft_drive[dev].pchannel->padapter->deviceid ; DebFtFun(printk("%#x/%#x/%#x\n",pio,dma,udma);); if( DID26x(deviceid) ) speed_26x( dev,pio,dma,udma ); else if( DID27x(deviceid) ) { if( deviceid != DID270 ) speed_27x( dev,pio,dma,udma ); } return(0); } /********************************************************************* * Function: * void FreeResource(char force, unchar *str) ; * * Description: * Free Memory Resource and print message if need . ********************************************************************/ void FreeResource(char force, unchar *str) { free_pages((ulong)ENGINE,5); free_pages((ulong)P_BVIR,1); if( force ) printk(str); else DEB(printk(str);); return; } /********************************************************************* * Function: * int fasttrak_proc_info(char *, char **, off_t, int, int, int) * * Description: * in user space , user can view "/proc/scsi/FastTrak/x" * to run fasttrak_proc_info() in kernel space. * PS: * the rebuilding information reported under the condition of * one MIRROR array , not support two MIRROR array concurrently. *********************************************************************/ int fasttrak_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int func) { ft_proc_t info; static char StopFlag = 0 ; if( StopFlag-- ) return(0); info.buffer = buffer; info.length = length; info.offset = offset; info.position = 0; if (start) { *start = buffer; } GetProcInfo(&info); StopFlag = 1; if (info.position > info.offset) return (info.position - info.offset); else return 0; } /********************************************************************* * Function: * int fasttrak_ioctl(Scsi_Device *device,int cmd,void *arg) * * Description: * Ioctl Interface: commands list * . 0x3801: Read FastTrak Status (ft_info_t) * . 0x3802: Read Identify Drive x Data (ft_driveid) * . 0x3803: Read Swap Box Information (ft_swapbox_t) * . 0x3804: Set Disable Mirroring Synchronous Flag * . 0x3805: Control Swap Box power (on/off - 1/0) *********************************************************************/ static int fasttrak_ioctl(Scsi_Device *device,int cmd,void *arg) { uint ui ; unchar *args; if( !arg ) { DEB(printk("fasttrak_ioctl: Unable to handle NULL pointer.\n");); //return(0x10); return -EINVAL ; } args = (unchar *) arg ; switch( cmd ) { // monitor FastTrak Adapter/Array/Drive Status (arg="") case 0x3801 : { memset(args,0,sizeof(ft_info_t)); RepArrInfo(args); return( 0 ); } case 0x3802 : { // Read Identify Data (arg="0") unchar *tmp, error; error = 0 ; if( !(args[0] >= '0' && args[0] <= FT_Max_Dev + '0') ) error = 1 ; else if( !ft_drive[args[0]-'1'].present ) error = 1 ; if( error ) { strcpy(args,"fasttrak_ioctl: Drive not exist.\n"); return(-1); } tmp = (unchar *)ft_drive[args[0]-'1'].identify ; ui = 0 ; do { args[ui] = tmp[ui]; } while( ++ui < 512 ) ; args[ui] = 0 ; return( 0 ); } case 0x3803 : { // Get Swap Box Information unchar *ptr, ret; //memset(&ft_box,0,sizeof(ft_swapbox_t)*FT_Max_Dev); //structure can't not be reset, fix in 1.02.0.25 if( (ret=GetAllSwapInfo()) ) { sprintf(args,"IOCTL: System is busy."); return(ret); } ptr = (unchar *) &ft_box ; ui = 0 ; while( ui < sizeof(ft_swapbox_t)*FT_Max_Dev ) { args[ui] = ptr[ui] ; ui++ ; } return(0); } case 0x3804 : // Enable(1)/Disable(0) Rebuild Option with args[0] return( Ioctl3804(args) ) ; case 0x3805 : { unchar dev,fun; ulong flags; ushort base2; dev = args[0] ; // user count drive from '1' fun = args[1] ; // fun : on/off - '1'/'0' if( (dev < '1') || (dev > '0'+FT_Max_Dev) ) return(-1); if( (fun!='0') && (fun!='1') ) return(-2); dev -= '1'; fun -= '0'; base2 = ft_drive[dev].pchannel->base + 2 ; if( ft_drive[dev].lbusy ) return(-3); // device busy save_flags(flags); cli(); SWAP_STATE(0,dev); if( fun ) // power on outb( 0x12,base2 ); // Green LED else // power off outb( 0x1,base2 ); // RED LED SWAP_STATE(1,dev); restore_flags(flags); return(0); } case 0x3806 : { static int event = 0; snmp_log_t *p; memset(args,0,sizeof(snmp_log_t)); p = (snmp_log_t *)args; if ( !snmp_log_index ) return(-1); while (event < snmp_log_index) { p[event].sequence = snmp_log[event].sequence ; p[event].eventid = snmp_log[event].eventid; p[event].arrayid = snmp_log[event].arrayid; p[event].diskid = snmp_log[event].diskid; event += 1; } p[event].sequence = p[event].eventid = 0 ; p[event].arrayid = p[event].diskid = 0 ; event = snmp_log_index = 0; memset(snmp_log,0,sizeof(snmp_log_t)*50); return(0); } #ifdef Linux_Fujitsu_0060 case 0x3807 : // RAID1 Synchronization return( Ioctl3807(args) ) ; case 0x3808 : return( Ioctl3808(args) ) ; //Disk Write Cache case 0x3809 : return( Ioctl3809(args) ) ; //Flush Cache #endif case 0x380A : case 0x380B : case 0x380C : { extern int ATIoctl(int cmd , unchar *args); DEB(printk("ATIoctl cmd %#x.\n",cmd);); return(ATIoctl(cmd,args)); } case 0x380E : // FastCheck event ioctl ( add by hank & bennett ) return( Ioctl380E( args ) ); case 0x380F : // BIOS flash ioctl ( add by hank & bennett ) return( Ioctl380F( device , args ) ); default : printk("fasttrak_ioctl not support the fun (%#x).\n",cmd); return(-1); } } /********************************************************************* * Function: * init_handler * * Description: * Waitting bInitRAID() terminates. *********************************************************************/ void init_handler(ulong wait) { if(blConfigDoneFlag!=TRUE) { if( wait ) { if( (wait!=InitTime) && !(wait%1000) ) printk("Waiting initial ...\n"); init_timer(&Init_Timer); Init_Timer.expires = jiffies + 5; // 5*10 ms Init_Timer.data = wait-50 ; // 50 ms Init_Timer.function = init_handler; add_timer(&Init_Timer); } return; } #ifdef KERNEL_VERSION_24x wake_up(&Wait24); #else module_wake_up(&Wait22); #endif return; } /********************************************************************* * Function: * FindAdapters24() * * Description: for Linux Kernel 2.2.x & 2.4.x * 1. find controller * 2. find FastTrak adapter ( ClassCode=0x0104 ) *********************************************************************/ int FindAdaptersNumber( void ) { unchar class ; unchar adapters ; #ifdef KERNEL_VERSION_24x struct pci_dev *ft_pci_dev = NULL ; #else struct pci_dev *ft_pci_dev = pci_devices ; #endif class = adapters = 0 ; while( FT_DEVID[class] ) { while( (ft_pci_dev = pci_find_device(PCI_VENDOR_ID_PROMISE,FT_DEVID[class],ft_pci_dev)) ) { if( (ft_pci_dev->class)>>8 == 0x0104 ) { ft_adapter_t *pada = &ft_adapter[adapters]; if( adapters >= FT_Max_Ada ) { printk("FastTrak: The Driver only supports one/two "); printk("FastTrak adapter(s).\n"); printk("Others do not be supported:\n"); printk(" -- FastTrak%s not been enabled.\n", (FT_DEVID[class] == DID262) ? "66" : "100" ); return(adapters); } pada->present = 1; pada->ft_pci_dev= ft_pci_dev; pada->deviceid = ft_pci_dev->device; pada->irq = ft_pci_dev->irq; adapters ++; } } class++; } // End of while( FT_DEVID[class] ) return(adapters); } /********************************************************************* * Function: * FindAdapters() * * Description: * 1. find controller * 2. find FastTrak adapter ( ClassCode=0x0104 ) * 3. request ioports and irq , and then fill out structure *********************************************************************/ int FindAdapters( void ) { unchar uc ; unchar adapters ; unsigned int ldata; unsigned short fwport; if (!pci_present()) { // return non-zero on detection DEB(printk("FastTrak : PCI card is not present. \n")); return 0; } if( !(adapters = FindAdaptersNumber()) ) return(0); for( uc=0 ; uc < FT_Max_Ada ; uc++ ) { if( ft_adapter[uc].present ) { if( init_ioports(uc) ) { printk("FastTrak: init_ioports(%d) error.\n",uc); return(0); } else { // origin by Bennett // read base address #5 pci_read_config_dword( ft_adapter[uc].ft_pci_dev , PCI_BASE_ADDRESS_5 , &ldata ); flash_pmem[uc] = (unsigned char *)ldata; //printk( "Hank: BA#5(flash) = %8.8X\n" , (unsigned int)flash_pmem[uc] ); pci_read_config_word( ft_adapter[uc].ft_pci_dev , PCI_BASE_ADDRESS_4 , &fwport ); fwport &= 0xFFFC; index1[uc] = fwport + 0x09; //printk( "Hank: index1 = %4.4X\n" , index1[uc] ); data1[uc] = fwport + 0x0B; //printk( "Hank: data1 = %4.4X\n" , data1[uc] ); fwport += 0x14; // for flash memory write flash_port[uc] = fwport; //printk( "Hank: Flash Write port = %4.4X\n" , fwport ); } } } return(adapters); } /********************************************************************* * Function: * do_fasttrak_detect * * Description: * Try to detect , initialize and register an FastTrak adapter. * Return non-zero number on detection. * The driver only support one FastTrak adapter now. *********************************************************************/ int do_fasttrak_detect( struct SHT *template ) { unchar dev, result ; unchar adapters ; struct Scsi_Host *shpnt ; ft_adapter_t *ft_ada0; /* * Initial Global Data Structure : * ft_adapter[FT_Max_Ada] * ft_channel[FT_Max_Ch] * ft_drive[FT_Max_Dev] */ if( InitGDS() ) { printk("FastTrak: Initial Global Data Structure fail.\n"); return(0); } InitForSpecificOEM() ; /* * Find Adapter : * 1. find controller * 2. find FastTrak adapter ( ClassCode=0x0104 ) * 3. request ioports and irq , and then fill out structure */ adapters = FindAdapters(); DEB(printk("FastTrak : total %d FastTrak adapter(s).\n",adapters)); if( !adapters ) return(0); TX4ImprovePerformance() ; /* * Register Array : * register arrays to OS not drives to OS .otherwise , * the driver will return(0) on above code. * FastTrak all arrays(0-3) are handled by shpnt(SCSI HOST), * if there are many FastTrak adapters, they can be * define zero device in order to tell user there are * two/three/... FastTrak adapters exist.But they do * not handle any FastTrak array. */ shpnt = scsi_register(template,sizeof(ft_adapter_t)); shpnt -> max_channel = 0 ; // channel: primary shpnt -> max_id = 4 ; // dev : array[0-3] shpnt -> max_lun = 1 ; // one device if( !shpnt->hostdata ) { printk("FastTrak: Bad scsi hostdata for card.\n"); // scsi_unregister(shpnt); release ..... return(0); } ft_ada0 = (ft_adapter_t *) shpnt->hostdata ; memcpy(ft_ada0,&ft_adapter[0],sizeof(ft_adapter_t)); if( adapters >= FT_Max_Ada ) { struct Scsi_Host *shpnt2 ; shpnt2 = scsi_register(template,sizeof(ft_adapter_t)); shpnt2 -> max_channel = 0 ; // channel: primary shpnt2 -> max_id = 0 ; // dev : array[0-3] shpnt2 -> max_lun = 0 ; // one device } /* * Find Drives : * 1. identify to know which drive exist. * 2. if drive exist , and then set feature and speed. * 3. in set_feature() , identify drive once more , * in order to record new information to structure. */ for( dev = 0 ; dev < FT_Max_Dev ; dev++ ) { unchar pio, dma, udma; ft_drive_t *drive = &ft_drive[dev]; ft_channel_t *channel = drive->pchannel ; if(!channel->padapter->present) break; // Adapter does not exist drive->identify = kmalloc(512,GFP_ATOMIC); result = identify_device(dev,drive->identify) ; if( result==1 || result==2 ) continue; // drive not exist // if( result == 3 ) return(0); // irq error DEB(printk("FastTrak : Drive[%d] Exist.\n",dev+1);); DEB(printk("FastTrak : Drive[%d] Exist.\n",dev+1);); pio = dma = udma = 0xFF; if( set_feature(dev,&pio,&dma,&udma) ) { printk("FastTrak: set_feature fail.\n"); return(0); } DEB(printk("Feature(%d) P/D/U = %#x/%#x/%#x\n",dev,pio,dma,udma);); set_speed(dev,pio,dma,udma); } { ///////////// Set AT extern char SetATConf(void) ; SetATConf(); } init_timer(&submit_timer); submit_timer.expires = jiffies + 200; submit_timer.data = 0; submit_timer.function = submit_timer_handler; add_timer(&submit_timer); /* * Initialize RAID ENGINE : * 1. allocate memory for RAID ENGINE arguments * 2. start initialize RAID ENGINE : bInitRAID */ ENGINE = (unchar *) __get_free_pages(GFP_ATOMIC,5); // 5(15B00 bytes) P_BVIR = (unchar *) __get_free_pages(GFP_ATOMIC,1); // 1(1D38 bytes) memset(ENGINE, 0, PAGE_SIZE << 5); memset(P_BVIR, 0, PAGE_SIZE << 1); if( (!ENGINE) || (!P_BVIR) ) { printk("FastTrak : System does not allocate "); printk("enough memory to FastTrak !!\n"); return(0); } bInitRAID(bPOWER_UP,virt_to_bus(ENGINE),ENGINE,0X15B00,P_BVIR); init_timer(&Init_Timer); Init_Timer.expires = jiffies + 5 ; //1*HZ; Init_Timer.data = InitTime ; Init_Timer.function = init_handler; add_timer(&Init_Timer); #ifdef KERNEL_VERSION_24x // sleep_on(&Wait24); interruptible_sleep_on(&Wait24); #else module_interruptible_sleep_on(&Wait22); #endif if( !InitTime ) { FreeResource(1,"FastTrak: bInitRAID Fail.\n"); return(0); } /* * Fill out data structure after RAID initialize * 1. define ft_drive[dev].arr * 2. define ft_drive[dev].strm */ if( DefDriveStruct() ) { FreeResource(1,"FastTrak: Define Drive Structure Error.\n"); return(0); } /* * Initialize SwapBox/PTI LED : * Drive Fail - red light * Normal - green light * Critical - orange light */ InitLED(); /* get swap box info */ for( dev=0 ; dev < FT_Max_Dev ; dev+=2 ) GetSwapInfo(dev); //General rule for proc info CurScsiReq = kmalloc(sizeof(*CurScsiReq),GFP_ATOMIC); InitQueueBuffer(); return(adapters); } /********************************************************************* * Function: * fasttrak_detect * * Description: * Try to detect , initialize and register an FastTrak adapter. * Return non-zero number on detection. * The driver only support one FastTrak adapter now. *********************************************************************/ int fasttrak_detect( struct SHT *template ) { unchar adapters ; char name[20]; extern int ProductName(char *name) ; ProductName(name); printk("PROMISE %s Series Linux Driver ",name); printk(VERSION " " VERDATE"\n"); // spin_unlock_irq(&io_request_lock); DebScsiFun(printk("DebScsiFun : fasttrak_detect(). \n");); template -> proc_dir = &proc_scsi_fasttrak; template -> proc_info = fasttrak_proc_info; adapters = do_fasttrak_detect( template ); // spin_lock_irq(&io_request_lock); return(adapters); } /*********************************************************** * Function: * fasttrak_queuecommand * * Description: * cmd - SCSI command. * fn - function called on completion. ***********************************************************/ extern int do_queuecommand(ScsiEngReq_p p); int fasttrak_queuecommand(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) { ushort us; int ret; ulong my_flags; ft_adapter_t *ft_ada0 = (ft_adapter_t *) cmd->host->hostdata ; DebScsiFun(printk("DebScsiFun : fasttrak_queuecommand()\n");); if( !ft_ada0 ) ; // only avoid warning on UP compiling spin_lock_irqsave(&ft_ada0->ft_lock,my_flags); memset(CurScsiReq,0,sizeof(*CurScsiReq)); CurScsiReq->cmd = (void *)cmd ; CurScsiReq->fn = (void *)fn ; CurScsiReq->target = cmd->target ; CurScsiReq->use_sg = cmd->use_sg ; CurScsiReq->buffer = (unchar *)cmd->buffer ; CurScsiReq->sense = (unchar *)cmd->sense_buffer ; for( us=0 ; us < 12 ; us ++ ) CurScsiReq->cmnd[us] = cmd->cmnd[us] ; if(cmd->use_sg) { struct scatterlist *sgpnt; sgpnt = (struct scatterlist *) cmd->request_buffer; for( us=0 ; us < cmd->use_sg ; us++ ) { CurScsiReq->WStartAddr[us] = virt_to_bus(sgpnt[us].address) ; CurScsiReq->WCount[us] = sgpnt[us].length ; } CurScsiReq->WCount[us] |= (1<<31); // EOT=1 } ret = do_queuecommand( CurScsiReq ) ; spin_unlock_irqrestore(&ft_ada0->ft_lock,my_flags); return( ret ) ; } /*********************************************************** * Function: * EndRequest(unchar id,int result) * * Description: * End SCSI request and return to SCSI high/middle level ***********************************************************/ char EndRequest(void *cmnd,void *fun,int result) { Scsi_Cmnd *cmd; *cmd = (Scsi_Cmnd *)cmnd ; void (*fn)(Scsi_Cmnd *) = (void *)fun ; cmd->result = result ; cmd->scsi_done = fn ; fn(cmd); DEB(printk("End SCSI request .\n")); return(0); } /*********************************************************** * Function: * fasttrak_abort * * Description: * cmd - SCSI command. ***********************************************************/ int fasttrak_abort(Scsi_Cmnd *cmd) { // This is called when a scsi cmnd timeout at the os level // Returning SCSI_ABORT_ERROR will cause the os to call our // reset routine. This is how miniport handles timeouts. printk("fasttrak_abort: returning SCSI_ABORT_ERROR\n"); return SCSI_ABORT_ERROR; } int fasttrak_abort_eh(Scsi_Cmnd *cmd) { printk("fasttrak_abort_eh: returning SCSI_ABORT_ERROR\n"); return SCSI_ABORT_ERROR; // 0x05 } /*********************************************************** * Function: * fasttrak_reset * * Description: * cmd - SCSI command. * reset_flags - reset flags. ***********************************************************/ extern int reset_controller(void); int fasttrak_reset(Scsi_Cmnd *cmd, unsigned int reset_flags) { printk("fasttrak_reset: returning SCSI_RESET_SUCCESS\n"); reset_controller(); return SCSI_RESET_SUCCESS; } int fasttrak_reset_eh(Scsi_Cmnd *cmd) { printk("fasttrak_reset_eh: returning SCSI_RESET_SUCCESS\n"); reset_controller(); return SCSI_RESET_SUCCESS; // 0x02 } /*********************************************************** * Function: * fasttrak_bios_param * * Description: * This function returns unit geometry in cylinders/heads/sectors ***********************************************************/ int fasttrak_bios_param(Disk *disk, kdev_t dev, int Geometry[]) { Geometry[0]=64; // heads Geometry[1]=32; // sectors Geometry[2]=disk->capacity / (Geometry[0]*Geometry[1]); // cylinders if (disk->capacity > 0x200000) { // 1GB Geometry[0]=255; // heads Geometry[1]=63; // sectors Geometry[2]=disk->capacity/(Geometry[0]*Geometry[1]); // cylinders // capacity larger than 526GB(C/H/S = 65535/255/63) if (Geometry[2] > 65535) { Geometry[2] = 65535; Geometry[1] = disk->capacity / (Geometry[2]*Geometry[0]); } } return 0; } // ----------------------------------------------- ulong wV2P(unchar *p_b,unchar *p_wCount) { ulong addr; DebEngFun(printk("DebEngFun : wV2P(0x%-lx)\n",(ulong)p_b);); addr = virt_to_bus(p_b); return((ulong)cpu_to_le32(addr)); } // ----------------------------------------------- unchar *p_P2V(ulong wAddr,ushort hCount) { DebEngFun(printk("DebEngFun : p_P2V(0x%-lx)\n",wAddr);); return((unchar *)bus_to_virt(wAddr)); } // ----------------------------------------------- #ifdef MODULE Scsi_Host_Template driver_template = FASTTRAK; #include int init_module(void) { driver_template.module = &__this_module; scsi_register_module(MODULE_SCSI_HA, &driver_template); if (driver_template.present) { return 0; } free_pages((ulong)ENGINE,5); free_pages((ulong)P_BVIR,1); scsi_unregister_module(MODULE_SCSI_HA, &driver_template); return -1; } void cleanup_module(void) { unchar ch; uint irq0, irq1; del_timer(&submit_timer); del_timer(&error_timer_ch0); del_timer(&error_timer_ch1); del_timer(&error_timer_ch2); del_timer(&error_timer_ch3); irq0 = ft_adapter[0].ft_pci_dev->irq ; free_irq(irq0,&ft_adapter[0]) ; if(ft_adapter[1].present) { irq1 = ft_adapter[1].ft_pci_dev->irq ; if(irq0 != irq1) free_irq(irq1,&ft_adapter[0]) ; } for( ch=0 ; ch < FT_Max_Ch ; ch++ ) { if(ft_channel[ch].padapter->present) { release_region(ft_channel[ch].base,8); release_region(ft_channel[ch].ctrl,1); release_region(ft_channel[ch].bm,8); } } free_pages((ulong)ENGINE,5); free_pages((ulong)P_BVIR,1); driver_template.proc_dir = &proc_scsi_fasttrak; scsi_unregister_module(MODULE_SCSI_HA, &driver_template); driver_template.proc_dir = &proc_scsi_fasttrak; return; } #endif [root@proxy ftsrc]#