|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.