Annotation of Gnu-Mach/linux/src/drivers/scsi/gdth.c, revision 1.1

1.1     ! root        1: /************************************************************************
        !             2:  * GDT ISA/EISA/PCI Disk Array Controller driver for Linux              *
        !             3:  *                                                                      *
        !             4:  * gdth.c                                                               *
        !             5:  * Copyright (C) 1995-98 ICP vortex Computersysteme GmbH, Achim Leubner *
        !             6:  *                                                                      *
        !             7:  * <[email protected]>                                                    *
        !             8:  *                                                                      *
        !             9:  * This program is free software; you can redistribute it and/or modify *
        !            10:  * it under the terms of the GNU General Public License as published    *
        !            11:  * by the Free Software Foundation; either version 2 of the License,    *
        !            12:  * or (at your option) any later version.                               *
        !            13:  *                                                                      *
        !            14:  * This program is distributed in the hope that it will be useful,      *
        !            15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
        !            16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
        !            17:  * GNU General Public License for more details.                         *
        !            18:  *                                                                      *
        !            19:  * You should have received a copy of the GNU General Public License    *
        !            20:  * along with this kernel; if not, write to the Free Software           *
        !            21:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
        !            22:  *                                                                      *
        !            23:  * Tested with Linux 1.2.13, ..., 2.1.103                               *
        !            24:  *                                                                      *
        !            25:  * $Log: gdth.c,v $
        !            26:  * Revision 1.1  1999/04/26 05:54:35  tb
        !            27:  * 1998-11-30  OKUJI Yoshinori  <[email protected]>
        !            28:  *
        !            29:  *     Clean up linux emulation code to make it architecture-independent
        !            30:  *     as much as possible.
        !            31:  *
        !            32:  *     * linux: Renamed from linuxdev.
        !            33:  *     * Makefile.in (objfiles): Add linux.o instead of linuxdev.o.
        !            34:  *     (MAKE): New variable. Used for the linux.o target.
        !            35:  *     * configure.in: Add AC_CHECK_TOOL(MAKE, make).
        !            36:  *     * i386/i386/spl.h: Include <i386/ipl.h>, for compatibility with
        !            37:  *     OSF Mach 3.0. Suggested by Elgin Lee <[email protected]>.
        !            38:  *     * linux/src: Renamed from linux/linux.
        !            39:  *     * linux/dev: Renamed from linux/mach.
        !            40:  *     * linux/Drivers.in (AC_INIT): Use dev/include/linux/autoconf.h,
        !            41:  *     instead of mach/include/linux/autoconf.h.
        !            42:  *     * Makefile.in (all): Target ../linux.o instead of ../linuxdev.o.
        !            43:  *     * linux/dev/drivers/block/genhd.c: Include <machine/spl.h> instead
        !            44:  *     of <i386/ipl.h>.
        !            45:  *     * linux/dev/drivers/net/auto_irq.c: Remove unneeded header files,
        !            46:  *     <i386/ipl.h> and <i386/pic.h>.
        !            47:  *     * linux/dev/init/main.c: Many i386-dependent codes moved to ...
        !            48:  *     * linux/dev/arch/i386/irq.c: ... here.
        !            49:  *     * linux/dev/arch/i386/setup.c: New file.
        !            50:  *     * linux/dev/arch/i386/linux_emul.h: Likewise.
        !            51:  *     * linux/dev/arch/i386/glue/timer.c: Merged into sched.c.
        !            52:  *     * linux/dev/arch/i386/glue/sched.c: Include <machine/spl.h> instead
        !            53:  *     of <i386/ipl.h>, and moved to ...
        !            54:  *     * linux/dev/kernel/sched.c: ... here.
        !            55:  *     * linux/dev/arch/i386/glue/block.c: Include <machine/spl.h> and
        !            56:  *     <linux_emul.h>, instead of i386-dependent header files, and
        !            57:  *     moved to ...
        !            58:  *     * linux/dev/glue/blocl.c: ... here.
        !            59:  *     * linux/dev/arch/i386/glue/net.c: Include <machine/spl.h> and
        !            60:  *     <linux_emul.h>, instead of i386-dependent header files, and
        !            61:  *     moved to ...
        !            62:  *     * linux/dev/glue/net.c: ... here.
        !            63:  *     * linux/dev/arch/i386/glue/misc.c: Remove `x86' and moved to ...
        !            64:  *     * linux/dev/glue/misc.c: ... here.
        !            65:  *     * linux/dev/arch/i386/glue/kmem.c: Moved to ...
        !            66:  *     * linux/dev/glue/kmem.c: ... here.
        !            67:  *
        !            68:  * Revision 1.16  1998/09/28 16:08:46  achim
        !            69:  * GDT_PCIMPR: DPMEM remapping, if required
        !            70:  * mdelay() added
        !            71:  *
        !            72:  * Revision 1.15  1998/06/03 14:54:06  achim
        !            73:  * gdth_delay(), gdth_flush() implemented
        !            74:  * Bugfix: gdth_release() changed
        !            75:  *
        !            76:  * Revision 1.14  1998/05/22 10:01:17  achim
        !            77:  * mj: pcibios_strerror() removed
        !            78:  * Improved SMP support (if version >= 2.1.95)
        !            79:  * gdth_halt(): halt_called flag added (if version < 2.1)
        !            80:  *
        !            81:  * Revision 1.13  1998/04/16 09:14:57  achim
        !            82:  * Reserve drives (for raw service) implemented
        !            83:  * New error handling code enabled
        !            84:  * Get controller name from board_info() IOCTL
        !            85:  * Final round of PCI device driver patches by Martin Mares
        !            86:  *
        !            87:  * Revision 1.12  1998/03/03 09:32:37  achim
        !            88:  * Fibre channel controller support added
        !            89:  *
        !            90:  * Revision 1.11  1998/01/27 16:19:14  achim
        !            91:  * SA_SHIRQ added
        !            92:  * add_timer()/del_timer() instead of GDTH_TIMER
        !            93:  * scsi_add_timer()/scsi_del_timer() instead of SCSI_TIMER
        !            94:  * New error handling included
        !            95:  *
        !            96:  * Revision 1.10  1997/10/31 12:29:57  achim
        !            97:  * Read heads/sectors from host drive
        !            98:  *
        !            99:  * Revision 1.9  1997/09/04 10:07:25  achim
        !           100:  * IO-mapping with virt_to_bus(), readb(), writeb(), ...
        !           101:  * register_reboot_notifier() to get a notify on shutdown used
        !           102:  *
        !           103:  * Revision 1.8  1997/04/02 12:14:30  achim
        !           104:  * Version 1.00 (see gdth.h), tested with kernel 2.0.29
        !           105:  *
        !           106:  * Revision 1.7  1997/03/12 13:33:37  achim
        !           107:  * gdth_reset() changed, new async. events
        !           108:  *
        !           109:  * Revision 1.6  1997/03/04 14:01:11  achim
        !           110:  * Shutdown routine gdth_halt() implemented
        !           111:  *
        !           112:  * Revision 1.5  1997/02/21 09:08:36  achim
        !           113:  * New controller included (RP, RP1, RP2 series)
        !           114:  * IOCTL interface implemented
        !           115:  *
        !           116:  * Revision 1.4  1996/07/05 12:48:55  achim
        !           117:  * Function gdth_bios_param() implemented
        !           118:  * New constant GDTH_MAXC_P_L inserted
        !           119:  * GDT_WRITE_THR, GDT_EXT_INFO implemented
        !           120:  * Function gdth_reset() changed
        !           121:  *
        !           122:  * Revision 1.3  1996/05/10 09:04:41  achim
        !           123:  * Small changes for Linux 1.2.13
        !           124:  *
        !           125:  * Revision 1.2  1996/05/09 12:45:27  achim
        !           126:  * Loadable module support implemented
        !           127:  * /proc support corrections made
        !           128:  *
        !           129:  * Revision 1.1  1996/04/11 07:35:57  achim
        !           130:  * Initial revision
        !           131:  *
        !           132:  *
        !           133:  * $Id: gdth.c,v 1.1 1999/04/26 05:54:35 tb Exp $ 
        !           134:  ************************************************************************/
        !           135: 
        !           136: #ifdef MODULE
        !           137: #include <linux/module.h>
        !           138: #endif
        !           139: 
        !           140: #include <linux/version.h>
        !           141: #include <linux/kernel.h>
        !           142: #include <linux/head.h>
        !           143: #include <linux/types.h>
        !           144: #include <linux/pci.h>
        !           145: #include <linux/string.h>
        !           146: #include <linux/ioport.h>
        !           147: #include <linux/delay.h>
        !           148: #include <linux/sched.h>
        !           149: #include <linux/in.h>
        !           150: #include <linux/proc_fs.h>
        !           151: #include <linux/time.h>
        !           152: #include <linux/timer.h>
        !           153: #if LINUX_VERSION_CODE >= 0x020100
        !           154: #include <linux/reboot.h>
        !           155: #else
        !           156: #include <linux/bios32.h>
        !           157: #endif
        !           158: 
        !           159: #include <asm/dma.h>
        !           160: #include <asm/system.h>
        !           161: #include <asm/io.h>
        !           162: #if LINUX_VERSION_CODE >= 0x02015F
        !           163: #include <asm/spinlock.h>
        !           164: #endif
        !           165: 
        !           166: #if LINUX_VERSION_CODE >= 0x010300
        !           167: #include <linux/blk.h>
        !           168: #else
        !           169: #include "../block/blk.h"
        !           170: #endif
        !           171: #include "scsi.h"
        !           172: #include "hosts.h"
        !           173: #include "sd.h"
        !           174: 
        !           175: #include "gdth.h"
        !           176: 
        !           177: /****************************************************************************/
        !           178: 
        !           179: /* LILO params: gdth=<IRQ>
        !           180:  *
        !           181:  * Where: <IRQ> is any of the valid IRQs for EISA controllers (10,11,12,14)
        !           182:  * Sets the IRQ of the GDT3000/3020 EISA controller to this value,
        !           183:  * if the IRQ can not automat. detect (controller BIOS disabled)
        !           184:  * See gdth_init_eisa() 
        !           185:  *
        !           186:  * You can use the command line gdth=0 to disable the driver 
        !           187:  */
        !           188: static unchar irqs[MAXHA] = {0xff};
        !           189: static unchar disable_gdth_scan = FALSE;
        !           190: 
        !           191: /* Reserve drives for raw service: Fill the following structure with the
        !           192:  * appropriate values: Controller number, Channel, Target ID 
        !           193:  */
        !           194: static gdth_reserve_str reserve_list[] = {
        !           195:     /* { 0, 1, 4 },            Example: Controller 0, Channel B, ID 4 */
        !           196:     { 0xff, 0xff, 0xff }       /* end of list */
        !           197: };
        !           198: 
        !           199: /****************************************************************************/
        !           200: 
        !           201: #if LINUX_VERSION_CODE >= 0x02015F
        !           202: static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
        !           203: static void do_gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
        !           204: #elif LINUX_VERSION_CODE >= 0x010346
        !           205: static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
        !           206: #else
        !           207: static void gdth_interrupt(int irq,struct pt_regs *regs);
        !           208: #endif
        !           209: static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
        !           210: static int gdth_async_event(int hanum,int service);
        !           211: 
        !           212: static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);
        !           213: static void gdth_next(int hanum);
        !           214: static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b);
        !           215: static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp,unchar b);
        !           216: static gdth_evt_str *gdth_store_event(ushort source, ushort idx,
        !           217:                                       gdth_evt_data *evt);
        !           218: static int gdth_read_event(int handle, gdth_evt_str *estr);
        !           219: static void gdth_readapp_event(unchar application, gdth_evt_str *estr);
        !           220: static void gdth_clear_events(void);
        !           221: 
        !           222: static void gdth_copy_internal_data(Scsi_Cmnd *scp,char *buffer,ushort count);
        !           223: static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp,
        !           224:                                    unchar b,ulong *flags);
        !           225: static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive);
        !           226: 
        !           227: static int gdth_search_eisa(ushort eisa_adr);
        !           228: static int gdth_search_isa(ulong bios_adr);
        !           229: static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr);
        !           230: static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha);
        !           231: static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha);
        !           232: static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha);
        !           233: 
        !           234: static void gdth_enable_int(int hanum);
        !           235: static int gdth_get_status(unchar *pIStatus,int irq);
        !           236: static int gdth_test_busy(int hanum);
        !           237: static int gdth_get_cmd_index(int hanum);
        !           238: static void gdth_release_event(int hanum);
        !           239: static int gdth_wait(int hanum,int index,ulong time);
        !           240: static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong p1,
        !           241:                              ulong p2,ulong p3);
        !           242: static int gdth_search_drives(int hanum);
        !           243: 
        !           244: static void *gdth_mmap(ulong paddr, ulong size);
        !           245: static void gdth_munmap(void *addr);
        !           246: 
        !           247: static const char *gdth_ctr_name(int hanum);
        !           248: 
        !           249: static void gdth_flush(int hanum);
        !           250: #if LINUX_VERSION_CODE >= 0x020100
        !           251: static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
        !           252: #else
        !           253: static int halt_called = FALSE;
        !           254: void gdth_halt(void);
        !           255: #endif
        !           256: 
        !           257: #ifdef DEBUG_GDTH
        !           258: static unchar   DebugState = DEBUG_GDTH;
        !           259: extern int sys_syslog(int,char*,int);
        !           260: #define LOGEN           sys_syslog(7,NULL,0)
        !           261: 
        !           262: #ifdef __SERIAL__
        !           263: #define MAX_SERBUF 160
        !           264: static void ser_init(void);
        !           265: static void ser_puts(char *str);
        !           266: static void ser_putc(char c);
        !           267: static int  ser_printk(const char *fmt, ...);
        !           268: static char strbuf[MAX_SERBUF+1];
        !           269: #ifdef __COM2__
        !           270: #define COM_BASE 0x2f8
        !           271: #else
        !           272: #define COM_BASE 0x3f8
        !           273: #endif
        !           274: static void ser_init()
        !           275: {
        !           276:     unsigned port=COM_BASE;
        !           277: 
        !           278:     outb(0x80,port+3);
        !           279:     outb(0,port+1);
        !           280:     /* 19200 Baud, if 9600: outb(12,port) */
        !           281:     outb(6, port);
        !           282:     outb(3,port+3);
        !           283:     outb(0,port+1);
        !           284:     /*
        !           285:     ser_putc('I');
        !           286:     ser_putc(' ');
        !           287:     */
        !           288: }
        !           289: 
        !           290: static void ser_puts(char *str)
        !           291: {
        !           292:     char *ptr;
        !           293: 
        !           294:     ser_init();
        !           295:     for (ptr=str;*ptr;++ptr)
        !           296:         ser_putc(*ptr);
        !           297: }
        !           298: 
        !           299: static void ser_putc(char c)
        !           300: {
        !           301:     unsigned port=COM_BASE;
        !           302: 
        !           303:     while ((inb(port+5) & 0x20)==0);
        !           304:     outb(c,port);
        !           305:     if (c==0x0a)
        !           306:     {
        !           307:         while ((inb(port+5) & 0x20)==0);
        !           308:         outb(0x0d,port);
        !           309:     }
        !           310: }
        !           311: 
        !           312: static int ser_printk(const char *fmt, ...)
        !           313: {
        !           314:     va_list args;
        !           315:     int i;
        !           316: 
        !           317:     va_start(args,fmt);
        !           318:     i = vsprintf(strbuf,fmt,args);
        !           319:     ser_puts(strbuf);
        !           320:     va_end(args);
        !           321:     return i;
        !           322: }
        !           323: 
        !           324: #define TRACE(a)    {if (DebugState==1) {ser_printk a;}}
        !           325: #define TRACE2(a)   {if (DebugState==1 || DebugState==2) {ser_printk a;}}
        !           326: #define TRACE3(a)   {if (DebugState!=0) {ser_printk a;}}
        !           327: 
        !           328: #else /* !__SERIAL__ */
        !           329: #define TRACE(a)    {if (DebugState==1) {LOGEN;printk a;}}
        !           330: #define TRACE2(a)   {if (DebugState==1 || DebugState==2) {LOGEN;printk a;}}
        !           331: #define TRACE3(a)   {if (DebugState!=0) {LOGEN;printk a;}}
        !           332: #endif
        !           333: 
        !           334: #else /* !DEBUG */
        !           335: #define TRACE(a)
        !           336: #define TRACE2(a)
        !           337: #define TRACE3(a)
        !           338: #endif
        !           339: 
        !           340: #ifdef GDTH_STATISTICS
        !           341: static ulong max_rq=0, max_index=0, max_sg=0;
        !           342: static ulong act_ints=0, act_ios=0, act_stats=0, act_rq=0;
        !           343: static struct timer_list gdth_timer;
        !           344: #endif
        !           345: 
        !           346: #define PTR2USHORT(a)   (ushort)(ulong)(a)
        !           347: #define GDTOFFSOF(a,b)  (size_t)&(((a*)0)->b)   
        !           348: #define INDEX_OK(i,t)   ((i)<sizeof(t)/sizeof((t)[0]))
        !           349: 
        !           350: #define NUMDATA(a)      ( (gdth_num_str  *)((a)->hostdata))
        !           351: #define HADATA(a)       (&((gdth_ext_str *)((a)->hostdata))->haext)
        !           352: #define CMDDATA(a)      (&((gdth_ext_str *)((a)->hostdata))->cmdext)
        !           353: #define DMADATA(a)      (&((gdth_ext_str *)((a)->hostdata))->dmaext)
        !           354: 
        !           355: 
        !           356: #if LINUX_VERSION_CODE < 0x010300
        !           357: static void *gdth_mmap(ulong paddr, ulong size) 
        !           358: {
        !           359:     if (paddr >= high_memory)
        !           360:        return NULL; 
        !           361:     else
        !           362:        return (void *)paddr;
        !           363: }
        !           364: static void gdth_munmap(void *addr) 
        !           365: {
        !           366: }
        !           367: inline ulong virt_to_phys(volatile void *addr)
        !           368: {
        !           369:     return (ulong)addr;
        !           370: }
        !           371: inline void *phys_to_virt(ulong addr)
        !           372: {
        !           373:     return (void *)addr;
        !           374: }
        !           375: #define virt_to_bus            virt_to_phys
        !           376: #define bus_to_virt            phys_to_virt
        !           377: #define readb(addr)            (*(volatile unchar *)(addr))
        !           378: #define readw(addr)            (*(volatile ushort *)(addr))
        !           379: #define readl(addr)            (*(volatile ulong *)(addr))
        !           380: #define writeb(b,addr)         (*(volatile unchar *)(addr) = (b))
        !           381: #define writew(b,addr)         (*(volatile ushort *)(addr) = (b))
        !           382: #define writel(b,addr)         (*(volatile ulong *)(addr) = (b))
        !           383: #define memset_io(a,b,c)       memset((void *)(a),(b),(c))
        !           384: #define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
        !           385: #define memcpy_toio(a,b,c)     memcpy((void *)(a),(b),(c))
        !           386: 
        !           387: #elif LINUX_VERSION_CODE < 0x020100
        !           388: static int remapped = FALSE;
        !           389: static void *gdth_mmap(ulong paddr, ulong size) 
        !           390: {
        !           391:     if ( paddr >= high_memory) {
        !           392:        remapped = TRUE;
        !           393:        return vremap(paddr, size);
        !           394:     } else {
        !           395:        return (void *)paddr; 
        !           396:     }
        !           397: }
        !           398: static void gdth_munmap(void *addr) 
        !           399: {
        !           400:     if (remapped)
        !           401:        vfree(addr);
        !           402:     remapped = FALSE;
        !           403: }
        !           404: #else
        !           405: static void *gdth_mmap(ulong paddr, ulong size) 
        !           406: { 
        !           407:     return ioremap(paddr, size); 
        !           408: }
        !           409: static void gdth_munmap(void *addr) 
        !           410: {
        !           411:     return iounmap(addr);
        !           412: }
        !           413: #endif
        !           414: 
        !           415: 
        !           416: static unchar   gdth_drq_tab[4] = {5,6,7,7};            /* DRQ table */
        !           417: static unchar   gdth_irq_tab[6] = {0,10,11,12,14,0};    /* IRQ table */
        !           418: static unchar   gdth_polling;                           /* polling if TRUE */
        !           419: static unchar   gdth_from_wait  = FALSE;                /* gdth_wait() */
        !           420: static int      wait_index,wait_hanum;                  /* gdth_wait() */
        !           421: static int      gdth_ctr_count  = 0;                    /* controller count */
        !           422: static int      gdth_ctr_vcount = 0;                    /* virt. ctr. count */
        !           423: static int     gdth_ctr_released = 0;                  /* gdth_release() */
        !           424: static struct Scsi_Host *gdth_ctr_tab[MAXHA];           /* controller table */
        !           425: static struct Scsi_Host *gdth_ctr_vtab[MAXHA*MAXBUS];   /* virt. ctr. table */
        !           426: static unchar   gdth_write_through = FALSE;             /* write through */
        !           427: static char *gdth_ioctl_tab[4][MAXHA];                  /* ioctl buffer */
        !           428: static gdth_evt_str ebuffer[MAX_EVENTS];                /* event buffer */
        !           429: static int elastidx;
        !           430: static int eoldidx;
        !           431: 
        !           432: static struct {
        !           433:     Scsi_Cmnd   *cmnd;                          /* pending request */
        !           434:     ushort      service;                        /* service */
        !           435: } gdth_cmd_tab[GDTH_MAXCMDS][MAXHA];            /* table of pend. requests */
        !           436: 
        !           437: #define DIN     1                               /* IN data direction */
        !           438: #define DOU     2                               /* OUT data direction */
        !           439: #define DNO     DIN                             /* no data transfer */
        !           440: #define DUN     DIN                             /* unknown data direction */
        !           441: static unchar gdth_direction_tab[0x100] = {
        !           442:     DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN,
        !           443:     DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN,
        !           444:     DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DIN,DUN,DUN,DIN,DIN,DIN,
        !           445:     DIN,DIN,DIN,DNO,DIN,DNO,DNO,DIN,DIN,DIN,DIN,DIN,DIN,DIN,DIN,DIN,
        !           446:     DIN,DIN,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DIN,DIN,DUN,DUN,
        !           447:     DUN,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN,
        !           448:     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
        !           449:     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
        !           450:     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
        !           451:     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
        !           452:     DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DIN,DUN,DNO,DUN,DIN,DIN,
        !           453:     DIN,DIN,DIN,DNO,DUN,DIN,DIN,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
        !           454:     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
        !           455:     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
        !           456:     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
        !           457:     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN
        !           458: };
        !           459: 
        !           460: /* __initfunc, __initdata macros */
        !           461: #if LINUX_VERSION_CODE >= 0x020126
        !           462: #include <linux/init.h>
        !           463: #else
        !           464: #define __initfunc(A) A
        !           465: #define __initdata
        !           466: #define __init
        !           467: #endif
        !           468: 
        !           469: /* /proc support */
        !           470: #if LINUX_VERSION_CODE >= 0x010300
        !           471: #include <linux/stat.h> 
        !           472: struct proc_dir_entry proc_scsi_gdth = {
        !           473:     PROC_SCSI_GDTH, 4, "gdth",
        !           474:     S_IFDIR | S_IRUGO | S_IXUGO, 2
        !           475: };
        !           476: #include "gdth_proc.h"
        !           477: #include "gdth_proc.c"
        !           478: #endif
        !           479: 
        !           480: #if LINUX_VERSION_CODE >= 0x020100
        !           481: /* notifier block to get a notify on system shutdown/halt/reboot */
        !           482: static struct notifier_block gdth_notifier = {
        !           483:     gdth_halt, NULL, 0
        !           484: };
        !           485: #endif
        !           486: 
        !           487: static void gdth_delay(int milliseconds)
        !           488: {
        !           489:     if (milliseconds == 0) {
        !           490:         udelay(1);
        !           491:     } else {
        !           492: #if LINUX_VERSION_CODE >= 0x020168
        !           493:         mdelay(milliseconds);
        !           494: #else
        !           495:         int i;
        !           496:         for (i = 0; i < milliseconds; ++i) 
        !           497:             udelay(1000);
        !           498: #endif
        !           499:     }
        !           500: }
        !           501: 
        !           502: /* controller search and initialization functions */
        !           503: 
        !           504: __initfunc (static int gdth_search_eisa(ushort eisa_adr))
        !           505: {
        !           506:     ulong id;
        !           507:     
        !           508:     TRACE(("gdth_search_eisa() adr. %x\n",eisa_adr));
        !           509:     id = inl(eisa_adr+ID0REG);
        !           510:     if (id == GDT3A_ID || id == GDT3B_ID) {     /* GDT3000A or GDT3000B */
        !           511:         if ((inb(eisa_adr+EISAREG) & 8) == 0)   
        !           512:             return 0;                           /* not EISA configured */
        !           513:         return 1;
        !           514:     }
        !           515:     if (id == GDT3_ID)                          /* GDT3000 */
        !           516:         return 1;
        !           517: 
        !           518:     return 0;                                   
        !           519: }
        !           520: 
        !           521: 
        !           522: __initfunc (static int gdth_search_isa(ulong bios_adr))
        !           523: {
        !           524:     void *addr;
        !           525:     ulong id;
        !           526: 
        !           527:     TRACE(("gdth_search_isa() bios adr. %lx\n",bios_adr));
        !           528:     if ((addr = gdth_mmap(bios_adr+BIOS_ID_OFFS, sizeof(ulong))) != NULL) {
        !           529:        id = readl(addr);
        !           530:        gdth_munmap(addr);
        !           531:        if (id == GDT2_ID)                          /* GDT2000 */
        !           532:            return 1;
        !           533:     }
        !           534:     return 0;
        !           535: }
        !           536: 
        !           537: 
        !           538: __initfunc (static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr))
        !           539: {
        !           540:     int error;
        !           541:     ulong base0,base1,base2;
        !           542: 
        !           543:     TRACE(("gdth_search_pci() device_id %d, index %d\n",
        !           544:                  device_id,index));
        !           545: 
        !           546: #if LINUX_VERSION_CODE >= 0x20155
        !           547:     if (!pci_present())
        !           548:         return 0;
        !           549: #else
        !           550:     if (!pcibios_present())
        !           551:         return 0;
        !           552: #endif
        !           553: 
        !           554:     if (pcibios_find_device(PCI_VENDOR_ID_VORTEX,device_id,index,
        !           555:                              &pcistr->bus,&pcistr->device_fn))
        !           556:         return 0;
        !           557: 
        !           558:     /* GDT PCI controller found, now read resources from config space */
        !           559: #if LINUX_VERSION_CODE >= 0x20155
        !           560:     {
        !           561:        struct pci_dev *pdev = pci_find_slot(pcistr->bus, pcistr->device_fn);
        !           562:        base0 = pdev->base_address[0];
        !           563:        base1 = pdev->base_address[1];
        !           564:        base2 = pdev->base_address[2];
        !           565:        if ((error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
        !           566:                                               PCI_ROM_ADDRESS,
        !           567:                                               (int *) &pcistr->bios))) {
        !           568:            printk("GDT-PCI: error %d reading configuration space", error);
        !           569:            return -1;
        !           570:        }
        !           571:        pcistr->irq = pdev->irq;
        !           572:     }
        !           573: #else
        !           574: #if LINUX_VERSION_CODE >= 0x010300
        !           575: #define GDTH_BASEP      (int *)
        !           576: #else
        !           577: #define GDTH_BASEP
        !           578: #endif
        !           579:     if ((error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
        !           580:                                            PCI_BASE_ADDRESS_0,
        !           581:                                            GDTH_BASEP&base0)) ||
        !           582:         (error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
        !           583:                                            PCI_BASE_ADDRESS_1,
        !           584:                                            GDTH_BASEP&base1)) ||
        !           585:         (error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
        !           586:                                            PCI_BASE_ADDRESS_2,
        !           587:                                            GDTH_BASEP&base2)) ||
        !           588:         (error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
        !           589:                                            PCI_ROM_ADDRESS,
        !           590:                                            GDTH_BASEP&pcistr->bios)) ||
        !           591:         (error = pcibios_read_config_byte(pcistr->bus,pcistr->device_fn,
        !           592:                                           PCI_INTERRUPT_LINE,&pcistr->irq))) {
        !           593:         printk("GDT-PCI: error %d reading configuration space", error);
        !           594:         return -1;
        !           595:     }
        !           596: #endif
        !           597: 
        !           598:     pcistr->device_id = device_id;
        !           599:     if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000 or GDT6000B */
        !           600:         device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
        !           601:         if ((base0 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_MEMORY)
        !           602:             return -1;
        !           603:         pcistr->dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
        !           604:     } else {                                    /* GDT6110, GDT6120, .. */
        !           605:         if ((base0 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_MEMORY ||
        !           606:             (base2 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_MEMORY ||
        !           607:             (base1 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_IO)
        !           608:             return -1;
        !           609:         pcistr->dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
        !           610:         pcistr->io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
        !           611:         pcistr->io    = base1 & PCI_BASE_ADDRESS_IO_MASK;
        !           612:     }
        !           613:     return 1;
        !           614: }
        !           615: 
        !           616: 
        !           617: __initfunc (static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha))
        !           618: {
        !           619:     ulong retries,id;
        !           620:     unchar prot_ver,eisacf,i,irq_found;
        !           621: 
        !           622:     TRACE(("gdth_init_eisa() adr. %x\n",eisa_adr));
        !           623:     
        !           624:     /* disable board interrupts, deinitialize services */
        !           625:     outb(0xff,eisa_adr+EDOORREG);
        !           626:     outb(0x00,eisa_adr+EDENABREG);
        !           627:     outb(0x00,eisa_adr+EINTENABREG);
        !           628:     
        !           629:     outb(0xff,eisa_adr+LDOORREG);
        !           630:     retries = INIT_RETRIES;
        !           631:     gdth_delay(20);
        !           632:     while (inb(eisa_adr+EDOORREG) != 0xff) {
        !           633:         if (--retries == 0) {
        !           634:             printk("GDT-EISA: Initialization error (DEINIT failed)\n");
        !           635:             return 0;
        !           636:         }
        !           637:         gdth_delay(1);
        !           638:         TRACE2(("wait for DEINIT: retries=%ld\n",retries));
        !           639:     }
        !           640:     prot_ver = inb(eisa_adr+MAILBOXREG);
        !           641:     outb(0xff,eisa_adr+EDOORREG);
        !           642:     if (prot_ver != PROTOCOL_VERSION) {
        !           643:         printk("GDT-EISA: Illegal protocol version\n");
        !           644:         return 0;
        !           645:     }
        !           646:     ha->bmic = eisa_adr;
        !           647:     ha->brd_phys = (ulong)eisa_adr >> 12;
        !           648: 
        !           649:     outl(0,eisa_adr+MAILBOXREG);
        !           650:     outl(0,eisa_adr+MAILBOXREG+4);
        !           651:     outl(0,eisa_adr+MAILBOXREG+8);
        !           652:     outl(0,eisa_adr+MAILBOXREG+12);
        !           653: 
        !           654:     /* detect IRQ */ 
        !           655:     if ((id = inl(eisa_adr+ID0REG)) == GDT3_ID) {
        !           656:         ha->type = GDT_EISA;
        !           657:         ha->stype = id;
        !           658:         outl(1,eisa_adr+MAILBOXREG+8);
        !           659:         outb(0xfe,eisa_adr+LDOORREG);
        !           660:         retries = INIT_RETRIES;
        !           661:         gdth_delay(20);
        !           662:         while (inb(eisa_adr+EDOORREG) != 0xfe) {
        !           663:             if (--retries == 0) {
        !           664:                 printk("GDT-EISA: Initialization error (get IRQ failed)\n");
        !           665:                 return 0;
        !           666:             }
        !           667:             gdth_delay(1);
        !           668:         }
        !           669:         ha->irq = inb(eisa_adr+MAILBOXREG);
        !           670:         outb(0xff,eisa_adr+EDOORREG);
        !           671:         TRACE2(("GDT3000/3020: IRQ=%d\n",ha->irq));
        !           672:        /* check the result */
        !           673:        if (ha->irq == 0) {
        !           674:            TRACE2(("Unknown IRQ, check IRQ table from cmd line !\n"));
        !           675:            for (i=0,irq_found=FALSE; i<MAXHA && irqs[i]!=0xff; ++i) {
        !           676:                if (irqs[i]!=0) {
        !           677:                    irq_found=TRUE;
        !           678:                    break;
        !           679:                }
        !           680:            }
        !           681:            if (irq_found) {
        !           682:                ha->irq = irqs[i];
        !           683:                irqs[i] = 0;
        !           684:                printk("GDT-EISA: Can not detect controller IRQ,\n");
        !           685:                printk("Use IRQ setting from command line (IRQ = %d)\n",
        !           686:                       ha->irq);
        !           687:            } else {
        !           688:                printk("GDT-EISA: Initialization error (unknown IRQ), Enable\n");
        !           689:                printk("the controller BIOS or use command line parameters\n");
        !           690:                return 0;
        !           691:            }
        !           692:        }
        !           693:     } else {
        !           694:         eisacf = inb(eisa_adr+EISAREG) & 7;
        !           695:         if (eisacf > 4)                         /* level triggered */
        !           696:             eisacf -= 4;
        !           697:         ha->irq = gdth_irq_tab[eisacf];
        !           698:         ha->type = GDT_EISA;
        !           699:         ha->stype= id;
        !           700:     }
        !           701:     return 1;
        !           702: }
        !           703: 
        !           704:        
        !           705: __initfunc (static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha))
        !           706: {
        !           707:     register gdt2_dpram_str *dp2_ptr;
        !           708:     int i;
        !           709:     unchar irq_drq,prot_ver;
        !           710:     ulong retries;
        !           711: 
        !           712:     TRACE(("gdth_init_isa() bios adr. %lx\n",bios_adr));
        !           713: 
        !           714:     ha->brd = gdth_mmap(bios_adr, sizeof(gdt2_dpram_str));
        !           715:     if (ha->brd == NULL) {
        !           716:        printk("GDT-ISA: Initialization error (DPMEM remap error)\n");
        !           717:        return 0;
        !           718:     }
        !           719:     dp2_ptr = (gdt2_dpram_str *)ha->brd;
        !           720:     writeb(1, &dp2_ptr->io.memlock);                   /* switch off write protection */
        !           721:     /* reset interface area */
        !           722:     memset_io((char *)&dp2_ptr->u,0,sizeof(dp2_ptr->u));
        !           723:     if (readl(&dp2_ptr->u) != 0) {
        !           724:        printk("GDT-PCI: Initialization error (DPMEM write error)\n");
        !           725:        gdth_munmap(ha->brd);
        !           726:        return 0;
        !           727:     }
        !           728: 
        !           729:     /* disable board interrupts, read DRQ and IRQ */
        !           730:     writeb(0xff, &dp2_ptr->io.irqdel);
        !           731:     writeb(0x00, &dp2_ptr->io.irqen);
        !           732:     writeb(0x00, &dp2_ptr->u.ic.S_Status);
        !           733:     writeb(0x00, &dp2_ptr->u.ic.Cmd_Index);
        !           734: 
        !           735:     irq_drq = readb(&dp2_ptr->io.rq);
        !           736:     for (i=0; i<3; ++i) {
        !           737:         if ((irq_drq & 1)==0)
        !           738:             break;
        !           739:         irq_drq >>= 1;
        !           740:     }
        !           741:     ha->drq = gdth_drq_tab[i];
        !           742: 
        !           743:     irq_drq = readb(&dp2_ptr->io.rq) >> 3;
        !           744:     for (i=1; i<5; ++i) {
        !           745:         if ((irq_drq & 1)==0)
        !           746:             break;
        !           747:         irq_drq >>= 1;
        !           748:     }
        !           749:     ha->irq = gdth_irq_tab[i];
        !           750: 
        !           751:     /* deinitialize services */
        !           752:     writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]);
        !           753:     writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx);
        !           754:     writeb(0, &dp2_ptr->io.event);
        !           755:     retries = INIT_RETRIES;
        !           756:     gdth_delay(20);
        !           757:     while (readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
        !           758:         if (--retries == 0) {
        !           759:             printk("GDT-ISA: Initialization error (DEINIT failed)\n");
        !           760:            gdth_munmap(ha->brd);
        !           761:             return 0;
        !           762:         }
        !           763:         gdth_delay(1);
        !           764:     }
        !           765:     prot_ver = (unchar)readl(&dp2_ptr->u.ic.S_Info[0]);
        !           766:     writeb(0, &dp2_ptr->u.ic.Status);
        !           767:     writeb(0xff, &dp2_ptr->io.irqdel);
        !           768:     if (prot_ver != PROTOCOL_VERSION) {
        !           769:         printk("GDT-ISA: Illegal protocol version\n");
        !           770:        gdth_munmap(ha->brd);
        !           771:         return 0;
        !           772:     }
        !           773: 
        !           774:     ha->type = GDT_ISA;
        !           775:     ha->ic_all_size = sizeof(dp2_ptr->u);
        !           776:     ha->stype= GDT2_ID;
        !           777:     ha->brd_phys = bios_adr >> 4;
        !           778: 
        !           779:     /* special request to controller BIOS */
        !           780:     writel(0x00, &dp2_ptr->u.ic.S_Info[0]);
        !           781:     writel(0x00, &dp2_ptr->u.ic.S_Info[1]);
        !           782:     writel(0x01, &dp2_ptr->u.ic.S_Info[2]);
        !           783:     writel(0x00, &dp2_ptr->u.ic.S_Info[3]);
        !           784:     writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx);
        !           785:     writeb(0, &dp2_ptr->io.event);
        !           786:     retries = INIT_RETRIES;
        !           787:     gdth_delay(20);
        !           788:     while (readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
        !           789:         if (--retries == 0) {
        !           790:             printk("GDT-ISA: Initialization error\n");
        !           791:            gdth_munmap(ha->brd);
        !           792:             return 0;
        !           793:         }
        !           794:         gdth_delay(1);
        !           795:     }
        !           796:     writeb(0, &dp2_ptr->u.ic.Status);
        !           797:     writeb(0xff, &dp2_ptr->io.irqdel);
        !           798:     return 1;
        !           799: }
        !           800: 
        !           801: 
        !           802: __initfunc (static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha))
        !           803: {
        !           804:     register gdt6_dpram_str *dp6_ptr;
        !           805:     register gdt6c_dpram_str *dp6c_ptr;
        !           806:     register gdt6m_dpram_str *dp6m_ptr;
        !           807:     ulong retries;
        !           808:     unchar prot_ver;
        !           809:     int i, found = FALSE;
        !           810: 
        !           811:     TRACE(("gdth_init_pci()\n"));
        !           812: 
        !           813:     ha->brd_phys = (pcistr->bus << 8) | (pcistr->device_fn & 0xf8);
        !           814:     ha->stype    = (ulong)pcistr->device_id;
        !           815:     ha->irq      = pcistr->irq;
        !           816:     
        !           817:     if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6000B) {   /* GDT6000 or GDT6000B */
        !           818:         TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
        !           819:        ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6_dpram_str));
        !           820:        if (ha->brd == NULL) {
        !           821:            printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
        !           822:            return 0;
        !           823:        }
        !           824:         dp6_ptr = (gdt6_dpram_str *)ha->brd;
        !           825:         /* reset interface area */
        !           826:         memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u));
        !           827:         if (readl(&dp6_ptr->u) != 0) {
        !           828:             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
        !           829:            gdth_munmap(ha->brd);
        !           830:             return 0;
        !           831:         }
        !           832:         
        !           833:         /* disable board interrupts, deinit services */
        !           834:         writeb(0xff, &dp6_ptr->io.irqdel);
        !           835:         writeb(0x00, &dp6_ptr->io.irqen);;
        !           836:         writeb(0x00, &dp6_ptr->u.ic.S_Status);
        !           837:         writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
        !           838: 
        !           839:         writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
        !           840:         writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
        !           841:         writeb(0, &dp6_ptr->io.event);
        !           842:         retries = INIT_RETRIES;
        !           843:         gdth_delay(20);
        !           844:         while (readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
        !           845:             if (--retries == 0) {
        !           846:                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
        !           847:                gdth_munmap(ha->brd);
        !           848:                 return 0;
        !           849:             }
        !           850:             gdth_delay(1);
        !           851:         }
        !           852:         prot_ver = (unchar)readl(&dp6_ptr->u.ic.S_Info[0]);
        !           853:         writeb(0, &dp6_ptr->u.ic.S_Status);
        !           854:         writeb(0xff, &dp6_ptr->io.irqdel);
        !           855:         if (prot_ver != PROTOCOL_VERSION) {
        !           856:             printk("GDT-PCI: Illegal protocol version\n");
        !           857:            gdth_munmap(ha->brd);
        !           858:             return 0;
        !           859:         }
        !           860: 
        !           861:         ha->type = GDT_PCI;
        !           862:         ha->ic_all_size = sizeof(dp6_ptr->u);
        !           863:         
        !           864:         /* special command to controller BIOS */
        !           865:         writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
        !           866:         writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
        !           867:         writel(0x01, &dp6_ptr->u.ic.S_Info[2]);
        !           868:         writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
        !           869:         writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
        !           870:         writeb(0, &dp6_ptr->io.event);
        !           871:         retries = INIT_RETRIES;
        !           872:         gdth_delay(20);
        !           873:         while (readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
        !           874:             if (--retries == 0) {
        !           875:                 printk("GDT-PCI: Initialization error\n");
        !           876:                gdth_munmap(ha->brd);
        !           877:                 return 0;
        !           878:             }
        !           879:             gdth_delay(1);
        !           880:         }
        !           881:         writeb(0, &dp6_ptr->u.ic.S_Status);
        !           882:         writeb(0xff, &dp6_ptr->io.irqdel);
        !           883: 
        !           884:     } else if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, GDT6120, .. */
        !           885:        ha->plx = (gdt6c_plx_regs *)pcistr->io;
        !           886:        TRACE2(("init_pci_new() dpmem %lx io %lx irq %d\n",
        !           887:                pcistr->dpmem,(ulong)ha->plx,ha->irq));
        !           888:        ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6c_dpram_str));
        !           889:        if (ha->brd == NULL) {
        !           890:            printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
        !           891:            gdth_munmap(ha->brd);
        !           892:            return 0;
        !           893:        }
        !           894:         dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
        !           895:         /* reset interface area */
        !           896:         memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u));
        !           897:         if (readl(&dp6c_ptr->u) != 0) {
        !           898:             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
        !           899:            gdth_munmap(ha->brd);
        !           900:             return 0;
        !           901:         }
        !           902:         
        !           903:         /* disable board interrupts, deinit services */
        !           904:         outb(0x00,PTR2USHORT(&ha->plx->control1));
        !           905:         outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
        !           906:         
        !           907:         writeb(0x00, &dp6c_ptr->u.ic.S_Status);
        !           908:         writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
        !           909: 
        !           910:         writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
        !           911:         writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
        !           912: 
        !           913:         outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
        !           914: 
        !           915:         retries = INIT_RETRIES;
        !           916:         gdth_delay(20);
        !           917:         while (readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
        !           918:             if (--retries == 0) {
        !           919:                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
        !           920:                gdth_munmap(ha->brd);
        !           921:                 return 0;
        !           922:             }
        !           923:             gdth_delay(1);
        !           924:         }
        !           925:         prot_ver = (unchar)readl(&dp6c_ptr->u.ic.S_Info[0]);
        !           926:         writeb(0, &dp6c_ptr->u.ic.Status);
        !           927:         if (prot_ver != PROTOCOL_VERSION) {
        !           928:             printk("GDT-PCI: Illegal protocol version\n");
        !           929:            gdth_munmap(ha->brd);
        !           930:             return 0;
        !           931:         }
        !           932: 
        !           933:         ha->type = GDT_PCINEW;
        !           934:         ha->ic_all_size = sizeof(dp6c_ptr->u);
        !           935: 
        !           936:         /* special command to controller BIOS */
        !           937:         writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
        !           938:         writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
        !           939:         writel(0x01, &dp6c_ptr->u.ic.S_Info[2]);
        !           940:         writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
        !           941:         writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
        !           942:         
        !           943:         outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
        !           944: 
        !           945:         retries = INIT_RETRIES;
        !           946:         gdth_delay(20);
        !           947:         while (readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
        !           948:             if (--retries == 0) {
        !           949:                 printk("GDT-PCI: Initialization error\n");
        !           950:                gdth_munmap(ha->brd);
        !           951:                 return 0;
        !           952:             }
        !           953:             gdth_delay(1);
        !           954:         }
        !           955:         writeb(0, &dp6c_ptr->u.ic.S_Status);
        !           956: 
        !           957:     } else {                                            /* MPR */
        !           958:        TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
        !           959:        ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6m_dpram_str));
        !           960:        if (ha->brd == NULL) {
        !           961:            printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
        !           962:            return 0;
        !           963:        }
        !           964: 
        !           965:         /* check and reset interface area */
        !           966:         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
        !           967:        writel(DPMEM_MAGIC, &dp6m_ptr->u);
        !           968:        if (readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
        !           969:            printk("GDT-PCI: Cannot access DPMEM at 0x%x (shadowed?)\n", 
        !           970:                   (int)ha->brd);
        !           971:            found = FALSE;
        !           972:            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
        !           973:                pcibios_write_config_dword( pcistr->bus, pcistr->device_fn,
        !           974:                                            PCI_BASE_ADDRESS_0, i );
        !           975:                gdth_munmap( ha->brd );
        !           976:                ha->brd = gdth_mmap(i, sizeof(gdt6m_dpram_str)); 
        !           977:                if (ha->brd == NULL) {
        !           978:                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
        !           979:                    return 0;
        !           980:                }
        !           981:                dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
        !           982:                writel(DPMEM_MAGIC, &dp6m_ptr->u);
        !           983:                if (readl(&dp6m_ptr->u) == DPMEM_MAGIC) {
        !           984:                    printk("GDT-PCI: Use free address at 0x%x\n",
        !           985:                           (int)ha->brd);
        !           986:                    found = TRUE;
        !           987:                    break;
        !           988:                }
        !           989:            }   
        !           990:            if (!found) {
        !           991:                printk("GDT-PCI: No free address found!\n");
        !           992:                gdth_munmap( ha->brd );
        !           993:                return 0;
        !           994:            }
        !           995:        }
        !           996:         memset_io((char *)&dp6m_ptr->u,0,sizeof(dp6m_ptr->u));
        !           997:         
        !           998:         /* disable board interrupts, deinit services */
        !           999:         writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) | 4,
        !          1000:               &dp6m_ptr->i960r.edoor_en_reg);
        !          1001:         writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
        !          1002:         writeb(0x00, &dp6m_ptr->u.ic.S_Status);
        !          1003:         writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index);
        !          1004: 
        !          1005:         writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]);
        !          1006:         writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx);
        !          1007:         writeb(1, &dp6m_ptr->i960r.ldoor_reg);
        !          1008:         retries = INIT_RETRIES;
        !          1009:         gdth_delay(20);
        !          1010:         while (readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
        !          1011:             if (--retries == 0) {
        !          1012:                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
        !          1013:                gdth_munmap(ha->brd);
        !          1014:                 return 0;
        !          1015:             }
        !          1016:             gdth_delay(1);
        !          1017:         }
        !          1018:         prot_ver = (unchar)readl(&dp6m_ptr->u.ic.S_Info[0]);
        !          1019:         writeb(0, &dp6m_ptr->u.ic.S_Status);
        !          1020:         if (prot_ver != PROTOCOL_VERSION) {
        !          1021:             printk("GDT-PCI: Illegal protocol version\n");
        !          1022:            gdth_munmap(ha->brd);
        !          1023:             return 0;
        !          1024:         }
        !          1025: 
        !          1026:         ha->type = GDT_PCIMPR;
        !          1027:         ha->ic_all_size = sizeof(dp6m_ptr->u);
        !          1028:         
        !          1029:         /* special command to controller BIOS */
        !          1030:         writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
        !          1031:         writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
        !          1032:         writel(0x01, &dp6m_ptr->u.ic.S_Info[2]);
        !          1033:         writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
        !          1034:         writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
        !          1035:         writeb(1, &dp6m_ptr->i960r.ldoor_reg);
        !          1036:         retries = INIT_RETRIES;
        !          1037:         gdth_delay(20);
        !          1038:         while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
        !          1039:             if (--retries == 0) {
        !          1040:                 printk("GDT-PCI: Initialization error\n");
        !          1041:                gdth_munmap(ha->brd);
        !          1042:                 return 0;
        !          1043:             }
        !          1044:             gdth_delay(1);
        !          1045:         }
        !          1046:         writeb(0, &dp6m_ptr->u.ic.S_Status);
        !          1047:     }
        !          1048: 
        !          1049:     return 1;
        !          1050: }
        !          1051: 
        !          1052: 
        !          1053: /* controller protocol functions */
        !          1054: 
        !          1055: __initfunc (static void gdth_enable_int(int hanum))
        !          1056: {
        !          1057:     gdth_ha_str *ha;
        !          1058:     ulong flags;
        !          1059:     gdt2_dpram_str *dp2_ptr;
        !          1060:     gdt6_dpram_str *dp6_ptr;
        !          1061:     gdt6m_dpram_str *dp6m_ptr;
        !          1062: 
        !          1063:     TRACE(("gdth_enable_int() hanum %d\n",hanum));
        !          1064:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1065: 
        !          1066:     save_flags(flags);
        !          1067:     cli();
        !          1068: 
        !          1069:     if (ha->type == GDT_EISA) {
        !          1070:         outb(0xff, ha->bmic + EDOORREG);
        !          1071:         outb(0xff, ha->bmic + EDENABREG);
        !          1072:         outb(0x01, ha->bmic + EINTENABREG);
        !          1073:     } else if (ha->type == GDT_ISA) {
        !          1074:         dp2_ptr = (gdt2_dpram_str *)ha->brd;
        !          1075:         writeb(1, &dp2_ptr->io.irqdel);
        !          1076:         writeb(0, &dp2_ptr->u.ic.Cmd_Index);
        !          1077:         writeb(1, &dp2_ptr->io.irqen);
        !          1078:     } else if (ha->type == GDT_PCI) {
        !          1079:         dp6_ptr = (gdt6_dpram_str *)ha->brd;
        !          1080:         writeb(1, &dp6_ptr->io.irqdel);
        !          1081:         writeb(0, &dp6_ptr->u.ic.Cmd_Index);
        !          1082:         writeb(1, &dp6_ptr->io.irqen);
        !          1083:     } else if (ha->type == GDT_PCINEW) {
        !          1084:         outb(0xff, PTR2USHORT(&ha->plx->edoor_reg));
        !          1085:         outb(0x03, PTR2USHORT(&ha->plx->control1));
        !          1086:     } else if (ha->type == GDT_PCIMPR) {
        !          1087:         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
        !          1088:         writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
        !          1089:         writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4,
        !          1090:               &dp6m_ptr->i960r.edoor_en_reg);
        !          1091:     }
        !          1092:     restore_flags(flags);
        !          1093: }
        !          1094: 
        !          1095: 
        !          1096: static int gdth_get_status(unchar *pIStatus,int irq)
        !          1097: {
        !          1098:     register gdth_ha_str *ha;
        !          1099:     int i;
        !          1100: 
        !          1101:     TRACE(("gdth_get_status() irq %d ctr_count %d\n",
        !          1102:                  irq,gdth_ctr_count));
        !          1103:     
        !          1104:     *pIStatus = 0;
        !          1105:     for (i=0; i<gdth_ctr_count; ++i) {
        !          1106:         ha = HADATA(gdth_ctr_tab[i]);
        !          1107:         if (ha->irq != (unchar)irq)             /* check IRQ */
        !          1108:             continue;
        !          1109:         if (ha->type == GDT_EISA)
        !          1110:             *pIStatus = inb((ushort)ha->bmic + EDOORREG);
        !          1111:         else if (ha->type == GDT_ISA)
        !          1112:             *pIStatus = readb(&((gdt2_dpram_str *)ha->brd)->u.ic.Cmd_Index);
        !          1113:         else if (ha->type == GDT_PCI)
        !          1114:             *pIStatus = readb(&((gdt6_dpram_str *)ha->brd)->u.ic.Cmd_Index);
        !          1115:         else if (ha->type == GDT_PCINEW) 
        !          1116:             *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
        !          1117:         else if (ha->type == GDT_PCIMPR)
        !          1118:             *pIStatus = readb(&((gdt6m_dpram_str *)ha->brd)->i960r.edoor_reg);
        !          1119:    
        !          1120:         if (*pIStatus)                                  
        !          1121:             return i;                           /* board found */
        !          1122:     }
        !          1123:     return -1;
        !          1124: }
        !          1125:                  
        !          1126:     
        !          1127: static int gdth_test_busy(int hanum)
        !          1128: {
        !          1129:     register gdth_ha_str *ha;
        !          1130:     register int gdtsema0 = 0;
        !          1131: 
        !          1132:     TRACE(("gdth_test_busy() hanum %d\n",hanum));
        !          1133:     
        !          1134:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1135:     if (ha->type == GDT_EISA)
        !          1136:         gdtsema0 = (int)inb(ha->bmic + SEMA0REG);
        !          1137:     else if (ha->type == GDT_ISA)
        !          1138:         gdtsema0 = (int)readb(&((gdt2_dpram_str *)ha->brd)->u.ic.Sema0);
        !          1139:     else if (ha->type == GDT_PCI)
        !          1140:         gdtsema0 = (int)readb(&((gdt6_dpram_str *)ha->brd)->u.ic.Sema0);
        !          1141:     else if (ha->type == GDT_PCINEW) 
        !          1142:         gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg));
        !          1143:     else if (ha->type == GDT_PCIMPR)
        !          1144:         gdtsema0 = (int)readb(&((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg);
        !          1145: 
        !          1146:     return (gdtsema0 & 1);
        !          1147: }
        !          1148: 
        !          1149: 
        !          1150: static int gdth_get_cmd_index(int hanum)
        !          1151: {
        !          1152:     register gdth_ha_str *ha;
        !          1153:     int i;
        !          1154: 
        !          1155:     TRACE(("gdth_get_cmd_index() hanum %d\n",hanum));
        !          1156: 
        !          1157:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1158:     for (i=0; i<GDTH_MAXCMDS; ++i) {
        !          1159:         if (gdth_cmd_tab[i][hanum].cmnd == UNUSED_CMND) {
        !          1160:             gdth_cmd_tab[i][hanum].cmnd = ha->pccb->RequestBuffer;
        !          1161:             gdth_cmd_tab[i][hanum].service = ha->pccb->Service;
        !          1162:             ha->pccb->CommandIndex = (ulong)i+2;
        !          1163:             return (i+2);
        !          1164:         }
        !          1165:     }
        !          1166:     return 0;
        !          1167: }
        !          1168: 
        !          1169: 
        !          1170: static void gdth_set_sema0(int hanum)
        !          1171: {
        !          1172:     register gdth_ha_str *ha;
        !          1173: 
        !          1174:     TRACE(("gdth_set_sema0() hanum %d\n",hanum));
        !          1175: 
        !          1176:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1177:     if (ha->type == GDT_EISA)
        !          1178:         outb(1, ha->bmic + SEMA0REG);
        !          1179:     else if (ha->type == GDT_ISA)
        !          1180:         writeb(1, &((gdt2_dpram_str *)ha->brd)->u.ic.Sema0);
        !          1181:     else if (ha->type == GDT_PCI)
        !          1182:         writeb(1, &((gdt6_dpram_str *)ha->brd)->u.ic.Sema0);
        !          1183:     else if (ha->type == GDT_PCINEW)  
        !          1184:         outb(1, PTR2USHORT(&ha->plx->sema0_reg));
        !          1185:     else if (ha->type == GDT_PCIMPR)
        !          1186:         writeb(1, &((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg);
        !          1187:     
        !          1188: }
        !          1189: 
        !          1190: 
        !          1191: static void gdth_copy_command(int hanum)
        !          1192: {
        !          1193:     register gdth_ha_str *ha;
        !          1194:     register gdth_cmd_str *cmd_ptr;
        !          1195:     register gdt6m_dpram_str *dp6m_ptr;
        !          1196:     register gdt6c_dpram_str *dp6c_ptr;
        !          1197:     gdt6_dpram_str *dp6_ptr;
        !          1198:     gdt2_dpram_str *dp2_ptr;
        !          1199:     ushort cp_count,dp_offset,cmd_no;
        !          1200:     
        !          1201:     TRACE(("gdth_copy_command() hanum %d\n",hanum));
        !          1202: 
        !          1203:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1204:     cp_count = ha->cmd_len;
        !          1205:     dp_offset= ha->cmd_offs_dpmem;
        !          1206:     cmd_no   = ha->cmd_cnt;
        !          1207:     cmd_ptr  = ha->pccb;
        !          1208: 
        !          1209:     ++ha->cmd_cnt;                                                      
        !          1210:     if (ha->type == GDT_EISA)
        !          1211:         return;                                 /* no DPMEM, no copy */
        !          1212: 
        !          1213:     /* set cpcount dword aligned */
        !          1214:     if (cp_count & 3)
        !          1215:         cp_count += (4 - (cp_count & 3));
        !          1216: 
        !          1217:     ha->cmd_offs_dpmem += cp_count;
        !          1218:     
        !          1219:     /* set offset and service, copy command to DPMEM */
        !          1220:     if (ha->type == GDT_ISA) {
        !          1221:         dp2_ptr = (gdt2_dpram_str *)ha->brd;
        !          1222:         writew(dp_offset + DPMEM_COMMAND_OFFSET, 
        !          1223:               &dp2_ptr->u.ic.comm_queue[cmd_no].offset);
        !          1224:         writew((ushort)cmd_ptr->Service, 
        !          1225:               &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id);
        !          1226:        memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
        !          1227:     } else if (ha->type == GDT_PCI) {
        !          1228:         dp6_ptr = (gdt6_dpram_str *)ha->brd;
        !          1229:         writew(dp_offset + DPMEM_COMMAND_OFFSET, 
        !          1230:               &dp6_ptr->u.ic.comm_queue[cmd_no].offset);
        !          1231:         writew((ushort)cmd_ptr->Service, 
        !          1232:               &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id);
        !          1233:         memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
        !          1234:     } else if (ha->type == GDT_PCINEW) {
        !          1235:         dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
        !          1236:         writew(dp_offset + DPMEM_COMMAND_OFFSET, 
        !          1237:               &dp6c_ptr->u.ic.comm_queue[cmd_no].offset);
        !          1238:        writew((ushort)cmd_ptr->Service, 
        !          1239:               &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id);
        !          1240:        memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
        !          1241:     } else if (ha->type == GDT_PCIMPR) {
        !          1242:         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
        !          1243:         writew(dp_offset + DPMEM_COMMAND_OFFSET, 
        !          1244:               &dp6m_ptr->u.ic.comm_queue[cmd_no].offset);
        !          1245:         writew((ushort)cmd_ptr->Service, 
        !          1246:               &dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id);
        !          1247:         memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
        !          1248:     }
        !          1249: }
        !          1250: 
        !          1251: 
        !          1252: static void gdth_release_event(int hanum)
        !          1253: {
        !          1254:     register gdth_ha_str *ha;
        !          1255: 
        !          1256: #ifdef GDTH_STATISTICS
        !          1257:     ulong i,j;
        !          1258:     for (i=0,j=0; j<GDTH_MAXCMDS; ++j) {
        !          1259:         if (gdth_cmd_tab[j][hanum].cmnd != UNUSED_CMND)
        !          1260:             ++i;
        !          1261:     }
        !          1262:     if (max_index < i) {
        !          1263:         max_index = i;
        !          1264:         TRACE3(("GDT: max_index = %d\n",(ushort)i));
        !          1265:     }
        !          1266: #endif
        !          1267: 
        !          1268:     TRACE(("gdth_release_event() hanum %d\n",hanum));
        !          1269:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1270: 
        !          1271:     if (ha->pccb->OpCode == GDT_INIT)
        !          1272:         ha->pccb->Service |= 0x80;
        !          1273: 
        !          1274:     if (ha->type == GDT_EISA) {
        !          1275:         outb(ha->pccb->Service, ha->bmic + LDOORREG);
        !          1276:         if (ha->pccb->OpCode == GDT_INIT)               /* store DMA buffer */
        !          1277:             outl((ulong)ha->pccb, ha->bmic + MAILBOXREG);
        !          1278:     } else if (ha->type == GDT_ISA)
        !          1279:         writeb(0, &((gdt2_dpram_str *)ha->brd)->io.event);
        !          1280:     else if (ha->type == GDT_PCI)
        !          1281:         writeb(0, &((gdt6_dpram_str *)ha->brd)->io.event);
        !          1282:     else if (ha->type == GDT_PCINEW) 
        !          1283:         outb(1, PTR2USHORT(&ha->plx->ldoor_reg));
        !          1284:     else if (ha->type == GDT_PCIMPR)
        !          1285:         writeb(1, &((gdt6m_dpram_str *)ha->brd)->i960r.ldoor_reg);
        !          1286: }
        !          1287: 
        !          1288:     
        !          1289: static int gdth_wait(int hanum,int index,ulong time)
        !          1290: {
        !          1291:     gdth_ha_str *ha;
        !          1292:     int answer_found = FALSE;
        !          1293: 
        !          1294:     TRACE(("gdth_wait() hanum %d index %d time %ld\n",hanum,index,time));
        !          1295: 
        !          1296:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1297:     if (index == 0)
        !          1298:         return 1;                               /* no wait required */
        !          1299: 
        !          1300:     gdth_from_wait = TRUE;
        !          1301:     do {
        !          1302: #if LINUX_VERSION_CODE >= 0x010346
        !          1303:         gdth_interrupt((int)ha->irq,NULL,NULL);
        !          1304: #else
        !          1305:         gdth_interrupt((int)ha->irq,NULL);
        !          1306: #endif
        !          1307:         if (wait_hanum==hanum && wait_index==index) {
        !          1308:             answer_found = TRUE;
        !          1309:             break;
        !          1310:         }
        !          1311:         gdth_delay(1);
        !          1312:     } while (--time);
        !          1313:     gdth_from_wait = FALSE;
        !          1314:     
        !          1315:     while (gdth_test_busy(hanum))
        !          1316:         gdth_delay(0);
        !          1317: 
        !          1318:     return (answer_found);
        !          1319: }
        !          1320: 
        !          1321: 
        !          1322: static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong p1,
        !          1323:                              ulong p2,ulong p3)
        !          1324: {
        !          1325:     register gdth_ha_str *ha;
        !          1326:     register gdth_cmd_str *cmd_ptr;
        !          1327:     int retries,index;
        !          1328: 
        !          1329:     TRACE2(("gdth_internal_cmd() service %d opcode %d\n",service,opcode));
        !          1330: 
        !          1331:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1332:     cmd_ptr = ha->pccb;
        !          1333:     memset((char*)cmd_ptr,0,sizeof(gdth_cmd_str));
        !          1334: 
        !          1335:     /* make command  */
        !          1336:     for (retries = INIT_RETRIES;;) {
        !          1337:         cmd_ptr->Service          = service;
        !          1338:         cmd_ptr->RequestBuffer    = INTERNAL_CMND;
        !          1339:         if (!(index=gdth_get_cmd_index(hanum))) {
        !          1340:             TRACE(("GDT: No free command index found\n"));
        !          1341:             return 0;
        !          1342:         }
        !          1343:         gdth_set_sema0(hanum);
        !          1344:         cmd_ptr->OpCode           = opcode;
        !          1345:         cmd_ptr->BoardNode        = LOCALBOARD;
        !          1346:         if (service == CACHESERVICE) {
        !          1347:             if (opcode == GDT_IOCTL) {
        !          1348:                 cmd_ptr->u.ioctl.subfunc = p1;
        !          1349:                 cmd_ptr->u.ioctl.channel = p2;
        !          1350:                 cmd_ptr->u.ioctl.param_size = (ushort)p3;
        !          1351:                 cmd_ptr->u.ioctl.p_param = virt_to_bus(ha->pscratch);
        !          1352:             } else {
        !          1353:                 cmd_ptr->u.cache.DeviceNo = (ushort)p1;
        !          1354:                 cmd_ptr->u.cache.BlockNo  = p2;
        !          1355:             }
        !          1356:         } else if (service == SCSIRAWSERVICE) {
        !          1357:             cmd_ptr->u.raw.direction  = p1;
        !          1358:             cmd_ptr->u.raw.bus        = (unchar)p2;
        !          1359:             cmd_ptr->u.raw.target     = (unchar)p3;
        !          1360:             cmd_ptr->u.raw.lun        = 0;
        !          1361:         }
        !          1362:         ha->cmd_len          = sizeof(gdth_cmd_str);
        !          1363:         ha->cmd_offs_dpmem   = 0;
        !          1364:         ha->cmd_cnt          = 0;
        !          1365:         gdth_copy_command(hanum);
        !          1366:         gdth_release_event(hanum);
        !          1367:         gdth_delay(20);
        !          1368:         if (!gdth_wait(hanum,index,INIT_TIMEOUT)) {
        !          1369:             printk("GDT: Initialization error (timeout service %d)\n",service);
        !          1370:             return 0;
        !          1371:         }
        !          1372:         if (ha->status != S_BSY || --retries == 0)
        !          1373:             break;
        !          1374:         gdth_delay(1);   
        !          1375:     }   
        !          1376:     
        !          1377:     return (ha->status != S_OK ? 0:1);
        !          1378: }
        !          1379:     
        !          1380: 
        !          1381: /* search for devices */
        !          1382: 
        !          1383: __initfunc (static int gdth_search_drives(int hanum))
        !          1384: {
        !          1385:     register gdth_ha_str *ha;
        !          1386:     ushort cdev_cnt,i;
        !          1387:     unchar b,t,pos_found;
        !          1388:     ulong drv_cyls, drv_hds, drv_secs;
        !          1389:     ulong bus_no;
        !          1390:     gdth_getch_str *chn;
        !          1391:     gdth_iochan_str *ioc;
        !          1392:     
        !          1393:     TRACE(("gdth_search_drives() hanum %d\n",hanum));
        !          1394:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1395: 
        !          1396:     /* initialize controller services, at first: screen service */
        !          1397:     if (!gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0)) {
        !          1398:         printk("GDT: Initialization error screen service (code %d)\n",
        !          1399:                ha->status);
        !          1400:         return 0;
        !          1401:     }
        !          1402:     TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
        !          1403:     
        !          1404:     /* initialize cache service */
        !          1405:     if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
        !          1406:         printk("GDT: Initialization error cache service (code %d)\n",
        !          1407:                ha->status);
        !          1408:         return 0;
        !          1409:     }
        !          1410:     TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
        !          1411:     cdev_cnt = (ushort)ha->info;
        !          1412: 
        !          1413:     /* mount all cache devices */
        !          1414:     gdth_internal_cmd(hanum,CACHESERVICE,GDT_MOUNT,0xffff,1,0);
        !          1415:     TRACE2(("gdth_search_drives(): mountall CACHESERVICE OK\n"));
        !          1416: 
        !          1417:     /* initialize cache service after mountall */
        !          1418:     if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
        !          1419:        printk("GDT: Initialization error cache service (code %d)\n",
        !          1420:               ha->status);
        !          1421:        return 0;
        !          1422:     }
        !          1423:     TRACE2(("gdth_search_drives() CACHES. init. after mountall\n"));
        !          1424:     cdev_cnt = (ushort)ha->info;
        !          1425: 
        !          1426:     /* detect number of SCSI buses - try new IOCTL */
        !          1427:     ioc = (gdth_iochan_str *)DMADATA(gdth_ctr_tab[hanum]);
        !          1428:     ioc->version       = -1UL;
        !          1429:     ioc->list_entries  = MAXBUS;
        !          1430:     ioc->first_chan    = 0;
        !          1431:     ioc->last_chan     = MAXBUS-1;
        !          1432:     ioc->list_offset   = GDTOFFSOF(gdth_iochan_str, list[0]);
        !          1433:     if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,GET_IOCHAN_DESC,
        !          1434:                          INVALID_CHANNEL,sizeof(gdth_iochan_str))) {
        !          1435:        TRACE2(("GET_IOCHAN_DESC supported!\n"));
        !          1436:        ha->bus_cnt = ioc->chan_count;
        !          1437:        for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no)
        !          1438:            if (ioc->list[bus_no].proc_id < MAXID)
        !          1439:                ha->id[bus_no][ioc->list[bus_no].proc_id].type = SIOP_DTYP;
        !          1440:     } else {
        !          1441:        /* old method */
        !          1442:        chn = (gdth_getch_str *)DMADATA(gdth_ctr_tab[hanum]);
        !          1443:        for (bus_no = 0; bus_no < MAXBUS; ++bus_no) {
        !          1444:            chn->channel_no = bus_no;
        !          1445:            if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
        !          1446:                                   SCSI_CHAN_CNT | L_CTRL_PATTERN,
        !          1447:                                   IO_CHANNEL | INVALID_CHANNEL,
        !          1448:                                   sizeof(gdth_getch_str))) {
        !          1449:                if (bus_no == 0) {
        !          1450:                    printk("GDT: Error detecting SCSI channel count (0x%x)\n",
        !          1451:                           ha->status);
        !          1452:                    return 0;
        !          1453:                }
        !          1454:                break;
        !          1455:            }
        !          1456:            if (chn->siop_id < MAXID)
        !          1457:                ha->id[bus_no][chn->siop_id].type = SIOP_DTYP;
        !          1458:        }       
        !          1459:        ha->bus_cnt = (unchar)bus_no;
        !          1460:     }
        !          1461:     TRACE2(("gdth_search_drives() %d SCSI channels\n",ha->bus_cnt));
        !          1462: 
        !          1463:     /* read cache configuration */
        !          1464:     if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
        !          1465:                           INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
        !          1466:        printk("GDT: Initialization error cache service (code %d)\n",
        !          1467:               ha->status);
        !          1468:        return 0;
        !          1469:     }
        !          1470:     ha->cpar = ((gdth_cinfo_str *)DMADATA(gdth_ctr_tab[hanum]))->cpar;
        !          1471:     TRACE2(("gdth_search_drives() cinfo: vs %lx sta %d str %d dw %d b %d\n",
        !          1472:            ha->cpar.version,ha->cpar.state,ha->cpar.strategy,
        !          1473:            ha->cpar.write_back,ha->cpar.block_size));
        !          1474: 
        !          1475:     /* read board info, fill ctr_name[] */
        !          1476:     if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO,
        !          1477:                          INVALID_CHANNEL,sizeof(gdth_binfo_str))) {
        !          1478:        TRACE2(("BOARD_INFO supported!\n"));
        !          1479:        strcpy(ha->ctr_name, ((gdth_binfo_str *)DMADATA(gdth_ctr_tab[hanum]))->type_string);
        !          1480:     } else {
        !          1481:        strcpy(ha->ctr_name, gdth_ctr_name(hanum));
        !          1482:     }
        !          1483:     TRACE2(("Controller name: %s\n",ha->ctr_name));
        !          1484: 
        !          1485:     /* initialize raw service */
        !          1486:     if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0)) {
        !          1487:         printk("GDT: Initialization error raw service (code %d)\n",
        !          1488:                ha->status);
        !          1489:         return 0;
        !          1490:     }
        !          1491:     TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
        !          1492: 
        !          1493:     /* set/get features raw service (scatter/gather) */
        !          1494:     ha->raw_feat = 0;
        !          1495:     if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
        !          1496:                           0,0)) {
        !          1497:         TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
        !          1498:         if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0)) {
        !          1499:             TRACE2(("gdth_search_dr(): get feat RAWSERVICE %ld\n",
        !          1500:                           ha->info));
        !          1501:             ha->raw_feat = (ushort)ha->info;
        !          1502:         }
        !          1503:     } 
        !          1504: 
        !          1505:     /* set/get features cache service (equal to raw service) */
        !          1506:     if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_SET_FEAT,0,
        !          1507:                           SCATTER_GATHER,0)) {
        !          1508:         TRACE2(("gdth_search_drives(): set features CACHESERVICE OK\n"));
        !          1509:         if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) {
        !          1510:             TRACE2(("gdth_search_dr(): get feat CACHESERV. %ld\n",
        !          1511:                           ha->info));
        !          1512:             ha->cache_feat = (ushort)ha->info;
        !          1513:         }
        !          1514:     }
        !          1515: 
        !          1516:     /* reserve drives for raw service */
        !          1517:     for (i = 0; reserve_list[i].hanum != 0xff; ++i) {
        !          1518:        if (reserve_list[i].hanum < MAXHA && reserve_list[i].hanum == hanum &&
        !          1519:            reserve_list[i].bus < MAXBUS && reserve_list[i].id < MAXID) {
        !          1520:            TRACE2(("gdth_search_drives(): reserve ha %d bus %d id %d\n",
        !          1521:                    reserve_list[i].hanum, reserve_list[i].bus,
        !          1522:                    reserve_list[i].id));
        !          1523:            if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE,0,
        !          1524:                                   reserve_list[i].bus, reserve_list[i].id)) {
        !          1525:                printk("GDT: Error raw service (RESERVE, code %d)\n",
        !          1526:                       ha->status);
        !          1527:            }
        !          1528:        }
        !          1529:     }
        !          1530: 
        !          1531:     /* scanning for raw devices */
        !          1532:     for (b=0; b<ha->bus_cnt; ++b) {
        !          1533:         for (t=0; t<MAXID; ++t) {
        !          1534:             TRACE(("gdth_search_drives() rawd. bus %d id %d\n",b,t));
        !          1535:             if (ha->id[b][t].type != SIOP_DTYP && 
        !          1536:                 gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INFO,0,b,t)) {
        !          1537:                 ha->id[b][t].type = RAW_DTYP;
        !          1538:             }
        !          1539:         }
        !          1540:     }
        !          1541: 
        !          1542:     /* scanning for cache devices */
        !          1543:     for (i=0; i<cdev_cnt && i<MAX_HDRIVES; ++i) {
        !          1544:         TRACE(("gdth_search_drives() cachedev. %d\n",i));
        !          1545:         if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,i,0,0)) {
        !          1546:             /* dynamic relation between host drive number and Bus/ID */
        !          1547:             /* search free position */
        !          1548:             pos_found = FALSE;
        !          1549:             for (b=0,t=0; b<ha->bus_cnt; ++b) {
        !          1550:                 for (t=0; t<MAXID; ++t) {
        !          1551:                     if (ha->id[b][t].type == EMPTY_DTYP) {
        !          1552:                         pos_found = TRUE;
        !          1553:                         break;
        !          1554:                     }
        !          1555:                 }
        !          1556:                 if (pos_found)
        !          1557:                     break;
        !          1558:             }
        !          1559:             TRACE(("gdth_search_dr() drive %d free pos at bus/id %d/%d\n",
        !          1560:                          i,b,t));
        !          1561: 
        !          1562:             ha->id[b][t].type      = CACHE_DTYP;
        !          1563:             ha->id[b][t].devtype   = 0;
        !          1564:             ha->id[b][t].size      = ha->info;
        !          1565:             ha->id[b][t].hostdrive = i;
        !          1566: 
        !          1567:             /* evaluate mapping (sectors per head, heads per cylinder) */
        !          1568:            ha->id[b][t].size &= ~SECS32;
        !          1569:            if (ha->info2 == 0) {
        !          1570:                drv_cyls = ha->id[b][t].size /HEADS/SECS;
        !          1571:                if (drv_cyls <= MAXCYLS) {
        !          1572:                    drv_hds = HEADS;
        !          1573:                    drv_secs= SECS;
        !          1574:                } else {                            /* too high for 64*32 */
        !          1575:                    drv_cyls = ha->id[b][t].size /MEDHEADS/MEDSECS;
        !          1576:                    if (drv_cyls <= MAXCYLS) {
        !          1577:                        drv_hds = MEDHEADS;
        !          1578:                        drv_secs= MEDSECS;
        !          1579:                    } else {                        /* too high for 127*63 */
        !          1580:                        drv_cyls = ha->id[b][t].size /BIGHEADS/BIGSECS;
        !          1581:                        drv_hds = BIGHEADS;
        !          1582:                        drv_secs= BIGSECS;
        !          1583:                    }
        !          1584:                }
        !          1585:             } else {
        !          1586:                drv_hds = ha->info2 & 0xff;
        !          1587:                drv_secs = (ha->info2 >> 8) & 0xff;
        !          1588:                drv_cyls = ha->id[b][t].size /drv_hds/drv_secs;
        !          1589:            }
        !          1590:             ha->id[b][t].heads = (unchar)drv_hds;
        !          1591:             ha->id[b][t].secs  = (unchar)drv_secs;
        !          1592:             /* round size */
        !          1593:             ha->id[b][t].size  = drv_cyls * drv_hds * drv_secs;
        !          1594:             TRACE2(("gdth_search_dr() cdr. %d size %ld hds %ld scs %ld\n",
        !          1595:                    i,ha->id[b][t].size,drv_hds,drv_secs));
        !          1596:             
        !          1597:             /* get informations about device */
        !          1598:             if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,i,
        !          1599:                                   0,0)) {
        !          1600:                 TRACE(("gdth_search_dr() cache drive %d devtype %ld\n",
        !          1601:                        i,ha->info));
        !          1602:                 ha->id[b][t].devtype = (ushort)ha->info;
        !          1603:             }
        !          1604:         }
        !          1605:     }
        !          1606: 
        !          1607:     TRACE(("gdth_search_drives() OK\n"));
        !          1608:     return 1;
        !          1609: }
        !          1610: 
        !          1611: 
        !          1612: /* command queueing/sending functions */
        !          1613: 
        !          1614: static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
        !          1615: {
        !          1616:     register gdth_ha_str *ha;
        !          1617:     register Scsi_Cmnd *pscp;
        !          1618:     register Scsi_Cmnd *nscp;
        !          1619:     ulong flags;
        !          1620:     unchar b, t;
        !          1621: 
        !          1622:     TRACE(("gdth_putq() priority %d\n",priority));
        !          1623:     save_flags(flags);
        !          1624:     cli();
        !          1625: 
        !          1626:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1627:     scp->SCp.this_residual = (int)priority;
        !          1628:     gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
        !          1629: #if LINUX_VERSION_CODE >= 0x020000
        !          1630:     b = scp->channel;
        !          1631: #else
        !          1632:     b = NUMDATA(nscp->host)->busnum;
        !          1633: #endif
        !          1634:     t = scp->target;
        !          1635: #if LINUX_VERSION_CODE >= 0x010300
        !          1636:     if (priority >= DEFAULT_PRI && ha->id[b][t].lock) {
        !          1637:         TRACE2(("gdth_putq(): locked IO -> update_timeout()\n"));
        !          1638:         scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
        !          1639:     }
        !          1640: #endif
        !          1641: 
        !          1642:     if (ha->req_first==NULL) {
        !          1643:         ha->req_first = scp;                    /* queue was empty */
        !          1644:         scp->SCp.ptr = NULL;
        !          1645:     } else {                                    /* queue not empty */
        !          1646:         pscp = ha->req_first;
        !          1647:         nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
        !          1648:         /* priority: 0-highest,..,0xff-lowest */
        !          1649:         while (nscp && (unchar)nscp->SCp.this_residual <= priority) {
        !          1650:             pscp = nscp;
        !          1651:             nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
        !          1652:         }
        !          1653:         pscp->SCp.ptr = (char *)scp;
        !          1654:         scp->SCp.ptr  = (char *)nscp;
        !          1655:     }
        !          1656:     restore_flags(flags);
        !          1657: 
        !          1658: #ifdef GDTH_STATISTICS
        !          1659:     flags = 0;
        !          1660:     for (nscp=ha->req_first; nscp; nscp=(Scsi_Cmnd*)nscp->SCp.ptr)
        !          1661:         ++flags;
        !          1662:     if (max_rq < flags) {
        !          1663:         max_rq = flags;
        !          1664:         TRACE3(("GDT: max_rq = %d\n",(ushort)max_rq));
        !          1665:     }
        !          1666: #endif
        !          1667: }
        !          1668: 
        !          1669: static void gdth_next(int hanum)
        !          1670: {
        !          1671:     register gdth_ha_str *ha;
        !          1672:     register Scsi_Cmnd *pscp;
        !          1673:     register Scsi_Cmnd *nscp;
        !          1674:     unchar b, t, next_cmd, firsttime;
        !          1675:     ushort hdrive;
        !          1676:     ulong flags;
        !          1677:     int cmd_index;
        !          1678: 
        !          1679:     TRACE(("gdth_next() hanum %d\n",hanum));
        !          1680:     save_flags(flags);
        !          1681:     cli();
        !          1682: 
        !          1683:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1684:     ha->cmd_cnt = ha->cmd_offs_dpmem = 0;
        !          1685:     next_cmd = firsttime = TRUE;
        !          1686:     cmd_index = 0;
        !          1687: 
        !          1688:     for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
        !          1689:         if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
        !          1690:             pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
        !          1691: #if LINUX_VERSION_CODE >= 0x020000
        !          1692:         b = nscp->channel;
        !          1693: #else
        !          1694:         b = NUMDATA(nscp->host)->busnum;
        !          1695: #endif
        !          1696:         t = nscp->target;
        !          1697:         if (nscp->SCp.this_residual < DEFAULT_PRI || !ha->id[b][t].lock) {
        !          1698: 
        !          1699:             if (firsttime) {
        !          1700:                 if (gdth_test_busy(hanum)) {        /* controller busy ? */
        !          1701:                     TRACE(("gdth_next() controller %d busy !\n",hanum));
        !          1702:                     if (!gdth_polling) {
        !          1703:                         restore_flags(flags);
        !          1704:                         return;
        !          1705:                     }
        !          1706:                     while (gdth_test_busy(hanum))
        !          1707:                         gdth_delay(1);
        !          1708:                 }
        !          1709:                 firsttime = FALSE;
        !          1710:             }
        !          1711: 
        !          1712: #if LINUX_VERSION_CODE >= 0x010300
        !          1713:             if (nscp->done == gdth_scsi_done) {
        !          1714:                 if (!(cmd_index=gdth_special_cmd(hanum,nscp,b)))
        !          1715:                     next_cmd = FALSE;
        !          1716:             } else
        !          1717: #endif
        !          1718:             if (ha->id[b][t].type != CACHE_DTYP) {
        !          1719:                 if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,b)))
        !          1720:                     next_cmd = FALSE;
        !          1721:             } else {
        !          1722:                 hdrive = ha->id[b][t].hostdrive;
        !          1723:                 switch (nscp->cmnd[0]) {
        !          1724:                   case TEST_UNIT_READY:
        !          1725:                   case INQUIRY:
        !          1726:                   case REQUEST_SENSE:
        !          1727:                   case READ_CAPACITY:
        !          1728:                   case VERIFY:
        !          1729:                   case START_STOP:
        !          1730:                   case MODE_SENSE:
        !          1731:                     TRACE2(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
        !          1732:                         nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
        !          1733:                         nscp->cmnd[4],nscp->cmnd[5]));
        !          1734:                         gdth_internal_cache_cmd(hanum,nscp,b,&flags);
        !          1735:                     break;
        !          1736: 
        !          1737:                   case ALLOW_MEDIUM_REMOVAL:
        !          1738:                     TRACE2(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
        !          1739:                         nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
        !          1740:                         nscp->cmnd[4],nscp->cmnd[5]));
        !          1741:                     if ( (nscp->cmnd[4]&1) && !(ha->id[b][t].devtype&1) ) {
        !          1742:                         TRACE2(("Prevent r. nonremov. drive->do nothing\n"));
        !          1743:                         nscp->result = DID_OK << 16;
        !          1744:                         restore_flags( flags );
        !          1745:                         if (!nscp->SCp.have_data_in)
        !          1746:                             nscp->SCp.have_data_in++;
        !          1747:                         else
        !          1748:                             nscp->scsi_done(nscp);
        !          1749:                         save_flags( flags );
        !          1750:                         cli();
        !          1751:                     } else {
        !          1752:                         nscp->cmnd[3] = (ha->id[b][t].devtype&1) ? 1:0;
        !          1753:                         TRACE2(("Prevent/allow r. %d rem. drive %d\n",
        !          1754:                             nscp->cmnd[4],nscp->cmnd[3]));
        !          1755:                         if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,hdrive)))
        !          1756:                             next_cmd = FALSE;
        !          1757:                     }
        !          1758:                     break;
        !          1759: 
        !          1760:                   case READ_6:
        !          1761:                   case WRITE_6:
        !          1762:                   case READ_10:
        !          1763:                   case WRITE_10:
        !          1764:                     if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,hdrive)))
        !          1765:                         next_cmd = FALSE;
        !          1766:                     break;
        !          1767: 
        !          1768:                   default:
        !          1769:                     TRACE2(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
        !          1770:                         nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
        !          1771:                         nscp->cmnd[4],nscp->cmnd[5]));
        !          1772:                     printk("GDT: Unknown SCSI command 0x%x to cache service !\n",
        !          1773:                        nscp->cmnd[0]);
        !          1774:                     nscp->result = DID_ABORT << 16;
        !          1775:                     restore_flags( flags );
        !          1776:                     if (!nscp->SCp.have_data_in)
        !          1777:                         nscp->SCp.have_data_in++;
        !          1778:                     else
        !          1779:                         nscp->scsi_done(nscp);
        !          1780:                     save_flags( flags );
        !          1781:                     cli();
        !          1782:                     break;
        !          1783:                 }
        !          1784:             }
        !          1785: 
        !          1786:             if (!next_cmd)
        !          1787:                 break;
        !          1788:             if (nscp == ha->req_first)
        !          1789:                 ha->req_first = pscp = (Scsi_Cmnd *)nscp->SCp.ptr;
        !          1790:             else
        !          1791:                 pscp->SCp.ptr = nscp->SCp.ptr;
        !          1792:             if (gdth_polling)
        !          1793:                 break;
        !          1794:         }
        !          1795:     }
        !          1796: 
        !          1797:     if (ha->cmd_cnt > 0) {
        !          1798:         gdth_release_event(hanum);
        !          1799:     }
        !          1800: 
        !          1801:     restore_flags(flags);
        !          1802: 
        !          1803:     if (gdth_polling && ha->cmd_cnt > 0) {
        !          1804:         if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
        !          1805:             printk("GDT: Controller %d: Command %d timed out !\n",
        !          1806:                    hanum,cmd_index);
        !          1807:     }
        !          1808: }
        !          1809:     
        !          1810: static void gdth_copy_internal_data(Scsi_Cmnd *scp,char *buffer,ushort count)
        !          1811: {
        !          1812:     ushort cpcount,i;
        !          1813:     ushort cpsum,cpnow;
        !          1814:     struct scatterlist *sl;
        !          1815: 
        !          1816:     cpcount = count<=(ushort)scp->bufflen ? count:(ushort)scp->bufflen;
        !          1817:     if (scp->use_sg) {
        !          1818:         sl = (struct scatterlist *)scp->request_buffer;
        !          1819:         for (i=0,cpsum=0; i<scp->use_sg; ++i,++sl) {
        !          1820:             cpnow = (ushort)sl->length;
        !          1821:             TRACE(("copy_internal() now %d sum %d count %d %d\n",
        !          1822:                           cpnow,cpsum,cpcount,(ushort)scp->bufflen));
        !          1823:             if (cpsum+cpnow > cpcount) 
        !          1824:                 cpnow = cpcount - cpsum;
        !          1825:             cpsum += cpnow;
        !          1826:             memcpy((char*)sl->address,buffer,cpnow);
        !          1827:             if (cpsum == cpcount)
        !          1828:                 break;
        !          1829:             buffer += cpnow;
        !          1830:         }
        !          1831:     } else {
        !          1832:         TRACE(("copy_internal() count %d\n",cpcount));
        !          1833:         memcpy((char*)scp->request_buffer,buffer,cpcount);
        !          1834:     }
        !          1835: }
        !          1836: 
        !          1837: static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp,
        !          1838:                                    unchar b,ulong *flags)
        !          1839: {
        !          1840:     register gdth_ha_str *ha;
        !          1841:     ushort hdrive;
        !          1842:     unchar t;
        !          1843:     gdth_inq_data inq;
        !          1844:     gdth_rdcap_data rdc;
        !          1845:     gdth_sense_data sd;
        !          1846:     gdth_modep_data mpd;
        !          1847: 
        !          1848:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1849:     t  = scp->target;
        !          1850:     hdrive = ha->id[b][t].hostdrive;
        !          1851:     TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n",
        !          1852:                  scp->cmnd[0],hdrive));
        !          1853: 
        !          1854:     if (scp->lun !=0)
        !          1855:         scp->result = DID_BAD_TARGET << 16;
        !          1856:     else {
        !          1857:         switch (scp->cmnd[0]) {
        !          1858:           case TEST_UNIT_READY:
        !          1859:           case VERIFY:
        !          1860:           case START_STOP:
        !          1861:             TRACE2(("Test/Verify/Start hdrive %d\n",hdrive));
        !          1862:             break;
        !          1863: 
        !          1864:           case INQUIRY:
        !          1865:             TRACE2(("Inquiry hdrive %d devtype %d\n",
        !          1866:                           hdrive,ha->id[b][t].devtype));
        !          1867:             inq.type_qual = (ha->id[b][t].devtype&4) ? TYPE_ROM:TYPE_DISK;
        !          1868:             /* you can here set all disks to removable, if you want to do
        !          1869:                a flush using the ALLOW_MEDIUM_REMOVAL command */
        !          1870:             inq.modif_rmb = ha->id[b][t].devtype&1 ? 0x80:0x00;
        !          1871:             inq.version   = 2;
        !          1872:             inq.resp_aenc = 2;
        !          1873:             inq.add_length= 32;
        !          1874:             strcpy(inq.vendor,"ICP    ");
        !          1875:             sprintf(inq.product,"Host Drive  #%02d",hdrive);
        !          1876:             strcpy(inq.revision,"   ");
        !          1877:             gdth_copy_internal_data(scp,(char*)&inq,sizeof(gdth_inq_data));
        !          1878:             break;
        !          1879: 
        !          1880:           case REQUEST_SENSE:
        !          1881:             TRACE2(("Request sense hdrive %d\n",hdrive));
        !          1882:             sd.errorcode = 0x70;
        !          1883:             sd.segno     = 0x00;
        !          1884:             sd.key       = NO_SENSE;
        !          1885:             sd.info      = 0;
        !          1886:             sd.add_length= 0;
        !          1887:             gdth_copy_internal_data(scp,(char*)&sd,sizeof(gdth_sense_data));
        !          1888:             break;
        !          1889: 
        !          1890:           case MODE_SENSE:
        !          1891:             TRACE2(("Mode sense hdrive %d\n",hdrive));
        !          1892:             memset((char*)&mpd,0,sizeof(gdth_modep_data));
        !          1893:             mpd.hd.data_length = sizeof(gdth_modep_data);
        !          1894:             mpd.hd.dev_par     = (ha->id[b][t].devtype&2) ? 0x80:0;
        !          1895:             mpd.hd.bd_length   = sizeof(mpd.bd);
        !          1896:             mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
        !          1897:             mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
        !          1898:             mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff);
        !          1899:             gdth_copy_internal_data(scp,(char*)&mpd,sizeof(gdth_modep_data));
        !          1900:             break;
        !          1901: 
        !          1902:           case READ_CAPACITY:
        !          1903:             TRACE2(("Read capacity hdrive %d\n",hdrive));
        !          1904:             rdc.last_block_no = ntohl(ha->id[b][t].size-1);
        !          1905:             rdc.block_length  = ntohl(SECTOR_SIZE);
        !          1906:             gdth_copy_internal_data(scp,(char*)&rdc,sizeof(gdth_rdcap_data));
        !          1907:             break;
        !          1908: 
        !          1909:           default:
        !          1910:             TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0]));
        !          1911:             break;
        !          1912:         }
        !          1913:         scp->result = DID_OK << 16;
        !          1914:     }
        !          1915: 
        !          1916:     restore_flags(*flags);
        !          1917:     if (!scp->SCp.have_data_in)
        !          1918:         scp->SCp.have_data_in++;
        !          1919:     else
        !          1920:         scp->scsi_done(scp);
        !          1921:     save_flags(*flags);
        !          1922:     cli();
        !          1923:     return 1;
        !          1924: }
        !          1925:     
        !          1926: static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
        !          1927: {
        !          1928:     register gdth_ha_str *ha;
        !          1929:     register gdth_cmd_str *cmdp;
        !          1930:     struct scatterlist *sl;
        !          1931:     ushort i;
        !          1932:     int cmd_index;
        !          1933: 
        !          1934:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          1935:     cmdp = ha->pccb;
        !          1936:     TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n",
        !          1937:                  scp->cmnd[0],scp->cmd_len,hdrive));
        !          1938: 
        !          1939:     if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
        !          1940:         return 0;
        !          1941: 
        !          1942:     cmdp->Service = CACHESERVICE;
        !          1943:     cmdp->RequestBuffer = scp;
        !          1944:     /* search free command index */
        !          1945:     if (!(cmd_index=gdth_get_cmd_index(hanum))) {
        !          1946:         TRACE(("GDT: No free command index found\n"));
        !          1947:         return 0;
        !          1948:     }
        !          1949:     /* if it's the first command, set command semaphore */
        !          1950:     if (ha->cmd_cnt == 0)
        !          1951:         gdth_set_sema0(hanum);
        !          1952: 
        !          1953:     /* fill command */
        !          1954:     if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
        !          1955:         if (scp->cmnd[4] & 1)                   /* prevent ? */
        !          1956:             cmdp->OpCode      = GDT_MOUNT;
        !          1957:         else if (scp->cmnd[3] & 1)              /* removable drive ? */
        !          1958:             cmdp->OpCode      = GDT_UNMOUNT;
        !          1959:         else
        !          1960:             cmdp->OpCode      = GDT_FLUSH;
        !          1961:     } else {
        !          1962:         if (scp->cmnd[0]==WRITE_6 || scp->cmnd[0]==WRITE_10) {
        !          1963:             if (gdth_write_through)
        !          1964:                 cmdp->OpCode  = GDT_WRITE_THR;
        !          1965:             else
        !          1966:                 cmdp->OpCode  = GDT_WRITE;
        !          1967:         } else {
        !          1968:             cmdp->OpCode      = GDT_READ;
        !          1969:         }
        !          1970:     }
        !          1971: 
        !          1972:     cmdp->BoardNode           = LOCALBOARD;
        !          1973:     cmdp->u.cache.DeviceNo    = hdrive;
        !          1974: 
        !          1975:     if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
        !          1976:         cmdp->u.cache.BlockNo = 1;
        !          1977:         cmdp->u.cache.sg_canz = 0;
        !          1978:     } else {
        !          1979:         if (scp->cmd_len != 6) {
        !          1980:             cmdp->u.cache.BlockNo = ntohl(*(ulong*)&scp->cmnd[2]);
        !          1981:             cmdp->u.cache.BlockCnt= (ulong)ntohs(*(ushort*)&scp->cmnd[7]);
        !          1982:         } else {
        !          1983:             cmdp->u.cache.BlockNo = ntohl(*(ulong*)&scp->cmnd[0]) & 0x001fffffUL;
        !          1984:             cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
        !          1985:         }
        !          1986: 
        !          1987:         if (scp->use_sg) {
        !          1988:             cmdp->u.cache.DestAddr= -1UL;
        !          1989:             sl = (struct scatterlist *)scp->request_buffer;
        !          1990:             for (i=0; i<scp->use_sg; ++i,++sl) {
        !          1991:                 cmdp->u.cache.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
        !          1992:                 cmdp->u.cache.sg_lst[i].sg_len = (ulong)sl->length;
        !          1993:             }
        !          1994:             cmdp->u.cache.sg_canz = (ulong)i;
        !          1995: 
        !          1996: #ifdef GDTH_STATISTICS
        !          1997:             if (max_sg < (ulong)i) {
        !          1998:                 max_sg = (ulong)i;
        !          1999:                 TRACE3(("GDT: max_sg = %d\n",i));
        !          2000:             }
        !          2001: #endif
        !          2002:             if (i<GDTH_MAXSG)
        !          2003:                 cmdp->u.cache.sg_lst[i].sg_len = 0;
        !          2004:         } else {
        !          2005:             if (ha->cache_feat & SCATTER_GATHER) {
        !          2006:                 cmdp->u.cache.DestAddr = -1UL;
        !          2007:                 cmdp->u.cache.sg_canz = 1;
        !          2008:                 cmdp->u.cache.sg_lst[0].sg_ptr = virt_to_bus(scp->request_buffer);
        !          2009:                 cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
        !          2010:                 cmdp->u.cache.sg_lst[1].sg_len = 0;
        !          2011:             } else {
        !          2012:                 cmdp->u.cache.DestAddr  = virt_to_bus(scp->request_buffer);
        !          2013:                 cmdp->u.cache.sg_canz= 0;
        !          2014:             }
        !          2015:         }
        !          2016:     }
        !          2017:     TRACE(("cache cmd: addr. %lx sganz %lx sgptr0 %lx sglen0 %lx\n",
        !          2018:                   cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz,
        !          2019:                   cmdp->u.cache.sg_lst[0].sg_ptr,
        !          2020:                   cmdp->u.cache.sg_lst[0].sg_len));
        !          2021:     TRACE(("cache cmd: cmd %d blockno. %ld, blockcnt %ld\n",
        !          2022:                   cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt));
        !          2023: 
        !          2024:     /* evaluate command size, check space */
        !          2025:     ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) +
        !          2026:         (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str);
        !          2027:     if (ha->cmd_len & 3)
        !          2028:         ha->cmd_len += (4 - (ha->cmd_len & 3));
        !          2029: 
        !          2030:     if (ha->cmd_cnt > 0) {
        !          2031:         if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
        !          2032:             ha->ic_all_size) {
        !          2033:             TRACE2(("gdth_fill_cache() DPMEM overflow\n"));
        !          2034:             gdth_cmd_tab[cmd_index-2][hanum].cmnd = UNUSED_CMND;
        !          2035:             return 0;
        !          2036:         }
        !          2037:     }
        !          2038: 
        !          2039:     /* copy command */
        !          2040:     gdth_copy_command(hanum);
        !          2041:     return cmd_index;
        !          2042: }
        !          2043: 
        !          2044: static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
        !          2045: {
        !          2046:     register gdth_ha_str *ha;
        !          2047:     register gdth_cmd_str *cmdp;
        !          2048:     struct scatterlist *sl;
        !          2049:     ushort i;
        !          2050:     int cmd_index;
        !          2051:     unchar t,l;
        !          2052: 
        !          2053:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          2054:     t = scp->target;
        !          2055:     l = scp->lun;
        !          2056:     cmdp = ha->pccb;
        !          2057:     TRACE(("gdth_fill_raw_cmd() cmd 0x%x bus %d ID %d LUN %d\n",
        !          2058:                  scp->cmnd[0],b,t,l));
        !          2059: 
        !          2060:     if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
        !          2061:         return 0;
        !          2062: 
        !          2063:     cmdp->Service = SCSIRAWSERVICE;
        !          2064:     cmdp->RequestBuffer = scp;
        !          2065:     /* search free command index */
        !          2066:     if (!(cmd_index=gdth_get_cmd_index(hanum))) {
        !          2067:         TRACE(("GDT: No free command index found\n"));
        !          2068:         return 0;
        !          2069:     }
        !          2070:     /* if it's the first command, set command semaphore */
        !          2071:     if (ha->cmd_cnt == 0)
        !          2072:         gdth_set_sema0(hanum);
        !          2073: 
        !          2074:     /* fill command */  
        !          2075:     cmdp->OpCode           = GDT_WRITE;         /* always */
        !          2076:     cmdp->BoardNode        = LOCALBOARD;
        !          2077:     cmdp->u.raw.reserved   = 0;
        !          2078:     cmdp->u.raw.mdisc_time = 0;
        !          2079:     cmdp->u.raw.mcon_time  = 0;
        !          2080:     cmdp->u.raw.clen       = scp->cmd_len;
        !          2081:     cmdp->u.raw.target     = t;
        !          2082:     cmdp->u.raw.lun        = l;
        !          2083:     cmdp->u.raw.bus        = b;
        !          2084:     cmdp->u.raw.priority   = 0;
        !          2085:     cmdp->u.raw.link_p     = NULL;
        !          2086:     cmdp->u.raw.sdlen      = scp->request_bufflen;
        !          2087:     cmdp->u.raw.sense_len  = 16;
        !          2088:     cmdp->u.raw.sense_data = virt_to_bus(scp->sense_buffer);
        !          2089:     cmdp->u.raw.direction  = 
        !          2090:         gdth_direction_tab[scp->cmnd[0]]==DOU ? DATA_OUT : DATA_IN;
        !          2091:     memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
        !          2092: 
        !          2093:     if (scp->use_sg) {
        !          2094:         cmdp->u.raw.sdata  = -1UL;
        !          2095:         sl = (struct scatterlist *)scp->request_buffer;
        !          2096:         for (i=0; i<scp->use_sg; ++i,++sl) {
        !          2097:             cmdp->u.raw.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
        !          2098:             cmdp->u.raw.sg_lst[i].sg_len = (ulong)sl->length;
        !          2099:         }
        !          2100:         cmdp->u.raw.sg_ranz = (ulong)i;
        !          2101: 
        !          2102: #ifdef GDTH_STATISTICS
        !          2103:         if (max_sg < (ulong)i) {
        !          2104:             max_sg = (ulong)i;
        !          2105:             TRACE3(("GDT: max_sg = %d\n",i));
        !          2106:         }
        !          2107: #endif
        !          2108:         if (i<GDTH_MAXSG)
        !          2109:             cmdp->u.raw.sg_lst[i].sg_len = 0;
        !          2110:     } else {
        !          2111:         if (ha->raw_feat & SCATTER_GATHER) {
        !          2112:             cmdp->u.raw.sdata  = -1UL;
        !          2113:             cmdp->u.raw.sg_ranz= 1;
        !          2114:             cmdp->u.raw.sg_lst[0].sg_ptr = virt_to_bus(scp->request_buffer);
        !          2115:             cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
        !          2116:             cmdp->u.raw.sg_lst[1].sg_len = 0;
        !          2117:         } else {
        !          2118:             cmdp->u.raw.sdata  = virt_to_bus(scp->request_buffer);
        !          2119:             cmdp->u.raw.sg_ranz= 0;
        !          2120:         }
        !          2121:     }
        !          2122:     TRACE(("raw cmd: addr. %lx sganz %lx sgptr0 %lx sglen0 %lx\n",
        !          2123:                   cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz,
        !          2124:                   cmdp->u.raw.sg_lst[0].sg_ptr,
        !          2125:                   cmdp->u.raw.sg_lst[0].sg_len));
        !          2126: 
        !          2127:     /* evaluate command size, check space */
        !          2128:     ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) +
        !          2129:         (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str);
        !          2130:     if (ha->cmd_len & 3)
        !          2131:         ha->cmd_len += (4 - (ha->cmd_len & 3));
        !          2132: 
        !          2133:     if (ha->cmd_cnt > 0) {
        !          2134:         if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
        !          2135:             ha->ic_all_size) {
        !          2136:             TRACE2(("gdth_fill_raw() DPMEM overflow\n"));
        !          2137:             gdth_cmd_tab[cmd_index-2][hanum].cmnd = UNUSED_CMND;
        !          2138:             return 0;
        !          2139:         }
        !          2140:     }
        !          2141: 
        !          2142:     /* copy command */
        !          2143:     gdth_copy_command(hanum);
        !          2144:     return cmd_index;
        !          2145: }
        !          2146: 
        !          2147: static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
        !          2148: {
        !          2149:     register gdth_ha_str *ha;
        !          2150:     register gdth_cmd_str *cmdp;
        !          2151:     int cmd_index;
        !          2152: 
        !          2153:     ha  = HADATA(gdth_ctr_tab[hanum]);
        !          2154:     cmdp= ha->pccb;
        !          2155:     TRACE2(("gdth_special_cmd(): "));
        !          2156: 
        !          2157:     if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
        !          2158:         return 0;
        !          2159: 
        !          2160:     memcpy( cmdp, scp->request_buffer, sizeof(gdth_cmd_str));
        !          2161:     cmdp->RequestBuffer = scp;
        !          2162: 
        !          2163:     /* search free command index */
        !          2164:     if (!(cmd_index=gdth_get_cmd_index(hanum))) {
        !          2165:         TRACE(("GDT: No free command index found\n"));
        !          2166:         return 0;
        !          2167:     }
        !          2168: 
        !          2169:     /* if it's the first command, set command semaphore */
        !          2170:     if (ha->cmd_cnt == 0)
        !          2171:        gdth_set_sema0(hanum);
        !          2172: 
        !          2173:     /* evaluate command size, check space */
        !          2174:     if (cmdp->OpCode == GDT_IOCTL) {
        !          2175:         TRACE2(("IOCTL\n"));
        !          2176:         ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong);
        !          2177:     } else if (cmdp->Service == CACHESERVICE) {
        !          2178:         TRACE2(("cache command %d\n",cmdp->OpCode));
        !          2179:         ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str);
        !          2180:     } else if (cmdp->Service == SCSIRAWSERVICE) {
        !          2181:         TRACE2(("raw command %d/%d\n",cmdp->OpCode,cmdp->u.raw.cmd[0]));
        !          2182:         ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str);
        !          2183:     }
        !          2184: 
        !          2185:     if (ha->cmd_len & 3)
        !          2186:         ha->cmd_len += (4 - (ha->cmd_len & 3));
        !          2187: 
        !          2188:     if (ha->cmd_cnt > 0) {
        !          2189:         if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
        !          2190:             ha->ic_all_size) {
        !          2191:             TRACE2(("gdth_special_cmd() DPMEM overflow\n"));
        !          2192:             gdth_cmd_tab[cmd_index-2][hanum].cmnd = UNUSED_CMND;
        !          2193:             return 0;
        !          2194:         }
        !          2195:     }
        !          2196: 
        !          2197:     /* copy command */
        !          2198:     gdth_copy_command(hanum);
        !          2199:     return cmd_index;
        !          2200: }    
        !          2201: 
        !          2202: 
        !          2203: /* Controller event handling functions */
        !          2204: static gdth_evt_str *gdth_store_event(ushort source, ushort idx,
        !          2205:                                       gdth_evt_data *evt)
        !          2206: {
        !          2207:     gdth_evt_str *e;
        !          2208:     ulong flags;
        !          2209:     struct timeval tv;
        !          2210: 
        !          2211:     TRACE2(("gdth_store_event() source %d idx %d\n", source, idx));
        !          2212:     if (source == 0)                        /* no source -> no event */
        !          2213:         return 0;
        !          2214: 
        !          2215:     save_flags(flags);
        !          2216:     cli();
        !          2217:     if (ebuffer[elastidx].event_source == source &&
        !          2218:         ebuffer[elastidx].event_idx == idx &&
        !          2219:         !memcmp((char *)&ebuffer[elastidx].event_data.eu,
        !          2220:             (char *)&evt->eu, evt->size)) {
        !          2221:         e = &ebuffer[elastidx];
        !          2222:         do_gettimeofday(&tv);
        !          2223:         e->last_stamp = tv.tv_sec;
        !          2224:         ++e->same_count;
        !          2225:     } else {
        !          2226:         if (ebuffer[elastidx].event_source != 0) {  /* entry not free ? */
        !          2227:             ++elastidx;
        !          2228:             if (elastidx == MAX_EVENTS)
        !          2229:                 elastidx = 0;
        !          2230:             if (elastidx == eoldidx) {              /* reached mark ? */
        !          2231:                 ++eoldidx;
        !          2232:                 if (eoldidx == MAX_EVENTS)
        !          2233:                     eoldidx = 0;
        !          2234:             }
        !          2235:         }
        !          2236:         e = &ebuffer[elastidx];
        !          2237:         e->event_source = source;
        !          2238:         e->event_idx = idx;
        !          2239:         do_gettimeofday(&tv);
        !          2240:         e->first_stamp = e->last_stamp = tv.tv_sec;
        !          2241:         e->same_count = 1;
        !          2242:         e->event_data = *evt;
        !          2243:     }
        !          2244:     restore_flags(flags);
        !          2245:     return e;
        !          2246: }
        !          2247: 
        !          2248: static int gdth_read_event(int handle, gdth_evt_str *estr)
        !          2249: {
        !          2250:     gdth_evt_str *e;
        !          2251:     int eindex;
        !          2252:     ulong flags;
        !          2253: 
        !          2254:     TRACE2(("gdth_read_event() handle %d\n", handle));
        !          2255:     save_flags(flags);
        !          2256:     cli();
        !          2257:     if (handle == -1)
        !          2258:         eindex = eoldidx;
        !          2259:     else
        !          2260:         eindex = handle;
        !          2261:     estr->event_source = 0;
        !          2262: 
        !          2263:     if (eindex >= MAX_EVENTS) {
        !          2264:         restore_flags(flags);
        !          2265:         return eindex;
        !          2266:     }
        !          2267:     e = &ebuffer[eindex];
        !          2268:     if (e->event_source != 0) {
        !          2269:         if (eindex != elastidx) {
        !          2270:             if (++eindex == MAX_EVENTS)
        !          2271:                 eindex = 0;
        !          2272:         } else {
        !          2273:             eindex = -1;
        !          2274:         }
        !          2275:         memcpy(estr, e, sizeof(gdth_evt_str));
        !          2276:     }
        !          2277:     restore_flags(flags);
        !          2278:     return eindex;
        !          2279: }
        !          2280: 
        !          2281: static void gdth_readapp_event(unchar application, gdth_evt_str *estr)
        !          2282: {
        !          2283:     gdth_evt_str *e;
        !          2284:     int eindex;
        !          2285:     ulong flags;
        !          2286:     unchar found = FALSE;
        !          2287: 
        !          2288:     TRACE2(("gdth_readapp_event() app. %d\n", application));
        !          2289:     save_flags(flags);
        !          2290:     cli();
        !          2291:     eindex = eoldidx;
        !          2292:     for (;;) {
        !          2293:         e = &ebuffer[eindex];
        !          2294:         if (e->event_source == 0)
        !          2295:             break;
        !          2296:         if ((e->application & application) == 0) {
        !          2297:             e->application |= application;
        !          2298:             found = TRUE;
        !          2299:             break;
        !          2300:         }
        !          2301:         if (eindex == elastidx)
        !          2302:             break;
        !          2303:         if (++eindex == MAX_EVENTS)
        !          2304:             eindex = 0;
        !          2305:     }
        !          2306:     if (found)
        !          2307:         memcpy(estr, e, sizeof(gdth_evt_str));
        !          2308:     else
        !          2309:         estr->event_source = 0;
        !          2310:     restore_flags(flags);
        !          2311: }
        !          2312: 
        !          2313: static void gdth_clear_events()
        !          2314: {
        !          2315:     ulong flags;
        !          2316: 
        !          2317:     TRACE(("gdth_clear_events()"));
        !          2318:     save_flags(flags);
        !          2319:     cli();
        !          2320: 
        !          2321:     eoldidx = elastidx = 0;
        !          2322:     ebuffer[0].event_source = 0;
        !          2323:     restore_flags(flags);
        !          2324: }
        !          2325: 
        !          2326: 
        !          2327: /* SCSI interface functions */
        !          2328: 
        !          2329: #if LINUX_VERSION_CODE >= 0x02015F
        !          2330: static void do_gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
        !          2331: {
        !          2332:     ulong flags;
        !          2333: 
        !          2334:     spin_lock_irqsave(&io_request_lock, flags);
        !          2335:     gdth_interrupt(irq, dev_id, regs);
        !          2336:     spin_unlock_irqrestore(&io_request_lock, flags);
        !          2337: }
        !          2338: #endif
        !          2339: 
        !          2340: #if LINUX_VERSION_CODE >= 0x010346
        !          2341: static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
        !          2342: #else
        !          2343: static void gdth_interrupt(int irq,struct pt_regs *regs)
        !          2344: #endif
        !          2345: {
        !          2346:     register gdth_ha_str *ha;
        !          2347:     gdt6m_dpram_str *dp6m_ptr;
        !          2348:     gdt6_dpram_str *dp6_ptr;
        !          2349:     gdt2_dpram_str *dp2_ptr;
        !          2350:     Scsi_Cmnd *scp;
        !          2351:     int hanum;
        !          2352:     unchar IStatus;
        !          2353:     ushort CmdStatus, Service = 0;
        !          2354:     ulong InfoBytes, InfoBytes2 = 0;
        !          2355:     gdth_evt_data dvr;
        !          2356: 
        !          2357:     TRACE(("gdth_interrupt() IRQ %d\n",irq));
        !          2358: 
        !          2359:     /* if polling and not from gdth_wait() -> return */
        !          2360:     if (gdth_polling) {
        !          2361:         if (!gdth_from_wait) {
        !          2362:             return;
        !          2363:         }
        !          2364:     }
        !          2365: 
        !          2366:     wait_index = 0;
        !          2367: 
        !          2368:     /* search controller */
        !          2369:     if ((hanum = gdth_get_status(&IStatus,irq)) == -1) {
        !          2370:         /*
        !          2371:         TRACE2(("gdth_interrupt(): Spurious interrupt received\n"));
        !          2372:         */
        !          2373:         return;
        !          2374:     }
        !          2375: 
        !          2376: #ifdef GDTH_STATISTICS
        !          2377:     ++act_ints;
        !          2378: #endif
        !          2379:     
        !          2380:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          2381:     if (ha->type == GDT_EISA) {
        !          2382:         if (IStatus & 0x80) {                   /* error flag */
        !          2383:             IStatus &= ~0x80;
        !          2384:             CmdStatus = inw(ha->bmic + MAILBOXREG+8);
        !          2385:             TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
        !          2386:             if (IStatus == ASYNCINDEX) {        /* async. event ? */
        !          2387:                 Service = inw(ha->bmic + MAILBOXREG+10);
        !          2388:                 InfoBytes2 = inl(ha->bmic + MAILBOXREG+4);
        !          2389:             }
        !          2390:         } else                                  /* no error */
        !          2391:             CmdStatus = S_OK;
        !          2392:         InfoBytes = inl(ha->bmic + MAILBOXREG+12);
        !          2393:        if (gdth_polling)                       /* init. -> more info */
        !          2394:            InfoBytes2 = inl(ha->bmic + MAILBOXREG+4);
        !          2395:         outb(0xff, ha->bmic + EDOORREG);    /* acknowledge interrupt */
        !          2396:         outb(0x00, ha->bmic + SEMA1REG);    /* reset status semaphore */
        !          2397:     } else if (ha->type == GDT_ISA) {
        !          2398:         dp2_ptr = (gdt2_dpram_str *)ha->brd;
        !          2399:         if (IStatus & 0x80) {                   /* error flag */
        !          2400:             IStatus &= ~0x80;
        !          2401:             CmdStatus = readw(&dp2_ptr->u.ic.Status);
        !          2402:             TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
        !          2403:             if (IStatus == ASYNCINDEX) {        /* async. event ? */
        !          2404:                 Service = readw(&dp2_ptr->u.ic.Service);
        !          2405:                 InfoBytes2 = readl(&dp2_ptr->u.ic.Info[1]);
        !          2406:             }
        !          2407:         } else                                  /* no error */
        !          2408:             CmdStatus = S_OK;
        !          2409:         InfoBytes = readl(&dp2_ptr->u.ic.Info[0]);
        !          2410:        if (gdth_polling)                       /* init. -> more info */
        !          2411:            InfoBytes2 = readl(&dp2_ptr->u.ic.Info[1]);
        !          2412:         writeb(0xff, &dp2_ptr->io.irqdel);              /* acknowledge interrupt */
        !          2413:         writeb(0, &dp2_ptr->u.ic.Cmd_Index);            /* reset command index */
        !          2414:         writeb(0, &dp2_ptr->io.Sema1);                 /* reset status semaphore */
        !          2415:     } else if (ha->type == GDT_PCI) {
        !          2416:         dp6_ptr = (gdt6_dpram_str *)ha->brd;
        !          2417:         if (IStatus & 0x80) {                   /* error flag */
        !          2418:             IStatus &= ~0x80;
        !          2419:             CmdStatus = readw(&dp6_ptr->u.ic.Status);
        !          2420:             TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
        !          2421:             if (IStatus == ASYNCINDEX) {        /* async. event ? */
        !          2422:                 Service = readw(&dp6_ptr->u.ic.Service);
        !          2423:                 InfoBytes2 = readl(&dp6_ptr->u.ic.Info[1]);
        !          2424:             }
        !          2425:         } else                                  /* no error */
        !          2426:             CmdStatus = S_OK;
        !          2427:         InfoBytes = readl(&dp6_ptr->u.ic.Info[0]);
        !          2428:        if (gdth_polling)                       /* init. -> more info */
        !          2429:            InfoBytes2 = readl(&dp6_ptr->u.ic.Info[1]);
        !          2430:         writeb(0xff, &dp6_ptr->io.irqdel);              /* acknowledge interrupt */
        !          2431:         writeb(0, &dp6_ptr->u.ic.Cmd_Index);            /* reset command index */
        !          2432:         writeb(0, &dp6_ptr->io.Sema1);                 /* reset status semaphore */
        !          2433:     } else if (ha->type == GDT_PCINEW) {
        !          2434:         if (IStatus & 0x80) {                   /* error flag */
        !          2435:             IStatus &= ~0x80;
        !          2436:             CmdStatus = inw(PTR2USHORT(&ha->plx->status));
        !          2437:             TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
        !          2438:             if (IStatus == ASYNCINDEX) {        /* async. event ? */
        !          2439:                 Service = inw(PTR2USHORT(&ha->plx->service));
        !          2440:                 InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1]));
        !          2441:             }
        !          2442:         } else
        !          2443:             CmdStatus = S_OK;
        !          2444: 
        !          2445:         InfoBytes = inl(PTR2USHORT(&ha->plx->info[0]));
        !          2446:        if (gdth_polling)                       /* init. -> more info */
        !          2447:            InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1]));
        !          2448:         outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 
        !          2449:         outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); 
        !          2450:     } else if (ha->type == GDT_PCIMPR) {
        !          2451:         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
        !          2452:         if (IStatus & 0x80) {                   /* error flag */
        !          2453:             IStatus &= ~0x80;
        !          2454:             CmdStatus = readw(&dp6m_ptr->i960r.status);
        !          2455:             TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
        !          2456:             if (IStatus == ASYNCINDEX) {        /* async. event ? */
        !          2457:                 Service = readw(&dp6m_ptr->i960r.service);
        !          2458:                 InfoBytes2 = readl(&dp6m_ptr->i960r.info[1]);
        !          2459:             }
        !          2460:         } else                                  /* no error */
        !          2461:             CmdStatus = S_OK;
        !          2462:         InfoBytes = readl(&dp6m_ptr->i960r.info[0]);
        !          2463:        if (gdth_polling)                       /* init. -> more info */
        !          2464:            InfoBytes2 = readl(&dp6m_ptr->i960r.info[1]);
        !          2465:         writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
        !          2466:         writeb(0, &dp6m_ptr->i960r.sema1_reg);
        !          2467:     } else {
        !          2468:         TRACE2(("gdth_interrupt() unknown controller type\n"));
        !          2469:         return;
        !          2470:     }
        !          2471: 
        !          2472:     TRACE(("gdth_interrupt() index %d stat %d info %ld\n",
        !          2473:                  IStatus,CmdStatus,InfoBytes));
        !          2474:     ha->status = CmdStatus;
        !          2475:     ha->info   = InfoBytes;
        !          2476:     ha->info2  = InfoBytes2;
        !          2477: 
        !          2478:     if (gdth_from_wait) {
        !          2479:         wait_hanum = hanum;
        !          2480:         wait_index = (int)IStatus;
        !          2481:     }
        !          2482: 
        !          2483:     if (IStatus == ASYNCINDEX) {
        !          2484:         TRACE2(("gdth_interrupt() async. event\n"));
        !          2485:         gdth_async_event(hanum,Service);
        !          2486:     } else {
        !          2487:         if (IStatus == SPEZINDEX) {
        !          2488:             TRACE2(("Service unknown or not initialized !\n"));
        !          2489:             dvr.size = sizeof(dvr.eu.driver);
        !          2490:             dvr.eu.driver.ionode = hanum;
        !          2491:             gdth_store_event(ES_DRIVER, 4, &dvr);
        !          2492:             return;
        !          2493:         }
        !          2494:         scp     = gdth_cmd_tab[IStatus-2][hanum].cmnd;
        !          2495:         Service = gdth_cmd_tab[IStatus-2][hanum].service;
        !          2496:         gdth_cmd_tab[IStatus-2][hanum].cmnd = UNUSED_CMND;
        !          2497:         if (scp == UNUSED_CMND) {
        !          2498:             TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
        !          2499:             dvr.size = sizeof(dvr.eu.driver);
        !          2500:             dvr.eu.driver.ionode = hanum;
        !          2501:             dvr.eu.driver.index = IStatus;
        !          2502:             gdth_store_event(ES_DRIVER, 1, &dvr);
        !          2503:             return;
        !          2504:         }
        !          2505:         if (scp == INTERNAL_CMND) {
        !          2506:             TRACE(("gdth_interrupt() answer to internal command\n"));
        !          2507:             return;
        !          2508:         }
        !          2509:         TRACE(("gdth_interrupt() sync. status\n"));
        !          2510:         gdth_sync_event(hanum,Service,IStatus,scp);
        !          2511:     }
        !          2512:     gdth_next(hanum);
        !          2513: }
        !          2514: 
        !          2515: static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
        !          2516: {
        !          2517:     register gdth_ha_str *ha;
        !          2518:     gdth_msg_str *msg;
        !          2519:     gdth_cmd_str *cmdp;
        !          2520:     char c='\r';
        !          2521:     ushort i;
        !          2522:     gdth_evt_data dvr;
        !          2523: 
        !          2524:     ha   = HADATA(gdth_ctr_tab[hanum]);
        !          2525:     cmdp = ha->pccb;
        !          2526:     TRACE(("gdth_sync_event() scp %lx serv %d status %d\n",
        !          2527:                  (ulong)scp,service,ha->status));
        !          2528: 
        !          2529:     if (service == SCREENSERVICE) {
        !          2530:         msg  = (gdth_msg_str *)ha->pscratch;
        !          2531:         TRACE(("len: %ld, answer: %d, ext: %d, alen: %ld\n",
        !          2532:                      msg->msg_len,msg->msg_answer,msg->msg_ext,msg->msg_alen));
        !          2533:         if (msg->msg_len)
        !          2534:             if (!(msg->msg_answer && msg->msg_ext)) {
        !          2535:                 msg->msg_text[msg->msg_len] = '\0';
        !          2536:                 printk("%s",msg->msg_text);
        !          2537:             }
        !          2538: 
        !          2539:         if (msg->msg_ext && !msg->msg_answer) {
        !          2540:             while (gdth_test_busy(hanum))
        !          2541:                 gdth_delay(0);
        !          2542:             cmdp->Service       = SCREENSERVICE;
        !          2543:             cmdp->RequestBuffer = SCREEN_CMND;
        !          2544:             gdth_get_cmd_index(hanum);
        !          2545:             gdth_set_sema0(hanum);
        !          2546:             cmdp->OpCode        = GDT_READ;
        !          2547:             cmdp->BoardNode     = LOCALBOARD;
        !          2548:             cmdp->u.screen.reserved  = 0;
        !          2549:             cmdp->u.screen.msg_handle= msg->msg_handle;
        !          2550:             cmdp->u.screen.msg_addr  = (ulong)msg;
        !          2551:             ha->cmd_offs_dpmem = 0;
        !          2552:             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
        !          2553:                 + sizeof(ulong);
        !          2554:             ha->cmd_cnt = 0;
        !          2555:             gdth_copy_command(hanum);
        !          2556:             gdth_release_event(hanum);
        !          2557:             return 1;
        !          2558:         }
        !          2559: 
        !          2560:         if (msg->msg_answer && msg->msg_alen) {
        !          2561:             for (i=0; i<msg->msg_alen && i<MSGLEN; ++i) {
        !          2562:                 /* getchar() ?? */           
        !          2563:                 /* .. */
        !          2564:                 if (c == '\r')
        !          2565:                     break;
        !          2566:                 msg->msg_text[i] = c; 
        !          2567:             }
        !          2568:             msg->msg_alen -= i;
        !          2569:             if (c!='\r' && msg->msg_alen!=0) {
        !          2570:                 msg->msg_answer = 1;
        !          2571:                 msg->msg_ext    = 1;
        !          2572:             } else {
        !          2573:                 msg->msg_ext    = 0;
        !          2574:                 msg->msg_answer = 0;
        !          2575:             }
        !          2576:             msg->msg_len = i;
        !          2577:             while (gdth_test_busy(hanum))
        !          2578:                 gdth_delay(0);
        !          2579:             cmdp->Service       = SCREENSERVICE;
        !          2580:             cmdp->RequestBuffer = SCREEN_CMND;
        !          2581:             gdth_get_cmd_index(hanum);
        !          2582:             gdth_set_sema0(hanum);
        !          2583:             cmdp->OpCode        = GDT_WRITE;
        !          2584:             cmdp->BoardNode     = LOCALBOARD;
        !          2585:             cmdp->u.screen.reserved  = 0;
        !          2586:             cmdp->u.screen.msg_handle= msg->msg_handle;
        !          2587:             cmdp->u.screen.msg_addr  = (ulong)msg;
        !          2588:             ha->cmd_offs_dpmem = 0;
        !          2589:             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
        !          2590:                 + sizeof(ulong);
        !          2591:             ha->cmd_cnt = 0;
        !          2592:             gdth_copy_command(hanum);
        !          2593:             gdth_release_event(hanum);
        !          2594:             return 1;
        !          2595:         }
        !          2596:         printk("\n");
        !          2597: 
        !          2598:     } else {
        !          2599:         scp->SCp.Message = (int)ha->status;
        !          2600:         /* cache or raw service */
        !          2601:         if (ha->status == S_OK) {
        !          2602:             scp->result = DID_OK << 16;
        !          2603:         } else if (ha->status == S_BSY) {
        !          2604:             TRACE2(("Controller busy -> retry !\n"));
        !          2605:             gdth_putq(hanum,scp,scp->SCp.this_residual);
        !          2606:             return 1;
        !          2607:         } else {
        !          2608:             if (service == CACHESERVICE) {
        !          2609:                 memset((char*)scp->sense_buffer,0,16);
        !          2610:                 scp->sense_buffer[0] = 0x70;
        !          2611:                 scp->sense_buffer[2] = NOT_READY;
        !          2612:                 scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
        !          2613: 
        !          2614:                 if (scp->done != gdth_scsi_done) {
        !          2615:                     dvr.size = sizeof(dvr.eu.sync);
        !          2616:                     dvr.eu.sync.ionode  = hanum;
        !          2617:                     dvr.eu.sync.service = service;
        !          2618:                     dvr.eu.sync.status  = ha->status;
        !          2619:                     dvr.eu.sync.info    = ha->info;
        !          2620:                     dvr.eu.sync.hostdrive =
        !          2621: #if LINUX_VERSION_CODE >= 0x020000
        !          2622:                         ha->id[scp->channel][scp->target].hostdrive;
        !          2623: #else
        !          2624:                         ha->id[NUMDATA(scp->host)->busnum][scp->target].hostdrive;
        !          2625: #endif
        !          2626:                     if (ha->status >= 0x8000)
        !          2627:                         gdth_store_event(ES_SYNC, 0, &dvr);
        !          2628:                     else
        !          2629:                         gdth_store_event(ES_SYNC, service, &dvr);
        !          2630:                 }
        !          2631:             } else {
        !          2632:                 if (ha->status!=S_RAW_SCSI || ha->status==S_RAW_ILL || ha->info>=0x100) {
        !          2633:                     scp->result = DID_BAD_TARGET << 16;
        !          2634:                 } else {
        !          2635:                     scp->result = (DID_OK << 16) | ha->info;
        !          2636:                 }
        !          2637:             }
        !          2638:         }
        !          2639:        if (!scp->SCp.have_data_in)
        !          2640:            scp->SCp.have_data_in++;
        !          2641:        else
        !          2642:            scp->scsi_done(scp);
        !          2643:     }
        !          2644: 
        !          2645:     return 1;
        !          2646: }
        !          2647: 
        !          2648: static char *async_cache_tab[] = {
        !          2649: /* 0*/  "\011\000\002\002\002\004\002\006\004"
        !          2650:         "GDT HA %u, service %u, async. status %u/%lu unknown",
        !          2651: /* 1*/  "\011\000\002\002\002\004\002\006\004"
        !          2652:         "GDT HA %u, service %u, async. status %u/%lu unknown",
        !          2653: /* 2*/  "\005\000\002\006\004"
        !          2654:         "GDT HA %u, Host Drive %lu not ready",
        !          2655: /* 3*/  "\005\000\002\006\004"
        !          2656:         "GDT HA %u, Host Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced",
        !          2657: /* 4*/  "\005\000\002\006\004"
        !          2658:         "GDT HA %u, mirror update on Host Drive %lu failed",
        !          2659: /* 5*/  "\005\000\002\006\004"
        !          2660:         "GDT HA %u, Mirror Drive %lu failed",
        !          2661: /* 6*/  "\005\000\002\006\004"
        !          2662:         "GDT HA %u, Mirror Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced",
        !          2663: /* 7*/  "\005\000\002\006\004"
        !          2664:         "GDT HA %u, Host Drive %lu write protected",
        !          2665: /* 8*/  "\005\000\002\006\004"
        !          2666:         "GDT HA %u, media changed in Host Drive %lu",
        !          2667: /* 9*/  "\005\000\002\006\004"
        !          2668:         "GDT HA %u, Host Drive %lu is offline",
        !          2669: /*10*/  "\005\000\002\006\004"
        !          2670:         "GDT HA %u, media change of Mirror Drive %lu",
        !          2671: /*11*/  "\005\000\002\006\004"
        !          2672:         "GDT HA %u, Mirror Drive %lu is write protected",
        !          2673: /*12*/  "\005\000\002\006\004"
        !          2674:         "GDT HA %u, general error on Host Drive %lu. Please check the devices of this drive!",
        !          2675: /*13*/  "\007\000\002\006\002\010\002"
        !          2676:         "GDT HA %u, Array Drive %u: Cache Drive %u failed",
        !          2677: /*14*/  "\005\000\002\006\002"
        !          2678:         "GDT HA %u, Array Drive %u: FAIL state entered",
        !          2679: /*15*/  "\005\000\002\006\002"
        !          2680:         "GDT HA %u, Array Drive %u: error",
        !          2681: /*16*/  "\007\000\002\006\002\010\002"
        !          2682:         "GDT HA %u, Array Drive %u: failed drive replaced by Cache Drive %u",
        !          2683: /*17*/  "\005\000\002\006\002"
        !          2684:         "GDT HA %u, Array Drive %u: parity build failed",
        !          2685: /*18*/  "\005\000\002\006\002"
        !          2686:         "GDT HA %u, Array Drive %u: drive rebuild failed",
        !          2687: /*19*/  "\007\000\002\010\002"
        !          2688:         "GDT HA %u, Test of Hot Fix %u failed",
        !          2689: /*20*/  "\005\000\002\006\002"
        !          2690:         "GDT HA %u, Array Drive %u: drive build finished successfully",
        !          2691: /*21*/  "\005\000\002\006\002"
        !          2692:         "GDT HA %u, Array Drive %u: drive rebuild finished successfully",
        !          2693: /*22*/  "\007\000\002\006\002\010\002"
        !          2694:         "GDT HA %u, Array Drive %u: Hot Fix %u activated",
        !          2695: /*23*/  "\005\000\002\006\002"
        !          2696:         "GDT HA %u, Host Drive %u: processing of i/o aborted due to serious drive error",
        !          2697: /*24*/  "\005\000\002\010\002"
        !          2698:         "GDT HA %u, mirror update on Cache Drive %u completed",
        !          2699: /*25*/  "\005\000\002\010\002"
        !          2700:         "GDT HA %u, mirror update on Cache Drive %lu failed",
        !          2701: /*26*/  "\005\000\002\006\002"
        !          2702:         "GDT HA %u, Array Drive %u: drive rebuild started",
        !          2703: /*27*/  "\005\000\002\012\001"
        !          2704:         "GDT HA %u, Fault bus %u: SHELF OK detected",
        !          2705: /*28*/  "\005\000\002\012\001"
        !          2706:         "GDT HA %u, Fault bus %u: SHELF not OK detected",
        !          2707: /*29*/  "\007\000\002\012\001\013\001"
        !          2708:         "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug started",
        !          2709: /*30*/  "\007\000\002\012\001\013\001"
        !          2710:         "GDT HA %u, Fault bus %u, ID %u: new disk detected",
        !          2711: /*31*/  "\007\000\002\012\001\013\001"
        !          2712:         "GDT HA %u, Fault bus %u, ID %u: old disk detected",
        !          2713: /*32*/  "\007\000\002\012\001\013\001"
        !          2714:         "GDT HA %u, Fault bus %u, ID %u: plugging an active disk is illegal",
        !          2715: /*33*/  "\007\000\002\012\001\013\001"
        !          2716:         "GDT HA %u, Fault bus %u, ID %u: illegal device detected",
        !          2717: /*34*/  "\011\000\002\012\001\013\001\006\004"
        !          2718:         "GDT HA %u, Fault bus %u, ID %u: insufficient disk capacity (%lu MB required)",
        !          2719: /*35*/  "\007\000\002\012\001\013\001"
        !          2720:         "GDT HA %u, Fault bus %u, ID %u: disk write protected",
        !          2721: /*36*/  "\007\000\002\012\001\013\001"
        !          2722:         "GDT HA %u, Fault bus %u, ID %u: disk not available",
        !          2723: /*37*/  "\007\000\002\012\001\006\004"
        !          2724:         "GDT HA %u, Fault bus %u: swap detected (%lu)",
        !          2725: /*38*/  "\007\000\002\012\001\013\001"
        !          2726:         "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug finished successfully",
        !          2727: /*39*/  "\007\000\002\012\001\013\001"
        !          2728:         "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted due to user Hot Plug",
        !          2729: /*40*/  "\007\000\002\012\001\013\001"
        !          2730:         "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted",
        !          2731: /*41*/  "\007\000\002\012\001\013\001"
        !          2732:         "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug for Hot Fix started",
        !          2733: /*42*/  "\005\000\002\006\002"
        !          2734:         "GDT HA %u, Array Drive %u: drive build started",
        !          2735: /*43*/  "\003\000\002"
        !          2736:         "GDT HA %u, DRAM parity error detected",
        !          2737: /*44*/  "\005\000\002\006\002"
        !          2738:         "GDT HA %u, Mirror Drive %u: update started",
        !          2739: /*45*/  "\007\000\002\006\002\010\002"
        !          2740:         "GDT HA %u, Mirror Drive %u: Hot Fix %u activated",
        !          2741: /*46*/  "\005\000\002\006\002"
        !          2742:         "GDT HA %u, Array Drive %u: no matching Pool Hot Fix Drive available",
        !          2743: /*47*/  "\005\000\002\006\002"
        !          2744:         "GDT HA %u, Array Drive %u: Pool Hot Fix Drive available",
        !          2745: /*48*/  "\005\000\002\006\002"
        !          2746:         "GDT HA %u, Mirror Drive %u: no matching Pool Hot Fix Drive available",
        !          2747: /*49*/  "\005\000\002\006\002"
        !          2748:         "GDT HA %u, Mirror Drive %u: Pool Hot Fix Drive available",
        !          2749: /*50*/  "\007\000\002\012\001\013\001"
        !          2750:         "GDT HA %u, SCSI bus %u, ID %u: IGNORE_WIDE_RESIDUE message received",
        !          2751: /*51*/  "\005\000\002\006\002"
        !          2752:         "GDT HA %u, Array Drive %u: expand started",
        !          2753: /*52*/  "\005\000\002\006\002"
        !          2754:         "GDT HA %u, Array Drive %u: expand finished successfully",
        !          2755: /*53*/  "\005\000\002\006\002"
        !          2756:         "GDT HA %u, Array Drive %u: expand failed",
        !          2757: /*54*/  "\003\000\002"
        !          2758:         "GDT HA %u, CPU temperature critical",
        !          2759: /*55*/  "\003\000\002"
        !          2760:         "GDT HA %u, CPU temperature OK",
        !          2761: /*56*/  "\005\000\002\006\004"
        !          2762:         "GDT HA %u, Host drive %lu created",
        !          2763: /*57*/  "\005\000\002\006\002"
        !          2764:         "GDT HA %u, Array Drive %u: expand restarted",
        !          2765: /*58*/  "\005\000\002\006\002"
        !          2766:         "GDT HA %u, Array Drive %u: expand stopped",
        !          2767: };
        !          2768: 
        !          2769: 
        !          2770: static int gdth_async_event(int hanum,int service)
        !          2771: {
        !          2772:     gdth_stackframe stack;
        !          2773:     gdth_evt_data dvr;
        !          2774:     char *f = NULL;
        !          2775:     int i,j;
        !          2776:     gdth_ha_str *ha;
        !          2777:     gdth_msg_str *msg;
        !          2778:     gdth_cmd_str *cmdp;
        !          2779:     int cmd_index;
        !          2780: 
        !          2781:     ha  = HADATA(gdth_ctr_tab[hanum]);
        !          2782:     cmdp= ha->pccb;
        !          2783:     msg = (gdth_msg_str *)ha->pscratch;
        !          2784:     TRACE2(("gdth_async_event() ha %d serv %d\n",
        !          2785:                  hanum,service));
        !          2786: 
        !          2787:     if (service == SCREENSERVICE) {
        !          2788:         if (ha->status == MSG_REQUEST) {
        !          2789:             while (gdth_test_busy(hanum))
        !          2790:                 gdth_delay(0);
        !          2791:             cmdp->Service       = SCREENSERVICE;
        !          2792:             cmdp->RequestBuffer = SCREEN_CMND;
        !          2793:             cmd_index = gdth_get_cmd_index(hanum);
        !          2794:             gdth_set_sema0(hanum);
        !          2795:             cmdp->OpCode        = GDT_READ;
        !          2796:             cmdp->BoardNode     = LOCALBOARD;
        !          2797:             cmdp->u.screen.reserved  = 0;
        !          2798:             cmdp->u.screen.msg_handle= MSG_INV_HANDLE;
        !          2799:             cmdp->u.screen.msg_addr  = (ulong)msg;
        !          2800:             ha->cmd_offs_dpmem = 0;
        !          2801:             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
        !          2802:                 + sizeof(ulong);
        !          2803:             ha->cmd_cnt = 0;
        !          2804:             gdth_copy_command(hanum);
        !          2805:             if (ha->type == GDT_EISA)
        !          2806:                 printk("[EISA slot %d] ",(ushort)ha->brd_phys);
        !          2807:             else if (ha->type == GDT_ISA)
        !          2808:                 printk("[DPMEM 0x%4X] ",(ushort)ha->brd_phys);
        !          2809:             else 
        !          2810:                 printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8),
        !          2811:                        (ushort)((ha->brd_phys>>3)&0x1f));
        !          2812:             gdth_release_event(hanum);
        !          2813:         }
        !          2814: 
        !          2815:     } else {
        !          2816:         dvr.size = sizeof(dvr.eu.async);
        !          2817:         dvr.eu.async.ionode   = hanum;
        !          2818:         dvr.eu.async.service = service;
        !          2819:         dvr.eu.async.status  = ha->status;
        !          2820:         dvr.eu.async.info    = ha->info;
        !          2821:         *(ulong *)dvr.eu.async.scsi_coord  = ha->info2;
        !          2822:         gdth_store_event(ES_ASYNC, service, &dvr);
        !          2823: 
        !          2824:         if (service==CACHESERVICE && INDEX_OK(ha->status,async_cache_tab)) {
        !          2825:             TRACE2(("GDT: Async. event cache service, event no.: %d\n",
        !          2826:                 ha->status));
        !          2827:         
        !          2828:             f = async_cache_tab[ha->status];
        !          2829: 
        !          2830:             /* i: parameter to push, j: stack element to fill */
        !          2831:             for (j=0,i=1; i < f[0]; i+=2) {
        !          2832:                 switch (f[i+1]) {
        !          2833:                   case 4:
        !          2834:                     stack.b[j++] = *(ulong*)&dvr.eu.stream[(int)f[i]];
        !          2835:                     break;
        !          2836:                   case 2:
        !          2837:                     stack.b[j++] = *(ushort*)&dvr.eu.stream[(int)f[i]];
        !          2838:                     break;
        !          2839:                   case 1:
        !          2840:                     stack.b[j++] = *(unchar*)&dvr.eu.stream[(int)f[i]];
        !          2841:                     break;
        !          2842:                   default:
        !          2843:                     break;
        !          2844:                 }
        !          2845:             }
        !          2846: 
        !          2847:             printk(&f[f[0]],stack); printk("\n");
        !          2848: 
        !          2849:         } else {
        !          2850:             printk("GDT: Unknown async. event service %d event no. %d\n",
        !          2851:                 service,ha->status);
        !          2852:         }
        !          2853:     }
        !          2854:     return 1;
        !          2855: }
        !          2856: 
        !          2857: 
        !          2858: #ifdef GDTH_STATISTICS
        !          2859: void gdth_timeout(ulong data)
        !          2860: {
        !          2861:     ulong flags,i;
        !          2862:     Scsi_Cmnd *nscp;
        !          2863:     gdth_ha_str *ha;
        !          2864:     int hanum = 0;
        !          2865: 
        !          2866:     save_flags(flags);
        !          2867:     cli();
        !          2868: 
        !          2869:     for (act_stats=0,i=0; i<GDTH_MAXCMDS; ++i) 
        !          2870:         if (gdth_cmd_tab[i][hanum].cmnd != UNUSED_CMND)
        !          2871:             ++act_stats;
        !          2872: 
        !          2873:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          2874:     for (act_rq=0,nscp=ha->req_first; nscp; nscp=(Scsi_Cmnd*)nscp->SCp.ptr)
        !          2875:         ++act_rq;
        !          2876: 
        !          2877:     TRACE2(("gdth_to(): ints %ld, ios %ld, act_stats %ld, act_rq %ld\n",
        !          2878:             act_ints, act_ios, act_stats, act_rq));
        !          2879:     act_ints = act_ios = 0;
        !          2880: 
        !          2881:     gdth_timer.expires = jiffies + 30 * HZ;
        !          2882:     add_timer(&gdth_timer);
        !          2883:     restore_flags(flags);
        !          2884: }
        !          2885: #endif
        !          2886: 
        !          2887: 
        !          2888: __initfunc (int gdth_detect(Scsi_Host_Template *shtp))
        !          2889: {
        !          2890:     struct Scsi_Host *shp;
        !          2891:     gdth_ha_str *ha;
        !          2892:     unsigned long flags;
        !          2893:     ulong isa_bios;
        !          2894:     ushort eisa_slot,device_id,index;
        !          2895:     gdth_pci_str pcistr;
        !          2896:     int i,j,hanum;
        !          2897:     unchar b;
        !          2898:     
        !          2899:  
        !          2900: #ifdef DEBUG_GDTH
        !          2901:     printk("GDT: This driver contains debugging information !! Trace level = %d\n",
        !          2902:         DebugState);
        !          2903:     printk("     Destination of debugging information: ");
        !          2904: #ifdef __SERIAL__
        !          2905: #ifdef __COM2__
        !          2906:     printk("Serial port COM2\n");
        !          2907: #else
        !          2908:     printk("Serial port COM1\n");
        !          2909: #endif
        !          2910: #else
        !          2911:     printk("Console\n");
        !          2912: #endif
        !          2913:     gdth_delay(3000);
        !          2914: #endif
        !          2915: 
        !          2916:     TRACE(("gdth_detect()\n"));
        !          2917: 
        !          2918:     if (disable_gdth_scan) {
        !          2919:         printk("GDT: Controller driver disabled from command line !\n");
        !          2920:         return 0;
        !          2921:     }
        !          2922: 
        !          2923:     /* initializations */
        !          2924:     gdth_polling = TRUE; b = 0;
        !          2925:     for (i=0; i<GDTH_MAXCMDS; ++i)
        !          2926:         for (j=0; j<MAXHA; ++j)
        !          2927:             gdth_cmd_tab[i][j].cmnd = UNUSED_CMND;
        !          2928:     for (i=0; i<4; ++i)
        !          2929:         for (j=0; j<MAXHA; ++j)
        !          2930:             gdth_ioctl_tab[i][j] = NULL;
        !          2931:     gdth_clear_events();
        !          2932: 
        !          2933:     /* scanning for controllers, at first: ISA controller */
        !          2934:     for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) {
        !          2935:         if (gdth_search_isa(isa_bios)) {        /* controller found */
        !          2936:             shp = scsi_register(shtp,sizeof(gdth_ext_str));
        !          2937:             ha = HADATA(shp);
        !          2938:             if (!gdth_init_isa(isa_bios,ha)) {
        !          2939:                 scsi_unregister(shp);
        !          2940:                 continue;
        !          2941:             }
        !          2942:             /* controller found and initialized */
        !          2943:             printk("Configuring GDT-ISA HA at BIOS 0x%05lX IRQ %u DRQ %u\n",
        !          2944:                    isa_bios,ha->irq,ha->drq);
        !          2945: 
        !          2946:             save_flags(flags);
        !          2947:             cli();
        !          2948: #if LINUX_VERSION_CODE >= 0x02015F 
        !          2949:             if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
        !          2950: #elif LINUX_VERSION_CODE >= 0x010346 
        !          2951:             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
        !          2952: #else
        !          2953:             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
        !          2954: #endif
        !          2955:             {
        !          2956:                 printk("GDT-ISA: Unable to allocate IRQ\n");
        !          2957:                 restore_flags(flags);
        !          2958:                 scsi_unregister(shp);
        !          2959:                 continue;
        !          2960:             }
        !          2961:             if (request_dma(ha->drq,"gdth")) {
        !          2962:                 printk("GDT-ISA: Unable to allocate DMA channel\n");
        !          2963: #if LINUX_VERSION_CODE >= 0x010346 
        !          2964:                 free_irq(ha->irq,NULL);
        !          2965: #else
        !          2966:                 free_irq(ha->irq);
        !          2967: #endif
        !          2968:                 restore_flags(flags);
        !          2969:                 scsi_unregister(shp);
        !          2970:                 continue;
        !          2971:             }
        !          2972:             set_dma_mode(ha->drq,DMA_MODE_CASCADE);
        !          2973:             enable_dma(ha->drq);
        !          2974:             shp->unchecked_isa_dma = 1;
        !          2975:             shp->irq = ha->irq;
        !          2976:             shp->dma_channel = ha->drq;
        !          2977:             for (i=0; i<MAXID; ++i) {
        !          2978:                 if (ha->id[0][i].type==SIOP_DTYP) {
        !          2979:                     shp->this_id = i;
        !          2980:                     break;
        !          2981:                 }
        !          2982:             }
        !          2983:             hanum = gdth_ctr_count;         
        !          2984:             gdth_ctr_tab[gdth_ctr_count++] = shp;
        !          2985:             gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
        !          2986: 
        !          2987:             NUMDATA(shp)->hanum = (ushort)hanum;
        !          2988:             NUMDATA(shp)->busnum= 0;
        !          2989: 
        !          2990:             ha->pccb = CMDDATA(shp);
        !          2991:             ha->pscratch = DMADATA(shp);
        !          2992:             ha->req_first = NULL;
        !          2993:             for (i=0; i<MAXBUS; ++i) {
        !          2994:                 for (j=0; j<MAXID; ++j) {
        !          2995:                     ha->id[i][j].type = EMPTY_DTYP;
        !          2996:                     ha->id[i][j].lock = 0;
        !          2997:                    ha->id[i][j].heads = 0;
        !          2998:                 }
        !          2999:             }
        !          3000:             restore_flags(flags);
        !          3001: 
        !          3002:             if (!gdth_search_drives(hanum)) {
        !          3003:                 printk("GDT-ISA: Error during device scan\n");
        !          3004:                 --gdth_ctr_count;
        !          3005:                --gdth_ctr_vcount;
        !          3006:                 save_flags(flags);
        !          3007:                 cli();
        !          3008: #if LINUX_VERSION_CODE >= 0x010346 
        !          3009:                 free_irq(ha->irq,NULL);
        !          3010: #else
        !          3011:                 free_irq(ha->irq);
        !          3012: #endif
        !          3013:                 restore_flags(flags);
        !          3014:                 scsi_unregister(shp);
        !          3015:                 continue;
        !          3016:             }
        !          3017: 
        !          3018: #if LINUX_VERSION_CODE >= 0x020000
        !          3019:             shp->max_id      = 8;
        !          3020:             shp->max_lun     = MAXLUN;
        !          3021:             shp->max_channel = ha->bus_cnt - 1;
        !          3022: #else
        !          3023:             /* register addit. SCSI channels as virtual controllers */
        !          3024:             for (b=1; b<ha->bus_cnt; ++b) {
        !          3025:                 shp = scsi_register(shtp,sizeof(gdth_num_str));
        !          3026:                 shp->unchecked_isa_dma = 1;
        !          3027:                 shp->irq = ha->irq;
        !          3028:                 shp->dma_channel = ha->drq;
        !          3029:                 for (i=0; i<MAXID; ++i) {
        !          3030:                     if (ha->id[b][i].type==SIOP_DTYP) {
        !          3031:                         shp->this_id = i;
        !          3032:                         break;
        !          3033:                     }
        !          3034:                 }
        !          3035:                 gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
        !          3036:                 NUMDATA(shp)->hanum = (ushort)hanum;
        !          3037:                 NUMDATA(shp)->busnum = b;
        !          3038:             }
        !          3039: #endif
        !          3040: 
        !          3041:             gdth_enable_int(hanum);
        !          3042:         }
        !          3043:     }
        !          3044: 
        !          3045:     /* scanning for EISA controllers */
        !          3046:     for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) {
        !          3047:         if (gdth_search_eisa(eisa_slot)) {      /* controller found */
        !          3048:             shp = scsi_register(shtp,sizeof(gdth_ext_str));
        !          3049:             ha = HADATA(shp);
        !          3050:             if (!gdth_init_eisa(eisa_slot,ha)) {
        !          3051:                 scsi_unregister(shp);
        !          3052:                 continue;
        !          3053:             }
        !          3054:             /* controller found and initialized */
        !          3055:             printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
        !          3056:                    eisa_slot>>12,ha->irq);
        !          3057: 
        !          3058:             save_flags(flags);
        !          3059:             cli();
        !          3060: #if LINUX_VERSION_CODE >= 0x02015F 
        !          3061:             if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
        !          3062: #elif LINUX_VERSION_CODE >= 0x010346 
        !          3063:             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
        !          3064: #else
        !          3065:             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
        !          3066: #endif
        !          3067:             {
        !          3068:                 printk("GDT-EISA: Unable to allocate IRQ\n");
        !          3069:                 restore_flags(flags);
        !          3070:                 scsi_unregister(shp);
        !          3071:                 continue;
        !          3072:             }
        !          3073:             shp->unchecked_isa_dma = 0;
        !          3074:             shp->irq = ha->irq;
        !          3075:             shp->dma_channel = 0xff;
        !          3076:             for (i=0; i<MAXID; ++i) {
        !          3077:                 if (ha->id[0][i].type==SIOP_DTYP) {
        !          3078:                     shp->this_id = i;
        !          3079:                     break;
        !          3080:                 }
        !          3081:             }
        !          3082:             hanum = gdth_ctr_count;
        !          3083:             gdth_ctr_tab[gdth_ctr_count++] = shp;
        !          3084:             gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
        !          3085: 
        !          3086:             NUMDATA(shp)->hanum = (ushort)hanum;
        !          3087:             NUMDATA(shp)->busnum= 0;
        !          3088:             TRACE2(("EISA detect Bus 0: shp %lx hanum %d\n",
        !          3089:                           (ulong)shp,NUMDATA(shp)->hanum));
        !          3090: 
        !          3091:             ha->pccb = CMDDATA(shp);
        !          3092:             ha->pscratch = DMADATA(shp);
        !          3093:             ha->req_first = NULL;
        !          3094:             for (i=0; i<MAXBUS; ++i) {
        !          3095:                 for (j=0; j<MAXID; ++j) {
        !          3096:                     ha->id[i][j].type = EMPTY_DTYP;
        !          3097:                     ha->id[i][j].lock = 0;
        !          3098:                    ha->id[i][j].heads = 0;
        !          3099:                 }
        !          3100:             }
        !          3101:             restore_flags(flags);
        !          3102: 
        !          3103:             if (!gdth_search_drives(hanum)) {
        !          3104:                 printk("GDT-EISA: Error during device scan\n");
        !          3105:                 --gdth_ctr_count;
        !          3106:                --gdth_ctr_vcount;
        !          3107:                 save_flags(flags);
        !          3108:                 cli();
        !          3109: #if LINUX_VERSION_CODE >= 0x010346 
        !          3110:                 free_irq(ha->irq,NULL);
        !          3111: #else
        !          3112:                 free_irq(ha->irq);
        !          3113: #endif
        !          3114:                 restore_flags(flags);
        !          3115:                 scsi_unregister(shp);
        !          3116:                 continue;
        !          3117:             }
        !          3118: 
        !          3119: #if LINUX_VERSION_CODE >= 0x020000
        !          3120:             shp->max_id      = 8;
        !          3121:             shp->max_lun     = MAXLUN;
        !          3122:             shp->max_channel = ha->bus_cnt - 1;
        !          3123: #else
        !          3124:             /* register addit. SCSI channels as virtual controllers */
        !          3125:             for (b=1; b<ha->bus_cnt; ++b) {
        !          3126:                 shp = scsi_register(shtp,sizeof(gdth_num_str));
        !          3127:                 shp->unchecked_isa_dma = 0;
        !          3128:                 shp->irq = ha->irq;
        !          3129:                 shp->dma_channel = 0xff;
        !          3130:                 for (i=0; i<MAXID; ++i) {
        !          3131:                     if (ha->id[b][i].type==SIOP_DTYP) {
        !          3132:                         shp->this_id = i;
        !          3133:                         break;
        !          3134:                     }
        !          3135:                 }
        !          3136:                 gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
        !          3137:                 NUMDATA(shp)->hanum = (ushort)hanum;
        !          3138:                 NUMDATA(shp)->busnum = b;
        !          3139:                 TRACE2(("EISA detect Bus %d: shp %lx hanum %d\n",
        !          3140:                               NUMDATA(shp)->busnum,(ulong)shp,
        !          3141:                               NUMDATA(shp)->hanum));
        !          3142:             }
        !          3143: #endif
        !          3144: 
        !          3145:             gdth_enable_int(hanum);
        !          3146:         }
        !          3147:     }
        !          3148: 
        !          3149:     /* scanning for PCI controllers */
        !          3150:     for (device_id = 0; device_id <= PCI_DEVICE_ID_VORTEX_GDTMAXRP; ++device_id) {
        !          3151:         if (device_id > PCI_DEVICE_ID_VORTEX_GDT6555 &&
        !          3152:             device_id < PCI_DEVICE_ID_VORTEX_GDT6x17RP)
        !          3153:             continue;
        !          3154:         for (index = 0; ; ++index) {
        !          3155:             if (!gdth_search_pci(device_id,index,&pcistr)) 
        !          3156:                 break;                          /* next device_id */
        !          3157:             shp = scsi_register(shtp,sizeof(gdth_ext_str));
        !          3158:             ha = HADATA(shp);
        !          3159:             if (!gdth_init_pci(&pcistr,ha)) {
        !          3160:                 scsi_unregister(shp);
        !          3161:                 continue;
        !          3162:             }
        !          3163:             /* controller found and initialized */
        !          3164:             printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
        !          3165:                    pcistr.bus,pcistr.device_fn>>3,ha->irq);
        !          3166: 
        !          3167:             save_flags(flags);
        !          3168:             cli();
        !          3169: #if LINUX_VERSION_CODE >= 0x02015F 
        !          3170:             if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT|SA_SHIRQ,"gdth",NULL))
        !          3171: #elif LINUX_VERSION_CODE >= 0x010346 
        !          3172:             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT|SA_SHIRQ,"gdth",NULL))
        !          3173: #else
        !          3174:             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT|SA_SHIRQ,"gdth")) 
        !          3175: #endif
        !          3176:             {
        !          3177:                 printk("GDT-PCI: Unable to allocate IRQ\n");
        !          3178:                 restore_flags(flags);
        !          3179:                 scsi_unregister(shp);
        !          3180:                 continue;
        !          3181:             }
        !          3182:             shp->unchecked_isa_dma = 0;
        !          3183:             shp->irq = ha->irq;
        !          3184:             shp->dma_channel = 0xff;
        !          3185:             for (i=0; i<MAXID; ++i) {
        !          3186:                 if (ha->id[0][i].type==SIOP_DTYP) {
        !          3187:                     shp->this_id = i;
        !          3188:                     break;
        !          3189:                 }
        !          3190:             }
        !          3191:             hanum = gdth_ctr_count;
        !          3192:             gdth_ctr_tab[gdth_ctr_count++] = shp;
        !          3193:             gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
        !          3194: 
        !          3195:             NUMDATA(shp)->hanum = (ushort)hanum;
        !          3196:             NUMDATA(shp)->busnum= 0;
        !          3197: 
        !          3198:             ha->pccb = CMDDATA(shp);
        !          3199:             ha->pscratch = DMADATA(shp);
        !          3200:             ha->req_first = NULL;
        !          3201:             for (i=0; i<MAXBUS; ++i) {
        !          3202:                 for (j=0; j<MAXID; ++j) {
        !          3203:                     ha->id[i][j].type = EMPTY_DTYP;
        !          3204:                     ha->id[i][j].lock = 0;
        !          3205:                    ha->id[i][j].heads = 0;
        !          3206:                 }
        !          3207:             }
        !          3208:             restore_flags(flags);
        !          3209: 
        !          3210:             if (!gdth_search_drives(hanum)) {
        !          3211:                 printk("GDT-PCI: Error during device scan\n");
        !          3212:                 --gdth_ctr_count;
        !          3213:                --gdth_ctr_vcount;
        !          3214:                 save_flags(flags);
        !          3215:                 cli();
        !          3216: #if LINUX_VERSION_CODE >= 0x010346 
        !          3217:                 free_irq(ha->irq,NULL);
        !          3218: #else
        !          3219:                 free_irq(ha->irq);
        !          3220: #endif
        !          3221:                 restore_flags(flags);
        !          3222:                 scsi_unregister(shp);
        !          3223:                 continue;
        !          3224:             }
        !          3225: 
        !          3226: #if LINUX_VERSION_CODE >= 0x020000
        !          3227:             shp->max_id      = MAXID;
        !          3228:             shp->max_lun     = MAXLUN;
        !          3229:             shp->max_channel = ha->bus_cnt - 1;
        !          3230: #else
        !          3231:             /* register addit. SCSI channels as virtual controllers */
        !          3232:             for (b=1; b<ha->bus_cnt; ++b) {
        !          3233:                 shp = scsi_register(shtp,sizeof(gdth_num_str));
        !          3234:                 shp->unchecked_isa_dma = 0;
        !          3235:                 shp->irq = ha->irq;
        !          3236:                 shp->dma_channel = 0xff;
        !          3237:                 for (i=0; i<MAXID; ++i) {
        !          3238:                     if (ha->id[b][i].type==SIOP_DTYP) {
        !          3239:                         shp->this_id = i;
        !          3240:                         break;
        !          3241:                     }
        !          3242:                 }
        !          3243:                 gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
        !          3244:                 NUMDATA(shp)->hanum = (ushort)hanum;
        !          3245:                 NUMDATA(shp)->busnum = b;
        !          3246:             }
        !          3247: #endif
        !          3248: 
        !          3249:             gdth_enable_int(hanum);
        !          3250:         }
        !          3251:     }
        !          3252: 
        !          3253:     TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count));
        !          3254:     if (gdth_ctr_count > 0) {
        !          3255: #ifdef GDTH_STATISTICS
        !          3256:        TRACE2(("gdth_detect(): Initializing timer !\n"));
        !          3257:        init_timer(&gdth_timer);
        !          3258:        gdth_timer.expires = jiffies + HZ;
        !          3259:        gdth_timer.data = 0L;
        !          3260:        gdth_timer.function = gdth_timeout;
        !          3261:        add_timer(&gdth_timer);
        !          3262: #endif
        !          3263: #if LINUX_VERSION_CODE >= 0x020100
        !          3264:        register_reboot_notifier(&gdth_notifier);
        !          3265: #endif
        !          3266:     }
        !          3267:     gdth_polling = FALSE;
        !          3268:     return gdth_ctr_vcount;
        !          3269: }
        !          3270: 
        !          3271: 
        !          3272: int gdth_release(struct Scsi_Host *shp)
        !          3273: {
        !          3274:     unsigned long flags;
        !          3275: 
        !          3276:     TRACE2(("gdth_release()\n"));
        !          3277: 
        !          3278:     if (NUMDATA(shp)->busnum == 0) {
        !          3279:        gdth_flush(NUMDATA(shp)->hanum);
        !          3280: 
        !          3281:        save_flags(flags);
        !          3282:        cli();
        !          3283:         if (shp->irq) {
        !          3284: #if LINUX_VERSION_CODE >= 0x010346
        !          3285:             free_irq(shp->irq,NULL);
        !          3286: #else
        !          3287:             free_irq(shp->irq);
        !          3288: #endif
        !          3289:         }
        !          3290:         if (shp->dma_channel != 0xff) {
        !          3291:             free_dma(shp->dma_channel);
        !          3292:         }
        !          3293:        restore_flags(flags);
        !          3294:        gdth_ctr_released++;
        !          3295:        TRACE2(("gdth_release(): HA %d of %d\n", 
        !          3296:                gdth_ctr_released, gdth_ctr_count));
        !          3297: 
        !          3298:        if (gdth_ctr_released == gdth_ctr_count) {
        !          3299: #ifdef GDTH_STATISTICS
        !          3300:            del_timer(&gdth_timer);
        !          3301: #endif
        !          3302: #if LINUX_VERSION_CODE >= 0x020100
        !          3303:            unregister_reboot_notifier(&gdth_notifier);
        !          3304: #endif
        !          3305:        }
        !          3306:     }
        !          3307: 
        !          3308:     scsi_unregister(shp);
        !          3309:     return 0;
        !          3310: }
        !          3311:             
        !          3312: 
        !          3313: static const char *gdth_ctr_name(int hanum)
        !          3314: {
        !          3315:     gdth_ha_str *ha;
        !          3316: 
        !          3317:     TRACE2(("gdth_ctr_name()\n"));
        !          3318: 
        !          3319:     ha    = HADATA(gdth_ctr_tab[hanum]);
        !          3320: 
        !          3321:     if (ha->type == GDT_EISA) {
        !          3322:         switch (ha->stype) {
        !          3323:           case GDT3_ID:
        !          3324:             return("GDT3000/3020");
        !          3325:           case GDT3A_ID:
        !          3326:             return("GDT3000A/3020A/3050A");
        !          3327:           case GDT3B_ID:
        !          3328:             return("GDT3000B/3010A");
        !          3329:         }
        !          3330:     } else if (ha->type == GDT_ISA) {
        !          3331:         return("GDT2000/2020");
        !          3332:     } else if (ha->type == GDT_PCI) {
        !          3333:         switch (ha->stype) {
        !          3334:           case PCI_DEVICE_ID_VORTEX_GDT60x0:
        !          3335:             return("GDT6000/6020/6050");
        !          3336:           case PCI_DEVICE_ID_VORTEX_GDT6000B:
        !          3337:             return("GDT6000B/6010");
        !          3338:         }
        !          3339:     } 
        !          3340:     /* new controllers (GDT_PCINEW, GDT_PCIMPR, ..) use board_info IOCTL! */
        !          3341: 
        !          3342:     return("");
        !          3343: }
        !          3344: 
        !          3345: const char *gdth_info(struct Scsi_Host *shp)
        !          3346: {
        !          3347:     int hanum;
        !          3348:     gdth_ha_str *ha;
        !          3349: 
        !          3350:     TRACE2(("gdth_info()\n"));
        !          3351:     hanum = NUMDATA(shp)->hanum;
        !          3352:     ha    = HADATA(gdth_ctr_tab[hanum]);
        !          3353: 
        !          3354:     return ((const char *)ha->ctr_name);
        !          3355: }
        !          3356: 
        !          3357: /* old error handling */
        !          3358: int gdth_abort(Scsi_Cmnd *scp)
        !          3359: {
        !          3360:     TRACE2(("gdth_abort() reason %d\n",scp->abort_reason));
        !          3361:     return SCSI_ABORT_SNOOZE;
        !          3362: }
        !          3363: 
        !          3364: #if LINUX_VERSION_CODE >= 0x010346
        !          3365: int gdth_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
        !          3366: #else
        !          3367: int gdth_reset(Scsi_Cmnd *scp)
        !          3368: #endif
        !          3369: {
        !          3370:     TRACE2(("gdth_reset()\n"));
        !          3371:     return SCSI_RESET_PUNT;
        !          3372: }
        !          3373: 
        !          3374: #if LINUX_VERSION_CODE >= 0x02015F
        !          3375: /* new error handling */
        !          3376: int gdth_eh_abort(Scsi_Cmnd *scp)
        !          3377: {
        !          3378:     TRACE2(("gdth_eh_abort()\n"));
        !          3379:     return FAILED;
        !          3380: }
        !          3381: 
        !          3382: int gdth_eh_device_reset(Scsi_Cmnd *scp)
        !          3383: {
        !          3384:     TRACE2(("gdth_eh_device_reset()\n"));
        !          3385:     return FAILED;
        !          3386: }
        !          3387: 
        !          3388: int gdth_eh_bus_reset(Scsi_Cmnd *scp)
        !          3389: {
        !          3390:     TRACE2(("gdth_eh_bus_reset()\n"));
        !          3391:     return FAILED;
        !          3392: }
        !          3393: 
        !          3394: int gdth_eh_host_reset(Scsi_Cmnd *scp)
        !          3395: {
        !          3396:     TRACE2(("gdth_eh_host_reset()\n"));
        !          3397:     return FAILED;
        !          3398: }
        !          3399: #endif
        !          3400: 
        !          3401: #if LINUX_VERSION_CODE >= 0x010300
        !          3402: int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
        !          3403: #else
        !          3404: int gdth_bios_param(Disk *disk,int dev,int *ip)
        !          3405: #endif
        !          3406: {
        !          3407:     unchar b, t;
        !          3408:     int hanum;
        !          3409:     gdth_ha_str *ha;
        !          3410:     int drv_hds, drv_secs;
        !          3411: 
        !          3412:     hanum = NUMDATA(disk->device->host)->hanum;
        !          3413:     b = disk->device->channel;
        !          3414:     t = disk->device->id;
        !          3415:     TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t));
        !          3416:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          3417: 
        !          3418:     if (ha->id[b][t].heads == 0) {
        !          3419:        /* raw device: evaluate mapping (sectors per head, heads per cylinder) */
        !          3420:        if (disk->capacity /HEADS/SECS <= MAXCYLS) {
        !          3421:            drv_hds = HEADS;
        !          3422:            drv_secs= SECS;
        !          3423:        } else if (disk->capacity /MEDHEADS/MEDSECS <= MAXCYLS) {
        !          3424:            drv_hds = MEDHEADS;
        !          3425:            drv_secs= MEDSECS;
        !          3426:        } else {
        !          3427:            drv_hds = BIGHEADS;
        !          3428:            drv_secs= BIGSECS;
        !          3429:        }
        !          3430:        ha->id[b][t].heads = drv_hds;
        !          3431:        ha->id[b][t].secs = drv_secs;
        !          3432:        TRACE2(("gdth_bios_param(): raw device -> params evaluated\n"));
        !          3433:     }
        !          3434: 
        !          3435:     ip[0] = ha->id[b][t].heads;
        !          3436:     ip[1] = ha->id[b][t].secs;
        !          3437:     ip[2] = disk->capacity / ip[0] / ip[1];
        !          3438: 
        !          3439:     TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n",
        !          3440:             ip[0],ip[1],ip[2]));
        !          3441:     return 0;
        !          3442: }
        !          3443: 
        !          3444: 
        !          3445: static void internal_done(Scsi_Cmnd *scp)
        !          3446: {
        !          3447:     scp->SCp.sent_command++;
        !          3448: }
        !          3449: 
        !          3450: int gdth_command(Scsi_Cmnd *scp)
        !          3451: {
        !          3452:     TRACE2(("gdth_command()\n"));
        !          3453: 
        !          3454:     scp->SCp.sent_command = 0;
        !          3455:     gdth_queuecommand(scp,internal_done);
        !          3456: 
        !          3457:     while (!scp->SCp.sent_command)
        !          3458:         barrier();
        !          3459:     return scp->result;
        !          3460: }
        !          3461: 
        !          3462: 
        !          3463: int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
        !          3464: {
        !          3465:     int hanum;
        !          3466:     int priority;
        !          3467: 
        !          3468:     TRACE(("gdth_queuecommand() cmd 0x%x id %d lun %d\n",
        !          3469:                   scp->cmnd[0],scp->target,scp->lun));
        !          3470:     
        !          3471:     scp->scsi_done = (void *)done;
        !          3472:     scp->SCp.have_data_in = 1;
        !          3473:     hanum = NUMDATA(scp->host)->hanum;
        !          3474: #ifdef GDTH_STATISTICS
        !          3475:     ++act_ios;
        !          3476: #endif
        !          3477: 
        !          3478:     priority = DEFAULT_PRI;
        !          3479: #if LINUX_VERSION_CODE >= 0x010300
        !          3480:     if (scp->done == gdth_scsi_done)
        !          3481:         priority = scp->SCp.this_residual;
        !          3482: #endif
        !          3483:     gdth_putq( hanum, scp, priority );
        !          3484:     gdth_next( hanum );
        !          3485:     return 0;
        !          3486: }
        !          3487: 
        !          3488: /* flush routine */
        !          3489: static void gdth_flush(int hanum)
        !          3490: {
        !          3491:     int             i, j;
        !          3492:     gdth_ha_str     *ha;
        !          3493:     Scsi_Cmnd       scp;
        !          3494:     Scsi_Device     sdev;
        !          3495:     gdth_cmd_str    gdtcmd;
        !          3496:     char            cmnd[12];
        !          3497: 
        !          3498:     TRACE2(("gdth_flush() hanum %d\n",hanum));
        !          3499:     ha = HADATA(gdth_ctr_tab[hanum]);
        !          3500:     memset(&sdev,0,sizeof(Scsi_Device));
        !          3501:     memset(&scp, 0,sizeof(Scsi_Cmnd));
        !          3502:     sdev.host = gdth_ctr_tab[hanum];
        !          3503:     sdev.id = sdev.host->this_id;
        !          3504:     scp.cmd_len = 12;
        !          3505:     scp.host = gdth_ctr_tab[hanum];
        !          3506:     scp.target = sdev.host->this_id;
        !          3507:     scp.device = &sdev;
        !          3508:     scp.use_sg = 0;
        !          3509: 
        !          3510:     for (i = 0; i < MAXBUS; ++i) {
        !          3511:        for (j = 0; j < MAXID; ++j) {
        !          3512:            if (ha->id[i][j].type == CACHE_DTYP) {
        !          3513:                gdtcmd.BoardNode = LOCALBOARD;
        !          3514:                gdtcmd.Service = CACHESERVICE;
        !          3515:                gdtcmd.OpCode = GDT_FLUSH;
        !          3516:                gdtcmd.u.cache.DeviceNo = ha->id[i][j].hostdrive;
        !          3517:                gdtcmd.u.cache.BlockNo = 1;
        !          3518:                gdtcmd.u.cache.sg_canz = 0;
        !          3519:                TRACE2(("gdth_flush(): flush ha %d drive %d\n",
        !          3520:                         hanum, ha->id[i][j].hostdrive));
        !          3521:                {
        !          3522:                    struct semaphore sem = MUTEX_LOCKED;
        !          3523:                    scp.request.rq_status = RQ_SCSI_BUSY;
        !          3524:                    scp.request.sem = &sem;
        !          3525:                    scp.SCp.this_residual = IOCTL_PRI;
        !          3526:                    scsi_do_cmd(&scp, cmnd, &gdtcmd,
        !          3527:                                sizeof(gdth_cmd_str), gdth_scsi_done,
        !          3528:                                30*HZ, 1);
        !          3529:                    down(&sem);
        !          3530:                }
        !          3531:            }
        !          3532:        }
        !          3533:     }
        !          3534: }
        !          3535: 
        !          3536: /* shutdown routine */
        !          3537: #if LINUX_VERSION_CODE >= 0x020100
        !          3538: static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
        !          3539: #else
        !          3540: void gdth_halt(void)
        !          3541: #endif
        !          3542: {
        !          3543:     int             hanum;
        !          3544:     Scsi_Cmnd       scp;
        !          3545:     Scsi_Device     sdev;
        !          3546:     gdth_cmd_str    gdtcmd;
        !          3547:     char            cmnd[12];
        !          3548: 
        !          3549: #if LINUX_VERSION_CODE >= 0x020100
        !          3550:     TRACE2(("gdth_halt() event %d\n",event));
        !          3551:     if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
        !          3552:        return NOTIFY_DONE;
        !          3553: #else
        !          3554:     TRACE2(("gdth_halt()\n"));
        !          3555:     if (halt_called) {
        !          3556:        TRACE2(("already called\n"));
        !          3557:        return;
        !          3558:     }
        !          3559:     halt_called = TRUE;
        !          3560: #endif
        !          3561:     printk("GDT: Flushing all host drives .. ");
        !          3562:     for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
        !          3563:         gdth_flush(hanum);
        !          3564: 
        !          3565:         /* controller reset */
        !          3566:         memset(&sdev,0,sizeof(Scsi_Device));
        !          3567:         memset(&scp, 0,sizeof(Scsi_Cmnd));
        !          3568:         sdev.host = gdth_ctr_tab[hanum];
        !          3569:         sdev.id = sdev.host->this_id;
        !          3570:         scp.cmd_len = 12;
        !          3571:         scp.host = gdth_ctr_tab[hanum];
        !          3572:         scp.target = sdev.host->this_id;
        !          3573:         scp.device = &sdev;
        !          3574:         scp.use_sg = 0;
        !          3575: 
        !          3576:         gdtcmd.BoardNode = LOCALBOARD;
        !          3577:         gdtcmd.Service = CACHESERVICE;
        !          3578:         gdtcmd.OpCode = GDT_RESET;
        !          3579:         TRACE2(("gdth_halt(): reset controller %d\n", hanum));
        !          3580:         {
        !          3581:             struct semaphore sem = MUTEX_LOCKED;
        !          3582:             scp.request.rq_status = RQ_SCSI_BUSY;
        !          3583:             scp.request.sem = &sem;
        !          3584:             scp.SCp.this_residual = IOCTL_PRI;
        !          3585:             scsi_do_cmd(&scp, cmnd, &gdtcmd,
        !          3586:                 sizeof(gdth_cmd_str), gdth_scsi_done,
        !          3587:                 10*HZ, 1);
        !          3588:             down(&sem);
        !          3589:         }
        !          3590:     }
        !          3591:     printk("Done.\n");
        !          3592: 
        !          3593: #ifdef GDTH_STATISTICS
        !          3594:     del_timer(&gdth_timer);
        !          3595: #endif
        !          3596: #if LINUX_VERSION_CODE >= 0x020100
        !          3597:     unregister_reboot_notifier(&gdth_notifier);
        !          3598:     return NOTIFY_OK;
        !          3599: #endif
        !          3600: }
        !          3601: 
        !          3602: 
        !          3603: /* called from init/main.c */
        !          3604: __initfunc (void gdth_setup(char *str,int *ints))
        !          3605: {
        !          3606:     static size_t setup_idx = 0;
        !          3607: 
        !          3608:     TRACE2(("gdth_setup() str %s ints[0] %d ints[1] %d\n",
        !          3609:                   str ? str:"NULL", ints[0],
        !          3610:                   ints[0] ? ints[1]:0));
        !          3611: 
        !          3612:     if (setup_idx >= MAXHA) {
        !          3613:         printk("GDT: gdth_setup() called too many times. Bad LILO params ?\n");
        !          3614:         return;
        !          3615:     }
        !          3616:     if (ints[0] != 1) {
        !          3617:         printk("GDT: Illegal command line !\n");
        !          3618:         printk("Usage: gdth=<IRQ>\n");
        !          3619:         printk("Where: <IRQ>: valid EISA controller IRQ (10,11,12,14)\n");
        !          3620:         printk("              or 0 to disable controller driver\n");
        !          3621:         return;
        !          3622:     }
        !          3623:     if (ints[1] == 10 || ints[1] == 11 || ints[1] == 12 || ints[1] == 14) {
        !          3624:         irqs[setup_idx++] = ints[1];
        !          3625:         irqs[setup_idx]   = 0xff;
        !          3626:         return;
        !          3627:     }
        !          3628:     if (ints[1] == 0) {
        !          3629:         disable_gdth_scan = TRUE;
        !          3630:         return;
        !          3631:     }
        !          3632:     printk("GDT: Invalid IRQ (%d) specified\n",ints[1]);
        !          3633: }
        !          3634: 
        !          3635: 
        !          3636: #ifdef MODULE
        !          3637: Scsi_Host_Template driver_template = GDTH;
        !          3638: #include "scsi_module.c"
        !          3639: #endif
        !          3640: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.