Annotation of ntddk/src/scsi/qic117/mtaccess.c, revision 1.1.1.1

1.1       root        1: /*++
                      2: 
                      3: Copyright (c) 1993 - Colorado Memory Systems, Inc.
                      4: All Rights Reserved
                      5: 
                      6: Module Name:
                      7: 
                      8:     mtaccess.c
                      9: 
                     10: Abstract:
                     11: 
                     12:     interface functions to lower level driver.
                     13: 
                     14: Revision History:
                     15: 
                     16: 
                     17: 
                     18: 
                     19: --*/
                     20: 
                     21: //
                     22: // include files
                     23: //
                     24: 
                     25: #include <ntddk.h>
                     26: #include <ntddtape.h>
                     27: #include "common.h"
                     28: #include "q117.h"
                     29: #include "protos.h"
                     30: 
                     31: #define PAGES_TO_SECTORS(pages)  (((pages)*PAGE_SIZE)/BYTES_PER_SECTOR)
                     32: 
                     33: #define MIN(a,b) ((a)>(b)?(b):(a))
                     34: 
                     35: STATUS
                     36: q117ReqIO(
                     37:     IN PIO_REQUEST IoRequest,
                     38:     IN PSEGMENT_BUFFER BufferInfo,
                     39:     IN PQ117_CONTEXT Context
                     40:     )
                     41: 
                     42: /*++
                     43: 
                     44: Routine Description:
                     45: 
                     46:     Form an IRP to send to the lower level driver,  and send it.
                     47:     For MIPS,  allocate sub-requests and break the request into
                     48:     smaller chunks to allow for the 4K DMA limitation of the MIPS
                     49:     box.
                     50: 
                     51: 
                     52: Arguments:
                     53: 
                     54:     IoRequest - Original request
                     55: 
                     56:     BufferInfo - If a DMA is involved,  this contains information about the
                     57:                 associated memory for DMA.
                     58: 
                     59:     Context - Context of the driver.
                     60: 
                     61: Return Value:
                     62: 
                     63: --*/
                     64: 
                     65: {
                     66:     PIO_STACK_LOCATION irpStack;
                     67:     PIRP irp;
                     68: #ifdef BUFFER_SPLIT
                     69:     BOOLEAN secondary = FALSE;
                     70:     PVOID address;
                     71:     PIO_REQUEST subRequest;
                     72:     IO_REQUEST requestCopy;
                     73:     PKEVENT pevent;
                     74:     ULONG mask;
                     75:     ULONG numberOfPagesInTransfer;
                     76:     BOOLEAN needToSplit;
                     77:     ULONG sectorsToTransfer;
                     78:     ULONG maxSplits;
                     79: #endif
                     80: 
                     81: 
                     82:     IoRequest->BufferInfo = BufferInfo;
                     83: 
                     84: #ifdef BUFFER_SPLIT
                     85: 
                     86:     needToSplit = FALSE;
                     87: 
                     88:     if (BufferInfo) {
                     89:         numberOfPagesInTransfer = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
                     90:             IoRequest->Data,
                     91:             IoRequest->Number * BYTES_PER_SECTOR );
                     92: 
                     93:         if ( numberOfPagesInTransfer >
                     94:                 Context->AdapterInfo->NumberOfMapRegisters ) {
                     95: 
                     96:             needToSplit = TRUE;
                     97:             maxSplits =
                     98:                 (numberOfPagesInTransfer /
                     99:                 Context->AdapterInfo->NumberOfMapRegisters) + 1;
                    100: 
                    101:         }
                    102:     }
                    103: 
                    104: #endif
                    105: 
                    106: 
                    107: #if DBG
                    108:     if (BufferInfo) {
                    109:         //
                    110:         // Check to make sure the buffer information is for the data pointer
                    111:         // we recieved.
                    112:         // If not,  then there is a real problem with the calling function.
                    113:         // We need to check this so we don't page fault the system when a bug
                    114:         // occurs.
                    115:         //
                    116:         if (BufferInfo->logical < IoRequest->Data ||
                    117:             ((PUCHAR)(IoRequest->Data) + (IoRequest->Number * BYTES_PER_SECTOR)) >
                    118:             ((PUCHAR)(BufferInfo->logical) + BYTES_PER_SEGMENT) ) {
                    119: 
                    120:             CheckedDump(QIC117DBGP,("Buffer pointer out of range\n"));
                    121: 
                    122:             return FCodeErr;
                    123: 
                    124:         }
                    125:     }
                    126: #endif
                    127: 
                    128: 
                    129: #ifdef BUFFER_SPLIT
                    130: 
                    131: //
                    132: // For MIPS we must split the request into 4K DMA requests because
                    133: // the MIPS will not transfer more than 4K at a time.
                    134: //
                    135: 
                    136:     if (BufferInfo && IoRequest->Command != DFmt && needToSplit) {
                    137: 
                    138:         address = IoRequest->Data;
                    139: 
                    140:         //
                    141:         // Split request into chunks
                    142:         //
                    143:         subRequest = ExAllocatePool(NonPagedPool,
                    144:                          sizeof(*IoRequest)*maxSplits);
                    145: 
                    146:         CheckedDump(QIC117INFO,("q117ReqIO: Allocating %d subreqs\n", maxSplits));
                    147: 
                    148:         IoRequest->Next = subRequest;
                    149:         IoRequest->Status = SplitRequests;
                    150: 
                    151:         requestCopy = *IoRequest;
                    152: 
                    153: #if DBG
                    154:         CheckedDump(QIC117SHOWTD,("*************************", requestCopy.Block ));
                    155:         CheckedDump(QIC117SHOWTD,("IoRequest->Block     %x\n", requestCopy.Block ));
                    156:         CheckedDump(QIC117SHOWTD,("IoRequest->Number    %x\n", requestCopy.Number ));
                    157:         CheckedDump(QIC117SHOWTD,("IoRequest->Data      %x\n", requestCopy.Data ));
                    158:         CheckedDump(QIC117SHOWTD,("IoRequest->BadList   %x\n", requestCopy.BadList ));
                    159:         CheckedDump(QIC117SHOWTD,("IoRequest->RetryList %x\n", requestCopy.RetryList ));
                    160:         CheckedDump(QIC117SHOWTD,("IoRequest->Command   %x\n\n", requestCopy.Command ));
                    161: #endif
                    162: 
                    163:         while (requestCopy.Number) {
                    164: 
                    165:             //
                    166:             // Make a copy of the current request
                    167:             //
                    168:             *subRequest = requestCopy;
                    169: 
                    170:             //
                    171:             // there aren't enough map registers to handle the whole
                    172:             // transfer so cap the transfer at the number of map registers
                    173:             // we have
                    174:             //
                    175: 
                    176:             sectorsToTransfer =
                    177:                 PAGES_TO_SECTORS(Context->AdapterInfo->NumberOfMapRegisters);
                    178: 
                    179:             //
                    180:             // Perform the lesser of the two for this request
                    181:             //
                    182:             subRequest->Number = (UCHAR)
                    183:                 MIN(sectorsToTransfer, (ULONG)subRequest->Number);
                    184: 
                    185:             CheckedDump(QIC117SHOWTD,("Split at %d sectors\n", subRequest->Number));
                    186: 
                    187:             //
                    188:             // Adjust the current request to be the remainder of request
                    189:             //
                    190:             (PCHAR)requestCopy.Data += subRequest->Number * BYTES_PER_SECTOR;
                    191:             requestCopy.Block += subRequest->Number;
                    192:             requestCopy.Number -= subRequest->Number;
                    193:             requestCopy.BadList >>= subRequest->Number;
                    194:             requestCopy.RetryList >>= subRequest->Number;
                    195: 
                    196:             mask = ~(0xffffffff << subRequest->Number);
                    197:             requestCopy.BadList &=  mask;
                    198:             requestCopy.RetryList &= mask;
                    199: 
                    200: 
                    201:             //
                    202:             // use IoRequest.DoneEvent on last request so that all requests
                    203:             //  up to the last one are done before event is set
                    204:             //
                    205:             pevent = requestCopy.Number ?
                    206:                 &subRequest->DoneEvent : &IoRequest->DoneEvent;
                    207: 
                    208:             KeInitializeEvent(
                    209:                 pevent,
                    210:                 NotificationEvent,
                    211:                 FALSE);
                    212: 
                    213: 
                    214:             irp = IoBuildDeviceIoControlRequest(
                    215:                     IOCTL_QIC117_DRIVE_REQUEST,
                    216:                     Context->q117iDeviceObject,
                    217:                     NULL,
                    218:                     0,
                    219:                     NULL,
                    220:                     0,
                    221:                     TRUE,
                    222:                     pevent,
                    223:                     &subRequest->IoStatus
                    224:                 );
                    225: 
                    226: 
                    227:             if (irp == NULL) {
                    228: 
                    229:                 CheckedDump(QIC117DBGP,("q117ReqIO: Can't allocate Irp\n"));
                    230: 
                    231:                 //
                    232:                 // If an Irp can't be allocated, then this call will
                    233:                 // simply return. This will leave the queue frozen for
                    234:                 // this device, which means it can no longer be accessed.
                    235:                 //
                    236: 
                    237:                 return FCodeErr;
                    238:             }
                    239: 
                    240: 
                    241: 
                    242:             //
                    243:             // Build mdl
                    244:             //
                    245:             irp->MdlAddress = IoAllocateMdl(
                    246:                     address,
                    247:                     subRequest->Number * BYTES_PER_SECTOR,
                    248:                     secondary,
                    249:                     FALSE,  // no charge of quota
                    250:                     NULL    // no irp
                    251:                 );
                    252: 
                    253:             (PCHAR)address += subRequest->Number * BYTES_PER_SECTOR;
                    254:             secondary = TRUE;
                    255: 
                    256:             if (irp->MdlAddress == NULL) {
                    257: 
                    258:                 CheckedDump(QIC117DBGP,("q117ReqIO: Can't allocate MDL\n"));
                    259: 
                    260:                 //
                    261:                 // If a MDL can't be allocated, then this call will
                    262:                 // simply return. This will leave the queue frozen for
                    263:                 // this device, which means it can no longer be accessed.
                    264:                 //
                    265: 
                    266:                 IoFreeIrp(irp);
                    267: 
                    268:                 return FCodeErr;
                    269:             }
                    270: 
                    271:             MmBuildMdlForNonPagedPool(irp->MdlAddress);
                    272: 
                    273:             //
                    274:             // Get Q117I's stack location and store IoRequest for it's use
                    275:             //
                    276: 
                    277:             irpStack = IoGetNextIrpStackLocation(irp);
                    278:             irpStack->Parameters.DeviceIoControl.Type3InputBuffer = subRequest;
                    279: 
                    280: #if DBG
                    281:             CheckedDump(QIC117SHOWTD,("subRequest->Block     %x\n", subRequest->Block ));
                    282:             CheckedDump(QIC117SHOWTD,("subRequest->Number    %x\n", subRequest->Number ));
                    283:             CheckedDump(QIC117SHOWTD,("subRequest->Data      %x\n", subRequest->Data ));
                    284:             CheckedDump(QIC117SHOWTD,("subRequest->BadList   %x\n", subRequest->BadList ));
                    285:             CheckedDump(QIC117SHOWTD,("subRequest->RetryList %x\n", subRequest->RetryList ));
                    286:             CheckedDump(QIC117SHOWTD,("subRequest->Command   %x\n\n", subRequest->Command ));
                    287: #endif
                    288:             (VOID)IoCallDriver(Context->q117iDeviceObject, irp);
                    289: 
                    290:             CheckedDump(QIC117INFO,("q117ReqIO: Sending subreq\n"));
                    291: 
                    292:             //
                    293:             // point to the next sub-request to make
                    294:             //
                    295:             ++subRequest;
                    296:         }
                    297: 
                    298:     } else {
                    299: 
                    300: #endif // BUFFER_SPLIT
                    301: 
                    302:     IoRequest->Status = InQue;
                    303: 
                    304:     KeInitializeEvent(
                    305:         &IoRequest->DoneEvent,
                    306:         NotificationEvent,
                    307:         FALSE);
                    308: 
                    309:     irp = IoBuildDeviceIoControlRequest(
                    310:             IOCTL_QIC117_DRIVE_REQUEST,
                    311:             Context->q117iDeviceObject,
                    312:             NULL,
                    313:             0,
                    314:             NULL,
                    315:             0,
                    316:             TRUE,
                    317:             &IoRequest->DoneEvent,
                    318:             &IoRequest->IoStatus
                    319:         );
                    320: 
                    321: 
                    322:     if (irp == NULL) {
                    323: 
                    324:         CheckedDump(QIC117DBGP,("q117ReqIO: Can't allocate Irp\n"));
                    325: 
                    326:         //
                    327:         // If an Irp can't be allocated, then this call will
                    328:         // simply return. This will leave the queue frozen for
                    329:         // this device, which means it can no longer be accessed.
                    330:         //
                    331: 
                    332:         return FCodeErr;
                    333:     }
                    334: 
                    335: 
                    336: 
                    337:     //
                    338:     // If we have buffer information
                    339:     //
                    340:     if (BufferInfo) {
                    341: 
                    342:         irp->MdlAddress = IoAllocateMdl(
                    343:                 IoRequest->Data,
                    344:                 IoRequest->Number * BYTES_PER_SECTOR,
                    345:                 FALSE,  // not a secondary buffer
                    346:                 FALSE,  // no charge of quota
                    347:                 NULL    // no irp
                    348:             );
                    349: 
                    350:         if (irp->MdlAddress == NULL) {
                    351: 
                    352:             CheckedDump(QIC117DBGP,("q117ReqIO: Can't allocate MDL\n"));
                    353: 
                    354:             //
                    355:             // If a MDL can't be allocated, then this call will
                    356:             // simply return. This will leave the queue frozen for
                    357:             // this device, which means it can no longer be accessed.
                    358:             //
                    359: 
                    360:             IoFreeIrp(irp);
                    361: 
                    362:             return FCodeErr;
                    363:         }
                    364:         MmBuildMdlForNonPagedPool(irp->MdlAddress);
                    365:     }
                    366: 
                    367: 
                    368: 
                    369:     //
                    370:     // Get Q117I's stack location and store IoRequest for it's use
                    371:     //
                    372: 
                    373:     irpStack = IoGetNextIrpStackLocation(irp);
                    374:     irpStack->Parameters.DeviceIoControl.Type3InputBuffer = IoRequest;
                    375: 
                    376:     IoCallDriver(Context->q117iDeviceObject, irp);
                    377: 
                    378: #ifdef BUFFER_SPLIT
                    379:     }
                    380: #endif // BUFFER_SPLIT
                    381: 
                    382:     return NoErr;
                    383: 
                    384: }
                    385: 
                    386: STATUS
                    387: q117WaitIO(
                    388:     IN PIO_REQUEST IoRequest,
                    389:     IN PQ117_CONTEXT Context
                    390:     )
                    391: 
                    392: /*++
                    393: 
                    394: Routine Description:
                    395: 
                    396:     Wait for an I/O request to complete.  If a MIPS machine,
                    397:     coalesce the sub-requests into the original request.
                    398: 
                    399: Arguments:
                    400: 
                    401:    IoRequest -
                    402: 
                    403: Return Value:
                    404: 
                    405: --*/
                    406: 
                    407: {
                    408:     CheckedDump(QIC117INFO,("WaitIO(%x,%x,%x) ... ", IoRequest->Command,IoRequest->Block,IoRequest->Status));
                    409: 
                    410:     KeWaitForSingleObject(
                    411:         &IoRequest->DoneEvent,
                    412:         Suspended,
                    413:         KernelMode,
                    414:         FALSE,
                    415:         NULL);
                    416: 
                    417: #ifdef BUFFER_SPLIT
                    418: 
                    419:     if (IoRequest->Status == SplitRequests) {
                    420:         PIO_REQUEST subRequest;
                    421:         ULONG blocksLeft,mask,slot;
                    422: 
                    423:         CheckedDump(QIC117INFO,("Got split request\n"));
                    424: 
                    425:         subRequest = IoRequest->Next;
                    426:         blocksLeft = IoRequest->Number;
                    427: 
                    428:         //
                    429:         // Zero accumulating fields
                    430:         //
                    431: 
                    432:         IoRequest->BadList = IoRequest->RetryList = 0;
                    433:         IoRequest->Status = NoErr;
                    434: 
                    435:         //
                    436:         // Loop through all sub-requests and build the resultant request
                    437:         //
                    438:         while (blocksLeft) {
                    439: 
                    440: #if DBG
                    441:         CheckedDump(QIC117SHOWTD,("subRequest(%x)\n",subRequest));
                    442:         CheckedDump(QIC117SHOWTD,("subRequest->Block     %x\n", subRequest->Block ));
                    443:         CheckedDump(QIC117SHOWTD,("subRequest->Number    %x\n", subRequest->Number ));
                    444:         CheckedDump(QIC117SHOWTD,("subRequest->Data      %x\n", subRequest->Data ));
                    445:         CheckedDump(QIC117SHOWTD,("subRequest->BadList   %x\n", subRequest->BadList ));
                    446:         CheckedDump(QIC117SHOWTD,("subRequest->RetryList %x\n", subRequest->RetryList ));
                    447:         CheckedDump(QIC117SHOWTD,("subRequest->Command   %x\n", subRequest->Command ));
                    448:         CheckedDump(QIC117SHOWTD,("subRequest->Status    %x\n", subRequest->Status ));
                    449: #endif
                    450: 
                    451:             //
                    452:             // Create mask and calculate bit shift (slot) for each
                    453:             // sub-request
                    454:             //
                    455:             mask = ~(0xffffffff << subRequest->Number);
                    456:             slot = subRequest->Block - IoRequest->Block;
                    457: 
                    458:             CheckedDump(QIC117SHOWTD,("mask=%08lx slot=%x\n",mask,slot));
                    459: 
                    460:             //
                    461:             // Coalesce the bad sector and retry bitfields
                    462:             //
                    463:             IoRequest->BadList |= (subRequest->BadList & mask) << slot;
                    464:             IoRequest->RetryList |= (subRequest->RetryList & mask) << slot;
                    465: 
                    466:             if (subRequest->Status == NewCart) {
                    467:                 //
                    468:                 // Saw new cart,  so set need loaded flag
                    469:                 //
                    470:                 Context->CurrentTape.State = NeedInfoLoaded;
                    471:                 CheckedDump(QIC117SHOWTD,("New Cart Detected\n"));
                    472: 
                    473:             }
                    474: 
                    475:             //
                    476:             // Ignore BadBlk errors (but report them)
                    477:             //
                    478:             if (subRequest->Status == BadBlk) {
                    479: 
                    480:                 IoRequest->Status = subRequest->Status;
                    481:                 subRequest->Status = NoErr;
                    482: 
                    483:             }
                    484: 
                    485:             if (subRequest->Status != NoErr) {
                    486: 
                    487:                 blocksLeft = 0;
                    488:                 IoRequest->Status = subRequest->Status;
                    489: 
                    490:             } else {
                    491: 
                    492:                 blocksLeft -= subRequest->Number;
                    493: 
                    494:             }
                    495: 
                    496:             //
                    497:             // point to the next sub-request to process
                    498:             //
                    499:             ++subRequest;
                    500:         }
                    501: 
                    502:         //
                    503:         // Free the sub-requests for this I/O request
                    504:         //
                    505:         ExFreePool(IoRequest->Next);
                    506: 
                    507: #if DBG
                    508:         CheckedDump(QIC117SHOWTD,("IoRequest->Status    %x\n", IoRequest->Status ));
                    509:         CheckedDump(QIC117SHOWTD,("IoRequest->Block     %x\n", IoRequest->Block ));
                    510:         CheckedDump(QIC117SHOWTD,("IoRequest->Number    %x\n", IoRequest->Number ));
                    511:         CheckedDump(QIC117SHOWTD,("IoRequest->Data      %x\n", IoRequest->Data ));
                    512:         CheckedDump(QIC117SHOWTD,("IoRequest->BadList   %x\n", IoRequest->BadList ));
                    513:         CheckedDump(QIC117SHOWTD,("IoRequest->RetryList %x\n", IoRequest->RetryList ));
                    514:         CheckedDump(QIC117SHOWTD,("IoRequest->Command   %x\n", IoRequest->Command ));
                    515: #endif
                    516:     }
                    517: 
                    518:     if (IoRequest->Status == NewCart) {
                    519:         //
                    520:         // Saw new cart,  so set need loaded flag
                    521:         //
                    522:         Context->CurrentTape.State = NeedInfoLoaded;
                    523:         CheckedDump(QIC117SHOWTD,("New Cart Detected\n"));
                    524: 
                    525:     }
                    526: 
                    527: #endif // BUFFER_SPLIT
                    528: 
                    529: #if DBG
                    530:     if (IoRequest->Status == BadBlk) {
                    531:         CheckedDump(QIC117INFO,("bbm: %x ", IoRequest->BadList));
                    532:     }
                    533: #endif
                    534:     CheckedDump(QIC117INFO,("waitio status %x\n", IoRequest->Status));
                    535: 
                    536:     return NoErr;
                    537: }
                    538: 
                    539: STATUS
                    540: q117DoIO(
                    541:     IN PIO_REQUEST IoRequest,
                    542:     IN PSEGMENT_BUFFER BufferInfo,
                    543:     IN PQ117_CONTEXT Context
                    544:     )
                    545: 
                    546: /*++
                    547: 
                    548: Routine Description:
                    549: 
                    550: 
                    551: Arguments:
                    552: 
                    553:     IoRequest -
                    554: 
                    555:     BufferInfo -
                    556: 
                    557:     Context -
                    558: 
                    559: Return Value:
                    560: 
                    561: --*/
                    562: 
                    563: {
                    564:     STATUS ret;
                    565: 
                    566:     CheckedDump(QIC117INFO,("DoIO called (%x)\n", IoRequest->Command));
                    567: 
                    568:     ret = q117ReqIO(IoRequest, BufferInfo, Context);
                    569:     if (!ret) {
                    570:         ret = q117WaitIO(IoRequest, Context);
                    571:     }
                    572:     return ret;
                    573: }
                    574: 
                    575: STATUS
                    576: q117AbortIo(
                    577:     IN PQ117_CONTEXT Context,
                    578:     IN PKEVENT DoneEvent,
                    579:     IN PIO_STATUS_BLOCK IoStatus
                    580:     )
                    581: 
                    582: /*++
                    583: 
                    584: Routine Description:
                    585: 
                    586: 
                    587: Arguments:
                    588: 
                    589:     Context -
                    590: 
                    591:     DoneEvent -
                    592: 
                    593:     IoStatus -
                    594: 
                    595: Return Value:
                    596: 
                    597: --*/
                    598: 
                    599: {
                    600:     PIRP irp;
                    601: 
                    602: 
                    603:     CheckedDump(QIC117INFO,("ClearIO Called\n"));
                    604: 
                    605:     KeInitializeEvent(
                    606:         DoneEvent,
                    607:         NotificationEvent,
                    608:         FALSE);
                    609: 
                    610:     irp = IoBuildDeviceIoControlRequest(
                    611:             IOCTL_QIC117_CLEAR_QUEUE,
                    612:             Context->q117iDeviceObject,
                    613:             NULL,
                    614:             0,
                    615:             NULL,
                    616:             0,
                    617:             TRUE,
                    618:             DoneEvent,
                    619:             IoStatus
                    620:         );
                    621: 
                    622: 
                    623:     if (irp == NULL) {
                    624: 
                    625:         CheckedDump(QIC117DBGP,("q117ClearIO: Can't allocate Irp\n"));
                    626: 
                    627:         //
                    628:         // If an Irp can't be allocated, then this call will
                    629:         // simply return. This will leave the queue frozen for
                    630:         // this device, which means it can no longer be accessed.
                    631:         //
                    632: 
                    633:         return FCodeErr;
                    634:     }
                    635: 
                    636: 
                    637:     (VOID)IoCallDriver(Context->q117iDeviceObject, irp);
                    638: 
                    639:     return NoErr;
                    640: }
                    641: 
                    642: STATUS
                    643: q117AbortIoDone(
                    644:     IN PQ117_CONTEXT Context,
                    645:     IN PKEVENT DoneEvent
                    646:     )
                    647: 
                    648: /*++
                    649: 
                    650: Routine Description:
                    651: 
                    652: 
                    653: Arguments:
                    654: 
                    655:     Context -
                    656: 
                    657:     DoneEvent -
                    658: 
                    659: Return Value:
                    660: 
                    661: --*/
                    662: 
                    663: {
                    664: 
                    665:     //
                    666:     // wait for the driver to complete request
                    667:     //
                    668: 
                    669:     KeWaitForSingleObject(
                    670:         DoneEvent,
                    671:         Suspended,
                    672: 
                    673:         KernelMode,
                    674:         FALSE,
                    675:         NULL);
                    676: 
                    677:     return NoErr;
                    678: }

unix.superglobalmegacorp.com

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