1 /* 2 * PROJECT: ReactOS Storage Stack 3 * LICENSE: DDK - see license.txt in the root dir 4 * FILE: drivers/storage/atapi/atapi.c 5 * PURPOSE: ATAPI IDE miniport driver 6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK 7 */ 8 9 #include <ntddk.h> 10 #include "atapi.h" // includes scsi.h 11 #include <ntddscsi.h> 12 #include <ntdddisk.h> 13 #include <ntddstor.h> 14 15 //#define NDEBUG 16 #include <debug.h> 17 18 // 19 // Device extension 20 // 21 22 typedef struct _HW_DEVICE_EXTENSION { 23 24 // 25 // Current request on controller. 26 // 27 28 PSCSI_REQUEST_BLOCK CurrentSrb; 29 30 // 31 // Base register locations 32 // 33 34 PIDE_REGISTERS_1 BaseIoAddress1[2]; 35 PIDE_REGISTERS_2 BaseIoAddress2[2]; 36 37 // 38 // Interrupt level 39 // 40 41 ULONG InterruptLevel; 42 43 // 44 // Interrupt Mode (Level or Edge) 45 // 46 47 ULONG InterruptMode; 48 49 // 50 // Data buffer pointer. 51 // 52 53 PUSHORT DataBuffer; 54 55 // 56 // Data words left. 57 // 58 59 ULONG WordsLeft; 60 61 // 62 // Number of channels being supported by one instantiation 63 // of the device extension. Normally (and correctly) one, but 64 // with so many broken PCI IDE controllers being sold, we have 65 // to support them. 66 // 67 68 ULONG NumberChannels; 69 70 // 71 // Count of errors. Used to turn off features. 72 // 73 74 ULONG ErrorCount; 75 76 // 77 // Indicates number of platters on changer-ish devices. 78 // 79 80 ULONG DiscsPresent[4]; 81 82 // 83 // Flags word for each possible device. 84 // 85 86 USHORT DeviceFlags[4]; 87 88 // 89 // Indicates the number of blocks transferred per int. according to the 90 // identify data. 91 // 92 93 UCHAR MaximumBlockXfer[4]; 94 95 // 96 // Indicates expecting an interrupt 97 // 98 99 BOOLEAN ExpectingInterrupt; 100 101 // 102 // Indicate last tape command was DSC Restrictive. 103 // 104 105 BOOLEAN RDP; 106 107 // 108 // Driver is being used by the crash dump utility or ntldr. 109 // 110 111 BOOLEAN DriverMustPoll; 112 113 // 114 // Indicates use of 32-bit PIO 115 // 116 117 BOOLEAN DWordIO; 118 119 // 120 // Indicates whether '0x1f0' is the base address. Used 121 // in SMART Ioctl calls. 122 // 123 124 BOOLEAN PrimaryAddress; 125 126 // 127 // Placeholder for the sub-command value of the last 128 // SMART command. 129 // 130 131 UCHAR SmartCommand; 132 133 // 134 // Placeholder for status register after a GET_MEDIA_STATUS command 135 // 136 137 UCHAR ReturningMediaStatus; 138 139 UCHAR Reserved[1]; 140 141 // 142 // Identify data for device 143 // 144 145 IDENTIFY_DATA FullIdentifyData; 146 IDENTIFY_DATA2 IdentifyData[4]; 147 148 // 149 // Mechanism Status Srb Data 150 // 151 PSCSI_REQUEST_BLOCK OriginalSrb; 152 SCSI_REQUEST_BLOCK InternalSrb; 153 MECHANICAL_STATUS_INFORMATION_HEADER MechStatusData; 154 SENSE_DATA MechStatusSense; 155 ULONG MechStatusRetryCount; 156 157 } HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION; 158 159 // 160 // Logical unit extension 161 // 162 163 typedef struct _HW_LU_EXTENSION { 164 ULONG Reserved; 165 } HW_LU_EXTENSION, *PHW_LU_EXTENSION; 166 167 PSCSI_REQUEST_BLOCK 168 NTAPI 169 BuildMechanismStatusSrb ( 170 IN PVOID HwDeviceExtension, 171 IN ULONG PathId, 172 IN ULONG TargetId 173 ); 174 175 PSCSI_REQUEST_BLOCK 176 NTAPI 177 BuildRequestSenseSrb ( 178 IN PVOID HwDeviceExtension, 179 IN ULONG PathId, 180 IN ULONG TargetId 181 ); 182 183 VOID 184 NTAPI 185 AtapiHwInitializeChanger ( 186 IN PVOID HwDeviceExtension, 187 IN ULONG TargetId, 188 IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus 189 ); 190 191 ULONG 192 NTAPI 193 AtapiSendCommand( 194 IN PVOID HwDeviceExtension, 195 IN PSCSI_REQUEST_BLOCK Srb 196 ); 197 198 VOID 199 NTAPI 200 AtapiZeroMemory( 201 IN PUCHAR Buffer, 202 IN ULONG Count 203 ); 204 205 VOID 206 NTAPI 207 AtapiHexToString ( 208 ULONG Value, 209 PCHAR *Buffer 210 ); 211 212 LONG 213 NTAPI 214 AtapiStringCmp ( 215 PCHAR FirstStr, 216 PCHAR SecondStr, 217 ULONG Count 218 ); 219 220 BOOLEAN 221 NTAPI 222 AtapiInterrupt( 223 IN PVOID HwDeviceExtension 224 ); 225 226 BOOLEAN 227 NTAPI 228 AtapiHwInitialize( 229 IN PVOID HwDeviceExtension 230 ); 231 232 ULONG 233 NTAPI 234 IdeBuildSenseBuffer( 235 IN PVOID HwDeviceExtension, 236 IN PSCSI_REQUEST_BLOCK Srb 237 ); 238 239 VOID 240 NTAPI 241 IdeMediaStatus( 242 IN BOOLEAN EnableMSN, 243 IN PVOID HwDeviceExtension, 244 IN ULONG Channel 245 ); 246 247 248 249 BOOLEAN 250 NTAPI 251 IssueIdentify( 252 IN PVOID HwDeviceExtension, 253 IN ULONG DeviceNumber, 254 IN ULONG Channel, 255 IN UCHAR Command 256 ) 257 258 /*++ 259 260 Routine Description: 261 262 Issue IDENTIFY command to a device. 263 264 Arguments: 265 266 HwDeviceExtension - HBA miniport driver's adapter data storage 267 DeviceNumber - Indicates which device. 268 Command - Either the standard (EC) or the ATAPI packet (A1) IDENTIFY. 269 270 Return Value: 271 272 TRUE if all goes well. 273 274 --*/ 275 276 { 277 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 278 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel] ; 279 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel]; 280 ULONG waitCount = 20000; 281 ULONG i,j; 282 UCHAR statusByte; 283 UCHAR signatureLow, 284 signatureHigh; 285 286 // 287 // Select device 0 or 1. 288 // 289 290 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 291 (UCHAR)((DeviceNumber << 4) | 0xA0)); 292 293 // 294 // Check that the status register makes sense. 295 // 296 297 GetBaseStatus(baseIoAddress1, statusByte); 298 299 if (Command == IDE_COMMAND_IDENTIFY) { 300 301 // 302 // Mask status byte ERROR bits. 303 // 304 305 statusByte &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX); 306 307 DebugPrint((1, 308 "IssueIdentify: Checking for IDE. Status (%x)\n", 309 statusByte)); 310 311 // 312 // Check if register value is reasonable. 313 // 314 315 if (statusByte != IDE_STATUS_IDLE) { 316 317 // 318 // Reset the controller. 319 // 320 321 AtapiSoftReset(baseIoAddress1,DeviceNumber); 322 323 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 324 (UCHAR)((DeviceNumber << 4) | 0xA0)); 325 326 WaitOnBusy(baseIoAddress2,statusByte); 327 328 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 329 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 330 331 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 332 333 // 334 // Device is Atapi. 335 // 336 337 return FALSE; 338 } 339 340 DebugPrint((1, 341 "IssueIdentify: Resetting controller.\n")); 342 343 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER ); 344 ScsiPortStallExecution(500 * 1000); 345 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER); 346 347 348 // We really should wait up to 31 seconds 349 // The ATA spec. allows device 0 to come back from BUSY in 31 seconds! 350 // (30 seconds for device 1) 351 do { 352 353 // 354 // Wait for Busy to drop. 355 // 356 357 ScsiPortStallExecution(100); 358 GetStatus(baseIoAddress2, statusByte); 359 360 } while ((statusByte & IDE_STATUS_BUSY) && waitCount--); 361 362 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 363 (UCHAR)((DeviceNumber << 4) | 0xA0)); 364 365 // 366 // Another check for signature, to deal with one model Atapi that doesn't assert signature after 367 // a soft reset. 368 // 369 370 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 371 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 372 373 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 374 375 // 376 // Device is Atapi. 377 // 378 379 return FALSE; 380 } 381 382 statusByte &= ~IDE_STATUS_INDEX; 383 384 if (statusByte != IDE_STATUS_IDLE) { 385 386 // 387 // Give up on this. 388 // 389 390 return FALSE; 391 } 392 393 } 394 395 } else { 396 397 DebugPrint((1, 398 "IssueIdentify: Checking for ATAPI. Status (%x)\n", 399 statusByte)); 400 401 } 402 403 // 404 // Load CylinderHigh and CylinderLow with number bytes to transfer. 405 // 406 407 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh, (0x200 >> 8)); 408 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow, (0x200 & 0xFF)); 409 410 for (j = 0; j < 2; j++) { 411 412 // 413 // Send IDENTIFY command. 414 // 415 416 WaitOnBusy(baseIoAddress2,statusByte); 417 418 ScsiPortWritePortUchar(&baseIoAddress1->Command, Command); 419 420 // 421 // Wait for DRQ. 422 // 423 424 for (i = 0; i < 4; i++) { 425 426 WaitForDrq(baseIoAddress2, statusByte); 427 428 if (statusByte & IDE_STATUS_DRQ) { 429 430 // 431 // Read status to acknowledge any interrupts generated. 432 // 433 434 GetBaseStatus(baseIoAddress1, statusByte); 435 436 // 437 // One last check for Atapi. 438 // 439 440 441 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 442 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 443 444 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 445 446 // 447 // Device is Atapi. 448 // 449 450 return FALSE; 451 } 452 453 break; 454 } 455 456 if (Command == IDE_COMMAND_IDENTIFY) { 457 458 // 459 // Check the signature. If DRQ didn't come up it's likely Atapi. 460 // 461 462 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 463 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 464 465 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 466 467 // 468 // Device is Atapi. 469 // 470 471 return FALSE; 472 } 473 } 474 475 WaitOnBusy(baseIoAddress2,statusByte); 476 } 477 478 if (i == 4 && j == 0) { 479 480 // 481 // Device didn't respond correctly. It will be given one more chances. 482 // 483 484 DebugPrint((1, 485 "IssueIdentify: DRQ never asserted (%x). Error reg (%x)\n", 486 statusByte, 487 ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1))); 488 489 AtapiSoftReset(baseIoAddress1,DeviceNumber); 490 491 GetStatus(baseIoAddress2,statusByte); 492 493 DebugPrint((1, 494 "IssueIdentify: Status after soft reset (%x)\n", 495 statusByte)); 496 497 } else { 498 499 break; 500 501 } 502 } 503 504 // 505 // Check for error on really stupid master devices that assert random 506 // patterns of bits in the status register at the slave address. 507 // 508 509 if ((Command == IDE_COMMAND_IDENTIFY) && (statusByte & IDE_STATUS_ERROR)) { 510 return FALSE; 511 } 512 513 DebugPrint((1, 514 "IssueIdentify: Status before read words %x\n", 515 statusByte)); 516 517 // 518 // Suck out 256 words. After waiting for one model that asserts busy 519 // after receiving the Packet Identify command. 520 // 521 522 WaitOnBusy(baseIoAddress2,statusByte); 523 524 if (!(statusByte & IDE_STATUS_DRQ)) { 525 return FALSE; 526 } 527 528 ReadBuffer(baseIoAddress1, 529 (PUSHORT)&deviceExtension->FullIdentifyData, 530 256); 531 532 // 533 // Check out a few capabilities / limitations of the device. 534 // 535 536 if (deviceExtension->FullIdentifyData.SpecialFunctionsEnabled & 1) { 537 538 // 539 // Determine if this drive supports the MSN functions. 540 // 541 542 DebugPrint((2,"IssueIdentify: Marking drive %d as removable. SFE = %d\n", 543 Channel * 2 + DeviceNumber, 544 deviceExtension->FullIdentifyData.SpecialFunctionsEnabled)); 545 546 547 deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_REMOVABLE_DRIVE; 548 } 549 550 if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) { 551 552 // 553 // Determine max. block transfer for this device. 554 // 555 556 deviceExtension->MaximumBlockXfer[(Channel * 2) + DeviceNumber] = 557 (UCHAR)(deviceExtension->FullIdentifyData.MaximumBlockTransfer & 0xFF); 558 } 559 560 ScsiPortMoveMemory(&deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber],&deviceExtension->FullIdentifyData,sizeof(IDENTIFY_DATA2)); 561 562 if (deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0x20 && 563 Command != IDE_COMMAND_IDENTIFY) { 564 565 // 566 // This device interrupts with the assertion of DRQ after receiving 567 // Atapi Packet Command 568 // 569 570 deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_INT_DRQ; 571 572 DebugPrint((2, 573 "IssueIdentify: Device interrupts on assertion of DRQ.\n")); 574 575 } else { 576 577 DebugPrint((2, 578 "IssueIdentify: Device does not interrupt on assertion of DRQ.\n")); 579 } 580 581 if (((deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0xF00) == 0x100) && 582 Command != IDE_COMMAND_IDENTIFY) { 583 584 // 585 // This is a tape. 586 // 587 588 deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_TAPE_DEVICE; 589 590 DebugPrint((2, 591 "IssueIdentify: Device is a tape drive.\n")); 592 593 } else { 594 595 DebugPrint((2, 596 "IssueIdentify: Device is not a tape drive.\n")); 597 } 598 599 // 600 // Work around for some IDE and one model Atapi that will present more than 601 // 256 bytes for the Identify data. 602 // 603 604 WaitOnBusy(baseIoAddress2,statusByte); 605 606 for (i = 0; i < 0x10000; i++) { 607 608 GetStatus(baseIoAddress2,statusByte); 609 610 if (statusByte & IDE_STATUS_DRQ) { 611 612 // 613 // Suck out any remaining bytes and throw away. 614 // 615 616 ScsiPortReadPortUshort(&baseIoAddress1->Data); 617 618 } else { 619 620 break; 621 622 } 623 } 624 625 DebugPrint((3, 626 "IssueIdentify: Status after read words (%x)\n", 627 statusByte)); 628 629 return TRUE; 630 631 } // end IssueIdentify() 632 633 634 BOOLEAN 635 NTAPI 636 SetDriveParameters( 637 IN PVOID HwDeviceExtension, 638 IN ULONG DeviceNumber, 639 IN ULONG Channel 640 ) 641 642 /*++ 643 644 Routine Description: 645 646 Set drive parameters using the IDENTIFY data. 647 648 Arguments: 649 650 HwDeviceExtension - HBA miniport driver's adapter data storage 651 DeviceNumber - Indicates which device. 652 653 Return Value: 654 655 TRUE if all goes well. 656 657 658 --*/ 659 660 { 661 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 662 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel]; 663 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel]; 664 PIDENTIFY_DATA2 identifyData = &deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber]; 665 ULONG i; 666 UCHAR statusByte; 667 668 DebugPrint((1, 669 "SetDriveParameters: Number of heads %x\n", 670 identifyData->NumberOfHeads)); 671 672 DebugPrint((1, 673 "SetDriveParameters: Sectors per track %x\n", 674 identifyData->SectorsPerTrack)); 675 676 // 677 // Set up registers for SET PARAMETER command. 678 // 679 680 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 681 (UCHAR)(((DeviceNumber << 4) | 0xA0) | (identifyData->NumberOfHeads - 1))); 682 683 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount, 684 (UCHAR)identifyData->SectorsPerTrack); 685 686 // 687 // Send SET PARAMETER command. 688 // 689 690 ScsiPortWritePortUchar(&baseIoAddress1->Command, 691 IDE_COMMAND_SET_DRIVE_PARAMETERS); 692 693 // 694 // Wait for up to 30 milliseconds for ERROR or command complete. 695 // 696 697 for (i=0; i<30 * 1000; i++) { 698 699 UCHAR errorByte; 700 701 GetStatus(baseIoAddress2, statusByte); 702 703 if (statusByte & IDE_STATUS_ERROR) { 704 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 705 DebugPrint((1, 706 "SetDriveParameters: Error bit set. Status %x, error %x\n", 707 errorByte, 708 statusByte)); 709 710 return FALSE; 711 } else if ((statusByte & ~IDE_STATUS_INDEX ) == IDE_STATUS_IDLE) { 712 break; 713 } else { 714 ScsiPortStallExecution(100); 715 } 716 } 717 718 // 719 // Check for timeout. 720 // 721 722 if (i == 30 * 1000) { 723 return FALSE; 724 } else { 725 return TRUE; 726 } 727 728 } // end SetDriveParameters() 729 730 731 BOOLEAN 732 NTAPI 733 AtapiResetController( 734 IN PVOID HwDeviceExtension, 735 IN ULONG PathId 736 ) 737 738 /*++ 739 740 Routine Description: 741 742 Reset IDE controller and/or Atapi device. 743 744 Arguments: 745 746 HwDeviceExtension - HBA miniport driver's adapter data storage 747 748 Return Value: 749 750 Nothing. 751 752 753 --*/ 754 755 { 756 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 757 ULONG numberChannels = deviceExtension->NumberChannels; 758 PIDE_REGISTERS_1 baseIoAddress1; 759 PIDE_REGISTERS_2 baseIoAddress2; 760 BOOLEAN result = FALSE; 761 ULONG i,j; 762 UCHAR statusByte; 763 764 DebugPrint((2,"AtapiResetController: Reset IDE\n")); 765 766 // 767 // Check and see if we are processing an internal srb 768 // 769 if (deviceExtension->OriginalSrb) { 770 deviceExtension->CurrentSrb = deviceExtension->OriginalSrb; 771 deviceExtension->OriginalSrb = NULL; 772 } 773 774 // 775 // Check if request is in progress. 776 // 777 778 if (deviceExtension->CurrentSrb) { 779 780 // 781 // Complete outstanding request with SRB_STATUS_BUS_RESET. 782 // 783 784 ScsiPortCompleteRequest(deviceExtension, 785 deviceExtension->CurrentSrb->PathId, 786 deviceExtension->CurrentSrb->TargetId, 787 deviceExtension->CurrentSrb->Lun, 788 (ULONG)SRB_STATUS_BUS_RESET); 789 790 // 791 // Clear request tracking fields. 792 // 793 794 deviceExtension->CurrentSrb = NULL; 795 deviceExtension->WordsLeft = 0; 796 deviceExtension->DataBuffer = NULL; 797 798 // 799 // Indicate ready for next request. 800 // 801 802 ScsiPortNotification(NextRequest, 803 deviceExtension, 804 NULL); 805 } 806 807 // 808 // Clear expecting interrupt flag. 809 // 810 811 deviceExtension->ExpectingInterrupt = FALSE; 812 deviceExtension->RDP = FALSE; 813 814 for (j = 0; j < numberChannels; j++) { 815 816 baseIoAddress1 = deviceExtension->BaseIoAddress1[j]; 817 baseIoAddress2 = deviceExtension->BaseIoAddress2[j]; 818 819 // 820 // Do special processing for ATAPI and IDE disk devices. 821 // 822 823 for (i = 0; i < 2; i++) { 824 825 // 826 // Check if device present. 827 // 828 829 if (deviceExtension->DeviceFlags[i + (j * 2)] & DFLAGS_DEVICE_PRESENT) { 830 831 // 832 // Check for ATAPI disk. 833 // 834 835 if (deviceExtension->DeviceFlags[i + (j * 2)] & DFLAGS_ATAPI_DEVICE) { 836 837 // 838 // Issue soft reset and issue identify. 839 // 840 841 GetStatus(baseIoAddress2,statusByte); 842 DebugPrint((1, 843 "AtapiResetController: Status before Atapi reset (%x).\n", 844 statusByte)); 845 846 AtapiSoftReset(baseIoAddress1,i); 847 848 GetStatus(baseIoAddress2,statusByte); 849 850 if (statusByte == 0x0) { 851 852 IssueIdentify(HwDeviceExtension, 853 i, 854 j, 855 IDE_COMMAND_ATAPI_IDENTIFY); 856 } else { 857 858 DebugPrint((1, 859 "AtapiResetController: Status after soft reset %x\n", 860 statusByte)); 861 } 862 863 } else { 864 865 // 866 // Write IDE reset controller bits. 867 // 868 869 IdeHardReset(baseIoAddress2,result); 870 871 if (!result) { 872 return FALSE; 873 } 874 875 // 876 // Set disk geometry parameters. 877 // 878 879 if (!SetDriveParameters(HwDeviceExtension, 880 i, 881 j)) { 882 883 DebugPrint((1, 884 "AtapiResetController: SetDriveParameters failed\n")); 885 } 886 } 887 } 888 } 889 } 890 891 // 892 // Call the HwInitialize routine to setup multi-block. 893 // 894 895 AtapiHwInitialize(HwDeviceExtension); 896 897 return TRUE; 898 899 } // end AtapiResetController() 900 901 902 903 ULONG 904 NTAPI 905 MapError( 906 IN PVOID HwDeviceExtension, 907 IN PSCSI_REQUEST_BLOCK Srb 908 ) 909 910 /*++ 911 912 Routine Description: 913 914 This routine maps ATAPI and IDE errors to specific SRB statuses. 915 916 Arguments: 917 918 HwDeviceExtension - HBA miniport driver's adapter data storage 919 Srb - IO request packet 920 921 Return Value: 922 923 SRB status 924 925 --*/ 926 927 { 928 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 929 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 930 //PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 931 ULONG i; 932 UCHAR errorByte; 933 UCHAR srbStatus = SRB_STATUS_ERROR; 934 UCHAR scsiStatus; 935 936 // 937 // Read the error register. 938 // 939 940 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 941 DebugPrint((1, 942 "MapError: Error register is %x\n", 943 errorByte)); 944 945 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 946 947 switch (errorByte >> 4) { 948 case SCSI_SENSE_NO_SENSE: 949 950 DebugPrint((1, 951 "ATAPI: No sense information\n")); 952 scsiStatus = SCSISTAT_CHECK_CONDITION; 953 srbStatus = SRB_STATUS_ERROR; 954 break; 955 956 case SCSI_SENSE_RECOVERED_ERROR: 957 958 DebugPrint((1, 959 "ATAPI: Recovered error\n")); 960 scsiStatus = 0; 961 srbStatus = SRB_STATUS_SUCCESS; 962 break; 963 964 case SCSI_SENSE_NOT_READY: 965 966 DebugPrint((1, 967 "ATAPI: Device not ready\n")); 968 scsiStatus = SCSISTAT_CHECK_CONDITION; 969 srbStatus = SRB_STATUS_ERROR; 970 break; 971 972 case SCSI_SENSE_MEDIUM_ERROR: 973 974 DebugPrint((1, 975 "ATAPI: Media error\n")); 976 scsiStatus = SCSISTAT_CHECK_CONDITION; 977 srbStatus = SRB_STATUS_ERROR; 978 break; 979 980 case SCSI_SENSE_HARDWARE_ERROR: 981 982 DebugPrint((1, 983 "ATAPI: Hardware error\n")); 984 scsiStatus = SCSISTAT_CHECK_CONDITION; 985 srbStatus = SRB_STATUS_ERROR; 986 break; 987 988 case SCSI_SENSE_ILLEGAL_REQUEST: 989 990 DebugPrint((1, 991 "ATAPI: Illegal request\n")); 992 scsiStatus = SCSISTAT_CHECK_CONDITION; 993 srbStatus = SRB_STATUS_ERROR; 994 break; 995 996 case SCSI_SENSE_UNIT_ATTENTION: 997 998 DebugPrint((1, 999 "ATAPI: Unit attention\n")); 1000 scsiStatus = SCSISTAT_CHECK_CONDITION; 1001 srbStatus = SRB_STATUS_ERROR; 1002 break; 1003 1004 case SCSI_SENSE_DATA_PROTECT: 1005 1006 DebugPrint((1, 1007 "ATAPI: Data protect\n")); 1008 scsiStatus = SCSISTAT_CHECK_CONDITION; 1009 srbStatus = SRB_STATUS_ERROR; 1010 break; 1011 1012 case SCSI_SENSE_BLANK_CHECK: 1013 1014 DebugPrint((1, 1015 "ATAPI: Blank check\n")); 1016 scsiStatus = SCSISTAT_CHECK_CONDITION; 1017 srbStatus = SRB_STATUS_ERROR; 1018 break; 1019 1020 case SCSI_SENSE_ABORTED_COMMAND: 1021 DebugPrint((1, 1022 "Atapi: Command Aborted\n")); 1023 scsiStatus = SCSISTAT_CHECK_CONDITION; 1024 srbStatus = SRB_STATUS_ERROR; 1025 break; 1026 1027 default: 1028 1029 DebugPrint((1, 1030 "ATAPI: Invalid sense information\n")); 1031 scsiStatus = 0; 1032 srbStatus = SRB_STATUS_ERROR; 1033 break; 1034 } 1035 1036 } else { 1037 1038 scsiStatus = 0; 1039 1040 // 1041 // Save errorByte,to be used by SCSIOP_REQUEST_SENSE. 1042 // 1043 1044 deviceExtension->ReturningMediaStatus = errorByte; 1045 1046 if (errorByte & IDE_ERROR_MEDIA_CHANGE_REQ) { 1047 DebugPrint((1, 1048 "IDE: Media change\n")); 1049 scsiStatus = SCSISTAT_CHECK_CONDITION; 1050 srbStatus = SRB_STATUS_ERROR; 1051 1052 } else if (errorByte & IDE_ERROR_COMMAND_ABORTED) { 1053 DebugPrint((1, 1054 "IDE: Command abort\n")); 1055 srbStatus = SRB_STATUS_ABORTED; 1056 scsiStatus = SCSISTAT_CHECK_CONDITION; 1057 1058 if (Srb->SenseInfoBuffer) { 1059 1060 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 1061 1062 senseBuffer->ErrorCode = 0x70; 1063 senseBuffer->Valid = 1; 1064 senseBuffer->AdditionalSenseLength = 0xb; 1065 senseBuffer->SenseKey = SCSI_SENSE_ABORTED_COMMAND; 1066 senseBuffer->AdditionalSenseCode = 0; 1067 senseBuffer->AdditionalSenseCodeQualifier = 0; 1068 1069 srbStatus |= SRB_STATUS_AUTOSENSE_VALID; 1070 } 1071 1072 deviceExtension->ErrorCount++; 1073 1074 } else if (errorByte & IDE_ERROR_END_OF_MEDIA) { 1075 1076 DebugPrint((1, 1077 "IDE: End of media\n")); 1078 scsiStatus = SCSISTAT_CHECK_CONDITION; 1079 srbStatus = SRB_STATUS_ERROR; 1080 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED)){ 1081 deviceExtension->ErrorCount++; 1082 } 1083 1084 } else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH) { 1085 1086 DebugPrint((1, 1087 "IDE: Illegal length\n")); 1088 srbStatus = SRB_STATUS_INVALID_REQUEST; 1089 1090 } else if (errorByte & IDE_ERROR_BAD_BLOCK) { 1091 1092 DebugPrint((1, 1093 "IDE: Bad block\n")); 1094 srbStatus = SRB_STATUS_ERROR; 1095 scsiStatus = SCSISTAT_CHECK_CONDITION; 1096 if (Srb->SenseInfoBuffer) { 1097 1098 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 1099 1100 senseBuffer->ErrorCode = 0x70; 1101 senseBuffer->Valid = 1; 1102 senseBuffer->AdditionalSenseLength = 0xb; 1103 senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR; 1104 senseBuffer->AdditionalSenseCode = 0; 1105 senseBuffer->AdditionalSenseCodeQualifier = 0; 1106 1107 srbStatus |= SRB_STATUS_AUTOSENSE_VALID; 1108 } 1109 1110 } else if (errorByte & IDE_ERROR_ID_NOT_FOUND) { 1111 1112 DebugPrint((1, 1113 "IDE: Id not found\n")); 1114 srbStatus = SRB_STATUS_ERROR; 1115 scsiStatus = SCSISTAT_CHECK_CONDITION; 1116 1117 if (Srb->SenseInfoBuffer) { 1118 1119 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 1120 1121 senseBuffer->ErrorCode = 0x70; 1122 senseBuffer->Valid = 1; 1123 senseBuffer->AdditionalSenseLength = 0xb; 1124 senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR; 1125 senseBuffer->AdditionalSenseCode = 0; 1126 senseBuffer->AdditionalSenseCodeQualifier = 0; 1127 1128 srbStatus |= SRB_STATUS_AUTOSENSE_VALID; 1129 } 1130 1131 deviceExtension->ErrorCount++; 1132 1133 } else if (errorByte & IDE_ERROR_MEDIA_CHANGE) { 1134 1135 DebugPrint((1, 1136 "IDE: Media change\n")); 1137 scsiStatus = SCSISTAT_CHECK_CONDITION; 1138 srbStatus = SRB_STATUS_ERROR; 1139 1140 if (Srb->SenseInfoBuffer) { 1141 1142 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 1143 1144 senseBuffer->ErrorCode = 0x70; 1145 senseBuffer->Valid = 1; 1146 senseBuffer->AdditionalSenseLength = 0xb; 1147 senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; 1148 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED; 1149 senseBuffer->AdditionalSenseCodeQualifier = 0; 1150 1151 srbStatus |= SRB_STATUS_AUTOSENSE_VALID; 1152 } 1153 1154 } else if (errorByte & IDE_ERROR_DATA_ERROR) { 1155 1156 DebugPrint((1, 1157 "IDE: Data error\n")); 1158 scsiStatus = SCSISTAT_CHECK_CONDITION; 1159 srbStatus = SRB_STATUS_ERROR; 1160 1161 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED)){ 1162 deviceExtension->ErrorCount++; 1163 } 1164 1165 // 1166 // Build sense buffer 1167 // 1168 1169 if (Srb->SenseInfoBuffer) { 1170 1171 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 1172 1173 senseBuffer->ErrorCode = 0x70; 1174 senseBuffer->Valid = 1; 1175 senseBuffer->AdditionalSenseLength = 0xb; 1176 senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR; 1177 senseBuffer->AdditionalSenseCode = 0; 1178 senseBuffer->AdditionalSenseCodeQualifier = 0; 1179 1180 srbStatus |= SRB_STATUS_AUTOSENSE_VALID; 1181 } 1182 } 1183 1184 if (deviceExtension->ErrorCount >= MAX_ERRORS) { 1185 deviceExtension->DWordIO = FALSE; 1186 deviceExtension->MaximumBlockXfer[Srb->TargetId] = 0; 1187 1188 DebugPrint((1, 1189 "MapError: Disabling 32-bit PIO and Multi-sector IOs\n")); 1190 1191 // 1192 // Log the error. 1193 // 1194 1195 ScsiPortLogError( HwDeviceExtension, 1196 Srb, 1197 Srb->PathId, 1198 Srb->TargetId, 1199 Srb->Lun, 1200 SP_BAD_FW_WARNING, 1201 4); 1202 // 1203 // Reprogram to not use Multi-sector. 1204 // 1205 1206 for (i = 0; i < 4; i++) { 1207 UCHAR statusByte; 1208 1209 if (deviceExtension->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT && 1210 !(deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE)) { 1211 1212 // 1213 // Select the device. 1214 // 1215 1216 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 1217 (UCHAR)(((i & 0x1) << 4) | 0xA0)); 1218 1219 // 1220 // Setup sector count to reflect the # of blocks. 1221 // 1222 1223 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount, 1224 0); 1225 1226 // 1227 // Issue the command. 1228 // 1229 1230 ScsiPortWritePortUchar(&baseIoAddress1->Command, 1231 IDE_COMMAND_SET_MULTIPLE); 1232 1233 // 1234 // Wait for busy to drop. 1235 // 1236 1237 WaitOnBaseBusy(baseIoAddress1,statusByte); 1238 1239 // 1240 // Check for errors. Reset the value to 0 (disable MultiBlock) if the 1241 // command was aborted. 1242 // 1243 1244 if (statusByte & IDE_STATUS_ERROR) { 1245 1246 // 1247 // Read the error register. 1248 // 1249 1250 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 1251 1252 DebugPrint((1, 1253 "AtapiHwInitialize: Error setting multiple mode. Status %x, error byte %x\n", 1254 statusByte, 1255 errorByte)); 1256 // 1257 // Adjust the devExt. value, if necessary. 1258 // 1259 1260 deviceExtension->MaximumBlockXfer[i] = 0; 1261 1262 } 1263 } 1264 } 1265 } 1266 } 1267 1268 1269 // 1270 // Set SCSI status to indicate a check condition. 1271 // 1272 1273 Srb->ScsiStatus = scsiStatus; 1274 1275 return srbStatus; 1276 1277 } // end MapError() 1278 1279 1280 BOOLEAN 1281 NTAPI 1282 AtapiHwInitialize( 1283 IN PVOID HwDeviceExtension 1284 ) 1285 1286 /*++ 1287 1288 Routine Description: 1289 1290 Arguments: 1291 1292 HwDeviceExtension - HBA miniport driver's adapter data storage 1293 1294 Return Value: 1295 1296 TRUE - if initialization successful. 1297 FALSE - if initialization unsuccessful. 1298 1299 --*/ 1300 1301 { 1302 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 1303 PIDE_REGISTERS_1 baseIoAddress; 1304 ULONG i; 1305 UCHAR statusByte, errorByte; 1306 1307 1308 for (i = 0; i < 4; i++) { 1309 if (deviceExtension->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT) { 1310 1311 if (!(deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE)) { 1312 1313 // 1314 // Enable media status notification 1315 // 1316 1317 baseIoAddress = deviceExtension->BaseIoAddress1[i >> 1]; 1318 1319 IdeMediaStatus(TRUE,HwDeviceExtension,i); 1320 1321 // 1322 // If supported, setup Multi-block transfers. 1323 // 1324 if (deviceExtension->MaximumBlockXfer[i]) { 1325 1326 // 1327 // Select the device. 1328 // 1329 1330 ScsiPortWritePortUchar(&baseIoAddress->DriveSelect, 1331 (UCHAR)(((i & 0x1) << 4) | 0xA0)); 1332 1333 // 1334 // Setup sector count to reflect the # of blocks. 1335 // 1336 1337 ScsiPortWritePortUchar(&baseIoAddress->BlockCount, 1338 deviceExtension->MaximumBlockXfer[i]); 1339 1340 // 1341 // Issue the command. 1342 // 1343 1344 ScsiPortWritePortUchar(&baseIoAddress->Command, 1345 IDE_COMMAND_SET_MULTIPLE); 1346 1347 // 1348 // Wait for busy to drop. 1349 // 1350 1351 WaitOnBaseBusy(baseIoAddress,statusByte); 1352 1353 // 1354 // Check for errors. Reset the value to 0 (disable MultiBlock) if the 1355 // command was aborted. 1356 // 1357 1358 if (statusByte & IDE_STATUS_ERROR) { 1359 1360 // 1361 // Read the error register. 1362 // 1363 1364 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress + 1); 1365 1366 DebugPrint((1, 1367 "AtapiHwInitialize: Error setting multiple mode. Status %x, error byte %x\n", 1368 statusByte, 1369 errorByte)); 1370 // 1371 // Adjust the devExt. value, if necessary. 1372 // 1373 1374 deviceExtension->MaximumBlockXfer[i] = 0; 1375 1376 } else { 1377 DebugPrint((2, 1378 "AtapiHwInitialize: Using Multiblock on Device %d. Blocks / int - %d\n", 1379 i, 1380 deviceExtension->MaximumBlockXfer[i])); 1381 } 1382 } 1383 } else if (!(deviceExtension->DeviceFlags[i] & DFLAGS_CHANGER_INITED)){ 1384 1385 ULONG j; 1386 UCHAR vendorId[26]; 1387 1388 // 1389 // Attempt to identify any special-case devices - psuedo-atapi changers, atapi changers, etc. 1390 // 1391 1392 for (j = 0; j < 13; j += 2) { 1393 1394 // 1395 // Build a buffer based on the identify data. 1396 // 1397 1398 vendorId[j] = ((PUCHAR)deviceExtension->IdentifyData[i].ModelNumber)[j + 1]; 1399 vendorId[j+1] = ((PUCHAR)deviceExtension->IdentifyData[i].ModelNumber)[j]; 1400 } 1401 1402 if (!AtapiStringCmp ((PCHAR)vendorId, "CD-ROM CDR", 11)) { 1403 1404 // 1405 // Inquiry string for older model had a '-', newer is '_' 1406 // 1407 1408 if (vendorId[12] == 'C') { 1409 1410 // 1411 // Torisan changer. Set the bit. This will be used in several places 1412 // acting like 1) a multi-lun device and 2) building the 'special' TUR's. 1413 // 1414 1415 deviceExtension->DeviceFlags[i] |= (DFLAGS_CHANGER_INITED | DFLAGS_SANYO_ATAPI_CHANGER); 1416 deviceExtension->DiscsPresent[i] = 3; 1417 } 1418 } 1419 } 1420 1421 // 1422 // We need to get our device ready for action before 1423 // returning from this function 1424 // 1425 // According to the atapi spec 2.5 or 2.6, an atapi device 1426 // clears its status BSY bit when it is ready for atapi commands. 1427 // However, some devices (Panasonic SQ-TC500N) are still 1428 // not ready even when the status BSY is clear. They don't react 1429 // to atapi commands. 1430 // 1431 // Since there is really no other indication that tells us 1432 // the drive is really ready for action. We are going to check BSY 1433 // is clear and then just wait for an arbitrary amount of time! 1434 // 1435 if (deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE) { 1436 //PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[i >> 1]; 1437 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[i >> 1]; 1438 ULONG waitCount; 1439 1440 // have to get out of the loop sometime! 1441 // 10000 * 100us = 1000,000us = 1000ms = 1s 1442 waitCount = 10000; 1443 GetStatus(baseIoAddress2, statusByte); 1444 while ((statusByte & IDE_STATUS_BUSY) && waitCount) { 1445 // 1446 // Wait for Busy to drop. 1447 // 1448 ScsiPortStallExecution(100); 1449 GetStatus(baseIoAddress2, statusByte); 1450 waitCount--; 1451 } 1452 1453 // 5000 * 100us = 500,000us = 500ms = 0.5s 1454 waitCount = 5000; 1455 do { 1456 ScsiPortStallExecution(100); 1457 } while (waitCount--); 1458 } 1459 } 1460 } 1461 1462 return TRUE; 1463 1464 } // end AtapiHwInitialize() 1465 1466 1467 VOID 1468 NTAPI 1469 AtapiHwInitializeChanger ( 1470 IN PVOID HwDeviceExtension, 1471 IN ULONG TargetId, 1472 IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus) 1473 { 1474 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 1475 1476 if (MechanismStatus) { 1477 deviceExtension->DiscsPresent[TargetId] = MechanismStatus->NumberAvailableSlots; 1478 if (deviceExtension->DiscsPresent[TargetId] > 1) { 1479 deviceExtension->DeviceFlags[TargetId] |= DFLAGS_ATAPI_CHANGER; 1480 } 1481 } 1482 return; 1483 } 1484 1485 1486 1487 BOOLEAN 1488 NTAPI 1489 FindDevices( 1490 IN PVOID HwDeviceExtension, 1491 IN BOOLEAN AtapiOnly, 1492 IN ULONG Channel 1493 ) 1494 1495 /*++ 1496 1497 Routine Description: 1498 1499 This routine is called from AtapiFindController to identify 1500 devices attached to an IDE controller. 1501 1502 Arguments: 1503 1504 HwDeviceExtension - HBA miniport driver's adapter data storage 1505 AtapiOnly - Indicates that routine should return TRUE only if 1506 an ATAPI device is attached to the controller. 1507 1508 Return Value: 1509 1510 TRUE - True if devices found. 1511 1512 --*/ 1513 1514 { 1515 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 1516 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel]; 1517 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel]; 1518 BOOLEAN deviceResponded = FALSE, 1519 skipSetParameters = FALSE; 1520 ULONG waitCount = 10000; 1521 ULONG deviceNumber; 1522 ULONG i; 1523 UCHAR signatureLow, 1524 signatureHigh; 1525 UCHAR statusByte; 1526 1527 // 1528 // Clear expecting interrupt flag and current SRB field. 1529 // 1530 1531 deviceExtension->ExpectingInterrupt = FALSE; 1532 deviceExtension->CurrentSrb = NULL; 1533 1534 // 1535 // Search for devices. 1536 // 1537 1538 for (deviceNumber = 0; deviceNumber < 2; deviceNumber++) { 1539 1540 // 1541 // Select the device. 1542 // 1543 1544 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 1545 (UCHAR)((deviceNumber << 4) | 0xA0)); 1546 1547 // 1548 // Check here for some SCSI adapters that incorporate IDE emulation. 1549 // 1550 1551 GetStatus(baseIoAddress2, statusByte); 1552 if (statusByte == 0xFF) { 1553 continue; 1554 } 1555 1556 AtapiSoftReset(baseIoAddress1,deviceNumber); 1557 WaitOnBusy(baseIoAddress2,statusByte); 1558 1559 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 1560 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 1561 1562 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 1563 1564 // 1565 // ATAPI signature found. 1566 // Issue the ATAPI identify command if this 1567 // is not for the crash dump utility. 1568 // 1569 1570 atapiIssueId: 1571 1572 if (!deviceExtension->DriverMustPoll) { 1573 1574 // 1575 // Issue ATAPI packet identify command. 1576 // 1577 1578 if (IssueIdentify(HwDeviceExtension, 1579 deviceNumber, 1580 Channel, 1581 IDE_COMMAND_ATAPI_IDENTIFY)) { 1582 1583 // 1584 // Indicate ATAPI device. 1585 // 1586 1587 DebugPrint((1, 1588 "FindDevices: Device %x is ATAPI\n", 1589 deviceNumber)); 1590 1591 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_ATAPI_DEVICE; 1592 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_DEVICE_PRESENT; 1593 1594 deviceResponded = TRUE; 1595 1596 GetStatus(baseIoAddress2, statusByte); 1597 if (statusByte & IDE_STATUS_ERROR) { 1598 AtapiSoftReset(baseIoAddress1, deviceNumber); 1599 } 1600 1601 1602 } else { 1603 1604 // 1605 // Indicate no working device. 1606 // 1607 1608 DebugPrint((1, 1609 "FindDevices: Device %x not responding\n", 1610 deviceNumber)); 1611 1612 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] &= ~DFLAGS_DEVICE_PRESENT; 1613 } 1614 1615 } 1616 1617 } else { 1618 1619 // 1620 // Issue IDE Identify. If an Atapi device is actually present, the signature 1621 // will be asserted, and the drive will be recognized as such. 1622 // 1623 1624 if (IssueIdentify(HwDeviceExtension, 1625 deviceNumber, 1626 Channel, 1627 IDE_COMMAND_IDENTIFY)) { 1628 1629 // 1630 // IDE drive found. 1631 // 1632 1633 1634 DebugPrint((1, 1635 "FindDevices: Device %x is IDE\n", 1636 deviceNumber)); 1637 1638 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_DEVICE_PRESENT; 1639 1640 if (!AtapiOnly) { 1641 deviceResponded = TRUE; 1642 } 1643 1644 // 1645 // Indicate IDE - not ATAPI device. 1646 // 1647 1648 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] &= ~DFLAGS_ATAPI_DEVICE; 1649 1650 1651 } else { 1652 1653 // 1654 // Look to see if an Atapi device is present. 1655 // 1656 1657 AtapiSoftReset(baseIoAddress1,deviceNumber); 1658 1659 WaitOnBusy(baseIoAddress2,statusByte); 1660 1661 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 1662 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 1663 1664 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 1665 goto atapiIssueId; 1666 } 1667 } 1668 } 1669 } 1670 1671 for (i = 0; i < 2; i++) { 1672 if ((deviceExtension->DeviceFlags[i + (Channel * 2)] & DFLAGS_DEVICE_PRESENT) && 1673 (!(deviceExtension->DeviceFlags[i + (Channel * 2)] & DFLAGS_ATAPI_DEVICE)) && deviceResponded) { 1674 1675 // 1676 // This hideous hack is to deal with ESDI devices that return 1677 // garbage geometry in the IDENTIFY data. 1678 // This is ONLY for the crashdump environment as 1679 // these are ESDI devices. 1680 // 1681 1682 if (deviceExtension->IdentifyData[i].SectorsPerTrack == 1683 0x35 && 1684 deviceExtension->IdentifyData[i].NumberOfHeads == 1685 0x07) { 1686 1687 DebugPrint((1, 1688 "FindDevices: Found nasty Compaq ESDI!\n")); 1689 1690 // 1691 // Change these values to something reasonable. 1692 // 1693 1694 deviceExtension->IdentifyData[i].SectorsPerTrack = 1695 0x34; 1696 deviceExtension->IdentifyData[i].NumberOfHeads = 1697 0x0E; 1698 } 1699 1700 if (deviceExtension->IdentifyData[i].SectorsPerTrack == 1701 0x35 && 1702 deviceExtension->IdentifyData[i].NumberOfHeads == 1703 0x0F) { 1704 1705 DebugPrint((1, 1706 "FindDevices: Found nasty Compaq ESDI!\n")); 1707 1708 // 1709 // Change these values to something reasonable. 1710 // 1711 1712 deviceExtension->IdentifyData[i].SectorsPerTrack = 1713 0x34; 1714 deviceExtension->IdentifyData[i].NumberOfHeads = 1715 0x0F; 1716 } 1717 1718 1719 if (deviceExtension->IdentifyData[i].SectorsPerTrack == 1720 0x36 && 1721 deviceExtension->IdentifyData[i].NumberOfHeads == 1722 0x07) { 1723 1724 DebugPrint((1, 1725 "FindDevices: Found nasty UltraStor ESDI!\n")); 1726 1727 // 1728 // Change these values to something reasonable. 1729 // 1730 1731 deviceExtension->IdentifyData[i].SectorsPerTrack = 1732 0x3F; 1733 deviceExtension->IdentifyData[i].NumberOfHeads = 1734 0x10; 1735 skipSetParameters = TRUE; 1736 } 1737 1738 1739 if (!skipSetParameters) { 1740 1741 WaitOnBusy(baseIoAddress2,statusByte); 1742 1743 // 1744 // Select the device. 1745 // 1746 1747 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 1748 (UCHAR)((i << 4) | 0xA0)); 1749 1750 GetStatus(baseIoAddress2, statusByte); 1751 1752 if (statusByte & IDE_STATUS_ERROR) { 1753 1754 // 1755 // Reset the device. 1756 // 1757 1758 DebugPrint((2, 1759 "FindDevices: Resetting controller before SetDriveParameters.\n")); 1760 1761 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER ); 1762 ScsiPortStallExecution(500 * 1000); 1763 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER); 1764 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 1765 (UCHAR)((i << 4) | 0xA0)); 1766 1767 do { 1768 1769 // 1770 // Wait for Busy to drop. 1771 // 1772 1773 ScsiPortStallExecution(100); 1774 GetStatus(baseIoAddress2, statusByte); 1775 1776 } while ((statusByte & IDE_STATUS_BUSY) && waitCount--); 1777 } 1778 1779 WaitOnBusy(baseIoAddress2,statusByte); 1780 DebugPrint((2, 1781 "FindDevices: Status before SetDriveParameters: (%x) (%x)\n", 1782 statusByte, 1783 ScsiPortReadPortUchar(&baseIoAddress1->DriveSelect))); 1784 1785 // 1786 // Use the IDENTIFY data to set drive parameters. 1787 // 1788 1789 if (!SetDriveParameters(HwDeviceExtension,i,Channel)) { 1790 1791 DebugPrint((0, 1792 "AtapHwInitialize: Set drive parameters for device %d failed\n", 1793 i)); 1794 1795 // 1796 // Don't use this device as writes could cause corruption. 1797 // 1798 1799 deviceExtension->DeviceFlags[i + Channel] = 0; 1800 continue; 1801 1802 } 1803 if (deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] & DFLAGS_REMOVABLE_DRIVE) { 1804 1805 // 1806 // Pick up ALL IDE removable drives that conform to Yosemite V0.2... 1807 // 1808 1809 AtapiOnly = FALSE; 1810 } 1811 1812 1813 // 1814 // Indicate that a device was found. 1815 // 1816 1817 if (!AtapiOnly) { 1818 deviceResponded = TRUE; 1819 } 1820 } 1821 } 1822 } 1823 1824 // 1825 // Make sure master device is selected on exit. 1826 // 1827 1828 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 0xA0); 1829 1830 // 1831 // Reset the controller. This is a feeble attempt to leave the ESDI 1832 // controllers in a state that ATDISK driver will recognize them. 1833 // The problem in ATDISK has to do with timings as it is not reproducible 1834 // in debug. The reset should restore the controller to its poweron state 1835 // and give the system enough time to settle. 1836 // 1837 1838 if (!deviceResponded) { 1839 1840 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER ); 1841 ScsiPortStallExecution(50 * 1000); 1842 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER); 1843 } 1844 1845 return deviceResponded; 1846 1847 } // end FindDevices() 1848 1849 1850 ULONG 1851 NTAPI 1852 AtapiParseArgumentString( 1853 IN PCHAR String, 1854 IN PCHAR KeyWord 1855 ) 1856 1857 /*++ 1858 1859 Routine Description: 1860 1861 This routine will parse the string for a match on the keyword, then 1862 calculate the value for the keyword and return it to the caller. 1863 1864 Arguments: 1865 1866 String - The ASCII string to parse. 1867 KeyWord - The keyword for the value desired. 1868 1869 Return Values: 1870 1871 Zero if value not found 1872 Value converted from ASCII to binary. 1873 1874 --*/ 1875 1876 { 1877 PCHAR cptr; 1878 PCHAR kptr; 1879 ULONG value; 1880 ULONG stringLength = 0; 1881 ULONG keyWordLength = 0; 1882 ULONG index; 1883 1884 if (!String) { 1885 return 0; 1886 } 1887 if (!KeyWord) { 1888 return 0; 1889 } 1890 1891 // 1892 // Calculate the string length and lower case all characters. 1893 // 1894 1895 cptr = String; 1896 while (*cptr) { 1897 if (*cptr >= 'A' && *cptr <= 'Z') { 1898 *cptr = *cptr + ('a' - 'A'); 1899 } 1900 cptr++; 1901 stringLength++; 1902 } 1903 1904 // 1905 // Calculate the keyword length and lower case all characters. 1906 // 1907 1908 cptr = KeyWord; 1909 while (*cptr) { 1910 1911 if (*cptr >= 'A' && *cptr <= 'Z') { 1912 *cptr = *cptr + ('a' - 'A'); 1913 } 1914 cptr++; 1915 keyWordLength++; 1916 } 1917 1918 if (keyWordLength > stringLength) { 1919 1920 // 1921 // Can't possibly have a match. 1922 // 1923 1924 return 0; 1925 } 1926 1927 // 1928 // Now setup and start the compare. 1929 // 1930 1931 cptr = String; 1932 1933 ContinueSearch: 1934 1935 // 1936 // The input string may start with white space. Skip it. 1937 // 1938 1939 while (*cptr == ' ' || *cptr == '\t') { 1940 cptr++; 1941 } 1942 1943 if (*cptr == '\0') { 1944 1945 // 1946 // end of string. 1947 // 1948 1949 return 0; 1950 } 1951 1952 kptr = KeyWord; 1953 while (*cptr++ == *kptr++) { 1954 1955 if (*(cptr - 1) == '\0') { 1956 1957 // 1958 // end of string 1959 // 1960 1961 return 0; 1962 } 1963 } 1964 1965 if (*(kptr - 1) == '\0') { 1966 1967 // 1968 // May have a match backup and check for blank or equals. 1969 // 1970 1971 cptr--; 1972 while (*cptr == ' ' || *cptr == '\t') { 1973 cptr++; 1974 } 1975 1976 // 1977 // Found a match. Make sure there is an equals. 1978 // 1979 1980 if (*cptr != '=') { 1981 1982 // 1983 // Not a match so move to the next semicolon. 1984 // 1985 1986 while (*cptr) { 1987 if (*cptr++ == ';') { 1988 goto ContinueSearch; 1989 } 1990 } 1991 return 0; 1992 } 1993 1994 // 1995 // Skip the equals sign. 1996 // 1997 1998 cptr++; 1999 2000 // 2001 // Skip white space. 2002 // 2003 2004 while ((*cptr == ' ') || (*cptr == '\t')) { 2005 cptr++; 2006 } 2007 2008 if (*cptr == '\0') { 2009 2010 // 2011 // Early end of string, return not found 2012 // 2013 2014 return 0; 2015 } 2016 2017 if (*cptr == ';') { 2018 2019 // 2020 // This isn't it either. 2021 // 2022 2023 cptr++; 2024 goto ContinueSearch; 2025 } 2026 2027 value = 0; 2028 if ((*cptr == '0') && (*(cptr + 1) == 'x')) { 2029 2030 // 2031 // Value is in Hex. Skip the "0x" 2032 // 2033 2034 cptr += 2; 2035 for (index = 0; *(cptr + index); index++) { 2036 2037 if (*(cptr + index) == ' ' || 2038 *(cptr + index) == '\t' || 2039 *(cptr + index) == ';') { 2040 break; 2041 } 2042 2043 if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) { 2044 value = (16 * value) + (*(cptr + index) - '0'); 2045 } else { 2046 if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) { 2047 value = (16 * value) + (*(cptr + index) - 'a' + 10); 2048 } else { 2049 2050 // 2051 // Syntax error, return not found. 2052 // 2053 return 0; 2054 } 2055 } 2056 } 2057 } else { 2058 2059 // 2060 // Value is in Decimal. 2061 // 2062 2063 for (index = 0; *(cptr + index); index++) { 2064 2065 if (*(cptr + index) == ' ' || 2066 *(cptr + index) == '\t' || 2067 *(cptr + index) == ';') { 2068 break; 2069 } 2070 2071 if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) { 2072 value = (10 * value) + (*(cptr + index) - '0'); 2073 } else { 2074 2075 // 2076 // Syntax error return not found. 2077 // 2078 return 0; 2079 } 2080 } 2081 } 2082 2083 return value; 2084 } else { 2085 2086 // 2087 // Not a match check for ';' to continue search. 2088 // 2089 2090 while (*cptr) { 2091 if (*cptr++ == ';') { 2092 goto ContinueSearch; 2093 } 2094 } 2095 2096 return 0; 2097 } 2098 } 2099 2100 2101 2102 2103 2104 ULONG 2105 NTAPI 2106 AtapiFindController( 2107 IN PVOID HwDeviceExtension, 2108 IN PVOID Context, 2109 IN PVOID BusInformation, 2110 IN PCHAR ArgumentString, 2111 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, 2112 OUT PBOOLEAN Again 2113 ) 2114 /*++ 2115 2116 Routine Description: 2117 2118 This function is called by the OS-specific port driver after 2119 the necessary storage has been allocated, to gather information 2120 about the adapter's configuration. 2121 2122 Arguments: 2123 2124 HwDeviceExtension - HBA miniport driver's adapter data storage 2125 Context - Address of adapter count 2126 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility. 2127 ConfigInfo - Configuration information structure describing HBA 2128 Again - Indicates search for adapters to continue 2129 2130 Return Value: 2131 2132 ULONG 2133 2134 --*/ 2135 2136 { 2137 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 2138 PULONG adapterCount = (PULONG)Context; 2139 PUCHAR ioSpace = NULL; 2140 ULONG i; 2141 ULONG irq; 2142 ULONG portBase; 2143 ULONG retryCount; 2144 PCI_SLOT_NUMBER slotData; 2145 PPCI_COMMON_CONFIG pciData; 2146 ULONG pciBuffer; 2147 BOOLEAN atapiOnly; 2148 UCHAR statusByte; 2149 BOOLEAN preConfig = FALSE; 2150 // 2151 // The following table specifies the ports to be checked when searching for 2152 // an IDE controller. A zero entry terminates the search. 2153 // 2154 2155 CONST ULONG AdapterAddresses[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0}; 2156 2157 // 2158 // The following table specifies interrupt levels corresponding to the 2159 // port addresses in the previous table. 2160 // 2161 2162 CONST ULONG InterruptLevels[5] = {14, 15, 11, 10, 0}; 2163 2164 if (!deviceExtension) { 2165 return SP_RETURN_ERROR; 2166 } 2167 2168 // 2169 // Check to see if this is a special configuration environment. 2170 // 2171 2172 portBase = irq = 0; 2173 if (ArgumentString) { 2174 2175 irq = AtapiParseArgumentString(ArgumentString, "Interrupt"); 2176 if (irq ) { 2177 2178 // 2179 // Both parameters must be present to proceed 2180 // 2181 2182 portBase = AtapiParseArgumentString(ArgumentString, "BaseAddress"); 2183 if (!portBase) { 2184 2185 // 2186 // Try a default search for the part. 2187 // 2188 2189 irq = 0; 2190 } 2191 } 2192 } 2193 2194 2195 2196 // 2197 // Scan though the adapter address looking for adapters. 2198 // 2199 if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart) != 0) { 2200 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 2201 ConfigInfo->AdapterInterfaceType, 2202 ConfigInfo->SystemIoBusNumber, 2203 (*ConfigInfo->AccessRanges)[0].RangeStart, 2204 (*ConfigInfo->AccessRanges)[0].RangeLength, 2205 (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory)); 2206 *Again = FALSE; 2207 // 2208 // Since we have pre-configured information we only need to go through this loop once 2209 // 2210 preConfig = TRUE; 2211 portBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart); 2212 2213 } 2214 2215 2216 2217 while (AdapterAddresses[*adapterCount] != 0) { 2218 2219 retryCount = 4; 2220 2221 for (i = 0; i < 4; i++) { 2222 2223 // 2224 // Zero device fields to ensure that if earlier devices were found, 2225 // but not claimed, the fields are cleared. 2226 // 2227 2228 deviceExtension->DeviceFlags[i] &= ~(DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT | DFLAGS_TAPE_DEVICE); 2229 } 2230 2231 // 2232 // Get the system physical address for this IO range. 2233 // 2234 2235 2236 // 2237 // Check if configInfo has the default information 2238 // if not, we go and find ourselves 2239 // 2240 2241 if (preConfig == FALSE) { 2242 2243 if (portBase) { 2244 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 2245 ConfigInfo->AdapterInterfaceType, 2246 ConfigInfo->SystemIoBusNumber, 2247 ScsiPortConvertUlongToPhysicalAddress(portBase), 2248 8, 2249 TRUE); 2250 } else { 2251 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 2252 ConfigInfo->AdapterInterfaceType, 2253 ConfigInfo->SystemIoBusNumber, 2254 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]), 2255 8, 2256 TRUE); 2257 } 2258 2259 }// ConfigInfo check 2260 // 2261 // Update the adapter count. 2262 // 2263 2264 (*adapterCount)++; 2265 2266 // 2267 // Check if ioSpace accessible. 2268 // 2269 2270 if (!ioSpace) { 2271 continue; 2272 } 2273 2274 retryIdentifier: 2275 2276 // 2277 // Select master. 2278 // 2279 2280 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xA0); 2281 2282 // 2283 // Check if card at this address. 2284 // 2285 2286 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 2287 2288 // 2289 // Check if identifier can be read back. 2290 // 2291 2292 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 2293 2294 DebugPrint((2, 2295 "AtapiFindController: Identifier read back from Master (%x)\n", 2296 statusByte)); 2297 2298 statusByte = ScsiPortReadPortUchar(&((PATAPI_REGISTERS_2)ioSpace)->AlternateStatus); 2299 2300 if (statusByte & IDE_STATUS_BUSY) { 2301 2302 i = 0; 2303 2304 // 2305 // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that 2306 // warm boots don't clear. 2307 // 2308 2309 do { 2310 ScsiPortStallExecution(1000); 2311 statusByte = ScsiPortReadPortUchar(&((PATAPI_REGISTERS_1)ioSpace)->Command); 2312 DebugPrint((3, 2313 "AtapiFindController: First access to status %x\n", 2314 statusByte)); 2315 } while ((statusByte & IDE_STATUS_BUSY) && ++i < 10); 2316 2317 if (retryCount-- && (!(statusByte & IDE_STATUS_BUSY))) { 2318 goto retryIdentifier; 2319 } 2320 } 2321 2322 // 2323 // Select slave. 2324 // 2325 2326 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xB0); 2327 2328 // 2329 // See if slave is present. 2330 // 2331 2332 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 2333 2334 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 2335 2336 DebugPrint((2, 2337 "AtapiFindController: Identifier read back from Slave (%x)\n", 2338 statusByte)); 2339 2340 // 2341 // 2342 // No controller at this base address. 2343 // 2344 2345 ScsiPortFreeDeviceBase(HwDeviceExtension, 2346 ioSpace); 2347 2348 continue; 2349 } 2350 } 2351 2352 // 2353 // Record base IO address. 2354 // 2355 2356 deviceExtension->BaseIoAddress1[0] = (PIDE_REGISTERS_1)(ioSpace); 2357 2358 // 2359 // Fill in the access array information only if default params are not in there. 2360 // 2361 if (preConfig == FALSE) { 2362 2363 // 2364 // An adapter has been found request another call, only if we didn't get preconfigured info. 2365 // 2366 *Again = TRUE; 2367 2368 if (portBase) { 2369 (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(portBase); 2370 } else { 2371 (*ConfigInfo->AccessRanges)[0].RangeStart = 2372 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]); 2373 } 2374 2375 (*ConfigInfo->AccessRanges)[0].RangeLength = 8; 2376 (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; 2377 2378 // 2379 // Indicate the interrupt level corresponding to this IO range. 2380 // 2381 2382 if (irq) { 2383 ConfigInfo->BusInterruptLevel = irq; 2384 } else { 2385 ConfigInfo->BusInterruptLevel = InterruptLevels[*adapterCount - 1]; 2386 } 2387 2388 if (ConfigInfo->AdapterInterfaceType == MicroChannel) { 2389 ConfigInfo->InterruptMode = LevelSensitive; 2390 } else { 2391 ConfigInfo->InterruptMode = Latched; 2392 } 2393 } 2394 // 2395 // Get the system physical address for the second IO range. 2396 // 2397 2398 2399 if (portBase) { 2400 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 2401 ConfigInfo->AdapterInterfaceType, 2402 ConfigInfo->SystemIoBusNumber, 2403 ScsiPortConvertUlongToPhysicalAddress(portBase + 0x206), 2404 1, 2405 TRUE); 2406 } else { 2407 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 2408 ConfigInfo->AdapterInterfaceType, 2409 ConfigInfo->SystemIoBusNumber, 2410 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1] + 0x206), 2411 1, 2412 TRUE); 2413 } 2414 2415 deviceExtension->BaseIoAddress2[0] = (PIDE_REGISTERS_2)(ioSpace); 2416 2417 deviceExtension->NumberChannels = 1; 2418 2419 ConfigInfo->NumberOfBuses = 1; 2420 ConfigInfo->MaximumNumberOfTargets = 2; 2421 2422 // 2423 // Indicate maximum transfer length is 64k. 2424 // 2425 2426 ConfigInfo->MaximumTransferLength = 0x10000; 2427 2428 DebugPrint((1, 2429 "AtapiFindController: Found IDE at %x\n", 2430 deviceExtension->BaseIoAddress1[0])); 2431 2432 2433 // 2434 // For Daytona, the atdisk driver gets the first shot at the 2435 // primary and secondary controllers. 2436 // 2437 2438 if (preConfig == FALSE) { 2439 2440 2441 if (*adapterCount - 1 < 2) { 2442 2443 // 2444 // Determine whether this driver is being initialized by the 2445 // system or as a crash dump driver. 2446 // 2447 2448 if (ArgumentString) { 2449 2450 if (AtapiParseArgumentString(ArgumentString, "dump") == 1) { 2451 DebugPrint((3, 2452 "AtapiFindController: Crash dump\n")); 2453 atapiOnly = FALSE; 2454 deviceExtension->DriverMustPoll = TRUE; 2455 } else { 2456 DebugPrint((3, 2457 "AtapiFindController: Atapi Only\n")); 2458 atapiOnly = TRUE; 2459 deviceExtension->DriverMustPoll = FALSE; 2460 } 2461 } else { 2462 2463 DebugPrint((3, 2464 "AtapiFindController: Atapi Only\n")); 2465 atapiOnly = TRUE; 2466 deviceExtension->DriverMustPoll = FALSE; 2467 } 2468 2469 } else { 2470 atapiOnly = FALSE; 2471 } 2472 2473 // 2474 // If this is a PCI machine, pick up all devices. 2475 // 2476 2477 2478 pciData = (PPCI_COMMON_CONFIG)&pciBuffer; 2479 2480 slotData.u.bits.DeviceNumber = 0; 2481 slotData.u.bits.FunctionNumber = 0; 2482 2483 if (ScsiPortGetBusData(deviceExtension, 2484 PCIConfiguration, 2485 0, // BusNumber 2486 slotData.u.AsULONG, 2487 pciData, 2488 sizeof(ULONG))) { 2489 2490 atapiOnly = FALSE; 2491 2492 // 2493 // Wait on doing this, until a reliable method 2494 // of determining support is found. 2495 // 2496 2497 #if 0 2498 deviceExtension->DWordIO = TRUE; 2499 #endif 2500 2501 } else { 2502 deviceExtension->DWordIO = FALSE; 2503 } 2504 2505 } else { 2506 2507 atapiOnly = FALSE; 2508 deviceExtension->DriverMustPoll = FALSE; 2509 2510 }// preConfig check 2511 2512 // 2513 // Save the Interrupt Mode for later use 2514 // 2515 deviceExtension->InterruptMode = ConfigInfo->InterruptMode; 2516 2517 // 2518 // Search for devices on this controller. 2519 // 2520 2521 if (FindDevices(HwDeviceExtension, 2522 atapiOnly, 2523 0)) { 2524 2525 // 2526 // Claim primary or secondary ATA IO range. 2527 // 2528 2529 if (portBase) { 2530 switch (portBase) { 2531 case 0x170: 2532 ConfigInfo->AtdiskSecondaryClaimed = TRUE; 2533 deviceExtension->PrimaryAddress = FALSE; 2534 break; 2535 case 0x1f0: 2536 ConfigInfo->AtdiskPrimaryClaimed = TRUE; 2537 deviceExtension->PrimaryAddress = TRUE; 2538 break; 2539 default: 2540 break; 2541 } 2542 } else { 2543 if (*adapterCount == 1) { 2544 ConfigInfo->AtdiskPrimaryClaimed = TRUE; 2545 deviceExtension->PrimaryAddress = TRUE; 2546 } else if (*adapterCount == 2) { 2547 ConfigInfo->AtdiskSecondaryClaimed = TRUE; 2548 deviceExtension->PrimaryAddress = FALSE; 2549 } 2550 } 2551 2552 return(SP_RETURN_FOUND); 2553 } 2554 } 2555 2556 // 2557 // The entire table has been searched and no adapters have been found. 2558 // There is no need to call again and the device base can now be freed. 2559 // Clear the adapter count for the next bus. 2560 // 2561 2562 *Again = FALSE; 2563 *(adapterCount) = 0; 2564 2565 return(SP_RETURN_NOT_FOUND); 2566 2567 } // end AtapiFindController() 2568 2569 2570 2571 2572 2573 BOOLEAN 2574 NTAPI 2575 FindBrokenController( 2576 IN PVOID DeviceExtension, 2577 IN PUCHAR VendorID, 2578 IN ULONG VendorIDLength, 2579 IN PUCHAR DeviceID, 2580 IN ULONG DeviceIDLength, 2581 IN OUT PULONG FunctionNumber, 2582 IN OUT PULONG SlotNumber, 2583 IN ULONG BusNumber, 2584 OUT PBOOLEAN LastSlot 2585 ) 2586 2587 /*++ 2588 2589 Routine Description: 2590 2591 Walk PCI slot information looking for Vendor and Product ID matches. 2592 2593 Arguments: 2594 2595 Return Value: 2596 2597 TRUE if card found. 2598 2599 --*/ 2600 { 2601 ULONG pciBuffer; 2602 ULONG slotNumber; 2603 ULONG functionNumber; 2604 PCI_SLOT_NUMBER slotData; 2605 PPCI_COMMON_CONFIG pciData; 2606 UCHAR vendorString[5]; 2607 UCHAR deviceString[5]; 2608 PUCHAR vendorStrPtr; 2609 PUCHAR deviceStrPtr; 2610 2611 pciData = (PPCI_COMMON_CONFIG)&pciBuffer; 2612 2613 slotData.u.AsULONG = 0; 2614 2615 // 2616 // Look at each device. 2617 // 2618 2619 for (slotNumber = *SlotNumber; 2620 slotNumber < 32; 2621 slotNumber++) { 2622 2623 slotData.u.bits.DeviceNumber = slotNumber; 2624 2625 // 2626 // Look at each function. 2627 // 2628 2629 for (functionNumber= *FunctionNumber; 2630 functionNumber < 8; 2631 functionNumber++) { 2632 2633 slotData.u.bits.FunctionNumber = functionNumber; 2634 2635 if (!ScsiPortGetBusData(DeviceExtension, 2636 PCIConfiguration, 2637 BusNumber, 2638 slotData.u.AsULONG, 2639 pciData, 2640 sizeof(ULONG))) { 2641 2642 // 2643 // Out of PCI data. 2644 // 2645 2646 *LastSlot = TRUE; 2647 return FALSE; 2648 } 2649 2650 if (pciData->VendorID == PCI_INVALID_VENDORID) { 2651 2652 // 2653 // No PCI device, or no more functions on device 2654 // move to next PCI device. 2655 // 2656 2657 break; 2658 } 2659 2660 // 2661 // Translate hex ids to strings. 2662 // 2663 2664 vendorStrPtr = vendorString; 2665 deviceStrPtr = deviceString; 2666 AtapiHexToString(pciData->VendorID, (PCHAR*)&vendorStrPtr); 2667 AtapiHexToString(pciData->DeviceID, (PCHAR*)&deviceStrPtr); 2668 2669 DebugPrint((2, 2670 "FindBrokenController: Bus %x Slot %x Function %x Vendor %s Product %s\n", 2671 BusNumber, 2672 slotNumber, 2673 functionNumber, 2674 vendorString, 2675 deviceString)); 2676 2677 // 2678 // Compare strings. 2679 // 2680 2681 if (AtapiStringCmp((PCHAR)vendorString, 2682 (PCHAR)VendorID, 2683 VendorIDLength) || 2684 AtapiStringCmp((PCHAR)deviceString, 2685 (PCHAR)DeviceID, 2686 DeviceIDLength)) { 2687 2688 // 2689 // Not our PCI device. Try next device/function 2690 // 2691 2692 continue; 2693 } 2694 2695 *FunctionNumber = functionNumber; 2696 *SlotNumber = slotNumber; 2697 return TRUE; 2698 2699 } // next PCI function 2700 2701 *FunctionNumber = 0; 2702 2703 } // next PCI slot 2704 2705 *LastSlot = TRUE; 2706 return FALSE; 2707 } // end FindBrokenController 2708 2709 2710 ULONG 2711 NTAPI 2712 AtapiFindNativeModeController( 2713 IN PVOID HwDeviceExtension, 2714 IN PVOID Context, 2715 IN PVOID BusInformation, 2716 IN PCHAR ArgumentString, 2717 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, 2718 OUT PBOOLEAN Again 2719 ) 2720 /*++ 2721 2722 Routine Description: 2723 2724 This function is called by the OS-specific port driver after 2725 the necessary storage has been allocated, to gather information 2726 about the adapter's configuration. 2727 2728 Arguments: 2729 2730 HwDeviceExtension - HBA miniport driver's adapter data storage 2731 Context - Address of adapter count 2732 BusInformation - 2733 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility. 2734 ConfigInfo - Configuration information structure describing HBA 2735 Again - Indicates search for adapters to continue 2736 2737 Return Value: 2738 2739 ULONG 2740 2741 --*/ 2742 2743 { 2744 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 2745 ULONG nativeModeAdapterTableIndex = (ULONG_PTR)Context; 2746 ULONG channel; 2747 PUCHAR ioSpace; 2748 BOOLEAN atapiOnly, 2749 deviceFound = FALSE; 2750 UCHAR statusByte; 2751 PCI_SLOT_NUMBER slotData; 2752 PCI_COMMON_CONFIG pciData; 2753 ULONG funcNumber; 2754 ULONG busDataRead; 2755 UCHAR vendorString[5]; 2756 UCHAR deviceString[5]; 2757 PUCHAR vendorStrPtr; 2758 PUCHAR deviceStrPtr; 2759 SCSI_PHYSICAL_ADDRESS IoBasePort1; 2760 SCSI_PHYSICAL_ADDRESS IoBasePort2; 2761 2762 // 2763 // The following table specifies the ports to be checked when searching for 2764 // an IDE controller. A zero entry terminates the search. 2765 // 2766 2767 CONST ULONG AdapterAddresses[3] = {0x1F0, 0x170, 0}; 2768 2769 if (!deviceExtension) { 2770 return SP_RETURN_ERROR; 2771 } 2772 2773 *Again = FALSE; 2774 2775 slotData.u.AsULONG = 0; 2776 slotData.u.bits.DeviceNumber = ConfigInfo->SlotNumber; 2777 2778 for (funcNumber= 0; funcNumber < 8; funcNumber++) { 2779 2780 slotData.u.bits.FunctionNumber = funcNumber; 2781 2782 busDataRead = ScsiPortGetBusData(HwDeviceExtension, 2783 PCIConfiguration, 2784 ConfigInfo->SystemIoBusNumber, 2785 slotData.u.AsULONG, 2786 &pciData, 2787 sizeof (pciData)); 2788 if (busDataRead != sizeof (pciData)) { 2789 return SP_RETURN_ERROR; 2790 } 2791 if (pciData.VendorID == PCI_INVALID_VENDORID) { 2792 return SP_RETURN_ERROR; 2793 } 2794 2795 // 2796 // Translate hex ids to strings. 2797 // 2798 2799 vendorStrPtr = vendorString; 2800 deviceStrPtr = deviceString; 2801 AtapiHexToString(pciData.VendorID, (PCHAR*)&vendorStrPtr); 2802 AtapiHexToString(pciData.DeviceID, (PCHAR*)&deviceStrPtr); 2803 2804 // 2805 // Compare strings. 2806 // 2807 2808 if (AtapiStringCmp((PCHAR)vendorString, 2809 NativeModeAdapters[nativeModeAdapterTableIndex].VendorId, 2810 NativeModeAdapters[nativeModeAdapterTableIndex].VendorIdLength) || 2811 AtapiStringCmp((PCHAR)deviceString, 2812 NativeModeAdapters[nativeModeAdapterTableIndex].DeviceId, 2813 NativeModeAdapters[nativeModeAdapterTableIndex].DeviceIdLength)) { 2814 continue; 2815 } 2816 2817 if (pciData.ProgIf & ((1 << 2) | (1 << 0))) { 2818 // both primary and secondary channel are in native mode 2819 2820 // Found our device 2821 *Again = TRUE; 2822 2823 break; 2824 } 2825 } 2826 2827 if (*Again != FALSE) { 2828 2829 for (channel = 0; channel < 2; channel++) { 2830 2831 IoBasePort1 = (*ConfigInfo->AccessRanges)[channel * 2 + 0].RangeStart; 2832 IoBasePort2 = (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeStart; 2833 IoBasePort2 = ScsiPortConvertUlongToPhysicalAddress(ScsiPortConvertPhysicalAddressToUlong(IoBasePort2) + 2); 2834 2835 // 2836 // Get the system physical address for this IO range. 2837 // 2838 2839 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 2840 ConfigInfo->AdapterInterfaceType, 2841 ConfigInfo->SystemIoBusNumber, 2842 IoBasePort1, 2843 8, 2844 TRUE); 2845 2846 // 2847 // Check if ioSpace accessible. 2848 // 2849 2850 if (!ioSpace) { 2851 continue; 2852 } 2853 2854 // 2855 // Select master. 2856 // 2857 2858 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xA0); 2859 2860 // 2861 // Check if card at this address. 2862 // 2863 2864 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 2865 2866 // 2867 // Check if identifier can be read back. 2868 // 2869 2870 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 2871 2872 DebugPrint((2, 2873 "AtapiFindPciController: Identifier read back from Master (%x)\n", 2874 statusByte)); 2875 2876 2877 // 2878 // Select slave. 2879 // 2880 2881 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xB0); 2882 2883 // 2884 // See if slave is present. 2885 // 2886 2887 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 2888 2889 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 2890 2891 DebugPrint((2, 2892 "AtapiFindPciController: Identifier read back from Slave (%x)\n", 2893 statusByte)); 2894 2895 // 2896 // 2897 // No controller at this base address. 2898 // 2899 2900 ScsiPortFreeDeviceBase(HwDeviceExtension, 2901 ioSpace); 2902 2903 // 2904 // If the chip is there, but we couldn't find the primary channel, try the secondary. 2905 // If we couldn't find a secondary, who cares. 2906 // 2907 2908 if (channel == 1) { 2909 2910 goto setStatusAndExit; 2911 2912 } else { 2913 continue; 2914 } 2915 } 2916 } 2917 2918 // 2919 // Record base IO address. 2920 // 2921 2922 deviceExtension->BaseIoAddress1[channel] = (PIDE_REGISTERS_1)(ioSpace); 2923 2924 // 2925 // Get the system physical address for the second IO range. 2926 // 2927 2928 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 2929 ConfigInfo->AdapterInterfaceType, 2930 ConfigInfo->SystemIoBusNumber, 2931 IoBasePort2, 2932 1, 2933 TRUE); 2934 2935 deviceExtension->BaseIoAddress2[channel] = (PIDE_REGISTERS_2)(ioSpace); 2936 2937 deviceExtension->NumberChannels = 2; 2938 2939 // 2940 // Indicate only one bus. 2941 // 2942 2943 ConfigInfo->NumberOfBuses = 1; 2944 2945 // 2946 // Indicate four devices can be attached to the adapter, since we 2947 // have to serialize access to the two channels. 2948 // 2949 2950 ConfigInfo->MaximumNumberOfTargets = 4; 2951 2952 // 2953 // Indicate maximum transfer length is 64k. 2954 // 2955 2956 ConfigInfo->MaximumTransferLength = 0x10000; 2957 2958 DebugPrint((1, 2959 "AtapiFindPciController: Found native mode IDE at %x\n", 2960 deviceExtension->BaseIoAddress1[channel])); 2961 2962 // 2963 // Since we will always pick up this part, and not atdisk, so indicate. 2964 // 2965 2966 atapiOnly = FALSE; 2967 2968 // 2969 // Save the Interrupt Mode for later use 2970 // 2971 deviceExtension->InterruptMode = ConfigInfo->InterruptMode; 2972 2973 // 2974 // Search for devices on this controller. 2975 // 2976 2977 if (FindDevices(HwDeviceExtension, 2978 atapiOnly, 2979 channel)){ 2980 deviceFound = TRUE; 2981 } 2982 2983 // 2984 // Claim primary or secondary ATA IO range. 2985 // 2986 2987 if (ScsiPortConvertPhysicalAddressToUlong(IoBasePort1) == AdapterAddresses[0]) { 2988 ConfigInfo->AtdiskPrimaryClaimed = TRUE; 2989 deviceExtension->PrimaryAddress = TRUE; 2990 2991 } else if (ScsiPortConvertPhysicalAddressToUlong(IoBasePort2) == AdapterAddresses[1]) { 2992 ConfigInfo->AtdiskSecondaryClaimed = TRUE; 2993 deviceExtension->PrimaryAddress = FALSE; 2994 } 2995 } 2996 } 2997 2998 setStatusAndExit: 2999 3000 if (deviceFound) { 3001 3002 *Again = TRUE; 3003 return SP_RETURN_FOUND; 3004 } 3005 3006 *Again = FALSE; 3007 return SP_RETURN_NOT_FOUND; 3008 3009 } // end AtapiFindNativeModeController() 3010 3011 3012 ULONG 3013 NTAPI 3014 AtapiFindPCIController( 3015 IN PVOID HwDeviceExtension, 3016 IN PVOID Context, 3017 IN PVOID BusInformation, 3018 IN PCHAR ArgumentString, 3019 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, 3020 OUT PBOOLEAN Again 3021 ) 3022 /*++ 3023 3024 Routine Description: 3025 3026 This function is called by the OS-specific port driver after 3027 the necessary storage has been allocated, to gather information 3028 about the adapter's configuration. 3029 3030 Arguments: 3031 3032 HwDeviceExtension - HBA miniport driver's adapter data storage 3033 Context - Address of adapter count 3034 BusInformation - 3035 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility. 3036 ConfigInfo - Configuration information structure describing HBA 3037 Again - Indicates search for adapters to continue 3038 3039 Return Value: 3040 3041 ULONG 3042 3043 --*/ 3044 3045 { 3046 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 3047 PULONG adapterCount = (PULONG)Context; 3048 ULONG channel = 0; 3049 static ULONG functionNumber, 3050 slotNumber, 3051 controllers; 3052 ULONG i,j; 3053 PUCHAR ioSpace; 3054 BOOLEAN atapiOnly, 3055 lastSlot, 3056 controllerFound = FALSE, 3057 deviceFound = FALSE; 3058 UCHAR statusByte; 3059 3060 // 3061 // The following table specifies the ports to be checked when searching for 3062 // an IDE controller. A zero entry terminates the search. 3063 // 3064 3065 CONST ULONG AdapterAddresses[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0}; 3066 3067 // 3068 // The following table specifies interrupt levels corresponding to the 3069 // port addresses in the previous table. 3070 // 3071 3072 CONST ULONG InterruptLevels[5] = {14, 15, 11, 10, 0}; 3073 3074 if (!deviceExtension) { 3075 return SP_RETURN_ERROR; 3076 } 3077 3078 // 3079 // Since scsiport will call this function first before it calls AtapiFindController 3080 // we need to bypass it if we have data installed in ConfigInfo, by the pcmcia driver. 3081 // In that case atapifindcontroller should be called first. 3082 // Instead of modifying atapi driverEntry to search of PCIBus first (now its ISA) 3083 // the check is put here. 3084 // 3085 3086 if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart) != 0) { 3087 3088 return AtapiFindController(HwDeviceExtension, 3089 Context, 3090 BusInformation, 3091 ArgumentString, 3092 ConfigInfo, 3093 Again); 3094 } 3095 3096 3097 // 3098 // Gronk PCI config space looking for the broken PCI IDE controllers that have only 3099 // one FIFO for both channels. 3100 // Don't do this. It's incorrect and nasty. It has to be done to work around these 3101 // broken parts, no other reason can justify this. 3102 // 3103 3104 for (i = controllers; i < BROKEN_ADAPTERS; i++) { 3105 3106 // 3107 // Determine if both channels are enabled and have devices. 3108 // 3109 3110 lastSlot = FALSE; 3111 3112 if (FindBrokenController(deviceExtension, 3113 (PUCHAR)BrokenAdapters[i].VendorId, 3114 BrokenAdapters[i].VendorIdLength, 3115 (PUCHAR)BrokenAdapters[i].DeviceId, 3116 BrokenAdapters[i].DeviceIdLength, 3117 &functionNumber, 3118 &slotNumber, 3119 ConfigInfo->SystemIoBusNumber, 3120 &lastSlot)) { 3121 3122 slotNumber++; 3123 functionNumber = 0; 3124 controllerFound = TRUE; 3125 3126 DebugPrint((1, 3127 "Found broken PCI IDE controller: VendorId %s, DeviceId %s\n", 3128 BrokenAdapters[i].VendorId, 3129 BrokenAdapters[i].DeviceId)); 3130 3131 if (AdapterAddresses[*adapterCount] != 0) { 3132 3133 for (j = 0; j < 2; j++) { 3134 3135 // 3136 // Get the system physical address for this IO range. 3137 // 3138 3139 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 3140 ConfigInfo->AdapterInterfaceType, 3141 ConfigInfo->SystemIoBusNumber, 3142 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]), 3143 8, 3144 TRUE); 3145 3146 // 3147 // Update the adapter count. 3148 // 3149 3150 (*adapterCount)++; 3151 3152 // 3153 // Check if ioSpace accessible. 3154 // 3155 3156 if (!ioSpace) { 3157 continue; 3158 } 3159 3160 // 3161 // Select master. 3162 // 3163 3164 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xA0); 3165 3166 // 3167 // Check if card at this address. 3168 // 3169 3170 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 3171 3172 // 3173 // Check if identifier can be read back. 3174 // 3175 3176 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 3177 3178 DebugPrint((2, 3179 "AtapiFindPciController: Identifier read back from Master (%x)\n", 3180 statusByte)); 3181 3182 3183 // 3184 // Select slave. 3185 // 3186 3187 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xB0); 3188 3189 // 3190 // See if slave is present. 3191 // 3192 3193 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 3194 3195 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 3196 3197 DebugPrint((2, 3198 "AtapiFindPciController: Identifier read back from Slave (%x)\n", 3199 statusByte)); 3200 3201 // 3202 // 3203 // No controller at this base address. 3204 // 3205 3206 ScsiPortFreeDeviceBase(HwDeviceExtension, 3207 ioSpace); 3208 3209 // 3210 // If the chip is there, but we couldn't find the primary channel, try the secondary. 3211 // If we couldn't find a secondary, who cares. 3212 // 3213 3214 if (j == 1) { 3215 3216 goto setStatusAndExit; 3217 3218 } else { 3219 continue; 3220 } 3221 } 3222 } 3223 3224 if (controllerFound) { 3225 3226 // 3227 // Record base IO address. 3228 // 3229 3230 deviceExtension->BaseIoAddress1[channel] = (PIDE_REGISTERS_1)(ioSpace); 3231 3232 // 3233 // Fill in the access array information. 3234 // 3235 3236 (*ConfigInfo->AccessRanges)[channel].RangeStart = 3237 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]); 3238 3239 (*ConfigInfo->AccessRanges)[channel].RangeLength = 8; 3240 (*ConfigInfo->AccessRanges)[channel].RangeInMemory = FALSE; 3241 3242 // 3243 // Indicate the interrupt level corresponding to this IO range. 3244 // 3245 3246 if (channel == 0) { 3247 ConfigInfo->BusInterruptLevel = InterruptLevels[*adapterCount - 1]; 3248 ConfigInfo->InterruptMode = Latched; 3249 } else { 3250 ConfigInfo->BusInterruptLevel2 = InterruptLevels[*adapterCount - 1]; 3251 ConfigInfo->InterruptMode2 = Latched; 3252 } 3253 3254 // 3255 // Get the system physical address for the second IO range. 3256 // 3257 3258 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 3259 ConfigInfo->AdapterInterfaceType, 3260 ConfigInfo->SystemIoBusNumber, 3261 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1] + 0x206), 3262 1, 3263 TRUE); 3264 3265 deviceExtension->BaseIoAddress2[channel] = (PIDE_REGISTERS_2)(ioSpace); 3266 3267 deviceExtension->NumberChannels = 2; 3268 3269 // 3270 // Indicate only one bus. 3271 // 3272 3273 ConfigInfo->NumberOfBuses = 1; 3274 3275 // 3276 // Indicate four devices can be attached to the adapter, since we 3277 // have to serialize access to the two channels. 3278 // 3279 3280 ConfigInfo->MaximumNumberOfTargets = 4; 3281 3282 // 3283 // Indicate maximum transfer length is 64k. 3284 // 3285 3286 ConfigInfo->MaximumTransferLength = 0x10000; 3287 3288 DebugPrint((1, 3289 "AtapiFindPciController: Found broken IDE at %x\n", 3290 deviceExtension->BaseIoAddress1[channel])); 3291 3292 // 3293 // Since we will always pick up this part, and not atdisk, so indicate. 3294 // 3295 3296 atapiOnly = FALSE; 3297 3298 // 3299 // Save the Interrupt Mode for later use 3300 // 3301 deviceExtension->InterruptMode = ConfigInfo->InterruptMode; 3302 3303 // 3304 // Search for devices on this controller. 3305 // 3306 3307 if (FindDevices(HwDeviceExtension, 3308 atapiOnly, 3309 channel++)){ 3310 deviceFound = TRUE; 3311 } 3312 3313 // 3314 // Claim primary or secondary ATA IO range. 3315 // 3316 3317 if (*adapterCount == 1) { 3318 ConfigInfo->AtdiskPrimaryClaimed = TRUE; 3319 deviceExtension->PrimaryAddress = TRUE; 3320 3321 } else if (*adapterCount == 2) { 3322 ConfigInfo->AtdiskSecondaryClaimed = TRUE; 3323 deviceExtension->PrimaryAddress = FALSE; 3324 } 3325 } 3326 } 3327 } 3328 } 3329 3330 setStatusAndExit: 3331 3332 if (lastSlot) { 3333 slotNumber = 0; 3334 functionNumber = 0; 3335 } 3336 3337 controllers = i; 3338 3339 if (controllerFound && deviceFound) { 3340 3341 *Again = TRUE; 3342 return SP_RETURN_FOUND; 3343 } 3344 } 3345 3346 3347 // 3348 // The entire table has been searched and no adapters have been found. 3349 // 3350 3351 *Again = FALSE; 3352 3353 return SP_RETURN_NOT_FOUND; 3354 3355 } // end AtapiFindPCIController() 3356 3357 3358 ULONG 3359 NTAPI 3360 Atapi2Scsi( 3361 IN PSCSI_REQUEST_BLOCK Srb, 3362 IN char *DataBuffer, 3363 IN ULONG ByteCount 3364 ) 3365 { 3366 ULONG bytesAdjust = 0; 3367 if (Srb->Cdb[0] == ATAPI_MODE_SENSE) { 3368 3369 PMODE_PARAMETER_HEADER_10 header_10 = (PMODE_PARAMETER_HEADER_10)DataBuffer; 3370 PMODE_PARAMETER_HEADER header = (PMODE_PARAMETER_HEADER)DataBuffer; 3371 3372 header->ModeDataLength = header_10->ModeDataLengthLsb; 3373 header->MediumType = header_10->MediumType; 3374 3375 // 3376 // ATAPI Mode Parameter Header doesn't have these fields. 3377 // 3378 3379 header->DeviceSpecificParameter = header_10->Reserved[0]; 3380 header->BlockDescriptorLength = header_10->Reserved[1]; 3381 3382 ByteCount -= sizeof(MODE_PARAMETER_HEADER_10); 3383 if (ByteCount > 0) 3384 ScsiPortMoveMemory(DataBuffer+sizeof(MODE_PARAMETER_HEADER), 3385 DataBuffer+sizeof(MODE_PARAMETER_HEADER_10), 3386 ByteCount); 3387 3388 // 3389 // Change ATAPI_MODE_SENSE opcode back to SCSIOP_MODE_SENSE 3390 // so that we don't convert again. 3391 // 3392 3393 Srb->Cdb[0] = SCSIOP_MODE_SENSE; 3394 3395 bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) - 3396 sizeof(MODE_PARAMETER_HEADER); 3397 3398 3399 } 3400 3401 // 3402 // Convert to words. 3403 // 3404 3405 return bytesAdjust >> 1; 3406 } 3407 3408 3409 VOID 3410 NTAPI 3411 AtapiCallBack( 3412 IN PVOID HwDeviceExtension 3413 ) 3414 { 3415 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 3416 PSCSI_REQUEST_BLOCK srb = deviceExtension->CurrentSrb; 3417 PATAPI_REGISTERS_2 baseIoAddress2; 3418 UCHAR statusByte; 3419 3420 // 3421 // If the last command was DSC restrictive, see if it's set. If so, the device is 3422 // ready for a new request. Otherwise, reset the timer and come back to here later. 3423 // 3424 3425 if (srb && (!(deviceExtension->ExpectingInterrupt))) { 3426 #if DBG 3427 if (!IS_RDP((srb->Cdb[0]))) { 3428 DebugPrint((1, 3429 "AtapiCallBack: Invalid CDB marked as RDP - %x\n", 3430 srb->Cdb[0])); 3431 } 3432 #endif 3433 3434 baseIoAddress2 = (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[srb->TargetId >> 1]; 3435 if (deviceExtension->RDP) { 3436 GetStatus(baseIoAddress2, statusByte); 3437 if (statusByte & IDE_STATUS_DSC) { 3438 3439 ScsiPortNotification(RequestComplete, 3440 deviceExtension, 3441 srb); 3442 3443 // 3444 // Clear current SRB. 3445 // 3446 3447 deviceExtension->CurrentSrb = NULL; 3448 deviceExtension->RDP = FALSE; 3449 3450 // 3451 // Ask for next request. 3452 // 3453 3454 ScsiPortNotification(NextRequest, 3455 deviceExtension, 3456 NULL); 3457 3458 3459 return; 3460 3461 } else { 3462 3463 DebugPrint((3, 3464 "AtapiCallBack: Requesting another timer for Op %x\n", 3465 deviceExtension->CurrentSrb->Cdb[0])); 3466 3467 ScsiPortNotification(RequestTimerCall, 3468 HwDeviceExtension, 3469 AtapiCallBack, 3470 1000); 3471 return; 3472 } 3473 } 3474 } 3475 3476 DebugPrint((2, 3477 "AtapiCallBack: Calling ISR directly due to BUSY\n")); 3478 AtapiInterrupt(HwDeviceExtension); 3479 } 3480 3481 3482 BOOLEAN 3483 NTAPI 3484 AtapiInterrupt( 3485 IN PVOID HwDeviceExtension 3486 ) 3487 3488 /*++ 3489 3490 Routine Description: 3491 3492 This is the interrupt service routine for ATAPI IDE miniport driver. 3493 3494 Arguments: 3495 3496 HwDeviceExtension - HBA miniport driver's adapter data storage 3497 3498 Return Value: 3499 3500 TRUE if expecting an interrupt. 3501 3502 --*/ 3503 3504 { 3505 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 3506 PSCSI_REQUEST_BLOCK srb = deviceExtension->CurrentSrb; 3507 PATAPI_REGISTERS_1 baseIoAddress1; 3508 PATAPI_REGISTERS_2 baseIoAddress2; 3509 ULONG wordCount = 0, wordsThisInterrupt = 256; 3510 ULONG status; 3511 ULONG i; 3512 UCHAR statusByte,interruptReason; 3513 BOOLEAN atapiDev = FALSE; 3514 3515 if (srb) { 3516 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[srb->TargetId >> 1]; 3517 baseIoAddress2 = (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[srb->TargetId >> 1]; 3518 } else { 3519 DebugPrint((2, 3520 "AtapiInterrupt: CurrentSrb is NULL\n")); 3521 // 3522 // We can only support one ATAPI IDE master on Carolina, so find 3523 // the base address that is non NULL and clear its interrupt before 3524 // returning. 3525 // 3526 3527 #ifdef _PPC_ 3528 3529 if ((PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0] != NULL) { 3530 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0]; 3531 } else { 3532 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[1]; 3533 } 3534 3535 GetBaseStatus(baseIoAddress1, statusByte); 3536 #else 3537 3538 if (deviceExtension->InterruptMode == LevelSensitive) { 3539 if (deviceExtension->BaseIoAddress1[0] != NULL) { 3540 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0]; 3541 GetBaseStatus(baseIoAddress1, statusByte); 3542 } 3543 if (deviceExtension->BaseIoAddress1[1] != NULL) { 3544 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[1]; 3545 GetBaseStatus(baseIoAddress1, statusByte); 3546 } 3547 } 3548 #endif 3549 return FALSE; 3550 } 3551 3552 if (!(deviceExtension->ExpectingInterrupt)) { 3553 3554 DebugPrint((3, 3555 "AtapiInterrupt: Unexpected interrupt.\n")); 3556 return FALSE; 3557 } 3558 3559 // 3560 // Clear interrupt by reading status. 3561 // 3562 3563 GetBaseStatus(baseIoAddress1, statusByte); 3564 3565 DebugPrint((3, 3566 "AtapiInterrupt: Entered with status (%x)\n", 3567 statusByte)); 3568 3569 3570 if (statusByte & IDE_STATUS_BUSY) { 3571 if (deviceExtension->DriverMustPoll) { 3572 3573 // 3574 // Crashdump is polling and we got caught with busy asserted. 3575 // Just go away, and we will be polled again shortly. 3576 // 3577 3578 DebugPrint((3, 3579 "AtapiInterrupt: Hit BUSY while polling during crashdump.\n")); 3580 3581 return TRUE; 3582 } 3583 3584 // 3585 // Ensure BUSY is non-asserted. 3586 // 3587 3588 for (i = 0; i < 10; i++) { 3589 3590 GetBaseStatus(baseIoAddress1, statusByte); 3591 if (!(statusByte & IDE_STATUS_BUSY)) { 3592 break; 3593 } 3594 ScsiPortStallExecution(5000); 3595 } 3596 3597 if (i == 10) { 3598 3599 DebugPrint((2, 3600 "AtapiInterrupt: BUSY on entry. Status %x, Base IO %x\n", 3601 statusByte, 3602 baseIoAddress1)); 3603 3604 ScsiPortNotification(RequestTimerCall, 3605 HwDeviceExtension, 3606 AtapiCallBack, 3607 500); 3608 return TRUE; 3609 } 3610 } 3611 3612 3613 // 3614 // Check for error conditions. 3615 // 3616 3617 if (statusByte & IDE_STATUS_ERROR) { 3618 3619 if (srb->Cdb[0] != SCSIOP_REQUEST_SENSE) { 3620 3621 // 3622 // Fail this request. 3623 // 3624 3625 status = SRB_STATUS_ERROR; 3626 goto CompleteRequest; 3627 } 3628 } 3629 3630 // 3631 // check reason for this interrupt. 3632 // 3633 3634 if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 3635 3636 interruptReason = (ScsiPortReadPortUchar(&baseIoAddress1->InterruptReason) & 0x3); 3637 atapiDev = TRUE; 3638 wordsThisInterrupt = 256; 3639 3640 } else { 3641 3642 if (statusByte & IDE_STATUS_DRQ) { 3643 3644 if (deviceExtension->MaximumBlockXfer[srb->TargetId]) { 3645 wordsThisInterrupt = 256 * deviceExtension->MaximumBlockXfer[srb->TargetId]; 3646 3647 } 3648 3649 if (srb->SrbFlags & SRB_FLAGS_DATA_IN) { 3650 3651 interruptReason = 0x2; 3652 3653 } else if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) { 3654 interruptReason = 0x0; 3655 3656 } else { 3657 status = SRB_STATUS_ERROR; 3658 goto CompleteRequest; 3659 } 3660 3661 } else if (statusByte & IDE_STATUS_BUSY) { 3662 3663 return FALSE; 3664 3665 } else { 3666 3667 if (deviceExtension->WordsLeft) { 3668 3669 ULONG k; 3670 3671 // 3672 // Funky behaviour seen with PCI IDE (not all, just one). 3673 // The ISR hits with DRQ low, but comes up later. 3674 // 3675 3676 for (k = 0; k < 5000; k++) { 3677 GetStatus(baseIoAddress2,statusByte); 3678 if (!(statusByte & IDE_STATUS_DRQ)) { 3679 ScsiPortStallExecution(100); 3680 } else { 3681 break; 3682 } 3683 } 3684 3685 if (k == 5000) { 3686 3687 // 3688 // reset the controller. 3689 // 3690 3691 DebugPrint((1, 3692 "AtapiInterrupt: Resetting due to DRQ not up. Status %x, Base IO %x\n", 3693 statusByte, 3694 baseIoAddress1)); 3695 3696 AtapiResetController(HwDeviceExtension,srb->PathId); 3697 return TRUE; 3698 } else { 3699 3700 interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x2 : 0x0; 3701 } 3702 3703 } else { 3704 3705 // 3706 // Command complete - verify, write, or the SMART enable/disable. 3707 // 3708 // Also get_media_status 3709 3710 interruptReason = 0x3; 3711 } 3712 } 3713 } 3714 3715 if (interruptReason == 0x1 && (statusByte & IDE_STATUS_DRQ)) { 3716 3717 // 3718 // Write the packet. 3719 // 3720 3721 DebugPrint((2, 3722 "AtapiInterrupt: Writing Atapi packet.\n")); 3723 3724 // 3725 // Send CDB to device. 3726 // 3727 3728 WriteBuffer(baseIoAddress1, 3729 (PUSHORT)srb->Cdb, 3730 6); 3731 3732 return TRUE; 3733 3734 } else if (interruptReason == 0x0 && (statusByte & IDE_STATUS_DRQ)) { 3735 3736 // 3737 // Write the data. 3738 // 3739 3740 if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 3741 3742 // 3743 // Pick up bytes to transfer and convert to words. 3744 // 3745 3746 wordCount = 3747 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow); 3748 3749 wordCount |= 3750 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh) << 8; 3751 3752 // 3753 // Covert bytes to words. 3754 // 3755 3756 wordCount >>= 1; 3757 3758 if (wordCount != deviceExtension->WordsLeft) { 3759 DebugPrint((3, 3760 "AtapiInterrupt: %d words requested; %d words xferred\n", 3761 deviceExtension->WordsLeft, 3762 wordCount)); 3763 } 3764 3765 // 3766 // Verify this makes sense. 3767 // 3768 3769 if (wordCount > deviceExtension->WordsLeft) { 3770 wordCount = deviceExtension->WordsLeft; 3771 } 3772 3773 } else { 3774 3775 // 3776 // IDE path. Check if words left is at least 256. 3777 // 3778 3779 if (deviceExtension->WordsLeft < wordsThisInterrupt) { 3780 3781 // 3782 // Transfer only words requested. 3783 // 3784 3785 wordCount = deviceExtension->WordsLeft; 3786 3787 } else { 3788 3789 // 3790 // Transfer next block. 3791 // 3792 3793 wordCount = wordsThisInterrupt; 3794 } 3795 } 3796 3797 // 3798 // Ensure that this is a write command. 3799 // 3800 3801 if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) { 3802 3803 DebugPrint((3, 3804 "AtapiInterrupt: Write interrupt\n")); 3805 3806 WaitOnBusy(baseIoAddress2,statusByte); 3807 3808 if (atapiDev || !deviceExtension->DWordIO) { 3809 3810 WriteBuffer(baseIoAddress1, 3811 deviceExtension->DataBuffer, 3812 wordCount); 3813 } else { 3814 3815 PIDE_REGISTERS_3 address3 = (PIDE_REGISTERS_3)baseIoAddress1; 3816 3817 WriteBuffer2(address3, 3818 (PULONG)(deviceExtension->DataBuffer), 3819 wordCount / 2); 3820 } 3821 } else { 3822 3823 DebugPrint((1, 3824 "AtapiInterrupt: Int reason %x, but srb is for a write %x.\n", 3825 interruptReason, 3826 srb)); 3827 3828 // 3829 // Fail this request. 3830 // 3831 3832 status = SRB_STATUS_ERROR; 3833 goto CompleteRequest; 3834 } 3835 3836 3837 // 3838 // Advance data buffer pointer and bytes left. 3839 // 3840 3841 deviceExtension->DataBuffer += wordCount; 3842 deviceExtension->WordsLeft -= wordCount; 3843 3844 return TRUE; 3845 3846 } else if (interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) { 3847 3848 3849 if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 3850 3851 // 3852 // Pick up bytes to transfer and convert to words. 3853 // 3854 3855 wordCount = 3856 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow); 3857 3858 wordCount |= 3859 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh) << 8; 3860 3861 // 3862 // Covert bytes to words. 3863 // 3864 3865 wordCount >>= 1; 3866 3867 if (wordCount != deviceExtension->WordsLeft) { 3868 DebugPrint((3, 3869 "AtapiInterrupt: %d words requested; %d words xferred\n", 3870 deviceExtension->WordsLeft, 3871 wordCount)); 3872 } 3873 3874 // 3875 // Verify this makes sense. 3876 // 3877 3878 if (wordCount > deviceExtension->WordsLeft) { 3879 wordCount = deviceExtension->WordsLeft; 3880 } 3881 3882 } else { 3883 3884 // 3885 // Check if words left is at least 256. 3886 // 3887 3888 if (deviceExtension->WordsLeft < wordsThisInterrupt) { 3889 3890 // 3891 // Transfer only words requested. 3892 // 3893 3894 wordCount = deviceExtension->WordsLeft; 3895 3896 } else { 3897 3898 // 3899 // Transfer next block. 3900 // 3901 3902 wordCount = wordsThisInterrupt; 3903 } 3904 } 3905 3906 // 3907 // Ensure that this is a read command. 3908 // 3909 3910 if (srb->SrbFlags & SRB_FLAGS_DATA_IN) { 3911 3912 DebugPrint((3, 3913 "AtapiInterrupt: Read interrupt\n")); 3914 3915 WaitOnBusy(baseIoAddress2,statusByte); 3916 3917 if (atapiDev || !deviceExtension->DWordIO) { 3918 ReadBuffer(baseIoAddress1, 3919 deviceExtension->DataBuffer, 3920 wordCount); 3921 3922 } else { 3923 PIDE_REGISTERS_3 address3 = (PIDE_REGISTERS_3)baseIoAddress1; 3924 3925 ReadBuffer2(address3, 3926 (PULONG)(deviceExtension->DataBuffer), 3927 wordCount / 2); 3928 } 3929 } else { 3930 3931 DebugPrint((1, 3932 "AtapiInterrupt: Int reason %x, but srb is for a read %x.\n", 3933 interruptReason, 3934 srb)); 3935 3936 // 3937 // Fail this request. 3938 // 3939 3940 status = SRB_STATUS_ERROR; 3941 goto CompleteRequest; 3942 } 3943 3944 // 3945 // Translate ATAPI data back to SCSI data if needed 3946 // 3947 3948 if (srb->Cdb[0] == ATAPI_MODE_SENSE && 3949 deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 3950 3951 // 3952 //convert and adjust the wordCount 3953 // 3954 3955 wordCount -= Atapi2Scsi(srb, (char *)deviceExtension->DataBuffer, 3956 wordCount << 1); 3957 } 3958 // 3959 // Advance data buffer pointer and bytes left. 3960 // 3961 3962 deviceExtension->DataBuffer += wordCount; 3963 deviceExtension->WordsLeft -= wordCount; 3964 3965 // 3966 // Check for read command complete. 3967 // 3968 3969 if (deviceExtension->WordsLeft == 0) { 3970 3971 if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 3972 3973 // 3974 // Work around to make many atapi devices return correct sector size 3975 // of 2048. Also certain devices will have sector count == 0x00, check 3976 // for that also. 3977 // 3978 3979 if ((srb->Cdb[0] == 0x25) && 3980 ((deviceExtension->IdentifyData[srb->TargetId].GeneralConfiguration >> 8) & 0x1f) == 0x05) { 3981 3982 deviceExtension->DataBuffer -= wordCount; 3983 if (deviceExtension->DataBuffer[0] == 0x00) { 3984 3985 *((ULONG *) &(deviceExtension->DataBuffer[0])) = 0xFFFFFF7F; 3986 3987 } 3988 3989 *((ULONG *) &(deviceExtension->DataBuffer[2])) = 0x00080000; 3990 deviceExtension->DataBuffer += wordCount; 3991 } 3992 } else { 3993 3994 // 3995 // Completion for IDE drives. 3996 // 3997 3998 3999 if (deviceExtension->WordsLeft) { 4000 4001 status = SRB_STATUS_DATA_OVERRUN; 4002 4003 } else { 4004 4005 status = SRB_STATUS_SUCCESS; 4006 4007 } 4008 4009 goto CompleteRequest; 4010 4011 } 4012 } 4013 4014 return TRUE; 4015 4016 } else if (interruptReason == 0x3 && !(statusByte & IDE_STATUS_DRQ)) { 4017 4018 // 4019 // Command complete. 4020 // 4021 4022 if (deviceExtension->WordsLeft) { 4023 4024 status = SRB_STATUS_DATA_OVERRUN; 4025 4026 } else { 4027 4028 status = SRB_STATUS_SUCCESS; 4029 4030 } 4031 4032 CompleteRequest: 4033 4034 // 4035 // Check and see if we are processing our secret (mechanism status/request sense) srb 4036 // 4037 if (deviceExtension->OriginalSrb) { 4038 4039 ULONG srbStatus; 4040 4041 if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) { 4042 4043 if (status == SRB_STATUS_SUCCESS) { 4044 // Bingo!! 4045 AtapiHwInitializeChanger (HwDeviceExtension, 4046 srb->TargetId, 4047 (PMECHANICAL_STATUS_INFORMATION_HEADER) srb->DataBuffer); 4048 4049 // Get ready to issue the original srb 4050 srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb; 4051 deviceExtension->OriginalSrb = NULL; 4052 4053 } else { 4054 // failed! Get the sense key and maybe try again 4055 srb = deviceExtension->CurrentSrb = BuildRequestSenseSrb ( 4056 HwDeviceExtension, 4057 deviceExtension->OriginalSrb->PathId, 4058 deviceExtension->OriginalSrb->TargetId); 4059 } 4060 4061 srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb); 4062 if (srbStatus == SRB_STATUS_PENDING) { 4063 return TRUE; 4064 } 4065 4066 } else { // srb->Cdb[0] == SCSIOP_REQUEST_SENSE) 4067 4068 PSENSE_DATA senseData = (PSENSE_DATA) srb->DataBuffer; 4069 4070 if (status == SRB_STATUS_DATA_OVERRUN) { 4071 // Check to see if we at least get minimum number of bytes 4072 if ((srb->DataTransferLength - deviceExtension->WordsLeft) > 4073 (FIELD_OFFSET (SENSE_DATA, AdditionalSenseLength) + sizeof(senseData->AdditionalSenseLength))) { 4074 status = SRB_STATUS_SUCCESS; 4075 } 4076 } 4077 4078 if (status == SRB_STATUS_SUCCESS) { 4079 if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) && 4080 deviceExtension->MechStatusRetryCount) { 4081 4082 // The sense key doesn't say the last request is illegal, so try again 4083 deviceExtension->MechStatusRetryCount--; 4084 srb = deviceExtension->CurrentSrb = BuildMechanismStatusSrb ( 4085 HwDeviceExtension, 4086 deviceExtension->OriginalSrb->PathId, 4087 deviceExtension->OriginalSrb->TargetId); 4088 } else { 4089 4090 // last request was illegal. No point trying again 4091 4092 AtapiHwInitializeChanger (HwDeviceExtension, 4093 srb->TargetId, 4094 (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL); 4095 4096 // Get ready to issue the original srb 4097 srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb; 4098 deviceExtension->OriginalSrb = NULL; 4099 } 4100 4101 srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb); 4102 if (srbStatus == SRB_STATUS_PENDING) { 4103 return TRUE; 4104 } 4105 } 4106 } 4107 4108 // If we get here, it means AtapiSendCommand() has failed 4109 // Can't recover. Pretend the original srb has failed and complete it. 4110 4111 if (deviceExtension->OriginalSrb) { 4112 AtapiHwInitializeChanger (HwDeviceExtension, 4113 srb->TargetId, 4114 (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL); 4115 srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb; 4116 deviceExtension->OriginalSrb = NULL; 4117 } 4118 4119 // fake an error and read no data 4120 status = SRB_STATUS_ERROR; 4121 srb->ScsiStatus = 0; 4122 deviceExtension->DataBuffer = srb->DataBuffer; 4123 deviceExtension->WordsLeft = srb->DataTransferLength; 4124 deviceExtension->RDP = FALSE; 4125 4126 } else if (status == SRB_STATUS_ERROR) { 4127 4128 // 4129 // Map error to specific SRB status and handle request sense. 4130 // 4131 4132 status = MapError(deviceExtension, 4133 srb); 4134 4135 deviceExtension->RDP = FALSE; 4136 4137 } else { 4138 4139 // 4140 // Wait for busy to drop. 4141 // 4142 4143 for (i = 0; i < 30; i++) { 4144 GetStatus(baseIoAddress2,statusByte); 4145 if (!(statusByte & IDE_STATUS_BUSY)) { 4146 break; 4147 } 4148 ScsiPortStallExecution(500); 4149 } 4150 4151 if (i == 30) { 4152 4153 // 4154 // reset the controller. 4155 // 4156 4157 DebugPrint((1, 4158 "AtapiInterrupt: Resetting due to BSY still up - %x. Base Io %x\n", 4159 statusByte, 4160 baseIoAddress1)); 4161 AtapiResetController(HwDeviceExtension,srb->PathId); 4162 return TRUE; 4163 } 4164 4165 // 4166 // Check to see if DRQ is still up. 4167 // 4168 4169 if (statusByte & IDE_STATUS_DRQ) { 4170 4171 for (i = 0; i < 500; i++) { 4172 GetStatus(baseIoAddress2,statusByte); 4173 if (!(statusByte & IDE_STATUS_DRQ)) { 4174 break; 4175 } 4176 ScsiPortStallExecution(100); 4177 4178 } 4179 4180 if (i == 500) { 4181 4182 // 4183 // reset the controller. 4184 // 4185 4186 DebugPrint((1, 4187 "AtapiInterrupt: Resetting due to DRQ still up - %x\n", 4188 statusByte)); 4189 AtapiResetController(HwDeviceExtension,srb->PathId); 4190 return TRUE; 4191 } 4192 4193 } 4194 } 4195 4196 4197 // 4198 // Clear interrupt expecting flag. 4199 // 4200 4201 deviceExtension->ExpectingInterrupt = FALSE; 4202 4203 // 4204 // Sanity check that there is a current request. 4205 // 4206 4207 if (srb != NULL) { 4208 4209 // 4210 // Set status in SRB. 4211 // 4212 4213 srb->SrbStatus = (UCHAR)status; 4214 4215 // 4216 // Check for underflow. 4217 // 4218 4219 if (deviceExtension->WordsLeft) { 4220 4221 // 4222 // Subtract out residual words and update if filemark hit, 4223 // setmark hit , end of data, end of media... 4224 // 4225 4226 if (!(deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_TAPE_DEVICE)) { 4227 if (status == SRB_STATUS_DATA_OVERRUN) { 4228 srb->DataTransferLength -= deviceExtension->WordsLeft; 4229 } else { 4230 srb->DataTransferLength = 0; 4231 } 4232 } else { 4233 srb->DataTransferLength -= deviceExtension->WordsLeft; 4234 } 4235 } 4236 4237 if (srb->Function != SRB_FUNCTION_IO_CONTROL) { 4238 4239 // 4240 // Indicate command complete. 4241 // 4242 4243 if (!(deviceExtension->RDP)) { 4244 ScsiPortNotification(RequestComplete, 4245 deviceExtension, 4246 srb); 4247 4248 } 4249 } else { 4250 4251 PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 4252 UCHAR error = 0; 4253 4254 if (status != SRB_STATUS_SUCCESS) { 4255 error = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 4256 } 4257 4258 // 4259 // Build the SMART status block depending upon the completion status. 4260 // 4261 4262 cmdOutParameters->cBufferSize = wordCount; 4263 cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0; 4264 cmdOutParameters->DriverStatus.bIDEError = error; 4265 4266 // 4267 // If the sub-command is return smart status, jam the value from cylinder low and high, into the 4268 // data buffer. 4269 // 4270 4271 if (deviceExtension->SmartCommand == RETURN_SMART_STATUS) { 4272 cmdOutParameters->bBuffer[0] = RETURN_SMART_STATUS; 4273 cmdOutParameters->bBuffer[1] = ScsiPortReadPortUchar(&baseIoAddress1->InterruptReason); 4274 cmdOutParameters->bBuffer[2] = ScsiPortReadPortUchar(&baseIoAddress1->Unused1); 4275 cmdOutParameters->bBuffer[3] = ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow); 4276 cmdOutParameters->bBuffer[4] = ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh); 4277 cmdOutParameters->bBuffer[5] = ScsiPortReadPortUchar(&baseIoAddress1->DriveSelect); 4278 cmdOutParameters->bBuffer[6] = SMART_CMD; 4279 cmdOutParameters->cBufferSize = 8; 4280 } 4281 4282 // 4283 // Indicate command complete. 4284 // 4285 4286 ScsiPortNotification(RequestComplete, 4287 deviceExtension, 4288 srb); 4289 4290 } 4291 4292 } else { 4293 4294 DebugPrint((1, 4295 "AtapiInterrupt: No SRB!\n")); 4296 } 4297 4298 // 4299 // Indicate ready for next request. 4300 // 4301 4302 if (!(deviceExtension->RDP)) { 4303 4304 // 4305 // Clear current SRB. 4306 // 4307 4308 deviceExtension->CurrentSrb = NULL; 4309 4310 ScsiPortNotification(NextRequest, 4311 deviceExtension, 4312 NULL); 4313 } else { 4314 4315 ScsiPortNotification(RequestTimerCall, 4316 HwDeviceExtension, 4317 AtapiCallBack, 4318 2000); 4319 } 4320 4321 return TRUE; 4322 4323 } else { 4324 4325 // 4326 // Unexpected int. 4327 // 4328 4329 DebugPrint((3, 4330 "AtapiInterrupt: Unexpected interrupt. InterruptReason %x. Status %x.\n", 4331 interruptReason, 4332 statusByte)); 4333 return FALSE; 4334 } 4335 4336 return TRUE; 4337 4338 } // end AtapiInterrupt() 4339 4340 4341 ULONG 4342 NTAPI 4343 IdeSendSmartCommand( 4344 IN PVOID HwDeviceExtension, 4345 IN PSCSI_REQUEST_BLOCK Srb 4346 ) 4347 4348 /*++ 4349 4350 Routine Description: 4351 4352 This routine handles SMART enable, disable, read attributes and threshold commands. 4353 4354 Arguments: 4355 4356 HwDeviceExtension - HBA miniport driver's adapter data storage 4357 Srb - IO request packet 4358 4359 Return Value: 4360 4361 SRB status 4362 4363 --*/ 4364 4365 { 4366 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 4367 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 4368 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 4369 PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 4370 SENDCMDINPARAMS cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 4371 PIDEREGS regs = &cmdInParameters.irDriveRegs; 4372 ULONG i; 4373 UCHAR statusByte,targetId; 4374 4375 4376 if (cmdInParameters.irDriveRegs.bCommandReg == SMART_CMD) { 4377 4378 targetId = cmdInParameters.bDriveNumber; 4379 4380 //TODO optimize this check 4381 4382 if ((!(deviceExtension->DeviceFlags[targetId] & DFLAGS_DEVICE_PRESENT)) || 4383 (deviceExtension->DeviceFlags[targetId] & DFLAGS_ATAPI_DEVICE)) { 4384 4385 return SRB_STATUS_SELECTION_TIMEOUT; 4386 } 4387 4388 deviceExtension->SmartCommand = cmdInParameters.irDriveRegs.bFeaturesReg; 4389 4390 // 4391 // Determine which of the commands to carry out. 4392 // 4393 4394 if ((cmdInParameters.irDriveRegs.bFeaturesReg == READ_ATTRIBUTES) || 4395 (cmdInParameters.irDriveRegs.bFeaturesReg == READ_THRESHOLDS)) { 4396 4397 WaitOnBusy(baseIoAddress2,statusByte); 4398 4399 if (statusByte & IDE_STATUS_BUSY) { 4400 DebugPrint((1, 4401 "IdeSendSmartCommand: Returning BUSY status\n")); 4402 return SRB_STATUS_BUSY; 4403 } 4404 4405 // 4406 // Zero the output buffer as the input buffer info. has been saved off locally (the buffers are the same). 4407 // 4408 4409 for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1); i++) { 4410 ((PUCHAR)cmdOutParameters)[i] = 0; 4411 } 4412 4413 // 4414 // Set data buffer pointer and words left. 4415 // 4416 4417 deviceExtension->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer; 4418 deviceExtension->WordsLeft = READ_ATTRIBUTE_BUFFER_SIZE / 2; 4419 4420 // 4421 // Indicate expecting an interrupt. 4422 // 4423 4424 deviceExtension->ExpectingInterrupt = TRUE; 4425 4426 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,(UCHAR)(((targetId & 0x1) << 4) | 0xA0)); 4427 ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,regs->bFeaturesReg); 4428 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,regs->bSectorCountReg); 4429 ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,regs->bSectorNumberReg); 4430 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,regs->bCylLowReg); 4431 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,regs->bCylHighReg); 4432 ScsiPortWritePortUchar(&baseIoAddress1->Command,regs->bCommandReg); 4433 4434 // 4435 // Wait for interrupt. 4436 // 4437 4438 return SRB_STATUS_PENDING; 4439 4440 } else if ((cmdInParameters.irDriveRegs.bFeaturesReg == ENABLE_SMART) || 4441 (cmdInParameters.irDriveRegs.bFeaturesReg == DISABLE_SMART) || 4442 (cmdInParameters.irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) || 4443 (cmdInParameters.irDriveRegs.bFeaturesReg == ENABLE_DISABLE_AUTOSAVE) || 4444 (cmdInParameters.irDriveRegs.bFeaturesReg == EXECUTE_OFFLINE_DIAGS) || 4445 (cmdInParameters.irDriveRegs.bFeaturesReg == SAVE_ATTRIBUTE_VALUES)) { 4446 4447 WaitOnBusy(baseIoAddress2,statusByte); 4448 4449 if (statusByte & IDE_STATUS_BUSY) { 4450 DebugPrint((1, 4451 "IdeSendSmartCommand: Returning BUSY status\n")); 4452 return SRB_STATUS_BUSY; 4453 } 4454 4455 // 4456 // Zero the output buffer as the input buffer info. has been saved off locally (the buffers are the same). 4457 // 4458 4459 for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) - 1); i++) { 4460 ((PUCHAR)cmdOutParameters)[i] = 0; 4461 } 4462 4463 // 4464 // Set data buffer pointer and indicate no data transfer. 4465 // 4466 4467 deviceExtension->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer; 4468 deviceExtension->WordsLeft = 0; 4469 4470 // 4471 // Indicate expecting an interrupt. 4472 // 4473 4474 deviceExtension->ExpectingInterrupt = TRUE; 4475 4476 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,(UCHAR)(((targetId & 0x1) << 4) | 0xA0)); 4477 ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,regs->bFeaturesReg); 4478 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,regs->bSectorCountReg); 4479 ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,regs->bSectorNumberReg); 4480 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,regs->bCylLowReg); 4481 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,regs->bCylHighReg); 4482 ScsiPortWritePortUchar(&baseIoAddress1->Command,regs->bCommandReg); 4483 4484 // 4485 // Wait for interrupt. 4486 // 4487 4488 return SRB_STATUS_PENDING; 4489 } 4490 } 4491 4492 return SRB_STATUS_INVALID_REQUEST; 4493 4494 } // end IdeSendSmartCommand() 4495 4496 4497 ULONG 4498 NTAPI 4499 IdeReadWrite( 4500 IN PVOID HwDeviceExtension, 4501 IN PSCSI_REQUEST_BLOCK Srb 4502 ) 4503 4504 /*++ 4505 4506 Routine Description: 4507 4508 This routine handles IDE read and writes. 4509 4510 Arguments: 4511 4512 HwDeviceExtension - HBA miniport driver's adapter data storage 4513 Srb - IO request packet 4514 4515 Return Value: 4516 4517 SRB status 4518 4519 --*/ 4520 4521 { 4522 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 4523 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 4524 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 4525 ULONG startingSector,i; 4526 ULONG wordCount; 4527 UCHAR statusByte,statusByte2; 4528 UCHAR cylinderHigh,cylinderLow,drvSelect,sectorNumber; 4529 4530 // 4531 // Select device 0 or 1. 4532 // 4533 4534 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 4535 (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0)); 4536 4537 WaitOnBusy(baseIoAddress2,statusByte2); 4538 4539 if (statusByte2 & IDE_STATUS_BUSY) { 4540 DebugPrint((1, 4541 "IdeReadWrite: Returning BUSY status\n")); 4542 return SRB_STATUS_BUSY; 4543 } 4544 4545 // 4546 // Set data buffer pointer and words left. 4547 // 4548 4549 deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer; 4550 deviceExtension->WordsLeft = Srb->DataTransferLength / 2; 4551 4552 // 4553 // Indicate expecting an interrupt. 4554 // 4555 4556 deviceExtension->ExpectingInterrupt = TRUE; 4557 4558 // 4559 // Set up sector count register. Round up to next block. 4560 // 4561 4562 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount, 4563 (UCHAR)((Srb->DataTransferLength + 0x1FF) / 0x200)); 4564 4565 // 4566 // Get starting sector number from CDB. 4567 // 4568 4569 startingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 | 4570 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 | 4571 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 | 4572 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24; 4573 4574 DebugPrint((2, 4575 "IdeReadWrite: Starting sector is %x, Number of bytes %x\n", 4576 startingSector, 4577 Srb->DataTransferLength)); 4578 4579 // 4580 // Set up sector number register. 4581 // 4582 4583 sectorNumber = (UCHAR)((startingSector % deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) + 1); 4584 ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,sectorNumber); 4585 4586 // 4587 // Set up cylinder low register. 4588 // 4589 4590 cylinderLow = (UCHAR)(startingSector / (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 4591 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)); 4592 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,cylinderLow); 4593 4594 // 4595 // Set up cylinder high register. 4596 // 4597 4598 cylinderHigh = (UCHAR)((startingSector / (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 4599 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)) >> 8); 4600 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,cylinderHigh); 4601 4602 // 4603 // Set up head and drive select register. 4604 // 4605 4606 drvSelect = (UCHAR)(((startingSector / deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) % 4607 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads) |((Srb->TargetId & 0x1) << 4) | 0xA0); 4608 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,drvSelect); 4609 4610 DebugPrint((2, 4611 "IdeReadWrite: Cylinder %x Head %x Sector %x\n", 4612 startingSector / 4613 (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 4614 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads), 4615 (startingSector / 4616 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) % 4617 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads, 4618 startingSector % 4619 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack + 1)); 4620 4621 // 4622 // Check if write request. 4623 // 4624 4625 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) { 4626 4627 // 4628 // Send read command. 4629 // 4630 4631 if (deviceExtension->MaximumBlockXfer[Srb->TargetId]) { 4632 ScsiPortWritePortUchar(&baseIoAddress1->Command, 4633 IDE_COMMAND_READ_MULTIPLE); 4634 4635 } else { 4636 ScsiPortWritePortUchar(&baseIoAddress1->Command, 4637 IDE_COMMAND_READ); 4638 } 4639 } else { 4640 4641 4642 // 4643 // Send write command. 4644 // 4645 4646 if (deviceExtension->MaximumBlockXfer[Srb->TargetId]) { 4647 wordCount = 256 * deviceExtension->MaximumBlockXfer[Srb->TargetId]; 4648 4649 if (deviceExtension->WordsLeft < wordCount) { 4650 4651 // 4652 // Transfer only words requested. 4653 // 4654 4655 wordCount = deviceExtension->WordsLeft; 4656 4657 } 4658 ScsiPortWritePortUchar(&baseIoAddress1->Command, 4659 IDE_COMMAND_WRITE_MULTIPLE); 4660 4661 } else { 4662 wordCount = 256; 4663 ScsiPortWritePortUchar(&baseIoAddress1->Command, 4664 IDE_COMMAND_WRITE); 4665 } 4666 4667 // 4668 // Wait for BSY and DRQ. 4669 // 4670 4671 WaitOnBaseBusy(baseIoAddress1,statusByte); 4672 4673 if (statusByte & IDE_STATUS_BUSY) { 4674 4675 DebugPrint((1, 4676 "IdeReadWrite 2: Returning BUSY status %x\n", 4677 statusByte)); 4678 return SRB_STATUS_BUSY; 4679 } 4680 4681 for (i = 0; i < 1000; i++) { 4682 GetBaseStatus(baseIoAddress1, statusByte); 4683 if (statusByte & IDE_STATUS_DRQ) { 4684 break; 4685 } 4686 ScsiPortStallExecution(200); 4687 4688 } 4689 4690 if (!(statusByte & IDE_STATUS_DRQ)) { 4691 4692 DebugPrint((1, 4693 "IdeReadWrite: DRQ never asserted (%x) original status (%x)\n", 4694 statusByte, 4695 statusByte2)); 4696 4697 deviceExtension->WordsLeft = 0; 4698 4699 // 4700 // Clear interrupt expecting flag. 4701 // 4702 4703 deviceExtension->ExpectingInterrupt = FALSE; 4704 4705 // 4706 // Clear current SRB. 4707 // 4708 4709 deviceExtension->CurrentSrb = NULL; 4710 4711 return SRB_STATUS_TIMEOUT; 4712 } 4713 4714 // 4715 // Write next 256 words. 4716 // 4717 4718 WriteBuffer(baseIoAddress1, 4719 deviceExtension->DataBuffer, 4720 wordCount); 4721 4722 // 4723 // Adjust buffer address and words left count. 4724 // 4725 4726 deviceExtension->WordsLeft -= wordCount; 4727 deviceExtension->DataBuffer += wordCount; 4728 4729 } 4730 4731 // 4732 // Wait for interrupt. 4733 // 4734 4735 return SRB_STATUS_PENDING; 4736 4737 } // end IdeReadWrite() 4738 4739 4740 4741 ULONG 4742 NTAPI 4743 IdeVerify( 4744 IN PVOID HwDeviceExtension, 4745 IN PSCSI_REQUEST_BLOCK Srb 4746 ) 4747 4748 /*++ 4749 4750 Routine Description: 4751 4752 This routine handles IDE Verify. 4753 4754 Arguments: 4755 4756 HwDeviceExtension - HBA miniport driver's adapter data storage 4757 Srb - IO request packet 4758 4759 Return Value: 4760 4761 SRB status 4762 4763 --*/ 4764 4765 { 4766 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 4767 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 4768 //PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 4769 ULONG startingSector; 4770 ULONG sectors; 4771 ULONG endSector; 4772 USHORT sectorCount; 4773 4774 // 4775 // Drive has these number sectors. 4776 // 4777 4778 sectors = deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 4779 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads * 4780 deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders; 4781 4782 DebugPrint((3, 4783 "IdeVerify: Total sectors %x\n", 4784 sectors)); 4785 4786 // 4787 // Get starting sector number from CDB. 4788 // 4789 4790 startingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 | 4791 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 | 4792 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 | 4793 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24; 4794 4795 DebugPrint((3, 4796 "IdeVerify: Starting sector %x. Number of blocks %x\n", 4797 startingSector, 4798 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb)); 4799 4800 sectorCount = (USHORT)(((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8 | 4801 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb ); 4802 endSector = startingSector + sectorCount; 4803 4804 DebugPrint((3, 4805 "IdeVerify: Ending sector %x\n", 4806 endSector)); 4807 4808 if (endSector > sectors) { 4809 4810 // 4811 // Too big, round down. 4812 // 4813 4814 DebugPrint((1, 4815 "IdeVerify: Truncating request to %x blocks\n", 4816 sectors - startingSector - 1)); 4817 4818 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount, 4819 (UCHAR)(sectors - startingSector - 1)); 4820 4821 } else { 4822 4823 // 4824 // Set up sector count register. Round up to next block. 4825 // 4826 4827 if (sectorCount > 0xFF) { 4828 sectorCount = (USHORT)0xFF; 4829 } 4830 4831 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,(UCHAR)sectorCount); 4832 } 4833 4834 // 4835 // Set data buffer pointer and words left. 4836 // 4837 4838 deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer; 4839 deviceExtension->WordsLeft = Srb->DataTransferLength / 2; 4840 4841 // 4842 // Indicate expecting an interrupt. 4843 // 4844 4845 deviceExtension->ExpectingInterrupt = TRUE; 4846 4847 // 4848 // Set up sector number register. 4849 // 4850 4851 ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber, 4852 (UCHAR)((startingSector % 4853 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) + 1)); 4854 4855 // 4856 // Set up cylinder low register. 4857 // 4858 4859 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow, 4860 (UCHAR)(startingSector / 4861 (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 4862 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads))); 4863 4864 // 4865 // Set up cylinder high register. 4866 // 4867 4868 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh, 4869 (UCHAR)((startingSector / 4870 (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 4871 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)) >> 8)); 4872 4873 // 4874 // Set up head and drive select register. 4875 // 4876 4877 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 4878 (UCHAR)(((startingSector / 4879 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) % 4880 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads) | 4881 ((Srb->TargetId & 0x1) << 4) | 0xA0)); 4882 4883 DebugPrint((2, 4884 "IdeVerify: Cylinder %x Head %x Sector %x\n", 4885 startingSector / 4886 (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 4887 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads), 4888 (startingSector / 4889 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) % 4890 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads, 4891 startingSector % 4892 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack + 1)); 4893 4894 4895 // 4896 // Send verify command. 4897 // 4898 4899 ScsiPortWritePortUchar(&baseIoAddress1->Command, 4900 IDE_COMMAND_VERIFY); 4901 4902 // 4903 // Wait for interrupt. 4904 // 4905 4906 return SRB_STATUS_PENDING; 4907 4908 } // end IdeVerify() 4909 4910 4911 VOID 4912 NTAPI 4913 Scsi2Atapi( 4914 IN PSCSI_REQUEST_BLOCK Srb 4915 ) 4916 4917 /*++ 4918 4919 Routine Description: 4920 4921 Convert SCSI packet command to Atapi packet command. 4922 4923 Arguments: 4924 4925 Srb - IO request packet 4926 4927 Return Value: 4928 4929 None 4930 4931 --*/ 4932 { 4933 // 4934 // Change the cdb length 4935 // 4936 4937 Srb->CdbLength = 12; 4938 4939 switch (Srb->Cdb[0]) { 4940 case SCSIOP_MODE_SENSE: { 4941 PMODE_SENSE_10 modeSense10 = (PMODE_SENSE_10)Srb->Cdb; 4942 UCHAR PageCode = ((PCDB)Srb->Cdb)->MODE_SENSE.PageCode; 4943 UCHAR Length = ((PCDB)Srb->Cdb)->MODE_SENSE.AllocationLength; 4944 4945 AtapiZeroMemory(Srb->Cdb,MAXIMUM_CDB_SIZE); 4946 4947 modeSense10->OperationCode = ATAPI_MODE_SENSE; 4948 modeSense10->PageCode = PageCode; 4949 modeSense10->ParameterListLengthMsb = 0; 4950 modeSense10->ParameterListLengthLsb = Length; 4951 break; 4952 } 4953 4954 case SCSIOP_MODE_SELECT: { 4955 PMODE_SELECT_10 modeSelect10 = (PMODE_SELECT_10)Srb->Cdb; 4956 UCHAR Length = ((PCDB)Srb->Cdb)->MODE_SELECT.ParameterListLength; 4957 4958 // 4959 // Zero the original cdb 4960 // 4961 4962 AtapiZeroMemory(Srb->Cdb,MAXIMUM_CDB_SIZE); 4963 4964 modeSelect10->OperationCode = ATAPI_MODE_SELECT; 4965 modeSelect10->PFBit = 1; 4966 modeSelect10->ParameterListLengthMsb = 0; 4967 modeSelect10->ParameterListLengthLsb = Length; 4968 break; 4969 } 4970 4971 case SCSIOP_FORMAT_UNIT: 4972 Srb->Cdb[0] = ATAPI_FORMAT_UNIT; 4973 break; 4974 } 4975 } 4976 4977 4978 4979 ULONG 4980 NTAPI 4981 AtapiSendCommand( 4982 IN PVOID HwDeviceExtension, 4983 IN PSCSI_REQUEST_BLOCK Srb 4984 ) 4985 4986 /*++ 4987 4988 Routine Description: 4989 4990 Send ATAPI packet command to device. 4991 4992 Arguments: 4993 4994 HwDeviceExtension - HBA miniport driver's adapter data storage 4995 Srb - IO request packet 4996 4997 Return Value: 4998 4999 5000 --*/ 5001 5002 { 5003 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 5004 PATAPI_REGISTERS_1 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 5005 PATAPI_REGISTERS_2 baseIoAddress2 = (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 5006 ULONG i; 5007 ULONG flags; 5008 UCHAR statusByte,byteCountLow,byteCountHigh; 5009 5010 // 5011 // We need to know how many platters our atapi cd-rom device might have. 5012 // Before anyone tries to send a srb to our target for the first time, 5013 // we must "secretly" send down a separate mechanism status srb in order to 5014 // initialize our device extension changer data. That's how we know how 5015 // many platters our target has. 5016 // 5017 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_CHANGER_INITED) && 5018 !deviceExtension->OriginalSrb) { 5019 5020 ULONG srbStatus; 5021 5022 // 5023 // Set this flag now. If the device hangs on the mech. status 5024 // command, we will not have the change to set it. 5025 // 5026 deviceExtension->DeviceFlags[Srb->TargetId] |= DFLAGS_CHANGER_INITED; 5027 5028 deviceExtension->MechStatusRetryCount = 3; 5029 deviceExtension->CurrentSrb = BuildMechanismStatusSrb ( 5030 HwDeviceExtension, 5031 Srb->PathId, 5032 Srb->TargetId); 5033 deviceExtension->OriginalSrb = Srb; 5034 5035 srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb); 5036 if (srbStatus == SRB_STATUS_PENDING) { 5037 return srbStatus; 5038 } else { 5039 deviceExtension->CurrentSrb = deviceExtension->OriginalSrb; 5040 deviceExtension->OriginalSrb = NULL; 5041 AtapiHwInitializeChanger (HwDeviceExtension, 5042 Srb->TargetId, 5043 (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL); 5044 // fall out 5045 } 5046 } 5047 5048 DebugPrint((2, 5049 "AtapiSendCommand: Command %x to TargetId %d lun %d\n", 5050 Srb->Cdb[0], 5051 Srb->TargetId, 5052 Srb->Lun)); 5053 5054 // 5055 // Make sure command is to ATAPI device. 5056 // 5057 5058 flags = deviceExtension->DeviceFlags[Srb->TargetId]; 5059 if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) { 5060 if ((Srb->Lun) > (deviceExtension->DiscsPresent[Srb->TargetId] - 1)) { 5061 5062 // 5063 // Indicate no device found at this address. 5064 // 5065 5066 return SRB_STATUS_SELECTION_TIMEOUT; 5067 } 5068 } else if (Srb->Lun > 0) { 5069 return SRB_STATUS_SELECTION_TIMEOUT; 5070 } 5071 5072 if (!(flags & DFLAGS_ATAPI_DEVICE)) { 5073 return SRB_STATUS_SELECTION_TIMEOUT; 5074 } 5075 5076 // 5077 // Select device 0 or 1. 5078 // 5079 5080 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 5081 (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0)); 5082 5083 // 5084 // Verify that controller is ready for next command. 5085 // 5086 5087 GetStatus(baseIoAddress2,statusByte); 5088 5089 DebugPrint((2, 5090 "AtapiSendCommand: Entered with status %x\n", 5091 statusByte)); 5092 5093 if (statusByte & IDE_STATUS_BUSY) { 5094 DebugPrint((1, 5095 "AtapiSendCommand: Device busy (%x)\n", 5096 statusByte)); 5097 return SRB_STATUS_BUSY; 5098 5099 } 5100 5101 if (statusByte & IDE_STATUS_ERROR) { 5102 if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) { 5103 5104 DebugPrint((1, 5105 "AtapiSendCommand: Error on entry: (%x)\n", 5106 statusByte)); 5107 // 5108 // Read the error reg. to clear it and fail this request. 5109 // 5110 5111 return MapError(deviceExtension, 5112 Srb); 5113 } 5114 } 5115 5116 // 5117 // If a tape drive has doesn't have DSC set and the last command is restrictive, don't send 5118 // the next command. See discussion of Restrictive Delayed Process commands in QIC-157. 5119 // 5120 5121 if ((!(statusByte & IDE_STATUS_DSC)) && 5122 (flags & DFLAGS_TAPE_DEVICE) && deviceExtension->RDP) { 5123 ScsiPortStallExecution(1000); 5124 DebugPrint((2,"AtapiSendCommand: DSC not set. %x\n",statusByte)); 5125 return SRB_STATUS_BUSY; 5126 } 5127 5128 if (IS_RDP(Srb->Cdb[0])) { 5129 5130 deviceExtension->RDP = TRUE; 5131 5132 DebugPrint((3, 5133 "AtapiSendCommand: %x mapped as DSC restrictive\n", 5134 Srb->Cdb[0])); 5135 5136 } else { 5137 5138 deviceExtension->RDP = FALSE; 5139 } 5140 5141 if (statusByte & IDE_STATUS_DRQ) { 5142 5143 DebugPrint((1, 5144 "AtapiSendCommand: Entered with status (%x). Attempting to recover.\n", 5145 statusByte)); 5146 // 5147 // Try to drain the data that one preliminary device thinks that it has 5148 // to transfer. Hopefully this random assertion of DRQ will not be present 5149 // in production devices. 5150 // 5151 5152 for (i = 0; i < 0x10000; i++) { 5153 5154 GetStatus(baseIoAddress2, statusByte); 5155 5156 if (statusByte & IDE_STATUS_DRQ) { 5157 5158 ScsiPortReadPortUshort(&baseIoAddress1->Data); 5159 5160 } else { 5161 5162 break; 5163 } 5164 } 5165 5166 if (i == 0x10000) { 5167 5168 DebugPrint((1, 5169 "AtapiSendCommand: DRQ still asserted.Status (%x)\n", 5170 statusByte)); 5171 5172 AtapiSoftReset(baseIoAddress1,Srb->TargetId); 5173 5174 DebugPrint((1, 5175 "AtapiSendCommand: Issued soft reset to Atapi device. \n")); 5176 5177 // 5178 // Re-initialize Atapi device. 5179 // 5180 5181 IssueIdentify(HwDeviceExtension, 5182 (Srb->TargetId & 0x1), 5183 (Srb->TargetId >> 1), 5184 IDE_COMMAND_ATAPI_IDENTIFY); 5185 5186 // 5187 // Inform the port driver that the bus has been reset. 5188 // 5189 5190 ScsiPortNotification(ResetDetected, HwDeviceExtension, 0); 5191 5192 // 5193 // Clean up device extension fields that AtapiStartIo won't. 5194 // 5195 5196 deviceExtension->ExpectingInterrupt = FALSE; 5197 deviceExtension->RDP = FALSE; 5198 5199 return SRB_STATUS_BUS_RESET; 5200 5201 } 5202 } 5203 5204 if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) { 5205 5206 // 5207 // As the cdrom driver sets the LUN field in the cdb, it must be removed. 5208 // 5209 5210 Srb->Cdb[1] &= ~0xE0; 5211 5212 if ((Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY) && (flags & DFLAGS_SANYO_ATAPI_CHANGER)) { 5213 5214 // 5215 // Torisan changer. TUR's are overloaded to be platter switches. 5216 // 5217 5218 Srb->Cdb[7] = Srb->Lun; 5219 5220 } 5221 } 5222 5223 // 5224 // Convert SCSI to ATAPI commands if needed 5225 // 5226 5227 switch (Srb->Cdb[0]) { 5228 case SCSIOP_MODE_SENSE: 5229 case SCSIOP_MODE_SELECT: 5230 case SCSIOP_FORMAT_UNIT: 5231 if (!(flags & DFLAGS_TAPE_DEVICE)) { 5232 Scsi2Atapi(Srb); 5233 } 5234 5235 break; 5236 } 5237 5238 // 5239 // Set data buffer pointer and words left. 5240 // 5241 5242 deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer; 5243 deviceExtension->WordsLeft = Srb->DataTransferLength / 2; 5244 5245 WaitOnBusy(baseIoAddress2,statusByte); 5246 5247 // 5248 // Write transfer byte count to registers. 5249 // 5250 5251 byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF); 5252 byteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8); 5253 5254 if (Srb->DataTransferLength >= 0x10000) { 5255 byteCountLow = byteCountHigh = 0xFF; 5256 } 5257 5258 ScsiPortWritePortUchar(&baseIoAddress1->ByteCountLow,byteCountLow); 5259 ScsiPortWritePortUchar(&baseIoAddress1->ByteCountHigh, byteCountHigh); 5260 5261 ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,0); 5262 5263 5264 if (flags & DFLAGS_INT_DRQ) { 5265 5266 // 5267 // This device interrupts when ready to receive the packet. 5268 // 5269 // Write ATAPI packet command. 5270 // 5271 5272 ScsiPortWritePortUchar(&baseIoAddress1->Command, 5273 IDE_COMMAND_ATAPI_PACKET); 5274 5275 DebugPrint((3, 5276 "AtapiSendCommand: Wait for int. to send packet. Status (%x)\n", 5277 statusByte)); 5278 5279 deviceExtension->ExpectingInterrupt = TRUE; 5280 5281 return SRB_STATUS_PENDING; 5282 5283 } else { 5284 5285 // 5286 // Write ATAPI packet command. 5287 // 5288 5289 ScsiPortWritePortUchar(&baseIoAddress1->Command, 5290 IDE_COMMAND_ATAPI_PACKET); 5291 5292 // 5293 // Wait for DRQ. 5294 // 5295 5296 WaitOnBusy(baseIoAddress2, statusByte); 5297 WaitForDrq(baseIoAddress2, statusByte); 5298 5299 if (!(statusByte & IDE_STATUS_DRQ)) { 5300 5301 DebugPrint((1, 5302 "AtapiSendCommand: DRQ never asserted (%x)\n", 5303 statusByte)); 5304 return SRB_STATUS_ERROR; 5305 } 5306 } 5307 5308 // 5309 // Need to read status register. 5310 // 5311 5312 GetBaseStatus(baseIoAddress1, statusByte); 5313 5314 // 5315 // Send CDB to device. 5316 // 5317 5318 WaitOnBusy(baseIoAddress2,statusByte); 5319 5320 WriteBuffer(baseIoAddress1, 5321 (PUSHORT)Srb->Cdb, 5322 6); 5323 5324 // 5325 // Indicate expecting an interrupt and wait for it. 5326 // 5327 5328 deviceExtension->ExpectingInterrupt = TRUE; 5329 5330 return SRB_STATUS_PENDING; 5331 5332 } // end AtapiSendCommand() 5333 5334 ULONG 5335 NTAPI 5336 IdeSendCommand( 5337 IN PVOID HwDeviceExtension, 5338 IN PSCSI_REQUEST_BLOCK Srb 5339 ) 5340 5341 /*++ 5342 5343 Routine Description: 5344 5345 Program ATA registers for IDE disk transfer. 5346 5347 Arguments: 5348 5349 HwDeviceExtension - ATAPI driver storage. 5350 Srb - System request block. 5351 5352 Return Value: 5353 5354 SRB status (pending if all goes well). 5355 5356 --*/ 5357 5358 { 5359 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 5360 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 5361 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 5362 PCDB cdb; 5363 5364 UCHAR statusByte,errorByte; 5365 ULONG status; 5366 ULONG i; 5367 PMODE_PARAMETER_HEADER modeData; 5368 5369 DebugPrint((2, 5370 "IdeSendCommand: Command %x to device %d\n", 5371 Srb->Cdb[0], 5372 Srb->TargetId)); 5373 5374 5375 5376 switch (Srb->Cdb[0]) { 5377 case SCSIOP_INQUIRY: 5378 5379 // 5380 // Filter out all TIDs but 0 and 1 since this is an IDE interface 5381 // which support up to two devices. 5382 // 5383 5384 if ((Srb->Lun != 0) || 5385 (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT))) { 5386 5387 // 5388 // Indicate no device found at this address. 5389 // 5390 5391 status = SRB_STATUS_SELECTION_TIMEOUT; 5392 break; 5393 5394 } else { 5395 5396 PINQUIRYDATA inquiryData = Srb->DataBuffer; 5397 PIDENTIFY_DATA2 identifyData = &deviceExtension->IdentifyData[Srb->TargetId]; 5398 5399 // 5400 // Zero INQUIRY data structure. 5401 // 5402 5403 for (i = 0; i < Srb->DataTransferLength; i++) { 5404 ((PUCHAR)Srb->DataBuffer)[i] = 0; 5405 } 5406 5407 // 5408 // Standard IDE interface only supports disks. 5409 // 5410 5411 inquiryData->DeviceType = DIRECT_ACCESS_DEVICE; 5412 5413 // 5414 // Set the removable bit, if applicable. 5415 // 5416 5417 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_REMOVABLE_DRIVE) { 5418 inquiryData->RemovableMedia = 1; 5419 } 5420 5421 // 5422 // Fill in vendor identification fields. 5423 // 5424 5425 for (i = 0; i < 8; i += 2) { 5426 inquiryData->VendorId[i] = 5427 ((PUCHAR)identifyData->ModelNumber)[i + 1]; 5428 inquiryData->VendorId[i+1] = 5429 ((PUCHAR)identifyData->ModelNumber)[i]; 5430 } 5431 5432 for (i = 0; i < 12; i += 2) { 5433 inquiryData->ProductId[i] = 5434 ((PUCHAR)identifyData->ModelNumber)[i + 8 + 1]; 5435 inquiryData->ProductId[i+1] = 5436 ((PUCHAR)identifyData->ModelNumber)[i + 8]; 5437 } 5438 5439 // 5440 // Initialize unused portion of product id. 5441 // 5442 5443 for (i = 0; i < 4; i++) { 5444 inquiryData->ProductId[12+i] = ' '; 5445 } 5446 5447 // 5448 // Move firmware revision from IDENTIFY data to 5449 // product revision in INQUIRY data. 5450 // 5451 5452 for (i = 0; i < 4; i += 2) { 5453 inquiryData->ProductRevisionLevel[i] = 5454 ((PUCHAR)identifyData->FirmwareRevision)[i+1]; 5455 inquiryData->ProductRevisionLevel[i+1] = 5456 ((PUCHAR)identifyData->FirmwareRevision)[i]; 5457 } 5458 5459 status = SRB_STATUS_SUCCESS; 5460 } 5461 5462 break; 5463 5464 case SCSIOP_MODE_SENSE: 5465 5466 // 5467 // This is used to determine of the media is write-protected. 5468 // Since IDE does not support mode sense then we will modify just the portion we need 5469 // so the higher level driver can determine if media is protected. 5470 // 5471 5472 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) { 5473 5474 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 5475 (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0)); 5476 ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_GET_MEDIA_STATUS); 5477 WaitOnBusy(baseIoAddress2,statusByte); 5478 5479 if (!(statusByte & IDE_STATUS_ERROR)){ 5480 5481 // 5482 // no error occured return success, media is not protected 5483 // 5484 5485 deviceExtension->ExpectingInterrupt = FALSE; 5486 5487 } else { 5488 5489 // 5490 // error occured, handle it locally, clear interrupt 5491 // 5492 5493 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 5494 5495 GetBaseStatus(baseIoAddress1, statusByte); 5496 deviceExtension->ExpectingInterrupt = FALSE; 5497 5498 if (errorByte & IDE_ERROR_DATA_ERROR) { 5499 5500 // 5501 //media is write-protected, set bit in mode sense buffer 5502 // 5503 5504 modeData = (PMODE_PARAMETER_HEADER)Srb->DataBuffer; 5505 5506 Srb->DataTransferLength = sizeof(MODE_PARAMETER_HEADER); 5507 modeData->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT; 5508 } 5509 } 5510 status = SRB_STATUS_SUCCESS; 5511 } else { 5512 status = SRB_STATUS_INVALID_REQUEST; 5513 } 5514 break; 5515 5516 case SCSIOP_TEST_UNIT_READY: 5517 5518 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) { 5519 5520 // 5521 // Select device 0 or 1. 5522 // 5523 5524 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 5525 (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0)); 5526 ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_GET_MEDIA_STATUS); 5527 5528 // 5529 // Wait for busy. If media has not changed, return success 5530 // 5531 5532 WaitOnBusy(baseIoAddress2,statusByte); 5533 5534 if (!(statusByte & IDE_STATUS_ERROR)){ 5535 deviceExtension->ExpectingInterrupt = FALSE; 5536 status = SRB_STATUS_SUCCESS; 5537 } else { 5538 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 5539 if (errorByte == IDE_ERROR_DATA_ERROR){ 5540 5541 // 5542 // Special case: If current media is write-protected, 5543 // the 0xDA command will always fail since the write-protect bit 5544 // is sticky,so we can ignore this error 5545 // 5546 5547 GetBaseStatus(baseIoAddress1, statusByte); 5548 deviceExtension->ExpectingInterrupt = FALSE; 5549 status = SRB_STATUS_SUCCESS; 5550 5551 } else { 5552 5553 // 5554 // Request sense buffer to be build 5555 // 5556 deviceExtension->ExpectingInterrupt = TRUE; 5557 status = SRB_STATUS_PENDING; 5558 } 5559 } 5560 } else { 5561 status = SRB_STATUS_SUCCESS; 5562 } 5563 5564 break; 5565 5566 case SCSIOP_READ_CAPACITY: 5567 5568 // 5569 // Claim 512 byte blocks (big-endian). 5570 // 5571 5572 ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000; 5573 5574 // 5575 // Calculate last sector. 5576 // 5577 5578 5579 i = (deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads * 5580 deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders * 5581 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) - 1; 5582 5583 ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress = 5584 (((PUCHAR)&i)[0] << 24) | (((PUCHAR)&i)[1] << 16) | 5585 (((PUCHAR)&i)[2] << 8) | ((PUCHAR)&i)[3]; 5586 5587 DebugPrint((1, 5588 "IDE disk %x - #sectors %x, #heads %x, #cylinders %x\n", 5589 Srb->TargetId, 5590 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack, 5591 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads, 5592 deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders)); 5593 5594 5595 status = SRB_STATUS_SUCCESS; 5596 break; 5597 5598 case SCSIOP_VERIFY: 5599 status = IdeVerify(HwDeviceExtension,Srb); 5600 5601 break; 5602 5603 case SCSIOP_READ: 5604 case SCSIOP_WRITE: 5605 5606 status = IdeReadWrite(HwDeviceExtension, 5607 Srb); 5608 break; 5609 5610 case SCSIOP_START_STOP_UNIT: 5611 5612 // 5613 //Determine what type of operation we should perform 5614 // 5615 cdb = (PCDB)Srb->Cdb; 5616 5617 if (cdb->START_STOP.LoadEject == 1){ 5618 5619 // 5620 // Eject media, 5621 // first select device 0 or 1. 5622 // 5623 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 5624 (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0)); 5625 ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_MEDIA_EJECT); 5626 } 5627 status = SRB_STATUS_SUCCESS; 5628 break; 5629 5630 case SCSIOP_REQUEST_SENSE: 5631 // this function makes sense buffers to report the results 5632 // of the original GET_MEDIA_STATUS command 5633 5634 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) { 5635 status = IdeBuildSenseBuffer(HwDeviceExtension,Srb); 5636 break; 5637 } 5638 5639 default: 5640 5641 DebugPrint((1, 5642 "IdeSendCommand: Unsupported command %x\n", 5643 Srb->Cdb[0])); 5644 5645 status = SRB_STATUS_INVALID_REQUEST; 5646 5647 } // end switch 5648 5649 return status; 5650 5651 } // end IdeSendCommand() 5652 5653 VOID 5654 NTAPI 5655 IdeMediaStatus( 5656 BOOLEAN EnableMSN, 5657 IN PVOID HwDeviceExtension, 5658 ULONG Channel 5659 ) 5660 /*++ 5661 5662 Routine Description: 5663 5664 Enables disables media status notification 5665 5666 Arguments: 5667 5668 HwDeviceExtension - ATAPI driver storage. 5669 5670 --*/ 5671 5672 { 5673 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 5674 PIDE_REGISTERS_1 baseIoAddress = deviceExtension->BaseIoAddress1[Channel >> 1]; 5675 UCHAR statusByte,errorByte; 5676 5677 5678 if (EnableMSN != FALSE){ 5679 5680 // 5681 // If supported enable Media Status Notification support 5682 // 5683 5684 if ((deviceExtension->DeviceFlags[Channel] & DFLAGS_REMOVABLE_DRIVE)) { 5685 5686 // 5687 // enable 5688 // 5689 ScsiPortWritePortUchar((PUCHAR)baseIoAddress + 1,(UCHAR) (0x95)); 5690 ScsiPortWritePortUchar(&baseIoAddress->Command, 5691 IDE_COMMAND_ENABLE_MEDIA_STATUS); 5692 5693 WaitOnBaseBusy(baseIoAddress,statusByte); 5694 5695 if (statusByte & IDE_STATUS_ERROR) { 5696 // 5697 // Read the error register. 5698 // 5699 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress + 1); 5700 5701 DebugPrint((1, 5702 "IdeMediaStatus: Error enabling media status. Status %x, error byte %x\n", 5703 statusByte, 5704 errorByte)); 5705 } else { 5706 deviceExtension->DeviceFlags[Channel] |= DFLAGS_MEDIA_STATUS_ENABLED; 5707 DebugPrint((1,"IdeMediaStatus: Media Status Notification Supported\n")); 5708 deviceExtension->ReturningMediaStatus = 0; 5709 5710 } 5711 5712 } 5713 } else { // end if EnableMSN != FALSE 5714 5715 // 5716 // disable if previously enabled 5717 // 5718 if ((deviceExtension->DeviceFlags[Channel] & DFLAGS_MEDIA_STATUS_ENABLED)) { 5719 5720 ScsiPortWritePortUchar((PUCHAR)baseIoAddress + 1,(UCHAR) (0x31)); 5721 ScsiPortWritePortUchar(&baseIoAddress->Command, 5722 IDE_COMMAND_ENABLE_MEDIA_STATUS); 5723 5724 WaitOnBaseBusy(baseIoAddress,statusByte); 5725 deviceExtension->DeviceFlags[Channel] &= ~DFLAGS_MEDIA_STATUS_ENABLED; 5726 } 5727 5728 5729 } 5730 5731 5732 5733 } 5734 5735 ULONG 5736 NTAPI 5737 IdeBuildSenseBuffer( 5738 IN PVOID HwDeviceExtension, 5739 IN PSCSI_REQUEST_BLOCK Srb 5740 ) 5741 5742 /*++ 5743 5744 Routine Description: 5745 5746 Builts an artificial sense buffer to report the results of a GET_MEDIA_STATUS 5747 command. This function is invoked to satisfy the SCSIOP_REQUEST_SENSE. 5748 Arguments: 5749 5750 HwDeviceExtension - ATAPI driver storage. 5751 Srb - System request block. 5752 5753 Return Value: 5754 5755 SRB status (ALWAYS SUCCESS). 5756 5757 --*/ 5758 5759 { 5760 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 5761 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->DataBuffer; 5762 5763 5764 if (senseBuffer){ 5765 5766 5767 if(deviceExtension->ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE) { 5768 5769 senseBuffer->ErrorCode = 0x70; 5770 senseBuffer->Valid = 1; 5771 senseBuffer->AdditionalSenseLength = 0xb; 5772 senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; 5773 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED; 5774 senseBuffer->AdditionalSenseCodeQualifier = 0; 5775 } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE_REQ) { 5776 5777 senseBuffer->ErrorCode = 0x70; 5778 senseBuffer->Valid = 1; 5779 senseBuffer->AdditionalSenseLength = 0xb; 5780 senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; 5781 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED; 5782 senseBuffer->AdditionalSenseCodeQualifier = 0; 5783 } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_END_OF_MEDIA) { 5784 5785 senseBuffer->ErrorCode = 0x70; 5786 senseBuffer->Valid = 1; 5787 senseBuffer->AdditionalSenseLength = 0xb; 5788 senseBuffer->SenseKey = SCSI_SENSE_NOT_READY; 5789 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE; 5790 senseBuffer->AdditionalSenseCodeQualifier = 0; 5791 } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_DATA_ERROR) { 5792 5793 senseBuffer->ErrorCode = 0x70; 5794 senseBuffer->Valid = 1; 5795 senseBuffer->AdditionalSenseLength = 0xb; 5796 senseBuffer->SenseKey = SCSI_SENSE_DATA_PROTECT; 5797 senseBuffer->AdditionalSenseCode = 0; 5798 senseBuffer->AdditionalSenseCodeQualifier = 0; 5799 } 5800 return SRB_STATUS_SUCCESS; 5801 } 5802 return SRB_STATUS_ERROR; 5803 5804 }// End of IdeBuildSenseBuffer 5805 5806 5807 5808 5809 BOOLEAN 5810 NTAPI 5811 AtapiStartIo( 5812 IN PVOID HwDeviceExtension, 5813 IN PSCSI_REQUEST_BLOCK Srb 5814 ) 5815 5816 /*++ 5817 5818 Routine Description: 5819 5820 This routine is called from the SCSI port driver synchronized 5821 with the kernel to start an IO request. 5822 5823 Arguments: 5824 5825 HwDeviceExtension - HBA miniport driver's adapter data storage 5826 Srb - IO request packet 5827 5828 Return Value: 5829 5830 TRUE 5831 5832 --*/ 5833 5834 { 5835 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 5836 ULONG status; 5837 5838 // 5839 // Determine which function. 5840 // 5841 5842 switch (Srb->Function) { 5843 5844 case SRB_FUNCTION_EXECUTE_SCSI: 5845 5846 // 5847 // Sanity check. Only one request can be outstanding on a 5848 // controller. 5849 // 5850 5851 if (deviceExtension->CurrentSrb) { 5852 5853 DebugPrint((1, 5854 "AtapiStartIo: Already have a request!\n")); 5855 Srb->SrbStatus = SRB_STATUS_BUSY; 5856 ScsiPortNotification(RequestComplete, 5857 deviceExtension, 5858 Srb); 5859 return FALSE; 5860 } 5861 5862 // 5863 // Indicate that a request is active on the controller. 5864 // 5865 5866 deviceExtension->CurrentSrb = Srb; 5867 5868 // 5869 // Send command to device. 5870 // 5871 5872 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 5873 5874 status = AtapiSendCommand(HwDeviceExtension, 5875 Srb); 5876 5877 } else if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) { 5878 5879 status = IdeSendCommand(HwDeviceExtension, 5880 Srb); 5881 } else { 5882 5883 status = SRB_STATUS_SELECTION_TIMEOUT; 5884 } 5885 5886 break; 5887 5888 case SRB_FUNCTION_ABORT_COMMAND: 5889 5890 // 5891 // Verify that SRB to abort is still outstanding. 5892 // 5893 5894 if (!deviceExtension->CurrentSrb) { 5895 5896 DebugPrint((1, "AtapiStartIo: SRB to abort already completed\n")); 5897 5898 // 5899 // Complete abort SRB. 5900 // 5901 5902 status = SRB_STATUS_ABORT_FAILED; 5903 5904 break; 5905 } 5906 5907 // 5908 // Abort function indicates that a request timed out. 5909 // Call reset routine. Card will only be reset if 5910 // status indicates something is wrong. 5911 // Fall through to reset code. 5912 // 5913 5914 case SRB_FUNCTION_RESET_BUS: 5915 5916 // 5917 // Reset Atapi and SCSI bus. 5918 // 5919 5920 DebugPrint((1, "AtapiStartIo: Reset bus request received\n")); 5921 5922 if (!AtapiResetController(deviceExtension, 5923 Srb->PathId)) { 5924 5925 DebugPrint((1,"AtapiStartIo: Reset bus failed\n")); 5926 5927 // 5928 // Log reset failure. 5929 // 5930 5931 ScsiPortLogError( 5932 HwDeviceExtension, 5933 NULL, 5934 0, 5935 0, 5936 0, 5937 SP_INTERNAL_ADAPTER_ERROR, 5938 5 << 8 5939 ); 5940 5941 status = SRB_STATUS_ERROR; 5942 5943 } else { 5944 5945 status = SRB_STATUS_SUCCESS; 5946 } 5947 5948 break; 5949 5950 case SRB_FUNCTION_IO_CONTROL: 5951 5952 if (deviceExtension->CurrentSrb) { 5953 5954 DebugPrint((1, 5955 "AtapiStartIo: Already have a request!\n")); 5956 Srb->SrbStatus = SRB_STATUS_BUSY; 5957 ScsiPortNotification(RequestComplete, 5958 deviceExtension, 5959 Srb); 5960 return FALSE; 5961 } 5962 5963 // 5964 // Indicate that a request is active on the controller. 5965 // 5966 5967 deviceExtension->CurrentSrb = Srb; 5968 5969 if (AtapiStringCmp( (PCHAR)((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature,"SCSIDISK",strlen("SCSIDISK"))) { 5970 5971 DebugPrint((1, 5972 "AtapiStartIo: IoControl signature incorrect. Send %s, expected %s\n", 5973 ((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature, 5974 "SCSIDISK")); 5975 5976 status = SRB_STATUS_INVALID_REQUEST; 5977 break; 5978 } 5979 5980 switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) { 5981 5982 case IOCTL_SCSI_MINIPORT_SMART_VERSION: { 5983 5984 PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 5985 UCHAR deviceNumber; 5986 5987 // 5988 // Version and revision per SMART 1.03 5989 // 5990 5991 versionParameters->bVersion = 1; 5992 versionParameters->bRevision = 1; 5993 versionParameters->bReserved = 0; 5994 5995 // 5996 // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands. 5997 // 5998 5999 versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD); 6000 6001 // 6002 // This is done because of how the IOCTL_SCSI_MINIPORT 6003 // determines 'targetid's'. Disk.sys places the real target id value 6004 // in the DeviceMap field. Once we do some parameter checking, the value passed 6005 // back to the application will be determined. 6006 // 6007 6008 deviceNumber = versionParameters->bIDEDeviceMap; 6009 6010 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) || 6011 (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE)) { 6012 6013 status = SRB_STATUS_SELECTION_TIMEOUT; 6014 break; 6015 } 6016 6017 // 6018 // NOTE: This will only set the bit 6019 // corresponding to this drive's target id. 6020 // The bit mask is as follows: 6021 // 6022 // Sec Pri 6023 // S M S M 6024 // 3 2 1 0 6025 // 6026 6027 if (deviceExtension->NumberChannels == 1) { 6028 if (deviceExtension->PrimaryAddress) { 6029 deviceNumber = 1 << Srb->TargetId; 6030 } else { 6031 deviceNumber = 4 << Srb->TargetId; 6032 } 6033 } else { 6034 deviceNumber = 1 << Srb->TargetId; 6035 } 6036 6037 versionParameters->bIDEDeviceMap = deviceNumber; 6038 6039 status = SRB_STATUS_SUCCESS; 6040 break; 6041 } 6042 6043 case IOCTL_SCSI_MINIPORT_IDENTIFY: { 6044 6045 PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 6046 SENDCMDINPARAMS cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 6047 ULONG i; 6048 UCHAR targetId; 6049 6050 6051 if (cmdInParameters.irDriveRegs.bCommandReg == ID_CMD) { 6052 6053 // 6054 // Extract the target. 6055 // 6056 6057 targetId = cmdInParameters.bDriveNumber; 6058 6059 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) || 6060 (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE)) { 6061 6062 status = SRB_STATUS_SELECTION_TIMEOUT; 6063 break; 6064 } 6065 6066 // 6067 // Zero the output buffer 6068 // 6069 6070 for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1); i++) { 6071 ((PUCHAR)cmdOutParameters)[i] = 0; 6072 } 6073 6074 // 6075 // Build status block. 6076 // 6077 6078 cmdOutParameters->cBufferSize = IDENTIFY_BUFFER_SIZE; 6079 cmdOutParameters->DriverStatus.bDriverError = 0; 6080 cmdOutParameters->DriverStatus.bIDEError = 0; 6081 6082 // 6083 // Extract the identify data from the device extension. 6084 // 6085 6086 ScsiPortMoveMemory (cmdOutParameters->bBuffer, &deviceExtension->IdentifyData[targetId], IDENTIFY_DATA_SIZE); 6087 6088 status = SRB_STATUS_SUCCESS; 6089 6090 6091 } else { 6092 status = SRB_STATUS_INVALID_REQUEST; 6093 } 6094 break; 6095 } 6096 6097 case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS: 6098 case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS: 6099 case IOCTL_SCSI_MINIPORT_ENABLE_SMART: 6100 case IOCTL_SCSI_MINIPORT_DISABLE_SMART: 6101 case IOCTL_SCSI_MINIPORT_RETURN_STATUS: 6102 case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE: 6103 case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES: 6104 case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS: 6105 6106 status = IdeSendSmartCommand(HwDeviceExtension,Srb); 6107 break; 6108 6109 default : 6110 6111 status = SRB_STATUS_INVALID_REQUEST; 6112 break; 6113 6114 } 6115 6116 break; 6117 6118 default: 6119 6120 // 6121 // Indicate unsupported command. 6122 // 6123 6124 status = SRB_STATUS_INVALID_REQUEST; 6125 6126 break; 6127 6128 } // end switch 6129 6130 // 6131 // Check if command complete. 6132 // 6133 6134 if (status != SRB_STATUS_PENDING) { 6135 6136 DebugPrint((2, 6137 "AtapiStartIo: Srb %x complete with status %x\n", 6138 Srb, 6139 status)); 6140 6141 // 6142 // Clear current SRB. 6143 // 6144 6145 deviceExtension->CurrentSrb = NULL; 6146 6147 // 6148 // Set status in SRB. 6149 // 6150 6151 Srb->SrbStatus = (UCHAR)status; 6152 6153 // 6154 // Indicate command complete. 6155 // 6156 6157 ScsiPortNotification(RequestComplete, 6158 deviceExtension, 6159 Srb); 6160 6161 // 6162 // Indicate ready for next request. 6163 // 6164 6165 ScsiPortNotification(NextRequest, 6166 deviceExtension, 6167 NULL); 6168 } 6169 6170 return TRUE; 6171 6172 } // end AtapiStartIo() 6173 6174 6175 ULONG 6176 NTAPI 6177 DriverEntry( 6178 IN PVOID DriverObject, 6179 IN PVOID Argument2 6180 ) 6181 6182 /*++ 6183 6184 Routine Description: 6185 6186 Installable driver initialization entry point for system. 6187 6188 Arguments: 6189 6190 Driver Object 6191 6192 Return Value: 6193 6194 Status from ScsiPortInitialize() 6195 6196 --*/ 6197 6198 { 6199 HW_INITIALIZATION_DATA hwInitializationData; 6200 ULONG adapterCount; 6201 ULONG i; 6202 ULONG statusToReturn, newStatus; 6203 6204 DebugPrint((1,"\n\nATAPI IDE MiniPort Driver\n")); 6205 6206 statusToReturn = 0xffffffff; 6207 6208 // 6209 // Zero out structure. 6210 // 6211 6212 AtapiZeroMemory(((PUCHAR)&hwInitializationData), sizeof(HW_INITIALIZATION_DATA)); 6213 6214 // 6215 // Set size of hwInitializationData. 6216 // 6217 6218 hwInitializationData.HwInitializationDataSize = 6219 sizeof(HW_INITIALIZATION_DATA); 6220 6221 // 6222 // Set entry points. 6223 // 6224 6225 hwInitializationData.HwInitialize = AtapiHwInitialize; 6226 hwInitializationData.HwResetBus = AtapiResetController; 6227 hwInitializationData.HwStartIo = AtapiStartIo; 6228 hwInitializationData.HwInterrupt = AtapiInterrupt; 6229 6230 // 6231 // Specify size of extensions. 6232 // 6233 6234 hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION); 6235 hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION); 6236 6237 // 6238 // Indicate PIO device. 6239 // 6240 6241 hwInitializationData.MapBuffers = TRUE; 6242 6243 // 6244 // Native Mode Devices 6245 // 6246 for (i=0; i <NUM_NATIVE_MODE_ADAPTERS; i++) { 6247 hwInitializationData.HwFindAdapter = AtapiFindNativeModeController; 6248 hwInitializationData.NumberOfAccessRanges = 4; 6249 hwInitializationData.AdapterInterfaceType = PCIBus; 6250 6251 hwInitializationData.VendorId = NativeModeAdapters[i].VendorId; 6252 hwInitializationData.VendorIdLength = (USHORT) NativeModeAdapters[i].VendorIdLength; 6253 hwInitializationData.DeviceId = NativeModeAdapters[i].DeviceId; 6254 hwInitializationData.DeviceIdLength = (USHORT) NativeModeAdapters[i].DeviceIdLength; 6255 6256 newStatus = ScsiPortInitialize(DriverObject, 6257 Argument2, 6258 &hwInitializationData, 6259 (PVOID)(ULONG_PTR)i); 6260 if (newStatus < statusToReturn) 6261 statusToReturn = newStatus; 6262 } 6263 6264 hwInitializationData.VendorId = 0; 6265 hwInitializationData.VendorIdLength = 0; 6266 hwInitializationData.DeviceId = 0; 6267 hwInitializationData.DeviceIdLength = 0; 6268 6269 // 6270 // The adapter count is used by the find adapter routine to track how 6271 // which adapter addresses have been tested. 6272 // 6273 6274 adapterCount = 0; 6275 6276 hwInitializationData.HwFindAdapter = AtapiFindPCIController; 6277 hwInitializationData.NumberOfAccessRanges = 4; 6278 hwInitializationData.AdapterInterfaceType = Isa; 6279 6280 newStatus = ScsiPortInitialize(DriverObject, 6281 Argument2, 6282 &hwInitializationData, 6283 &adapterCount); 6284 if (newStatus < statusToReturn) 6285 statusToReturn = newStatus; 6286 6287 // 6288 // Indicate 2 access ranges and reset FindAdapter. 6289 // 6290 6291 hwInitializationData.NumberOfAccessRanges = 2; 6292 hwInitializationData.HwFindAdapter = AtapiFindController; 6293 6294 // 6295 // Indicate ISA bustype. 6296 // 6297 6298 hwInitializationData.AdapterInterfaceType = Isa; 6299 6300 // 6301 // Call initialization for ISA bustype. 6302 // 6303 6304 newStatus = ScsiPortInitialize(DriverObject, 6305 Argument2, 6306 &hwInitializationData, 6307 &adapterCount); 6308 if (newStatus < statusToReturn) 6309 statusToReturn = newStatus; 6310 6311 // 6312 // Set up for MCA 6313 // 6314 6315 hwInitializationData.AdapterInterfaceType = MicroChannel; 6316 adapterCount = 0; 6317 6318 newStatus = ScsiPortInitialize(DriverObject, 6319 Argument2, 6320 &hwInitializationData, 6321 &adapterCount); 6322 if (newStatus < statusToReturn) 6323 statusToReturn = newStatus; 6324 6325 return statusToReturn; 6326 6327 } // end DriverEntry() 6328 6329 6330 6331 LONG 6332 NTAPI 6333 AtapiStringCmp ( 6334 PCHAR FirstStr, 6335 PCHAR SecondStr, 6336 ULONG Count 6337 ) 6338 { 6339 UCHAR first ,last; 6340 6341 if (Count) { 6342 do { 6343 6344 // 6345 // Get next char. 6346 // 6347 6348 first = *FirstStr++; 6349 last = *SecondStr++; 6350 6351 if (first != last) { 6352 6353 // 6354 // If no match, try lower-casing. 6355 // 6356 6357 if (first>='A' && first<='Z') { 6358 first = first - 'A' + 'a'; 6359 } 6360 if (last>='A' && last<='Z') { 6361 last = last - 'A' + 'a'; 6362 } 6363 if (first != last) { 6364 6365 // 6366 // No match 6367 // 6368 6369 return first - last; 6370 } 6371 } 6372 }while (--Count && first); 6373 } 6374 6375 return 0; 6376 } 6377 6378 6379 VOID 6380 NTAPI 6381 AtapiZeroMemory( 6382 IN PUCHAR Buffer, 6383 IN ULONG Count 6384 ) 6385 { 6386 ULONG i; 6387 6388 for (i = 0; i < Count; i++) { 6389 Buffer[i] = 0; 6390 } 6391 } 6392 6393 6394 VOID 6395 NTAPI 6396 AtapiHexToString ( 6397 IN ULONG Value, 6398 IN OUT PCHAR *Buffer 6399 ) 6400 { 6401 PCHAR string; 6402 PCHAR firstdig; 6403 CHAR temp; 6404 ULONG i; 6405 USHORT digval; 6406 6407 string = *Buffer; 6408 6409 firstdig = string; 6410 6411 for (i = 0; i < 4; i++) { 6412 digval = (USHORT)(Value % 16); 6413 Value /= 16; 6414 6415 // 6416 // convert to ascii and store. Note this will create 6417 // the buffer with the digits reversed. 6418 // 6419 6420 if (digval > 9) { 6421 *string++ = (char) (digval - 10 + 'a'); 6422 } else { 6423 *string++ = (char) (digval + '0'); 6424 } 6425 6426 } 6427 6428 // 6429 // Reverse the digits. 6430 // 6431 6432 *string-- = '\0'; 6433 6434 do { 6435 temp = *string; 6436 *string = *firstdig; 6437 *firstdig = temp; 6438 --string; 6439 ++firstdig; 6440 } while (firstdig < string); 6441 } 6442 6443 6444 6445 PSCSI_REQUEST_BLOCK 6446 NTAPI 6447 BuildMechanismStatusSrb ( 6448 IN PVOID HwDeviceExtension, 6449 IN ULONG PathId, 6450 IN ULONG TargetId 6451 ) 6452 { 6453 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 6454 PSCSI_REQUEST_BLOCK srb; 6455 PCDB cdb; 6456 6457 srb = &deviceExtension->InternalSrb; 6458 6459 AtapiZeroMemory((PUCHAR) srb, sizeof(SCSI_REQUEST_BLOCK)); 6460 6461 srb->PathId = (UCHAR) PathId; 6462 srb->TargetId = (UCHAR) TargetId; 6463 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 6464 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 6465 6466 // 6467 // Set flags to disable synchronous negotiation. 6468 // 6469 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 6470 6471 // 6472 // Set timeout to 2 seconds. 6473 // 6474 srb->TimeOutValue = 4; 6475 6476 srb->CdbLength = 6; 6477 srb->DataBuffer = &deviceExtension->MechStatusData; 6478 srb->DataTransferLength = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER); 6479 6480 // 6481 // Set CDB operation code. 6482 // 6483 cdb = (PCDB)srb->Cdb; 6484 cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS; 6485 cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER); 6486 6487 return srb; 6488 } 6489 6490 6491 PSCSI_REQUEST_BLOCK 6492 NTAPI 6493 BuildRequestSenseSrb ( 6494 IN PVOID HwDeviceExtension, 6495 IN ULONG PathId, 6496 IN ULONG TargetId 6497 ) 6498 { 6499 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 6500 PSCSI_REQUEST_BLOCK srb; 6501 PCDB cdb; 6502 6503 srb = &deviceExtension->InternalSrb; 6504 6505 AtapiZeroMemory((PUCHAR) srb, sizeof(SCSI_REQUEST_BLOCK)); 6506 6507 srb->PathId = (UCHAR) PathId; 6508 srb->TargetId = (UCHAR) TargetId; 6509 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 6510 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 6511 6512 // 6513 // Set flags to disable synchronous negotiation. 6514 // 6515 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 6516 6517 // 6518 // Set timeout to 2 seconds. 6519 // 6520 srb->TimeOutValue = 4; 6521 6522 srb->CdbLength = 6; 6523 srb->DataBuffer = &deviceExtension->MechStatusSense; 6524 srb->DataTransferLength = sizeof(SENSE_DATA); 6525 6526 // 6527 // Set CDB operation code. 6528 // 6529 cdb = (PCDB)srb->Cdb; 6530 cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE; 6531 cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA); 6532 6533 return srb; 6534 } 6535 6536 6537 6538 6539 6540