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