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

1.1     ! root        1: /* 
        !             2:  *  NCR53c406.c
        !             3:  *  Low-level SCSI driver for NCR53c406a chip.
        !             4:  *  Copyright (C) 1994, 1995, 1996 Normunds Saumanis ([email protected])
        !             5:  * 
        !             6:  *  LILO command line usage: ncr53c406a=<PORTBASE>[,<IRQ>[,<FASTPIO>]]
        !             7:  *  Specify IRQ = 0 for non-interrupt driven mode.
        !             8:  *  FASTPIO = 1 for fast pio mode, 0 for slow mode.
        !             9:  *
        !            10:  *  This program is free software; you can redistribute it and/or modify it
        !            11:  *  under the terms of the GNU General Public License as published by the
        !            12:  *  Free Software Foundation; either version 2, or (at your option) any
        !            13:  *  later version.
        !            14:  *
        !            15:  *  This program is distributed in the hope that it will be useful, but
        !            16:  *  WITHOUT ANY WARRANTY; without even the implied warranty of
        !            17:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            18:  *  General Public License for more details.
        !            19:  *
        !            20:  */
        !            21: 
        !            22: #define NCR53C406A_DEBUG 0
        !            23: #define VERBOSE_NCR53C406A_DEBUG 0
        !            24: 
        !            25: /* Set this to 1 for PIO mode (recommended) or to 0 for DMA mode */
        !            26: #define USE_PIO 1
        !            27: 
        !            28: #define USE_BIOS 0
        !            29: /* #define BIOS_ADDR 0xD8000 */ /* define this if autoprobe fails */
        !            30: /* #define PORT_BASE 0x330 */   /* define this if autoprobe fails */
        !            31: /* #define IRQ_LEV   0 */      /* define this if autoprobe fails */
        !            32: #define DMA_CHAN  5            /* this is ignored if DMA is disabled */
        !            33: 
        !            34: /* Set this to 0 if you encounter kernel lockups while transferring 
        !            35:  * data in PIO mode */
        !            36: #define USE_FAST_PIO 1
        !            37: 
        !            38: /* ============= End of user configurable parameters ============= */
        !            39: 
        !            40: #include <linux/module.h>
        !            41: 
        !            42: #include <linux/errno.h>
        !            43: #include <linux/ioport.h>
        !            44: #include <linux/sched.h>
        !            45: #include <linux/interrupt.h>
        !            46: #include <linux/proc_fs.h>
        !            47: #include <linux/stat.h>
        !            48: #include <asm/io.h>
        !            49: #include <asm/dma.h>
        !            50: #include <asm/bitops.h>
        !            51: #include <asm/irq.h>
        !            52: 
        !            53: #include <linux/blk.h>
        !            54: #include "scsi.h"
        !            55: #include "hosts.h"
        !            56: #include "sd.h"
        !            57: 
        !            58: #include "NCR53c406a.h"
        !            59: 
        !            60: /* ============================================================= */
        !            61: 
        !            62: #define WATCHDOG 5000000
        !            63: 
        !            64: #define SYNC_MODE 0            /* Synchronous transfer mode */
        !            65: 
        !            66: #if DEBUG
        !            67: #undef NCR53C406A_DEBUG
        !            68: #define NCR53C406A_DEBUG 1
        !            69: #endif
        !            70: 
        !            71: #if USE_PIO
        !            72: #define USE_DMA 0
        !            73: #else
        !            74: #define USE_DMA 1
        !            75: #endif
        !            76: 
        !            77: /* Default configuration */
        !            78: #define C1_IMG   0x07          /* ID=7 */
        !            79: #define C2_IMG   0x48          /* FE SCSI2 */
        !            80: #if USE_DMA
        !            81: #define C3_IMG   0x21          /* CDB TE */
        !            82: #else
        !            83: #define C3_IMG   0x20          /* CDB */
        !            84: #endif
        !            85: #define C4_IMG   0x04          /* ANE */
        !            86: #define C5_IMG   0xb6          /* AA PI SIE POL */
        !            87: 
        !            88: #define REG0 (outb(C4_IMG, CONFIG4))
        !            89: #define REG1 (outb(C5_IMG, CONFIG5))
        !            90: 
        !            91: #if NCR53C406A_DEBUG
        !            92: #define DEB(x) x
        !            93: #else
        !            94: #define DEB(x)
        !            95: #endif
        !            96: 
        !            97: #if VERBOSE_NCR53C406A_DEBUG
        !            98: #define VDEB(x) x
        !            99: #else
        !           100: #define VDEB(x)
        !           101: #endif
        !           102: 
        !           103: #define LOAD_DMA_COUNT(count) \
        !           104:   outb(count & 0xff, TC_LSB); \
        !           105:   outb((count >> 8) & 0xff, TC_MSB); \
        !           106:   outb((count >> 16) & 0xff, TC_HIGH);
        !           107: 
        !           108: /* Chip commands */
        !           109: #define DMA_OP               0x80
        !           110: 
        !           111: #define SCSI_NOP             0x00
        !           112: #define FLUSH_FIFO           0x01
        !           113: #define CHIP_RESET           0x02
        !           114: #define SCSI_RESET           0x03
        !           115: #define RESELECT             0x40
        !           116: #define SELECT_NO_ATN        0x41
        !           117: #define SELECT_ATN           0x42
        !           118: #define SELECT_ATN_STOP      0x43
        !           119: #define ENABLE_SEL           0x44
        !           120: #define DISABLE_SEL          0x45
        !           121: #define SELECT_ATN3          0x46
        !           122: #define RESELECT3            0x47
        !           123: #define TRANSFER_INFO        0x10
        !           124: #define INIT_CMD_COMPLETE    0x11
        !           125: #define MSG_ACCEPT           0x12
        !           126: #define TRANSFER_PAD         0x18
        !           127: #define SET_ATN              0x1a
        !           128: #define RESET_ATN            0x1b
        !           129: #define SEND_MSG             0x20
        !           130: #define SEND_STATUS          0x21
        !           131: #define SEND_DATA            0x22
        !           132: #define DISCONN_SEQ          0x23
        !           133: #define TERMINATE_SEQ        0x24
        !           134: #define TARG_CMD_COMPLETE    0x25
        !           135: #define DISCONN              0x27
        !           136: #define RECV_MSG             0x28
        !           137: #define RECV_CMD             0x29
        !           138: #define RECV_DATA            0x2a
        !           139: #define RECV_CMD_SEQ         0x2b
        !           140: #define TARGET_ABORT_DMA     0x04
        !           141: 
        !           142: /*----------------------------------------------------------------*/
        !           143: /* the following will set the monitor border color (useful to find
        !           144:    where something crashed or gets stuck at */
        !           145: /* 1 = blue
        !           146:    2 = green
        !           147:    3 = cyan
        !           148:    4 = red
        !           149:    5 = magenta
        !           150:    6 = yellow
        !           151:    7 = white
        !           152: */
        !           153: 
        !           154: #if NCR53C406A_DEBUG
        !           155: #define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
        !           156: #else
        !           157: #define rtrc(i) {}
        !           158: #endif
        !           159: /*----------------------------------------------------------------*/
        !           160: 
        !           161: enum Phase {
        !           162:     idle,
        !           163:     data_out,
        !           164:     data_in,
        !           165:     command_ph,
        !           166:     status_ph,
        !           167:     message_out,
        !           168:     message_in
        !           169: };
        !           170: 
        !           171: /* Static function prototypes */
        !           172: static  void NCR53c406a_intr(int, void *, struct pt_regs *);
        !           173: static  void internal_done(Scsi_Cmnd *);
        !           174: static  void wait_intr(void);
        !           175: static  void chip_init(void);
        !           176: static  void calc_port_addr(void);
        !           177: #ifndef IRQ_LEV
        !           178: static  int  irq_probe(void);
        !           179: #endif
        !           180: 
        !           181: /* ================================================================= */
        !           182: 
        !           183: #if USE_BIOS
        !           184: static void *bios_base = (void *)0;
        !           185: #endif
        !           186: 
        !           187: #if PORT_BASE
        !           188: static int   port_base = PORT_BASE;
        !           189: #else
        !           190: static int   port_base = 0;
        !           191: #endif
        !           192: 
        !           193: #if IRQ_LEV
        !           194: static int   irq_level = IRQ_LEV;
        !           195: #else
        !           196: static int   irq_level = -1; /* 0 is 'no irq', so use -1 for 'uninitialized'*/
        !           197: #endif
        !           198: 
        !           199: #if USE_DMA
        !           200: static int   dma_chan = 0;
        !           201: #endif
        !           202: 
        !           203: #if USE_PIO
        !           204: static int   fast_pio = USE_FAST_PIO;
        !           205: #endif
        !           206: 
        !           207: static Scsi_Cmnd         *current_SC       = NULL;
        !           208: static volatile int internal_done_flag = 0;
        !           209: static volatile int internal_done_errcode = 0;
        !           210: static char info_msg[256];
        !           211: 
        !           212: struct proc_dir_entry proc_scsi_NCR53c406a = {
        !           213:     PROC_SCSI_NCR53C406A, 7, "NCR53c406a",
        !           214:     S_IFDIR | S_IRUGO | S_IXUGO, 2
        !           215: };
        !           216: /* ================================================================= */
        !           217: 
        !           218: /* possible BIOS locations */
        !           219: #if USE_BIOS
        !           220: static void *addresses[] = {
        !           221:     (void *)0xd8000,
        !           222:     (void *)0xc8000
        !           223: };
        !           224: #define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
        !           225: #endif USE_BIOS
        !           226:                       
        !           227: /* possible i/o port addresses */
        !           228: static unsigned short ports[] = { 0x230, 0x330 };
        !           229: #define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
        !           230: 
        !           231: /* possible interrupt channels */
        !           232: static unsigned short intrs[] = { 10, 11, 12, 15 };
        !           233: #define INTR_COUNT (sizeof( intrs ) / sizeof( unsigned short ))
        !           234: 
        !           235: /* signatures for NCR 53c406a based controllers */
        !           236: #if USE_BIOS
        !           237: struct signature {
        !           238:     char *signature;
        !           239:     int  sig_offset;
        !           240:     int  sig_length;
        !           241: } signatures[] = {
        !           242:     /*          1         2         3         4         5         6 */
        !           243:     /* 123456789012345678901234567890123456789012345678901234567890 */
        !           244:     { "Copyright (C) Acculogic, Inc.\r\n2.8M Diskette Extension Bios ver 4.04.03 03/01/1993", 61, 82 },
        !           245: };
        !           246: #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
        !           247: #endif USE_BIOS
        !           248: 
        !           249: /* ============================================================ */
        !           250: 
        !           251: /* Control Register Set 0 */
        !           252: static int TC_LSB;             /* transfer counter lsb         */
        !           253: static int TC_MSB;             /* transfer counter msb */
        !           254: static int SCSI_FIFO;          /* scsi fifo register   */
        !           255: static int CMD_REG;            /* command register             */
        !           256: static int STAT_REG;           /* status register              */
        !           257: static int DEST_ID;            /* selection/reselection bus id */
        !           258: static int INT_REG;            /* interrupt status register    */
        !           259: static int SRTIMOUT;           /* select/reselect timeout reg  */
        !           260: static int SEQ_REG;            /* sequence step register       */
        !           261: static int SYNCPRD;            /* synchronous transfer period  */
        !           262: static int FIFO_FLAGS;         /* indicates # of bytes in fifo */
        !           263: static int SYNCOFF;            /* synchronous offset register  */
        !           264: static int CONFIG1;            /* configuration register       */
        !           265: static int CLKCONV;            /* clock conversion reg */
        !           266: /*static int TESTREG;*/                /* test mode register           */
        !           267: static int CONFIG2;            /* Configuration 2 Register     */
        !           268: static int CONFIG3;            /* Configuration 3 Register     */
        !           269: static int CONFIG4;            /* Configuration 4 Register     */
        !           270: static int TC_HIGH;            /* Transfer Counter High */
        !           271: /*static int FIFO_BOTTOM;*/    /* Reserve FIFO byte register   */
        !           272: 
        !           273: /* Control Register Set 1 */
        !           274: /*static int JUMPER_SENSE;*/   /* Jumper sense port reg (r/w) */
        !           275: /*static int SRAM_PTR;*/       /* SRAM address pointer reg (r/w) */
        !           276: /*static int SRAM_DATA;*/      /* SRAM data register (r/w) */
        !           277: static int PIO_FIFO;           /* PIO FIFO registers (r/w) */
        !           278: /*static int PIO_FIFO1;*/      /*  */
        !           279: /*static int PIO_FIFO2;*/      /*  */
        !           280: /*static int PIO_FIFO3;*/      /*  */
        !           281: static int PIO_STATUS;         /* PIO status (r/w) */
        !           282: /*static int ATA_CMD;*/                /* ATA command/status reg (r/w) */
        !           283: /*static int ATA_ERR;*/                /* ATA features/error register (r/w)*/
        !           284: static int PIO_FLAG;           /* PIO flag interrupt enable (r/w) */
        !           285: static int CONFIG5;            /* Configuration 5 register (r/w) */
        !           286: /*static int SIGNATURE;*/      /* Signature Register (r) */
        !           287: /*static int CONFIG6;*/                /* Configuration 6 register (r) */
        !           288: 
        !           289: /* ============================================================== */
        !           290: 
        !           291: #if USE_DMA
        !           292: static __inline__ int 
        !           293: NCR53c406a_dma_setup (unsigned char *ptr, 
        !           294:                      unsigned int count, 
        !           295:                      unsigned char mode) {
        !           296:     unsigned limit;
        !           297:     unsigned long flags = 0;
        !           298:     
        !           299:     VDEB(printk("dma: before count=%d   ", count));
        !           300:     if (dma_chan <=3) {
        !           301:         if (count > 65536)
        !           302:             count = 65536;
        !           303:         limit = 65536 - (((unsigned) ptr) & 0xFFFF);
        !           304:     } else {
        !           305:         if (count > (65536<<1)) 
        !           306:             count = (65536<<1);
        !           307:         limit = (65536<<1) - (((unsigned) ptr) & 0x1FFFF);
        !           308:     }
        !           309:     
        !           310:     if (count > limit) count = limit;
        !           311:     
        !           312:     VDEB(printk("after count=%d\n", count));
        !           313:     if ((count & 1) || (((unsigned) ptr) & 1))
        !           314:         panic ("NCR53c406a: attempted unaligned DMA transfer\n"); 
        !           315:     
        !           316:     save_flags(flags);
        !           317:     cli();
        !           318:     disable_dma(dma_chan);
        !           319:     clear_dma_ff(dma_chan);
        !           320:     set_dma_addr(dma_chan, (long) ptr);
        !           321:     set_dma_count(dma_chan, count);
        !           322:     set_dma_mode(dma_chan, mode);
        !           323:     enable_dma(dma_chan);
        !           324:     restore_flags(flags);
        !           325:     
        !           326:     return count;
        !           327: }
        !           328: 
        !           329: static __inline__ int 
        !           330: NCR53c406a_dma_write(unsigned char *src, unsigned int count) {
        !           331:     return NCR53c406a_dma_setup (src, count, DMA_MODE_WRITE);
        !           332: }
        !           333: 
        !           334: static __inline__ int 
        !           335: NCR53c406a_dma_read(unsigned char *src, unsigned int count) {
        !           336:     return NCR53c406a_dma_setup (src, count, DMA_MODE_READ);
        !           337: }
        !           338: 
        !           339: static __inline__ int 
        !           340: NCR53c406a_dma_residual (void) {
        !           341:     register int tmp;
        !           342:     unsigned long flags = 0;
        !           343:     save_flags(flags);
        !           344:     cli();
        !           345:     clear_dma_ff(dma_chan);
        !           346:     tmp = get_dma_residue(dma_chan);
        !           347:     restore_flags(flags);
        !           348:     
        !           349:     return tmp;
        !           350: }
        !           351: #endif USE_DMA
        !           352: 
        !           353: #if USE_PIO
        !           354: static __inline__ int NCR53c406a_pio_read(unsigned char *request, 
        !           355:                                          unsigned int reqlen) 
        !           356: {
        !           357:     int        i;
        !           358:     int        len;    /* current scsi fifo size */
        !           359:     unsigned long flags = 0;
        !           360:     
        !           361:     REG1;
        !           362:     while (reqlen) {
        !           363:         i = inb(PIO_STATUS);
        !           364:         /*    VDEB(printk("pio_status=%x\n", i)); */
        !           365:         if (i & 0x80) 
        !           366:             return 0;
        !           367:         
        !           368:         switch( i & 0x1e ) {
        !           369:         default:
        !           370:         case 0x10:
        !           371:             len=0; break;
        !           372:         case 0x0:
        !           373:             len=1; break;
        !           374:         case 0x8:
        !           375:             len=42; break;
        !           376:         case 0xc:
        !           377:             len=84; break;
        !           378:         case 0xe:
        !           379:             len=128; break;
        !           380:         }
        !           381:         
        !           382:         if ((i & 0x40) && len == 0) { /* fifo empty and interrupt occurred */
        !           383:             return 0;
        !           384:         }
        !           385:         
        !           386:         if (len) {
        !           387:             if( len > reqlen ) 
        !           388:                 len = reqlen;
        !           389:             
        !           390:             save_flags(flags);
        !           391:             cli();
        !           392:             if( fast_pio && len > 3 ) { 
        !           393:                 insl(PIO_FIFO,request,len>>2); 
        !           394:                 request += len & 0xfc; 
        !           395:                 reqlen -= len & 0xfc; 
        !           396:             } 
        !           397:             else { 
        !           398:                 while(len--) {
        !           399:                     *request++ = inb(PIO_FIFO);
        !           400:                     reqlen--;
        !           401:                 }
        !           402:             }
        !           403:             restore_flags(flags);
        !           404:         }
        !           405:     }
        !           406:     return 0;
        !           407: }
        !           408: 
        !           409: static __inline__ int NCR53c406a_pio_write(unsigned char *request,
        !           410:                                           unsigned int reqlen) 
        !           411: {
        !           412:     int        i = 0;
        !           413:     int        len;    /* current scsi fifo size */
        !           414:     unsigned long flags = 0;
        !           415:     
        !           416:     REG1;
        !           417:     while (reqlen && !(i&0x40)) {
        !           418:         i = inb(PIO_STATUS);
        !           419:         /*    VDEB(printk("pio_status=%x\n", i)); */
        !           420:         if (i & 0x80)          /* error */
        !           421:             return 0;
        !           422:         
        !           423:         switch( i & 0x1e ) {
        !           424:         case 0x10:
        !           425:             len=128; break;
        !           426:         case 0x0:
        !           427:             len=84; break;
        !           428:         case 0x8:
        !           429:             len=42; break;
        !           430:         case 0xc:
        !           431:             len=1; break;
        !           432:         default:
        !           433:         case 0xe:
        !           434:             len=0; break;
        !           435:         }
        !           436:         
        !           437:         if (len) {
        !           438:             if( len > reqlen ) 
        !           439:                 len = reqlen;
        !           440:             
        !           441:             save_flags(flags);
        !           442:             cli();
        !           443:             if( fast_pio && len > 3 ) { 
        !           444:                 outsl(PIO_FIFO,request,len>>2); 
        !           445:                 request += len & 0xfc; 
        !           446:                 reqlen -= len & 0xfc; 
        !           447:             } 
        !           448:             else { 
        !           449:                 while(len--) {
        !           450:                     outb(*request++, PIO_FIFO);
        !           451:                     reqlen--;
        !           452:                 }
        !           453:             }
        !           454:             restore_flags(flags);
        !           455:         }
        !           456:     }
        !           457:     return 0;
        !           458: }
        !           459: #endif USE_PIO
        !           460: 
        !           461: int 
        !           462: NCR53c406a_detect(Scsi_Host_Template * tpnt){
        !           463:     struct Scsi_Host *shpnt;
        !           464: #ifndef PORT_BASE
        !           465:     int i;
        !           466: #endif
        !           467:     
        !           468: #if USE_BIOS
        !           469:     int ii, jj;
        !           470:     bios_base = 0;
        !           471:     /* look for a valid signature */
        !           472:     for( ii=0; ii < ADDRESS_COUNT && !bios_base; ii++)
        !           473:         for( jj=0; (jj < SIGNATURE_COUNT) && !bios_base; jj++)
        !           474:             if(!memcmp((void *) addresses[ii]+signatures[jj].sig_offset,
        !           475:                        (void *) signatures[jj].signature,
        !           476:                        (int) signatures[jj].sig_length))
        !           477:                 bios_base=addresses[ii];
        !           478:     
        !           479:     if(!bios_base){
        !           480:         printk("NCR53c406a: BIOS signature not found\n");
        !           481:         return 0;
        !           482:     }
        !           483:     
        !           484:     DEB(printk("NCR53c406a BIOS found at %X\n", (unsigned int) bios_base););
        !           485: #endif USE_BIOS
        !           486:     
        !           487: #ifdef PORT_BASE
        !           488:     if (check_region(port_base, 0x10)) /* ports already snatched */
        !           489:         port_base = 0;
        !           490:     
        !           491: #else  /* autodetect */
        !           492:     if (port_base) {           /* LILO override */
        !           493:         if (check_region(port_base, 0x10))
        !           494:             port_base = 0;
        !           495:     }
        !           496:     else {
        !           497:         for(i=0;  i<PORT_COUNT && !port_base; i++){
        !           498:             if(check_region(ports[i], 0x10)){
        !           499:                 DEB(printk("NCR53c406a: port %x in use\n", ports[i]));
        !           500:             }
        !           501:             else {
        !           502:                 VDEB(printk("NCR53c406a: port %x available\n", ports[i]));
        !           503:                 outb(C5_IMG, ports[i] + 0x0d); /* reg set 1 */
        !           504:                 if(   (inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7
        !           505:                    && (inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7
        !           506:                    && (inb(ports[i] + 0x0e) & 0xf8) == 0x58 ) {
        !           507:                     VDEB(printk("NCR53c406a: Sig register valid\n"));
        !           508:                     VDEB(printk("port_base=%x\n", port_base));
        !           509:                     port_base = ports[i];
        !           510:                 }
        !           511:             }
        !           512:         }
        !           513:     }
        !           514: #endif PORT_BASE
        !           515:     
        !           516:     if(!port_base){            /* no ports found */
        !           517:         printk("NCR53c406a: no available ports found\n");
        !           518:         return 0;
        !           519:     }
        !           520:     
        !           521:     DEB(printk("NCR53c406a detected\n"));
        !           522:     
        !           523:     calc_port_addr();
        !           524:     chip_init();
        !           525:     
        !           526: #ifndef IRQ_LEV
        !           527:     if (irq_level < 0) {               /* LILO override if >= 0*/
        !           528:         irq_level=irq_probe();
        !           529:         if (irq_level < 0) {           /* Trouble */
        !           530:             printk("NCR53c406a: IRQ problem, irq_level=%d, giving up\n", irq_level);
        !           531:             return 0;
        !           532:         }
        !           533:     }
        !           534: #endif
        !           535:     
        !           536:     DEB(printk("NCR53c406a: using port_base %x\n", port_base));
        !           537:     request_region(port_base, 0x10, "NCR53c406a");
        !           538:     
        !           539:     if(irq_level > 0) {
        !           540:         if(request_irq(irq_level, NCR53c406a_intr, 0, "NCR53c406a", NULL)){
        !           541:             printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level);
        !           542:             return 0;
        !           543:         }
        !           544:         tpnt->can_queue = 1;
        !           545:         DEB(printk("NCR53c406a: allocated IRQ %d\n", irq_level));
        !           546:     }
        !           547:     else if (irq_level == 0) {
        !           548:         tpnt->can_queue = 0;
        !           549:         DEB(printk("NCR53c406a: No interrupts detected\n"));
        !           550: #if USE_DMA
        !           551:         printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n");
        !           552:         return 0;
        !           553: #endif USE_DMA
        !           554:     }
        !           555:     else {
        !           556:         DEB(printk("NCR53c406a: Shouldn't get here!\n"));
        !           557:         return 0;
        !           558:     }
        !           559:     
        !           560: #if USE_DMA
        !           561:     dma_chan = DMA_CHAN;
        !           562:     if(request_dma(dma_chan, "NCR53c406a") != 0){
        !           563:         printk("NCR53c406a: unable to allocate DMA channel %d\n", dma_chan);
        !           564:         return 0;
        !           565:     }
        !           566:     
        !           567:     DEB(printk("Allocated DMA channel %d\n", dma_chan));
        !           568: #endif USE_DMA 
        !           569:     
        !           570:     tpnt->present = 1;
        !           571:     tpnt->proc_dir = &proc_scsi_NCR53c406a;
        !           572:     
        !           573:     shpnt = scsi_register(tpnt, 0);
        !           574:     shpnt->irq = irq_level;
        !           575:     shpnt->io_port = port_base;
        !           576:     shpnt->n_io_port = 0x10;
        !           577: #if USE_DMA
        !           578:     shpnt->dma = dma_chan;
        !           579: #endif
        !           580:     
        !           581: #if USE_DMA
        !           582:     sprintf(info_msg, "NCR53c406a at 0x%x, IRQ %d, DMA channel %d.", 
        !           583:             port_base, irq_level, dma_chan);
        !           584: #else
        !           585:     sprintf(info_msg, "NCR53c406a at 0x%x, IRQ %d, %s PIO mode.", 
        !           586:             port_base, irq_level, fast_pio ? "fast" : "slow");
        !           587: #endif
        !           588:     
        !           589:     return (tpnt->present);
        !           590: }
        !           591: 
        !           592: /* called from init/main.c */
        !           593: void NCR53c406a_setup(char *str, int *ints)
        !           594: {
        !           595:     static size_t setup_idx = 0;
        !           596:     size_t i;
        !           597:     
        !           598:     DEB(printk("NCR53c406a: Setup called\n"););
        !           599:     
        !           600:     if (setup_idx >= PORT_COUNT - 1) {
        !           601:         printk("NCR53c406a: Setup called too many times.  Bad LILO params?\n");
        !           602:         return;
        !           603:     }
        !           604:     if (ints[0] < 1 || ints[0] > 3) {
        !           605:         printk("NCR53c406a: Malformed command line\n");
        !           606:         printk("NCR53c406a: Usage: ncr53c406a=<PORTBASE>[,<IRQ>[,<FASTPIO>]]\n");
        !           607:         return;
        !           608:     }
        !           609:     for (i = 0; i < PORT_COUNT && !port_base; i++)
        !           610:         if (ports[i] == ints[1]) {
        !           611:             port_base = ints[1];
        !           612:             DEB(printk("NCR53c406a: Specified port_base 0x%X\n", port_base);)
        !           613:         }
        !           614:     if (!port_base) {
        !           615:         printk("NCR53c406a: Invalid PORTBASE 0x%X specified\n", ints[1]);
        !           616:         return;
        !           617:     }
        !           618:     
        !           619:     if (ints[0] > 1) {
        !           620:         if (ints[2] == 0) {
        !           621:             irq_level = 0;
        !           622:             DEB(printk("NCR53c406a: Specified irq %d\n", irq_level);)
        !           623:         }
        !           624:         else
        !           625:             for (i = 0; i < INTR_COUNT && irq_level < 0; i++)
        !           626:                 if (intrs[i] == ints[2]) {
        !           627:                     irq_level = ints[2];
        !           628:                     DEB(printk("NCR53c406a: Specified irq %d\n", port_base);)
        !           629:                 }
        !           630:         if (irq_level < 0)
        !           631:             printk("NCR53c406a: Invalid IRQ %d specified\n", ints[2]);
        !           632:     }
        !           633:     
        !           634:     if (ints[0] > 2)
        !           635:         fast_pio = ints[3];
        !           636:     
        !           637:     DEB(printk("NCR53c406a: port_base=0x%X, irq=%d, fast_pio=%d\n", 
        !           638:                port_base, irq_level, fast_pio);)
        !           639: }
        !           640: 
        !           641: const char* 
        !           642: NCR53c406a_info(struct Scsi_Host *SChost){
        !           643:     DEB(printk("NCR53c406a_info called\n"));
        !           644:     return (info_msg);
        !           645: }
        !           646: 
        !           647: static void internal_done(Scsi_Cmnd *SCpnt) {
        !           648:     internal_done_errcode = SCpnt->result;
        !           649:     ++internal_done_flag;
        !           650: }
        !           651: 
        !           652: 
        !           653: static void wait_intr() {
        !           654:     int i = jiffies + WATCHDOG;
        !           655:     
        !           656:     while(i>jiffies && !(inb(STAT_REG)&0xe0)) /* wait for a pseudo-interrupt */
        !           657:         barrier();
        !           658:     
        !           659:     if (i <= jiffies) {                /* Timed out */
        !           660:         rtrc(0);
        !           661:         current_SC->result = DID_TIME_OUT << 16;
        !           662:         current_SC->SCp.phase = idle;
        !           663:         current_SC->scsi_done(current_SC);
        !           664:         return;
        !           665:     }
        !           666:     
        !           667:     NCR53c406a_intr(0, NULL, NULL);
        !           668: }
        !           669: 
        !           670: int NCR53c406a_command(Scsi_Cmnd *SCpnt){
        !           671:     DEB(printk("NCR53c406a_command called\n"));
        !           672:     NCR53c406a_queue(SCpnt, internal_done);
        !           673:     if(irq_level)
        !           674:         while (!internal_done_flag);
        !           675:     else                        /* interrupts not supported */
        !           676:         while (!internal_done_flag)
        !           677:             wait_intr();
        !           678:     
        !           679:     internal_done_flag = 0;
        !           680:     return internal_done_errcode;
        !           681: }
        !           682: 
        !           683: 
        !           684: int 
        !           685: NCR53c406a_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){
        !           686:     int i;
        !           687:     unsigned long flags = 0;
        !           688: 
        !           689:     VDEB(printk("NCR53c406a_queue called\n"));
        !           690:     DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", 
        !           691:                SCpnt->cmnd[0],
        !           692:                SCpnt->cmd_len,
        !           693:                SCpnt->target, 
        !           694:                SCpnt->lun,  
        !           695:                SCpnt->request_bufflen));
        !           696:     
        !           697: #if 0
        !           698:     VDEB(for(i=0; i<SCpnt->cmd_len; i++)
        !           699:          printk("cmd[%d]=%02x  ", i, SCpnt->cmnd[i]));
        !           700:     VDEB(printk("\n"));
        !           701: #endif
        !           702:     
        !           703:     current_SC = SCpnt;
        !           704:     current_SC->scsi_done = done;
        !           705:     current_SC->SCp.phase = command_ph;
        !           706:     current_SC->SCp.Status = 0;
        !           707:     current_SC->SCp.Message = 0;
        !           708:     
        !           709:     save_flags(flags);
        !           710:     cli();
        !           711:     REG0;
        !           712:     outb(SCpnt->target, DEST_ID); /* set destination */
        !           713:     outb(FLUSH_FIFO, CMD_REG); /* reset the fifos */
        !           714:     
        !           715:     for(i=0; i<SCpnt->cmd_len; i++){
        !           716:         outb(SCpnt->cmnd[i], SCSI_FIFO);
        !           717:     }
        !           718:     outb(SELECT_NO_ATN, CMD_REG);
        !           719:     restore_flags(flags);
        !           720:     
        !           721:     rtrc(1);
        !           722:     return 0;
        !           723: }
        !           724: 
        !           725: int
        !           726: NCR53c406a_abort(Scsi_Cmnd *SCpnt){
        !           727:     DEB(printk("NCR53c406a_abort called\n"));
        !           728:     return SCSI_ABORT_SNOOZE;  /* Don't know how to abort */
        !           729: }
        !           730: 
        !           731: int 
        !           732: NCR53c406a_reset(Scsi_Cmnd *SCpnt, unsigned int flags){
        !           733:     DEB(printk("NCR53c406a_reset called\n"));
        !           734:     outb(C4_IMG, CONFIG4);      /* Select reg set 0 */
        !           735:     outb(CHIP_RESET, CMD_REG);
        !           736:     outb(SCSI_NOP, CMD_REG);   /* required after reset */
        !           737:     outb(SCSI_RESET, CMD_REG);
        !           738:     chip_init();
        !           739:     
        !           740:     rtrc(2);
        !           741:     if (irq_level)
        !           742:         return SCSI_RESET_PENDING; /* should get an interrupt */
        !           743:     else
        !           744:         return SCSI_RESET_WAKEUP; /* won't get any interrupts */
        !           745: }
        !           746: 
        !           747: int 
        !           748: NCR53c406a_biosparm(Scsi_Disk *disk, kdev_t dev, int* info_array){
        !           749:     int size;
        !           750:     
        !           751:     DEB(printk("NCR53c406a_biosparm called\n"));
        !           752:     
        !           753:     size = disk->capacity;
        !           754:     info_array[0] = 64;         /* heads */
        !           755:     info_array[1] = 32;         /* sectors */
        !           756:     info_array[2] = size>>11;   /* cylinders */
        !           757:     if (info_array[2] > 1024) {        /* big disk */
        !           758:       info_array[0] = 255;
        !           759:       info_array[1] = 63;
        !           760:       info_array[2] = size / (255*63);
        !           761:     }
        !           762:     return 0;
        !           763:   }
        !           764:      
        !           765:      static void
        !           766: NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs){
        !           767:     DEB(unsigned char fifo_size;)
        !           768:     DEB(unsigned char seq_reg;)
        !           769:     unsigned char status, int_reg;
        !           770:     unsigned long flags = 0;
        !           771: #if USE_PIO
        !           772:     unsigned char pio_status; 
        !           773:     struct scatterlist *sglist;
        !           774:     unsigned int sgcount;
        !           775: #endif
        !           776:     
        !           777:     VDEB(printk("NCR53c406a_intr called\n"));
        !           778:     
        !           779:     save_flags(flags);
        !           780:     cli();
        !           781: #if USE_PIO
        !           782:     REG1;
        !           783:     pio_status = inb(PIO_STATUS);
        !           784: #endif
        !           785:     REG0;
        !           786:     status = inb(STAT_REG);
        !           787:     DEB(seq_reg = inb(SEQ_REG));
        !           788:     int_reg = inb(INT_REG);
        !           789:     DEB(fifo_size = inb(FIFO_FLAGS) & 0x1f);
        !           790:     restore_flags(flags);
        !           791:     
        !           792: #if NCR53C406A_DEBUG
        !           793:     printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x", 
        !           794:            status, seq_reg, int_reg, fifo_size);
        !           795: #if (USE_DMA)
        !           796:     printk("\n");
        !           797: #else
        !           798:     printk(", pio=%02x\n", pio_status);
        !           799: #endif USE_DMA
        !           800: #endif NCR53C406A_DEBUG
        !           801:     
        !           802:     if(int_reg & 0x80){         /* SCSI reset intr */
        !           803:         rtrc(3);
        !           804:         DEB(printk("NCR53c406a: reset intr received\n"));
        !           805:         current_SC->SCp.phase = idle;
        !           806:         current_SC->result = DID_RESET << 16;
        !           807:         current_SC->scsi_done(current_SC);
        !           808:         return;
        !           809:     }
        !           810:     
        !           811: #if USE_PIO
        !           812:     if(pio_status & 0x80) {
        !           813:         printk("NCR53C406A: Warning: PIO error!\n");
        !           814:         current_SC->SCp.phase = idle;
        !           815:         current_SC->result = DID_ERROR << 16;
        !           816:         current_SC->scsi_done(current_SC);
        !           817:         return;
        !           818:     }
        !           819: #endif USE_PIO
        !           820:     
        !           821:     if(status & 0x20) {                /* Parity error */
        !           822:         printk("NCR53c406a: Warning: parity error!\n");
        !           823:         current_SC->SCp.phase = idle;
        !           824:         current_SC->result = DID_PARITY << 16;
        !           825:         current_SC->scsi_done(current_SC);
        !           826:         return;
        !           827:     }
        !           828:     
        !           829:     if(status & 0x40) {                /* Gross error */
        !           830:         printk("NCR53c406a: Warning: gross error!\n");
        !           831:         current_SC->SCp.phase = idle;
        !           832:         current_SC->result = DID_ERROR << 16;
        !           833:         current_SC->scsi_done(current_SC);
        !           834:         return;
        !           835:     }
        !           836:     
        !           837:     if(int_reg & 0x20){                /* Disconnect */
        !           838:         DEB(printk("NCR53c406a: disconnect intr received\n"));
        !           839:         if(current_SC->SCp.phase != message_in){ /* Unexpected disconnect */
        !           840:             current_SC->result = DID_NO_CONNECT << 16;
        !           841:         }
        !           842:         else{  /* Command complete, return status and message */
        !           843:             current_SC->result = (current_SC->SCp.Status & 0xff) 
        !           844:                 | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16);
        !           845:         }
        !           846:         
        !           847:         rtrc(0);
        !           848:         current_SC->SCp.phase = idle;
        !           849:         current_SC->scsi_done( current_SC );
        !           850:         return;
        !           851:     }
        !           852:     
        !           853:     switch(status & 0x07){     /* scsi phase */
        !           854:     case 0x00:                 /* DATA-OUT */
        !           855:         if(int_reg & 0x10){     /* Target requesting info transfer */
        !           856:             rtrc(5);
        !           857:             current_SC->SCp.phase = data_out;
        !           858:             VDEB(printk("NCR53c406a: Data-Out phase\n"));
        !           859:             outb(FLUSH_FIFO, CMD_REG);
        !           860:             LOAD_DMA_COUNT(current_SC->request_bufflen); /* Max transfer size */
        !           861: #if USE_DMA                    /* No s/g support for DMA */
        !           862:             NCR53c406a_dma_write(current_SC->request_buffer, 
        !           863:                                  current_SC->request_bufflen);
        !           864: #endif USE_DMA
        !           865:             outb(TRANSFER_INFO | DMA_OP, CMD_REG); 
        !           866: #if USE_PIO
        !           867:             if (!current_SC->use_sg) /* Don't use scatter-gather */
        !           868:                 NCR53c406a_pio_write(current_SC->request_buffer, 
        !           869:                                      current_SC->request_bufflen);
        !           870:             else {              /* use scatter-gather */
        !           871:                 sgcount = current_SC->use_sg;
        !           872:                 sglist = current_SC->request_buffer;
        !           873:                 while( sgcount-- ) {
        !           874:                     NCR53c406a_pio_write(sglist->address, sglist->length);
        !           875:                     sglist++;
        !           876:                 }
        !           877:             }
        !           878:             REG0;
        !           879: #endif USE_PIO
        !           880:         }
        !           881:         break;
        !           882:         
        !           883:     case 0x01:                 /* DATA-IN */
        !           884:         if(int_reg & 0x10){     /* Target requesting info transfer */
        !           885:             rtrc(6);
        !           886:             current_SC->SCp.phase = data_in;
        !           887:             VDEB(printk("NCR53c406a: Data-In phase\n"));
        !           888:             outb(FLUSH_FIFO, CMD_REG);
        !           889:             LOAD_DMA_COUNT(current_SC->request_bufflen); /* Max transfer size */
        !           890: #if USE_DMA                    /* No s/g support for DMA */
        !           891:             NCR53c406a_dma_read(current_SC->request_buffer, 
        !           892:                                 current_SC->request_bufflen);
        !           893: #endif USE_DMA
        !           894:             outb(TRANSFER_INFO | DMA_OP, CMD_REG); 
        !           895: #if USE_PIO
        !           896:             if (!current_SC->use_sg) /* Don't use scatter-gather */
        !           897:                 NCR53c406a_pio_read(current_SC->request_buffer, 
        !           898:                                     current_SC->request_bufflen);
        !           899:             else {              /* Use scatter-gather */
        !           900:                 sgcount = current_SC->use_sg;
        !           901:                 sglist = current_SC->request_buffer;
        !           902:                 while( sgcount-- ) {
        !           903:                     NCR53c406a_pio_read(sglist->address, sglist->length);
        !           904:                     sglist++;
        !           905:                 }
        !           906:             }
        !           907:             REG0;
        !           908: #endif USE_PIO
        !           909:         }
        !           910:         break;
        !           911:         
        !           912:     case 0x02:                 /* COMMAND */
        !           913:         current_SC->SCp.phase = command_ph;
        !           914:         printk("NCR53c406a: Warning: Unknown interrupt occurred in command phase!\n");
        !           915:         break;
        !           916:         
        !           917:     case 0x03:                 /* STATUS */
        !           918:         rtrc(7);
        !           919:         current_SC->SCp.phase = status_ph;
        !           920:         VDEB(printk("NCR53c406a: Status phase\n"));
        !           921:         outb(FLUSH_FIFO, CMD_REG);
        !           922:         outb(INIT_CMD_COMPLETE, CMD_REG);
        !           923:         break;
        !           924:         
        !           925:     case 0x04:                 /* Reserved */
        !           926:     case 0x05:                 /* Reserved */
        !           927:         printk("NCR53c406a: WARNING: Reserved phase!!!\n");
        !           928:         break;
        !           929:         
        !           930:     case 0x06:                 /* MESSAGE-OUT */
        !           931:         DEB(printk("NCR53c406a: Message-Out phase\n"));
        !           932:         current_SC->SCp.phase = message_out;
        !           933:         outb(SET_ATN, CMD_REG);        /* Reject the message */
        !           934:         outb(MSG_ACCEPT, CMD_REG);
        !           935:         break;
        !           936:         
        !           937:     case 0x07:                 /* MESSAGE-IN */
        !           938:         rtrc(4);
        !           939:         VDEB(printk("NCR53c406a: Message-In phase\n"));
        !           940:         current_SC->SCp.phase = message_in;
        !           941:         
        !           942:         current_SC->SCp.Status = inb(SCSI_FIFO);    
        !           943:         current_SC->SCp.Message = inb(SCSI_FIFO);
        !           944:         
        !           945:         VDEB(printk("SCSI FIFO size=%d\n", inb(FIFO_FLAGS) & 0x1f));
        !           946:         DEB(printk("Status = %02x  Message = %02x\n", 
        !           947:                    current_SC->SCp.Status, current_SC->SCp.Message));
        !           948:         
        !           949:         if(current_SC->SCp.Message == SAVE_POINTERS || 
        !           950:            current_SC->SCp.Message == DISCONNECT) {
        !           951:             outb(SET_ATN, CMD_REG); /* Reject message */
        !           952:             DEB(printk("Discarding SAVE_POINTERS message\n"));
        !           953:         }
        !           954:         outb(MSG_ACCEPT, CMD_REG);
        !           955:         break;
        !           956:     }
        !           957: }
        !           958: 
        !           959: #ifndef IRQ_LEV
        !           960: static int irq_probe()
        !           961: {
        !           962:     int irqs, irq;
        !           963:     int i;
        !           964:     
        !           965:     inb(INT_REG);               /* clear the interrupt register */
        !           966:     sti();
        !           967:     irqs = probe_irq_on();
        !           968:     
        !           969:     /* Invalid command will cause an interrupt */
        !           970:     REG0;
        !           971:     outb(0xff, CMD_REG);
        !           972:     
        !           973:     /* Wait for the interrupt to occur */
        !           974:     i = jiffies + WATCHDOG;
        !           975:     while(i > jiffies && !(inb(STAT_REG) & 0x80))
        !           976:         barrier();
        !           977:     if (i <= jiffies) {                /* Timed out, must be hardware trouble */
        !           978:         probe_irq_off(irqs);
        !           979:         return -1;
        !           980:     }
        !           981:     
        !           982:     irq = probe_irq_off(irqs);
        !           983:     
        !           984:     /* Kick the chip */
        !           985:     outb(CHIP_RESET, CMD_REG);
        !           986:     outb(SCSI_NOP, CMD_REG);
        !           987:     chip_init();
        !           988:     
        !           989:     return irq;
        !           990: }
        !           991: #endif IRQ_LEV
        !           992: 
        !           993: static void chip_init()
        !           994: {
        !           995:     REG1;
        !           996: #if USE_DMA
        !           997:     outb(0x00, PIO_STATUS);
        !           998: #else  /* USE_PIO */
        !           999:     outb(0x01, PIO_STATUS);
        !          1000: #endif
        !          1001:     outb(0x00, PIO_FLAG);
        !          1002:     
        !          1003:     outb(C4_IMG, CONFIG4);     /* REG0; */
        !          1004:     outb(C3_IMG, CONFIG3);
        !          1005:     outb(C2_IMG, CONFIG2);
        !          1006:     outb(C1_IMG, CONFIG1);
        !          1007:     
        !          1008:     outb(0x05, CLKCONV);        /* clock conversion factor */
        !          1009:     outb(0x9C, SRTIMOUT);       /* Selection timeout */
        !          1010:     outb(0x05, SYNCPRD);        /* Synchronous transfer period */
        !          1011:     outb(SYNC_MODE, SYNCOFF);   /* synchronous mode */  
        !          1012: }
        !          1013: 
        !          1014: void calc_port_addr()
        !          1015: {
        !          1016:     /* Control Register Set 0 */
        !          1017:     TC_LSB             = (port_base+0x00);
        !          1018:     TC_MSB             = (port_base+0x01);
        !          1019:     SCSI_FIFO          = (port_base+0x02);
        !          1020:     CMD_REG            = (port_base+0x03);
        !          1021:     STAT_REG           = (port_base+0x04);
        !          1022:     DEST_ID            = (port_base+0x04);
        !          1023:     INT_REG            = (port_base+0x05);
        !          1024:     SRTIMOUT           = (port_base+0x05);
        !          1025:     SEQ_REG            = (port_base+0x06);
        !          1026:     SYNCPRD            = (port_base+0x06);
        !          1027:     FIFO_FLAGS         = (port_base+0x07);
        !          1028:     SYNCOFF            = (port_base+0x07);
        !          1029:     CONFIG1            = (port_base+0x08);
        !          1030:     CLKCONV            = (port_base+0x09);
        !          1031:     /* TESTREG         = (port_base+0x0A); */
        !          1032:     CONFIG2            = (port_base+0x0B);
        !          1033:     CONFIG3            = (port_base+0x0C);
        !          1034:     CONFIG4            = (port_base+0x0D);
        !          1035:     TC_HIGH            = (port_base+0x0E);
        !          1036:     /* FIFO_BOTTOM     = (port_base+0x0F); */
        !          1037:     
        !          1038:     /* Control Register Set 1 */
        !          1039:     /* JUMPER_SENSE    = (port_base+0x00);*/
        !          1040:     /* SRAM_PTR                = (port_base+0x01);*/
        !          1041:     /* SRAM_DATA       = (port_base+0x02);*/
        !          1042:     PIO_FIFO           = (port_base+0x04);
        !          1043:     /* PIO_FIFO1       = (port_base+0x05);*/
        !          1044:     /* PIO_FIFO2       = (port_base+0x06);*/
        !          1045:     /* PIO_FIFO3       = (port_base+0x07);*/
        !          1046:     PIO_STATUS         = (port_base+0x08);
        !          1047:     /* ATA_CMD         = (port_base+0x09);*/
        !          1048:     /* ATA_ERR         = (port_base+0x0A);*/
        !          1049:     PIO_FLAG           = (port_base+0x0B);
        !          1050:     CONFIG5            = (port_base+0x0D);
        !          1051:     /* SIGNATURE       = (port_base+0x0E);*/
        !          1052:     /* CONFIG6         = (port_base+0x0F);*/
        !          1053: }
        !          1054: 
        !          1055: #ifdef MODULE
        !          1056: /* Eventually this will go into an include file, but this will be later */
        !          1057: Scsi_Host_Template driver_template = NCR53c406a;
        !          1058: 
        !          1059: #include "scsi_module.c"
        !          1060: #endif
        !          1061: 
        !          1062: /*
        !          1063:  * Overrides for Emacs so that we get a uniform tabbing style.
        !          1064:  * Emacs will notice this stuff at the end of the file and automatically
        !          1065:  * adjust the settings for this buffer only.  This must remain at the end
        !          1066:  * of the file.
        !          1067:  * ---------------------------------------------------------------------------
        !          1068:  * Local variables:
        !          1069:  * c-indent-level: 4
        !          1070:  * c-brace-imaginary-offset: 0
        !          1071:  * c-brace-offset: -4
        !          1072:  * c-argdecl-indent: 4
        !          1073:  * c-label-offset: -4
        !          1074:  * c-continued-statement-offset: 4
        !          1075:  * c-continued-brace-offset: 0
        !          1076:  * indent-tabs-mode: nil
        !          1077:  * tab-width: 8
        !          1078:  * End:
        !          1079:  */

unix.superglobalmegacorp.com

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