Annotation of ntddk/src/scsi/fd8xx/fd8xx.c, revision 1.1.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.