|
|
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()
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.