|
|
1.1 ! root 1: /* fdomain.c -- Future Domain TMC-1660/TMC-1680 driver ! 2: * Created: Sun May 3 18:53:19 1992 ! 3: * Revised: Tue Jul 28 19:45:25 1992 by root ! 4: * Author: Rickard E. Faith, [email protected] ! 5: * Copyright 1992 Rickard E. Faith ! 6: * ! 7: * $Log$ ! 8: ! 9: * This program is free software; you can redistribute it and/or modify it ! 10: * under the terms of the GNU General Public License as published by the ! 11: * Free Software Foundation; either version 2, or (at your option) any ! 12: * later version. ! 13: ! 14: * This program is distributed in the hope that it will be useful, but ! 15: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 17: * General Public License for more details. ! 18: ! 19: * WARNING: THIS IS A BETA VERSION! ! 20: * USE AT YOUR OWN RISK! ! 21: * BACKUP YOUR SYSTEM BEFORE USING! ! 22: ! 23: * I would like to thank Maxtor, whose *free* 206 page manual on the LXT ! 24: * drives was very helpful: "LXT SCSI Products: Specifications and OEM ! 25: * Technical Manual (Revision B/September 1991)" ! 26: ! 27: * I wish that I could thank Future Domain for the necessary documentation, ! 28: * but I can't. I used the $25 "TMC-1800 SCSI Chip Specification" document ! 29: * (FDC-1800T), which documents the *chip* and not the board. Without it, ! 30: * I would have been totally lost, but it would have been nice to have some ! 31: * example source. (The DOS BIOS source cost $250 and the UN*X driver ! 32: * source was $750 [both required a non-disclosure agreement]. Ever wonder ! 33: * why there are no freely available Future Domain drivers?) ! 34: ! 35: * Thanks to Todd Carrico ([email protected]), Dan Poirier ! 36: * ([email protected] ), Ken Corey ([email protected]), and C. de Bruin ! 37: * ([email protected]) for alpha testing. Also thanks to Drew ! 38: * Eckhardt ([email protected]) for answering questions. */ ! 39: ! 40: #include <linux/config.h> ! 41: ! 42: #ifdef CONFIG_SCSI_FUTURE_DOMAIN ! 43: ! 44: #include <linux/sched.h> ! 45: #include <asm/io.h> ! 46: #include "fdomain.h" ! 47: #include "scsi.h" ! 48: #include "hosts.h" ! 49: #if QUEUE ! 50: #include <asm/system.h> ! 51: #include <linux/errno.h> ! 52: #endif ! 53: ! 54: #define VERSION "1.9" /* Change with each revision */ ! 55: #define DEBUG 1 /* Enable debugging output */ ! 56: #define SEND_IDENTIFY 0 /* Send IDENTIFY message -- DOESN'T WORK! */ ! 57: #define USE_FIFO 1 /* Use the FIFO buffer for I/O */ ! 58: #define FAST_SYNCH 1 /* Enable Fast Synchronous */ ! 59: #define ALLOW_ALL_IRQ 0 /* Allow all IRQ's -- NOT RECOMMENDED */ ! 60: #define NEW_IRQ 1 /* Enable new IRQ handling */ ! 61: #define DECREASE_IL 1 /* Try to decrease interrupt latency */ ! 62: ! 63: #if DEBUG ! 64: #define EVERY_ACCESS 0 /* Write a line on every scsi access */ ! 65: #define ERRORS_ONLY 1 /* Only write a line if there is an error */ ! 66: #define DEBUG_DETECT 0 /* Debug fdomain_16x0_detect() */ ! 67: #else ! 68: #define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */ ! 69: #define ERRORS_ONLY 0 ! 70: #define DEBUG_DETECT 0 ! 71: #endif ! 72: ! 73: /* Errors are reported on the line, so we don't need to report them again */ ! 74: #if EVERY_ACCESS ! 75: #undef ERRORS_ONLY ! 76: #define ERRORS_ONLY 0 ! 77: #endif ! 78: ! 79: static int port_base = 0; ! 80: static void *bios_base = NULL; ! 81: static int interrupt_level = 0; ! 82: static volatile int aborted = 0; ! 83: ! 84: static int Data_Mode_Cntl_port; ! 85: static int FIFO_Data_Count_port; ! 86: static int Interrupt_Cntl_port; ! 87: static int Read_FIFO_port; ! 88: static int Read_SCSI_Data_port; ! 89: static int SCSI_Cntl_port; ! 90: static int SCSI_Status_port; ! 91: static int TMC_Cntl_port; ! 92: static int TMC_Status_port; ! 93: static int Write_FIFO_port; ! 94: static int Write_SCSI_Data_port; ! 95: ! 96: #if QUEUE ! 97: static unsigned char current_target = 0; ! 98: static unsigned char current_cmnd[10] = { 0, }; ! 99: static void *current_buff = NULL; ! 100: static int current_bufflen = 0; ! 101: static void (*current_done)(int,int) = NULL; ! 102: ! 103: volatile static int in_command = 0; ! 104: volatile static int current_phase; ! 105: static int this_host = 0; ! 106: ! 107: enum { in_arbitration, in_selection, in_other }; ! 108: ! 109: #if NEW_IRQ ! 110: extern void fdomain_16x0_intr( int unused ); ! 111: #else ! 112: extern void fdomain_16x0_interrupt(); ! 113: #endif ! 114: ! 115: static const char *cmd_pt; ! 116: static const char *the_command; ! 117: static unsigned char *out_buf_pt; ! 118: static unsigned char *in_buf_pt; ! 119: volatile static int Status; ! 120: volatile static int Message; ! 121: volatile static unsigned data_sent; ! 122: volatile static int have_data_in; ! 123: ! 124: volatile static int in_interrupt_code = 0; ! 125: ! 126: #endif ! 127: ! 128: ! 129: enum in_port_type { Read_SCSI_Data = 0, SCSI_Status = 1, TMC_Status = 2, ! 130: LSB_ID_Code = 5, MSB_ID_Code = 6, Read_Loopback = 7, ! 131: SCSI_Data_NoACK = 8, Option_Select = 10, ! 132: Read_FIFO = 12, FIFO_Data_Count = 14 }; ! 133: ! 134: enum out_port_type { Write_SCSI_Data = 0, SCSI_Cntl = 1, Interrupt_Cntl = 2, ! 135: Data_Mode_Cntl = 3, TMC_Cntl = 4, Write_Loopback = 7, ! 136: Write_FIFO = 12 }; ! 137: ! 138: static void *addresses[] = { ! 139: (void *)0xc8000, ! 140: (void *)0xca000, ! 141: (void *)0xce000, ! 142: (void *)0xde000 }; ! 143: #define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned )) ! 144: ! 145: static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; ! 146: #define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short )) ! 147: ! 148: static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; ! 149: ! 150: /* ! 151: ! 152: READ THIS BEFORE YOU ADD A SIGNATURE! ! 153: ! 154: READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME! ! 155: ! 156: READ EVERY WORD, ESPECIALLY THE WORD *NOT* ! 157: ! 158: This driver works *ONLY* for Future Domain cards using the ! 159: TMC-1600 chip. This includes models TMC-1660 and TMC-1680 ! 160: *ONLY*. ! 161: ! 162: The following is a BIOS signature for a TMC-950 board, which ! 163: looks like it is a 16 bit board (based on card edge), but ! 164: which only uses the extra lines for IRQ's (not for data): ! 165: ! 166: FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90 ! 167: ! 168: THIS WILL *NOT* WORK WITH THIS DRIVER! ! 169: ! 170: Here is another BIOS signature for yet another Future ! 171: Domain board WHICH WILL *NOT* WORK WITH THIS DRIVER: ! 172: ! 173: FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90 ! 174: ! 175: Here is another BIOS signature for the TMC-88x series: ! 176: ! 177: FUTURE DOMAIN COPR. (C) 1986-1989 V6.0A7/28/90 ! 178: ! 179: THIS WILL *NOT* WORK WITH THIS DRIVER, but it *WILL* ! 180: work with the *SEAGATE* ST-01/ST-02 driver. ! 181: ! 182: */ ! 183: ! 184: struct signature { ! 185: char *signature; ! 186: int sig_offset; ! 187: int sig_length; ! 188: } signatures[] = { ! 189: { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0 7/28/89", 5, 50 }, ! 190: { "FUTURE DOMAIN CORP. (C) 1986-1990 1800", 5, 37 }, ! 191: /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGANTURE */ ! 192: }; ! 193: ! 194: #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature )) ! 195: ! 196: ! 197: /* These functions are based on include/asm/io.h */ ! 198: ! 199: #if 1 ! 200: static unsigned short inline inw( unsigned short port ) ! 201: { ! 202: unsigned short _v; ! 203: ! 204: __asm__ volatile ("inw %1,%0" ! 205: :"=a" (_v):"d" ((unsigned short) port)); ! 206: return _v; ! 207: } ! 208: ! 209: static void inline outw( unsigned short value, unsigned short port ) ! 210: { ! 211: __asm__ volatile ("outw %0,%1" ! 212: ::"a" ((unsigned short) value), ! 213: "d" ((unsigned short) port)); ! 214: } ! 215: #else ! 216: ! 217: #define inw( port ) \ ! 218: ({ unsigned short _v; \ ! 219: __asm__ volatile ("inw %1,%0" \ ! 220: : "=a" (_v) : "d" ((unsigned short) port)); \ ! 221: _v; }) ! 222: ! 223: #define outw( value ) \ ! 224: __asm__ volatile \ ! 225: ("outw %0,%1" : : "a" ((unsigned short) value), \ ! 226: "d" ((unsigned short) port)) ! 227: #endif ! 228: ! 229: ! 230: /* These defines are copied from kernel/blk_drv/hd.c */ ! 231: ! 232: #define insw( buf, count, port ) \ ! 233: __asm__ volatile \ ! 234: ( "cld;rep;insw"::"d" (port),"D" (buf),"c" (count):"cx","di" ) ! 235: ! 236: #define outsw( buf, count, port) \ ! 237: __asm__ volatile \ ! 238: ("cld;rep;outsw"::"d" (port),"S" (buf),"c" (count):"cx","si") ! 239: ! 240: ! 241: static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */ ! 242: { ! 243: unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ ! 244: ! 245: while (jiffies < the_time); ! 246: } ! 247: ! 248: static void inline fdomain_make_bus_idle( void ) ! 249: { ! 250: outb( 0, SCSI_Cntl_port ); ! 251: outb( 0, Data_Mode_Cntl_port ); ! 252: outb( 1, TMC_Cntl_port ); ! 253: } ! 254: ! 255: static int fdomain_is_valid_port( int port ) ! 256: { ! 257: int options; ! 258: ! 259: #if DEBUG_DETECT ! 260: printk( " (%x%x),", ! 261: inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) ); ! 262: #endif ! 263: ! 264: /* The MCA ID is a unique id for each MCA compatible board. We ! 265: are using ISA boards, but Future Domain provides the MCA ID ! 266: anyway. We can use this ID to ensure that this is a Future ! 267: Domain TMC-1660/TMC-1680. ! 268: */ ! 269: ! 270: if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */ ! 271: if (inb( port + LSB_ID_Code ) != 0x27) return 0; ! 272: if (inb( port + MSB_ID_Code ) != 0x61) return 0; ! 273: } else { /* test for 0xe960 id */ ! 274: if (inb( port + MSB_ID_Code ) != 0x60) return 0; ! 275: } ! 276: ! 277: /* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board. ! 278: Now, check to be sure the bios_base matches these ports. ! 279: If someone was unlucky enough to have purchased more than one ! 280: Future Domain board, then they will have to modify this code, as ! 281: we only detect one board here. [The one with the lowest bios_base]. ! 282: */ ! 283: ! 284: options = inb( port + Option_Select ); ! 285: ! 286: #if DEBUG_DETECT ! 287: printk( " Options = %x,", options ); ! 288: #endif ! 289: ! 290: if (addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0; ! 291: interrupt_level = ints[ (options & 0x0e) >> 1 ]; ! 292: ! 293: return 1; ! 294: } ! 295: ! 296: static int fdomain_test_loopback( void ) ! 297: { ! 298: int i; ! 299: int result; ! 300: ! 301: for (i = 0; i < 255; i++) { ! 302: outb( i, port_base + Write_Loopback ); ! 303: result = inb( port_base + Read_Loopback ); ! 304: if (i != result) return 1; ! 305: } ! 306: return 0; ! 307: } ! 308: ! 309: #if !NEW_IRQ ! 310: static void fdomain_enable_interrupt( void ) ! 311: { ! 312: if (!interrupt_level) return; ! 313: ! 314: #if ALLOW_ALL_IRQ ! 315: if (interrupt_level < 8) { ! 316: outb( inb_p( 0x21 ) & ~(1 << interrupt_level), 0x21 ); ! 317: } else ! 318: #endif ! 319: { ! 320: outb( inb_p( 0xa1 ) & ~(1 << (interrupt_level - 8)), 0xa1 ); ! 321: } ! 322: } ! 323: ! 324: static void fdomain_disable_interrupt( void ) ! 325: { ! 326: if (!interrupt_level) return; ! 327: ! 328: #if ALLOW_ALL_IRQ ! 329: if (interrupt_level < 8) { ! 330: outb( inb_p( 0x21 ) | (1 << interrupt_level), 0x21 ); ! 331: } else ! 332: #endif ! 333: { ! 334: outb( inb_p( 0xa1 ) | (1 << (interrupt_level - 8)), 0xa1 ); ! 335: } ! 336: } ! 337: #endif ! 338: ! 339: int fdomain_16x0_detect( int hostnum ) ! 340: { ! 341: int i, j; ! 342: int flag; ! 343: unsigned char do_inquiry[] = { 0x12, 0, 0, 0, 255, 0 }; ! 344: unsigned char do_request_sense[] = { 0x03, 0, 0, 0, 255, 0 }; ! 345: unsigned char do_read_capacity[] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ! 346: unsigned char buf[256]; ! 347: unsigned retcode; ! 348: ! 349: #if DEBUG_DETECT ! 350: printk( "SCSI: fdomain_16x0_detect()," ); ! 351: #endif ! 352: ! 353: for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) { ! 354: #if DEBUG_DETECT ! 355: printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base ); ! 356: #endif ! 357: for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) { ! 358: if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset), ! 359: signatures[j].signature, signatures[j].sig_length )) { ! 360: bios_base = addresses[i]; ! 361: } ! 362: } ! 363: } ! 364: ! 365: if (!bios_base) { ! 366: #if DEBUG_DETECT ! 367: printk( " FAILED: NO BIOS\n" ); ! 368: #endif ! 369: return 0; ! 370: } ! 371: ! 372: /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM. ! 373: Assuming the ROM is enabled (otherwise we wouldn't have been ! 374: able to read the ROM signature :-), then the ROM set up the ! 375: RAM area with some magic numbers, such as a list of port ! 376: base addresses and a list of the disk "geometry" reported to ! 377: DOS (this geometry has nothing to do with physical geometry). ! 378: */ ! 379: ! 380: port_base = *((char *)bios_base + 0x1fcc) ! 381: + (*((char *)bios_base + 0x1fcd) << 8); ! 382: ! 383: #if DEBUG_DETECT ! 384: printk( " %x,", port_base ); ! 385: #endif ! 386: ! 387: for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) { ! 388: if (port_base == ports[i]) ++flag; ! 389: } ! 390: ! 391: if (flag) flag = fdomain_is_valid_port( port_base ); ! 392: ! 393: if (!flag) { /* Cannot get port base from BIOS RAM */ ! 394: ! 395: /* This is a bad sign. It usually means that someone patched the ! 396: BIOS signature list (the signatures variable) to contain a BIOS ! 397: signature for a board *OTHER THAN* the TMC-1660/TMC-1680. ! 398: */ ! 399: ! 400: #if DEBUG_DETECT ! 401: printk( " RAM FAILED, " ); ! 402: #endif ! 403: /* Anyway, the alternative to finding the address in the RAM is ! 404: to just search through every possible port address for one ! 405: that is attached to the Future Domain card. Don't panic, ! 406: though, about reading all these random port addresses--there ! 407: are rumors that the Future Domain BIOS does something very ! 408: similar. ! 409: */ ! 410: ! 411: for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) { ! 412: port_base = ports[i]; ! 413: #if DEBUG_DETECT ! 414: printk( " %x,", port_base ); ! 415: #endif ! 416: flag = fdomain_is_valid_port( port_base ); ! 417: } ! 418: } ! 419: ! 420: if (!flag) { ! 421: #if DEBUG_DETECT ! 422: printk( " FAILED: NO PORT\n" ); ! 423: #endif ! 424: return 0; /* Cannot find valid set of ports */ ! 425: } ! 426: ! 427: #if DEBUG_DETECT ! 428: printk( "\n" ); ! 429: printk( "SCSI: bios_base = %x, port_base = %x, interrupt_level = %d\n", ! 430: (unsigned)bios_base, port_base, interrupt_level ); ! 431: #endif ! 432: ! 433: if (interrupt_level) { ! 434: printk( "Future Domain BIOS at %x; port base at %x; using IRQ %d\n", ! 435: (unsigned)bios_base, port_base, interrupt_level ); ! 436: } else { ! 437: printk( "Future Domain BIOS at %x; port base at %x; *NO* IRQ\n", ! 438: (unsigned)bios_base, port_base ); ! 439: } ! 440: ! 441: Data_Mode_Cntl_port = port_base + Data_Mode_Cntl; ! 442: FIFO_Data_Count_port = port_base + FIFO_Data_Count; ! 443: Interrupt_Cntl_port = port_base + Interrupt_Cntl; ! 444: Read_FIFO_port = port_base + Read_FIFO; ! 445: Read_SCSI_Data_port = port_base + Read_SCSI_Data; ! 446: SCSI_Cntl_port = port_base + SCSI_Cntl; ! 447: SCSI_Status_port = port_base + SCSI_Status; ! 448: TMC_Cntl_port = port_base + TMC_Cntl; ! 449: TMC_Status_port = port_base + TMC_Status; ! 450: Write_FIFO_port = port_base + Write_FIFO; ! 451: Write_SCSI_Data_port = port_base + Write_SCSI_Data; ! 452: ! 453: fdomain_16x0_reset(); ! 454: ! 455: if (fdomain_test_loopback()) { ! 456: #if DEBUG_DETECT ! 457: printk( "SCSI: LOOPBACK TEST FAILED, FAILING DETECT!\n" ); ! 458: #endif ! 459: return 0; ! 460: } ! 461: ! 462: /* These routines are here because of the way the SCSI bus behaves ! 463: after a reset. This appropriate behavior was not handled correctly ! 464: by the higher level SCSI routines when I first wrote this driver. ! 465: */ ! 466: ! 467: printk( "Future Domain detection routine scanning for devices:\n" ); ! 468: for (i = 0; i < 8; i++) { ! 469: if (i == 6) continue; /* The host adapter is at SCSI ID 6 */ ! 470: retcode = fdomain_16x0_command( i, do_request_sense, buf, 255 ); ! 471: if (!retcode) { ! 472: retcode = fdomain_16x0_command( i, do_inquiry, buf, 255 ); ! 473: if (!retcode) { ! 474: printk( " SCSI ID %d: ", i ); ! 475: for (j = 8; j < 32; j++) printk( "%c", buf[j] ); ! 476: retcode = fdomain_16x0_command( i, do_read_capacity, buf, 255 ); ! 477: if (!retcode) { ! 478: unsigned long blocks, size, capacity; ! 479: ! 480: blocks = (buf[0] << 24) | (buf[1] << 16) ! 481: | (buf[2] << 8) | buf[3]; ! 482: size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; ! 483: capacity = +(blocks * size * 10) / +(1024L * 1024L); ! 484: ! 485: printk( "%lu MB (%lu byte blocks)", ! 486: ((capacity + 5L) / 10L), size ); ! 487: } ! 488: printk ("\n" ); ! 489: } ! 490: } ! 491: } ! 492: ! 493: #if QUEUE ! 494: #if !ALLOW_ALL_IRQ ! 495: if (interrupt_level < 8) { ! 496: printk( "Future Domain: WILL NOT USE IRQ LESS THAN 8 FOR QUEUEING!\n" ); ! 497: scsi_hosts[hostnum].can_queue = 0; ! 498: } else ! 499: #endif ! 500: #if NEW_IRQ ! 501: { ! 502: int retcode; ! 503: struct sigaction sa; ! 504: ! 505: this_host = hostnum; ! 506: ! 507: sa.sa_handler = fdomain_16x0_intr; ! 508: sa.sa_flags = SA_INTERRUPT; ! 509: sa.sa_mask = 0; ! 510: sa.sa_restorer = NULL; ! 511: ! 512: retcode = irqaction( interrupt_level, &sa ); ! 513: ! 514: if (retcode < 0) { ! 515: if (retcode == -EINVAL) { ! 516: printk( "Future Domain: IRQ %d is bad!\n", interrupt_level ); ! 517: printk( " This shouldn't happen: REPORT TO RIK!\n" ); ! 518: } else if (retcode == -EBUSY) { ! 519: printk( "Future Domain: IRQ %d is already in use!\n", ! 520: interrupt_level ); ! 521: printk( " Please use another IRQ for the FD card!\n" ); ! 522: } else { ! 523: printk( "Future Domain: Error getting IRQ %d\n", ! 524: interrupt_level ); ! 525: printk( " This shouldn't happen: REPORT TO RIK!\n" ); ! 526: } ! 527: printk( " IRQs WILL NOT BE USED!\n" ); ! 528: ! 529: scsi_hosts[this_host].can_queue = 0; ! 530: } else { ! 531: printk( "Future Domain: IRQ %d selected with retcode = %d\n", ! 532: interrupt_level, retcode ); ! 533: } ! 534: } ! 535: #else ! 536: { ! 537: this_host = hostnum; ! 538: set_intr_gate( 0x20 + interrupt_level, &fdomain_16x0_interrupt ); ! 539: fdomain_enable_interrupt(); ! 540: } ! 541: #endif ! 542: #endif ! 543: ! 544: return 1; ! 545: } ! 546: ! 547: char *fdomain_16x0_info(void) ! 548: { ! 549: static char buffer[] = ! 550: "Future Domain TMC-1660/TMC-1680 SCSI driver version " ! 551: VERSION ! 552: "\n"; ! 553: return buffer; ! 554: } ! 555: ! 556: static int fdomain_arbitrate( void ) ! 557: { ! 558: int status = 0; ! 559: unsigned long timeout; ! 560: ! 561: #if VERBOSE ! 562: printk( "SCSI: fdomain_arbitrate()\n" ); ! 563: #endif ! 564: ! 565: outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */ ! 566: outb( 0x40, port_base + SCSI_Data_NoACK ); /* Set our id bit */ ! 567: outb( 0x04, TMC_Cntl_port ); /* Start arbitration */ ! 568: ! 569: timeout = jiffies + 50; /* 500 mS */ ! 570: while (jiffies < timeout) { ! 571: status = inb( TMC_Status_port ); /* Read adapter status */ ! 572: if (status & 0x02) return 0; /* Arbitration complete */ ! 573: } ! 574: ! 575: /* Make bus idle */ ! 576: fdomain_make_bus_idle(); ! 577: ! 578: #if EVERY_ACCESS ! 579: printk( "Arbitration failed, status = %x\n", status ); ! 580: #endif ! 581: #if ERRORS_ONLY ! 582: printk( "SCSI: Arbitration failed, status = %x", status ); ! 583: #endif ! 584: return 1; ! 585: } ! 586: ! 587: static int fdomain_select( int target ) ! 588: { ! 589: int status; ! 590: unsigned long timeout; ! 591: ! 592: outb( 0x80, SCSI_Cntl_port ); /* Bus Enable */ ! 593: outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */ ! 594: ! 595: /* Send our address OR'd with target address */ ! 596: #if SEND_IDENTIFY ! 597: outb( 0x40 | (1 << target), port_base + SCSI_Data_NoACK ); ! 598: #else ! 599: outb( (1 << target), port_base + SCSI_Data_NoACK ); ! 600: #endif ! 601: ! 602: /* Stop arbitration (also set FIFO for output and enable parity) */ ! 603: outb( 0xc8, TMC_Cntl_port ); ! 604: ! 605: timeout = jiffies + 25; /* 250mS */ ! 606: while (jiffies < timeout) { ! 607: status = inb( SCSI_Status_port ); /* Read adapter status */ ! 608: if (status & 1) { /* Busy asserted */ ! 609: /* Enable SCSI Bus (on error, should make bus idle with 0) */ ! 610: #if SEND_IDENTIFY ! 611: /* Also, set ATN so that the drive will make a MESSAGE OUT phase */ ! 612: outb( 0x88, SCSI_Cntl_port ); ! 613: #else ! 614: outb( 0x80, SCSI_Cntl_port ); ! 615: #endif ! 616: return 0; ! 617: } ! 618: } ! 619: /* Make bus idle */ ! 620: fdomain_make_bus_idle(); ! 621: #if EVERY_ACCESS ! 622: if (!target) printk( "Select failed\n" ); ! 623: #endif ! 624: #if ERRORS_ONLY ! 625: if (!target) printk( "SCSI: Select failed" ); ! 626: #endif ! 627: return 1; ! 628: } ! 629: ! 630: #if QUEUE ! 631: ! 632: #if !USE_FIFO ! 633: #pragma error QUEUE requires USE_FIFO ! 634: #endif ! 635: ! 636: void my_done( int error ) ! 637: { ! 638: if (in_command) { ! 639: in_command = 0; ! 640: in_interrupt_code = 0; ! 641: outb( 0x00, Interrupt_Cntl_port ); ! 642: fdomain_make_bus_idle(); ! 643: if (current_done) current_done( this_host, error ); ! 644: else panic( "SCSI (Future Domain): current_done() == NULL" ); ! 645: } else { ! 646: panic( "SCSI (Future Domain): my_done() called outside of command\n" ); ! 647: } ! 648: } ! 649: ! 650: #if NEW_IRQ ! 651: void fdomain_16x0_intr( int unused ) ! 652: #else ! 653: void fdomain_16x0_intr( void ) ! 654: #endif ! 655: { ! 656: int status; ! 657: int done = 0; ! 658: unsigned data_count; ! 659: ! 660: #if NEW_IRQ ! 661: sti(); ! 662: #endif ! 663: ! 664: if (in_interrupt_code) ! 665: panic( "SCSI (Future Domain): fdomain_16x0_intr() NOT REENTRANT!\n" ); ! 666: else ! 667: ++in_interrupt_code; ! 668: ! 669: outb( 0x00, Interrupt_Cntl_port ); ! 670: ! 671: #if EVERY_ACCESS ! 672: printk( "aborted = %d, ", aborted ); ! 673: #endif ! 674: ! 675: if (aborted) { ! 676: /* Force retry for timeouts after selection complete */ ! 677: if (current_phase == in_other) ! 678: my_done( DID_BUS_BUSY << 16 ); ! 679: else ! 680: my_done( aborted << 16 ); ! 681: #if NEW_IRQ && !DECREASE_IL ! 682: cli(); ! 683: #endif ! 684: return; ! 685: } ! 686: ! 687: /* We usually have one spurious interrupt after each command. Ignore it. */ ! 688: if (!in_command) { /* Spurious interrupt */ ! 689: in_interrupt_code = 0; ! 690: #if NEW_IRQ && !DECREASE_IL ! 691: cli(); ! 692: #endif ! 693: return; ! 694: } ! 695: ! 696: if (current_phase == in_arbitration) { ! 697: status = inb( TMC_Status_port ); /* Read adapter status */ ! 698: if (!(status & 0x02)) { ! 699: #if EVERY_ACCESS ! 700: printk( " AFAIL " ); ! 701: #endif ! 702: my_done( DID_TIME_OUT << 16 ); ! 703: #if NEW_IRQ && !DECREASE_IL ! 704: cli(); ! 705: #endif ! 706: return; ! 707: } ! 708: current_phase = in_selection; ! 709: ! 710: outb( 0x80, SCSI_Cntl_port ); /* Bus Enable */ ! 711: outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */ ! 712: ! 713: outb( (1 << current_target), port_base + SCSI_Data_NoACK ); ! 714: ! 715: outb( 0x40, Interrupt_Cntl_port ); ! 716: /* Stop arbitration (also set FIFO for output and enable parity) */ ! 717: in_interrupt_code = 0; ! 718: outb( 0xd8, TMC_Cntl_port ); ! 719: #if NEW_IRQ && !DECREASE_IL ! 720: cli(); ! 721: #endif ! 722: return; ! 723: } else if (current_phase == in_selection) { ! 724: status = inb( SCSI_Status_port ); ! 725: if (!(status & 0x01)) { ! 726: #if EVERY_ACCESS ! 727: printk( " SFAIL " ); ! 728: #endif ! 729: my_done( DID_NO_CONNECT << 16 ); ! 730: #if NEW_IRQ && !DECREASE_IL ! 731: cli(); ! 732: #endif ! 733: return; ! 734: } ! 735: current_phase = in_other; ! 736: #if FAST_SYNCH ! 737: outb( 0xc0, Data_Mode_Cntl_port ); ! 738: #endif ! 739: in_interrupt_code = 0; ! 740: outb( 0x90, Interrupt_Cntl_port ); ! 741: outb( 0x80, SCSI_Cntl_port ); ! 742: #if NEW_IRQ && !DECREASE_IL ! 743: cli(); ! 744: #endif ! 745: return; ! 746: } ! 747: ! 748: /* current_phase == in_other: this is the body of the routine */ ! 749: ! 750: switch ((unsigned char)*the_command) { ! 751: case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a: ! 752: case 0x2e: case 0x3b: case 0xea: case 0x3f: ! 753: data_count = 0x2000 - inw( FIFO_Data_Count_port ); ! 754: if (current_bufflen - data_sent < data_count) ! 755: data_count = current_bufflen - data_sent; ! 756: if (data_count > 0) { ! 757: /* if (data_count > 512) data_count = 512; */ ! 758: #if EVERY_ACCESS ! 759: printk( "%d OUT, ", data_count ); ! 760: #endif ! 761: if (data_count == 1) { ! 762: outb( *out_buf_pt++, Write_FIFO_port ); ! 763: ++data_sent; ! 764: } else { ! 765: data_count >>= 1; ! 766: outsw( out_buf_pt, data_count, Write_FIFO_port ); ! 767: out_buf_pt += 2 * data_count; ! 768: data_sent += 2 * data_count; ! 769: } ! 770: } ! 771: break; ! 772: default: ! 773: if (!have_data_in) { ! 774: outb( 0x98, TMC_Cntl_port ); ! 775: ++have_data_in; ! 776: } else { ! 777: data_count = inw( FIFO_Data_Count_port ); ! 778: /* if (data_count > 512) data_count = 512; */ ! 779: if (data_count) { ! 780: #if EVERY_ACCESS ! 781: printk( "%d IN, ", data_count ); ! 782: #endif ! 783: if (data_count == 1) { ! 784: *in_buf_pt++ = inb( Read_FIFO_port ); ! 785: } else { ! 786: data_count >>= 1; /* Number of words */ ! 787: insw( in_buf_pt, data_count, Read_FIFO_port ); ! 788: in_buf_pt += 2 * data_count; ! 789: } ! 790: } ! 791: } ! 792: break; ! 793: } ! 794: ! 795: status = inb( SCSI_Status_port ); ! 796: ! 797: if (status & 0x10) { /* REQ */ ! 798: ! 799: switch (status & 0x0e) { ! 800: case 0x08: /* COMMAND OUT */ ! 801: outb( *cmd_pt++, Write_SCSI_Data_port ); ! 802: #if EVERY_ACCESS ! 803: printk( "CMD = %x,", (unsigned char)cmd_pt[-1] ); ! 804: #endif ! 805: break; ! 806: case 0x0c: /* STATUS IN */ ! 807: Status = inb( Read_SCSI_Data_port ); ! 808: #if EVERY_ACCESS ! 809: printk( "Status = %x, ", Status ); ! 810: #endif ! 811: #if ERRORS_ONLY ! 812: if (Status) { ! 813: printk( "SCSI: target = %d, command = %x, Status = %x\n", ! 814: current_target, (unsigned char)*the_command, Status ); ! 815: } ! 816: #endif ! 817: break; ! 818: case 0x0a: /* MESSAGE OUT */ ! 819: #if SEND_IDENTIFY ! 820: /* On the first request, send an Identify message */ ! 821: if (!sent_identify) { ! 822: outb( 0x80, SCSI_Cntl_port ); /* Lower ATN */ ! 823: outb( 0x80, Write_SCSI_Data_port ); /* Identify */ ! 824: ++sent_identify; ! 825: } else ! 826: #else ! 827: outb( 0x07, Write_SCSI_Data_port ); /* Reject */ ! 828: #endif ! 829: break; ! 830: case 0x0e: /* MESSAGE IN */ ! 831: Message = inb( Read_SCSI_Data_port ); ! 832: #if EVERY_ACCESS ! 833: printk( "Message = %x, ", Message ); ! 834: #endif ! 835: if (!Message) ++done; ! 836: break; ! 837: } ! 838: } ! 839: ! 840: if (done) { ! 841: #if EVERY_ACCESS ! 842: printk( " ** IN DONE ** " ); ! 843: #endif ! 844: ! 845: if (have_data_in) { ! 846: while (data_count = inw( FIFO_Data_Count_port )) { ! 847: if (data_count == 1) { ! 848: *in_buf_pt++ = inb( Read_FIFO_port ); ! 849: } else { ! 850: data_count >>= 1; /* Number of words */ ! 851: insw( in_buf_pt, data_count, Read_FIFO_port ); ! 852: in_buf_pt += 2 * data_count; ! 853: } ! 854: } ! 855: } ! 856: #if EVERY_ACCESS ! 857: printk( "AFTER DATA GET\n" ); ! 858: #endif ! 859: ! 860: #if ERRORS_ONLY ! 861: if (*the_command == REQUEST_SENSE && !Status) { ! 862: if ((unsigned char)(*((char *)current_buff + 2)) & 0x0f) { ! 863: printk( "SCSI REQUEST SENSE: Sense Key = %x, Sense Code = %x\n", ! 864: (unsigned char)(*((char *)current_buff + 2)) & 0x0f, ! 865: (unsigned char)(*((char *)current_buff + 12)) ); ! 866: } ! 867: } ! 868: #endif ! 869: #if EVERY_ACCESS ! 870: printk( "BEFORE MY_DONE\n" ); ! 871: #endif ! 872: my_done( (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16) ); ! 873: } else { ! 874: in_interrupt_code = 0; ! 875: outb( 0x90, Interrupt_Cntl_port ); ! 876: } ! 877: ! 878: #if NEW_IRQ && !DECREASE_IL ! 879: cli(); ! 880: #endif ! 881: return; ! 882: } ! 883: ! 884: int fdomain_16x0_queue( unsigned char target, const void *cmnd, ! 885: void *buff, int bufflen, void (*done)(int,int) ) ! 886: { ! 887: if (in_command) { ! 888: panic( "SCSI (Future Domain): fdomain_16x0_queue() NOT REENTRANT!\n" ); ! 889: } ! 890: #if EVERY_ACCESS ! 891: printk( "queue %d %x\n", target, *(unsigned char *)cmnd ); ! 892: #endif ! 893: ! 894: fdomain_make_bus_idle(); ! 895: ! 896: aborted = 0; ! 897: current_target = target; ! 898: memcpy( current_cmnd, cmnd, ((*(unsigned char *)cmnd) <= 0x1f ? 6 : 10 ) ); ! 899: current_buff = buff; ! 900: current_bufflen = bufflen; ! 901: current_done = done; ! 902: ! 903: /* Initialize static data */ ! 904: cmd_pt = current_cmnd; ! 905: the_command = current_cmnd; ! 906: out_buf_pt = current_buff; ! 907: in_buf_pt = current_buff; ! 908: ! 909: Status = 0; ! 910: Message = 0; ! 911: data_sent = 0; ! 912: have_data_in = 0; ! 913: ! 914: /* Start arbitration */ ! 915: current_phase = in_arbitration; ! 916: outb( 0x00, Interrupt_Cntl_port ); ! 917: outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */ ! 918: outb( 0x40, port_base + SCSI_Data_NoACK ); /* Set our id bit */ ! 919: ++in_command; ! 920: outb( 0x20, Interrupt_Cntl_port ); ! 921: outb( 0x1c, TMC_Cntl_port ); /* Start arbitration */ ! 922: ! 923: return 0; ! 924: } ! 925: #endif ! 926: ! 927: int fdomain_16x0_command( unsigned char target, const void *cmnd, ! 928: void *buff, int bufflen ) ! 929: { ! 930: const char *cmd_pt = cmnd; ! 931: const char *the_command = cmnd; ! 932: unsigned char *out_buf_pt = buff; ! 933: unsigned char *in_buf_pt = buff; ! 934: int Status = 0; ! 935: int Message = 0; ! 936: int status; ! 937: int done = 0; ! 938: unsigned long timeout; ! 939: unsigned data_sent = 0; ! 940: unsigned data_count; ! 941: #if USE_FIFO ! 942: int have_data_in = 0; ! 943: #endif ! 944: #if SEND_IDENTITY ! 945: int sent_identify = 0; ! 946: #endif ! 947: ! 948: #if EVERY_ACCESS ! 949: printk( "fdomain_command(%d, %x): ", target, (unsigned char)*the_command ); ! 950: #endif ! 951: ! 952: if (fdomain_arbitrate()) { ! 953: #if ERRORS_ONLY ! 954: printk( ", target = %d, command = %x\n", ! 955: target, (unsigned char)*the_command ); ! 956: #endif ! 957: return DID_TIME_OUT << 16; ! 958: } ! 959: ! 960: if (fdomain_select( target )) { ! 961: #if ERRORS_ONLY ! 962: if (!target) printk( ", target = %d, command = %x\n", ! 963: target, (unsigned char)*the_command ); ! 964: #endif ! 965: return DID_NO_CONNECT << 16; ! 966: } ! 967: ! 968: timeout = jiffies + 500; /* 5000 mS -- For Maxtor after a RST */ ! 969: aborted = 0; /* How is this supposed to get reset??? */ ! 970: ! 971: #if FAST_SYNCH ! 972: outb( 0xc0, Data_Mode_Cntl_port ); ! 973: #endif ! 974: ! 975: #if USE_FIFO ! 976: switch ((unsigned char)*the_command) { ! 977: case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a: ! 978: case 0x2e: case 0x3b: case 0xea: case 0x3f: ! 979: data_count = 0x2000 - inw( FIFO_Data_Count_port ); ! 980: if (bufflen - data_sent < data_count) ! 981: data_count = bufflen - data_sent; ! 982: if (data_count == 1) { ! 983: outb( *out_buf_pt++, Write_FIFO_port ); ! 984: ++data_sent; ! 985: } else { ! 986: data_count >>= 1; ! 987: outsw( out_buf_pt, data_count, Write_FIFO_port ); ! 988: out_buf_pt += 2 * data_count; ! 989: data_sent += 2 * data_count; ! 990: } ! 991: break; ! 992: default: ! 993: outb( 0x88, TMC_Cntl_port ); ! 994: ++have_data_in; ! 995: break; ! 996: } ! 997: #endif ! 998: ! 999: while (((status = inb( SCSI_Status_port )) & 1) ! 1000: && !done && !aborted && jiffies < timeout) { ! 1001: ! 1002: if (status & 0x10) { /* REQ */ ! 1003: ! 1004: switch (status & 0x0e) { ! 1005: case 0x00: /* DATA OUT */ ! 1006: #if USE_FIFO ! 1007: data_count = 0x2000 - inw( FIFO_Data_Count_port ); ! 1008: if (bufflen - data_sent < data_count) ! 1009: data_count = bufflen - data_sent; ! 1010: if (data_count == 1) { ! 1011: outb( *out_buf_pt++, Write_FIFO_port ); ! 1012: ++data_sent; ! 1013: } else { ! 1014: data_count >>= 1; ! 1015: outsw( out_buf_pt, data_count, Write_FIFO_port ); ! 1016: out_buf_pt += 2 * data_count; ! 1017: data_sent += 2 * data_count; ! 1018: } ! 1019: #else ! 1020: outb( *out_buf_pt++, Write_SCSI_Data_port ); ! 1021: #endif ! 1022: break; ! 1023: case 0x04: /* DATA IN */ ! 1024: #if USE_FIFO ! 1025: if (!have_data_in) { ! 1026: outb( 0x88, TMC_Cntl_port ); ! 1027: ++have_data_in; ! 1028: } ! 1029: data_count = inw( FIFO_Data_Count_port ); ! 1030: if (data_count == 1) { ! 1031: *in_buf_pt++ = inb( Read_FIFO_port ); ! 1032: } else { ! 1033: data_count >>= 1; /* Number of words */ ! 1034: insw( in_buf_pt, data_count, Read_FIFO_port ); ! 1035: in_buf_pt += 2 * data_count; ! 1036: } ! 1037: #else ! 1038: *in_buf_pt++ = inb( Read_SCSI_Data_port ); ! 1039: #endif ! 1040: break; ! 1041: case 0x08: /* COMMAND OUT */ ! 1042: outb( *cmd_pt++, Write_SCSI_Data_port ); ! 1043: #if EVERY_ACCESS ! 1044: printk( "%x,", (unsigned char)cmd_pt[-1] ); ! 1045: #endif ! 1046: break; ! 1047: case 0x0c: /* STATUS IN */ ! 1048: Status = inb( Read_SCSI_Data_port ); ! 1049: #if EVERY_ACCESS ! 1050: printk( "Status = %x, ", Status ); ! 1051: #endif ! 1052: #if ERRORS_ONLY ! 1053: if (Status) { ! 1054: printk( "SCSI: target = %d, command = %x, Status = %x\n", ! 1055: target, (unsigned char)*the_command, Status ); ! 1056: } ! 1057: #endif ! 1058: break; ! 1059: case 0x0a: /* MESSAGE OUT */ ! 1060: #if SEND_IDENTIFY ! 1061: /* On the first request, send an Identify message */ ! 1062: if (!sent_identify) { ! 1063: outb( 0x80, SCSI_Cntl_port ); /* Lower ATN */ ! 1064: outb( 0x80, Write_SCSI_Data_port ); /* Identify */ ! 1065: ++sent_identify; ! 1066: } else ! 1067: #else ! 1068: outb( 0x07, Write_SCSI_Data_port ); /* Reject */ ! 1069: #endif ! 1070: break; ! 1071: case 0x0e: /* MESSAGE IN */ ! 1072: Message = inb( Read_SCSI_Data_port ); ! 1073: #if EVERY_ACCESS ! 1074: printk( "Message = %x, ", Message ); ! 1075: #endif ! 1076: if (!Message) ++done; ! 1077: break; ! 1078: } ! 1079: } ! 1080: } ! 1081: ! 1082: if (jiffies >= timeout) { ! 1083: #if EVERY_ACCESS ! 1084: printk( "Time out, status = %x\n", status ); ! 1085: #endif ! 1086: #if ERRORS_ONLY ! 1087: printk( "SCSI: Time out, status = %x (target = %d, command = %x)\n", ! 1088: status, target, (unsigned char)*the_command ); ! 1089: #endif ! 1090: fdomain_make_bus_idle(); ! 1091: return DID_BUS_BUSY << 16; ! 1092: } ! 1093: ! 1094: if (aborted) { ! 1095: #if EVERY_ACCESS ! 1096: printk( "Aborted\n" ); ! 1097: #endif ! 1098: #if ONLY_ERRORS ! 1099: printk( "SCSI: Aborted (command = %x)\n", (unsigned char)*the_command ); ! 1100: #endif ! 1101: fdomain_16x0_reset(); ! 1102: return DID_ABORT << 16; ! 1103: } ! 1104: ! 1105: #if USE_FIFO ! 1106: if (have_data_in) { ! 1107: while (data_count = inw( FIFO_Data_Count_port )) { ! 1108: if (data_count == 1) { ! 1109: *in_buf_pt++ = inb( Read_FIFO_port ); ! 1110: } else { ! 1111: data_count >>= 1; /* Number of words */ ! 1112: insw( in_buf_pt, data_count, Read_FIFO_port ); ! 1113: in_buf_pt += 2 * data_count; ! 1114: } ! 1115: } ! 1116: } ! 1117: #endif ! 1118: ! 1119: fdomain_make_bus_idle(); ! 1120: ! 1121: #if EVERY_ACCESS ! 1122: printk( "Retcode = %x\n", ! 1123: (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16) ); ! 1124: #endif ! 1125: #if ERRORS_ONLY ! 1126: if (*the_command == REQUEST_SENSE && !Status) { ! 1127: if ((unsigned char)(*((char *)buff + 2)) & 0x0f) { ! 1128: printk( "SCSI REQUEST SENSE: Sense Key = %x, Sense Code = %x\n", ! 1129: (unsigned char)(*((char *)buff + 2)) & 0x0f, ! 1130: (unsigned char)(*((char *)buff + 12)) ); ! 1131: } ! 1132: } ! 1133: #endif ! 1134: ! 1135: return (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16); ! 1136: } ! 1137: ! 1138: int fdomain_16x0_abort( int code ) ! 1139: { ! 1140: ! 1141: #if EVERY_ACCESS ! 1142: printk( " ABORT " ); ! 1143: #endif ! 1144: ! 1145: #if QUEUE ! 1146: cli(); ! 1147: if (!in_command) { ! 1148: sti(); ! 1149: return 0; ! 1150: } ! 1151: ! 1152: aborted = code ? code : DID_ABORT; ! 1153: ! 1154: sti(); ! 1155: fdomain_make_bus_idle(); ! 1156: #else ! 1157: aborted = code ? code : DID_ABORT; ! 1158: #endif ! 1159: ! 1160: return 0; ! 1161: } ! 1162: ! 1163: int fdomain_16x0_reset( void ) ! 1164: { ! 1165: outb( 1, SCSI_Cntl_port ); ! 1166: do_pause( 2 ); ! 1167: outb( 0, SCSI_Cntl_port ); ! 1168: do_pause( 115 ); ! 1169: outb( 0, Data_Mode_Cntl_port ); ! 1170: outb( 0, TMC_Cntl_port ); ! 1171: ! 1172: aborted = DID_RESET; ! 1173: ! 1174: return 0; ! 1175: } ! 1176: ! 1177: #if QUEUE && !NEW_IRQ ! 1178: ! 1179: /* This is copied from kernel/sys_calls.s ! 1180: and from kernel/blk_drv/scsi/aha1542.c */ ! 1181: ! 1182: __asm__(" ! 1183: _fdomain_16x0_interrupt: ! 1184: cld ! 1185: push %gs ! 1186: push %fs ! 1187: push %es ! 1188: push %ds ! 1189: pushl %eax ! 1190: pushl %ebp ! 1191: pushl %edi ! 1192: pushl %esi ! 1193: pushl %edx ! 1194: pushl %ecx ! 1195: pushl %ebx ! 1196: movl $0x10,%edx ! 1197: mov %dx,%ds ! 1198: mov %dx,%es ! 1199: movl $0x17,%edx ! 1200: mov %dx,%fs ! 1201: ! 1202: movl $_fdomain_disable_interrupt,%edx ! 1203: call *%edx ! 1204: ! 1205: movb $0x20,%al ! 1206: outb %al,$0xA0 # EOI to interrupt controller #1 ! 1207: jmp 1f # give port chance to breathe ! 1208: 1: jmp 1f ! 1209: 1: outb %al,$0x20 ! 1210: ! 1211: sti ! 1212: movl $_fdomain_16x0_intr,%edx ! 1213: call *%edx # ``interesting'' way of handling intr. ! 1214: cli ! 1215: ! 1216: movl $_fdomain_enable_interrupt,%edx ! 1217: call *%edx ! 1218: ! 1219: popl %ebx ! 1220: popl %ecx ! 1221: popl %edx ! 1222: popl %esi ! 1223: popl %edi ! 1224: popl %ebp ! 1225: popl %eax ! 1226: pop %ds ! 1227: pop %es ! 1228: pop %fs ! 1229: pop %gs ! 1230: iret ! 1231: "); ! 1232: #endif ! 1233: ! 1234: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.