|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1991 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: aha174x.c ! 8: ! 9: Abstract: ! 10: ! 11: This is the port driver for the AHA174X SCSI adapter. ! 12: ! 13: Authors: ! 14: ! 15: Mike Glass ! 16: ! 17: Environment: ! 18: ! 19: kernel mode only ! 20: ! 21: Notes: ! 22: ! 23: Revision History: ! 24: ! 25: --*/ ! 26: ! 27: #include "miniport.h" ! 28: #include "aha174x.h" // includes scsi.h ! 29: ! 30: // ! 31: // Device extension ! 32: // ! 33: ! 34: typedef struct _HW_DEVICE_EXTENSION { ! 35: ! 36: PEISA_CONTROLLER EisaController; ! 37: ! 38: UCHAR HostTargetId; ! 39: ! 40: PSCSI_REQUEST_BLOCK PendingSrb; ! 41: ! 42: UCHAR RequestCount[8][8]; ! 43: ! 44: } HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION; ! 45: ! 46: // ! 47: // Define the maximum number of outstanding I/O requests per logical unit. ! 48: // ! 49: ! 50: #define MAX_QUEUE_DEPTH 2 ! 51: ! 52: ! 53: // ! 54: // Function declarations ! 55: // ! 56: // Functions that start with 'Aha174x' are entry points ! 57: // for the OS port driver. ! 58: // ! 59: ! 60: ULONG ! 61: DriverEntry( ! 62: IN PVOID DriverObject, ! 63: IN PVOID Argument2 ! 64: ); ! 65: ! 66: ULONG ! 67: Aha174xEntry( ! 68: IN PVOID DriverObject, ! 69: IN PVOID Argument2 ! 70: ); ! 71: ! 72: ULONG ! 73: Aha174xConfiguration( ! 74: IN PVOID DeviceExtension, ! 75: IN PVOID Context, ! 76: IN PVOID BusInformation, ! 77: IN PCHAR ArgumentString, ! 78: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, ! 79: OUT PBOOLEAN Again ! 80: ); ! 81: ! 82: BOOLEAN ! 83: Aha174xInitialize( ! 84: IN PVOID DeviceExtension ! 85: ); ! 86: ! 87: BOOLEAN ! 88: Aha174xStartIo( ! 89: IN PVOID DeviceExtension, ! 90: IN PSCSI_REQUEST_BLOCK Srb ! 91: ); ! 92: ! 93: BOOLEAN ! 94: Aha174xInterrupt( ! 95: IN PVOID DeviceExtension ! 96: ); ! 97: ! 98: BOOLEAN ! 99: Aha174xResetBus( ! 100: IN PVOID HwDeviceExtension, ! 101: IN ULONG PathId ! 102: ); ! 103: ! 104: // ! 105: // This function is called from Aha174xStartIo. ! 106: // ! 107: ! 108: VOID ! 109: A174xBuildEcb( ! 110: IN PHW_DEVICE_EXTENSION DeviceExtension, ! 111: IN PSCSI_REQUEST_BLOCK Srb ! 112: ); ! 113: ! 114: // ! 115: // This function is called from A174xBuildEcb. ! 116: // ! 117: ! 118: VOID ! 119: A174xBuildSgl( ! 120: IN PHW_DEVICE_EXTENSION DeviceExtension, ! 121: IN PSCSI_REQUEST_BLOCK Srb ! 122: ); ! 123: ! 124: VOID ! 125: A174xBuildRequestSense( ! 126: IN PVOID HwDeviceExtension, ! 127: IN PSCSI_REQUEST_BLOCK Srb ! 128: ); ! 129: ! 130: BOOLEAN ! 131: A174xSendCommand( ! 132: IN PHW_DEVICE_EXTENSION DeviceExtension, ! 133: IN UCHAR OperationCode, ! 134: IN ULONG Address ! 135: ); ! 136: ! 137: // ! 138: // This function is called from Aha174xInterrupt. ! 139: // ! 140: ! 141: VOID ! 142: A174xMapStatus( ! 143: IN PHW_DEVICE_EXTENSION DeviceExtension, ! 144: IN PSCSI_REQUEST_BLOCK Srb, ! 145: IN PSTATUS_BLOCK StatusBlock ! 146: ); ! 147: ! 148: ! 149: ULONG ! 150: DriverEntry ( ! 151: IN PVOID DriverObject, ! 152: IN PVOID Argument2 ! 153: ) ! 154: ! 155: /*++ ! 156: ! 157: Routine Description: ! 158: ! 159: Installable driver initialization entry point for system. ! 160: ! 161: Arguments: ! 162: ! 163: Driver Object ! 164: ! 165: Return Value: ! 166: ! 167: Status from ScsiPortInitialize() ! 168: ! 169: --*/ ! 170: ! 171: { ! 172: return Aha174xEntry(DriverObject, Argument2); ! 173: ! 174: } // end DriverEntry() ! 175: ! 176: ! 177: ULONG ! 178: Aha174xEntry( ! 179: IN PVOID DriverObject, ! 180: IN PVOID Argument2 ! 181: ) ! 182: ! 183: /*++ ! 184: ! 185: Routine Description: ! 186: ! 187: This routine is called from DriverEntry if this driver is installable ! 188: or directly from the system if the driver is built into the kernel. ! 189: It scans the EISA slots looking for an AHA174X that is configured ! 190: to the ENHANCED mode. ! 191: ! 192: Arguments: ! 193: ! 194: Driver Object ! 195: ! 196: Return Value: ! 197: ! 198: Status from ScsiPortInitialize() ! 199: ! 200: --*/ ! 201: ! 202: { ! 203: HW_INITIALIZATION_DATA hwInitializationData; ! 204: ULONG i; ! 205: ULONG AdapterCount = 0; ! 206: ! 207: DebugPrint((1,"\n\nSCSI Aha174x MiniPort Driver\n")); ! 208: ! 209: // ! 210: // Zero out structure. ! 211: // ! 212: ! 213: for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) { ! 214: ((PUCHAR)&hwInitializationData)[i] = 0; ! 215: } ! 216: ! 217: // ! 218: // Set size of hwInitializationData. ! 219: // ! 220: ! 221: hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA); ! 222: ! 223: // ! 224: // Set entry points. ! 225: // ! 226: ! 227: hwInitializationData.HwInitialize = Aha174xInitialize; ! 228: hwInitializationData.HwFindAdapter = Aha174xConfiguration; ! 229: hwInitializationData.HwStartIo = Aha174xStartIo; ! 230: hwInitializationData.HwInterrupt = Aha174xInterrupt; ! 231: hwInitializationData.HwResetBus = Aha174xResetBus; ! 232: ! 233: // ! 234: // Set number of access ranges and bus type. ! 235: // ! 236: ! 237: hwInitializationData.NumberOfAccessRanges = 2; ! 238: hwInitializationData.AdapterInterfaceType = Eisa; ! 239: ! 240: // ! 241: // Indicate no buffer mapping but will need physical addresses. ! 242: // ! 243: ! 244: hwInitializationData.NeedPhysicalAddresses = TRUE; ! 245: ! 246: // ! 247: // Indicate auto request sense is supported. ! 248: // ! 249: ! 250: hwInitializationData.MultipleRequestPerLu = TRUE; ! 251: hwInitializationData.AutoRequestSense = TRUE; ! 252: ! 253: // ! 254: // Specify size of extensions. ! 255: // ! 256: ! 257: hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION); ! 258: ! 259: // ! 260: // Ask for SRB extensions for ECBs. ! 261: // ! 262: ! 263: hwInitializationData.SrbExtensionSize = sizeof(ECB); ! 264: ! 265: return ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &AdapterCount); ! 266: ! 267: } // end Aha174xEntry() ! 268: ! 269: ! 270: ULONG ! 271: Aha174xConfiguration( ! 272: IN PVOID HwDeviceExtension, ! 273: IN PVOID Context, ! 274: IN PVOID BusInformation, ! 275: IN PCHAR ArgumentString, ! 276: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, ! 277: OUT PBOOLEAN Again ! 278: ) ! 279: ! 280: /*++ ! 281: ! 282: Routine Description: ! 283: ! 284: This function is called by the OS-specific port driver after ! 285: the necessary storage has been allocated, to gather information ! 286: about the adapter's configuration. ! 287: ! 288: Arguments: ! 289: ! 290: HwDeviceExtension - HBA miniport driver's adapter data storage ! 291: ConfigInfo - Configuration information structure describing HBA ! 292: ! 293: Return Value: ! 294: ! 295: TRUE if adapter present in system ! 296: ! 297: --*/ ! 298: ! 299: { ! 300: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; ! 301: PEISA_CONTROLLER eisaController; ! 302: ULONG eisaSlotNumber; ! 303: PVOID eisaAddress; ! 304: UCHAR dataByte; ! 305: PULONG adapterCount = Context; ! 306: ! 307: // ! 308: // Check to see if adapter present in system. ! 309: // ! 310: ! 311: for (eisaSlotNumber=*adapterCount + 1; eisaSlotNumber<MAXIMUM_EISA_SLOTS; eisaSlotNumber++) { ! 312: ! 313: // ! 314: // Update the adapter count to indicate this slot has been checked. ! 315: // ! 316: ! 317: (*adapterCount)++; ! 318: ! 319: // ! 320: // Get the system address for this card. ! 321: // The card uses I/O space. ! 322: // ! 323: ! 324: eisaAddress = ScsiPortGetDeviceBase(deviceExtension, ! 325: ConfigInfo->AdapterInterfaceType, ! 326: ConfigInfo->SystemIoBusNumber, ! 327: ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber), ! 328: 0x1000, ! 329: TRUE); ! 330: ! 331: eisaController = ! 332: (PEISA_CONTROLLER)((PUCHAR)eisaAddress + EISA_ADDRESS_BASE); ! 333: ! 334: if ((ScsiPortReadPortUchar(&eisaController->BoardId[0]) == 0x04) && ! 335: (ScsiPortReadPortUchar(&eisaController->BoardId[1]) == 0x90) && ! 336: (ScsiPortReadPortUchar(&eisaController->BoardId[2]) == 0x00)) { ! 337: ! 338: DebugPrint((1,"AHA174X: Adapter found at EISA slot %d\n", ! 339: eisaSlotNumber)); ! 340: #ifdef MIPS ! 341: // ! 342: // Add code to configure the device if necessary. This is only ! 343: // needed until we get an EISA configuration program. ! 344: // ! 345: ! 346: if (!(ScsiPortReadPortUchar(&eisaController->EBControl) & 0x1)) { ! 347: ! 348: // ! 349: // The card as not been configured. Jam in a default one. ! 350: // Enable the card, enable enhanced mode operation, set the ! 351: // irql to 14, set the target id to 7 and enable the DMA. ! 352: // ! 353: ! 354: ScsiPortWritePortUchar(&eisaController->EBControl, 1); ! 355: ScsiPortWritePortUchar(&eisaController->PortAddress, 0x80); ! 356: ScsiPortWritePortUchar(&eisaController->BiosAddress, 0x00); ! 357: ScsiPortWritePortUchar(&eisaController->Interrupt, 0x1d); ! 358: ScsiPortWritePortUchar(&eisaController->ScsiId, 0x7); ! 359: ScsiPortWritePortUchar(&eisaController->DmaChannel, 0x2); ! 360: ScsiPortStallExecution(1000); ! 361: ! 362: } ! 363: #endif ! 364: if (ScsiPortReadPortUchar(&eisaController->PortAddress) & ! 365: ENHANCED_INTERFACE_ENABLED) { ! 366: ! 367: // ! 368: // An adapter with the enhanced interface enabled was found. ! 369: // ! 370: ! 371: break; ! 372: ! 373: } else { ! 374: ! 375: DebugPrint((1,"AHA174X: Adapter is in STANDARD mode\n")); ! 376: } ! 377: } ! 378: ! 379: // ! 380: // If an adapter was not found unmap it. ! 381: // ! 382: ! 383: ScsiPortFreeDeviceBase(deviceExtension, ! 384: eisaAddress); ! 385: ! 386: } // end for (eisaSlotNumber ... ! 387: ! 388: if (!(eisaSlotNumber < MAXIMUM_EISA_SLOTS)) { ! 389: ! 390: // ! 391: // No adapter was found. Indicate that we are done and there are no ! 392: // more adapters here. Clear the adapter count for the next bus. ! 393: // ! 394: ! 395: *Again = FALSE; ! 396: *adapterCount = 0; ! 397: return SP_RETURN_NOT_FOUND; ! 398: } ! 399: ! 400: // ! 401: // There is still more to look at. ! 402: // ! 403: ! 404: *Again = TRUE; ! 405: ! 406: // ! 407: // Store base address of EISA registers in device extension. ! 408: // ! 409: ! 410: deviceExtension->EisaController = eisaController; ! 411: ! 412: ConfigInfo->InitiatorBusId[0] = ! 413: ScsiPortReadPortUchar(&eisaController->ScsiId) & 0x0F; ! 414: ! 415: deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0]; ! 416: ! 417: // ! 418: // Indicate maximum transfer length in bytes. ! 419: // ! 420: ! 421: ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_SIZE; ! 422: ! 423: // ! 424: // Maximum number of physical segments is 32. ! 425: // ! 426: ! 427: ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SGL_DESCRIPTORS; ! 428: ! 429: ConfigInfo->ScatterGather = TRUE; ! 430: ConfigInfo->Master = TRUE; ! 431: ConfigInfo->NumberOfBuses = 1; ! 432: ! 433: // ! 434: // Get the system interrupt vector and IRQL. ! 435: // ! 436: ! 437: dataByte = ScsiPortReadPortUchar(&eisaController->Interrupt); ! 438: ConfigInfo->BusInterruptLevel = (dataByte & 7) + 9; ! 439: ! 440: // ! 441: // Determine level or edge interrupt. ! 442: // ! 443: ! 444: ConfigInfo->InterruptMode = dataByte & 0x08 ? Latched : LevelSensitive; ! 445: ! 446: // ! 447: // Fill in the access array information. ! 448: // ! 449: ! 450: (*ConfigInfo->AccessRanges)[0].RangeStart = ! 451: ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber + EISA_ADDRESS_BASE); ! 452: (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER); ! 453: (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; ! 454: ! 455: ! 456: // ! 457: // Determine the BIOS address. ! 458: // ! 459: ! 460: dataByte = ScsiPortReadPortUchar(&eisaController->BiosAddress); ! 461: ! 462: if (dataByte & BIOS_ENABLED) { ! 463: ! 464: dataByte &= BIOS_ADDRESS; ! 465: ! 466: // ! 467: // Calculate the bios base address. ! 468: // ! 469: ! 470: eisaSlotNumber = 0xC0000 + (dataByte * 0x4000); ! 471: ! 472: if (eisaSlotNumber < 0xF0000) { ! 473: ! 474: DebugPrint((1, "Aha174xConfiguration: Bios address at: %lx.\n", eisaSlotNumber)); ! 475: (*ConfigInfo->AccessRanges)[1].RangeStart = ! 476: ScsiPortConvertUlongToPhysicalAddress(eisaSlotNumber); ! 477: (*ConfigInfo->AccessRanges)[1].RangeLength = BIOS_LENGTH; ! 478: (*ConfigInfo->AccessRanges)[1].RangeInMemory = TRUE; ! 479: ! 480: } ! 481: } ! 482: ! 483: return SP_RETURN_FOUND; ! 484: ! 485: } // end Aha174xConfiguration() ! 486: ! 487: ! 488: BOOLEAN ! 489: Aha174xInitialize( ! 490: IN PVOID HwDeviceExtension ! 491: ) ! 492: ! 493: /*++ ! 494: ! 495: Routine Description: ! 496: ! 497: Inititialize adapter and mailbox. ! 498: ! 499: Arguments: ! 500: ! 501: HwDeviceExtension - HBA miniport driver's adapter data storage ! 502: ! 503: Return Value: ! 504: ! 505: TRUE - if initialization successful. ! 506: FALSE - if initialization unsuccessful. ! 507: ! 508: --*/ ! 509: ! 510: { ! 511: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; ! 512: ! 513: // ! 514: // Reset Aha174x and SCSI bus. ! 515: // ! 516: ! 517: if (!Aha174xResetBus(deviceExtension, 0)) { ! 518: ! 519: DebugPrint((1, "Aha174xInitialize: Reset bus failed\n")); ! 520: return FALSE; ! 521: ! 522: } else { ! 523: ! 524: ScsiPortNotification(ResetDetected, deviceExtension, 0); ! 525: ! 526: return TRUE; ! 527: } ! 528: ! 529: } // end Aha174xInitialize() ! 530: ! 531: ! 532: BOOLEAN ! 533: Aha174xStartIo( ! 534: IN PVOID HwDeviceExtension, ! 535: IN PSCSI_REQUEST_BLOCK Srb ! 536: ) ! 537: ! 538: /*++ ! 539: ! 540: Routine Description: ! 541: ! 542: This routine is called from the SCSI port driver synchronized ! 543: with the kernel to send an ECB or issue an immediate command. ! 544: ! 545: Arguments: ! 546: ! 547: HwDeviceExtension - HBA miniport driver's adapter data storage ! 548: Srb - IO request packet ! 549: ! 550: Return Value: ! 551: ! 552: TRUE ! 553: ! 554: --*/ ! 555: ! 556: { ! 557: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; ! 558: PEISA_CONTROLLER eisaController = deviceExtension->EisaController; ! 559: PECB ecb; ! 560: PSCSI_REQUEST_BLOCK abortedSrb; ! 561: UCHAR opCode; ! 562: ULONG physicalEcb; ! 563: ULONG length; ! 564: ULONG i = 0; ! 565: UCHAR count = MAX_QUEUE_DEPTH; ! 566: ! 567: ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING); ! 568: ! 569: // ! 570: // Get ECB from SRB. ! 571: // ! 572: ! 573: if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) { ! 574: ! 575: // ! 576: // Verify that SRB to abort is still outstanding. ! 577: // ! 578: ! 579: abortedSrb = ScsiPortGetSrb(deviceExtension, ! 580: Srb->PathId, ! 581: Srb->TargetId, ! 582: Srb->Lun, ! 583: Srb->QueueTag); ! 584: ! 585: if (abortedSrb != Srb->NextSrb || ! 586: abortedSrb->SrbStatus != SRB_STATUS_PENDING) { ! 587: ! 588: DebugPrint((1, "A174xStartIo: SRB to abort already completed\n")); ! 589: ! 590: // ! 591: // Complete abort SRB. ! 592: // ! 593: ! 594: Srb->SrbStatus = SRB_STATUS_ABORT_FAILED; ! 595: ! 596: ScsiPortNotification(RequestComplete, ! 597: deviceExtension, ! 598: Srb); ! 599: // ! 600: // Adapter ready for next request. ! 601: // ! 602: ! 603: ScsiPortNotification(NextRequest, ! 604: deviceExtension, ! 605: NULL); ! 606: ! 607: return TRUE; ! 608: } ! 609: ! 610: // ! 611: // Get ECB to abort. ! 612: // ! 613: ! 614: ecb = Srb->NextSrb->SrbExtension; ! 615: ! 616: // ! 617: // Set abort SRB for completion. ! 618: // ! 619: ! 620: ecb->AbortSrb = Srb; ! 621: ! 622: } else { ! 623: ! 624: ecb = Srb->SrbExtension; ! 625: ! 626: // ! 627: // Save SRB back pointer in ECB. ! 628: // ! 629: ! 630: ecb->SrbAddress = Srb; ! 631: ecb->AbortSrb = NULL; ! 632: ! 633: } ! 634: ! 635: // ! 636: // Get ECB physical address. ! 637: // ! 638: ! 639: physicalEcb = ! 640: ScsiPortConvertPhysicalAddressToUlong( ! 641: ScsiPortGetPhysicalAddress(deviceExtension, NULL, ecb, &length)); ! 642: ! 643: // ! 644: // Assume physical address is contiguous for size of ECB. ! 645: // ! 646: ! 647: ASSERT(length >= sizeof(ECB)); ! 648: ! 649: switch (Srb->Function) { ! 650: ! 651: case SRB_FUNCTION_EXECUTE_SCSI: ! 652: ! 653: // ! 654: // Build ECB for regular request or request sense. ! 655: // ! 656: ! 657: if (Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) { ! 658: A174xBuildRequestSense(deviceExtension, Srb); ! 659: } else { ! 660: A174xBuildEcb(deviceExtension, Srb); ! 661: } ! 662: ! 663: // ! 664: // Increment the request count. ! 665: // ! 666: ! 667: count = ++deviceExtension->RequestCount[Srb->TargetId][Srb->Lun]; ! 668: ! 669: opCode = START_ECB; ! 670: ! 671: break; ! 672: ! 673: case SRB_FUNCTION_ABORT_COMMAND: ! 674: ! 675: DebugPrint((1, "Aha174xStartIo: Abort request received\n")); ! 676: ! 677: opCode = ABORT_ECB; ! 678: ! 679: break; ! 680: ! 681: default: ! 682: ! 683: // ! 684: // Set error, complete request ! 685: // and signal ready for next request. ! 686: // ! 687: ! 688: Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; ! 689: ! 690: ScsiPortNotification(RequestComplete, ! 691: deviceExtension, ! 692: Srb); ! 693: ! 694: ScsiPortNotification(NextRequest, ! 695: deviceExtension, ! 696: NULL); ! 697: ! 698: return TRUE; ! 699: ! 700: } // end switch ! 701: ! 702: if (!A174xSendCommand(deviceExtension, ! 703: (UCHAR)(opCode | Srb->TargetId), ! 704: physicalEcb)) { ! 705: ! 706: DebugPrint((1,"Aha174xStartIo: Send command timed out\n")); ! 707: ! 708: // ! 709: // Save the request utill a pending one completes. ! 710: // ! 711: ! 712: deviceExtension->PendingSrb = Srb; ! 713: ! 714: return(TRUE); ! 715: ! 716: } ! 717: ! 718: // ! 719: // Adapter ready for next request. ! 720: // ! 721: ! 722: if (count < MAX_QUEUE_DEPTH) { ! 723: ! 724: // ! 725: // Request another request for this logical unit. ! 726: // ! 727: ! 728: ScsiPortNotification(NextLuRequest, ! 729: deviceExtension, ! 730: Srb->PathId, ! 731: Srb->TargetId, ! 732: Srb->Lun); ! 733: ! 734: } else { ! 735: ! 736: // ! 737: // Request another request for this adapter. ! 738: // ! 739: ! 740: ScsiPortNotification(NextRequest, ! 741: deviceExtension, ! 742: Srb->PathId, ! 743: Srb->TargetId, ! 744: Srb->Lun); ! 745: ! 746: } ! 747: ! 748: return TRUE; ! 749: ! 750: } // end Aha174xStartIo() ! 751: ! 752: ! 753: BOOLEAN ! 754: Aha174xInterrupt( ! 755: IN PVOID HwDeviceExtension ! 756: ) ! 757: ! 758: /*++ ! 759: ! 760: Routine Description: ! 761: ! 762: This is the interrupt service routine for the Aha174x SCSI adapter. ! 763: It reads the interrupt register to determine if the adapter is indeed ! 764: the source of the interrupt and clears the interrupt at the device. ! 765: If the adapter is interrupting because a mailbox is full, the ECB is ! 766: retrieved to complete the request. ! 767: ! 768: Arguments: ! 769: ! 770: HwDeviceExtension - HBA miniport driver's adapter data storage ! 771: ! 772: Return Value: ! 773: ! 774: TRUE if MailboxIn full ! 775: ! 776: --*/ ! 777: ! 778: { ! 779: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; ! 780: PECB ecb; ! 781: PSCSI_REQUEST_BLOCK srb; ! 782: PEISA_CONTROLLER eisaController = deviceExtension->EisaController; ! 783: PSTATUS_BLOCK statusBlock; ! 784: UCHAR targetId; ! 785: UCHAR lun; ! 786: ULONG physicalEcb; ! 787: UCHAR interruptStatus; ! 788: ! 789: // ! 790: // Check interrupt pending. ! 791: // ! 792: ! 793: if (!(ScsiPortReadPortUchar(&eisaController->Status) & ! 794: INTERRUPT_PENDING)) { ! 795: ! 796: DebugPrint((4, "Aha174xInterrupt: Spurious interrupt\n")); ! 797: return FALSE; ! 798: } ! 799: ! 800: // ! 801: // Read interrupt status. ! 802: // ! 803: ! 804: interruptStatus = ScsiPortReadPortUchar( ! 805: &eisaController->InterruptStatus); ! 806: ! 807: // ! 808: // Get targetId ! 809: // ! 810: ! 811: targetId = interruptStatus & 0x0F; ! 812: ! 813: // ! 814: // Get physical address of ECB. ! 815: // ! 816: ! 817: physicalEcb = ScsiPortReadPortUlong(&eisaController->MailBoxIn); ! 818: ! 819: // ! 820: // Acknowledge interrupt. ! 821: // ! 822: ! 823: ScsiPortWritePortUchar(&eisaController->Control, CLEAR_INTERRUPT); ! 824: ! 825: // ! 826: // Check for pending requests. If there is one then start it. ! 827: // ! 828: ! 829: if (deviceExtension->PendingSrb != NULL) { ! 830: ! 831: srb = deviceExtension->PendingSrb; ! 832: deviceExtension->PendingSrb = NULL; ! 833: ! 834: Aha174xStartIo(deviceExtension, srb); ! 835: ! 836: } ! 837: ! 838: switch (interruptStatus>>4) { ! 839: ! 840: case ECB_COMPLETE_SUCCESS: ! 841: case ECB_COMPLETE_SUCCESS_RETRY: ! 842: ! 843: // ! 844: // Get virtual ECB address. ! 845: // ! 846: ! 847: ecb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalEcb)); ! 848: ! 849: // ! 850: // Make sure this was a valid physical address. ! 851: // ! 852: ! 853: if (ecb == NULL || ecb->SrbAddress == NULL) { ! 854: break; ! 855: } ! 856: ! 857: // ! 858: // Get SRB from ECB. ! 859: // ! 860: ! 861: srb = ecb->SrbAddress; ! 862: ! 863: // ! 864: // Clear SRB from ECB. ! 865: // ! 866: ! 867: ecb->SrbAddress = NULL; ! 868: ! 869: // ! 870: // Update SRB statuses. ! 871: // ! 872: ! 873: srb->SrbStatus = SRB_STATUS_SUCCESS; ! 874: srb->ScsiStatus = SCSISTAT_GOOD; ! 875: ! 876: // ! 877: // If there is a peneding abort request, then complete it. ! 878: // This adapter does not interrupt when an abort completes. ! 879: // So one of three cases will occur: ! 880: // The abort succeeds and the command is termainated. ! 881: // The abort is too late and command termainates. ! 882: // The abort fails but the command does not terminate. ! 883: // The first two cases are handled by completing the abort when the ! 884: // command completes. The last case is handled by the abort timing ! 885: // out. ! 886: // ! 887: ! 888: if (ecb->AbortSrb != NULL) { ! 889: ! 890: ecb->AbortSrb->SrbStatus = SRB_STATUS_SUCCESS; ! 891: ! 892: // ! 893: // Complete the abort request. ! 894: // ! 895: ! 896: ScsiPortNotification( ! 897: RequestComplete, ! 898: deviceExtension, ! 899: ecb->AbortSrb ! 900: ); ! 901: ! 902: ecb->AbortSrb = NULL; ! 903: } ! 904: ! 905: if (deviceExtension->RequestCount[srb->TargetId][srb->Lun]-- ! 906: == MAX_QUEUE_DEPTH) { ! 907: ! 908: // ! 909: // The adapter can now take another request for this device. ! 910: // ! 911: ! 912: ScsiPortNotification(NextLuRequest, ! 913: deviceExtension, ! 914: srb->PathId, ! 915: srb->TargetId, ! 916: srb->Lun); ! 917: ! 918: } ! 919: ! 920: // ! 921: // Call notification routine for the SRB. ! 922: // ! 923: ! 924: ScsiPortNotification(RequestComplete, ! 925: (PVOID)deviceExtension, ! 926: srb); ! 927: ! 928: return TRUE; ! 929: ! 930: case ECB_COMPLETE_ERROR: ! 931: ! 932: // ! 933: // Get virtual ECB address. ! 934: // ! 935: ! 936: ecb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalEcb)); ! 937: ! 938: // ! 939: // Make sure this was a valid physical address. ! 940: // ! 941: ! 942: if (ecb == NULL || ecb->SrbAddress == NULL) { ! 943: break; ! 944: } ! 945: ! 946: // ! 947: // Get SRB from ECB. ! 948: // ! 949: ! 950: srb = ecb->SrbAddress; ! 951: ! 952: // ! 953: // Clear SRB from ECB. ! 954: // ! 955: ! 956: ecb->SrbAddress = NULL; ! 957: ! 958: // ! 959: // Get Status Block virtual address. ! 960: // ! 961: ! 962: statusBlock = ScsiPortGetVirtualAddress(deviceExtension, ! 963: ScsiPortConvertUlongToPhysicalAddress(ecb->StatusBlockAddress)); ! 964: ! 965: // ! 966: // If there is a peneding abort request, then complete it. ! 967: // This adapter does not interrupt when an abort completes. ! 968: // So one of three cases will occur: ! 969: // The abort succeeds and the command is termainated. ! 970: // The abort is too late and command termainates. ! 971: // The abort fails but the command does not terminate. ! 972: // The first two cases are handled by completing the abort when the ! 973: // command completes. The last case is handled by the abort timing ! 974: // out. ! 975: // ! 976: ! 977: if (ecb->AbortSrb != NULL) { ! 978: ! 979: ecb->AbortSrb->SrbStatus = SRB_STATUS_SUCCESS; ! 980: ! 981: // ! 982: // Complete the abort request. ! 983: // ! 984: ! 985: ScsiPortNotification( ! 986: RequestComplete, ! 987: deviceExtension, ! 988: ecb->AbortSrb ! 989: ); ! 990: ! 991: ecb->AbortSrb = NULL; ! 992: } ! 993: ! 994: // ! 995: // Update SRB status. ! 996: // ! 997: ! 998: A174xMapStatus(deviceExtension, srb, statusBlock); ! 999: ! 1000: if (deviceExtension->RequestCount[srb->TargetId][srb->Lun]-- ! 1001: == MAX_QUEUE_DEPTH) { ! 1002: ! 1003: // ! 1004: // The adapter can now take another request for this device. ! 1005: // ! 1006: ! 1007: ScsiPortNotification(NextLuRequest, ! 1008: deviceExtension, ! 1009: srb->PathId, ! 1010: srb->TargetId, ! 1011: srb->Lun); ! 1012: ! 1013: } ! 1014: ! 1015: // ! 1016: // Call notification routine for the SRB. ! 1017: // ! 1018: ! 1019: ScsiPortNotification(RequestComplete, ! 1020: (PVOID)deviceExtension, ! 1021: srb); ! 1022: ! 1023: return TRUE; ! 1024: ! 1025: case IMMEDIATE_COMMAND_SUCCESS: ! 1026: ! 1027: DebugPrint((2,"Aha174xInterrupt: Immediate command completed\n")); ! 1028: return TRUE; ! 1029: ! 1030: case ASYNCHRONOUS_EVENT_NOTIFICATION: ! 1031: ! 1032: // ! 1033: // Check if bus was reset. ! 1034: // ! 1035: ! 1036: if ((physicalEcb >> 24) == 0x23) { ! 1037: ! 1038: // ! 1039: // Clear the reqeust counts. ! 1040: // ! 1041: ! 1042: for (targetId = 0; targetId < 8; targetId++) { ! 1043: for (lun = 0; lun < 8; lun++) { ! 1044: ! 1045: deviceExtension->RequestCount[targetId][lun] = 0; ! 1046: } ! 1047: } ! 1048: ! 1049: // ! 1050: // Complete all outstanding requests. ! 1051: // ! 1052: ! 1053: ScsiPortCompleteRequest(deviceExtension, ! 1054: 0, ! 1055: SP_UNTAGGED, ! 1056: 0, ! 1057: SRB_STATUS_BUS_RESET); ! 1058: ! 1059: ! 1060: // ! 1061: // Notify operating system of SCSI bus reset. ! 1062: // ! 1063: ! 1064: ScsiPortNotification(ResetDetected, ! 1065: deviceExtension, ! 1066: NULL); ! 1067: } ! 1068: ! 1069: return TRUE; ! 1070: ! 1071: case IMMEDIATE_COMMAND_ERROR: ! 1072: default: ! 1073: ! 1074: DebugPrint((1, "A174xInterrupt: Unrecognized interrupt status %x\n", ! 1075: interruptStatus)); ! 1076: ! 1077: // ! 1078: // Log the error. ! 1079: // ! 1080: ! 1081: ScsiPortLogError( ! 1082: HwDeviceExtension, ! 1083: NULL, ! 1084: 0, ! 1085: deviceExtension->HostTargetId, ! 1086: 0, ! 1087: SP_INTERNAL_ADAPTER_ERROR, ! 1088: 1 << 16 | interruptStatus ! 1089: ); ! 1090: ! 1091: return TRUE; ! 1092: ! 1093: } // end switch ! 1094: ! 1095: // ! 1096: // A bad physcial address was return by the adapter. ! 1097: // Log it as an error. ! 1098: // ! 1099: ! 1100: ScsiPortLogError( ! 1101: HwDeviceExtension, ! 1102: NULL, ! 1103: 0, ! 1104: deviceExtension->HostTargetId, ! 1105: 0, ! 1106: SP_INTERNAL_ADAPTER_ERROR, ! 1107: 5 << 16 | interruptStatus ! 1108: ); ! 1109: ! 1110: return TRUE; ! 1111: ! 1112: } // end Aha174xInterrupt() ! 1113: ! 1114: ! 1115: VOID ! 1116: A174xBuildEcb( ! 1117: IN PHW_DEVICE_EXTENSION DeviceExtension, ! 1118: IN PSCSI_REQUEST_BLOCK Srb ! 1119: ) ! 1120: ! 1121: /*++ ! 1122: ! 1123: Routine Description: ! 1124: ! 1125: Build ECB for Aha174x. ! 1126: ! 1127: Arguments: ! 1128: ! 1129: DeviceExtenson ! 1130: SRB ! 1131: ! 1132: Return Value: ! 1133: ! 1134: Nothing. ! 1135: ! 1136: --*/ ! 1137: ! 1138: { ! 1139: PECB ecb = Srb->SrbExtension; ! 1140: PSTATUS_BLOCK statusBlock = &ecb->StatusBlock; ! 1141: ULONG length; ! 1142: ! 1143: // ! 1144: // Set ECB command. ! 1145: // ! 1146: ! 1147: ecb->Command = ECB_COMMAND_INITIATOR_COMMAND; ! 1148: ! 1149: // ! 1150: // Disable updating status block on success; ! 1151: // ! 1152: ! 1153: ecb->Flags[0] = ECB_FLAGS_DISABLE_STATUS_BLOCK; ! 1154: ! 1155: // ! 1156: // initialize ECB flags ! 1157: // ! 1158: ! 1159: ecb->Flags[1] = 0; ! 1160: ! 1161: // ! 1162: // Set transfer direction bit. ! 1163: // ! 1164: ! 1165: if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) { ! 1166: ! 1167: // ! 1168: // Write command. ! 1169: // ! 1170: ! 1171: ecb->Flags[1] |= ECB_FLAGS_WRITE; ! 1172: ! 1173: } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) { ! 1174: ! 1175: // ! 1176: // Read command. ! 1177: // ! 1178: ! 1179: ecb->Flags[1] |= ECB_FLAGS_READ; ! 1180: } ! 1181: ! 1182: // ! 1183: // Check if disconnect explicity forbidden. ! 1184: // ! 1185: ! 1186: if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) { ! 1187: ! 1188: ecb->Flags[1] |= ECB_FLAGS_NO_DISCONNECT; ! 1189: } ! 1190: ! 1191: // ! 1192: // Set LUN (bits 16, 17 and 18). ! 1193: // ! 1194: ! 1195: ecb->Flags[1] |= Srb->Lun; ! 1196: ! 1197: // ! 1198: // Set CDB length and copy to ECB. ! 1199: // ! 1200: ! 1201: ecb->CdbLength = Srb->CdbLength; ! 1202: ScsiPortMoveMemory(ecb->Cdb, Srb->Cdb, Srb->CdbLength); ! 1203: ! 1204: // ! 1205: // Build SGL in ECB if data transfer. ! 1206: // ! 1207: ! 1208: if (Srb->DataTransferLength > 0) { ! 1209: ecb->Flags[0] |= ECB_FLAGS_SCATTER_GATHER; ! 1210: A174xBuildSgl(DeviceExtension, Srb); ! 1211: } else { ! 1212: ecb->SglLength = 0; ! 1213: } ! 1214: ! 1215: // ! 1216: // Set status block pointer. ! 1217: // ! 1218: ! 1219: ecb->StatusBlockAddress = ! 1220: ScsiPortConvertPhysicalAddressToUlong( ! 1221: ScsiPortGetPhysicalAddress(DeviceExtension, ! 1222: NULL, ! 1223: statusBlock, ! 1224: &length)); ! 1225: ! 1226: ASSERT(length >= sizeof(STATUS_BLOCK)); ! 1227: ! 1228: // ! 1229: // Setup auto sense if necessary. ! 1230: // ! 1231: ! 1232: if (Srb->SenseInfoBufferLength != 0 && ! 1233: !(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)) { ! 1234: ! 1235: // ! 1236: // Set the flag to enable auto sense and fill in the address and length ! 1237: // of the sense buffer. ! 1238: // ! 1239: ! 1240: ecb->Flags[0] |= ECB_FLAGS_AUTO_REQUEST_SENSE; ! 1241: ecb->SenseInfoLength = Srb->SenseInfoBufferLength; ! 1242: ecb->SenseInfoAddress = ScsiPortConvertPhysicalAddressToUlong( ! 1243: ScsiPortGetPhysicalAddress(DeviceExtension, ! 1244: Srb, ! 1245: Srb->SenseInfoBuffer, ! 1246: &length)); ! 1247: ! 1248: ASSERT(length >= Srb->SenseInfoBufferLength); ! 1249: ! 1250: } else { ! 1251: ! 1252: ecb->SenseInfoLength = 0; ! 1253: } ! 1254: ! 1255: // ! 1256: // Zero out next ECB, request sense info fields ! 1257: // and statuses in status block. ! 1258: // ! 1259: ! 1260: ecb->NextEcb = 0; ! 1261: statusBlock->HaStatus = 0; ! 1262: statusBlock->TargetStatus = 0; ! 1263: ! 1264: return; ! 1265: ! 1266: } // end A174xBuildEcb() ! 1267: ! 1268: ! 1269: VOID ! 1270: A174xBuildSgl( ! 1271: IN PHW_DEVICE_EXTENSION DeviceExtension, ! 1272: IN PSCSI_REQUEST_BLOCK Srb ! 1273: ) ! 1274: ! 1275: /*++ ! 1276: ! 1277: Routine Description: ! 1278: ! 1279: This routine builds a scatter/gather descriptor list for the ECB. ! 1280: ! 1281: Arguments: ! 1282: ! 1283: DeviceExtension ! 1284: Srb ! 1285: ! 1286: Return Value: ! 1287: ! 1288: None ! 1289: ! 1290: --*/ ! 1291: ! 1292: { ! 1293: PVOID dataPointer = Srb->DataBuffer; ! 1294: ULONG bytesLeft = Srb->DataTransferLength; ! 1295: PECB ecb = Srb->SrbExtension; ! 1296: PSGL sgl = &ecb->Sgl; ! 1297: ULONG physicalSgl; ! 1298: ULONG physicalAddress; ! 1299: ULONG length; ! 1300: ULONG descriptorCount = 0; ! 1301: ! 1302: // ! 1303: // Get physical SGL address. ! 1304: // ! 1305: ! 1306: physicalSgl = ScsiPortConvertPhysicalAddressToUlong( ! 1307: ScsiPortGetPhysicalAddress(DeviceExtension, NULL, ! 1308: sgl, &length)); ! 1309: ! 1310: // ! 1311: // Assume physical memory contiguous for sizeof(SGL) bytes. ! 1312: // ! 1313: ! 1314: ASSERT(length >= sizeof(SGL)); ! 1315: ! 1316: // ! 1317: // Create SGL segment descriptors. ! 1318: // ! 1319: ! 1320: do { ! 1321: ! 1322: // ! 1323: // Get physical address and length of contiguous ! 1324: // physical buffer. ! 1325: // ! 1326: ! 1327: physicalAddress = ! 1328: ScsiPortConvertPhysicalAddressToUlong( ! 1329: ScsiPortGetPhysicalAddress(DeviceExtension, ! 1330: Srb, ! 1331: dataPointer, ! 1332: &length)); ! 1333: ! 1334: // ! 1335: // If length of physical memory is more ! 1336: // than bytes left in transfer, use bytes ! 1337: // left as final length. ! 1338: // ! 1339: ! 1340: if (length > bytesLeft) { ! 1341: length = bytesLeft; ! 1342: } ! 1343: ! 1344: sgl->Descriptor[descriptorCount].Address = physicalAddress; ! 1345: sgl->Descriptor[descriptorCount].Length = length; ! 1346: ! 1347: // ! 1348: // Adjust counts. ! 1349: // ! 1350: ! 1351: dataPointer = (PUCHAR)dataPointer + length; ! 1352: bytesLeft -= length; ! 1353: descriptorCount++; ! 1354: ! 1355: } while (bytesLeft); ! 1356: ! 1357: // ! 1358: // Write SGL length to ECB. ! 1359: // ! 1360: ! 1361: ecb->SglLength = descriptorCount * sizeof(SG_DESCRIPTOR); ! 1362: ! 1363: // ! 1364: // Write SGL address to ECB. ! 1365: // ! 1366: ! 1367: ecb->PhysicalSgl = physicalSgl; ! 1368: ! 1369: return; ! 1370: ! 1371: } // end A174xBuildSgl() ! 1372: ! 1373: ! 1374: VOID ! 1375: A174xBuildRequestSense( ! 1376: IN PVOID HwDeviceExtension, ! 1377: IN PSCSI_REQUEST_BLOCK Srb ! 1378: ) ! 1379: ! 1380: /*++ ! 1381: ! 1382: Routine Description: ! 1383: ! 1384: This routine is called when a request sense is detected. An adapter ! 1385: command is then built for a request sense. This is the ! 1386: only way to clear the contingent alligience condition that the adapter ! 1387: is always in following a check condition. ! 1388: ! 1389: Arguments: ! 1390: ! 1391: HwDeviceExtension - HBA miniport driver's adapter data storage ! 1392: Srb - IO request packet ! 1393: ! 1394: Return Value: ! 1395: ! 1396: TRUE is request succeeds. ! 1397: ! 1398: --*/ ! 1399: ! 1400: { ! 1401: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; ! 1402: PEISA_CONTROLLER eisaController = deviceExtension->EisaController; ! 1403: PECB ecb = Srb->SrbExtension; ! 1404: PSTATUS_BLOCK statusBlock = &ecb->StatusBlock; ! 1405: ULONG length; ! 1406: ! 1407: // ! 1408: // Set ECB command. ! 1409: // ! 1410: ! 1411: ecb->Command = ECB_COMMAND_READ_SENSE_INFO; ! 1412: ! 1413: // ! 1414: // Disable updating status block on success and enable ! 1415: // automatic request senes. ! 1416: // ! 1417: ! 1418: ecb->Flags[0] = ECB_FLAGS_DISABLE_STATUS_BLOCK | ! 1419: ECB_FLAGS_SUPPRESS_UNDERRUN; ! 1420: ! 1421: // ! 1422: // Set transfer direction bit. ! 1423: // ! 1424: ! 1425: ecb->Flags[1] = ECB_FLAGS_READ; ! 1426: ! 1427: // ! 1428: // Check if disconnect explicity forbidden. ! 1429: // ! 1430: ! 1431: if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) { ! 1432: ! 1433: ecb->Flags[1] |= ECB_FLAGS_NO_DISCONNECT; ! 1434: } ! 1435: ! 1436: // ! 1437: // Set LUN (bits 16, 17 and 18). ! 1438: // ! 1439: ! 1440: ecb->Flags[1] |= Srb->Lun; ! 1441: ! 1442: // ! 1443: // Set status block pointer. ! 1444: // ! 1445: ! 1446: ecb->StatusBlockAddress = ! 1447: ScsiPortConvertPhysicalAddressToUlong( ! 1448: ScsiPortGetPhysicalAddress(deviceExtension, ! 1449: NULL, ! 1450: statusBlock, ! 1451: &length)); ! 1452: ! 1453: // ! 1454: // Set request sense address and length. ! 1455: // ! 1456: ! 1457: ecb->SenseInfoAddress = ScsiPortConvertPhysicalAddressToUlong( ! 1458: ScsiPortGetPhysicalAddress(deviceExtension, ! 1459: Srb, ! 1460: Srb->DataBuffer, ! 1461: &length)); ! 1462: ! 1463: ASSERT(length >= Srb->DataTransferLength); ! 1464: ! 1465: ecb->SenseInfoLength = (UCHAR) Srb->DataTransferLength; ! 1466: ! 1467: // ! 1468: // Zero out next ECB, request sense info fields ! 1469: // and statuses in status block. ! 1470: // ! 1471: ! 1472: ecb->NextEcb = 0; ! 1473: statusBlock->HaStatus = 0; ! 1474: statusBlock->TargetStatus = 0; ! 1475: ! 1476: return; ! 1477: ! 1478: } // end A174xBuildRequestSense() ! 1479: ! 1480: ! 1481: BOOLEAN ! 1482: A174xSendCommand( ! 1483: IN PHW_DEVICE_EXTENSION DeviceExtension, ! 1484: IN UCHAR OperationCode, ! 1485: IN ULONG Address ! 1486: ) ! 1487: ! 1488: /*++ ! 1489: ! 1490: Routine Description: ! 1491: ! 1492: Send ECB or immediate command to AHA174X. ! 1493: ! 1494: Arguments: ! 1495: ! 1496: HwDeviceExtension - HBA miniport driver's adapter data storage ! 1497: OperationCode - value to be written to attention register ! 1498: Address - ECB address or immediate command ! 1499: ! 1500: Return Value: ! 1501: ! 1502: True if command sent. ! 1503: False if adapter never reached 'ready for next command' state. ! 1504: ! 1505: --*/ ! 1506: ! 1507: { ! 1508: PEISA_CONTROLLER eisaController = DeviceExtension->EisaController; ! 1509: ULONG i; ! 1510: ! 1511: for (i=0; i<10; i++) { ! 1512: ! 1513: UCHAR status; ! 1514: ! 1515: status = ScsiPortReadPortUchar(&eisaController->Status); ! 1516: ! 1517: if ((status & MAILBOX_OUT_EMPTY) && ! 1518: !(status & ADAPTER_BUSY)) { ! 1519: ! 1520: // ! 1521: // Adapter ready for next command. ! 1522: // ! 1523: ! 1524: break; ! 1525: ! 1526: } else { ! 1527: ! 1528: // ! 1529: // Stall 1 microsecond before trying again. ! 1530: // ! 1531: ! 1532: ScsiPortStallExecution(1); ! 1533: } ! 1534: } ! 1535: ! 1536: if (i == 10) { ! 1537: ! 1538: return FALSE; ! 1539: } ! 1540: ! 1541: // ! 1542: // Write ECB address or immediate command. ! 1543: // ! 1544: ! 1545: ScsiPortWritePortUlong(&eisaController->MailBoxOut, Address); ! 1546: ! 1547: // ! 1548: // Write operation code to attention register. ! 1549: // ! 1550: ! 1551: ScsiPortWritePortUchar(&eisaController->Attention, OperationCode); ! 1552: ! 1553: return TRUE; ! 1554: ! 1555: } // end A174xSendCommand() ! 1556: ! 1557: BOOLEAN ! 1558: Aha174xResetBus( ! 1559: IN PVOID HwDeviceExtension, ! 1560: IN ULONG PathId ! 1561: ) ! 1562: ! 1563: /*++ ! 1564: ! 1565: Routine Description: ! 1566: ! 1567: Reset Aha174x SCSI adapter and SCSI bus. ! 1568: ! 1569: Arguments: ! 1570: ! 1571: HwDeviceExtension - HBA miniport driver's adapter data storage ! 1572: ! 1573: Return Value: ! 1574: ! 1575: Nothing. ! 1576: ! 1577: --*/ ! 1578: ! 1579: { ! 1580: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; ! 1581: PEISA_CONTROLLER eisaController = deviceExtension->EisaController; ! 1582: ULONG j; ! 1583: UCHAR targetId; ! 1584: UCHAR lun; ! 1585: ! 1586: ! 1587: UNREFERENCED_PARAMETER(PathId); ! 1588: ! 1589: DebugPrint((2,"ResetBus: Reset Aha174x and SCSI bus\n")); ! 1590: ! 1591: // ! 1592: // Clean up pending requests. ! 1593: // ! 1594: ! 1595: if (deviceExtension->PendingSrb) { ! 1596: ! 1597: // ! 1598: // Notify the port driver that another request can be accepted. ! 1599: // ! 1600: ! 1601: ScsiPortNotification(NextRequest, deviceExtension); ! 1602: ! 1603: // ! 1604: // Clear the pending request. It will be completed by ! 1605: // ScsiPortCompleteRequest. ! 1606: // ! 1607: ! 1608: deviceExtension->PendingSrb = NULL; ! 1609: ! 1610: } ! 1611: ! 1612: // ! 1613: // Clear the reqeust counts. ! 1614: // ! 1615: ! 1616: for (targetId = 0; targetId < 8; targetId++) { ! 1617: for (lun = 0; lun < 8; lun++) { ! 1618: ! 1619: deviceExtension->RequestCount[targetId][lun] = 0; ! 1620: } ! 1621: } ! 1622: ! 1623: // ! 1624: // Complete all outstanding requests. ! 1625: // ! 1626: ! 1627: ScsiPortCompleteRequest(deviceExtension, ! 1628: 0, ! 1629: SP_UNTAGGED, ! 1630: SP_UNTAGGED, ! 1631: SRB_STATUS_BUS_RESET); ! 1632: ! 1633: targetId = deviceExtension->HostTargetId; ! 1634: ! 1635: // ! 1636: // Allow the adapter card to settle. ! 1637: // ! 1638: ! 1639: ScsiPortStallExecution(75000); ! 1640: ScsiPortReadPortUchar(&eisaController->Status); ! 1641: ScsiPortStallExecution(1); ! 1642: ! 1643: if (!A174xSendCommand(deviceExtension, ! 1644: (UCHAR)(IMMEDIATE_COMMAND | targetId), ! 1645: ECB_IMMEDIATE_RESET)) { ! 1646: ! 1647: // ! 1648: // Timed out waiting for adapter to become ready. ! 1649: // ! 1650: ! 1651: ScsiPortLogError( ! 1652: deviceExtension, ! 1653: NULL, ! 1654: 0, ! 1655: deviceExtension->HostTargetId, ! 1656: 0, ! 1657: SP_INTERNAL_ADAPTER_ERROR, ! 1658: 4 << 16 ! 1659: ); ! 1660: ! 1661: // ! 1662: // Adapter never reached state to receive command. ! 1663: // Try a hard reset by wiggling the control line. ! 1664: // ! 1665: ! 1666: ScsiPortWritePortUchar(&eisaController->Control, HARD_RESET); ! 1667: ! 1668: // ! 1669: // Wait at least 10 microseconds. ! 1670: // ! 1671: ! 1672: ScsiPortStallExecution(10); ! 1673: ! 1674: // ! 1675: // Clear the reset line now that it has been held for 10 us. ! 1676: // ! 1677: ! 1678: ScsiPortWritePortUchar(&eisaController->Control, 0); ! 1679: ! 1680: // ! 1681: // Write the attention register to wake up the firmware so that ! 1682: // it will clear the busy line in the status register. ! 1683: // The attention value written (0) is ignored by the controller ! 1684: // but will wakeup the firmware. ! 1685: // ! 1686: ! 1687: ScsiPortStallExecution(20000); // Add a little delay ! 1688: ScsiPortWritePortUchar(&eisaController->Attention, 0); ! 1689: ! 1690: // ! 1691: // Wait for busy to go low. ! 1692: // ! 1693: ! 1694: j = 0; ! 1695: while (ScsiPortReadPortUchar(&eisaController->Status) & ADAPTER_BUSY) { ! 1696: ! 1697: j++; ! 1698: if (j > 200000) { ! 1699: ! 1700: // ! 1701: // Busy has not gone low. Assume the card is gone. ! 1702: // Log the error and fail the request. ! 1703: // ! 1704: ! 1705: ! 1706: ScsiPortLogError( ! 1707: deviceExtension, ! 1708: NULL, ! 1709: 0, ! 1710: deviceExtension->HostTargetId, ! 1711: 0, ! 1712: SP_INTERNAL_ADAPTER_ERROR, ! 1713: 3 << 16 ! 1714: ); ! 1715: ! 1716: return FALSE; ! 1717: ! 1718: } ! 1719: ! 1720: ScsiPortStallExecution(10); ! 1721: } ! 1722: } ! 1723: ! 1724: return TRUE; ! 1725: ! 1726: } // end Aha174xResetBus() ! 1727: ! 1728: ! 1729: VOID ! 1730: A174xMapStatus( ! 1731: IN PHW_DEVICE_EXTENSION DeviceExtension, ! 1732: IN PSCSI_REQUEST_BLOCK Srb, ! 1733: IN PSTATUS_BLOCK StatusBlock ! 1734: ) ! 1735: ! 1736: /*++ ! 1737: ! 1738: Routine Description: ! 1739: ! 1740: Translate Aha174x error to SRB error. ! 1741: ! 1742: Arguments: ! 1743: ! 1744: SRB ! 1745: Status block for request completing with error. ! 1746: ! 1747: Return Value: ! 1748: ! 1749: Updated SRB ! 1750: ! 1751: --*/ ! 1752: ! 1753: { ! 1754: ULONG logError = 0; ! 1755: UCHAR srbStatus; ! 1756: PECB ecb = Srb->SrbExtension; ! 1757: ! 1758: ! 1759: DebugPrint((2, ! 1760: "A174xMapStatus: Status word is %x\n", ! 1761: StatusBlock->StatusWord)); ! 1762: ! 1763: if (StatusBlock->TargetStatus == SCSISTAT_CHECK_CONDITION) { ! 1764: ! 1765: // ! 1766: // A check condition occured. Set the srb status and process the ! 1767: // auto sense data. ! 1768: // ! 1769: ! 1770: Srb->SrbStatus = SRB_STATUS_ERROR; ! 1771: ! 1772: // ! 1773: // Set target SCSI status in SRB. ! 1774: // ! 1775: ! 1776: Srb->ScsiStatus = StatusBlock->TargetStatus; ! 1777: ! 1778: // ! 1779: // Update SRB with actual bytes transferred. ! 1780: // ! 1781: ! 1782: Srb->DataTransferLength -= StatusBlock->ResidualByteCount; ! 1783: ! 1784: if (StatusBlock->StatusWord & SB_STATUS_SENSE_INFORMATION) { ! 1785: ! 1786: // ! 1787: // Indicate the sense information is valid and update the length. ! 1788: // ! 1789: ! 1790: Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; ! 1791: Srb->SenseInfoBufferLength = StatusBlock->RequestSenseLength; ! 1792: } ! 1793: ! 1794: return; ! 1795: } ! 1796: ! 1797: switch (StatusBlock->HaStatus) { ! 1798: ! 1799: case SB_HASTATUS_SELECTION_TIMEOUT: ! 1800: srbStatus = SRB_STATUS_SELECTION_TIMEOUT; ! 1801: break; ! 1802: ! 1803: case SB_HASTATUS_DATA_OVERUNDER_RUN: ! 1804: DebugPrint((1,"A174xMapStatus: Data over/underrun\n")); ! 1805: ! 1806: // ! 1807: // Update SRB with actual bytes transferred. ! 1808: // ! 1809: ! 1810: Srb->DataTransferLength -= StatusBlock->ResidualByteCount; ! 1811: ! 1812: srbStatus = SRB_STATUS_DATA_OVERRUN; ! 1813: break; ! 1814: ! 1815: case SB_HASTATUS_UNEXPECTED_BUS_FREE: ! 1816: DebugPrint((1,"A174xMapStatus: Unexpected bus free\n")); ! 1817: logError = SP_PROTOCOL_ERROR; ! 1818: srbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE; ! 1819: break; ! 1820: ! 1821: case SB_HASTATUS_INVALID_BUS_PHASE: ! 1822: DebugPrint((1,"A174xMapStatus: Invalid bus phase\n")); ! 1823: logError = SP_PROTOCOL_ERROR; ! 1824: srbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE; ! 1825: break; ! 1826: ! 1827: case SB_HASTATUS_TARGET_NOT_USED: ! 1828: DebugPrint((1,"A174xMapStatus: Target not used\n")); ! 1829: srbStatus = SRB_STATUS_NO_DEVICE; ! 1830: break; ! 1831: ! 1832: case SB_HASTATUS_INVALID_ECB: ! 1833: DebugPrint((1,"A174xMapStatus: Invalid ECB\n")); ! 1834: logError = SP_INTERNAL_ADAPTER_ERROR; ! 1835: srbStatus = SRB_STATUS_INVALID_REQUEST; ! 1836: break; ! 1837: ! 1838: case SB_HASTATUS_ADAPTER_HARDWARE_ERROR: ! 1839: DebugPrint((1,"A174xMapStatus: Hardware error\n")); ! 1840: logError = SP_INTERNAL_ADAPTER_ERROR; ! 1841: srbStatus = SRB_STATUS_ERROR; ! 1842: break; ! 1843: ! 1844: case SB_HASTATUS_ADAPTER_RESET_BUS: ! 1845: DebugPrint((1,"A174xMapStatus: Adapter reset bus\n")); ! 1846: srbStatus = SRB_STATUS_BUS_RESET; ! 1847: break; ! 1848: ! 1849: case SB_HASTATUS_DEVICE_RESET_BUS: ! 1850: DebugPrint((1,"A174xMapStatus: Device reset bus\n")); ! 1851: srbStatus = SRB_STATUS_BUS_RESET; ! 1852: break; ! 1853: ! 1854: case SB_HASTATUS_CHECKSUM_FAILURE: ! 1855: DebugPrint((1,"A174xMapStatus: Checksum failure\n")); ! 1856: logError = SP_INTERNAL_ADAPTER_ERROR; ! 1857: srbStatus = SRB_STATUS_ERROR; ! 1858: break; ! 1859: ! 1860: case SB_HASTATUS_ADAPTER_ABORTED: ! 1861: DebugPrint((1,"A174xMapStatus: Adapter aborted\n")); ! 1862: srbStatus = SRB_STATUS_ABORTED; ! 1863: break; ! 1864: ! 1865: case SB_HASTATUS_HOST_ABORTED: ! 1866: DebugPrint((1,"A174xMapStatus: Host aborted\n")); ! 1867: srbStatus = SRB_STATUS_ABORTED; ! 1868: break; ! 1869: ! 1870: case SB_HASTATUS_FW_NOT_DOWNLOADED: ! 1871: DebugPrint((1,"A174xMapStatus: Firmware not downloaded\n")); ! 1872: logError = SP_INTERNAL_ADAPTER_ERROR; ! 1873: srbStatus = SRB_STATUS_ERROR; ! 1874: break; ! 1875: ! 1876: case SB_HASTATUS_INVALID_SGL: ! 1877: DebugPrint((1,"A174xMapStatus: Invalid SGL\n")); ! 1878: logError = SP_INTERNAL_ADAPTER_ERROR; ! 1879: srbStatus = SRB_STATUS_INVALID_REQUEST; ! 1880: break; ! 1881: ! 1882: case SB_HASTATUS_REQUEST_SENSE_FAILED: ! 1883: DebugPrint((1,"A174xMapStatus: Request sense failed\n")); ! 1884: srbStatus = SRB_STATUS_ERROR; ! 1885: break; ! 1886: ! 1887: default: ! 1888: ! 1889: srbStatus = SRB_STATUS_ERROR; ! 1890: ! 1891: // ! 1892: // Check status block word. ! 1893: // ! 1894: ! 1895: if (StatusBlock->StatusWord & SB_STATUS_NO_ERROR) { ! 1896: ! 1897: // ! 1898: // This should never happen as this routine is only ! 1899: // called when there is an error. ! 1900: // ! 1901: ! 1902: DebugPrint((1,"A174xMapStatus: No error\n")); ! 1903: srbStatus = SRB_STATUS_SUCCESS; ! 1904: break; ! 1905: ! 1906: } ! 1907: ! 1908: // ! 1909: // Check for underrun. ! 1910: // ! 1911: ! 1912: if (StatusBlock->StatusWord & SB_STATUS_DATA_UNDERRUN) { ! 1913: ! 1914: DebugPrint((1, ! 1915: "A174xMapStatus: Data underrun indicated in status word\n")); ! 1916: ! 1917: // ! 1918: // Update SRB with actual bytes transferred. ! 1919: // ! 1920: ! 1921: Srb->DataTransferLength -= StatusBlock->ResidualByteCount; ! 1922: break; ! 1923: } ! 1924: ! 1925: // ! 1926: // Check for overrun. ! 1927: // ! 1928: ! 1929: if (StatusBlock->StatusWord & SB_STATUS_DATA_OVERRUN) { ! 1930: ! 1931: DebugPrint((1, ! 1932: "A174xMapStatus: Data overrun indicate in status word\n")); ! 1933: logError = SP_PROTOCOL_ERROR; ! 1934: break; ! 1935: } ! 1936: ! 1937: // ! 1938: // Check for initialization required. ! 1939: // ! 1940: ! 1941: if (StatusBlock->StatusWord & SB_STATUS_INIT_REQUIRED) { ! 1942: DebugPrint((1, ! 1943: "A174xMapStatus: Initialization required\n")); ! 1944: break; ! 1945: } ! 1946: ! 1947: // ! 1948: // Check for contingent allegience condition. If this happens ! 1949: // something is very wrong (because autorequest sense was indicated). ! 1950: // ! 1951: ! 1952: if (StatusBlock->StatusWord & SB_STATUS_EXT_CONT_ALLEGIANCE) { ! 1953: ! 1954: DebugPrint((1, ! 1955: "A174xMapStatus: Contingent allegiance condition\n")); ! 1956: ! 1957: ASSERT(0); ! 1958: } ! 1959: ! 1960: if (StatusBlock->StatusWord & SB_STATUS_MAJOR_ERROR) { ! 1961: ! 1962: DebugPrint((1, ! 1963: "A174xMapStatus: Major error indicated in status word\n")); ! 1964: break; ! 1965: } ! 1966: ! 1967: logError = SP_INTERNAL_ADAPTER_ERROR; ! 1968: break; ! 1969: ! 1970: } // end switch ... ! 1971: ! 1972: if (logError != 0) { ! 1973: ! 1974: // ! 1975: // Log error. ! 1976: // ! 1977: ! 1978: ScsiPortLogError( ! 1979: DeviceExtension, ! 1980: Srb, ! 1981: Srb->PathId, ! 1982: Srb->TargetId, ! 1983: Srb->Lun, ! 1984: logError, ! 1985: 2 << 16 | StatusBlock->HaStatus ! 1986: ); ! 1987: ! 1988: } ! 1989: ! 1990: // ! 1991: // Set SRB status. ! 1992: // ! 1993: ! 1994: Srb->SrbStatus = srbStatus; ! 1995: ! 1996: // ! 1997: // Set target SCSI status in SRB. ! 1998: // ! 1999: ! 2000: Srb->ScsiStatus = StatusBlock->TargetStatus; ! 2001: ! 2002: return; ! 2003: ! 2004: } // end A174xMapStatus()
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.