Annotation of kernel/bsd/dev/ppc/drvBMacEnet/BMacEnet.m, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:  * Copyright (c) 1998-1999 by Apple Computer, Inc., All rights reserved.
                     27:  *
                     28:  * Hardware independent (relatively) code for the BMac Ethernet Controller 
                     29:  *
                     30:  * HISTORY
                     31:  *
                     32:  * dd-mmm-yy    
                     33:  *     Created.
                     34:  *
                     35:  */
                     36: 
                     37: #import "BMacEnetPrivate.h"
                     38: 
                     39: @implementation BMacEnet
                     40: 
                     41: /*
                     42:  * Public Factory Methods
                     43:  */
                     44:  
                     45: + (BOOL)probe:(IOTreeDevice *)devDesc
                     46: {
                     47:     BMacEnet           *BMacEnetInstance;
                     48: 
                     49:     BMacEnetInstance = [self alloc];
                     50:     return [BMacEnetInstance initFromDeviceDescription:devDesc] != nil;
                     51: }
                     52: 
                     53: /*
                     54:  * Public Instance Methods
                     55:  */
                     56: 
                     57: /*-------------------------------------------------------------------------
                     58:  *
                     59:  *
                     60:  *
                     61:  *-------------------------------------------------------------------------*/
                     62: 
                     63: - initFromDeviceDescription:(IOTreeDevice *)devDesc
                     64: {
                     65:     IOTreeDevice       *devDescHeathrow;
                     66:     IORange            *ioRangeBMac;
                     67:     IORange            *ioRangeHeathrow;
                     68:     
                     69:     if ([super initFromDeviceDescription:devDesc] == nil)     
                     70:     {
                     71:       IOLog( "Ethernet(BMac): [super initFromDeviceDescription] failed\n");
                     72:       return nil;
                     73:     }
                     74: 
                     75:     if ( [devDesc numMemoryRanges] < 3 )
                     76:     {
                     77:       IOLog( "Ethernet(BMac): Incorrect deviceDescription - 1\n\r");
                     78:       return nil;
                     79:     }
                     80: 
                     81:     ioRangeBMac = [devDesc memoryRangeList];
                     82: 
                     83:     ioBaseEnet      = (IOPPCAddress) ioRangeBMac[0].start;
                     84:     ioBaseEnetTxDMA = (IOPPCAddress) ioRangeBMac[1].start;
                     85:     ioBaseEnetRxDMA = (IOPPCAddress) ioRangeBMac[2].start;
                     86: 
                     87:     devDescHeathrow = [[devDesc parent] deviceDescription];
                     88:   
                     89:     if ( [devDescHeathrow numMemoryRanges] < 1 )
                     90:     {  
                     91:       IOLog( "Ethernet(BMac): Incorrect deviceDescription - 2\n\r");
                     92:       return nil;
                     93:     } 
                     94: 
                     95:     ioRangeHeathrow = [devDescHeathrow memoryRangeList];
                     96: 
                     97:     ioBaseHeathrow  = (IOPPCAddress) ioRangeHeathrow[0].start;
                     98: 
                     99:     sromAddressBits   = 6;
                    100:     enetAddressOffset = 20;
                    101:     phyId             = -1;
                    102:     phyMIIDelay              = MII_DEFAULT_DELAY;
                    103: 
                    104:     if ( ![self resetAndEnable:NO] ) 
                    105:     {
                    106:       [self free];
                    107:       return nil;
                    108:     }
                    109: 
                    110:     [self _getStationAddress:&myAddress]; 
                    111: 
                    112:     if ([self _allocateMemory] == NO) 
                    113:     {
                    114:       [self free];
                    115:       return nil;
                    116:     }
                    117: 
                    118:     if ( ![self resetAndEnable:YES] ) 
                    119:     {
                    120:       [self free];
                    121:       return nil;
                    122:     }
                    123: 
                    124:     isPromiscuous = NO;
                    125:     multicastEnabled = NO;
                    126: 
                    127:     networkInterface = [super attachToNetworkWithAddress:myAddress];
                    128: 
                    129:     [networkInterface getIONetworkIfnet]->if_eflags |= IFEF_DVR_REENTRY_OK;
                    130: 
                    131:     return self;
                    132: }
                    133: 
                    134: /*-------------------------------------------------------------------------
                    135:  *
                    136:  *
                    137:  *
                    138:  *-------------------------------------------------------------------------*/
                    139: 
                    140: - free
                    141: {
                    142:     int                i;
                    143:     
                    144:     [self clearTimeout];
                    145:     
                    146:     [self _resetChip];
                    147:     
                    148:     if (networkInterface)
                    149:        [networkInterface free];
                    150: 
                    151:     for (i = 0; i < rxMaxCommand; i++)
                    152:        if (rxNetbuf[i])  nb_free(rxNetbuf[i]);
                    153: 
                    154:     for (i = 0; i < txMaxCommand; i++)
                    155:        if (txNetbuf[i]) nb_free(txNetbuf[i]);
                    156:     
                    157:     return [super free];
                    158: }
                    159: 
                    160: /*-------------------------------------------------------------------------
                    161:  *
                    162:  *
                    163:  *
                    164:  *-------------------------------------------------------------------------*/
                    165: 
                    166: - (void)interruptOccurredAt:(int)irqNum
                    167: {    
                    168: 
                    169:     [self reserveDebuggerLock];
                    170: 
                    171:     switch ( irqNum )
                    172:     {
                    173:       /*
                    174:        * On the transmit side, we use the chipset interrupt. Using the transmit
                    175:        * DMA interrupt (or having multiple transmit DMA entries) would allows us to 
                    176:        * send the next frame to the chipset prior the transmit fifo going empty. 
                    177:        * However, this aggrevates a BMac chipset bug where the next frame going out
                    178:        * gets corrupted (first two bytes lost) if the chipset had to retry the previous
                    179:        * frame.
                    180:        */ 
                    181:       case kIRQEnetDev:
                    182:       case kIRQEnetTxDMA:
                    183:         txWDInterrupts++;
                    184:         KERNEL_DEBUG(DBG_BMAC_TXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
                    185:         [self _transmitInterruptOccurred];
                    186:         [self serviceTransmitQueue];
                    187:         KERNEL_DEBUG(DBG_BMAC_TXIRQ | DBG_FUNC_END,   0, 0, 0, 0, 0 );
                    188:         break;
                    189:       case kIRQEnetRxDMA:
                    190:         KERNEL_DEBUG(DBG_BMAC_RXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
                    191:         [self _receiveInterruptOccurred];
                    192:         KERNEL_DEBUG(DBG_BMAC_RXIRQ | DBG_FUNC_END,   0, 0, 0, 0, 0 );
                    193:         break;
                    194:     }
                    195: 
                    196:     [self enableAllInterrupts];
                    197: 
                    198:     [self releaseDebuggerLock];
                    199: }
                    200: 
                    201: /*-------------------------------------------------------------------------
                    202:  *
                    203:  *
                    204:  *
                    205:  *-------------------------------------------------------------------------*/
                    206: 
                    207: - (void) serviceTransmitQueue
                    208: {
                    209:     netbuf_t                   packet;
                    210:     u_int32_t                  i;
                    211: 
                    212:     while ( 1 )
                    213:     {
                    214:       if ( ![transmitQueue count] )
                    215:       {
                    216:         break;
                    217:       }
                    218: 
                    219:       i = txCommandTail + 1;
                    220:       if ( i >= txMaxCommand ) i = 0;
                    221:       if ( i == txCommandHead )
                    222:       {
                    223:         break;
                    224:       }
                    225:       packet = [transmitQueue dequeue];
                    226:       [self _transmitPacket:packet];
                    227:     }
                    228: 
                    229: }
                    230: 
                    231: /*-------------------------------------------------------------------------
                    232:  *
                    233:  *
                    234:  *
                    235:  *-------------------------------------------------------------------------*/
                    236: 
                    237: - (void)transmit:(netbuf_t)pkt
                    238: {
                    239:     u_int32_t          i;
                    240:     u_int32_t           n;
                    241: 
                    242:     KERNEL_DEBUG(DBG_BMAC_TXQUEUE | DBG_FUNC_NONE, (int) pkt, (int) nb_size(pkt), 0, 0, 0 );
                    243: 
                    244:     /*
                    245:      * Hold the debugger lock so the debugger can't interrupt us
                    246:      */
                    247:     [self reserveDebuggerLock];
                    248:  
                    249:     do
                    250:     {
                    251:       /* 
                    252:        * Preliminary sanity checks
                    253:        */
                    254:       if (!pkt) 
                    255:       {
                    256:         IOLog("EtherNet(BMac): transmit received NULL netbuf\n");
                    257:         continue;  
                    258:       }
                    259:       if ( ![self isRunning] ) 
                    260:       {
                    261:         nb_free(pkt);
                    262:         continue;
                    263:       }
                    264: 
                    265: #if 0
                    266:       /*
                    267:        * Remove any completed packets from the Tx ring 
                    268:        */
                    269:       if ( chipId >= kCHIPID_PaddingtonXmitStreaming )
                    270:       {
                    271:         [self _transmitInterruptOccurred]; 
                    272:       }
                    273: #endif
                    274:        
                    275:       /*
                    276:        * Refill the Tx ring from the Transmit waiting list
                    277:        */
                    278:       [self serviceTransmitQueue];
                    279: 
                    280:       /*
                    281:        * If the Transmit waiting list is not empty or the Tx ring is
                    282:        * full, add the new packet to the waiting list.
                    283:        */
                    284:       n = [transmitQueue count];
                    285:       if ( n > 0 )
                    286:       {
                    287:         if ( n >= [transmitQueue maxCount] )
                    288:         {
                    289:           IOLog("Ethernet(BMac): Transmit queue overflow\n");
                    290:         }
                    291: 
                    292:         [transmitQueue enqueue:pkt];
                    293:         continue;
                    294:       }
                    295:       i = txCommandTail + 1;
                    296:       if ( i >= txMaxCommand ) i = 0;
                    297:       if ( i == txCommandHead )
                    298:       {
                    299:         [transmitQueue enqueue:pkt];
                    300:         continue;
                    301:       }
                    302: 
                    303:       /*
                    304:        * If there is space on the Tx ring, add the packet directly to the
                    305:        * ring
                    306:        */
                    307:       [self _transmitPacket:pkt];
                    308:     }
                    309:     while( 0 );
                    310: 
                    311:     [self releaseDebuggerLock];
                    312: }
                    313: 
                    314: /*-------------------------------------------------------------------------
                    315:  *
                    316:  *
                    317:  *
                    318:  *-------------------------------------------------------------------------*/
                    319: 
                    320: - (int) transmitQueueSize
                    321: {
                    322:     return (TRANSMIT_QUEUE_SIZE);
                    323: }
                    324: 
                    325: - (int) transmitQueueCount
                    326: {
                    327:     return ([transmitQueue count]);
                    328: }
                    329: /*-------------------------------------------------------------------------
                    330:  *
                    331:  *
                    332:  *
                    333:  *-------------------------------------------------------------------------*/
                    334: 
                    335: - (BOOL)resetAndEnable:(BOOL)enable
                    336: {
                    337:     resetAndEnabled = NO;
                    338:     [self clearTimeout];
                    339:     [self disableAllInterrupts];
                    340:     [self _resetChip];
                    341:     
                    342:     if (enable) 
                    343:     {
                    344:       if (![self _initRxRing] || ![self _initTxRing])  
                    345:       {
                    346:         return NO;
                    347:       }
                    348: 
                    349:       if ( phyId != 0xff )
                    350:       {
                    351:           [self miiInitializePHY:phyId];
                    352:       }
                    353: 
                    354:       if ([self _initChip] == NO) 
                    355:       {
                    356:        [self setRunning:NO];
                    357:        return NO;
                    358:       }
                    359: 
                    360:       [self _startChip];
                    361:        
                    362:       [self setRelativeTimeout: WATCHDOG_TIMER_MS];
                    363: 
                    364:       [self enableAllInterrupts]; 
                    365:       [self _enableAdapterInterrupts];
                    366: 
                    367:       resetAndEnabled = YES;
                    368: 
                    369:       [self _sendDummyPacket];      
                    370:     }
                    371: 
                    372:     [self setRunning:enable];
                    373: 
                    374:     return YES;
                    375: }
                    376: 
                    377: /*-------------------------------------------------------------------------
                    378:  *
                    379:  *
                    380:  *
                    381:  *-------------------------------------------------------------------------*/
                    382: 
                    383: - (void)timeoutOccurred
                    384: {
                    385:     u_int32_t          dmaStatus;
                    386:     u_int16_t          phyStatus;
                    387:     u_int16_t          linkStatus;
                    388:     u_int16_t          phyStatusChange;
                    389:     BOOL               fullDuplex = NO;
                    390: 
                    391:     if ( ![self isRunning] ) 
                    392:     {    
                    393:       return;
                    394:     }
                    395: 
                    396:     [self reserveDebuggerLock];
                    397: 
                    398:     /*
                    399:      * Check for DMA shutdown on receive channel
                    400:      */
                    401:     dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetRxDMA );
                    402:     if ( !(dmaStatus & kdbdmaActive) )
                    403:     {
                    404:       IOLog( "Ethernet(BMac): Checking for timeout - RxHead = %d RxTail = %d\n\r", rxCommandHead, rxCommandTail); 
                    405: #if 0
                    406:       IOLog( "Ethernet(BMac): Rx Commands = %08x(p) Rx DMA Ptr = %08x(p)\n\r", rxDMACommandsPhys, IOGetDBDMACommandPtr(ioBaseEnetRxDMA) ); 
                    407:       [self _dumpDesc:(void *)rxDMACommands Size:rxMaxCommand * sizeof(enet_dma_cmd_t)];
                    408: #endif 
                    409:       [self _receiveInterruptOccurred];
                    410:     } 
                    411: 
                    412:     /*
                    413:      * If there are pending entries on the Tx ring
                    414:      */
                    415:     if ( txCommandHead != txCommandTail )
                    416:     {
                    417:       /* 
                    418:        * If we did not service the Tx ring during the last timeout interval,
                    419:        * then force servicing of the Tx ring
                    420:        */
                    421:       if ( txWDInterrupts == 0 )
                    422:       {      
                    423:         if ( txWDCount++ > 0 )
                    424:         {
                    425:           if ( [self _transmitInterruptOccurred] == NO )
                    426:           {
                    427:               IOLog( "Ethernet(BMac): Checking for timeout - TxHead = %d TxTail = %d\n\r", txCommandHead, txCommandTail); 
                    428:               [self _restartTransmitter];
                    429:           }
                    430:         }
                    431:       }
                    432:       else
                    433:       {
                    434:         txWDInterrupts   = 0;
                    435:         txWDCount        = 0;
                    436:       }
                    437:     }
                    438:     else
                    439:     {      
                    440:       txWDInterrupts   = 0;
                    441:       txWDCount        = 0;
                    442:     }
                    443: 
                    444:     if ( phyId != 0xff )
                    445:     {
                    446:         if ( [self miiReadWord:&phyStatus reg:MII_STATUS phy:phyId] == YES )
                    447:         {
                    448:             phyStatusChange = (phyStatusPrev ^ phyStatus) & (MII_STATUS_LINK_STATUS | MII_STATUS_NEGOTIATION_COMPLETE);
                    449:             if ( phyStatusChange )
                    450:             {
                    451:                 if ( (phyStatus & MII_STATUS_LINK_STATUS) && (phyStatus & MII_STATUS_NEGOTIATION_COMPLETE ) )
                    452:                 {
                    453:                     if ( (phyType & MII_ST10040_MASK) == MII_ST10040_ID )
                    454:                     {
                    455:                         [self miiReadWord:&linkStatus reg:MII_ST10040_CHIPST phy:phyId];
                    456: 
                    457:                         fullDuplex =  (linkStatus & MII_ST10040_CHIPST_DUPLEX) ? YES : NO;
                    458: 
                    459:                         IOLog( "Ethernet(BMac): Link is up at %sMb - %s Duplex\n\r",
                    460:                               (linkStatus & MII_ST10040_CHIPST_SPEED)  ? "100" : "10",
                    461:                               (fullDuplex)                             ? "Full" : "Half" );                        
                    462:                     }
                    463:                     else if ( (phyType & MII_DP83843_MASK) == MII_DP83843_ID )
                    464:                     {
                    465:                         [self miiReadWord:&linkStatus reg:MII_DP83843_PHYSTS phy:phyId];
                    466: 
                    467:                         fullDuplex =  (linkStatus & MII_DP83843_PHYSTS_DUPLEX) ? YES : NO;
                    468: 
                    469:                         IOLog( "Ethernet(BMac): Link is up at %sMb - %s Duplex\n\r",
                    470:                               (linkStatus & MII_DP83843_PHYSTS_SPEED10) ? "10" : "100",
                    471:                               (fullDuplex)                              ? "Full" : "Half" );           
                    472:                      }  
                    473:                      else
                    474:                      {
                    475:                         fullDuplex = NO ;
                    476:                         IOLog( "Ethernet(BMac): Link is up\n\r" );
                    477:                      }
                    478: 
                    479:                      if ( fullDuplex != isFullDuplex )
                    480:                      {
                    481:                          [self _setDuplexMode: fullDuplex];    
                    482:                      }
                    483:                 }
                    484:                 else
                    485:                 {
                    486:                     IOLog( "Ethernet(BMac): Link is down.\n\r" );
                    487:                 }
                    488:                 phyStatusPrev = phyStatus;
                    489:             }
                    490:         }
                    491:     }          
                    492: 
                    493:     /*
                    494:      * Restart the watchdog timer
                    495:      */
                    496:     [self setRelativeTimeout: WATCHDOG_TIMER_MS];
                    497: 
                    498:     [self releaseDebuggerLock];
                    499: 
                    500: }
                    501: 
                    502: /*-------------------------------------------------------------------------
                    503:  *
                    504:  *
                    505:  *
                    506:  *-------------------------------------------------------------------------*/
                    507: 
                    508: - (BOOL)enablePromiscuousMode
                    509: {
                    510:     u_int16_t          rxCFGVal;
                    511:     
                    512:     isPromiscuous = YES;
                    513:     
                    514:     [self reserveDebuggerLock];
                    515: 
                    516:     /*
                    517:      * Turn off the receiver and wait for the chipset to acknowledge
                    518:      */
                    519:     rxCFGVal = ReadBigMacRegister(ioBaseEnet, kRXCFG);
                    520:     WriteBigMacRegister(ioBaseEnet, kRXCFG, rxCFGVal & ~kRxMACEnable );
                    521:     while( ReadBigMacRegister(ioBaseEnet, kRXCFG) & kRxMACEnable )
                    522:       ;
                    523: 
                    524:     /*
                    525:      * Set promiscuous mode and restore receiver state
                    526:      */
                    527:     rxCFGVal |= kRxPromiscEnable;      
                    528:     WriteBigMacRegister( ioBaseEnet, kRXCFG, rxCFGVal );               
                    529: 
                    530:     [self releaseDebuggerLock];
                    531:     
                    532:     return YES;
                    533: }
                    534: 
                    535: - (void)disablePromiscuousMode
                    536: {
                    537:     u_int16_t          rxCFGVal;
                    538:     
                    539:     isPromiscuous = NO;
                    540:     
                    541:     [self reserveDebuggerLock];
                    542: 
                    543:     /*
                    544:      * Turn off the receiver and wait for the chipset to acknowledge
                    545:      */
                    546:     rxCFGVal = ReadBigMacRegister(ioBaseEnet, kRXCFG);
                    547:     WriteBigMacRegister(ioBaseEnet, kRXCFG, rxCFGVal & ~kRxMACEnable );
                    548:     while( ReadBigMacRegister(ioBaseEnet, kRXCFG) & kRxMACEnable )
                    549:       ;
                    550: 
                    551:     /*
                    552:      * Reset promiscuous mode and restore receiver state
                    553:      */
                    554:     rxCFGVal &= ~kRxPromiscEnable;     
                    555:     WriteBigMacRegister( ioBaseEnet, kRXCFG, rxCFGVal );               
                    556: 
                    557:     [self releaseDebuggerLock];
                    558: }
                    559: 
                    560: - (BOOL)enableMulticastMode
                    561: {
                    562:     multicastEnabled = YES;
                    563:     return YES;
                    564: }
                    565:         
                    566: - (void)disableMulticastMode
                    567: {
                    568:     multicastEnabled = NO;
                    569: }
                    570: 
                    571: - (void)addMulticastAddress:(enet_addr_t *)addr
                    572: {
                    573:     multicastEnabled = YES;
                    574:     [self reserveDebuggerLock];
                    575:     [self _addToHashTableMask:addr->ea_byte];
                    576:     [self _updateBMacHashTableMask];
                    577:     [self releaseDebuggerLock];
                    578: }
                    579: 
                    580: - (void)removeMulticastAddress:(enet_addr_t *)addr
                    581: {
                    582:     [self reserveDebuggerLock];
                    583:     [self _removeFromHashTableMask:addr->ea_byte];
                    584:     [self _updateBMacHashTableMask];
                    585:     [self releaseDebuggerLock];
                    586: }
                    587: 
                    588: /*
                    589:  * Kernel Debugger Support 
                    590:  */
                    591: - (void)sendPacket:(void *)pkt length:(unsigned int)pkt_len
                    592: {
                    593:     [self _sendPacket:(void *)pkt length:(unsigned int)pkt_len];
                    594: }
                    595: 
                    596: - (void)receivePacket:(void *)pkt length:(unsigned int *)pkt_len  timeout:(unsigned int)timeout
                    597: {
                    598:     [self _receivePacket:(void *)pkt length:(unsigned int *)pkt_len  timeout:(unsigned int)timeout];
                    599: }
                    600: 
                    601: /*
                    602:  * Power management methods. 
                    603:  */
                    604: - (IOReturn)getPowerState:(PMPowerState *)state_p
                    605: {
                    606:     return IO_R_UNSUPPORTED;
                    607: }
                    608: 
                    609: - (IOReturn)setPowerState:(PMPowerState)state
                    610: {
                    611:     if (state == PM_OFF) {
                    612:        resetAndEnabled = NO;
                    613:         [self _resetChip];
                    614:        return IO_R_SUCCESS;
                    615:     }
                    616:     return IO_R_UNSUPPORTED;
                    617: }
                    618: 
                    619: - (IOReturn)getPowerManagement:(PMPowerManagementState *)state_p
                    620: {
                    621:     return IO_R_UNSUPPORTED;
                    622: }
                    623: 
                    624: - (IOReturn)setPowerManagement:(PMPowerManagementState)state
                    625: {
                    626:     return IO_R_UNSUPPORTED;
                    627: }
                    628: 
                    629: - (void)reserveDebuggerLock
                    630: {
                    631:     if ( debuggerLockCount++ == 0 )
                    632:     {
                    633:         [super reserveDebuggerLock];
                    634:     }
                    635: }   
                    636: 
                    637: - (void)releaseDebuggerLock
                    638: {
                    639:     if ( --debuggerLockCount == 0 )
                    640:     {
                    641:         [super releaseDebuggerLock];
                    642:     }
                    643: }   
                    644: 
                    645: 
                    646: @end
                    647: 
                    648: 
                    649: 
                    650: 
                    651: 
                    652: 
                    653: 
                    654: 
                    655: 
                    656: 
                    657: 
                    658: 
                    659: 
                    660: 
                    661: 

unix.superglobalmegacorp.com

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