Annotation of ntddk/src/scsi/fd8xx/fd8xx.c, revision 1.1

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1991, 1992  Microsoft Corporation
        !             4: Copyright (c) 1992  Future Domain Corporation
        !             5: 
        !             6: Module Name:
        !             7: 
        !             8:     fd8xx.c
        !             9: 
        !            10: Abstract:
        !            11: 
        !            12:     This is the miniport driver for the Future Domain TMC-8XX SCSI Adapters.
        !            13: 
        !            14: Environment:
        !            15: 
        !            16:     kernel mode only
        !            17: 
        !            18: Notes:
        !            19: 
        !            20: --*/
        !            21: 
        !            22: #include "miniport.h"
        !            23: #include "stdarg.h"
        !            24: #include <string.h>
        !            25: #include <math.h>
        !            26: #include <stdlib.h>
        !            27: #include "fd8xx.h"      // includes scsi.h
        !            28: 
        !            29: //
        !            30: // Logical Unit states.
        !            31: //
        !            32: typedef enum _LU_STATE {
        !            33: 
        !            34:     LS_UNDETERMINED,
        !            35:     LS_ARBITRATE,
        !            36:     LS_SELECT,
        !            37:     LS_IDENTIFY,
        !            38:     LS_MSG_SPECIAL,
        !            39:     LS_COMMAND,
        !            40:     LS_DATA,
        !            41:     LS_DISCONNECTED,
        !            42:     LS_ABORT,
        !            43:     LS_STATUS,
        !            44:     LS_MSG_IN,
        !            45:     LS_COMPLETE
        !            46: 
        !            47: } LU_STATE, *PLU_STATE;
        !            48: 
        !            49: //
        !            50: // Logical Unit extension.  The BOOLEANS in this structure will be initialized
        !            51: // to FALSE by the port driver.  It will zero the structure when allocated.
        !            52: // Therefore there is no explicit initialization of these fields.
        !            53: //
        !            54: typedef struct _SPECIFIC_LU_EXTENSION {
        !            55: 
        !            56:     LU_STATE            LuState;            // State information.
        !            57:     ULONG               SavedDataPointer;   // Current data pointer.
        !            58:     ULONG               SavedDataLength;    // Current data lenght.
        !            59:     PSCSI_REQUEST_BLOCK ActiveLuRequest;    // Active Srb for this LUN.
        !            60:     USHORT              OverRunCount;       // Initialized to zero, counts up
        !            61:     UCHAR               AbortBeingAttempted;// Abort active on this LU.
        !            62:     BOOLEAN             NoDisconnectActive; // No disconnect flag on SRB.
        !            63:     BOOLEAN             HandShakeAllData;   // Dribbling drive fix.
        !            64:     BOOLEAN             SixByteCDBActive;   // Potential tape access.
        !            65: 
        !            66: } SPECIFIC_LU_EXTENSION, *PSPECIFIC_LU_EXTENSION;
        !            67: 
        !            68: //
        !            69: // Device extension
        !            70: //
        !            71: typedef struct _SPECIFIC_DEVICE_EXTENSION {
        !            72: 
        !            73:     PUCHAR              BaseAddress;        // Memory map address of adapter.
        !            74:     ULONG               CurDataPointer;     // Current pointer for active LUN.
        !            75:     ULONG               CurDataLength;      // Bytes left to xfer to this LUN.
        !            76:     PSPECIFIC_LU_EXTENSION  SavedLu;        // Saved LUN during interrupts.
        !            77:     PSPECIFIC_LU_EXTENSION  ActiveLu;       // Currently active LUN.
        !            78:     UCHAR               PathId;             // Relates to SCSI bus.
        !            79:     UCHAR               ControlRegister;    // Current val of fd8xx control reg.
        !            80:     BOOLEAN             ExpectingInterrupt; // Bookkeeping for IRQ configuration.
        !            81:     BOOLEAN             NotifiedConfigurationError; // Event is logged.
        !            82:     USHORT              ContinueTimer;      // Indicator to continue polling
        !            83:     USHORT              TimerCaughtInterrupt; // Number times timer caught IRQ
        !            84:     UCHAR               InitiatorId;        // target id for host adapter
        !            85:     BOOLEAN             ConfiguredWithoutInterrupts; // Intentially configured w/o IRQ
        !            86: 
        !            87: } SPECIFIC_DEVICE_EXTENSION, *PSPECIFIC_DEVICE_EXTENSION;
        !            88: 
        !            89: 
        !            90: //
        !            91: // Function declarations
        !            92: //
        !            93: 
        !            94: ULONG
        !            95: DriverEntry(
        !            96:     IN PVOID DriverObject,
        !            97:     IN PVOID Argument2
        !            98:     );
        !            99: 
        !           100: ULONG
        !           101: Fd8xxFindAdapter(
        !           102:     IN PVOID                                Context,
        !           103:     IN PVOID                                AdaptersFound,
        !           104:     IN PVOID                                BusInformation,
        !           105:     IN PCHAR                                ArgumentString,
        !           106:     IN OUT PPORT_CONFIGURATION_INFORMATION  ConfigInfo,
        !           107:     OUT PBOOLEAN                            Again
        !           108:     );
        !           109: 
        !           110: BOOLEAN
        !           111: Fd8xxInitialize(
        !           112:     IN PVOID Context
        !           113:     );
        !           114: 
        !           115: BOOLEAN
        !           116: Fd8xxStartIo(
        !           117:     IN PVOID               Context,
        !           118:     IN PSCSI_REQUEST_BLOCK Srb
        !           119:     );
        !           120: 
        !           121: VOID
        !           122: Fd8xxDoReconnect(
        !           123:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !           124:     );
        !           125: 
        !           126: VOID
        !           127: Fd8xxDpcRunPhase(
        !           128:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !           129:     );
        !           130: 
        !           131: VOID
        !           132: Fd8xxTimer(
        !           133:     IN PVOID Context
        !           134:     );
        !           135: 
        !           136: BOOLEAN
        !           137: Fd8xxInterrupt(
        !           138:     IN PVOID Context
        !           139:     );
        !           140: 
        !           141: BOOLEAN
        !           142: Fd8xxResetBus(
        !           143:     IN PVOID Context,
        !           144:     IN ULONG PathId
        !           145:     );
        !           146: 
        !           147: VOID
        !           148: Fd8xxMoveMemoryUchar(
        !           149:     PUCHAR Source,
        !           150:     PUCHAR Dest,
        !           151:     ULONG  Length
        !           152:     );
        !           153: 
        !           154: 
        !           155: #if DBG
        !           156: 
        !           157: //
        !           158: // Globals and externals used for debugging.
        !           159: //
        !           160: 
        !           161: //
        !           162: // Fd8xxDebug affects which debug prints are enabled:
        !           163: //
        !           164: //      0x001    Arbitration and selection
        !           165: //      0x002    Command, message out, and status
        !           166: //      0x004    Data transfer
        !           167: //      0x008    Message in and status
        !           168: //      0x010    Miniport entry points and completion
        !           169: //      0x020    Initialization and interrupt
        !           170: //      0x040    StatusCheck and WaitForRequest
        !           171: //      0x080    Control register manipulation
        !           172: //      0x100    Completion
        !           173: //      0x200    Handshake all bytes set.
        !           174: //
        !           175: ULONG Fd8xxDebug = 0x0000;
        !           176: 
        !           177: #define FdDebugPrint(MASK, ARGS)    \
        !           178:         if (MASK & Fd8xxDebug) {    \
        !           179:             ScsiDebugPrint ARGS;    \
        !           180:         }
        !           181: 
        !           182: #else
        !           183: 
        !           184: #define FdDebugPrint(MASK, ARGS)
        !           185: 
        !           186: #endif
        !           187: 
        !           188: 
        !           189: VOID
        !           190: Fd8xxWriteControl(
        !           191:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
        !           192:     IN UCHAR                      Value
        !           193:     )
        !           194: 
        !           195: /*++
        !           196: 
        !           197: Routine Description:
        !           198: 
        !           199:     This routine sets the control register on the adapter and remembers
        !           200:     the value set in the device extension.
        !           201: 
        !           202: Arguments:
        !           203: 
        !           204:     DeviceExtension - Device adapter context pointer.
        !           205:     Value           - New value for the control register.
        !           206: 
        !           207: Return Value:
        !           208: 
        !           209:     None
        !           210: 
        !           211: --*/
        !           212: 
        !           213: {
        !           214:     FdDebugPrint(0x80,
        !           215:                  (0, "WriteControl: Device = %x, NewVal = %x\n",
        !           216:                  DeviceExtension,
        !           217:                  Value));
        !           218: 
        !           219:     DeviceExtension->ControlRegister = Value;
        !           220: 
        !           221:     FD8XX_SET_CONTROL(DeviceExtension->BaseAddress,
        !           222:                       Value);
        !           223: } // end Fd8xxWriteControl()
        !           224: 
        !           225: 
        !           226: VOID
        !           227: Fd8xxSetControl(
        !           228:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
        !           229:     IN UCHAR                      Value
        !           230:     )
        !           231: 
        !           232: /*++
        !           233: 
        !           234: Routine Description:
        !           235: 
        !           236:     This routine adds the control lines indicated to the current value
        !           237:     for the adapter control register.
        !           238: 
        !           239: Arguments:
        !           240: 
        !           241:     DeviceExtension - Device adapter context pointer.
        !           242:     Value           - The bits that are to be added (or'd in) to the
        !           243:                       control register.
        !           244: 
        !           245: Return Value:
        !           246: 
        !           247:     None
        !           248: 
        !           249: --*/
        !           250: 
        !           251: {
        !           252:     FdDebugPrint(0x80,
        !           253:                  (0, "SetControl: Device = %x, Value = %x, NewVal = %x\n",
        !           254:                  DeviceExtension,
        !           255:                  Value,
        !           256:                  DeviceExtension->ControlRegister | Value));
        !           257: 
        !           258:     DeviceExtension->ControlRegister |= Value;
        !           259: 
        !           260:     FD8XX_SET_CONTROL(DeviceExtension->BaseAddress,
        !           261:                       DeviceExtension->ControlRegister);
        !           262: } // end Fd8xxSetControl()
        !           263: 
        !           264: 
        !           265: VOID
        !           266: Fd8xxClearControl(
        !           267:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
        !           268:     IN UCHAR                      Mask
        !           269:     )
        !           270: 
        !           271: /*++
        !           272: 
        !           273: Routine Description:
        !           274: 
        !           275:     This routine masks out the bits for the control register that are
        !           276:     passed in Mask and sets the adapter control register to the new value.
        !           277: 
        !           278: Arguments:
        !           279: 
        !           280:     DeviceExtension - Device adapter context pointer.
        !           281:     Mask            - The bits that are to be reset to zero in the control
        !           282:                       register.
        !           283: 
        !           284: Return Value:
        !           285: 
        !           286:     None
        !           287: 
        !           288: --*/
        !           289: 
        !           290: {
        !           291:     FdDebugPrint(0x80,
        !           292:                  (0, "ClearControl: Device = %x, Mask = %x, NewVal = %x\n",
        !           293:                  DeviceExtension,
        !           294:                  Mask,
        !           295:                  DeviceExtension->ControlRegister & (~(Mask))));
        !           296: 
        !           297:     //
        !           298:     // Negate Value to get a zero based mask.
        !           299:     //
        !           300:     Mask = ~(Mask);
        !           301: 
        !           302:     //
        !           303:     // AND against the current contents of the control register.
        !           304:     //
        !           305:     DeviceExtension->ControlRegister &= Mask;
        !           306: 
        !           307:     FD8XX_SET_CONTROL(DeviceExtension->BaseAddress,
        !           308:                       DeviceExtension->ControlRegister);
        !           309: } // end Fd8xxClearControl()
        !           310: 
        !           311: 
        !           312: BOOLEAN
        !           313: Fd8xxWaitForRequestLine(
        !           314:     PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !           315:     )
        !           316: 
        !           317: /*++
        !           318: 
        !           319: Routine Description:
        !           320: 
        !           321:     Spin checking the status of the FD8XX adapter until it indicates that
        !           322:     the SCSI REQUEST line is high.
        !           323: 
        !           324: Arguments:
        !           325: 
        !           326:     DeviceExtension - Device adapter context pointer.
        !           327: 
        !           328: Return Value:
        !           329: 
        !           330:     TRUE    - indicates that the SCSI REQUEST line was asserted in time.
        !           331:     FALSE   - indicates timeout occurred while waiting for the SCSI REQUEST
        !           332:               line.
        !           333: 
        !           334: --*/
        !           335: 
        !           336: {
        !           337:     PUCHAR  baseAddress = DeviceExtension->BaseAddress;
        !           338:     ULONG   spinCount   = REQUEST_SPIN_WAIT;
        !           339: 
        !           340:     FdDebugPrint(0x40, (0, "FdWaitForReq: "));
        !           341: 
        !           342:     do {
        !           343: 
        !           344:         //
        !           345:         // Check if TWO of the status register reads are identical.  This is
        !           346:         // to validate that there was no "glitch" that caused some line to
        !           347:         // temporarily go high.
        !           348:         //
        !           349:         while (FD8XX_READ_STATUS(baseAddress) !=
        !           350:                FD8XX_READ_ALTERNATE_STATUS(baseAddress, 1)) {
        !           351: 
        !           352:             ScsiPortStallExecution(1);
        !           353:         }
        !           354: 
        !           355:         if (FD8XX_READ_STATUS(baseAddress) & S_REQUEST) {
        !           356: 
        !           357:             FdDebugPrint(0x40, (0, "Got REQUEST\n"));
        !           358:             return TRUE;
        !           359:         }
        !           360: 
        !           361:         ScsiPortStallExecution(1);
        !           362: 
        !           363:     } while (spinCount--);
        !           364: 
        !           365:     FdDebugPrint(0x40, (0, "TIMEOUT\n"));
        !           366: 
        !           367:     if (DeviceExtension->ActiveLu) {
        !           368: 
        !           369:         ScsiPortLogError(DeviceExtension,
        !           370:                          DeviceExtension->ActiveLu->ActiveLuRequest,
        !           371:                          DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
        !           372:                          DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
        !           373:                          DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
        !           374:                          SP_REQUEST_TIMEOUT,
        !           375:                          1);
        !           376:     }
        !           377: 
        !           378:     return FALSE;
        !           379: } // end Fd8xxWaitForRequestLine()
        !           380: 
        !           381: 
        !           382: BOOLEAN
        !           383: Fd8xxStatusCheck(
        !           384:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
        !           385:     IN UCHAR Mask,
        !           386:     IN UCHAR Compare,
        !           387:     IN ULONG SpinMax
        !           388:     )
        !           389: 
        !           390: /*++
        !           391: 
        !           392: Routine Description:
        !           393: 
        !           394:     Spin checking the status of the FD8XX adapter until it matches
        !           395:     the desired value.
        !           396: 
        !           397: Arguments:
        !           398: 
        !           399:     DeviceExtension - Device adapter context pointer.
        !           400:     Mask            - Bits to mask out of the value returned by adapter
        !           401:                       status register.
        !           402:     Compare         - Desired result of status register after is is "Mask"ed.
        !           403:     SpinMax         - Number of times to test adapter's status register.
        !           404: 
        !           405: Return Value:
        !           406: 
        !           407:     TRUE indicates desired value was returned by the adapter status register.
        !           408:     FALSE indicates timeout occurred and desired value was not returned.
        !           409: 
        !           410: --*/
        !           411: 
        !           412: {
        !           413:     PUCHAR  baseAddress = DeviceExtension->BaseAddress;
        !           414: 
        !           415:     FdDebugPrint(0x40, (0, "FdStatusCheck: "));
        !           416: 
        !           417:     FdDebugPrint(0x40,
        !           418:                   (0, "Dev=%x Status=%x Mask=%x Compare=%x ",
        !           419:                   DeviceExtension,
        !           420:                   FD8XX_READ_STATUS(baseAddress),
        !           421:                   Mask,
        !           422:                   Compare));
        !           423: 
        !           424:     do {
        !           425: 
        !           426:         //
        !           427:         // Check if TWO of the status register reads are identical.  This is
        !           428:         // to validate that there was no "glitch" that caused some line to
        !           429:         // temporarily go high.
        !           430:         //
        !           431:         while (FD8XX_READ_STATUS(baseAddress) !=
        !           432:                FD8XX_READ_ALTERNATE_STATUS(baseAddress, 1)) {
        !           433: 
        !           434:             ScsiPortStallExecution(1);
        !           435:         }
        !           436: 
        !           437:         if ((UCHAR)(FD8XX_READ_STATUS(baseAddress) & Mask) == Compare) {
        !           438: 
        !           439:             FdDebugPrint(0x40, (0, "Got Compare\n"));
        !           440:             return TRUE;
        !           441:         }
        !           442: 
        !           443:         ScsiPortStallExecution(1);
        !           444: 
        !           445:     } while (SpinMax--);
        !           446: 
        !           447:     FdDebugPrint(0x40,
        !           448:                   (0, "TIMEOUT Status=%x\n",
        !           449:                   FD8XX_READ_STATUS(baseAddress)));
        !           450: 
        !           451:     return FALSE;
        !           452: } // end Fd8xxStatusCheck()
        !           453: 
        !           454: 
        !           455: VOID
        !           456: Fd8xxDetermineNextState(
        !           457:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !           458:     )
        !           459: 
        !           460: /*++
        !           461: 
        !           462: Routine Description:
        !           463: 
        !           464:     This routine determines the next logical state of this state machine
        !           465:     based on the current SCSI bus phase.  It is typically called because
        !           466:     from the current state, the next state can be one of a number of other
        !           467:     states.  For example, after issuing the last command byte of COMMAND
        !           468:     phase, the device may want to drive us into DATA_IN, DATA_OUT, STATUS,
        !           469:     or MSG_IN (i.e., transfer data, report an error, or disconnect).
        !           470: 
        !           471: Arguments:
        !           472: 
        !           473:     DeviceExtension - Device adapter context pointer.
        !           474: 
        !           475: Return Value:
        !           476: 
        !           477:     None
        !           478: 
        !           479: --*/
        !           480: 
        !           481: {
        !           482:     FdDebugPrint(0x01,
        !           483:                   (0, "FdNextPhase: phase = %x ",
        !           484:                   FD8XX_READ_PHASE(DeviceExtension->BaseAddress)));
        !           485: 
        !           486:     switch (FD8XX_READ_PHASE(DeviceExtension->BaseAddress)) {
        !           487: 
        !           488:     case BP_COMMAND:
        !           489: 
        !           490:         FdDebugPrint(0x01, (0, "LS_COMMAND\n"));
        !           491:         DeviceExtension->ActiveLu->LuState = LS_COMMAND;
        !           492:         break;
        !           493: 
        !           494:     case BP_DATA_IN:
        !           495:     case BP_DATA_OUT:
        !           496: 
        !           497:         FdDebugPrint(0x01, (0, "LS_DATA\n"));
        !           498:         DeviceExtension->ActiveLu->LuState = LS_DATA;
        !           499:         break;
        !           500: 
        !           501:     case BP_MESSAGE_IN:
        !           502: 
        !           503:         FdDebugPrint(0x01, (0, "LS_MSG_IN\n"));
        !           504:         DeviceExtension->ActiveLu->LuState = LS_MSG_IN;
        !           505:         break;
        !           506: 
        !           507:     case BP_STATUS:
        !           508: 
        !           509:         FdDebugPrint(0x01, (0, "LS_STATUS\n"));
        !           510:         DeviceExtension->ActiveLu->LuState = LS_STATUS;
        !           511:         break;
        !           512: 
        !           513:     case BP_BUS_FREE:
        !           514: 
        !           515:         FdDebugPrint(0x01, (0, "LS_BUS_FREE\n"));
        !           516: 
        !           517:         if (DeviceExtension->ActiveLu->AbortBeingAttempted) {
        !           518: 
        !           519:             DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
        !           520:                                         SRB_STATUS_SUCCESS;
        !           521:         } else {
        !           522: 
        !           523:             DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
        !           524:                                         SRB_STATUS_UNEXPECTED_BUS_FREE;
        !           525:         }
        !           526: 
        !           527:         DeviceExtension->ActiveLu->LuState = LS_COMPLETE;
        !           528:         break;
        !           529: 
        !           530:     case BP_MESSAGE_OUT:
        !           531:     case BP_RESELECT:
        !           532:     default:
        !           533: 
        !           534:         //
        !           535:         // This will get handled in RunPhase.
        !           536:         //
        !           537:         FdDebugPrint(0x01, (0, "N/A\n"));
        !           538:         break;
        !           539:     }
        !           540: } // end Fd8xxDetermineNextState()
        !           541: 
        !           542: 
        !           543: VOID
        !           544: Fd8xxArbitrate(
        !           545:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !           546:     )
        !           547: 
        !           548: /*++
        !           549: 
        !           550: Routine Description:
        !           551: 
        !           552:     Attempt to arbitrate for the SCSI bus.
        !           553: 
        !           554: Arguments:
        !           555: 
        !           556:     DeviceExtension - Device adapter context pointer.
        !           557: 
        !           558: Return Value:
        !           559: 
        !           560:     None
        !           561: 
        !           562: --*/
        !           563: 
        !           564: {
        !           565:     PUCHAR  baseAddress = DeviceExtension->BaseAddress;
        !           566:     ULONG   attemptsRemaining = MAX_ARB_ATTEMPTS;
        !           567: 
        !           568:     FdDebugPrint(0x01, (0, "FdArbitrate: baseaddr = %x ", baseAddress));
        !           569: 
        !           570:     while (DeviceExtension->ActiveLu->LuState == LS_ARBITRATE) {
        !           571: 
        !           572:         if (FD8XX_READ_PHASE(baseAddress) == BP_BUS_FREE) {
        !           573: 
        !           574:             //
        !           575:             // Tell the adapter to initiate arbitration for the SCSI bus
        !           576:             // since it ia available.
        !           577:             //
        !           578:             Fd8xxClearControl(DeviceExtension,
        !           579:                               C_BUS_ENABLE);
        !           580:             Fd8xxSetControl(DeviceExtension,
        !           581:                             C_PARITY_ENABLE);
        !           582:             FD8XX_WRITE_DATA(baseAddress,
        !           583:                             (1 << DeviceExtension->InitiatorId));
        !           584:             Fd8xxSetControl(DeviceExtension,
        !           585:                             C_ARBITRATION);
        !           586:         }
        !           587: 
        !           588:         if (Fd8xxStatusCheck(DeviceExtension,
        !           589:                              S_ARB_COMPLETE,
        !           590:                              S_ARB_COMPLETE,
        !           591:                              ARBITRATION_DELAY)) {
        !           592: 
        !           593:             FdDebugPrint(0x01,
        !           594:                           (0, "SUCCESS on attempt #%x!\n",
        !           595:                           (MAX_ARB_ATTEMPTS - attemptsRemaining)));
        !           596: 
        !           597:             //
        !           598:             // Disable adapter interrupts so selection doesn't cause an
        !           599:             // interrupt.  Then go to selection phase.
        !           600:             //
        !           601:             Fd8xxClearControl(DeviceExtension,
        !           602:                               C_INT_ENABLE);
        !           603:             DeviceExtension->ActiveLu->LuState = LS_SELECT;
        !           604: 
        !           605:         } else {
        !           606: 
        !           607:             FdDebugPrint(0x01,
        !           608:                           (0, "FAILED! Status=%x ",
        !           609:                           FD8XX_READ_STATUS(baseAddress)));
        !           610: 
        !           611:             Fd8xxClearControl(DeviceExtension,
        !           612:                               C_ARBITRATION);
        !           613: 
        !           614:             if (FD8XX_READ_PHASE(baseAddress) & S_SELECT) {
        !           615: 
        !           616:                 FdDebugPrint(0x01, (0, "Being re-selected!\n"));
        !           617: 
        !           618:                 //
        !           619:                 // This will cause the interrupt routine to be called TWICE
        !           620:                 // for the same reason.  The first call will be from here.
        !           621:                 // The second call will be from the NT OS since it will
        !           622:                 // remember to call the interrupt routine due to the
        !           623:                 // adapter IRQ line (which is tied to the SCSI SELECT line)
        !           624:                 // going high.  The second call will be seen by the interrupt
        !           625:                 // routine as SPURRIOUS!
        !           626:                 //
        !           627:                 DeviceExtension->SavedLu = DeviceExtension->ActiveLu;
        !           628:                 DeviceExtension->ActiveLu = NULL;
        !           629: 
        !           630:                 Fd8xxDoReconnect(DeviceExtension);
        !           631: 
        !           632:                 if (DeviceExtension->SavedLu == NULL) {
        !           633: 
        !           634:                     //
        !           635:                     // The bus was reset during the reconnect.
        !           636:                     //
        !           637:                     return;
        !           638:                 }
        !           639: 
        !           640:                 DeviceExtension->ActiveLu = DeviceExtension->SavedLu;
        !           641:                 DeviceExtension->SavedLu = NULL;
        !           642: 
        !           643:                 FdDebugPrint(0x01, (0, "Back to Arbitration "));
        !           644: 
        !           645:             } else if (!(attemptsRemaining--)) {
        !           646: 
        !           647:                 FdDebugPrint(0x01, (0, "aborted.\n"));
        !           648: 
        !           649:                 DeviceExtension->ActiveLu->LuState = LS_COMPLETE;
        !           650:                 DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
        !           651:                                                         SRB_STATUS_TIMEOUT;
        !           652:             }
        !           653:         }
        !           654:     }
        !           655: } // end Fd8xxArbitrate()
        !           656: 
        !           657: 
        !           658: VOID
        !           659: Fd8xxSelect(
        !           660:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !           661:     )
        !           662: 
        !           663: /*++
        !           664: 
        !           665: Routine Description:
        !           666: 
        !           667:     Perform selection process on SCSI bus.
        !           668: 
        !           669: Arguments:
        !           670: 
        !           671:     DeviceExtension - Device adapter context pointer.
        !           672: 
        !           673: Return Value:
        !           674: 
        !           675:     None
        !           676: 
        !           677: --*/
        !           678: 
        !           679: {
        !           680:     FdDebugPrint(0x01,
        !           681:                   (0, "FdSelect: Device = %x, Target = %x ",
        !           682:                   DeviceExtension,
        !           683:                   DeviceExtension->ActiveLu->ActiveLuRequest->TargetId));
        !           684: 
        !           685:     //
        !           686:     // Raise Select line, keeping the BUSY line high.  Also, enable parity
        !           687:     // and tell the adapter to drive the SCSI data lines to prepare for
        !           688:     // outgoing ID bits.  Keep in mind that this also clears the
        !           689:     // C_ARBITRATION bit.
        !           690:     //
        !           691:     Fd8xxWriteControl(DeviceExtension,
        !           692:                       (C_SELECT | C_BUSY | C_BUS_ENABLE));
        !           693:     Fd8xxSetControl(DeviceExtension,
        !           694:                     C_PARITY_ENABLE);
        !           695: 
        !           696:     ScsiPortStallExecution(2);  // Delay 1200 nanoseconds (Bus-Settle + Bus-Clear).
        !           697: 
        !           698:     FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
        !           699:                      (1 << DeviceExtension->InitiatorId) |
        !           700:                      (1 << (DeviceExtension->ActiveLu->ActiveLuRequest->TargetId)));
        !           701: 
        !           702:     //
        !           703:     // Raise attention to get to message out phase.
        !           704:     //
        !           705:     Fd8xxSetControl(DeviceExtension,
        !           706:                     C_ATTENTION);
        !           707: 
        !           708:     ScsiPortStallExecution(1);  // Delay 90 nanoseconds (2 * Bus-Deskew).
        !           709: 
        !           710:     //
        !           711:     // Clear BUSY
        !           712:     //
        !           713:     Fd8xxClearControl(DeviceExtension,
        !           714:                       C_BUSY);
        !           715: 
        !           716:     ScsiPortStallExecution(1);  // Delay 400 nanoseconds (Bus-Settle).
        !           717: 
        !           718:     if (Fd8xxStatusCheck(DeviceExtension,
        !           719:                          S_BUSY,
        !           720:                          S_BUSY,
        !           721:                          SELECTION_DELAY)) {
        !           722: 
        !           723:         ScsiPortStallExecution(1);  // Delay 90 nanoseconds (2 * Bus-Deskew).
        !           724: 
        !           725:         //
        !           726:         // Selection is Ok.  Clear SELECT line.
        !           727:         //
        !           728:         Fd8xxClearControl(DeviceExtension,
        !           729:                           C_SELECT);
        !           730: 
        !           731:         DeviceExtension->ActiveLu->LuState = LS_IDENTIFY;
        !           732:         FdDebugPrint(0x01,
        !           733:                       (0, "SELECT OK %x\n",
        !           734:                       DeviceExtension->ActiveLu->ActiveLuRequest->TargetId));
        !           735:         return;
        !           736:     }
        !           737: 
        !           738:     //
        !           739:     // Selection failed.  Force SCSI bus back to Bus-Free.
        !           740:     //
        !           741:     Fd8xxWriteControl(DeviceExtension,
        !           742:                       C_PARITY_ENABLE);
        !           743: 
        !           744:     FdDebugPrint(0x01,
        !           745:                   (0, "SELECT FAILED %x\n",
        !           746:                   DeviceExtension->ActiveLu->ActiveLuRequest->TargetId));
        !           747: 
        !           748:     DeviceExtension->ActiveLu->LuState = LS_COMPLETE;
        !           749:     DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
        !           750:                                                 SRB_STATUS_SELECTION_TIMEOUT;
        !           751: } // end Fd8xxSelect()
        !           752: 
        !           753: 
        !           754: VOID
        !           755: Fd8xxSendIdentify(
        !           756:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !           757:     )
        !           758: 
        !           759: /*++
        !           760: 
        !           761: Routine Description:
        !           762: 
        !           763:     Send an identify message on the SCSI bus if the target will accept it.
        !           764: 
        !           765: Arguments:
        !           766: 
        !           767:     DeviceExtension - Device adapter context pointer.
        !           768: 
        !           769: Return Value:
        !           770: 
        !           771:     None
        !           772: 
        !           773: --*/
        !           774: 
        !           775: {
        !           776:     PUCHAR              baseAddress = DeviceExtension->BaseAddress;
        !           777:     PSCSI_REQUEST_BLOCK srb = DeviceExtension->ActiveLu->ActiveLuRequest;
        !           778: 
        !           779:     FdDebugPrint(0x02,
        !           780:                   (0, "FdSendIdentify: Device = %x, Lun = %x ",
        !           781:                   DeviceExtension,
        !           782:                   srb->Lun));
        !           783: 
        !           784:     if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
        !           785: 
        !           786:         ScsiPortLogError(DeviceExtension,
        !           787:                          DeviceExtension->ActiveLu->ActiveLuRequest,
        !           788:                          DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
        !           789:                          DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
        !           790:                          DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
        !           791:                          SP_REQUEST_TIMEOUT,
        !           792:                          12);
        !           793:         DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
        !           794:         return;
        !           795:     }
        !           796: 
        !           797:     if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
        !           798: 
        !           799:         Fd8xxWriteControl(DeviceExtension,
        !           800:                           (C_PARITY_ENABLE | C_BUS_ENABLE));
        !           801: 
        !           802:         ScsiPortStallExecution(1);  // Delay 90 nanoseconds (2 * Bus-Deskew).
        !           803: 
        !           804:         //
        !           805:         // The target may wish to negotiate synchronous with us, in which
        !           806:         // case we will reject the message and go on to COMMAND phase.
        !           807:         //
        !           808:         DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
        !           809: 
        !           810:     } else {
        !           811: 
        !           812:         //
        !           813:         // We still have an ABORT or RESET message to send, so keep the
        !           814:         // ATTENTION line high.
        !           815:         //
        !           816:         Fd8xxWriteControl(DeviceExtension,
        !           817:                           (C_PARITY_ENABLE | C_BUS_ENABLE | C_ATTENTION));
        !           818: 
        !           819:         DeviceExtension->ActiveLu->LuState = LS_MSG_SPECIAL;
        !           820:     }
        !           821: 
        !           822:     //
        !           823:     // Some old SCSI-I devices want to skip MESSAGE OUT phase and go
        !           824:     // directly to COMMAND phase.  We'll just let them do what they want.
        !           825:     // If the drive is really stupid, the error should get picked up in
        !           826:     // the phase to which it transitions, so just return and get on with
        !           827:     // life.
        !           828:     //
        !           829:     if (FD8XX_READ_PHASE(baseAddress) == BP_MESSAGE_OUT) {
        !           830: 
        !           831:         FdDebugPrint(0x02, (0, "IDENTIFY sent.\n"));
        !           832: 
        !           833:         if (srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) {
        !           834: 
        !           835:             DeviceExtension->ActiveLu->NoDisconnectActive = TRUE;
        !           836:             FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
        !           837:                              (SCSIMESS_IDENTIFY |
        !           838:                              srb->Lun));
        !           839:         } else {
        !           840: 
        !           841:             FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
        !           842:                              (SCSIMESS_IDENTIFY_WITH_DISCON |
        !           843:                              srb->Lun));
        !           844:         }
        !           845: 
        !           846:     } else {
        !           847: 
        !           848:         FdDebugPrint(0x02,
        !           849:                       (0, "IDENTIFY not sent %x\n",
        !           850:                       FD8XX_READ_STATUS(DeviceExtension->BaseAddress)));
        !           851: 
        !           852:         Fd8xxClearControl(DeviceExtension, C_ATTENTION);
        !           853:         ScsiPortStallExecution(1);  // Delay 90 nanoseconds (2 * Bus-Deskew).
        !           854: 
        !           855:         DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
        !           856:     }
        !           857: } // end Fd8xxSendIdentify()
        !           858: 
        !           859: 
        !           860: VOID
        !           861: Fd8xxSendSpecialMessage(
        !           862:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !           863:     )
        !           864: 
        !           865: /*++
        !           866: 
        !           867: Routine Description:
        !           868: 
        !           869:     Send an ABORT or RESET message on the SCSI bus if the target will accept
        !           870:     it.
        !           871: 
        !           872: Arguments:
        !           873: 
        !           874:     DeviceExtension - Device adapter context pointer.
        !           875: 
        !           876: Return Value:
        !           877: 
        !           878:     None
        !           879: 
        !           880: --*/
        !           881: 
        !           882: {
        !           883:     PUCHAR              baseAddress = DeviceExtension->BaseAddress;
        !           884:     PSCSI_REQUEST_BLOCK srb = DeviceExtension->ActiveLu->ActiveLuRequest;
        !           885: 
        !           886:     FdDebugPrint(0x02,
        !           887:                   (0, "FdSendSpecialMessage: Device = %x, Lun = %x ",
        !           888:                   DeviceExtension,
        !           889:                   srb->Lun));
        !           890: 
        !           891:     if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
        !           892: 
        !           893:         ScsiPortLogError(DeviceExtension,
        !           894:                          DeviceExtension->ActiveLu->ActiveLuRequest,
        !           895:                          DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
        !           896:                          DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
        !           897:                          DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
        !           898:                          SP_REQUEST_TIMEOUT,
        !           899:                          13);
        !           900:         DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
        !           901:         return;
        !           902:     }
        !           903: 
        !           904:     Fd8xxClearControl(DeviceExtension,
        !           905:                       C_ATTENTION);
        !           906:     ScsiPortStallExecution(1);  // Delay 90 nanoseconds (2 * Bus-Deskew).
        !           907: 
        !           908:     if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
        !           909: 
        !           910:         FdDebugPrint(0x02, (0, "ABORT\n"));
        !           911:         FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
        !           912:                          SCSIMESS_ABORT);
        !           913:     } else if (srb->Function == SRB_FUNCTION_RESET_DEVICE) {
        !           914: 
        !           915:         FdDebugPrint(0x02, (0, "BDR\n"));
        !           916:         FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
        !           917:                          SCSIMESS_BUS_DEVICE_RESET);
        !           918:     } else {
        !           919: 
        !           920:         ScsiPortLogError(DeviceExtension,
        !           921:                          srb,
        !           922:                          srb->PathId,
        !           923:                          srb->TargetId,
        !           924:                          srb->Lun,
        !           925:                          SP_PROTOCOL_ERROR,
        !           926:                          2);
        !           927: 
        !           928:         FdDebugPrint(0x02, (0, "NO-OP\n"));
        !           929:         FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
        !           930:                          SCSIMESS_NO_OPERATION);
        !           931:     }
        !           932: 
        !           933:     DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
        !           934: } // end Fd8xxSendSpecialMessage()
        !           935: 
        !           936: 
        !           937: VOID
        !           938: Fd8xxSendCDB(
        !           939:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !           940:     )
        !           941: 
        !           942: /*++
        !           943: 
        !           944: Routine Description:
        !           945: 
        !           946:     Send the SCSI Command Descriptor Block (CDB) to the indicated target/lun.
        !           947: 
        !           948: Arguments:
        !           949: 
        !           950:     DeviceExtension - Device adapter context pointer.
        !           951: 
        !           952: Return Value:
        !           953: 
        !           954:     None
        !           955: 
        !           956: --*/
        !           957: 
        !           958: {
        !           959:     UCHAR   cdbLength = DeviceExtension->ActiveLu->ActiveLuRequest->CdbLength;
        !           960:     PUCHAR  cdb = DeviceExtension->ActiveLu->ActiveLuRequest->Cdb;
        !           961:     PUCHAR  baseAddress = DeviceExtension->BaseAddress;
        !           962: 
        !           963:     FdDebugPrint(0x02, (0, "SendCommand: "));
        !           964: 
        !           965:     Fd8xxSetControl(DeviceExtension, C_BUS_ENABLE);
        !           966: 
        !           967:     while ((cdbLength-- != 0) &&
        !           968:            Fd8xxWaitForRequestLine(DeviceExtension) &&
        !           969:            (FD8XX_READ_PHASE(baseAddress) == BP_COMMAND)) {
        !           970: 
        !           971:         FdDebugPrint(0x02, (0, "%x ", *cdb));
        !           972: 
        !           973:         FD8XX_WRITE_DATA(baseAddress,
        !           974:                          *cdb++);
        !           975:     }
        !           976: 
        !           977:     DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
        !           978: 
        !           979:     //
        !           980:     // Set up the running data pointer info for a possible data transfer.
        !           981:     //
        !           982:     DeviceExtension->CurDataPointer = DeviceExtension->ActiveLu->SavedDataPointer;
        !           983:     DeviceExtension->CurDataLength = DeviceExtension->ActiveLu->SavedDataLength;
        !           984: 
        !           985:     FdDebugPrint(0x02, (0, "New phase=%x\n", FD8XX_READ_PHASE(baseAddress)));
        !           986: } // end Fd8xxSendCDB()
        !           987: 
        !           988: 
        !           989: VOID
        !           990: Fd8xxCopyData(
        !           991:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !           992:     )
        !           993: 
        !           994: /*++
        !           995: 
        !           996: Routine Description:
        !           997: 
        !           998:     Copy data byte-for-byte to and from adapter.  This is used to copy data
        !           999:     from the FD8XX controller to system memory and vice-versa.  Each
        !          1000:     iteration of the outer-most "while" loop will transfer MAX_BUFFER_LENGTH
        !          1001:     bytes (i.e., 512 bytes - this is the size of the TMC-950 memory-mapped
        !          1002:     SCSI data register), or any fraction thereof.
        !          1003: 
        !          1004:     In theory, one should be able to use the x86 REP MOVB instruction (or
        !          1005:     other equivalent) to "blast" 512 bytes of data to this register.  The
        !          1006:     REQ/ACK handshaking is done by the TMC-950 chip.  In practice, there is
        !          1007:     one problem.  The SCSI data register is "locked in" with the host bus
        !          1008:     (ISA).  This host bus cannot be tied up for longer than a memory refresh
        !          1009:     cycle (15 useconds, I think).  After completing a REQ/ACK cycle, the
        !          1010:     950 chip frees the bus, then locks it again waiting for the assertion
        !          1011:     SCSI REQ line by the target.  If REQ is not asserted within a memory
        !          1012:     refresh cycle, the 950 chip times out and frees the host bus so that a
        !          1013:     memory refresh can take place.  This puts the 950 chip one byte "ahead"
        !          1014:     of the target, thus screwing up the rest of the block transfer.
        !          1015: 
        !          1016:     Future Domain refers to this problem as the "dribbling drive" because
        !          1017:     the target delays the assertion of the SCSI REQ line for longer than
        !          1018:     usual (probably because the firmware did some maintenance task between
        !          1019:     bytes like filling or draining its internal FIFO).  SCSI places no
        !          1020:     limit on how long a target has to re-assert the SCSI REQ line, so we must
        !          1021:     provide a work-around.
        !          1022: 
        !          1023:     After a fair amount of research and experimentation, we have learned that
        !          1024:     "manually" handshaking the first x number of bytes, the last x number of
        !          1025:     bytes, or a combination of the two, solves the problem.  The determination
        !          1026:     of x in either case is purely trial-and-error and is based on device
        !          1027:     characteristics.
        !          1028: 
        !          1029: Arguments:
        !          1030: 
        !          1031:     DeviceExtension - Device adapter context pointer.
        !          1032: 
        !          1033: Return Value:
        !          1034: 
        !          1035:     None
        !          1036: 
        !          1037: --*/
        !          1038: 
        !          1039: {
        !          1040:     PUCHAR  baseAddress = DeviceExtension->BaseAddress;
        !          1041:     UCHAR   byteBucket = 0;
        !          1042:     UCHAR   wantedState;
        !          1043: 
        !          1044:     register ULONG   moveCount;
        !          1045:     register ULONG   headCount;
        !          1046:     register ULONG   tailCount;
        !          1047: 
        !          1048:     if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
        !          1049: 
        !          1050:         ScsiPortLogError(DeviceExtension,
        !          1051:                          DeviceExtension->ActiveLu->ActiveLuRequest,
        !          1052:                          DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
        !          1053:                          DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
        !          1054:                          DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
        !          1055:                          SP_REQUEST_TIMEOUT,
        !          1056:                          14);
        !          1057:         DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
        !          1058:         return;
        !          1059:     }
        !          1060: 
        !          1061:     wantedState = FD8XX_READ_PHASE(baseAddress);
        !          1062: 
        !          1063:     FdDebugPrint(0x04,
        !          1064:                   (0, "CopyData: from %s for %x ",
        !          1065:                   (wantedState == BP_DATA_IN) ? "Target" : "Memory",
        !          1066:                   DeviceExtension->CurDataLength));
        !          1067: 
        !          1068:     if (wantedState == BP_DATA_IN) {
        !          1069: 
        !          1070:         //
        !          1071:         // The target will drive the SCSI data lines in DATA_IN phase.
        !          1072:         //
        !          1073:         Fd8xxClearControl(DeviceExtension, C_BUS_ENABLE);
        !          1074:     } else {
        !          1075: 
        !          1076:         //
        !          1077:         // We will drive the SCSI data lines in DATA_OUT phase.
        !          1078:         //
        !          1079:         Fd8xxSetControl(DeviceExtension, C_BUS_ENABLE);
        !          1080:     }
        !          1081: 
        !          1082:     while (FD8XX_READ_PHASE(baseAddress) == wantedState) {
        !          1083: 
        !          1084:         if (DeviceExtension->CurDataLength == 0) {
        !          1085: 
        !          1086:             //
        !          1087:             // Overrun condition.  Read (or write) bytes until
        !          1088:             // out of DATA phase.
        !          1089:             //
        !          1090:             FdDebugPrint(0x04, (0, "overrun "));
        !          1091: 
        !          1092:             while ((FD8XX_READ_PHASE(baseAddress) == wantedState) &&
        !          1093:                     Fd8xxWaitForRequestLine(DeviceExtension)) {
        !          1094: 
        !          1095:                 FdDebugPrint(0x04, (0, "."));
        !          1096: 
        !          1097:                 if (wantedState == BP_DATA_IN) {
        !          1098: 
        !          1099:                     //
        !          1100:                     // Throw the byte away since there's nowhere to put it.
        !          1101:                     //
        !          1102:                     byteBucket = FD8XX_READ_DATA(baseAddress);
        !          1103:                 } else {
        !          1104: 
        !          1105:                     //
        !          1106:                     // Write a zero to the device.
        !          1107:                     //
        !          1108:                     FD8XX_WRITE_DATA(baseAddress, byteBucket);
        !          1109:                 }
        !          1110:             }
        !          1111: 
        !          1112:             DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
        !          1113:                                                     SRB_STATUS_DATA_OVERRUN;
        !          1114:             DeviceExtension->ActiveLu->OverRunCount++;
        !          1115:             if (DeviceExtension->ActiveLu->OverRunCount >= 5) {
        !          1116:                 FdDebugPrint(0x200, (0, "Fd8xx: Turned on handshake\n"));
        !          1117:                 DeviceExtension->ActiveLu->HandShakeAllData = TRUE;
        !          1118:             }
        !          1119:             continue;
        !          1120:         }
        !          1121: 
        !          1122:         //
        !          1123:         // First, copy the first bytes (if any) with REQ/ACK handshaking...
        !          1124:         //
        !          1125:         // NOTE:  Some devices are REALLY slow when transferring inquiry
        !          1126:         // data.  So, we'll treat any transfer less than a block
        !          1127:         // as a SLOW transfer.  Also, all transfers performed when
        !          1128:         // the DISABLE_DISCONNECT bit was on in the SRB are done in
        !          1129:         // the slower, handshake per byte way.  Finally some devices
        !          1130:         // tend to "dribble" bytes and need to have a handshake all
        !          1131:         // the time.  These are found by a threshold of overruns being
        !          1132:         // encountered above.  The single OR on the HandShake and SixByte
        !          1133:         // booleans is on purpose.  This generates an or and conditional
        !          1134:         // jump where a double OR generates more code.
        !          1135:         //
        !          1136:         if (((DeviceExtension->ActiveLu->NoDisconnectActive) &&
        !          1137:              (DeviceExtension->ActiveLu->OverRunCount != 0)) ||
        !          1138:             (DeviceExtension->ActiveLu->HandShakeAllData |
        !          1139:              DeviceExtension->ActiveLu->SixByteCDBActive)) {
        !          1140: 
        !          1141:             headCount = DeviceExtension->CurDataLength;
        !          1142:         } else {
        !          1143:             if (MAX_BUFFER_LENGTH > DeviceExtension->CurDataLength) {
        !          1144:     
        !          1145:                 headCount = DeviceExtension->CurDataLength;
        !          1146:             } else {
        !          1147:     
        !          1148:                 if (DeviceExtension->CurDataLength & (MAX_BUFFER_LENGTH - 1)) {
        !          1149:     
        !          1150:                     //
        !          1151:                     // If the expected transfer is not a block multiple, do it
        !          1152:                     // all the slow way.  This will correct problems with NEC
        !          1153:                     // CD drives when doing NEC CD audio commands.
        !          1154:                     //
        !          1155:                     headCount = DeviceExtension->CurDataLength;
        !          1156:                 } else {
        !          1157:                     headCount = min(MAX_HEAD_LENGTH,
        !          1158:                                     DeviceExtension->CurDataLength);
        !          1159:                 }
        !          1160:             }
        !          1161:         }
        !          1162: 
        !          1163:         moveCount = 0;
        !          1164: 
        !          1165:         while (moveCount != headCount) {
        !          1166: 
        !          1167:             if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
        !          1168:                 ScsiPortLogError(DeviceExtension,
        !          1169:                                  DeviceExtension->ActiveLu->ActiveLuRequest,
        !          1170:                                  DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
        !          1171:                                  DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
        !          1172:                                  DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
        !          1173:                                  SP_REQUEST_TIMEOUT,
        !          1174:                                  11);
        !          1175:                 break;
        !          1176:             }
        !          1177: 
        !          1178:             if (FD8XX_READ_PHASE(baseAddress) == BP_DATA_IN) {
        !          1179: 
        !          1180:                 *((PUCHAR) DeviceExtension->CurDataPointer++) =
        !          1181:                                             FD8XX_READ_DATA(baseAddress);
        !          1182:             } else if (FD8XX_READ_PHASE(baseAddress) == BP_DATA_OUT) {
        !          1183: 
        !          1184:                 FD8XX_WRITE_DATA(baseAddress,
        !          1185:                              *((PUCHAR) DeviceExtension->CurDataPointer++));
        !          1186:             } else {
        !          1187: 
        !          1188:                 //
        !          1189:                 // Account for the number of bytes moved.
        !          1190:                 //
        !          1191:                 DeviceExtension->CurDataLength -= moveCount;
        !          1192:                 goto Fd8xxCopyData_CheckNextPhase;
        !          1193:             }
        !          1194:             moveCount++;
        !          1195:         }
        !          1196: 
        !          1197:         DeviceExtension->CurDataLength -= moveCount;
        !          1198: 
        !          1199:         if (DeviceExtension->CurDataLength == 0) {
        !          1200:             goto Fd8xxCopyData_CheckNextPhase;
        !          1201:         }
        !          1202: 
        !          1203:         //
        !          1204:         // Now, calculate the the middle chunk for transfer without hanshaking...
        !          1205:         //
        !          1206:         moveCount = min(
        !          1207:             (DeviceExtension->CurDataLength & (MAX_BUFFER_LENGTH - 1)),
        !          1208:             MAX_BUFFER_LENGTH);
        !          1209: 
        !          1210:         if (moveCount >= MAX_TAIL_LENGTH) {
        !          1211: 
        !          1212:             moveCount -= MAX_TAIL_LENGTH;
        !          1213:         }
        !          1214: 
        !          1215:         if (wantedState == BP_DATA_IN) {
        !          1216: 
        !          1217:             ScsiPortReadRegisterBufferUchar((baseAddress + READ_SCSI),
        !          1218:                                       ((PUCHAR) DeviceExtension->CurDataPointer),
        !          1219:                                       moveCount);
        !          1220:         } else {
        !          1221: 
        !          1222:             ScsiPortWriteRegisterBufferUchar((baseAddress + WRITE_SCSI),
        !          1223:                                        ((PUCHAR) DeviceExtension->CurDataPointer),
        !          1224:                                        moveCount);
        !          1225:         }
        !          1226: 
        !          1227:         DeviceExtension->CurDataPointer += moveCount;
        !          1228:         DeviceExtension->CurDataLength -= moveCount;
        !          1229: 
        !          1230:         //
        !          1231:         // Finally, copy the last bytes (if any) with REQ/ACK handshaking...
        !          1232:         //
        !          1233:         tailCount = min(MAX_TAIL_LENGTH, DeviceExtension->CurDataLength);
        !          1234:         moveCount = 0;
        !          1235: 
        !          1236:         while ((moveCount != tailCount) &&
        !          1237:                (FD8XX_READ_PHASE(baseAddress) != BP_BUS_FREE) &&
        !          1238:                Fd8xxWaitForRequestLine(DeviceExtension)) {
        !          1239: 
        !          1240:             if (FD8XX_READ_PHASE(baseAddress) == BP_DATA_IN) {
        !          1241: 
        !          1242:                 *((PUCHAR) DeviceExtension->CurDataPointer++) =
        !          1243:                                             FD8XX_READ_DATA(baseAddress);
        !          1244:             } else if (FD8XX_READ_PHASE(baseAddress) == BP_DATA_OUT) {
        !          1245: 
        !          1246:                 FD8XX_WRITE_DATA(baseAddress,
        !          1247:                              *((PUCHAR) DeviceExtension->CurDataPointer++));
        !          1248:             } else {
        !          1249: 
        !          1250:                 DeviceExtension->CurDataLength -= moveCount;
        !          1251:                 goto Fd8xxCopyData_CheckNextPhase;
        !          1252:             }
        !          1253:             moveCount++;
        !          1254:         }
        !          1255: 
        !          1256:         DeviceExtension->CurDataLength -= moveCount;
        !          1257: 
        !          1258:         if ((FD8XX_READ_PHASE(baseAddress) == BP_BUS_FREE) ||
        !          1259:             (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE)) {
        !          1260: 
        !          1261:             DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
        !          1262:             FdDebugPrint(0x04, (0, "NO REQUEST\n"));
        !          1263:             return;
        !          1264:         }
        !          1265:     }
        !          1266: 
        !          1267: Fd8xxCopyData_CheckNextPhase:
        !          1268: 
        !          1269:     if (FD8XX_READ_PHASE(baseAddress) == BP_MESSAGE_IN) {
        !          1270: 
        !          1271:         //
        !          1272:         // The device most likely wants to disconnect.
        !          1273:         //
        !          1274:         DeviceExtension->ActiveLu->LuState = LS_MSG_IN;
        !          1275: 
        !          1276:     } else if (FD8XX_READ_PHASE(baseAddress) == BP_STATUS) {
        !          1277: 
        !          1278:         if (DeviceExtension->CurDataLength != 0) {
        !          1279: 
        !          1280:             //
        !          1281:             // We have an underrun condition.  Update the count of bytes transferred.
        !          1282:             //
        !          1283:             FdDebugPrint(0x04, (0, "underrun "));
        !          1284:             DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
        !          1285:                                                     SRB_STATUS_DATA_OVERRUN;
        !          1286:             DeviceExtension->ActiveLu->ActiveLuRequest->DataTransferLength -=
        !          1287:                 DeviceExtension->CurDataLength;
        !          1288:         } else if (FD8XX_READ_STATUS(baseAddress) & S_PARITY) {
        !          1289: 
        !          1290:             //
        !          1291:             // We have a parity error.
        !          1292:             //
        !          1293:             FdDebugPrint(0x04, (0, "Parity Error! "));
        !          1294:             DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
        !          1295:                                                     SRB_STATUS_PARITY_ERROR;
        !          1296:             ScsiPortLogError(DeviceExtension,
        !          1297:                              DeviceExtension->ActiveLu->ActiveLuRequest,
        !          1298:                              DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
        !          1299:                              DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
        !          1300:                              DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
        !          1301:                              SP_BUS_PARITY_ERROR,
        !          1302:                              3);
        !          1303:         }
        !          1304: 
        !          1305:         DeviceExtension->ActiveLu->LuState = LS_STATUS;
        !          1306: 
        !          1307:     } else {
        !          1308: 
        !          1309:         DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
        !          1310:         FdDebugPrint(0x04, (0, "OTHER\n"));
        !          1311:         return;
        !          1312:     }
        !          1313: 
        !          1314:     FdDebugPrint(0x04, (0, "Done\n"));
        !          1315: } // end Fd8xxCopyData()
        !          1316: 
        !          1317: 
        !          1318: VOID
        !          1319: Fd8xxStatus(
        !          1320:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !          1321:     )
        !          1322: 
        !          1323: /*++
        !          1324: 
        !          1325: Routine Description:
        !          1326: 
        !          1327:     This routine will obtain the status from the target.
        !          1328: 
        !          1329: Arguments:
        !          1330: 
        !          1331:     DeviceExtension - Device adapter context pointer.
        !          1332: 
        !          1333: Return Value:
        !          1334: 
        !          1335:     None
        !          1336: 
        !          1337: --*/
        !          1338: 
        !          1339: {
        !          1340:     UCHAR               status;
        !          1341:     UCHAR               srbStatus;
        !          1342:     PSCSI_REQUEST_BLOCK srb = DeviceExtension->ActiveLu->ActiveLuRequest;
        !          1343: 
        !          1344:     Fd8xxClearControl(DeviceExtension, C_BUS_ENABLE);
        !          1345: 
        !          1346:     if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
        !          1347: 
        !          1348:         DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
        !          1349:         ScsiPortLogError(DeviceExtension,
        !          1350:                          DeviceExtension->ActiveLu->ActiveLuRequest,
        !          1351:                          DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
        !          1352:                          DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
        !          1353:                          DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
        !          1354:                          SP_REQUEST_TIMEOUT,
        !          1355:                          17);
        !          1356:         return;
        !          1357:     }
        !          1358: 
        !          1359:     status = FD8XX_READ_DATA(DeviceExtension->BaseAddress);
        !          1360: 
        !          1361:     //
        !          1362:     // Save this away for the driver above.
        !          1363:     //
        !          1364:     srb->ScsiStatus = status;
        !          1365: 
        !          1366:     FdDebugPrint(0x02, (0, "FdStatus: Returned status byte=%x\n", status));
        !          1367: 
        !          1368:     switch (status) {
        !          1369: 
        !          1370:     case SCSISTAT_GOOD:
        !          1371:     case SCSISTAT_CONDITION_MET:
        !          1372:     case SCSISTAT_INTERMEDIATE:
        !          1373:     case SCSISTAT_INTERMEDIATE_COND_MET:
        !          1374: 
        !          1375:         srbStatus = SRB_STATUS_SUCCESS;
        !          1376:         break;
        !          1377: 
        !          1378:     case SCSISTAT_CHECK_CONDITION:
        !          1379:     case SCSISTAT_COMMAND_TERMINATED:
        !          1380: 
        !          1381:         srbStatus = SRB_STATUS_ERROR;
        !          1382:         break;
        !          1383: 
        !          1384:     case SCSISTAT_BUSY:
        !          1385:     case SCSISTAT_RESERVATION_CONFLICT:
        !          1386:     case SCSISTAT_QUEUE_FULL:
        !          1387:     default:
        !          1388: 
        !          1389:         srbStatus = SRB_STATUS_BUSY;
        !          1390:         break;
        !          1391:     }
        !          1392: 
        !          1393:     //
        !          1394:     // If some error condition already occurred (e.g., parity error), we'll
        !          1395:     // let that one take priority.
        !          1396:     //
        !          1397:     if (srb->SrbStatus == SRB_STATUS_PENDING)
        !          1398:         srb->SrbStatus = srbStatus;
        !          1399: 
        !          1400:     DeviceExtension->ActiveLu->LuState = LS_MSG_IN;
        !          1401: } // end Fd8xxStatus()
        !          1402: 
        !          1403: 
        !          1404: VOID
        !          1405: Fd8xxMessageIn(
        !          1406:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !          1407:     )
        !          1408: 
        !          1409: /*++
        !          1410: 
        !          1411: Routine Description:
        !          1412: 
        !          1413:     This routine will receive the message from the target.
        !          1414: 
        !          1415: Arguments:
        !          1416: 
        !          1417:     DeviceExtension - Device adapter context pointer.
        !          1418: 
        !          1419: Return Value:
        !          1420: 
        !          1421:     None
        !          1422: 
        !          1423: --*/
        !          1424: 
        !          1425: {
        !          1426:     PSPECIFIC_LU_EXTENSION  luExtension = DeviceExtension->ActiveLu;
        !          1427:     PSCSI_REQUEST_BLOCK     srb = luExtension->ActiveLuRequest;
        !          1428:     PUCHAR                  baseAddress = DeviceExtension->BaseAddress;
        !          1429:     UCHAR                   msg;
        !          1430: 
        !          1431:     Fd8xxClearControl(DeviceExtension,
        !          1432:                       C_BUS_ENABLE);
        !          1433: 
        !          1434:     luExtension->LuState = LS_UNDETERMINED;
        !          1435: 
        !          1436:     if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
        !          1437: 
        !          1438:         ScsiPortLogError(DeviceExtension,
        !          1439:                          DeviceExtension->ActiveLu->ActiveLuRequest,
        !          1440:                          DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
        !          1441:                          DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
        !          1442:                          DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
        !          1443:                          SP_REQUEST_TIMEOUT,
        !          1444:                          15);
        !          1445:         return;
        !          1446:     }
        !          1447: 
        !          1448:     msg = FD8XX_READ_DATA(baseAddress);
        !          1449: 
        !          1450:     FdDebugPrint(0x08, (0, "FdMessageIn: message=%x -- ", msg));
        !          1451: 
        !          1452:     if (msg == SCSIMESS_DISCONNECT) {
        !          1453: 
        !          1454:         FdDebugPrint(0x08, (0, "DISCONNECT\n"));
        !          1455: 
        !          1456:         luExtension->LuState = LS_DISCONNECTED;
        !          1457:         luExtension->SavedDataPointer = DeviceExtension->CurDataPointer;
        !          1458:         luExtension->SavedDataLength = DeviceExtension->CurDataLength;
        !          1459: 
        !          1460:         DeviceExtension->ActiveLu = NULL;
        !          1461: 
        !          1462:         if (DeviceExtension->ContinueTimer) {
        !          1463: 
        !          1464:             //
        !          1465:             // Still need the timer to insure interrupts.
        !          1466:             //
        !          1467:             DeviceExtension->ExpectingInterrupt = TRUE;
        !          1468:             ScsiPortNotification(RequestTimerCall,
        !          1469:                                  DeviceExtension,
        !          1470:                                  Fd8xxTimer,
        !          1471:                                  FD8xx_TIMER_VALUE);
        !          1472:         }
        !          1473: 
        !          1474:     } else if (msg == SCSIMESS_SAVE_DATA_POINTER) {
        !          1475: 
        !          1476:         FdDebugPrint(0x08, (0, "SAVE POINTERS\n"));
        !          1477: 
        !          1478:         luExtension->SavedDataPointer = DeviceExtension->CurDataPointer;
        !          1479:         luExtension->SavedDataLength = DeviceExtension->CurDataLength;
        !          1480: 
        !          1481:     } else if ((msg == SCSIMESS_COMMAND_COMPLETE) ||
        !          1482:                (msg == SCSIMESS_LINK_CMD_COMP) ||
        !          1483:                (msg == SCSIMESS_LINK_CMD_COMP_W_FLAG)) {
        !          1484: 
        !          1485:         FdDebugPrint(0x08, (0, "COMPLETION\n"));
        !          1486: 
        !          1487:         luExtension->LuState = LS_COMPLETE;
        !          1488: 
        !          1489:     } else if (msg == SCSIMESS_RESTORE_POINTERS) {
        !          1490: 
        !          1491:         FdDebugPrint(0x08, (0, "RESTORE POINTERS\n"));
        !          1492: 
        !          1493:         //
        !          1494:         // The Srb is already correct; just restore the adapter context
        !          1495:         // pointers.
        !          1496:         //
        !          1497:         DeviceExtension->CurDataPointer = luExtension->SavedDataPointer;
        !          1498:         DeviceExtension->CurDataLength = luExtension->SavedDataLength;
        !          1499: 
        !          1500:     } else if ((msg == SCSIMESS_NO_OPERATION) ||
        !          1501:                (msg == SCSIMESS_MESSAGE_REJECT)) {
        !          1502: 
        !          1503:         if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
        !          1504: 
        !          1505:             //
        !          1506:             // We may be talking to a stupid device that cannot handle an
        !          1507:             // identify message.  If this is the case, there's no telling
        !          1508:             // what it'll do next.  Just let it take us where it wants and
        !          1509:             // hope we can recover.
        !          1510:             //
        !          1511:             FdDebugPrint(0x08, (0, "Identify "));
        !          1512: 
        !          1513:         } else {
        !          1514: 
        !          1515:             //
        !          1516:             // We were trying to tell the device to abort or reset and it
        !          1517:             // puked on the message.  It's probably some old device that
        !          1518:             // cannot support these messages.  So, just let the device take
        !          1519:             // us where it wants.  If it's to cammand phase, we'll error this
        !          1520:             // out since there are no command bytes are associated w/ these
        !          1521:             // messages.  Hopefully, it'll at least take us back to bus free.
        !          1522:             //
        !          1523:             srb->SrbStatus = SRB_STATUS_MESSAGE_REJECTED;
        !          1524:             FdDebugPrint(0x08, (0, "Abort/Reset "));
        !          1525:         }
        !          1526: 
        !          1527:         FdDebugPrint(0x08, (0, "REJECT\n"));
        !          1528: 
        !          1529:     } else if (msg == SCSIMESS_EXTENDED_MESSAGE) {
        !          1530: 
        !          1531:         UCHAR   xMsgType;
        !          1532:         UCHAR   xMsgLength;
        !          1533: 
        !          1534:         FdDebugPrint(0x08, (0, "EXTENDED "));
        !          1535: 
        !          1536:         if (Fd8xxStatusCheck(DeviceExtension,
        !          1537:                              BP_MESSAGE_IN,
        !          1538:                              BP_MESSAGE_IN,
        !          1539:                              REQUEST_SPIN_WAIT)) {
        !          1540: 
        !          1541:             xMsgLength = FD8XX_READ_DATA(baseAddress);
        !          1542:             FdDebugPrint(0x08, (0, "length=%x ", xMsgLength));
        !          1543: 
        !          1544:         } else {
        !          1545: 
        !          1546:             //
        !          1547:             // This better NEVER happen!  If it does, this device is
        !          1548:             // BRAINDEAD!!
        !          1549:             //
        !          1550:             goto Fd8xxMessageIn_PhaseSequenceFailure;
        !          1551:         }
        !          1552: 
        !          1553:         if (Fd8xxStatusCheck(DeviceExtension,
        !          1554:                              BP_MESSAGE_IN,
        !          1555:                              BP_MESSAGE_IN,
        !          1556:                              REQUEST_SPIN_WAIT)) {
        !          1557: 
        !          1558:             xMsgType = FD8XX_READ_DATA(baseAddress);
        !          1559:         } else {
        !          1560: 
        !          1561:             goto Fd8xxMessageIn_PhaseSequenceFailure;
        !          1562:         }
        !          1563: 
        !          1564:         xMsgLength--;    // Received one of the bytes.
        !          1565: 
        !          1566:         if (xMsgType == SCSIMESS_MODIFY_DATA_POINTER) {
        !          1567: 
        !          1568:             LONG offset = 0;
        !          1569: 
        !          1570:             FdDebugPrint(0x08, (0, "MODIFY "));
        !          1571:             while (xMsgLength-- != 0) {
        !          1572: 
        !          1573:                 if (Fd8xxStatusCheck(DeviceExtension,
        !          1574:                                      BP_MESSAGE_IN,
        !          1575:                                      BP_MESSAGE_IN,
        !          1576:                                      REQUEST_SPIN_WAIT)) {
        !          1577: 
        !          1578:                     *(((PUCHAR) &(offset)) + (3 - xMsgLength)) =
        !          1579:                                                 FD8XX_READ_DATA(baseAddress);
        !          1580:                 } else {
        !          1581: 
        !          1582:                     goto Fd8xxMessageIn_PhaseSequenceFailure;
        !          1583:                 }
        !          1584:             }
        !          1585: 
        !          1586:             //
        !          1587:             // All message bytes for this message were read.  We can now
        !          1588:             // go and update our pointers as indicated by the juse-read
        !          1589:             // message.  Keep in mind that the value of offset is a twos-
        !          1590:             // compliment value (i.e., negative).
        !          1591:             //
        !          1592:             FdDebugPrint(0x08, (0, "offset=%x\n", offset));
        !          1593:             DeviceExtension->CurDataPointer += offset;
        !          1594:             DeviceExtension->CurDataLength -= offset;
        !          1595: 
        !          1596:         } else {
        !          1597: 
        !          1598:             goto Fd8xxMessageIn_NotImplemented;
        !          1599:         }
        !          1600: 
        !          1601:     } else {
        !          1602: 
        !          1603: Fd8xxMessageIn_NotImplemented:
        !          1604: 
        !          1605:         FdDebugPrint(0x08, (0, "NOT IMPLEMENTED\n"));
        !          1606: 
        !          1607:         Fd8xxSetControl(DeviceExtension, C_ATTENTION);
        !          1608:         ScsiPortStallExecution(1);  // Delay 90 nanoseconds (2 * Bus-Deskew).
        !          1609: 
        !          1610:         while (Fd8xxWaitForRequestLine(DeviceExtension) &&
        !          1611:                (FD8XX_READ_PHASE(baseAddress) == BP_MESSAGE_IN)) {
        !          1612: 
        !          1613:             //
        !          1614:             // Ignore the rest of this message.
        !          1615:             //
        !          1616:             msg = FD8XX_READ_DATA(baseAddress);
        !          1617:         }
        !          1618: 
        !          1619:         if (FD8XX_READ_PHASE(baseAddress) == BP_MESSAGE_OUT) {
        !          1620: 
        !          1621:             Fd8xxSetControl(DeviceExtension, C_BUS_ENABLE);
        !          1622:             Fd8xxClearControl(DeviceExtension, C_ATTENTION);
        !          1623:             ScsiPortStallExecution(1);  // Delay 90 nanoseconds.
        !          1624:             FD8XX_WRITE_DATA(baseAddress, SCSIMESS_MESSAGE_REJECT);
        !          1625:         }
        !          1626: 
        !          1627:         Fd8xxClearControl(DeviceExtension, C_ATTENTION);
        !          1628:     }
        !          1629: 
        !          1630:     return;
        !          1631: 
        !          1632: Fd8xxMessageIn_PhaseSequenceFailure:
        !          1633: 
        !          1634:     srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
        !          1635:     ScsiPortLogError(DeviceExtension,
        !          1636:                      srb,
        !          1637:                      srb->PathId,
        !          1638:                      srb->TargetId,
        !          1639:                      srb->Lun,
        !          1640:                      SP_PROTOCOL_ERROR,
        !          1641:                      4);
        !          1642: 
        !          1643:     FdDebugPrint(0x08,
        !          1644:                 (0,
        !          1645:                 "PHS SEQ ERROR=%x\n",
        !          1646:                 FD8XX_READ_DATA(baseAddress)));
        !          1647:     return;
        !          1648: 
        !          1649: } // end Fd8xxMessageIn()
        !          1650: 
        !          1651: 
        !          1652: VOID
        !          1653: Fd8xxNotifyCompletion(
        !          1654:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !          1655:     )
        !          1656: 
        !          1657: /*++
        !          1658: 
        !          1659: Routine Description:
        !          1660: 
        !          1661:     This routine will perform any clean up operations for the Srb
        !          1662:     and notify the ScsiPort driver of completion.
        !          1663: 
        !          1664: Arguments:
        !          1665: 
        !          1666:     DeviceExtension - Device adapter context pointer.
        !          1667: 
        !          1668: Return Value:
        !          1669: 
        !          1670:     None
        !          1671: 
        !          1672: --*/
        !          1673: 
        !          1674: {
        !          1675:     PSPECIFIC_LU_EXTENSION     luExtension = DeviceExtension->ActiveLu;
        !          1676:     PSCSI_REQUEST_BLOCK        srb = luExtension->ActiveLuRequest;
        !          1677: 
        !          1678:     FdDebugPrint(0x110,
        !          1679:          (0, "FdComplete Dev = %x, Srb = %x, Srbstat = %x, Scsistat = %x\n",
        !          1680:              DeviceExtension,
        !          1681:              srb,
        !          1682:              srb->SrbStatus,
        !          1683:              srb->ScsiStatus));
        !          1684: 
        !          1685:     if (srb != NULL) {
        !          1686:         if (srb->SrbStatus == SRB_STATUS_PENDING) {
        !          1687:         
        !          1688:             srb->SrbStatus = SRB_STATUS_ERROR;
        !          1689:             ScsiPortLogError(DeviceExtension,
        !          1690:                     luExtension->ActiveLuRequest,
        !          1691:                     luExtension->ActiveLuRequest->PathId,
        !          1692:                     luExtension->ActiveLuRequest->TargetId,
        !          1693:                     luExtension->ActiveLuRequest->Lun,
        !          1694:                     SP_INTERNAL_ADAPTER_ERROR,
        !          1695:                     5);
        !          1696:         }
        !          1697:     }
        !          1698: 
        !          1699:     luExtension->ActiveLuRequest = NULL;
        !          1700:     luExtension->NoDisconnectActive = FALSE;
        !          1701:     DeviceExtension->ActiveLu = NULL;
        !          1702: 
        !          1703:     //
        !          1704:     // Call notification routine.
        !          1705:     //
        !          1706:     if (srb != NULL) {
        !          1707:         ScsiPortNotification(RequestComplete,
        !          1708:                              (PVOID) DeviceExtension,
        !          1709:                              srb);
        !          1710:     }
        !          1711: 
        !          1712:     if (!(luExtension->AbortBeingAttempted)) {
        !          1713: 
        !          1714:         //
        !          1715:         // Adapter ready for next request.
        !          1716:         //
        !          1717:         ScsiPortNotification(NextRequest,
        !          1718:                              DeviceExtension,
        !          1719:                              NULL);
        !          1720:     }
        !          1721: 
        !          1722: } // end Fd8xxNotifyCompletion()
        !          1723: 
        !          1724: 
        !          1725: VOID
        !          1726: Fd8xxRunPhase(
        !          1727:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !          1728:     )
        !          1729: 
        !          1730: /*++
        !          1731: 
        !          1732: Routine Description:
        !          1733: 
        !          1734:     This routine runs through the bus phases until some type of completion
        !          1735:     indication is received.  This can be when a message informing the host
        !          1736:     that the target will be disconnecting is received or when the SCSI bus
        !          1737:     goes to a free state.
        !          1738: 
        !          1739: Arguments:
        !          1740: 
        !          1741:     DeviceExtension - Device adapter context pointer.
        !          1742: 
        !          1743: Return Value:
        !          1744: 
        !          1745:     None.
        !          1746: 
        !          1747: --*/
        !          1748: 
        !          1749: {
        !          1750:     PUCHAR  baseAddress = DeviceExtension->BaseAddress;
        !          1751:     ULONG   undetermined = 0;
        !          1752: 
        !          1753:     while (DeviceExtension->ActiveLu != NULL) {
        !          1754: 
        !          1755:         switch (DeviceExtension->ActiveLu->LuState) {
        !          1756: 
        !          1757:         case LS_UNDETERMINED:
        !          1758:             Fd8xxDetermineNextState(DeviceExtension);
        !          1759: 
        !          1760:             if (undetermined++ == REQUEST_SPIN_WAIT) {
        !          1761: 
        !          1762:                 //
        !          1763:                 // Some CD-ROM drives like to be SCSI bus hogs
        !          1764:                 // and hold the SCSI bus in COMMAND phase while feching
        !          1765:                 // data (they also conveniently skip message out phase
        !          1766:                 // so you can't tell it that you allow disconnect)!!  So,
        !          1767:                 // we better not time out if this happens.
        !          1768:                 //
        !          1769:                 if ((FD8XX_READ_PHASE(baseAddress) | S_REQUEST) !=
        !          1770:                                                             BP_COMMAND) {
        !          1771:                     FdDebugPrint(0x01, (0, "NO REQUEST\n"));
        !          1772: 
        !          1773:                     DeviceExtension->ActiveLu->LuState = LS_COMPLETE;
        !          1774:                     DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
        !          1775:                                             SRB_STATUS_PHASE_SEQUENCE_FAILURE;
        !          1776:     
        !          1777:                     ScsiPortLogError(DeviceExtension,
        !          1778:                             DeviceExtension->ActiveLu->ActiveLuRequest,
        !          1779:                             DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
        !          1780:                             DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
        !          1781:                             DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
        !          1782:                             SP_PROTOCOL_ERROR,
        !          1783:                             16);
        !          1784:                 }
        !          1785:             }
        !          1786:             break;
        !          1787: 
        !          1788:         case LS_ARBITRATE:
        !          1789:             Fd8xxArbitrate(DeviceExtension);
        !          1790:             break;
        !          1791: 
        !          1792:         case LS_SELECT:
        !          1793:             Fd8xxSelect(DeviceExtension);
        !          1794:             break;
        !          1795: 
        !          1796:         case LS_IDENTIFY:
        !          1797:             Fd8xxSendIdentify(DeviceExtension);
        !          1798:             break;
        !          1799: 
        !          1800:         case LS_MSG_SPECIAL:
        !          1801:             Fd8xxSendSpecialMessage(DeviceExtension);
        !          1802:             break;
        !          1803: 
        !          1804:         case LS_COMMAND:
        !          1805:             Fd8xxSendCDB(DeviceExtension);
        !          1806:             break;
        !          1807: 
        !          1808:         case LS_DATA:
        !          1809:             Fd8xxCopyData(DeviceExtension);
        !          1810:             break;
        !          1811: 
        !          1812:         case LS_STATUS:
        !          1813:             Fd8xxStatus(DeviceExtension);
        !          1814:             break;
        !          1815: 
        !          1816:         case LS_MSG_IN:
        !          1817:             Fd8xxMessageIn(DeviceExtension);
        !          1818:             break;
        !          1819: 
        !          1820:         case LS_COMPLETE:
        !          1821:             Fd8xxNotifyCompletion(DeviceExtension);
        !          1822:             break;
        !          1823: 
        !          1824:         default:
        !          1825: 
        !          1826:             DeviceExtension->ActiveLu->LuState = LS_COMPLETE;
        !          1827:             DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
        !          1828:                                     SRB_STATUS_PHASE_SEQUENCE_FAILURE;
        !          1829: 
        !          1830:             ScsiPortLogError(DeviceExtension,
        !          1831:                     DeviceExtension->ActiveLu->ActiveLuRequest,
        !          1832:                     DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
        !          1833:                     DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
        !          1834:                     DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
        !          1835:                     SP_PROTOCOL_ERROR,
        !          1836:                     6);
        !          1837:             break;
        !          1838:         }
        !          1839:     }
        !          1840: } // end Fd8xxRunPhase()
        !          1841: 
        !          1842: 
        !          1843: VOID
        !          1844: Fd8xxReenableAdapterInterrupts(
        !          1845:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !          1846:     )
        !          1847: /*++
        !          1848: 
        !          1849: Routine Description:
        !          1850: 
        !          1851:     This routine doesn't really do anything.  It is here to keep the
        !          1852:     SCSI port driver happy about what it can do with interrupts.
        !          1853:     The only time we should enable interrupts on selection is when we
        !          1854:     get a disconnect from a target.
        !          1855: 
        !          1856: Arguments:
        !          1857: 
        !          1858:     DeviceExtension - Device adapter context pointer.
        !          1859: 
        !          1860: Return Value:
        !          1861: 
        !          1862:     None.
        !          1863: 
        !          1864: --*/
        !          1865: 
        !          1866: {
        !          1867:     //
        !          1868:     // Re-enable interrupts on selection.
        !          1869:     //
        !          1870:     Fd8xxSetControl(DeviceExtension, C_INT_ENABLE);
        !          1871: 
        !          1872: } // end Fd8xxReenableAdapterInterrupts()
        !          1873: 
        !          1874: 
        !          1875: VOID
        !          1876: Fd8xxDoReconnect(
        !          1877:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !          1878:     )
        !          1879: 
        !          1880: /*++
        !          1881: 
        !          1882: Routine Description:
        !          1883: 
        !          1884:     This routine handles reconnecting devices.  It basically plucks the
        !          1885:     target ID out of reselection phase, followed by the LUN out of
        !          1886:     message in phase (from the IDENTIFY message).  Then, after validating
        !          1887:     the target/lun combination, starts up the state machine again for
        !          1888:     the reconnecting device.
        !          1889: 
        !          1890:     This routine should be called with interrupts enabled.
        !          1891: 
        !          1892: Arguments:
        !          1893: 
        !          1894:     DeviceExtension - Device adapter context pointer.
        !          1895: 
        !          1896: Return Value:
        !          1897: 
        !          1898:     None.
        !          1899: 
        !          1900: --*/
        !          1901: 
        !          1902: {
        !          1903:     PUCHAR                  baseAddress = DeviceExtension->BaseAddress;
        !          1904:     PSPECIFIC_LU_EXTENSION  luExtension;
        !          1905:     USHORT                  busFreeTimeout;
        !          1906:     UCHAR                   target;         // bit value returned from target
        !          1907:     UCHAR                   targetID;       // numeric value of target ID.
        !          1908:     UCHAR                   lunID;          // numeric value of LUN ID.
        !          1909: 
        !          1910:     //
        !          1911:     // Wait for the target to drop busy, which is the TRUE beginning of
        !          1912:     // reselection phase.  If BUSY is not dropped within the indicated time,
        !          1913:     // abort the interrupt (and the reselect).
        !          1914:     //
        !          1915:     if (Fd8xxStatusCheck(DeviceExtension,
        !          1916:                          BP_RESELECT,
        !          1917:                          BP_RESELECT,
        !          1918:                          RESELECTION_WAIT) == FALSE) {
        !          1919: 
        !          1920:         FdDebugPrint(0x20,
        !          1921:                      (0, "BUSY not dropped: Status=%x\n",
        !          1922:                      FD8XX_READ_STATUS(baseAddress)));
        !          1923: 
        !          1924:         goto Fd8xxDoReconnect_InvalidReselection;
        !          1925:     }
        !          1926: 
        !          1927:     //
        !          1928:     // Delay a bit to allow for something close to a bus settle time
        !          1929:     // before reading the target id bits.
        !          1930:     //
        !          1931:     ScsiPortStallExecution(1);
        !          1932: 
        !          1933:     //
        !          1934:     // Try to figure out who is reselecting.
        !          1935:     //
        !          1936:     target = (FD8XX_READ_DATA(baseAddress) & ~(1 << DeviceExtension->InitiatorId));
        !          1937: 
        !          1938:     FdDebugPrint(0x20, (0, "Target data=%x ", target));
        !          1939: 
        !          1940:     //
        !          1941:     // Convert the bit oriented target into a number.
        !          1942:     //
        !          1943:     for (targetID = ((UCHAR) -1); target != 0; target >>= 1) {
        !          1944: 
        !          1945:         targetID++;
        !          1946:     }
        !          1947:     FdDebugPrint(0x20, (0, "Target Id=%x ", targetID));
        !          1948: 
        !          1949:     //
        !          1950:     // Answer the reselection by raising busy.  This should cause the target
        !          1951:     // to transition to MESSAGE IN phase so that we cen figure out which LUN
        !          1952:     // is associated with the reselecting target.
        !          1953:     //
        !          1954:     ScsiPortStallExecution(1);  // Delay 400 nanoseconds (Bus-Settle).
        !          1955:     Fd8xxSetControl(DeviceExtension, C_BUSY);
        !          1956: 
        !          1957:     if (Fd8xxStatusCheck(DeviceExtension,
        !          1958:                          BP_MESSAGE_IN,
        !          1959:                          BP_MESSAGE_IN,
        !          1960:                          REQUEST_SPIN_WAIT) == FALSE) {
        !          1961: 
        !          1962:         FdDebugPrint(0x20,
        !          1963:                      (0, "REQ not raised: Status=%x\n",
        !          1964:                      FD8XX_READ_STATUS(baseAddress)));
        !          1965: 
        !          1966:         goto Fd8xxDoReconnect_InvalidReselection;
        !          1967:     }
        !          1968: 
        !          1969:     //
        !          1970:     // The target should be driving BUSY now, so we should de-assert it in
        !          1971:     // control register (keep in mind that BUSY is or-tied).
        !          1972:     //
        !          1973:     Fd8xxClearControl(DeviceExtension, C_BUSY);
        !          1974: 
        !          1975:     lunID = FD8XX_READ_DATA(baseAddress) & (SCSI_MAXIMUM_LOGICAL_UNITS - 1);
        !          1976:     FdDebugPrint(0x20, (0, "Lun Id=%x ", lunID));
        !          1977: 
        !          1978:     if ((targetID >= SCSI_MAXIMUM_TARGETS) ||
        !          1979:         (lunID >= SCSI_MAXIMUM_LOGICAL_UNITS)) {
        !          1980: 
        !          1981:         FdDebugPrint(0x20,
        !          1982:                      (0, "BAD Target/Lun: %x/%x\n",
        !          1983:                      targetID, lunID));
        !          1984: 
        !          1985:         goto Fd8xxDoReconnect_InvalidReselection;
        !          1986:     }
        !          1987: 
        !          1988:     //
        !          1989:     // Re-enable adapter interrupts.  Don't do this if we're being called
        !          1990:     // by the arbitration routine, because they will never have been turned
        !          1991:     // off in the first place, and we'll only confuse the port driver.
        !          1992:     //
        !          1993:     if (DeviceExtension->SavedLu == NULL) {
        !          1994: 
        !          1995:         ScsiPortNotification(CallDisableInterrupts,
        !          1996:                              DeviceExtension,
        !          1997:                              Fd8xxReenableAdapterInterrupts);
        !          1998:     }
        !          1999: 
        !          2000:     luExtension = ScsiPortGetLogicalUnit(DeviceExtension,
        !          2001:                                          DeviceExtension->PathId,
        !          2002:                                          targetID,
        !          2003:                                          lunID);
        !          2004: 
        !          2005:     if (luExtension == NULL) {
        !          2006: 
        !          2007:         //
        !          2008:         // This is the pathological case.  This would indicate that when
        !          2009:         // the target ID bits were read there was a parity error or some
        !          2010:         // other problem that made it look like a reselection from a phantom
        !          2011:         // device.
        !          2012:         //
        !          2013: 
        !          2014:         ScsiPortLogError(DeviceExtension,
        !          2015:                          NULL,
        !          2016:                          0,
        !          2017:                          0,
        !          2018:                          0,
        !          2019:                          SP_INVALID_RESELECTION,
        !          2020:                          (0x07 << 16) | (targetID << 8) | lunID);
        !          2021:         Fd8xxResetBus(DeviceExtension, DeviceExtension->PathId);
        !          2022:         ScsiPortNotification(ResetDetected, DeviceExtension, NULL);
        !          2023:         return;
        !          2024:     }
        !          2025: 
        !          2026:     if (luExtension->ActiveLuRequest == NULL) {
        !          2027: 
        !          2028:         //
        !          2029:         // This reconnect is not expected.  There is no request for the
        !          2030:         // device.
        !          2031:         //
        !          2032:         ScsiPortLogError(DeviceExtension,
        !          2033:                          NULL,
        !          2034:                          0,
        !          2035:                          0,
        !          2036:                          0,
        !          2037:                          SP_INVALID_RESELECTION,
        !          2038:                          (0x17 << 16) | (targetID << 8) | lunID);
        !          2039:         Fd8xxResetBus(DeviceExtension, DeviceExtension->PathId);
        !          2040:         ScsiPortNotification(ResetDetected, DeviceExtension, NULL);
        !          2041:         return;
        !          2042:     }
        !          2043: 
        !          2044:     if ((luExtension->AbortBeingAttempted) &&
        !          2045:         (DeviceExtension->SavedLu != NULL)) {
        !          2046: 
        !          2047:         //
        !          2048:         // We're being called while trying to arbitrate for an abort.
        !          2049:         // The LUN we're trying to abort is reconnecting, so complete the
        !          2050:         // abort from here, and force the arbitration routine to exit.
        !          2051:         //
        !          2052:         DeviceExtension->SavedLu->LuState = LS_COMPLETE;
        !          2053:         DeviceExtension->SavedLu->ActiveLuRequest->SrbStatus = SRB_STATUS_SUCCESS;
        !          2054:         goto Fd8xxDoReconnect_AbortReconnect;
        !          2055:     }
        !          2056: 
        !          2057:     DeviceExtension->CurDataPointer = luExtension->SavedDataPointer;
        !          2058:     DeviceExtension->CurDataLength  = luExtension->SavedDataLength;
        !          2059:     DeviceExtension->ActiveLu = luExtension;
        !          2060: 
        !          2061:     luExtension->LuState = LS_UNDETERMINED;
        !          2062: 
        !          2063:     Fd8xxRunPhase(DeviceExtension);
        !          2064: 
        !          2065:     return;
        !          2066: 
        !          2067: Fd8xxDoReconnect_InvalidReselection:
        !          2068: 
        !          2069:     ScsiPortLogError(DeviceExtension,
        !          2070:                      NULL,
        !          2071:                      0,
        !          2072:                      0,
        !          2073:                      0,
        !          2074:                      SP_INVALID_RESELECTION,
        !          2075:                      (0x27 << 16) | (targetID << 8) | lunID);
        !          2076: 
        !          2077:     if (DeviceExtension->SavedLu == NULL) {
        !          2078: 
        !          2079:         ScsiPortNotification(CallDisableInterrupts,
        !          2080:                              DeviceExtension,
        !          2081:                              Fd8xxReenableAdapterInterrupts);
        !          2082:     }
        !          2083: 
        !          2084: Fd8xxDoReconnect_AbortReconnect:
        !          2085: 
        !          2086:     //
        !          2087:     // Attempt to send an abort message to the target.
        !          2088:     //
        !          2089:     Fd8xxSetControl(DeviceExtension, C_ATTENTION);
        !          2090:     ScsiPortStallExecution(1);  // Delay 90 nanoseconds (2 * Bus-Deskew).
        !          2091: 
        !          2092:     while (Fd8xxWaitForRequestLine(DeviceExtension) &&
        !          2093:            (FD8XX_READ_PHASE(baseAddress) != BP_MESSAGE_OUT)) {
        !          2094: 
        !          2095:         FD8XX_READ_DATA(baseAddress);
        !          2096:     }
        !          2097: 
        !          2098:     Fd8xxSetControl(DeviceExtension, C_BUS_ENABLE);
        !          2099:     Fd8xxClearControl(DeviceExtension, C_ATTENTION);
        !          2100:     ScsiPortStallExecution(1);  // Delay 90 nanoseconds.
        !          2101: 
        !          2102:     if (FD8XX_READ_PHASE(baseAddress) == BP_MESSAGE_OUT) {
        !          2103: 
        !          2104:         FD8XX_WRITE_DATA(baseAddress, SCSIMESS_ABORT);
        !          2105:     }
        !          2106: 
        !          2107:     Fd8xxClearControl(DeviceExtension, C_BUS_ENABLE);
        !          2108: 
        !          2109:     busFreeTimeout = 2048;
        !          2110:     while ((FD8XX_READ_PHASE(baseAddress) & S_BUSY) && (busFreeTimeout--)) {
        !          2111: 
        !          2112:         if (FD8XX_READ_PHASE(baseAddress) & S_REQUEST) {
        !          2113: 
        !          2114:             FD8XX_READ_DATA(baseAddress);
        !          2115:         } else {
        !          2116: 
        !          2117:             ScsiPortStallExecution(100);
        !          2118:         }
        !          2119:     }
        !          2120: 
        !          2121:     if (FD8XX_READ_PHASE(baseAddress) != BP_BUS_FREE) {
        !          2122: 
        !          2123:         //
        !          2124:         // Reset SCSI bus.  Drastic measures for drastic times...
        !          2125:         //
        !          2126:         Fd8xxResetBus(DeviceExtension, DeviceExtension->PathId);
        !          2127:         ScsiPortNotification(ResetDetected, DeviceExtension, NULL);
        !          2128:     }
        !          2129: } // end Fd8xxDoReconnect()
        !          2130: 
        !          2131: 
        !          2132: VOID
        !          2133: Fd8xxTimer(
        !          2134:     IN PVOID Context
        !          2135:     )
        !          2136: 
        !          2137: /*++
        !          2138: 
        !          2139: Routine Description:
        !          2140: 
        !          2141:     This routine is used to monitor interrupts from the Fd8xx adapter.
        !          2142:     The ScsiPort support for a timer is used when a disconnect message is
        !          2143:     received to schedule this routine as a timer for later execution.  If
        !          2144:     this routine is invoked before the interrupt and the adapter is attempting
        !          2145:     to select, then it is assumed that the adapter is on a different IRQ then
        !          2146:     expected and operation will continue in a "polling" mode.  If the actual
        !          2147:     interrupt occurs before this routine is called, then everything is ok
        !          2148:     and this routine need not reschedule itself.
        !          2149: 
        !          2150:     Operation when called is to see if the actual interrupt routine serviced
        !          2151:     the interrupt.  If so, then mark the device extension such that this
        !          2152:     routine is not rescheduled and return.  If the actual interrupt routine
        !          2153:     has not serviced the interrupt and the adapter is indicating that a
        !          2154:     reselection is being attempted, then call the interrupt routine to service
        !          2155:     the interrupt and continue scheduling this routine.  Lastly, if the
        !          2156:     interrupt routine has not serviced the interrupt and the adapter is not
        !          2157:     indicating a reselection, schedule another timer.
        !          2158: 
        !          2159: Arguments:
        !          2160: 
        !          2161:     Context - Device adapter context pointer.
        !          2162: 
        !          2163: Return Value
        !          2164: 
        !          2165:     TRUE indicates that the interrupt was from this Fd8xx adapter,
        !          2166:     FALSE indicates that this interrupt was NOT from us.
        !          2167: 
        !          2168: --*/
        !          2169: 
        !          2170: {
        !          2171:     PSPECIFIC_DEVICE_EXTENSION deviceExtension = Context;
        !          2172:     BOOLEAN                    restartTimer = TRUE;
        !          2173: 
        !          2174:     if (deviceExtension->ExpectingInterrupt == FALSE) {
        !          2175: 
        !          2176:         //
        !          2177:         // The interrupt routine got the interrupt.  Decrement the number
        !          2178:         // of times to continue scheduling a timer routine.
        !          2179:         //
        !          2180:         deviceExtension->ContinueTimer--;
        !          2181:         return;
        !          2182:     }
        !          2183: 
        !          2184:     if (Fd8xxStatusCheck(deviceExtension, S_SELECT, S_SELECT, 1)) {
        !          2185: 
        !          2186:         //
        !          2187:         // If the interrupt routine does not claim this interrupt for some
        !          2188:         // reason, restart the timer.  If it does claim the interrupt, shut
        !          2189:         // off the timer.
        !          2190:         //
        !          2191:         restartTimer = Fd8xxInterrupt(Context) == FALSE ? TRUE : FALSE;
        !          2192: 
        !          2193:         //
        !          2194:         // Now determine if an event log entry should be made to inform
        !          2195:         // the system administrator that there is a possible configuration
        !          2196:         // error on this driver.
        !          2197:         //
        !          2198:         if ((restartTimer == FALSE) &&
        !          2199:             (deviceExtension->NotifiedConfigurationError == FALSE)) {
        !          2200:             deviceExtension->TimerCaughtInterrupt--;
        !          2201:             if ((deviceExtension->TimerCaughtInterrupt == 0) &&
        !          2202:                 (deviceExtension->ConfiguredWithoutInterrupts == FALSE)) {
        !          2203:                 ScsiPortLogError(deviceExtension,
        !          2204:                                  NULL,
        !          2205:                                  0,
        !          2206:                                  0,
        !          2207:                                  0,
        !          2208:                                  SP_IRQ_NOT_RESPONDING,
        !          2209:                                  8);
        !          2210:                 deviceExtension->NotifiedConfigurationError = TRUE;
        !          2211:             }
        !          2212:         }
        !          2213:     }
        !          2214: 
        !          2215:     if (restartTimer) {
        !          2216: 
        !          2217:         //
        !          2218:         // Not selected.  Set timer for another call.
        !          2219:         //
        !          2220:         ScsiPortNotification(RequestTimerCall,
        !          2221:                              deviceExtension,
        !          2222:                              Fd8xxTimer,
        !          2223:                              FD8xx_TIMER_VALUE);
        !          2224:     }
        !          2225: }
        !          2226: 
        !          2227: 
        !          2228: BOOLEAN
        !          2229: Fd8xxInterrupt(
        !          2230:     IN PVOID Context
        !          2231:     )
        !          2232: 
        !          2233: /*++
        !          2234: 
        !          2235: Routine Description:
        !          2236: 
        !          2237:     This routine handles the interrupts for the FD8XX.  The intention is to
        !          2238:     quickly determine the cause of the interrupt, clear the interrupt, and
        !          2239:     setup to process any SCSI command that may have been affected by the
        !          2240:     interrupt.
        !          2241: 
        !          2242: Arguments:
        !          2243: 
        !          2244:     Context - Device adapter context pointer.
        !          2245: 
        !          2246: Return Value:
        !          2247: 
        !          2248:     TRUE indicates that the interrupt was from this Fd8xx< adapter,
        !          2249:     FALSE indicates that this interrupt was NOT from us.
        !          2250: 
        !          2251: --*/
        !          2252: 
        !          2253: {
        !          2254:     PSPECIFIC_DEVICE_EXTENSION deviceExtension = Context;
        !          2255: 
        !          2256:     FdDebugPrint(0x20,
        !          2257:                   (0, "\nFdInterrupt: Device = %x ",
        !          2258:                   deviceExtension));
        !          2259: 
        !          2260:     if (Fd8xxStatusCheck(deviceExtension,
        !          2261:                          S_SELECT,
        !          2262:                          S_SELECT,
        !          2263:                          1) == FALSE) {
        !          2264: 
        !          2265:         //
        !          2266:         // Spurious interrupt or for some other device.
        !          2267:         //
        !          2268:         FdDebugPrint(0x20,
        !          2269:                       (0, "NOT Selected: Status = %x, Last CtrlReg = %x\n",
        !          2270:                       FD8XX_READ_STATUS(deviceExtension->BaseAddress),
        !          2271:                       deviceExtension->ControlRegister));
        !          2272:         return FALSE;
        !          2273: 
        !          2274:     } else {
        !          2275: 
        !          2276:         //
        !          2277:         // We are being reselected by a target.
        !          2278:         //
        !          2279:         FdDebugPrint(0x20,
        !          2280:                     (0, "Selected: Status = %x, Last CtrlReg = %x",
        !          2281:                     FD8XX_READ_STATUS(deviceExtension->BaseAddress),
        !          2282:                     deviceExtension->ControlRegister));
        !          2283: 
        !          2284:         deviceExtension->ExpectingInterrupt = FALSE;
        !          2285:         Fd8xxClearControl(deviceExtension, C_INT_ENABLE);
        !          2286: 
        !          2287:         //
        !          2288:         // Here's where the fun starts.  We tell the OS to call DoReconnect
        !          2289:         // with system interrupts enabled.  This way we're not transferring
        !          2290:         // gobs of data with the rest of the world blocked out.  We can be
        !          2291:         // friendly neighbors and do that sort of CPU hungry stuff while
        !          2292:         // letting others grab it when necessary.
        !          2293:         //
        !          2294:         ScsiPortNotification(CallEnableInterrupts,
        !          2295:                              deviceExtension,
        !          2296:                              Fd8xxDoReconnect);
        !          2297: 
        !          2298:         return TRUE;
        !          2299:     }
        !          2300: } // end Fd8xxInterrupt()
        !          2301: 
        !          2302: 
        !          2303: VOID
        !          2304: Fd8xxDpcRunPhase(
        !          2305:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
        !          2306:     )
        !          2307: 
        !          2308: /*++
        !          2309: 
        !          2310: Routine Description:
        !          2311: 
        !          2312:     This routine is called by the port driver with interrupts enabled.
        !          2313:     It calls the normal run phase routine of the 8xx driver to process
        !          2314:     the request.
        !          2315: 
        !          2316: Arguments:
        !          2317: 
        !          2318:     DeviceExtension - context pointer for the start or run phase.
        !          2319: 
        !          2320: Return Value:
        !          2321: 
        !          2322:     None.
        !          2323: 
        !          2324: --*/
        !          2325: 
        !          2326: {
        !          2327: 
        !          2328:     Fd8xxRunPhase(DeviceExtension);
        !          2329: 
        !          2330:     ScsiPortNotification(CallDisableInterrupts,
        !          2331:                          DeviceExtension,
        !          2332:                          Fd8xxReenableAdapterInterrupts);
        !          2333: 
        !          2334:     //
        !          2335:     // Adapter ready for next request.
        !          2336:     //
        !          2337:     ScsiPortNotification(NextRequest,
        !          2338:                          DeviceExtension,
        !          2339:                          NULL);
        !          2340: }
        !          2341: 
        !          2342: 
        !          2343: VOID
        !          2344: Fd8xxStartExecution(
        !          2345:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
        !          2346:     IN PSPECIFIC_LU_EXTENSION     LuExtension,
        !          2347:     IN PSCSI_REQUEST_BLOCK        Srb
        !          2348:     )
        !          2349: 
        !          2350: /*++
        !          2351: 
        !          2352: Routine Description:
        !          2353: 
        !          2354:     This routine will start (and possibley complete) the execution of
        !          2355:     a SCSI request.
        !          2356: 
        !          2357: Arguments:
        !          2358: 
        !          2359:     DeviceExtension -   Device adapter context pointer.
        !          2360:     LuExtension -       The logical unit specific information.
        !          2361:     Srb -               The Srb command to execute.
        !          2362: 
        !          2363: Return Value:
        !          2364: 
        !          2365:     None.
        !          2366: 
        !          2367: --*/
        !          2368: 
        !          2369: {
        !          2370:     FdDebugPrint(0x10,
        !          2371:                   (0, "FdStartExecution Device = %x, LuExt = %x, Srb = %x ",
        !          2372:                   DeviceExtension,
        !          2373:                   LuExtension,
        !          2374:                   Srb));
        !          2375:     FdDebugPrint(0x10,
        !          2376:                   (0, "Target = %x, Lun = %x.\n",
        !          2377:                   Srb->TargetId,
        !          2378:                   Srb->Lun));
        !          2379: 
        !          2380:     //
        !          2381:     // Setup the context for this adapter.
        !          2382:     //
        !          2383:     DeviceExtension->ActiveLu = LuExtension;
        !          2384: 
        !          2385:     //
        !          2386:     // Turn off selection interrupt.
        !          2387:     //
        !          2388:     Fd8xxClearControl(DeviceExtension, C_INT_ENABLE);
        !          2389: 
        !          2390:     //
        !          2391:     // Check for potential tape access to insure handshake data transfer.
        !          2392:     // This is done here instead of in the deferred routine to save
        !          2393:     // two pointer loads (Srb and LuExtension).
        !          2394:     //
        !          2395:     if (Srb->CdbLength == 6) {
        !          2396:         LuExtension->SixByteCDBActive = TRUE;
        !          2397:     } else {
        !          2398:         LuExtension->SixByteCDBActive = FALSE;
        !          2399:     }
        !          2400: 
        !          2401:     //
        !          2402:     // Run the bus phase with other interrupts in the system enabled.
        !          2403:     //
        !          2404:     ScsiPortNotification(CallEnableInterrupts,
        !          2405:                          DeviceExtension,
        !          2406:                          Fd8xxDpcRunPhase);
        !          2407: } // end Fd8xxStartExecution()
        !          2408: 
        !          2409: 
        !          2410: VOID
        !          2411: Fd8xxAbort(
        !          2412:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
        !          2413:     IN PSPECIFIC_LU_EXTENSION     LuExtension,
        !          2414:     IN PSCSI_REQUEST_BLOCK        Srb
        !          2415:     )
        !          2416: 
        !          2417: /*++
        !          2418: 
        !          2419: Routine Description:
        !          2420: 
        !          2421:     Attempt to abort a command on a SCSI target.
        !          2422: 
        !          2423: Arguments:
        !          2424: 
        !          2425:     DeviceExtension -   The adapter specific information.
        !          2426:     LuExtension     -   The specific target/logical unit information.
        !          2427:     Srb -               The Srb command to execute.
        !          2428: 
        !          2429: Return Value:
        !          2430: 
        !          2431:     None.
        !          2432: 
        !          2433: --*/
        !          2434: 
        !          2435: {
        !          2436:     PUCHAR              baseAddress = DeviceExtension->BaseAddress;
        !          2437:     PSCSI_REQUEST_BLOCK srbBeingAborted = LuExtension->ActiveLuRequest;
        !          2438: 
        !          2439:     FdDebugPrint(0x10, (0, "FdAbort: "));
        !          2440: 
        !          2441:     //
        !          2442:     // Make sure there is still a request to complete.  If so complete
        !          2443:     // it with an SRB_STATUS_ABORTED status.
        !          2444:     //
        !          2445:     if (srbBeingAborted == NULL) {
        !          2446: 
        !          2447:         //
        !          2448:         // If there is no request, then fail the abort.
        !          2449:         //
        !          2450:         Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
        !          2451: 
        !          2452:         FdDebugPrint(0x10, (0, "failed.\n"));
        !          2453: 
        !          2454:     } else {
        !          2455: 
        !          2456:         if (LuExtension->LuState == LS_DISCONNECTED) {
        !          2457: 
        !          2458:             FdDebugPrint(0x10, (0, "sending...\n"));
        !          2459: 
        !          2460:             //
        !          2461:             // Attempt to send an abort message SRB into the state machine.
        !          2462:             //
        !          2463:             LuExtension->LuState = LS_ARBITRATE;
        !          2464:             LuExtension->AbortBeingAttempted = TRUE;
        !          2465:             DeviceExtension->ActiveLu = LuExtension;
        !          2466:             Fd8xxArbitrate(DeviceExtension);
        !          2467: 
        !          2468:             if ((LuExtension->LuState == LS_SELECT) ||
        !          2469:                 (LuExtension->LuState == LS_COMPLETE)) {
        !          2470: 
        !          2471:                 //
        !          2472:                 // Finish off the abort.
        !          2473:                 //
        !          2474:                 Fd8xxRunPhase(DeviceExtension);
        !          2475:                 LuExtension->AbortBeingAttempted = FALSE;
        !          2476: 
        !          2477:                 //
        !          2478:                 // Now force a completion on the SRB that is being aborted.
        !          2479:                 //
        !          2480:                 LuExtension->LuState = LS_COMPLETE;
        !          2481:                 srbBeingAborted->SrbStatus = SRB_STATUS_ABORTED;
        !          2482: 
        !          2483:                 LuExtension->ActiveLuRequest = srbBeingAborted;
        !          2484:                 DeviceExtension->ActiveLu = LuExtension;
        !          2485:                 Fd8xxNotifyCompletion(DeviceExtension);
        !          2486:     
        !          2487:             } else {
        !          2488: 
        !          2489:                 LuExtension->AbortBeingAttempted = FALSE;
        !          2490:                 Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
        !          2491: 
        !          2492:                 FdDebugPrint(0x10, (0, "FdAbort failed.\n"));
        !          2493:             }
        !          2494: 
        !          2495:         } else if (LuExtension->LuState != LS_COMPLETE) {
        !          2496: 
        !          2497:             //
        !          2498:             // The SCSI bus is most likely hung by this LUN, so reset it.
        !          2499:             //
        !          2500:             FdDebugPrint(0x10, (0, "still connected to SCSI bus.\n"));
        !          2501:             Fd8xxResetBus(DeviceExtension, Srb->PathId);
        !          2502:             ScsiPortNotification(ResetDetected, DeviceExtension, NULL);
        !          2503:         }
        !          2504:     }
        !          2505: } // end Fd8xxAbort()
        !          2506: 
        !          2507: 
        !          2508: BOOLEAN
        !          2509: Fd8xxResetBus(
        !          2510:     IN PVOID Context,
        !          2511:     IN ULONG PathId
        !          2512:     )
        !          2513: 
        !          2514: /*++
        !          2515: 
        !          2516: Routine Description:
        !          2517: 
        !          2518:     Reset Future Domain 8XX SCSI adapter (there is no action for this)
        !          2519:     and SCSI bus.
        !          2520: 
        !          2521: Arguments:
        !          2522: 
        !          2523:     Context - pointer to the device extension for the reset.
        !          2524:     PathId  - The bus for telling the port driver where the reset occurred.
        !          2525: 
        !          2526: Return Value:
        !          2527: 
        !          2528:     Nothing.
        !          2529: 
        !          2530: --*/
        !          2531: 
        !          2532: {
        !          2533:     PSPECIFIC_DEVICE_EXTENSION deviceExtension = Context;
        !          2534: 
        !          2535:     FdDebugPrint(0x10, (0, "FdResetBus: Reset Fd8xx and SCSI bus\n"));
        !          2536: 
        !          2537:     //
        !          2538:     // RESET SCSI bus.
        !          2539:     //
        !          2540:     Fd8xxSetControl(deviceExtension,
        !          2541:                     C_RESET);
        !          2542:     ScsiPortStallExecution(RESET_HOLD_TIME);
        !          2543:     Fd8xxClearControl(deviceExtension,
        !          2544:                       C_RESET);
        !          2545: 
        !          2546:     //
        !          2547:     // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
        !          2548:     //
        !          2549:     ScsiPortCompleteRequest(deviceExtension,
        !          2550:                             (UCHAR) PathId,
        !          2551:                             (UCHAR) -1,
        !          2552:                             (UCHAR) -1,
        !          2553:                             SRB_STATUS_BUS_RESET);
        !          2554: 
        !          2555:     //
        !          2556:     // Find all luExtensions and zero them out.
        !          2557:     //
        !          2558:     if (deviceExtension->ActiveLu != NULL) {
        !          2559:         deviceExtension->ActiveLu->LuState = LS_COMPLETE;
        !          2560:         deviceExtension->ActiveLu->ActiveLuRequest = NULL;
        !          2561:         deviceExtension->ActiveLu->NoDisconnectActive = FALSE;
        !          2562:         deviceExtension->ActiveLu->AbortBeingAttempted = FALSE;
        !          2563:         deviceExtension->ActiveLu = NULL;
        !          2564:     }
        !          2565: 
        !          2566:     if (deviceExtension->SavedLu != NULL) {
        !          2567:         deviceExtension->SavedLu->LuState = LS_COMPLETE;
        !          2568:         deviceExtension->SavedLu->ActiveLuRequest = NULL;
        !          2569:         deviceExtension->SavedLu->NoDisconnectActive = FALSE;
        !          2570:         deviceExtension->SavedLu->AbortBeingAttempted = FALSE;
        !          2571:         deviceExtension->SavedLu = NULL;
        !          2572:     }
        !          2573: 
        !          2574:     return TRUE;
        !          2575: } // end Fd8xxResetBus()
        !          2576: 
        !          2577: 
        !          2578: BOOLEAN
        !          2579: Fd8xxStartIo(
        !          2580:     IN PVOID               Context,
        !          2581:     IN PSCSI_REQUEST_BLOCK Srb
        !          2582:     )
        !          2583: 
        !          2584: /*++
        !          2585: 
        !          2586: Routine Description:
        !          2587: 
        !          2588:     This routine is called from the SCSI port driver synchronized
        !          2589:     with the kernel with a request to be executed.
        !          2590: 
        !          2591: Arguments:
        !          2592:     Context -   The adapter specific information.
        !          2593:     Srb -       The Srb command to execute.
        !          2594: 
        !          2595: Return Value:
        !          2596: 
        !          2597:     TRUE
        !          2598: 
        !          2599: --*/
        !          2600: 
        !          2601: {
        !          2602:     PSPECIFIC_DEVICE_EXTENSION  deviceExtension = Context;
        !          2603:     PSPECIFIC_LU_EXTENSION      luExtension;
        !          2604: 
        !          2605:     FdDebugPrint(0x10,
        !          2606:                   (0, "\nFdStartIo: Device = %x, Srb = %x\n",
        !          2607:                   deviceExtension,
        !          2608:                   Srb));
        !          2609: 
        !          2610:     //
        !          2611:     // Determine the logical unit that this request is for.
        !          2612:     //
        !          2613:     deviceExtension->PathId = Srb->PathId;
        !          2614:     luExtension = ScsiPortGetLogicalUnit(deviceExtension,
        !          2615:                                          deviceExtension->PathId,
        !          2616:                                          Srb->TargetId,
        !          2617:                                          Srb->Lun);
        !          2618:     Srb->SrbStatus = SRB_STATUS_PENDING;
        !          2619: 
        !          2620:     switch (Srb->Function) {
        !          2621: 
        !          2622:     case SRB_FUNCTION_ABORT_COMMAND:
        !          2623: 
        !          2624:         FdDebugPrint(0x10, (0, "ABORT COMMAND.\n"));
        !          2625: 
        !          2626:         //
        !          2627:         // Abort request in progress.
        !          2628:         //
        !          2629:         // Fd8xxResetBus(deviceExtension, Srb->PathId);
        !          2630:         Fd8xxAbort(deviceExtension, luExtension, Srb);
        !          2631:         break;
        !          2632: 
        !          2633:     case SRB_FUNCTION_RESET_BUS:
        !          2634: 
        !          2635:         FdDebugPrint(0x10, (0, "RESET BUS.\n"));
        !          2636: 
        !          2637:         //
        !          2638:         // Reset Fd8xx and SCSI bus.
        !          2639:         //
        !          2640:         Fd8xxResetBus(deviceExtension, Srb->PathId);
        !          2641:         Srb->SrbStatus = SRB_STATUS_SUCCESS;
        !          2642:         break;
        !          2643: 
        !          2644:     case SRB_FUNCTION_EXECUTE_SCSI:
        !          2645: 
        !          2646:         FdDebugPrint(0x10, (0, "EXECUTE SCSI.\n"));
        !          2647: 
        !          2648:         //
        !          2649:         // Setup the context for this target/lun.
        !          2650:         //
        !          2651:         luExtension->ActiveLuRequest = Srb;
        !          2652:         luExtension->LuState = LS_ARBITRATE;
        !          2653:         luExtension->SavedDataPointer = (ULONG) Srb->DataBuffer;
        !          2654:         luExtension->SavedDataLength = Srb->DataTransferLength;
        !          2655: 
        !          2656:         //
        !          2657:         // Initiate a SCSI request.
        !          2658:         //
        !          2659:         Fd8xxStartExecution(deviceExtension, luExtension, Srb);
        !          2660:         return TRUE;
        !          2661: 
        !          2662:     default:
        !          2663: 
        !          2664:         Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
        !          2665:         ScsiPortNotification(RequestComplete,
        !          2666:                              (PVOID) deviceExtension,
        !          2667:                              Srb);
        !          2668:         break;
        !          2669: 
        !          2670:     }
        !          2671: 
        !          2672:     //
        !          2673:     // Adapter ready for next request.
        !          2674:     //
        !          2675:     ScsiPortNotification(NextRequest,
        !          2676:                          deviceExtension,
        !          2677:                          NULL);
        !          2678:     return TRUE;
        !          2679: } // end Fd8xxStartIo()
        !          2680: 
        !          2681: 
        !          2682: BOOLEAN
        !          2683: Fd8xxInitialize(
        !          2684:     IN PVOID Context
        !          2685:     )
        !          2686: 
        !          2687: /*++
        !          2688: 
        !          2689: Routine Description:
        !          2690: 
        !          2691:     Inititialize Fd8xx adapter.
        !          2692: 
        !          2693: Arguments:
        !          2694: 
        !          2695:     Context - Adapter object device extension.
        !          2696: 
        !          2697: Return Value:
        !          2698: 
        !          2699:     Status.
        !          2700: 
        !          2701: --*/
        !          2702: 
        !          2703: {
        !          2704:     PSPECIFIC_DEVICE_EXTENSION deviceExtension = Context;
        !          2705: 
        !          2706:     //
        !          2707:     // Reset Fd8xx and SCSI bus.
        !          2708:     //
        !          2709:     Fd8xxWriteControl(deviceExtension, C_RESET);
        !          2710:     ScsiPortStallExecution(RESET_HOLD_TIME);
        !          2711:     Fd8xxClearControl(deviceExtension, C_RESET);
        !          2712: 
        !          2713:     ScsiPortNotification(ResetDetected,
        !          2714:                          (PVOID) deviceExtension);
        !          2715: 
        !          2716:     Fd8xxClearControl(deviceExtension, C_INT_ENABLE);
        !          2717:     deviceExtension->ExpectingInterrupt = FALSE;
        !          2718:     deviceExtension->NotifiedConfigurationError = FALSE;
        !          2719:     deviceExtension->ContinueTimer = 5;
        !          2720:     deviceExtension->TimerCaughtInterrupt = 10;
        !          2721:     deviceExtension->ConfiguredWithoutInterrupts = FALSE;
        !          2722: 
        !          2723:     return TRUE;
        !          2724: } // end Fd8xx<Initialize()
        !          2725: 
        !          2726: 
        !          2727: BOOLEAN
        !          2728: Fd8xxCheckBaseAddress(
        !          2729:     IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
        !          2730:     IN PUCHAR                     BaseAddress
        !          2731:     )
        !          2732: 
        !          2733: /*++
        !          2734: 
        !          2735: Routine Description:
        !          2736: 
        !          2737:     This routine will check to see if there is an adapter at the
        !          2738:     provided base address.  It does this by first reading and comparing
        !          2739:     all of the data area bytes on the adapter.  If these are all equal
        !          2740:     it then changes the first value and performs the compare again.
        !          2741:     All other data area values should change to be equal to the first
        !          2742:     value when the change is made.  If they are not equal any changes
        !          2743:     are restored.
        !          2744: 
        !          2745: Arguments:
        !          2746: 
        !          2747:     DeviceExtension - Necessary to attempt the reads.
        !          2748:     BaseAddress     - The address to attempt to use for the base of the
        !          2749:                       memory area
        !          2750: 
        !          2751: Return Value:
        !          2752: 
        !          2753:     TRUE    - There is an adapter present at the base address provided.
        !          2754:     FALSE   - There is no adapter present at the base address provided.
        !          2755: 
        !          2756: --*/
        !          2757: 
        !          2758: {
        !          2759:     UCHAR  testValue;
        !          2760:     UCHAR  oldValue;
        !          2761:     USHORT offset;
        !          2762: 
        !          2763:     oldValue = FD8XX_READ_DATA(BaseAddress);
        !          2764: 
        !          2765:     //
        !          2766:     // Perform a read test of the memory area of the adapter.
        !          2767:     //
        !          2768:     for (offset = 254; offset > 0; offset--) {
        !          2769: 
        !          2770:         testValue = FD8XX_READ_ALTERNATE_DATA(BaseAddress, offset);
        !          2771:         if (oldValue != testValue) {
        !          2772: 
        !          2773:             FdDebugPrint(0x20, (0, "Read test failed. "));
        !          2774:             return FALSE;
        !          2775:         }
        !          2776:     }
        !          2777: 
        !          2778:     FdDebugPrint(0x20, (0, "Read test passed. "));
        !          2779: 
        !          2780:     //
        !          2781:     // Card may be present in the system.  Perform a write test.
        !          2782:     // The write value is insured to be different than the previous
        !          2783:     // value by adding 1
        !          2784:     //
        !          2785:     oldValue++;
        !          2786:     Fd8xxWriteControl(DeviceExtension,
        !          2787:                       (C_BUS_ENABLE | C_PARITY_ENABLE));
        !          2788: 
        !          2789:     FD8XX_WRITE_DATA(BaseAddress, oldValue);
        !          2790: 
        !          2791:     for (offset = 254; offset > 0; offset--) {
        !          2792: 
        !          2793:         testValue = FD8XX_READ_ALTERNATE_DATA(BaseAddress, offset);
        !          2794: 
        !          2795:         if (oldValue != testValue) {
        !          2796: 
        !          2797:             oldValue--;    // Get the original value and restore it.
        !          2798:             FD8XX_WRITE_DATA(BaseAddress, oldValue);
        !          2799:             FdDebugPrint(0x20, (0, "Write test failed. "));
        !          2800:             return FALSE;
        !          2801:         }
        !          2802:     }
        !          2803: 
        !          2804:     FdDebugPrint(0x20, (0, "Write test passed. "));
        !          2805: 
        !          2806:     return TRUE;
        !          2807: } // end Fd8xxCheckBaseAddress()
        !          2808: 
        !          2809: 
        !          2810: ULONG
        !          2811: Fd8xxParseArgumentString(
        !          2812:     IN PCHAR String,
        !          2813:     IN PCHAR KeyWord
        !          2814:     )
        !          2815: 
        !          2816: /*++
        !          2817: 
        !          2818: Routine Description:
        !          2819: 
        !          2820:     This routine will parse the string for a match on the keyword, then
        !          2821:     calculate the value for the keyword and return it to the caller.
        !          2822: 
        !          2823: Arguments:
        !          2824: 
        !          2825:     String - The ASCII string to parse.
        !          2826:     KeyWord - The keyword for the value desired.
        !          2827: 
        !          2828: Return Values:
        !          2829: 
        !          2830:     Zero if value not found
        !          2831:     Value converted from ASCII to binary.
        !          2832: 
        !          2833: --*/
        !          2834: 
        !          2835: {
        !          2836:     PCHAR cptr;
        !          2837:     PCHAR kptr;
        !          2838:     ULONG value;
        !          2839:     ULONG stringLength = 0;
        !          2840:     ULONG keyWordLength = 0;
        !          2841:     ULONG index;
        !          2842: 
        !          2843:     //
        !          2844:     // Calculate the string length and lower case all characters.
        !          2845:     //
        !          2846:     cptr = String;
        !          2847:     while (*cptr) {
        !          2848: 
        !          2849:         if (*cptr >= 'A' && *cptr <= 'Z') {
        !          2850:             *cptr = *cptr + ('a' - 'A');
        !          2851:         }
        !          2852:         cptr++;
        !          2853:         stringLength++;
        !          2854:     }
        !          2855: 
        !          2856:     //
        !          2857:     // Calculate the keyword length and lower case all characters.
        !          2858:     //
        !          2859:     cptr = KeyWord;
        !          2860:     while (*cptr) {
        !          2861: 
        !          2862:         if (*cptr >= 'A' && *cptr <= 'Z') {
        !          2863:             *cptr = *cptr + ('a' - 'A');
        !          2864:         }
        !          2865:         cptr++;
        !          2866:         keyWordLength++;
        !          2867:     }
        !          2868: 
        !          2869:     if (keyWordLength > stringLength) {
        !          2870: 
        !          2871:         //
        !          2872:         // Can't possibly have a match.
        !          2873:         //
        !          2874:         return 0;
        !          2875:     }
        !          2876: 
        !          2877:     //
        !          2878:     // Now setup and start the compare.
        !          2879:     //
        !          2880:     cptr = String;
        !          2881: 
        !          2882: ContinueSearch:
        !          2883:     //
        !          2884:     // The input string may start with white space.  Skip it.
        !          2885:     //
        !          2886:     while (*cptr == ' ' || *cptr == '\t') {
        !          2887:         cptr++;
        !          2888:     }
        !          2889: 
        !          2890:     if (*cptr == '\0') {
        !          2891: 
        !          2892:         //
        !          2893:         // end of string.
        !          2894:         //
        !          2895:         return 0;
        !          2896:     }
        !          2897: 
        !          2898:     kptr = KeyWord;
        !          2899:     while (*cptr++ == *kptr++) {
        !          2900: 
        !          2901:         if (*(cptr - 1) == '\0') {
        !          2902: 
        !          2903:             //
        !          2904:             // end of string
        !          2905:             //
        !          2906:             return 0;
        !          2907:         }
        !          2908:     }
        !          2909: 
        !          2910:     if (*(kptr - 1) == '\0') {
        !          2911: 
        !          2912:         //
        !          2913:         // May have a match backup and check for blank or equals.
        !          2914:         //
        !          2915: 
        !          2916:         cptr--;
        !          2917:         while (*cptr == ' ' || *cptr == '\t') {
        !          2918:             cptr++;
        !          2919:         }
        !          2920: 
        !          2921:         //
        !          2922:         // Found a match.  Make sure there is an equals.
        !          2923:         //
        !          2924:         if (*cptr != '=') {
        !          2925: 
        !          2926:             //
        !          2927:             // Not a match so move to the next semicolon.
        !          2928:             //
        !          2929:             while (*cptr) {
        !          2930:                 if (*cptr++ == ';') {
        !          2931:                     goto ContinueSearch;
        !          2932:                 }
        !          2933:             }
        !          2934:             return 0;
        !          2935:         }
        !          2936: 
        !          2937:         //
        !          2938:         // Skip the equals sign.
        !          2939:         //
        !          2940:         cptr++;
        !          2941: 
        !          2942:         //
        !          2943:         // Skip white space.
        !          2944:         //
        !          2945:         while ((*cptr == ' ') || (*cptr == '\t')) {
        !          2946:             cptr++;
        !          2947:         }
        !          2948: 
        !          2949:         if (*cptr == '\0') {
        !          2950: 
        !          2951:             //
        !          2952:             // Early end of string, return not found
        !          2953:             //
        !          2954:             return 0;
        !          2955:         }
        !          2956: 
        !          2957:         if (*cptr == ';') {
        !          2958: 
        !          2959:             //
        !          2960:             // This isn't it either.
        !          2961:             //
        !          2962:             cptr++;
        !          2963:             goto ContinueSearch;
        !          2964:         }
        !          2965: 
        !          2966:         value = 0;
        !          2967:         if ((*cptr == '0') && (*(cptr + 1) == 'x')) {
        !          2968: 
        !          2969:             //
        !          2970:             // Value is in Hex.  Skip the "0x"
        !          2971:             //
        !          2972:             cptr += 2;
        !          2973:             for (index = 0; *(cptr + index); index++) {
        !          2974: 
        !          2975:                 if (*(cptr + index) == ' ' ||
        !          2976:                     *(cptr + index) == '\t' ||
        !          2977:                     *(cptr + index) == ';') {
        !          2978:                      break;
        !          2979:                 }
        !          2980: 
        !          2981:                 if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
        !          2982:                     value = (16 * value) + (*(cptr + index) - '0');
        !          2983:                 } else {
        !          2984:                     if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) {
        !          2985:                         value = (16 * value) + (*(cptr + index) - 'a' + 10);
        !          2986:                     } else {
        !          2987:     
        !          2988:                         //
        !          2989:                         // Syntax error, return not found.
        !          2990:                         //
        !          2991:                         return 0;
        !          2992:                     }
        !          2993:                 }
        !          2994:             }
        !          2995:         } else {
        !          2996: 
        !          2997:             //
        !          2998:             // Value is in Decimal.
        !          2999:             //
        !          3000:             for (index = 0; *(cptr + index); index++) {
        !          3001: 
        !          3002:                 if (*(cptr + index) == ' ' ||
        !          3003:                     *(cptr + index) == '\t' ||
        !          3004:                     *(cptr + index) == ';') {
        !          3005:                      break;
        !          3006:                 }
        !          3007: 
        !          3008:                 if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
        !          3009:                     value = (10 * value) + (*(cptr + index) - '0');
        !          3010:                 } else {
        !          3011: 
        !          3012:                     //
        !          3013:                     // Syntax error return not found.
        !          3014:                     //
        !          3015:                     return 0;
        !          3016:                 }
        !          3017:             }
        !          3018:         }
        !          3019: 
        !          3020:         return value;
        !          3021:     } else {
        !          3022: 
        !          3023:         //
        !          3024:         // Not a match check for ';' to continue search.
        !          3025:         //
        !          3026:         while (*cptr) {
        !          3027:             if (*cptr++ == ';') {
        !          3028:                 goto ContinueSearch;
        !          3029:             }
        !          3030:         }
        !          3031: 
        !          3032:         return 0;
        !          3033:     }
        !          3034: }
        !          3035: 
        !          3036: 
        !          3037: BOOLEAN
        !          3038: Fd8xxFindSignature(
        !          3039:     PUCHAR romAddress,
        !          3040:     PUCHAR p1RomBiosId)
        !          3041:     
        !          3042: /*++
        !          3043: 
        !          3044: Routine Description:
        !          3045: 
        !          3046:     This routine searches for a P2 ROM BIOS signature within the rom address
        !          3047:     provided.
        !          3048:     
        !          3049: Arguments:
        !          3050: 
        !          3051:     romAddress - Location to search
        !          3052:     p1RomBiosId - BIOS string to match
        !          3053:     
        !          3054: Return Values:
        !          3055: 
        !          3056:     TRUE if found
        !          3057:     FALSE otherwise
        !          3058:     
        !          3059: --*/
        !          3060: 
        !          3061: {
        !          3062:     USHORT  count = 64;         // Check first 64 bytes of ROM space.
        !          3063:     PUCHAR  ptr1 = romAddress;
        !          3064: 
        !          3065:     while (count--) {
        !          3066: 
        !          3067:         PUCHAR  ptr2 = ptr1++;
        !          3068:         PUCHAR  ptr3 = p1RomBiosId;
        !          3069:         UCHAR   c = ScsiPortReadRegisterUchar(ptr2);
        !          3070: 
        !          3071:         while (c == *ptr3++) {
        !          3072: 
        !          3073:             ptr2++;
        !          3074:             c = ScsiPortReadRegisterUchar(ptr2);
        !          3075: 
        !          3076:             if (*ptr3 == '\0')
        !          3077:                 return TRUE;
        !          3078: 
        !          3079:             if (c == '\0')
        !          3080:                 return FALSE;
        !          3081:         }
        !          3082:     }
        !          3083: 
        !          3084:     return FALSE;
        !          3085: }
        !          3086: 
        !          3087: 
        !          3088: BOOLEAN
        !          3089: Fd8xxVerifyPatriot1(
        !          3090:     PSPECIFIC_DEVICE_EXTENSION      DeviceExtension,
        !          3091:     PPORT_CONFIGURATION_INFORMATION ConfigInfo
        !          3092:     )
        !          3093:     
        !          3094: /*++
        !          3095: 
        !          3096: Routine Descriptions:
        !          3097: 
        !          3098:     This routine verifies the presence of a P2 ROM based adapter.
        !          3099:     
        !          3100: Arguments:
        !          3101: 
        !          3102:     DeviceExtension - call context.
        !          3103:     ConfigInfo      - system provided configuration information.
        !          3104: 
        !          3105: Return Value:
        !          3106: 
        !          3107:     TRUE if found
        !          3108:     FALSE otherwise
        !          3109:     
        !          3110: --*/
        !          3111: 
        !          3112: {
        !          3113:     UCHAR   p1RomBiosId[] = "IBM F1 BIOS";
        !          3114:     BOOLEAN retval;
        !          3115: 
        !          3116:     if (Fd8xxFindSignature(DeviceExtension->BaseAddress, p1RomBiosId)) {
        !          3117: 
        !          3118:         //
        !          3119:         // We have a patriot-1 adapter installed.
        !          3120:         //
        !          3121:         retval = TRUE;
        !          3122: 
        !          3123:     } else {
        !          3124: 
        !          3125:         retval = FALSE;
        !          3126:     }
        !          3127: 
        !          3128:     return retval;
        !          3129: }
        !          3130: 
        !          3131: 
        !          3132: ULONG
        !          3133: Fd8xxFindAdapter(
        !          3134:     IN PVOID                                Context,
        !          3135:     IN PVOID                                AdaptersFound,
        !          3136:     IN PVOID                                BusInformation,
        !          3137:     IN PCHAR                                ArgumentString,
        !          3138:     IN OUT PPORT_CONFIGURATION_INFORMATION  ConfigInfo,
        !          3139:     OUT PBOOLEAN                            Again
        !          3140:     )
        !          3141: 
        !          3142: /*++
        !          3143: 
        !          3144: Routine Description:
        !          3145: 
        !          3146:     This routine maps the memory area for the FD8XX adapter into
        !          3147:     the virtual address space for the system.  It then attempts to
        !          3148:     find the adapter and set the configuration information.  If
        !          3149:     the adapter is not present in the system (or cannot be found)
        !          3150:     this routine returnes an indication as such (i.e. FALSE).
        !          3151: 
        !          3152: Arguments:
        !          3153: 
        !          3154:     Context         - The device specific context for the call.
        !          3155:     AdaptersFound   - Passed through from the driver entry as additional
        !          3156:                       context for the call.
        !          3157:     BusInformation  - Unused.
        !          3158:     ArgumentString  - Points to the potential IRQ for this adapter.
        !          3159:     ConfigInfo      - Pointer to the configuration information structure to
        !          3160:                       be filled in.
        !          3161:     Again           - Returns back a request to call this function again.
        !          3162: 
        !          3163: Return Value:
        !          3164: 
        !          3165:     SP_RETURN_FOUND     - if an adapter is found.
        !          3166:     SP_RETURN_NOT_FOUND - if no adapter is found.
        !          3167: 
        !          3168: --*/
        !          3169: 
        !          3170: {
        !          3171:     USHORT                      curBaseAddress;
        !          3172:     USHORT                      adaptersFound;
        !          3173:     ULONG                       returnStatus = SP_RETURN_NOT_FOUND;
        !          3174:     PSPECIFIC_DEVICE_EXTENSION  deviceExtension = Context;
        !          3175:     ULONG baseAddresses[] =
        !          3176:     {
        !          3177:         0x000c8000,
        !          3178:         0x000ca000,
        !          3179:         0x000ce000,
        !          3180:         0x000de000,
        !          3181:         0x000e8000,
        !          3182:         0x000ea000,
        !          3183:         0
        !          3184:     };
        !          3185: 
        !          3186:      //
        !          3187:      // This must never be set to TRUE for this controller.  If we return
        !          3188:      // TRUE for this parameter, the SCSI port driver will not move to the
        !          3189:      // next entry in the registry for the next controller of this type.
        !          3190:      // Instead, it will call this routine again with the SAME registry
        !          3191:      // information (i.e., IRQ vector) causing the next adapter with a
        !          3192:      // DIFFERENT IRQ to fail to install.
        !          3193:      // 
        !          3194:     *Again = FALSE;
        !          3195: 
        !          3196:     curBaseAddress = (USHORT) (*((PULONG) AdaptersFound) >> 16);
        !          3197:     adaptersFound = (USHORT) (*((PULONG) AdaptersFound));
        !          3198: 
        !          3199:     if ((baseAddresses[curBaseAddress] == 0) ||
        !          3200:            (adaptersFound == MAX_ADAPTERS)) {
        !          3201: 
        !          3202:         return SP_RETURN_NOT_FOUND;
        !          3203:     }
        !          3204: 
        !          3205:     while ((baseAddresses[curBaseAddress] != 0) &&
        !          3206:            (adaptersFound != MAX_ADAPTERS) &&
        !          3207:            (returnStatus == SP_RETURN_NOT_FOUND)) {
        !          3208: 
        !          3209:         PUCHAR  baseAddress;
        !          3210: 
        !          3211:         FdDebugPrint(0x20,
        !          3212:                          (0, "Fd8xxFindAdapter: baseAddresses[%x] = %x, ",
        !          3213:                          curBaseAddress,
        !          3214:                          baseAddresses[curBaseAddress]));
        !          3215:         FdDebugPrint(0x20,
        !          3216:                          (0, "%x adapters found so far.\n",
        !          3217:                          adaptersFound));
        !          3218: 
        !          3219:         //
        !          3220:         // Map the TMC-950 chip into the virtual memory address space.
        !          3221:         // If ConfigInfo already has default information about this
        !          3222:         // controller, use it.  If not, then we derive our own.  This
        !          3223:         // is for Chicago compatibility.
        !          3224:         //
        !          3225:         if (ScsiPortConvertPhysicalAddressToUlong(
        !          3226:                 (*ConfigInfo->AccessRanges)[0].RangeStart) != 0) {
        !          3227: 
        !          3228:             deviceExtension->BaseAddress = baseAddress =
        !          3229:                 ScsiPortGetDeviceBase(
        !          3230:                     deviceExtension,
        !          3231:                     ConfigInfo->AdapterInterfaceType,
        !          3232:                     ConfigInfo->SystemIoBusNumber,
        !          3233:                     (*ConfigInfo->AccessRanges)[0].RangeStart,
        !          3234:                     (*ConfigInfo->AccessRanges)[0].RangeLength,
        !          3235:                     (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory));
        !          3236:         } else {
        !          3237: 
        !          3238:             deviceExtension->BaseAddress = baseAddress =
        !          3239:                 ScsiPortGetDeviceBase(
        !          3240:                     deviceExtension,
        !          3241:                     ConfigInfo->AdapterInterfaceType,
        !          3242:                     ConfigInfo->SystemIoBusNumber,
        !          3243:                     ScsiPortConvertUlongToPhysicalAddress(baseAddresses[curBaseAddress]),
        !          3244:                     (FD8XX_ADDRESS_SIZE),     // NumberOfBytes
        !          3245:                     (BOOLEAN) FALSE);         // InIoSpace
        !          3246:         }
        !          3247:         FdDebugPrint(0x20,
        !          3248:                     (0, "MmMapIoSpace address = %x ",
        !          3249:                     baseAddress));
        !          3250: 
        !          3251:         //
        !          3252:         // Determine if the card is really installed in the system.
        !          3253:         //
        !          3254:         if (Fd8xxCheckBaseAddress(deviceExtension, baseAddress) == FALSE) {
        !          3255: 
        !          3256:             //
        !          3257:             // We did not find an adapter at this baseAddress.  Free the
        !          3258:             // mapped memory space and continue with the next address if
        !          3259:             // there is one.
        !          3260:             //
        !          3261:             returnStatus = SP_RETURN_NOT_FOUND;
        !          3262:             ScsiPortFreeDeviceBase(deviceExtension,
        !          3263:                                    (PVOID) baseAddress);
        !          3264: 
        !          3265:         } else {
        !          3266: 
        !          3267:             returnStatus = SP_RETURN_FOUND;
        !          3268: 
        !          3269:             //
        !          3270:             // If there was no previously configured value for the IRQ,
        !          3271:             // look at the other way to configure the value or use a default.
        !          3272:             //
        !          3273:             if (ConfigInfo->BusInterruptLevel == 0) {
        !          3274: 
        !          3275:                 ConfigInfo->BusInterruptLevel = FD8XX_IDT_VECTOR;
        !          3276: 
        !          3277:                 if (ArgumentString != NULL) {
        !          3278:                     ULONG irq = Fd8xxParseArgumentString(ArgumentString, "irq");
        !          3279: 
        !          3280:                     if (irq == 0) {
        !          3281: 
        !          3282:                         //
        !          3283:                         // Check for the old way.
        !          3284:                         //
        !          3285:                         irq = *((PULONG)ArgumentString);
        !          3286:                         if (irq > 15) {
        !          3287: 
        !          3288:                             //
        !          3289:                             // really was intended to be zero.
        !          3290:                             //
        !          3291:                             irq = 0;
        !          3292:                             deviceExtension->ConfiguredWithoutInterrupts = TRUE;
        !          3293:                         } else {
        !          3294:                             irq = FD8XX_IDT_VECTOR;
        !          3295:                         }
        !          3296:                     }
        !          3297: 
        !          3298:                     FdDebugPrint(0x20,
        !          3299:                                 (0,
        !          3300:                                 "IRQ %d passed in. ",
        !          3301:                                 irq));
        !          3302:                     ConfigInfo->BusInterruptLevel = irq;
        !          3303:                 } else {
        !          3304: 
        !          3305:                     FdDebugPrint(0x20, (0, "default IRQ. "));
        !          3306:                 }
        !          3307:             } else {
        !          3308: 
        !          3309:                 FdDebugPrint(0x20,
        !          3310:                             (0,
        !          3311:                             "IRQ previously set to %d. ",
        !          3312:                             ConfigInfo->BusInterruptLevel));
        !          3313:             }
        !          3314: 
        !          3315:             //
        !          3316:             // If the user has not specified a target ID, fill in a default.
        !          3317:             //
        !          3318:            if (ConfigInfo->InitiatorBusId[0] == (UCHAR)SP_UNINITIALIZED_VALUE) {
        !          3319: 
        !          3320:                 deviceExtension->InitiatorId = SCSI_INITIATOR_ID;
        !          3321:                 ConfigInfo->InitiatorBusId[0] = SCSI_INITIATOR_ID;
        !          3322:             } else {
        !          3323: 
        !          3324:                 deviceExtension->InitiatorId = ConfigInfo->InitiatorBusId[0];
        !          3325:                 FdDebugPrint(0x20,
        !          3326:                             (0,
        !          3327:                             "Initiator ID set to %d ",
        !          3328:                             ConfigInfo->InitiatorBusId[0]));
        !          3329:             }
        !          3330: 
        !          3331:             //
        !          3332:             // Fill in the access array information only if there are no
        !          3333:             // default parameters already there.
        !          3334:             //
        !          3335:             if (ScsiPortConvertPhysicalAddressToUlong(
        !          3336:                     (*ConfigInfo->AccessRanges)[0].RangeStart) == 0) {
        !          3337: 
        !          3338:                 //
        !          3339:                 // There is no pre-assigned information in the ConfigInfo
        !          3340:                 // structure derived by Chicago.  Thus, we can fill
        !          3341:                 // our own derived information into the ConfigInfo structure.
        !          3342:                 // Otherwise WE MUST NOT change the ConfigInfo structure, as
        !          3343:                 // this will overwrite the Chicago-prestored information.
        !          3344:                 //
        !          3345:                 (*ConfigInfo->AccessRanges)[0].RangeStart =
        !          3346:                     ScsiPortConvertUlongToPhysicalAddress(baseAddresses[curBaseAddress]);
        !          3347:                 (*ConfigInfo->AccessRanges)[0].RangeLength = FD8XX_ADDRESS_SIZE;
        !          3348:                 (*ConfigInfo->AccessRanges)[0].RangeInMemory = TRUE;
        !          3349: 
        !          3350:                 ConfigInfo->ScatterGather = FALSE;
        !          3351:                 ConfigInfo->Master = FALSE;
        !          3352:                 ConfigInfo->MaximumTransferLength = MAX_TRANSFER_LENGTH;
        !          3353:                 ConfigInfo->NumberOfBuses = 1;
        !          3354: 
        !          3355:                 if (Fd8xxVerifyPatriot1(deviceExtension, ConfigInfo)) {
        !          3356: 
        !          3357:                     //
        !          3358:                     // We have a Patriot-I adapter installed in the system
        !          3359:                     // which scans from Target ID 7 to Target ID 0.
        !          3360:                     //
        !          3361:                     ConfigInfo->AdapterScansDown = TRUE;
        !          3362:                 }
        !          3363:             }
        !          3364: 
        !          3365:             adaptersFound++;
        !          3366:         }
        !          3367: 
        !          3368:         curBaseAddress++;
        !          3369: 
        !          3370:         FdDebugPrint(0x20, (0, "\n"));
        !          3371:     }
        !          3372: 
        !          3373:     *((PULONG) AdaptersFound) = ((ULONG) curBaseAddress) << 16;
        !          3374:     *((PULONG) AdaptersFound) += (ULONG) adaptersFound;
        !          3375: 
        !          3376:     return returnStatus;
        !          3377: } // end Fd8xxFindAdapter()
        !          3378: 
        !          3379: 
        !          3380: BOOLEAN
        !          3381: Fd8xxAdapterState(
        !          3382:     IN PVOID    DeviceExtension,
        !          3383:     IN PVOID    AdaptersFound,
        !          3384:     IN BOOLEAN  SaveState
        !          3385:     )
        !          3386: 
        !          3387: /*++
        !          3388: 
        !          3389: Routine Description:
        !          3390: 
        !          3391:     Saves/restores adapter's real-mode configuration state.
        !          3392: 
        !          3393: Arguments:
        !          3394: 
        !          3395:     DeviceExtension - Adapter object device extension.
        !          3396:     AdaptersFound   - Passed through from DriverEntry as additional
        !          3397:                       context for the call.
        !          3398:     SaveState       - TRUE = Save adapter state, FALSE = restore state.
        !          3399: 
        !          3400: Return Value:
        !          3401: 
        !          3402:     The spec did not intend for this routine to have a return value.
        !          3403:     Whoever did the header file just forgot to change the BOOLEAN to
        !          3404:     a VOID.  We will just return FALSE to shot the compiler up.
        !          3405: 
        !          3406: --*/
        !          3407: 
        !          3408: {
        !          3409:     return FALSE;
        !          3410: }
        !          3411: 
        !          3412: 
        !          3413: ULONG
        !          3414: DriverEntry(
        !          3415:     IN PVOID DriverObject,
        !          3416:     IN PVOID Argument2
        !          3417:     )
        !          3418: 
        !          3419: /*++
        !          3420: 
        !          3421: Routine Description:
        !          3422: 
        !          3423:     Driver initialization entry point for system.
        !          3424: 
        !          3425: Arguments:
        !          3426: 
        !          3427:     DriverObject - The driver specific object pointer
        !          3428:     Argument2    - not used.
        !          3429: 
        !          3430: Return Value:
        !          3431: 
        !          3432:     Status from ScsiPortInitialize()
        !          3433: 
        !          3434: --*/
        !          3435: 
        !          3436: {
        !          3437:     HW_INITIALIZATION_DATA  hwInitializationData;
        !          3438:     ULONG                   i;
        !          3439: 
        !          3440:     FdDebugPrint(0x20, (0, "\nSCSI Future Domain 8XX Miniport Driver\n"));
        !          3441: 
        !          3442:     //
        !          3443:     // Zero out the hwInitializationData structure.
        !          3444:     //
        !          3445:     for (i = 0; i < sizeof(HW_INITIALIZATION_DATA); i++) {
        !          3446: 
        !          3447:         *(((PUCHAR)&hwInitializationData + i)) = 0;
        !          3448:     }
        !          3449: 
        !          3450:     hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
        !          3451: 
        !          3452:     //
        !          3453:     // Set entry points.
        !          3454:     //
        !          3455:     hwInitializationData.HwInitialize   = Fd8xxInitialize;
        !          3456:     hwInitializationData.HwStartIo      = Fd8xxStartIo;
        !          3457:     hwInitializationData.HwInterrupt    = Fd8xxInterrupt;
        !          3458:     hwInitializationData.HwFindAdapter  = Fd8xxFindAdapter;
        !          3459:     hwInitializationData.HwResetBus     = Fd8xxResetBus;
        !          3460:     hwInitializationData.HwAdapterState = Fd8xxAdapterState;
        !          3461: 
        !          3462:     //
        !          3463:     // Indicate need buffer mapping but not physical addresses.
        !          3464:     //
        !          3465:     hwInitializationData.MapBuffers             = TRUE;
        !          3466:     hwInitializationData.NeedPhysicalAddresses  = FALSE;
        !          3467:     hwInitializationData.NumberOfAccessRanges   = 1;
        !          3468: 
        !          3469:     //
        !          3470:     // Specify size of device extension.
        !          3471:     //
        !          3472:     hwInitializationData.DeviceExtensionSize = sizeof(SPECIFIC_DEVICE_EXTENSION);
        !          3473: 
        !          3474:     //
        !          3475:     // Specify size of logical unit extension.
        !          3476:     //
        !          3477:     hwInitializationData.SpecificLuExtensionSize = sizeof(SPECIFIC_LU_EXTENSION);
        !          3478: 
        !          3479:     //
        !          3480:     // The fourth parameter below (i.e., "i") will show up as the
        !          3481:     // "AdaptersFound" parameter when FindAdapter() is called.
        !          3482:     //
        !          3483: 
        !          3484:     FdDebugPrint(0x20, (0, "Trying ISA...\n"));
        !          3485:     hwInitializationData.AdapterInterfaceType = Isa;
        !          3486: 
        !          3487:     i = 0;
        !          3488:     return ScsiPortInitialize(DriverObject,
        !          3489:                               Argument2,
        !          3490:                               &hwInitializationData,
        !          3491:                               &(i));
        !          3492: 
        !          3493: } // end DriverEntry()

unix.superglobalmegacorp.com

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