/* Copyright (c) 1998-2003 VIA Technologies, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Name: viapubraid.c Description: Source code for VIA RAID Controller. */ #include "viapubraid.h" #include "viaprvdef.h" //static spinlock_t gio_request_lock = SPIN_LOCK_UNLOCKED; static spinlock_t queue_request_lock = SPIN_LOCK_UNLOCKED; Scsi_Cmnd *viaraid_req_last = 0; struct Scsi_Host *via_vhost; /* virtual scsi host */ #ifdef MULTIPLE_CARD_SUPPORT unsigned int DEVICE_ID[]={ 0x3249, 0x3164, 0x3149}; #endif int via_write_config_dword(struct pci_dev *dev, int where, u32 val); int via_write_config_byte(struct pci_dev *dev, int where, u8 val); int via_read_config_dword(struct pci_dev *dev, int where, u32 *val); int via_read_config_byte(struct pci_dev *dev, int where, u8 *val); ULONG GetDeviceExtensionSize(void * HwDeviceExtension); void * via_memcpy(void * dst,const void * src ,unsigned sz); void * via_memset(void * pos,int val,unsigned sz); void TaskQueue(); unsigned char ScsiPortReadPortUchar(unsigned char * port); void ScsiPortWritePortUchar(unsigned char * port, unsigned char value); unsigned short ScsiPortReadPortUshort(unsigned short * port); void ScsiPortWritePortUshort(unsigned short * port, unsigned short value); void ScsiPortReadPortBufferUshort(unsigned short * port, unsigned short * value, ULONG count); void ScsiPortWritePortBufferUshort(unsigned short * port, unsigned short * value, ULONG count); void ScsiPortStallExecution(ULONG s); void ScsiPortMoveMemory(void * WriteBuffer, void * ReadBuffer, ULONG Length); ULONG ScsiPortReadPortUlong(ULONG* port); void ScsiPortWritePortUlong(ULONG * port, ULONG value); void ScsiPortReadPortBufferUlong(ULONG * port, ULONG * value, ULONG count); void ScsiPortWritePortBufferUlong(ULONG * port, ULONG * value, ULONG count); void via_kfree(const void *obj); void *via_kmalloc(size_t sz, int val); void via_scsi_done(Scsi_Cmnd* SCpnt); void via_free_irq(unsigned int level, void * para); void* via_get_free_page(unsigned int mask); void via_add_timer(struct timer_list * timer); int via_del_timer_sync(struct timer_list * timer); int via_memcmp(const void *,const void *,__kernel_size_t); int via_request_irq(unsigned int level, void (*handler)(int, void *, struct pt_regs *), unsigned long id, const char * name, void * misc); struct resource * via_request_region(unsigned long start, unsigned long n, const char *name); void via_strcpy(char* dst, char* src); unsigned long via_virt_to_phys(void*); extern void execute_cmd(CmdInfo* SCpnt); //extern int get_diskinfo_size(); //extern int get_diskraidcfg_size(); //extern int get_adapterinfo_size(); /***************************************************** **Name: **Interrupt handler. ******************************************************/ EXPORT_NO_SYMBOLS; void viaraid_intr(int irq,void *dev_id,struct pt_regs *regs) { unsigned long flags; #ifdef VIARAID_DEBUG _Debug_Printf_Service("Entering irq %d\n",irq); #endif spin_lock_irqsave (&io_request_lock, flags); viaraid_intrrupt(irq,dev_id,regs); spin_unlock_irqrestore (&io_request_lock, flags); #ifdef VIARAID_DEBUG _Debug_Printf_Service("leave irq.\n"); #endif } int viaraid_QueueCommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { unsigned long flags; #ifdef VIARAID_DEBUG _Debug_Printf_Service("Enter queueCommand function.\n"); #endif SCpnt->scsi_done = (void *)done; spin_lock_irqsave(&queue_request_lock, flags); if(viaraid_req_last==NULL) SCpnt->SCp.ptr = (char*)SCpnt; else { SCpnt->SCp.ptr = viaraid_req_last->SCp.ptr; viaraid_req_last->SCp.ptr = (char*)SCpnt; } viaraid_req_last = SCpnt; spin_unlock_irqrestore (&queue_request_lock, flags); if(Driver_Free()) { // spin_lock_irqsave(&gio_request_lock, flags); TaskQueue(); // spin_unlock_irqrestore (&gio_request_lock, flags); } return 0; } /**************************************************************** * Name: internal_done :LOCAL * Description: Done handler for non-queued commands * Parameters: SCpnt - Pointer to SCSI command structure. * Returns: Nothing. ****************************************************************/ static void internal_done (Scsi_Cmnd * SCpnt) { SCpnt->SCp.Status++; } /**************************************************************** * Name: viaraid_Command * Description: Process a command from the SCSI manager. * Parameters: SCpnt - Pointer to SCSI command structure. * Returns: Status code. ****************************************************************/ int viaraid_Command(Scsi_Cmnd *SCpnt) { unsigned long timeout; SCpnt->SCp.Status = 0; viaraid_QueueCommand (SCpnt, internal_done); timeout = jiffies + 60 * HZ; // should be longer than hard-reset time while (!SCpnt->SCp.Status && time_before(jiffies, timeout)) barrier(); if (!SCpnt->SCp.Status) SCpnt->result = (DID_ERROR<<16); return SCpnt->result; } extern void testfun(); int viaraid_Detect(Scsi_Host_Template *tpnt){ struct pci_dev *pPciDev; //void * privat_data; int retval=0; #ifdef MULTIPLE_CARD_SUPPORT int i; #endif printk(_VERSIONINFO); if (!pci_present()) { #ifdef VIARAID_DEBUG _Debug_Printf_Service("PCI BIOS not present\n"); #endif return 0; } pPciDev = NULL; GlobalAdapterIndex=0; //privat_data=via_kmalloc(GetDeviceExtensionSize(NULL),GFP_KERNEL); #ifdef MULTIPLE_CARD_SUPPORT for(i=0;i=MAXCONTROLLER) break; via_vhost = scsi_register(tpnt, GetDeviceExtensionSize(NULL)); via_vhost->io_port = 0; via_vhost->n_io_port = 0; via_vhost->max_channel = 0; via_vhost->max_id = MAXDISKS; via_vhost->max_lun = 1; via_vhost->unique_id = GlobalAdapterIndex; retval=Init_Func(pPciDev,via_vhost->hostdata); if(retval==0)DEBUG_PRINT("Controller %d Init failed!\n",GlobalAdapterIndex); // GlobalAdapterIndex++; } } #else while((pPciDev=pci_find_device(VENDOR_ID,DEVICE_ID,pPciDev))){ //find one device, DEBUG_PRINT("find one device %d\n",GlobalAdapterIndex); if(GlobalAdapterIndex>=MAXCONTROLLER) break; via_vhost = scsi_register(tpnt, GetDeviceExtensionSize(NULL)); via_vhost->io_port = 0; via_vhost->n_io_port = 0; via_vhost->max_channel = 0; via_vhost->max_id = MAXDISKS; via_vhost->max_lun = 1; via_vhost->unique_id = GlobalAdapterIndex; retval=Init_Func(pPciDev,via_vhost->hostdata); if(retval==0)DEBUG_PRINT("Controller %d Init failed!\n",GlobalAdapterIndex); // GlobalAdapterIndex++; } #endif if(GlobalAdapterIndex){ return 1; } return 0; } /************************************************* **Name: viaraid_release **release function. **************************************************/ int viaraid_Release (struct Scsi_Host *pshost) { // int i; // PDiskInfo Disk = NULL; #ifdef DYF_DEBUG #ifdef VIARAID_DEBUG _Debug_Printf_Service("Enter Release function.\n"); #endif #endif #ifdef VIARAID_DEBUG _Debug_Printf_Service(KERN_INFO "Goodbye.\n"); #endif Release_Fun(pshost->hostdata); scsi_unregister(pshost); return 0; } /**************************************************************** * Name: viaraid_BiosParam * Description: Process the biosparam request from the SCSI manager to * return C/H/S data. * Parameters: disk - Pointer to SCSI disk structure. * dev - Major/minor number from kernel. * geom - Pointer to integer array to place geometry data. * Returns: zero. ****************************************************************/ int viaraid_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[]) { int heads, sectors, cylinders; #ifdef DYF_DEBUG #ifdef VIARAID_DEBUG _Debug_Printf_Service("Enter BiosParam function.\n"); #endif #endif sectors = 0x3f; heads = get_head_number(disk->capacity); cylinders = disk->capacity / (heads * sectors); /* return result */ geom[0] =heads; //head geom[1] = sectors; //sectors geom[2] = cylinders; //cylinder return 0; } /************************************************* **proc information **************************************************/ #undef SPRINTF #define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } int viaraid_ProcInfo (char *buffer, char **start, off_t offset,int length, int hostno, int inout) { unsigned long flags; char *pos=buffer; save_flags(flags); cli(); SPRINTF("%s",_VERSIONINFO); restore_flags(flags); if((pos-buffer)SCp.ptr; gSCpnt=SCpnt; if (viaraid_req_last==SCpnt) viaraid_req_last = NULL; else viaraid_req_last->SCp.ptr = (char*)SCpnt->SCp.ptr; spin_unlock_irqrestore (&queue_request_lock, flags); cmdinfo.index=SCpnt->host->hostdata;//unique_id; cmdinfo.target=SCpnt->target; cmdinfo.lun=SCpnt->lun; cmdinfo.cmd_len=SCpnt->cmd_len; cmdinfo.request_bufflen=SCpnt->request_bufflen; cmdinfo.request_buffer=SCpnt->request_buffer; cmdinfo.sense_buffer=SCpnt->sense_buffer; memcpy(cmdinfo.cmnd,SCpnt->cmnd,SCpnt->cmd_len); cmdinfo.sc_data_direction=SCpnt->sc_data_direction; execute_cmd(pcmdinfo); goto start_exe; } out: return; } int via_write_config_dword(struct pci_dev *dev, int where, u32 val) { return pci_write_config_dword(dev,where, val); } int via_write_config_byte(struct pci_dev *dev, int where, u8 val) { return pci_write_config_byte(dev, where, val); } int via_read_config_dword(struct pci_dev *dev, int where, u32 *val) { return pci_read_config_dword(dev,where,val); } int via_read_config_byte(struct pci_dev *dev, int where, u8 *val) { return pci_read_config_byte(dev,where,val); } unsigned char ScsiPortReadPortUchar(unsigned char * port) { return inb((unsigned long) port); }; void ScsiPortWritePortUchar(unsigned char * port, unsigned char value) { outb(value, (unsigned long) port); }; unsigned short ScsiPortReadPortUshort(unsigned short * port) { return inw((unsigned long) port); }; void ScsiPortWritePortUshort(unsigned short * port, unsigned short value) { outw(value, (unsigned long) port); }; void ScsiPortReadPortBufferUshort(unsigned short * port, unsigned short * value, ULONG count) { insw((unsigned long)port, value, count); }; void ScsiPortWritePortBufferUshort(unsigned short * port, unsigned short * value, ULONG count) { outsw((unsigned long)port, value, count); }; void ScsiPortReadPortBufferUlong(ULONG * port, ULONG * value, ULONG count) { insl((unsigned long)port, value, count); }; void ScsiPortWritePortBufferUlong(ULONG * port, ULONG * value, ULONG count) { outsl((unsigned long)port, value, count); }; void ScsiPortStallExecution(ULONG s) { int i; for(i = 0; i < s; i++) //inb((unsigned)0x80); udelay(1); }; void ScsiPortMoveMemory(void * WriteBuffer, void * ReadBuffer, ULONG Length) { memcpy(WriteBuffer, ReadBuffer, Length); }; ULONG ScsiPortReadPortUlong(ULONG* port) { return inl((unsigned long) port); }; void ScsiPortWritePortUlong(ULONG * port, ULONG value) { outl(value, (unsigned long) port); }; void * via_memcpy(void * dst,const void * src ,unsigned sz) { return memcpy( dst,src,sz); } void * via_memset(void * pos,int val,unsigned sz) { return memset(pos,val,sz); } int via_memcmp(const void *var1,const void *var2,__kernel_size_t sz) { return memcmp( var1,var2,sz); } void via_kfree(const void *obj) { kfree(obj); } void *via_kmalloc(size_t sz, int val) { void* addr; addr=kmalloc(sz,val); return addr; } void via_scsi_done(Scsi_Cmnd* SCpnt) { SCpnt->scsi_done(SCpnt); } void* via_get_free_page(unsigned int mask) { return (void*) __get_free_page(mask); } void via_add_timer(struct timer_list * timer) { add_timer(timer); } int via_del_timer_sync(struct timer_list * timer) { return del_timer_sync(timer); } void via_set_timer(void * timer,void (*pfun)(),unsigned long jiff_num,unsigned long data) //duyf_0717 { struct timer_list *my_timer = timer; init_timer(my_timer); my_timer->function = pfun; my_timer->expires = jiffies + jiff_num*HZ/(1000*1000); my_timer->data = data; } void scsicmd_done(unsigned char status) { switch(status){ case SCSI_STATUS_SUCCESS: gSCpnt->result=0; break; case SCSI_STATUS_SELECTION_TIMEOUT: gSCpnt->result=DID_NO_CONNECT; break; default: gSCpnt->result=DID_ERROR<<16; break; } gSCpnt->scsi_done(gSCpnt); } struct resource * via_request_region( unsigned long start, unsigned long n, const char *name) { struct resource* res; res=request_region( start,n,name); return res; } int via_request_irq(unsigned int level,void (*handler)(int, void *, struct pt_regs *), unsigned long id, const char * name, void * misc) { return request_irq(level,handler,id,name,misc); } void via_free_irq(unsigned int level, void * para) { free_irq(level,para); } unsigned long via_virt_to_phys(void* addr) { return virt_to_bus(addr); } void via_release_region( unsigned long addr, unsigned long len) { release_region(addr, len); } void via_strcpy(char* dst, char* src) { strcpy(dst,src); } unsigned char get_pci_bus_number(struct pci_dev *dev) { return dev->bus->number; } unsigned char get_pci_slot_number(struct pci_dev *dev) { return (unsigned char)0xff&((dev->devfn<<5) + (dev->devfn>>3)); } unsigned int get_pci_irq_number(struct pci_dev *dev) { return (unsigned int)dev->irq; } unsigned int get_pci_resource(struct pci_dev *dev,int i) { return (unsigned int)dev->resource[i].start; } unsigned int get_pci_resource_len(struct pci_dev *dev,int i) { return (unsigned int)(dev->resource[i].end-dev->resource[i].start+1); } struct timer_list *alloc_timer() { void* addr; addr=kmalloc(sizeof(struct timer_list),GFP_ATOMIC); return (struct timer_list *)addr; } /*every scsi module driver should contain scsi_module.c*/ static Scsi_Host_Template driver_template = VIACTRL; #include "scsi_module.c"