Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenatapi.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Storage Stack 00003 * LICENSE: DDK - see license.txt in the root dir 00004 * FILE: drivers/storage/atapi/atapi.c 00005 * PURPOSE: ATAPI IDE miniport driver 00006 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK 00007 */ 00008 00009 #include <ntddk.h> 00010 #include "atapi.h" // includes scsi.h 00011 #include <ntddscsi.h> 00012 #include <ntdddisk.h> 00013 #include <ntddstor.h> 00014 00015 //#define NDEBUG 00016 #include <debug.h> 00017 00018 // 00019 // Device extension 00020 // 00021 00022 typedef struct _HW_DEVICE_EXTENSION { 00023 00024 // 00025 // Current request on controller. 00026 // 00027 00028 PSCSI_REQUEST_BLOCK CurrentSrb; 00029 00030 // 00031 // Base register locations 00032 // 00033 00034 PIDE_REGISTERS_1 BaseIoAddress1[2]; 00035 PIDE_REGISTERS_2 BaseIoAddress2[2]; 00036 00037 // 00038 // Interrupt level 00039 // 00040 00041 ULONG InterruptLevel; 00042 00043 // 00044 // Interrupt Mode (Level or Edge) 00045 // 00046 00047 ULONG InterruptMode; 00048 00049 // 00050 // Data buffer pointer. 00051 // 00052 00053 PUSHORT DataBuffer; 00054 00055 // 00056 // Data words left. 00057 // 00058 00059 ULONG WordsLeft; 00060 00061 // 00062 // Number of channels being supported by one instantiation 00063 // of the device extension. Normally (and correctly) one, but 00064 // with so many broken PCI IDE controllers being sold, we have 00065 // to support them. 00066 // 00067 00068 ULONG NumberChannels; 00069 00070 // 00071 // Count of errors. Used to turn off features. 00072 // 00073 00074 ULONG ErrorCount; 00075 00076 // 00077 // Indicates number of platters on changer-ish devices. 00078 // 00079 00080 ULONG DiscsPresent[4]; 00081 00082 // 00083 // Flags word for each possible device. 00084 // 00085 00086 USHORT DeviceFlags[4]; 00087 00088 // 00089 // Indicates the number of blocks transferred per int. according to the 00090 // identify data. 00091 // 00092 00093 UCHAR MaximumBlockXfer[4]; 00094 00095 // 00096 // Indicates expecting an interrupt 00097 // 00098 00099 BOOLEAN ExpectingInterrupt; 00100 00101 // 00102 // Indicate last tape command was DSC Restrictive. 00103 // 00104 00105 BOOLEAN RDP; 00106 00107 // 00108 // Driver is being used by the crash dump utility or ntldr. 00109 // 00110 00111 BOOLEAN DriverMustPoll; 00112 00113 // 00114 // Indicates use of 32-bit PIO 00115 // 00116 00117 BOOLEAN DWordIO; 00118 00119 // 00120 // Indicates whether '0x1f0' is the base address. Used 00121 // in SMART Ioctl calls. 00122 // 00123 00124 BOOLEAN PrimaryAddress; 00125 00126 // 00127 // Placeholder for the sub-command value of the last 00128 // SMART command. 00129 // 00130 00131 UCHAR SmartCommand; 00132 00133 // 00134 // Placeholder for status register after a GET_MEDIA_STATUS command 00135 // 00136 00137 UCHAR ReturningMediaStatus; 00138 00139 UCHAR Reserved[1]; 00140 00141 // 00142 // Identify data for device 00143 // 00144 00145 IDENTIFY_DATA FullIdentifyData; 00146 IDENTIFY_DATA2 IdentifyData[4]; 00147 00148 // 00149 // Mechanism Status Srb Data 00150 // 00151 PSCSI_REQUEST_BLOCK OriginalSrb; 00152 SCSI_REQUEST_BLOCK InternalSrb; 00153 MECHANICAL_STATUS_INFORMATION_HEADER MechStatusData; 00154 SENSE_DATA MechStatusSense; 00155 ULONG MechStatusRetryCount; 00156 00157 } HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION; 00158 00159 // 00160 // Logical unit extension 00161 // 00162 00163 typedef struct _HW_LU_EXTENSION { 00164 ULONG Reserved; 00165 } HW_LU_EXTENSION, *PHW_LU_EXTENSION; 00166 00167 PSCSI_REQUEST_BLOCK 00168 NTAPI 00169 BuildMechanismStatusSrb ( 00170 IN PVOID HwDeviceExtension, 00171 IN ULONG PathId, 00172 IN ULONG TargetId 00173 ); 00174 00175 PSCSI_REQUEST_BLOCK 00176 NTAPI 00177 BuildRequestSenseSrb ( 00178 IN PVOID HwDeviceExtension, 00179 IN ULONG PathId, 00180 IN ULONG TargetId 00181 ); 00182 00183 VOID 00184 NTAPI 00185 AtapiHwInitializeChanger ( 00186 IN PVOID HwDeviceExtension, 00187 IN ULONG TargetId, 00188 IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus 00189 ); 00190 00191 ULONG 00192 NTAPI 00193 AtapiSendCommand( 00194 IN PVOID HwDeviceExtension, 00195 IN PSCSI_REQUEST_BLOCK Srb 00196 ); 00197 00198 VOID 00199 NTAPI 00200 AtapiZeroMemory( 00201 IN PUCHAR Buffer, 00202 IN ULONG Count 00203 ); 00204 00205 VOID 00206 NTAPI 00207 AtapiHexToString ( 00208 ULONG Value, 00209 PCHAR *Buffer 00210 ); 00211 00212 LONG 00213 NTAPI 00214 AtapiStringCmp ( 00215 PCHAR FirstStr, 00216 PCHAR SecondStr, 00217 ULONG Count 00218 ); 00219 00220 BOOLEAN 00221 NTAPI 00222 AtapiInterrupt( 00223 IN PVOID HwDeviceExtension 00224 ); 00225 00226 BOOLEAN 00227 NTAPI 00228 AtapiHwInitialize( 00229 IN PVOID HwDeviceExtension 00230 ); 00231 00232 ULONG 00233 NTAPI 00234 IdeBuildSenseBuffer( 00235 IN PVOID HwDeviceExtension, 00236 IN PSCSI_REQUEST_BLOCK Srb 00237 ); 00238 00239 VOID 00240 NTAPI 00241 IdeMediaStatus( 00242 IN BOOLEAN EnableMSN, 00243 IN PVOID HwDeviceExtension, 00244 IN ULONG Channel 00245 ); 00246 00247 00248 00249 BOOLEAN 00250 NTAPI 00251 IssueIdentify( 00252 IN PVOID HwDeviceExtension, 00253 IN ULONG DeviceNumber, 00254 IN ULONG Channel, 00255 IN UCHAR Command 00256 ) 00257 00258 /*++ 00259 00260 Routine Description: 00261 00262 Issue IDENTIFY command to a device. 00263 00264 Arguments: 00265 00266 HwDeviceExtension - HBA miniport driver's adapter data storage 00267 DeviceNumber - Indicates which device. 00268 Command - Either the standard (EC) or the ATAPI packet (A1) IDENTIFY. 00269 00270 Return Value: 00271 00272 TRUE if all goes well. 00273 00274 --*/ 00275 00276 { 00277 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 00278 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel] ; 00279 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel]; 00280 ULONG waitCount = 20000; 00281 ULONG i,j; 00282 UCHAR statusByte; 00283 UCHAR signatureLow, 00284 signatureHigh; 00285 00286 // 00287 // Select device 0 or 1. 00288 // 00289 00290 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 00291 (UCHAR)((DeviceNumber << 4) | 0xA0)); 00292 00293 // 00294 // Check that the status register makes sense. 00295 // 00296 00297 GetBaseStatus(baseIoAddress1, statusByte); 00298 00299 if (Command == IDE_COMMAND_IDENTIFY) { 00300 00301 // 00302 // Mask status byte ERROR bits. 00303 // 00304 00305 statusByte &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX); 00306 00307 DebugPrint((1, 00308 "IssueIdentify: Checking for IDE. Status (%x)\n", 00309 statusByte)); 00310 00311 // 00312 // Check if register value is reasonable. 00313 // 00314 00315 if (statusByte != IDE_STATUS_IDLE) { 00316 00317 // 00318 // Reset the controller. 00319 // 00320 00321 AtapiSoftReset(baseIoAddress1,DeviceNumber); 00322 00323 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 00324 (UCHAR)((DeviceNumber << 4) | 0xA0)); 00325 00326 WaitOnBusy(baseIoAddress2,statusByte); 00327 00328 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 00329 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 00330 00331 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 00332 00333 // 00334 // Device is Atapi. 00335 // 00336 00337 return FALSE; 00338 } 00339 00340 DebugPrint((1, 00341 "IssueIdentify: Resetting controller.\n")); 00342 00343 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER ); 00344 ScsiPortStallExecution(500 * 1000); 00345 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER); 00346 00347 00348 // We really should wait up to 31 seconds 00349 // The ATA spec. allows device 0 to come back from BUSY in 31 seconds! 00350 // (30 seconds for device 1) 00351 do { 00352 00353 // 00354 // Wait for Busy to drop. 00355 // 00356 00357 ScsiPortStallExecution(100); 00358 GetStatus(baseIoAddress2, statusByte); 00359 00360 } while ((statusByte & IDE_STATUS_BUSY) && waitCount--); 00361 00362 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 00363 (UCHAR)((DeviceNumber << 4) | 0xA0)); 00364 00365 // 00366 // Another check for signature, to deal with one model Atapi that doesn't assert signature after 00367 // a soft reset. 00368 // 00369 00370 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 00371 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 00372 00373 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 00374 00375 // 00376 // Device is Atapi. 00377 // 00378 00379 return FALSE; 00380 } 00381 00382 statusByte &= ~IDE_STATUS_INDEX; 00383 00384 if (statusByte != IDE_STATUS_IDLE) { 00385 00386 // 00387 // Give up on this. 00388 // 00389 00390 return FALSE; 00391 } 00392 00393 } 00394 00395 } else { 00396 00397 DebugPrint((1, 00398 "IssueIdentify: Checking for ATAPI. Status (%x)\n", 00399 statusByte)); 00400 00401 } 00402 00403 // 00404 // Load CylinderHigh and CylinderLow with number bytes to transfer. 00405 // 00406 00407 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh, (0x200 >> 8)); 00408 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow, (0x200 & 0xFF)); 00409 00410 for (j = 0; j < 2; j++) { 00411 00412 // 00413 // Send IDENTIFY command. 00414 // 00415 00416 WaitOnBusy(baseIoAddress2,statusByte); 00417 00418 ScsiPortWritePortUchar(&baseIoAddress1->Command, Command); 00419 00420 // 00421 // Wait for DRQ. 00422 // 00423 00424 for (i = 0; i < 4; i++) { 00425 00426 WaitForDrq(baseIoAddress2, statusByte); 00427 00428 if (statusByte & IDE_STATUS_DRQ) { 00429 00430 // 00431 // Read status to acknowledge any interrupts generated. 00432 // 00433 00434 GetBaseStatus(baseIoAddress1, statusByte); 00435 00436 // 00437 // One last check for Atapi. 00438 // 00439 00440 00441 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 00442 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 00443 00444 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 00445 00446 // 00447 // Device is Atapi. 00448 // 00449 00450 return FALSE; 00451 } 00452 00453 break; 00454 } 00455 00456 if (Command == IDE_COMMAND_IDENTIFY) { 00457 00458 // 00459 // Check the signature. If DRQ didn't come up it's likely Atapi. 00460 // 00461 00462 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 00463 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 00464 00465 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 00466 00467 // 00468 // Device is Atapi. 00469 // 00470 00471 return FALSE; 00472 } 00473 } 00474 00475 WaitOnBusy(baseIoAddress2,statusByte); 00476 } 00477 00478 if (i == 4 && j == 0) { 00479 00480 // 00481 // Device didn't respond correctly. It will be given one more chances. 00482 // 00483 00484 DebugPrint((1, 00485 "IssueIdentify: DRQ never asserted (%x). Error reg (%x)\n", 00486 statusByte, 00487 ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1))); 00488 00489 AtapiSoftReset(baseIoAddress1,DeviceNumber); 00490 00491 GetStatus(baseIoAddress2,statusByte); 00492 00493 DebugPrint((1, 00494 "IssueIdentify: Status after soft reset (%x)\n", 00495 statusByte)); 00496 00497 } else { 00498 00499 break; 00500 00501 } 00502 } 00503 00504 // 00505 // Check for error on really stupid master devices that assert random 00506 // patterns of bits in the status register at the slave address. 00507 // 00508 00509 if ((Command == IDE_COMMAND_IDENTIFY) && (statusByte & IDE_STATUS_ERROR)) { 00510 return FALSE; 00511 } 00512 00513 DebugPrint((1, 00514 "IssueIdentify: Status before read words %x\n", 00515 statusByte)); 00516 00517 // 00518 // Suck out 256 words. After waiting for one model that asserts busy 00519 // after receiving the Packet Identify command. 00520 // 00521 00522 WaitOnBusy(baseIoAddress2,statusByte); 00523 00524 if (!(statusByte & IDE_STATUS_DRQ)) { 00525 return FALSE; 00526 } 00527 00528 ReadBuffer(baseIoAddress1, 00529 (PUSHORT)&deviceExtension->FullIdentifyData, 00530 256); 00531 00532 // 00533 // Check out a few capabilities / limitations of the device. 00534 // 00535 00536 if (deviceExtension->FullIdentifyData.SpecialFunctionsEnabled & 1) { 00537 00538 // 00539 // Determine if this drive supports the MSN functions. 00540 // 00541 00542 DebugPrint((2,"IssueIdentify: Marking drive %d as removable. SFE = %d\n", 00543 Channel * 2 + DeviceNumber, 00544 deviceExtension->FullIdentifyData.SpecialFunctionsEnabled)); 00545 00546 00547 deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_REMOVABLE_DRIVE; 00548 } 00549 00550 if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) { 00551 00552 // 00553 // Determine max. block transfer for this device. 00554 // 00555 00556 deviceExtension->MaximumBlockXfer[(Channel * 2) + DeviceNumber] = 00557 (UCHAR)(deviceExtension->FullIdentifyData.MaximumBlockTransfer & 0xFF); 00558 } 00559 00560 ScsiPortMoveMemory(&deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber],&deviceExtension->FullIdentifyData,sizeof(IDENTIFY_DATA2)); 00561 00562 if (deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0x20 && 00563 Command != IDE_COMMAND_IDENTIFY) { 00564 00565 // 00566 // This device interrupts with the assertion of DRQ after receiving 00567 // Atapi Packet Command 00568 // 00569 00570 deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_INT_DRQ; 00571 00572 DebugPrint((2, 00573 "IssueIdentify: Device interrupts on assertion of DRQ.\n")); 00574 00575 } else { 00576 00577 DebugPrint((2, 00578 "IssueIdentify: Device does not interrupt on assertion of DRQ.\n")); 00579 } 00580 00581 if (((deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0xF00) == 0x100) && 00582 Command != IDE_COMMAND_IDENTIFY) { 00583 00584 // 00585 // This is a tape. 00586 // 00587 00588 deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_TAPE_DEVICE; 00589 00590 DebugPrint((2, 00591 "IssueIdentify: Device is a tape drive.\n")); 00592 00593 } else { 00594 00595 DebugPrint((2, 00596 "IssueIdentify: Device is not a tape drive.\n")); 00597 } 00598 00599 // 00600 // Work around for some IDE and one model Atapi that will present more than 00601 // 256 bytes for the Identify data. 00602 // 00603 00604 WaitOnBusy(baseIoAddress2,statusByte); 00605 00606 for (i = 0; i < 0x10000; i++) { 00607 00608 GetStatus(baseIoAddress2,statusByte); 00609 00610 if (statusByte & IDE_STATUS_DRQ) { 00611 00612 // 00613 // Suck out any remaining bytes and throw away. 00614 // 00615 00616 ScsiPortReadPortUshort(&baseIoAddress1->Data); 00617 00618 } else { 00619 00620 break; 00621 00622 } 00623 } 00624 00625 DebugPrint((3, 00626 "IssueIdentify: Status after read words (%x)\n", 00627 statusByte)); 00628 00629 return TRUE; 00630 00631 } // end IssueIdentify() 00632 00633 00634 BOOLEAN 00635 NTAPI 00636 SetDriveParameters( 00637 IN PVOID HwDeviceExtension, 00638 IN ULONG DeviceNumber, 00639 IN ULONG Channel 00640 ) 00641 00642 /*++ 00643 00644 Routine Description: 00645 00646 Set drive parameters using the IDENTIFY data. 00647 00648 Arguments: 00649 00650 HwDeviceExtension - HBA miniport driver's adapter data storage 00651 DeviceNumber - Indicates which device. 00652 00653 Return Value: 00654 00655 TRUE if all goes well. 00656 00657 00658 --*/ 00659 00660 { 00661 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 00662 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel]; 00663 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel]; 00664 PIDENTIFY_DATA2 identifyData = &deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber]; 00665 ULONG i; 00666 UCHAR statusByte; 00667 00668 DebugPrint((1, 00669 "SetDriveParameters: Number of heads %x\n", 00670 identifyData->NumberOfHeads)); 00671 00672 DebugPrint((1, 00673 "SetDriveParameters: Sectors per track %x\n", 00674 identifyData->SectorsPerTrack)); 00675 00676 // 00677 // Set up registers for SET PARAMETER command. 00678 // 00679 00680 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 00681 (UCHAR)(((DeviceNumber << 4) | 0xA0) | (identifyData->NumberOfHeads - 1))); 00682 00683 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount, 00684 (UCHAR)identifyData->SectorsPerTrack); 00685 00686 // 00687 // Send SET PARAMETER command. 00688 // 00689 00690 ScsiPortWritePortUchar(&baseIoAddress1->Command, 00691 IDE_COMMAND_SET_DRIVE_PARAMETERS); 00692 00693 // 00694 // Wait for up to 30 milliseconds for ERROR or command complete. 00695 // 00696 00697 for (i=0; i<30 * 1000; i++) { 00698 00699 UCHAR errorByte; 00700 00701 GetStatus(baseIoAddress2, statusByte); 00702 00703 if (statusByte & IDE_STATUS_ERROR) { 00704 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 00705 DebugPrint((1, 00706 "SetDriveParameters: Error bit set. Status %x, error %x\n", 00707 errorByte, 00708 statusByte)); 00709 00710 return FALSE; 00711 } else if ((statusByte & ~IDE_STATUS_INDEX ) == IDE_STATUS_IDLE) { 00712 break; 00713 } else { 00714 ScsiPortStallExecution(100); 00715 } 00716 } 00717 00718 // 00719 // Check for timeout. 00720 // 00721 00722 if (i == 30 * 1000) { 00723 return FALSE; 00724 } else { 00725 return TRUE; 00726 } 00727 00728 } // end SetDriveParameters() 00729 00730 00731 BOOLEAN 00732 NTAPI 00733 AtapiResetController( 00734 IN PVOID HwDeviceExtension, 00735 IN ULONG PathId 00736 ) 00737 00738 /*++ 00739 00740 Routine Description: 00741 00742 Reset IDE controller and/or Atapi device. 00743 00744 Arguments: 00745 00746 HwDeviceExtension - HBA miniport driver's adapter data storage 00747 00748 Return Value: 00749 00750 Nothing. 00751 00752 00753 --*/ 00754 00755 { 00756 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 00757 ULONG numberChannels = deviceExtension->NumberChannels; 00758 PIDE_REGISTERS_1 baseIoAddress1; 00759 PIDE_REGISTERS_2 baseIoAddress2; 00760 BOOLEAN result = FALSE; 00761 ULONG i,j; 00762 UCHAR statusByte; 00763 00764 DebugPrint((2,"AtapiResetController: Reset IDE\n")); 00765 00766 // 00767 // Check and see if we are processing an internal srb 00768 // 00769 if (deviceExtension->OriginalSrb) { 00770 deviceExtension->CurrentSrb = deviceExtension->OriginalSrb; 00771 deviceExtension->OriginalSrb = NULL; 00772 } 00773 00774 // 00775 // Check if request is in progress. 00776 // 00777 00778 if (deviceExtension->CurrentSrb) { 00779 00780 // 00781 // Complete outstanding request with SRB_STATUS_BUS_RESET. 00782 // 00783 00784 ScsiPortCompleteRequest(deviceExtension, 00785 deviceExtension->CurrentSrb->PathId, 00786 deviceExtension->CurrentSrb->TargetId, 00787 deviceExtension->CurrentSrb->Lun, 00788 (ULONG)SRB_STATUS_BUS_RESET); 00789 00790 // 00791 // Clear request tracking fields. 00792 // 00793 00794 deviceExtension->CurrentSrb = NULL; 00795 deviceExtension->WordsLeft = 0; 00796 deviceExtension->DataBuffer = NULL; 00797 00798 // 00799 // Indicate ready for next request. 00800 // 00801 00802 ScsiPortNotification(NextRequest, 00803 deviceExtension, 00804 NULL); 00805 } 00806 00807 // 00808 // Clear expecting interrupt flag. 00809 // 00810 00811 deviceExtension->ExpectingInterrupt = FALSE; 00812 deviceExtension->RDP = FALSE; 00813 00814 for (j = 0; j < numberChannels; j++) { 00815 00816 baseIoAddress1 = deviceExtension->BaseIoAddress1[j]; 00817 baseIoAddress2 = deviceExtension->BaseIoAddress2[j]; 00818 00819 // 00820 // Do special processing for ATAPI and IDE disk devices. 00821 // 00822 00823 for (i = 0; i < 2; i++) { 00824 00825 // 00826 // Check if device present. 00827 // 00828 00829 if (deviceExtension->DeviceFlags[i + (j * 2)] & DFLAGS_DEVICE_PRESENT) { 00830 00831 // 00832 // Check for ATAPI disk. 00833 // 00834 00835 if (deviceExtension->DeviceFlags[i + (j * 2)] & DFLAGS_ATAPI_DEVICE) { 00836 00837 // 00838 // Issue soft reset and issue identify. 00839 // 00840 00841 GetStatus(baseIoAddress2,statusByte); 00842 DebugPrint((1, 00843 "AtapiResetController: Status before Atapi reset (%x).\n", 00844 statusByte)); 00845 00846 AtapiSoftReset(baseIoAddress1,i); 00847 00848 GetStatus(baseIoAddress2,statusByte); 00849 00850 if (statusByte == 0x0) { 00851 00852 IssueIdentify(HwDeviceExtension, 00853 i, 00854 j, 00855 IDE_COMMAND_ATAPI_IDENTIFY); 00856 } else { 00857 00858 DebugPrint((1, 00859 "AtapiResetController: Status after soft reset %x\n", 00860 statusByte)); 00861 } 00862 00863 } else { 00864 00865 // 00866 // Write IDE reset controller bits. 00867 // 00868 00869 IdeHardReset(baseIoAddress2,result); 00870 00871 if (!result) { 00872 return FALSE; 00873 } 00874 00875 // 00876 // Set disk geometry parameters. 00877 // 00878 00879 if (!SetDriveParameters(HwDeviceExtension, 00880 i, 00881 j)) { 00882 00883 DebugPrint((1, 00884 "AtapiResetController: SetDriveParameters failed\n")); 00885 } 00886 } 00887 } 00888 } 00889 } 00890 00891 // 00892 // Call the HwInitialize routine to setup multi-block. 00893 // 00894 00895 AtapiHwInitialize(HwDeviceExtension); 00896 00897 return TRUE; 00898 00899 } // end AtapiResetController() 00900 00901 00902 00903 ULONG 00904 NTAPI 00905 MapError( 00906 IN PVOID HwDeviceExtension, 00907 IN PSCSI_REQUEST_BLOCK Srb 00908 ) 00909 00910 /*++ 00911 00912 Routine Description: 00913 00914 This routine maps ATAPI and IDE errors to specific SRB statuses. 00915 00916 Arguments: 00917 00918 HwDeviceExtension - HBA miniport driver's adapter data storage 00919 Srb - IO request packet 00920 00921 Return Value: 00922 00923 SRB status 00924 00925 --*/ 00926 00927 { 00928 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 00929 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 00930 //PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 00931 ULONG i; 00932 UCHAR errorByte; 00933 UCHAR srbStatus = SRB_STATUS_ERROR; 00934 UCHAR scsiStatus; 00935 00936 // 00937 // Read the error register. 00938 // 00939 00940 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 00941 DebugPrint((1, 00942 "MapError: Error register is %x\n", 00943 errorByte)); 00944 00945 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 00946 00947 switch (errorByte >> 4) { 00948 case SCSI_SENSE_NO_SENSE: 00949 00950 DebugPrint((1, 00951 "ATAPI: No sense information\n")); 00952 scsiStatus = SCSISTAT_CHECK_CONDITION; 00953 srbStatus = SRB_STATUS_ERROR; 00954 break; 00955 00956 case SCSI_SENSE_RECOVERED_ERROR: 00957 00958 DebugPrint((1, 00959 "ATAPI: Recovered error\n")); 00960 scsiStatus = 0; 00961 srbStatus = SRB_STATUS_SUCCESS; 00962 break; 00963 00964 case SCSI_SENSE_NOT_READY: 00965 00966 DebugPrint((1, 00967 "ATAPI: Device not ready\n")); 00968 scsiStatus = SCSISTAT_CHECK_CONDITION; 00969 srbStatus = SRB_STATUS_ERROR; 00970 break; 00971 00972 case SCSI_SENSE_MEDIUM_ERROR: 00973 00974 DebugPrint((1, 00975 "ATAPI: Media error\n")); 00976 scsiStatus = SCSISTAT_CHECK_CONDITION; 00977 srbStatus = SRB_STATUS_ERROR; 00978 break; 00979 00980 case SCSI_SENSE_HARDWARE_ERROR: 00981 00982 DebugPrint((1, 00983 "ATAPI: Hardware error\n")); 00984 scsiStatus = SCSISTAT_CHECK_CONDITION; 00985 srbStatus = SRB_STATUS_ERROR; 00986 break; 00987 00988 case SCSI_SENSE_ILLEGAL_REQUEST: 00989 00990 DebugPrint((1, 00991 "ATAPI: Illegal request\n")); 00992 scsiStatus = SCSISTAT_CHECK_CONDITION; 00993 srbStatus = SRB_STATUS_ERROR; 00994 break; 00995 00996 case SCSI_SENSE_UNIT_ATTENTION: 00997 00998 DebugPrint((1, 00999 "ATAPI: Unit attention\n")); 01000 scsiStatus = SCSISTAT_CHECK_CONDITION; 01001 srbStatus = SRB_STATUS_ERROR; 01002 break; 01003 01004 case SCSI_SENSE_DATA_PROTECT: 01005 01006 DebugPrint((1, 01007 "ATAPI: Data protect\n")); 01008 scsiStatus = SCSISTAT_CHECK_CONDITION; 01009 srbStatus = SRB_STATUS_ERROR; 01010 break; 01011 01012 case SCSI_SENSE_BLANK_CHECK: 01013 01014 DebugPrint((1, 01015 "ATAPI: Blank check\n")); 01016 scsiStatus = SCSISTAT_CHECK_CONDITION; 01017 srbStatus = SRB_STATUS_ERROR; 01018 break; 01019 01020 case SCSI_SENSE_ABORTED_COMMAND: 01021 DebugPrint((1, 01022 "Atapi: Command Aborted\n")); 01023 scsiStatus = SCSISTAT_CHECK_CONDITION; 01024 srbStatus = SRB_STATUS_ERROR; 01025 break; 01026 01027 default: 01028 01029 DebugPrint((1, 01030 "ATAPI: Invalid sense information\n")); 01031 scsiStatus = 0; 01032 srbStatus = SRB_STATUS_ERROR; 01033 break; 01034 } 01035 01036 } else { 01037 01038 scsiStatus = 0; 01039 01040 // 01041 // Save errorByte,to be used by SCSIOP_REQUEST_SENSE. 01042 // 01043 01044 deviceExtension->ReturningMediaStatus = errorByte; 01045 01046 if (errorByte & IDE_ERROR_MEDIA_CHANGE_REQ) { 01047 DebugPrint((1, 01048 "IDE: Media change\n")); 01049 scsiStatus = SCSISTAT_CHECK_CONDITION; 01050 srbStatus = SRB_STATUS_ERROR; 01051 01052 } else if (errorByte & IDE_ERROR_COMMAND_ABORTED) { 01053 DebugPrint((1, 01054 "IDE: Command abort\n")); 01055 srbStatus = SRB_STATUS_ABORTED; 01056 scsiStatus = SCSISTAT_CHECK_CONDITION; 01057 01058 if (Srb->SenseInfoBuffer) { 01059 01060 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 01061 01062 senseBuffer->ErrorCode = 0x70; 01063 senseBuffer->Valid = 1; 01064 senseBuffer->AdditionalSenseLength = 0xb; 01065 senseBuffer->SenseKey = SCSI_SENSE_ABORTED_COMMAND; 01066 senseBuffer->AdditionalSenseCode = 0; 01067 senseBuffer->AdditionalSenseCodeQualifier = 0; 01068 01069 srbStatus |= SRB_STATUS_AUTOSENSE_VALID; 01070 } 01071 01072 deviceExtension->ErrorCount++; 01073 01074 } else if (errorByte & IDE_ERROR_END_OF_MEDIA) { 01075 01076 DebugPrint((1, 01077 "IDE: End of media\n")); 01078 scsiStatus = SCSISTAT_CHECK_CONDITION; 01079 srbStatus = SRB_STATUS_ERROR; 01080 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED)){ 01081 deviceExtension->ErrorCount++; 01082 } 01083 01084 } else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH) { 01085 01086 DebugPrint((1, 01087 "IDE: Illegal length\n")); 01088 srbStatus = SRB_STATUS_INVALID_REQUEST; 01089 01090 } else if (errorByte & IDE_ERROR_BAD_BLOCK) { 01091 01092 DebugPrint((1, 01093 "IDE: Bad block\n")); 01094 srbStatus = SRB_STATUS_ERROR; 01095 scsiStatus = SCSISTAT_CHECK_CONDITION; 01096 if (Srb->SenseInfoBuffer) { 01097 01098 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 01099 01100 senseBuffer->ErrorCode = 0x70; 01101 senseBuffer->Valid = 1; 01102 senseBuffer->AdditionalSenseLength = 0xb; 01103 senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR; 01104 senseBuffer->AdditionalSenseCode = 0; 01105 senseBuffer->AdditionalSenseCodeQualifier = 0; 01106 01107 srbStatus |= SRB_STATUS_AUTOSENSE_VALID; 01108 } 01109 01110 } else if (errorByte & IDE_ERROR_ID_NOT_FOUND) { 01111 01112 DebugPrint((1, 01113 "IDE: Id not found\n")); 01114 srbStatus = SRB_STATUS_ERROR; 01115 scsiStatus = SCSISTAT_CHECK_CONDITION; 01116 01117 if (Srb->SenseInfoBuffer) { 01118 01119 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 01120 01121 senseBuffer->ErrorCode = 0x70; 01122 senseBuffer->Valid = 1; 01123 senseBuffer->AdditionalSenseLength = 0xb; 01124 senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR; 01125 senseBuffer->AdditionalSenseCode = 0; 01126 senseBuffer->AdditionalSenseCodeQualifier = 0; 01127 01128 srbStatus |= SRB_STATUS_AUTOSENSE_VALID; 01129 } 01130 01131 deviceExtension->ErrorCount++; 01132 01133 } else if (errorByte & IDE_ERROR_MEDIA_CHANGE) { 01134 01135 DebugPrint((1, 01136 "IDE: Media change\n")); 01137 scsiStatus = SCSISTAT_CHECK_CONDITION; 01138 srbStatus = SRB_STATUS_ERROR; 01139 01140 if (Srb->SenseInfoBuffer) { 01141 01142 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 01143 01144 senseBuffer->ErrorCode = 0x70; 01145 senseBuffer->Valid = 1; 01146 senseBuffer->AdditionalSenseLength = 0xb; 01147 senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; 01148 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED; 01149 senseBuffer->AdditionalSenseCodeQualifier = 0; 01150 01151 srbStatus |= SRB_STATUS_AUTOSENSE_VALID; 01152 } 01153 01154 } else if (errorByte & IDE_ERROR_DATA_ERROR) { 01155 01156 DebugPrint((1, 01157 "IDE: Data error\n")); 01158 scsiStatus = SCSISTAT_CHECK_CONDITION; 01159 srbStatus = SRB_STATUS_ERROR; 01160 01161 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED)){ 01162 deviceExtension->ErrorCount++; 01163 } 01164 01165 // 01166 // Build sense buffer 01167 // 01168 01169 if (Srb->SenseInfoBuffer) { 01170 01171 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 01172 01173 senseBuffer->ErrorCode = 0x70; 01174 senseBuffer->Valid = 1; 01175 senseBuffer->AdditionalSenseLength = 0xb; 01176 senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR; 01177 senseBuffer->AdditionalSenseCode = 0; 01178 senseBuffer->AdditionalSenseCodeQualifier = 0; 01179 01180 srbStatus |= SRB_STATUS_AUTOSENSE_VALID; 01181 } 01182 } 01183 01184 if (deviceExtension->ErrorCount >= MAX_ERRORS) { 01185 deviceExtension->DWordIO = FALSE; 01186 deviceExtension->MaximumBlockXfer[Srb->TargetId] = 0; 01187 01188 DebugPrint((1, 01189 "MapError: Disabling 32-bit PIO and Multi-sector IOs\n")); 01190 01191 // 01192 // Log the error. 01193 // 01194 01195 ScsiPortLogError( HwDeviceExtension, 01196 Srb, 01197 Srb->PathId, 01198 Srb->TargetId, 01199 Srb->Lun, 01200 SP_BAD_FW_WARNING, 01201 4); 01202 // 01203 // Reprogram to not use Multi-sector. 01204 // 01205 01206 for (i = 0; i < 4; i++) { 01207 UCHAR statusByte; 01208 01209 if (deviceExtension->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT && 01210 !(deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE)) { 01211 01212 // 01213 // Select the device. 01214 // 01215 01216 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 01217 (UCHAR)(((i & 0x1) << 4) | 0xA0)); 01218 01219 // 01220 // Setup sector count to reflect the # of blocks. 01221 // 01222 01223 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount, 01224 0); 01225 01226 // 01227 // Issue the command. 01228 // 01229 01230 ScsiPortWritePortUchar(&baseIoAddress1->Command, 01231 IDE_COMMAND_SET_MULTIPLE); 01232 01233 // 01234 // Wait for busy to drop. 01235 // 01236 01237 WaitOnBaseBusy(baseIoAddress1,statusByte); 01238 01239 // 01240 // Check for errors. Reset the value to 0 (disable MultiBlock) if the 01241 // command was aborted. 01242 // 01243 01244 if (statusByte & IDE_STATUS_ERROR) { 01245 01246 // 01247 // Read the error register. 01248 // 01249 01250 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 01251 01252 DebugPrint((1, 01253 "AtapiHwInitialize: Error setting multiple mode. Status %x, error byte %x\n", 01254 statusByte, 01255 errorByte)); 01256 // 01257 // Adjust the devExt. value, if necessary. 01258 // 01259 01260 deviceExtension->MaximumBlockXfer[i] = 0; 01261 01262 } 01263 } 01264 } 01265 } 01266 } 01267 01268 01269 // 01270 // Set SCSI status to indicate a check condition. 01271 // 01272 01273 Srb->ScsiStatus = scsiStatus; 01274 01275 return srbStatus; 01276 01277 } // end MapError() 01278 01279 01280 BOOLEAN 01281 NTAPI 01282 AtapiHwInitialize( 01283 IN PVOID HwDeviceExtension 01284 ) 01285 01286 /*++ 01287 01288 Routine Description: 01289 01290 Arguments: 01291 01292 HwDeviceExtension - HBA miniport driver's adapter data storage 01293 01294 Return Value: 01295 01296 TRUE - if initialization successful. 01297 FALSE - if initialization unsuccessful. 01298 01299 --*/ 01300 01301 { 01302 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 01303 PIDE_REGISTERS_1 baseIoAddress; 01304 ULONG i; 01305 UCHAR statusByte, errorByte; 01306 01307 01308 for (i = 0; i < 4; i++) { 01309 if (deviceExtension->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT) { 01310 01311 if (!(deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE)) { 01312 01313 // 01314 // Enable media status notification 01315 // 01316 01317 baseIoAddress = deviceExtension->BaseIoAddress1[i >> 1]; 01318 01319 IdeMediaStatus(TRUE,HwDeviceExtension,i); 01320 01321 // 01322 // If supported, setup Multi-block transfers. 01323 // 01324 if (deviceExtension->MaximumBlockXfer[i]) { 01325 01326 // 01327 // Select the device. 01328 // 01329 01330 ScsiPortWritePortUchar(&baseIoAddress->DriveSelect, 01331 (UCHAR)(((i & 0x1) << 4) | 0xA0)); 01332 01333 // 01334 // Setup sector count to reflect the # of blocks. 01335 // 01336 01337 ScsiPortWritePortUchar(&baseIoAddress->BlockCount, 01338 deviceExtension->MaximumBlockXfer[i]); 01339 01340 // 01341 // Issue the command. 01342 // 01343 01344 ScsiPortWritePortUchar(&baseIoAddress->Command, 01345 IDE_COMMAND_SET_MULTIPLE); 01346 01347 // 01348 // Wait for busy to drop. 01349 // 01350 01351 WaitOnBaseBusy(baseIoAddress,statusByte); 01352 01353 // 01354 // Check for errors. Reset the value to 0 (disable MultiBlock) if the 01355 // command was aborted. 01356 // 01357 01358 if (statusByte & IDE_STATUS_ERROR) { 01359 01360 // 01361 // Read the error register. 01362 // 01363 01364 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress + 1); 01365 01366 DebugPrint((1, 01367 "AtapiHwInitialize: Error setting multiple mode. Status %x, error byte %x\n", 01368 statusByte, 01369 errorByte)); 01370 // 01371 // Adjust the devExt. value, if necessary. 01372 // 01373 01374 deviceExtension->MaximumBlockXfer[i] = 0; 01375 01376 } else { 01377 DebugPrint((2, 01378 "AtapiHwInitialize: Using Multiblock on Device %d. Blocks / int - %d\n", 01379 i, 01380 deviceExtension->MaximumBlockXfer[i])); 01381 } 01382 } 01383 } else if (!(deviceExtension->DeviceFlags[i] & DFLAGS_CHANGER_INITED)){ 01384 01385 ULONG j; 01386 UCHAR vendorId[26]; 01387 01388 // 01389 // Attempt to identify any special-case devices - psuedo-atapi changers, atapi changers, etc. 01390 // 01391 01392 for (j = 0; j < 13; j += 2) { 01393 01394 // 01395 // Build a buffer based on the identify data. 01396 // 01397 01398 vendorId[j] = ((PUCHAR)deviceExtension->IdentifyData[i].ModelNumber)[j + 1]; 01399 vendorId[j+1] = ((PUCHAR)deviceExtension->IdentifyData[i].ModelNumber)[j]; 01400 } 01401 01402 if (!AtapiStringCmp ((PCHAR)vendorId, "CD-ROM CDR", 11)) { 01403 01404 // 01405 // Inquiry string for older model had a '-', newer is '_' 01406 // 01407 01408 if (vendorId[12] == 'C') { 01409 01410 // 01411 // Torisan changer. Set the bit. This will be used in several places 01412 // acting like 1) a multi-lun device and 2) building the 'special' TUR's. 01413 // 01414 01415 deviceExtension->DeviceFlags[i] |= (DFLAGS_CHANGER_INITED | DFLAGS_SANYO_ATAPI_CHANGER); 01416 deviceExtension->DiscsPresent[i] = 3; 01417 } 01418 } 01419 } 01420 01421 // 01422 // We need to get our device ready for action before 01423 // returning from this function 01424 // 01425 // According to the atapi spec 2.5 or 2.6, an atapi device 01426 // clears its status BSY bit when it is ready for atapi commands. 01427 // However, some devices (Panasonic SQ-TC500N) are still 01428 // not ready even when the status BSY is clear. They don't react 01429 // to atapi commands. 01430 // 01431 // Since there is really no other indication that tells us 01432 // the drive is really ready for action. We are going to check BSY 01433 // is clear and then just wait for an arbitrary amount of time! 01434 // 01435 if (deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE) { 01436 //PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[i >> 1]; 01437 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[i >> 1]; 01438 ULONG waitCount; 01439 01440 // have to get out of the loop sometime! 01441 // 10000 * 100us = 1000,000us = 1000ms = 1s 01442 waitCount = 10000; 01443 GetStatus(baseIoAddress2, statusByte); 01444 while ((statusByte & IDE_STATUS_BUSY) && waitCount) { 01445 // 01446 // Wait for Busy to drop. 01447 // 01448 ScsiPortStallExecution(100); 01449 GetStatus(baseIoAddress2, statusByte); 01450 waitCount--; 01451 } 01452 01453 // 5000 * 100us = 500,000us = 500ms = 0.5s 01454 waitCount = 5000; 01455 do { 01456 ScsiPortStallExecution(100); 01457 } while (waitCount--); 01458 } 01459 } 01460 } 01461 01462 return TRUE; 01463 01464 } // end AtapiHwInitialize() 01465 01466 01467 VOID 01468 NTAPI 01469 AtapiHwInitializeChanger ( 01470 IN PVOID HwDeviceExtension, 01471 IN ULONG TargetId, 01472 IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus) 01473 { 01474 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 01475 01476 if (MechanismStatus) { 01477 deviceExtension->DiscsPresent[TargetId] = MechanismStatus->NumberAvailableSlots; 01478 if (deviceExtension->DiscsPresent[TargetId] > 1) { 01479 deviceExtension->DeviceFlags[TargetId] |= DFLAGS_ATAPI_CHANGER; 01480 } 01481 } 01482 return; 01483 } 01484 01485 01486 01487 BOOLEAN 01488 NTAPI 01489 FindDevices( 01490 IN PVOID HwDeviceExtension, 01491 IN BOOLEAN AtapiOnly, 01492 IN ULONG Channel 01493 ) 01494 01495 /*++ 01496 01497 Routine Description: 01498 01499 This routine is called from AtapiFindController to identify 01500 devices attached to an IDE controller. 01501 01502 Arguments: 01503 01504 HwDeviceExtension - HBA miniport driver's adapter data storage 01505 AtapiOnly - Indicates that routine should return TRUE only if 01506 an ATAPI device is attached to the controller. 01507 01508 Return Value: 01509 01510 TRUE - True if devices found. 01511 01512 --*/ 01513 01514 { 01515 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 01516 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel]; 01517 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel]; 01518 BOOLEAN deviceResponded = FALSE, 01519 skipSetParameters = FALSE; 01520 ULONG waitCount = 10000; 01521 ULONG deviceNumber; 01522 ULONG i; 01523 UCHAR signatureLow, 01524 signatureHigh; 01525 UCHAR statusByte; 01526 01527 // 01528 // Clear expecting interrupt flag and current SRB field. 01529 // 01530 01531 deviceExtension->ExpectingInterrupt = FALSE; 01532 deviceExtension->CurrentSrb = NULL; 01533 01534 // 01535 // Search for devices. 01536 // 01537 01538 for (deviceNumber = 0; deviceNumber < 2; deviceNumber++) { 01539 01540 // 01541 // Select the device. 01542 // 01543 01544 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 01545 (UCHAR)((deviceNumber << 4) | 0xA0)); 01546 01547 // 01548 // Check here for some SCSI adapters that incorporate IDE emulation. 01549 // 01550 01551 GetStatus(baseIoAddress2, statusByte); 01552 if (statusByte == 0xFF) { 01553 continue; 01554 } 01555 01556 AtapiSoftReset(baseIoAddress1,deviceNumber); 01557 WaitOnBusy(baseIoAddress2,statusByte); 01558 01559 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 01560 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 01561 01562 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 01563 01564 // 01565 // ATAPI signature found. 01566 // Issue the ATAPI identify command if this 01567 // is not for the crash dump utility. 01568 // 01569 01570 atapiIssueId: 01571 01572 if (!deviceExtension->DriverMustPoll) { 01573 01574 // 01575 // Issue ATAPI packet identify command. 01576 // 01577 01578 if (IssueIdentify(HwDeviceExtension, 01579 deviceNumber, 01580 Channel, 01581 IDE_COMMAND_ATAPI_IDENTIFY)) { 01582 01583 // 01584 // Indicate ATAPI device. 01585 // 01586 01587 DebugPrint((1, 01588 "FindDevices: Device %x is ATAPI\n", 01589 deviceNumber)); 01590 01591 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_ATAPI_DEVICE; 01592 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_DEVICE_PRESENT; 01593 01594 deviceResponded = TRUE; 01595 01596 GetStatus(baseIoAddress2, statusByte); 01597 if (statusByte & IDE_STATUS_ERROR) { 01598 AtapiSoftReset(baseIoAddress1, deviceNumber); 01599 } 01600 01601 01602 } else { 01603 01604 // 01605 // Indicate no working device. 01606 // 01607 01608 DebugPrint((1, 01609 "FindDevices: Device %x not responding\n", 01610 deviceNumber)); 01611 01612 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] &= ~DFLAGS_DEVICE_PRESENT; 01613 } 01614 01615 } 01616 01617 } else { 01618 01619 // 01620 // Issue IDE Identify. If an Atapi device is actually present, the signature 01621 // will be asserted, and the drive will be recognized as such. 01622 // 01623 01624 if (IssueIdentify(HwDeviceExtension, 01625 deviceNumber, 01626 Channel, 01627 IDE_COMMAND_IDENTIFY)) { 01628 01629 // 01630 // IDE drive found. 01631 // 01632 01633 01634 DebugPrint((1, 01635 "FindDevices: Device %x is IDE\n", 01636 deviceNumber)); 01637 01638 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_DEVICE_PRESENT; 01639 01640 if (!AtapiOnly) { 01641 deviceResponded = TRUE; 01642 } 01643 01644 // 01645 // Indicate IDE - not ATAPI device. 01646 // 01647 01648 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] &= ~DFLAGS_ATAPI_DEVICE; 01649 01650 01651 } else { 01652 01653 // 01654 // Look to see if an Atapi device is present. 01655 // 01656 01657 AtapiSoftReset(baseIoAddress1,deviceNumber); 01658 01659 WaitOnBusy(baseIoAddress2,statusByte); 01660 01661 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow); 01662 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh); 01663 01664 if (signatureLow == 0x14 && signatureHigh == 0xEB) { 01665 goto atapiIssueId; 01666 } 01667 } 01668 } 01669 } 01670 01671 for (i = 0; i < 2; i++) { 01672 if ((deviceExtension->DeviceFlags[i + (Channel * 2)] & DFLAGS_DEVICE_PRESENT) && 01673 (!(deviceExtension->DeviceFlags[i + (Channel * 2)] & DFLAGS_ATAPI_DEVICE)) && deviceResponded) { 01674 01675 // 01676 // This hideous hack is to deal with ESDI devices that return 01677 // garbage geometry in the IDENTIFY data. 01678 // This is ONLY for the crashdump environment as 01679 // these are ESDI devices. 01680 // 01681 01682 if (deviceExtension->IdentifyData[i].SectorsPerTrack == 01683 0x35 && 01684 deviceExtension->IdentifyData[i].NumberOfHeads == 01685 0x07) { 01686 01687 DebugPrint((1, 01688 "FindDevices: Found nasty Compaq ESDI!\n")); 01689 01690 // 01691 // Change these values to something reasonable. 01692 // 01693 01694 deviceExtension->IdentifyData[i].SectorsPerTrack = 01695 0x34; 01696 deviceExtension->IdentifyData[i].NumberOfHeads = 01697 0x0E; 01698 } 01699 01700 if (deviceExtension->IdentifyData[i].SectorsPerTrack == 01701 0x35 && 01702 deviceExtension->IdentifyData[i].NumberOfHeads == 01703 0x0F) { 01704 01705 DebugPrint((1, 01706 "FindDevices: Found nasty Compaq ESDI!\n")); 01707 01708 // 01709 // Change these values to something reasonable. 01710 // 01711 01712 deviceExtension->IdentifyData[i].SectorsPerTrack = 01713 0x34; 01714 deviceExtension->IdentifyData[i].NumberOfHeads = 01715 0x0F; 01716 } 01717 01718 01719 if (deviceExtension->IdentifyData[i].SectorsPerTrack == 01720 0x36 && 01721 deviceExtension->IdentifyData[i].NumberOfHeads == 01722 0x07) { 01723 01724 DebugPrint((1, 01725 "FindDevices: Found nasty UltraStor ESDI!\n")); 01726 01727 // 01728 // Change these values to something reasonable. 01729 // 01730 01731 deviceExtension->IdentifyData[i].SectorsPerTrack = 01732 0x3F; 01733 deviceExtension->IdentifyData[i].NumberOfHeads = 01734 0x10; 01735 skipSetParameters = TRUE; 01736 } 01737 01738 01739 if (!skipSetParameters) { 01740 01741 WaitOnBusy(baseIoAddress2,statusByte); 01742 01743 // 01744 // Select the device. 01745 // 01746 01747 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 01748 (UCHAR)((i << 4) | 0xA0)); 01749 01750 GetStatus(baseIoAddress2, statusByte); 01751 01752 if (statusByte & IDE_STATUS_ERROR) { 01753 01754 // 01755 // Reset the device. 01756 // 01757 01758 DebugPrint((2, 01759 "FindDevices: Resetting controller before SetDriveParameters.\n")); 01760 01761 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER ); 01762 ScsiPortStallExecution(500 * 1000); 01763 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER); 01764 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 01765 (UCHAR)((i << 4) | 0xA0)); 01766 01767 do { 01768 01769 // 01770 // Wait for Busy to drop. 01771 // 01772 01773 ScsiPortStallExecution(100); 01774 GetStatus(baseIoAddress2, statusByte); 01775 01776 } while ((statusByte & IDE_STATUS_BUSY) && waitCount--); 01777 } 01778 01779 WaitOnBusy(baseIoAddress2,statusByte); 01780 DebugPrint((2, 01781 "FindDevices: Status before SetDriveParameters: (%x) (%x)\n", 01782 statusByte, 01783 ScsiPortReadPortUchar(&baseIoAddress1->DriveSelect))); 01784 01785 // 01786 // Use the IDENTIFY data to set drive parameters. 01787 // 01788 01789 if (!SetDriveParameters(HwDeviceExtension,i,Channel)) { 01790 01791 DebugPrint((0, 01792 "AtapHwInitialize: Set drive parameters for device %d failed\n", 01793 i)); 01794 01795 // 01796 // Don't use this device as writes could cause corruption. 01797 // 01798 01799 deviceExtension->DeviceFlags[i + Channel] = 0; 01800 continue; 01801 01802 } 01803 if (deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] & DFLAGS_REMOVABLE_DRIVE) { 01804 01805 // 01806 // Pick up ALL IDE removable drives that conform to Yosemite V0.2... 01807 // 01808 01809 AtapiOnly = FALSE; 01810 } 01811 01812 01813 // 01814 // Indicate that a device was found. 01815 // 01816 01817 if (!AtapiOnly) { 01818 deviceResponded = TRUE; 01819 } 01820 } 01821 } 01822 } 01823 01824 // 01825 // Make sure master device is selected on exit. 01826 // 01827 01828 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 0xA0); 01829 01830 // 01831 // Reset the controller. This is a feeble attempt to leave the ESDI 01832 // controllers in a state that ATDISK driver will recognize them. 01833 // The problem in ATDISK has to do with timings as it is not reproducible 01834 // in debug. The reset should restore the controller to its poweron state 01835 // and give the system enough time to settle. 01836 // 01837 01838 if (!deviceResponded) { 01839 01840 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER ); 01841 ScsiPortStallExecution(50 * 1000); 01842 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER); 01843 } 01844 01845 return deviceResponded; 01846 01847 } // end FindDevices() 01848 01849 01850 ULONG 01851 NTAPI 01852 AtapiParseArgumentString( 01853 IN PCHAR String, 01854 IN PCHAR KeyWord 01855 ) 01856 01857 /*++ 01858 01859 Routine Description: 01860 01861 This routine will parse the string for a match on the keyword, then 01862 calculate the value for the keyword and return it to the caller. 01863 01864 Arguments: 01865 01866 String - The ASCII string to parse. 01867 KeyWord - The keyword for the value desired. 01868 01869 Return Values: 01870 01871 Zero if value not found 01872 Value converted from ASCII to binary. 01873 01874 --*/ 01875 01876 { 01877 PCHAR cptr; 01878 PCHAR kptr; 01879 ULONG value; 01880 ULONG stringLength = 0; 01881 ULONG keyWordLength = 0; 01882 ULONG index; 01883 01884 if (!String) { 01885 return 0; 01886 } 01887 if (!KeyWord) { 01888 return 0; 01889 } 01890 01891 // 01892 // Calculate the string length and lower case all characters. 01893 // 01894 01895 cptr = String; 01896 while (*cptr) { 01897 if (*cptr >= 'A' && *cptr <= 'Z') { 01898 *cptr = *cptr + ('a' - 'A'); 01899 } 01900 cptr++; 01901 stringLength++; 01902 } 01903 01904 // 01905 // Calculate the keyword length and lower case all characters. 01906 // 01907 01908 cptr = KeyWord; 01909 while (*cptr) { 01910 01911 if (*cptr >= 'A' && *cptr <= 'Z') { 01912 *cptr = *cptr + ('a' - 'A'); 01913 } 01914 cptr++; 01915 keyWordLength++; 01916 } 01917 01918 if (keyWordLength > stringLength) { 01919 01920 // 01921 // Can't possibly have a match. 01922 // 01923 01924 return 0; 01925 } 01926 01927 // 01928 // Now setup and start the compare. 01929 // 01930 01931 cptr = String; 01932 01933 ContinueSearch: 01934 01935 // 01936 // The input string may start with white space. Skip it. 01937 // 01938 01939 while (*cptr == ' ' || *cptr == '\t') { 01940 cptr++; 01941 } 01942 01943 if (*cptr == '\0') { 01944 01945 // 01946 // end of string. 01947 // 01948 01949 return 0; 01950 } 01951 01952 kptr = KeyWord; 01953 while (*cptr++ == *kptr++) { 01954 01955 if (*(cptr - 1) == '\0') { 01956 01957 // 01958 // end of string 01959 // 01960 01961 return 0; 01962 } 01963 } 01964 01965 if (*(kptr - 1) == '\0') { 01966 01967 // 01968 // May have a match backup and check for blank or equals. 01969 // 01970 01971 cptr--; 01972 while (*cptr == ' ' || *cptr == '\t') { 01973 cptr++; 01974 } 01975 01976 // 01977 // Found a match. Make sure there is an equals. 01978 // 01979 01980 if (*cptr != '=') { 01981 01982 // 01983 // Not a match so move to the next semicolon. 01984 // 01985 01986 while (*cptr) { 01987 if (*cptr++ == ';') { 01988 goto ContinueSearch; 01989 } 01990 } 01991 return 0; 01992 } 01993 01994 // 01995 // Skip the equals sign. 01996 // 01997 01998 cptr++; 01999 02000 // 02001 // Skip white space. 02002 // 02003 02004 while ((*cptr == ' ') || (*cptr == '\t')) { 02005 cptr++; 02006 } 02007 02008 if (*cptr == '\0') { 02009 02010 // 02011 // Early end of string, return not found 02012 // 02013 02014 return 0; 02015 } 02016 02017 if (*cptr == ';') { 02018 02019 // 02020 // This isn't it either. 02021 // 02022 02023 cptr++; 02024 goto ContinueSearch; 02025 } 02026 02027 value = 0; 02028 if ((*cptr == '0') && (*(cptr + 1) == 'x')) { 02029 02030 // 02031 // Value is in Hex. Skip the "0x" 02032 // 02033 02034 cptr += 2; 02035 for (index = 0; *(cptr + index); index++) { 02036 02037 if (*(cptr + index) == ' ' || 02038 *(cptr + index) == '\t' || 02039 *(cptr + index) == ';') { 02040 break; 02041 } 02042 02043 if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) { 02044 value = (16 * value) + (*(cptr + index) - '0'); 02045 } else { 02046 if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) { 02047 value = (16 * value) + (*(cptr + index) - 'a' + 10); 02048 } else { 02049 02050 // 02051 // Syntax error, return not found. 02052 // 02053 return 0; 02054 } 02055 } 02056 } 02057 } else { 02058 02059 // 02060 // Value is in Decimal. 02061 // 02062 02063 for (index = 0; *(cptr + index); index++) { 02064 02065 if (*(cptr + index) == ' ' || 02066 *(cptr + index) == '\t' || 02067 *(cptr + index) == ';') { 02068 break; 02069 } 02070 02071 if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) { 02072 value = (10 * value) + (*(cptr + index) - '0'); 02073 } else { 02074 02075 // 02076 // Syntax error return not found. 02077 // 02078 return 0; 02079 } 02080 } 02081 } 02082 02083 return value; 02084 } else { 02085 02086 // 02087 // Not a match check for ';' to continue search. 02088 // 02089 02090 while (*cptr) { 02091 if (*cptr++ == ';') { 02092 goto ContinueSearch; 02093 } 02094 } 02095 02096 return 0; 02097 } 02098 } 02099 02100 02101 02102 02103 02104 ULONG 02105 NTAPI 02106 AtapiFindController( 02107 IN PVOID HwDeviceExtension, 02108 IN PVOID Context, 02109 IN PVOID BusInformation, 02110 IN PCHAR ArgumentString, 02111 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, 02112 OUT PBOOLEAN Again 02113 ) 02114 /*++ 02115 02116 Routine Description: 02117 02118 This function is called by the OS-specific port driver after 02119 the necessary storage has been allocated, to gather information 02120 about the adapter's configuration. 02121 02122 Arguments: 02123 02124 HwDeviceExtension - HBA miniport driver's adapter data storage 02125 Context - Address of adapter count 02126 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility. 02127 ConfigInfo - Configuration information structure describing HBA 02128 Again - Indicates search for adapters to continue 02129 02130 Return Value: 02131 02132 ULONG 02133 02134 --*/ 02135 02136 { 02137 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 02138 PULONG adapterCount = (PULONG)Context; 02139 PUCHAR ioSpace = NULL; 02140 ULONG i; 02141 ULONG irq; 02142 ULONG portBase; 02143 ULONG retryCount; 02144 PCI_SLOT_NUMBER slotData; 02145 PPCI_COMMON_CONFIG pciData; 02146 ULONG pciBuffer; 02147 BOOLEAN atapiOnly; 02148 UCHAR statusByte; 02149 BOOLEAN preConfig = FALSE; 02150 // 02151 // The following table specifies the ports to be checked when searching for 02152 // an IDE controller. A zero entry terminates the search. 02153 // 02154 02155 CONST ULONG AdapterAddresses[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0}; 02156 02157 // 02158 // The following table specifies interrupt levels corresponding to the 02159 // port addresses in the previous table. 02160 // 02161 02162 CONST ULONG InterruptLevels[5] = {14, 15, 11, 10, 0}; 02163 02164 if (!deviceExtension) { 02165 return SP_RETURN_ERROR; 02166 } 02167 02168 // 02169 // Check to see if this is a special configuration environment. 02170 // 02171 02172 portBase = irq = 0; 02173 if (ArgumentString) { 02174 02175 irq = AtapiParseArgumentString(ArgumentString, "Interrupt"); 02176 if (irq ) { 02177 02178 // 02179 // Both parameters must be present to proceed 02180 // 02181 02182 portBase = AtapiParseArgumentString(ArgumentString, "BaseAddress"); 02183 if (!portBase) { 02184 02185 // 02186 // Try a default search for the part. 02187 // 02188 02189 irq = 0; 02190 } 02191 } 02192 } 02193 02194 02195 02196 // 02197 // Scan though the adapter address looking for adapters. 02198 // 02199 if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart) != 0) { 02200 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 02201 ConfigInfo->AdapterInterfaceType, 02202 ConfigInfo->SystemIoBusNumber, 02203 (*ConfigInfo->AccessRanges)[0].RangeStart, 02204 (*ConfigInfo->AccessRanges)[0].RangeLength, 02205 (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory)); 02206 *Again = FALSE; 02207 // 02208 // Since we have pre-configured information we only need to go through this loop once 02209 // 02210 preConfig = TRUE; 02211 portBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart); 02212 02213 } 02214 02215 02216 02217 while (AdapterAddresses[*adapterCount] != 0) { 02218 02219 retryCount = 4; 02220 02221 for (i = 0; i < 4; i++) { 02222 02223 // 02224 // Zero device fields to ensure that if earlier devices were found, 02225 // but not claimed, the fields are cleared. 02226 // 02227 02228 deviceExtension->DeviceFlags[i] &= ~(DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT | DFLAGS_TAPE_DEVICE); 02229 } 02230 02231 // 02232 // Get the system physical address for this IO range. 02233 // 02234 02235 02236 // 02237 // Check if configInfo has the default information 02238 // if not, we go and find ourselves 02239 // 02240 02241 if (preConfig == FALSE) { 02242 02243 if (portBase) { 02244 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 02245 ConfigInfo->AdapterInterfaceType, 02246 ConfigInfo->SystemIoBusNumber, 02247 ScsiPortConvertUlongToPhysicalAddress(portBase), 02248 8, 02249 TRUE); 02250 } else { 02251 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 02252 ConfigInfo->AdapterInterfaceType, 02253 ConfigInfo->SystemIoBusNumber, 02254 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]), 02255 8, 02256 TRUE); 02257 } 02258 02259 }// ConfigInfo check 02260 // 02261 // Update the adapter count. 02262 // 02263 02264 (*adapterCount)++; 02265 02266 // 02267 // Check if ioSpace accessible. 02268 // 02269 02270 if (!ioSpace) { 02271 continue; 02272 } 02273 02274 retryIdentifier: 02275 02276 // 02277 // Select master. 02278 // 02279 02280 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xA0); 02281 02282 // 02283 // Check if card at this address. 02284 // 02285 02286 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 02287 02288 // 02289 // Check if indentifier can be read back. 02290 // 02291 02292 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 02293 02294 DebugPrint((2, 02295 "AtapiFindController: Identifier read back from Master (%x)\n", 02296 statusByte)); 02297 02298 statusByte = ScsiPortReadPortUchar(&((PATAPI_REGISTERS_2)ioSpace)->AlternateStatus); 02299 02300 if (statusByte & IDE_STATUS_BUSY) { 02301 02302 i = 0; 02303 02304 // 02305 // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that 02306 // warm boots don't clear. 02307 // 02308 02309 do { 02310 ScsiPortStallExecution(1000); 02311 statusByte = ScsiPortReadPortUchar(&((PATAPI_REGISTERS_1)ioSpace)->Command); 02312 DebugPrint((3, 02313 "AtapiFindController: First access to status %x\n", 02314 statusByte)); 02315 } while ((statusByte & IDE_STATUS_BUSY) && ++i < 10); 02316 02317 if (retryCount-- && (!(statusByte & IDE_STATUS_BUSY))) { 02318 goto retryIdentifier; 02319 } 02320 } 02321 02322 // 02323 // Select slave. 02324 // 02325 02326 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xB0); 02327 02328 // 02329 // See if slave is present. 02330 // 02331 02332 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 02333 02334 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 02335 02336 DebugPrint((2, 02337 "AtapiFindController: Identifier read back from Slave (%x)\n", 02338 statusByte)); 02339 02340 // 02341 // 02342 // No controller at this base address. 02343 // 02344 02345 ScsiPortFreeDeviceBase(HwDeviceExtension, 02346 ioSpace); 02347 02348 continue; 02349 } 02350 } 02351 02352 // 02353 // Record base IO address. 02354 // 02355 02356 deviceExtension->BaseIoAddress1[0] = (PIDE_REGISTERS_1)(ioSpace); 02357 02358 // 02359 // Fill in the access array information only if default params are not in there. 02360 // 02361 if (preConfig == FALSE) { 02362 02363 // 02364 // An adapter has been found request another call, only if we didn't get preconfigured info. 02365 // 02366 *Again = TRUE; 02367 02368 if (portBase) { 02369 (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(portBase); 02370 } else { 02371 (*ConfigInfo->AccessRanges)[0].RangeStart = 02372 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]); 02373 } 02374 02375 (*ConfigInfo->AccessRanges)[0].RangeLength = 8; 02376 (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; 02377 02378 // 02379 // Indicate the interrupt level corresponding to this IO range. 02380 // 02381 02382 if (irq) { 02383 ConfigInfo->BusInterruptLevel = irq; 02384 } else { 02385 ConfigInfo->BusInterruptLevel = InterruptLevels[*adapterCount - 1]; 02386 } 02387 02388 if (ConfigInfo->AdapterInterfaceType == MicroChannel) { 02389 ConfigInfo->InterruptMode = LevelSensitive; 02390 } else { 02391 ConfigInfo->InterruptMode = Latched; 02392 } 02393 } 02394 // 02395 // Get the system physical address for the second IO range. 02396 // 02397 02398 02399 if (portBase) { 02400 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 02401 ConfigInfo->AdapterInterfaceType, 02402 ConfigInfo->SystemIoBusNumber, 02403 ScsiPortConvertUlongToPhysicalAddress(portBase + 0x206), 02404 1, 02405 TRUE); 02406 } else { 02407 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 02408 ConfigInfo->AdapterInterfaceType, 02409 ConfigInfo->SystemIoBusNumber, 02410 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1] + 0x206), 02411 1, 02412 TRUE); 02413 } 02414 02415 deviceExtension->BaseIoAddress2[0] = (PIDE_REGISTERS_2)(ioSpace); 02416 02417 deviceExtension->NumberChannels = 1; 02418 02419 ConfigInfo->NumberOfBuses = 1; 02420 ConfigInfo->MaximumNumberOfTargets = 2; 02421 02422 // 02423 // Indicate maximum transfer length is 64k. 02424 // 02425 02426 ConfigInfo->MaximumTransferLength = 0x10000; 02427 02428 DebugPrint((1, 02429 "AtapiFindController: Found IDE at %x\n", 02430 deviceExtension->BaseIoAddress1[0])); 02431 02432 02433 // 02434 // For Daytona, the atdisk driver gets the first shot at the 02435 // primary and secondary controllers. 02436 // 02437 02438 if (preConfig == FALSE) { 02439 02440 02441 if (*adapterCount - 1 < 2) { 02442 02443 // 02444 // Determine whether this driver is being initialized by the 02445 // system or as a crash dump driver. 02446 // 02447 02448 if (ArgumentString) { 02449 02450 if (AtapiParseArgumentString(ArgumentString, "dump") == 1) { 02451 DebugPrint((3, 02452 "AtapiFindController: Crash dump\n")); 02453 atapiOnly = FALSE; 02454 deviceExtension->DriverMustPoll = TRUE; 02455 } else { 02456 DebugPrint((3, 02457 "AtapiFindController: Atapi Only\n")); 02458 atapiOnly = TRUE; 02459 deviceExtension->DriverMustPoll = FALSE; 02460 } 02461 } else { 02462 02463 DebugPrint((3, 02464 "AtapiFindController: Atapi Only\n")); 02465 atapiOnly = TRUE; 02466 deviceExtension->DriverMustPoll = FALSE; 02467 } 02468 02469 } else { 02470 atapiOnly = FALSE; 02471 } 02472 02473 // 02474 // If this is a PCI machine, pick up all devices. 02475 // 02476 02477 02478 pciData = (PPCI_COMMON_CONFIG)&pciBuffer; 02479 02480 slotData.u.bits.DeviceNumber = 0; 02481 slotData.u.bits.FunctionNumber = 0; 02482 02483 if (ScsiPortGetBusData(deviceExtension, 02484 PCIConfiguration, 02485 0, // BusNumber 02486 slotData.u.AsULONG, 02487 pciData, 02488 sizeof(ULONG))) { 02489 02490 atapiOnly = FALSE; 02491 02492 // 02493 // Wait on doing this, until a reliable method 02494 // of determining support is found. 02495 // 02496 02497 #if 0 02498 deviceExtension->DWordIO = TRUE; 02499 #endif 02500 02501 } else { 02502 deviceExtension->DWordIO = FALSE; 02503 } 02504 02505 } else { 02506 02507 atapiOnly = FALSE; 02508 deviceExtension->DriverMustPoll = FALSE; 02509 02510 }// preConfig check 02511 02512 // 02513 // Save the Interrupe Mode for later use 02514 // 02515 deviceExtension->InterruptMode = ConfigInfo->InterruptMode; 02516 02517 // 02518 // Search for devices on this controller. 02519 // 02520 02521 if (FindDevices(HwDeviceExtension, 02522 atapiOnly, 02523 0)) { 02524 02525 // 02526 // Claim primary or secondary ATA IO range. 02527 // 02528 02529 if (portBase) { 02530 switch (portBase) { 02531 case 0x170: 02532 ConfigInfo->AtdiskSecondaryClaimed = TRUE; 02533 deviceExtension->PrimaryAddress = FALSE; 02534 break; 02535 case 0x1f0: 02536 ConfigInfo->AtdiskPrimaryClaimed = TRUE; 02537 deviceExtension->PrimaryAddress = TRUE; 02538 break; 02539 default: 02540 break; 02541 } 02542 } else { 02543 if (*adapterCount == 1) { 02544 ConfigInfo->AtdiskPrimaryClaimed = TRUE; 02545 deviceExtension->PrimaryAddress = TRUE; 02546 } else if (*adapterCount == 2) { 02547 ConfigInfo->AtdiskSecondaryClaimed = TRUE; 02548 deviceExtension->PrimaryAddress = FALSE; 02549 } 02550 } 02551 02552 return(SP_RETURN_FOUND); 02553 } 02554 } 02555 02556 // 02557 // The entire table has been searched and no adapters have been found. 02558 // There is no need to call again and the device base can now be freed. 02559 // Clear the adapter count for the next bus. 02560 // 02561 02562 *Again = FALSE; 02563 *(adapterCount) = 0; 02564 02565 return(SP_RETURN_NOT_FOUND); 02566 02567 } // end AtapiFindController() 02568 02569 02570 02571 02572 02573 BOOLEAN 02574 NTAPI 02575 FindBrokenController( 02576 IN PVOID DeviceExtension, 02577 IN PUCHAR VendorID, 02578 IN ULONG VendorIDLength, 02579 IN PUCHAR DeviceID, 02580 IN ULONG DeviceIDLength, 02581 IN OUT PULONG FunctionNumber, 02582 IN OUT PULONG SlotNumber, 02583 IN ULONG BusNumber, 02584 OUT PBOOLEAN LastSlot 02585 ) 02586 02587 /*++ 02588 02589 Routine Description: 02590 02591 Walk PCI slot information looking for Vendor and Product ID matches. 02592 02593 Arguments: 02594 02595 Return Value: 02596 02597 TRUE if card found. 02598 02599 --*/ 02600 { 02601 ULONG pciBuffer; 02602 ULONG slotNumber; 02603 ULONG functionNumber; 02604 PCI_SLOT_NUMBER slotData; 02605 PPCI_COMMON_CONFIG pciData; 02606 UCHAR vendorString[5]; 02607 UCHAR deviceString[5]; 02608 PUCHAR vendorStrPtr; 02609 PUCHAR deviceStrPtr; 02610 02611 pciData = (PPCI_COMMON_CONFIG)&pciBuffer; 02612 02613 slotData.u.AsULONG = 0; 02614 02615 // 02616 // Look at each device. 02617 // 02618 02619 for (slotNumber = *SlotNumber; 02620 slotNumber < 32; 02621 slotNumber++) { 02622 02623 slotData.u.bits.DeviceNumber = slotNumber; 02624 02625 // 02626 // Look at each function. 02627 // 02628 02629 for (functionNumber= *FunctionNumber; 02630 functionNumber < 8; 02631 functionNumber++) { 02632 02633 slotData.u.bits.FunctionNumber = functionNumber; 02634 02635 if (!ScsiPortGetBusData(DeviceExtension, 02636 PCIConfiguration, 02637 BusNumber, 02638 slotData.u.AsULONG, 02639 pciData, 02640 sizeof(ULONG))) { 02641 02642 // 02643 // Out of PCI data. 02644 // 02645 02646 *LastSlot = TRUE; 02647 return FALSE; 02648 } 02649 02650 if (pciData->VendorID == PCI_INVALID_VENDORID) { 02651 02652 // 02653 // No PCI device, or no more functions on device 02654 // move to next PCI device. 02655 // 02656 02657 break; 02658 } 02659 02660 // 02661 // Translate hex ids to strings. 02662 // 02663 02664 vendorStrPtr = vendorString; 02665 deviceStrPtr = deviceString; 02666 AtapiHexToString(pciData->VendorID, (PCHAR*)&vendorStrPtr); 02667 AtapiHexToString(pciData->DeviceID, (PCHAR*)&deviceStrPtr); 02668 02669 DebugPrint((2, 02670 "FindBrokenController: Bus %x Slot %x Function %x Vendor %s Product %s\n", 02671 BusNumber, 02672 slotNumber, 02673 functionNumber, 02674 vendorString, 02675 deviceString)); 02676 02677 // 02678 // Compare strings. 02679 // 02680 02681 if (AtapiStringCmp((PCHAR)vendorString, 02682 (PCHAR)VendorID, 02683 VendorIDLength) || 02684 AtapiStringCmp((PCHAR)deviceString, 02685 (PCHAR)DeviceID, 02686 DeviceIDLength)) { 02687 02688 // 02689 // Not our PCI device. Try next device/function 02690 // 02691 02692 continue; 02693 } 02694 02695 *FunctionNumber = functionNumber; 02696 *SlotNumber = slotNumber; 02697 return TRUE; 02698 02699 } // next PCI function 02700 02701 *FunctionNumber = 0; 02702 02703 } // next PCI slot 02704 02705 *LastSlot = TRUE; 02706 return FALSE; 02707 } // end FindBrokenController 02708 02709 02710 ULONG 02711 NTAPI 02712 AtapiFindNativeModeController( 02713 IN PVOID HwDeviceExtension, 02714 IN PVOID Context, 02715 IN PVOID BusInformation, 02716 IN PCHAR ArgumentString, 02717 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, 02718 OUT PBOOLEAN Again 02719 ) 02720 /*++ 02721 02722 Routine Description: 02723 02724 This function is called by the OS-specific port driver after 02725 the necessary storage has been allocated, to gather information 02726 about the adapter's configuration. 02727 02728 Arguments: 02729 02730 HwDeviceExtension - HBA miniport driver's adapter data storage 02731 Context - Address of adapter count 02732 BusInformation - 02733 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility. 02734 ConfigInfo - Configuration information structure describing HBA 02735 Again - Indicates search for adapters to continue 02736 02737 Return Value: 02738 02739 ULONG 02740 02741 --*/ 02742 02743 { 02744 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 02745 ULONG nativeModeAdapterTableIndex = (ULONG_PTR)Context; 02746 ULONG channel; 02747 PUCHAR ioSpace; 02748 BOOLEAN atapiOnly, 02749 deviceFound = FALSE; 02750 UCHAR statusByte; 02751 PCI_SLOT_NUMBER slotData; 02752 PCI_COMMON_CONFIG pciData; 02753 ULONG funcNumber; 02754 ULONG busDataRead; 02755 UCHAR vendorString[5]; 02756 UCHAR deviceString[5]; 02757 PUCHAR vendorStrPtr; 02758 PUCHAR deviceStrPtr; 02759 SCSI_PHYSICAL_ADDRESS IoBasePort1; 02760 SCSI_PHYSICAL_ADDRESS IoBasePort2; 02761 02762 // 02763 // The following table specifies the ports to be checked when searching for 02764 // an IDE controller. A zero entry terminates the search. 02765 // 02766 02767 CONST ULONG AdapterAddresses[3] = {0x1F0, 0x170, 0}; 02768 02769 if (!deviceExtension) { 02770 return SP_RETURN_ERROR; 02771 } 02772 02773 *Again = FALSE; 02774 02775 slotData.u.AsULONG = 0; 02776 slotData.u.bits.DeviceNumber = ConfigInfo->SlotNumber; 02777 02778 for (funcNumber= 0; funcNumber < 8; funcNumber++) { 02779 02780 slotData.u.bits.FunctionNumber = funcNumber; 02781 02782 busDataRead = ScsiPortGetBusData(HwDeviceExtension, 02783 PCIConfiguration, 02784 ConfigInfo->SystemIoBusNumber, 02785 slotData.u.AsULONG, 02786 &pciData, 02787 sizeof (pciData)); 02788 if (busDataRead != sizeof (pciData)) { 02789 return SP_RETURN_ERROR; 02790 } 02791 if (pciData.VendorID == PCI_INVALID_VENDORID) { 02792 return SP_RETURN_ERROR; 02793 } 02794 02795 // 02796 // Translate hex ids to strings. 02797 // 02798 02799 vendorStrPtr = vendorString; 02800 deviceStrPtr = deviceString; 02801 AtapiHexToString(pciData.VendorID, (PCHAR*)&vendorStrPtr); 02802 AtapiHexToString(pciData.DeviceID, (PCHAR*)&deviceStrPtr); 02803 02804 // 02805 // Compare strings. 02806 // 02807 02808 if (AtapiStringCmp((PCHAR)vendorString, 02809 NativeModeAdapters[nativeModeAdapterTableIndex].VendorId, 02810 NativeModeAdapters[nativeModeAdapterTableIndex].VendorIdLength) || 02811 AtapiStringCmp((PCHAR)deviceString, 02812 NativeModeAdapters[nativeModeAdapterTableIndex].DeviceId, 02813 NativeModeAdapters[nativeModeAdapterTableIndex].DeviceIdLength)) { 02814 continue; 02815 } 02816 02817 if (pciData.ProgIf & ((1 << 2) | (1 << 0))) { 02818 // both primary and secondary channel are in native mode 02819 02820 // Found our device 02821 *Again = TRUE; 02822 02823 break; 02824 } 02825 } 02826 02827 if (*Again == TRUE) { 02828 02829 for (channel = 0; channel < 2; channel++) { 02830 02831 IoBasePort1 = (*ConfigInfo->AccessRanges)[channel * 2 + 0].RangeStart; 02832 IoBasePort2 = (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeStart; 02833 IoBasePort2 = ScsiPortConvertUlongToPhysicalAddress(ScsiPortConvertPhysicalAddressToUlong(IoBasePort2) + 2); 02834 02835 // 02836 // Get the system physical address for this IO range. 02837 // 02838 02839 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 02840 ConfigInfo->AdapterInterfaceType, 02841 ConfigInfo->SystemIoBusNumber, 02842 IoBasePort1, 02843 8, 02844 TRUE); 02845 02846 // 02847 // Check if ioSpace accessible. 02848 // 02849 02850 if (!ioSpace) { 02851 continue; 02852 } 02853 02854 // 02855 // Select master. 02856 // 02857 02858 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xA0); 02859 02860 // 02861 // Check if card at this address. 02862 // 02863 02864 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 02865 02866 // 02867 // Check if indentifier can be read back. 02868 // 02869 02870 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 02871 02872 DebugPrint((2, 02873 "AtapiFindPciController: Identifier read back from Master (%x)\n", 02874 statusByte)); 02875 02876 02877 // 02878 // Select slave. 02879 // 02880 02881 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xB0); 02882 02883 // 02884 // See if slave is present. 02885 // 02886 02887 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 02888 02889 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 02890 02891 DebugPrint((2, 02892 "AtapiFindPciController: Identifier read back from Slave (%x)\n", 02893 statusByte)); 02894 02895 // 02896 // 02897 // No controller at this base address. 02898 // 02899 02900 ScsiPortFreeDeviceBase(HwDeviceExtension, 02901 ioSpace); 02902 02903 // 02904 // If the chip is there, but we couldn't find the primary channel, try the secondary. 02905 // If we couldn't find a secondary, who cares. 02906 // 02907 02908 if (channel == 1) { 02909 02910 goto setStatusAndExit; 02911 02912 } else { 02913 continue; 02914 } 02915 } 02916 } 02917 02918 // 02919 // Record base IO address. 02920 // 02921 02922 deviceExtension->BaseIoAddress1[channel] = (PIDE_REGISTERS_1)(ioSpace); 02923 02924 // 02925 // Get the system physical address for the second IO range. 02926 // 02927 02928 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 02929 ConfigInfo->AdapterInterfaceType, 02930 ConfigInfo->SystemIoBusNumber, 02931 IoBasePort2, 02932 1, 02933 TRUE); 02934 02935 deviceExtension->BaseIoAddress2[channel] = (PIDE_REGISTERS_2)(ioSpace); 02936 02937 deviceExtension->NumberChannels = 2; 02938 02939 // 02940 // Indicate only one bus. 02941 // 02942 02943 ConfigInfo->NumberOfBuses = 1; 02944 02945 // 02946 // Indicate four devices can be attached to the adapter, since we 02947 // have to serialize access to the two channels. 02948 // 02949 02950 ConfigInfo->MaximumNumberOfTargets = 4; 02951 02952 // 02953 // Indicate maximum transfer length is 64k. 02954 // 02955 02956 ConfigInfo->MaximumTransferLength = 0x10000; 02957 02958 DebugPrint((1, 02959 "AtapiFindPciController: Found native mode IDE at %x\n", 02960 deviceExtension->BaseIoAddress1[channel])); 02961 02962 // 02963 // Since we will always pick up this part, and not atdisk, so indicate. 02964 // 02965 02966 atapiOnly = FALSE; 02967 02968 // 02969 // Save the Interrupe Mode for later use 02970 // 02971 deviceExtension->InterruptMode = ConfigInfo->InterruptMode; 02972 02973 // 02974 // Search for devices on this controller. 02975 // 02976 02977 if (FindDevices(HwDeviceExtension, 02978 atapiOnly, 02979 channel)){ 02980 deviceFound = TRUE; 02981 } 02982 02983 // 02984 // Claim primary or secondary ATA IO range. 02985 // 02986 02987 if (ScsiPortConvertPhysicalAddressToUlong(IoBasePort1) == AdapterAddresses[0]) { 02988 ConfigInfo->AtdiskPrimaryClaimed = TRUE; 02989 deviceExtension->PrimaryAddress = TRUE; 02990 02991 } else if (ScsiPortConvertPhysicalAddressToUlong(IoBasePort2) == AdapterAddresses[1]) { 02992 ConfigInfo->AtdiskSecondaryClaimed = TRUE; 02993 deviceExtension->PrimaryAddress = FALSE; 02994 } 02995 } 02996 } 02997 02998 setStatusAndExit: 02999 03000 if (deviceFound) { 03001 03002 *Again = TRUE; 03003 return SP_RETURN_FOUND; 03004 } 03005 03006 *Again = FALSE; 03007 return SP_RETURN_NOT_FOUND; 03008 03009 } // end AtapiFindNativeModeController() 03010 03011 03012 ULONG 03013 NTAPI 03014 AtapiFindPCIController( 03015 IN PVOID HwDeviceExtension, 03016 IN PVOID Context, 03017 IN PVOID BusInformation, 03018 IN PCHAR ArgumentString, 03019 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, 03020 OUT PBOOLEAN Again 03021 ) 03022 /*++ 03023 03024 Routine Description: 03025 03026 This function is called by the OS-specific port driver after 03027 the necessary storage has been allocated, to gather information 03028 about the adapter's configuration. 03029 03030 Arguments: 03031 03032 HwDeviceExtension - HBA miniport driver's adapter data storage 03033 Context - Address of adapter count 03034 BusInformation - 03035 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility. 03036 ConfigInfo - Configuration information structure describing HBA 03037 Again - Indicates search for adapters to continue 03038 03039 Return Value: 03040 03041 ULONG 03042 03043 --*/ 03044 03045 { 03046 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 03047 PULONG adapterCount = (PULONG)Context; 03048 ULONG channel = 0; 03049 static ULONG functionNumber, 03050 slotNumber, 03051 controllers; 03052 ULONG i,j; 03053 PUCHAR ioSpace; 03054 BOOLEAN atapiOnly, 03055 lastSlot, 03056 controllerFound = FALSE, 03057 deviceFound = FALSE; 03058 UCHAR statusByte; 03059 03060 // 03061 // The following table specifies the ports to be checked when searching for 03062 // an IDE controller. A zero entry terminates the search. 03063 // 03064 03065 CONST ULONG AdapterAddresses[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0}; 03066 03067 // 03068 // The following table specifies interrupt levels corresponding to the 03069 // port addresses in the previous table. 03070 // 03071 03072 CONST ULONG InterruptLevels[5] = {14, 15, 11, 10, 0}; 03073 03074 if (!deviceExtension) { 03075 return SP_RETURN_ERROR; 03076 } 03077 03078 // 03079 // Since scsiport will call this function first before it calls AtapiFindController 03080 // we need to bypass it if we have data installed in ConfigInfo, by the pcmcia driver. 03081 // In that case atapifindcontroller should be called first. 03082 // Instead of modifying atapi driverEntry to search of PCIBus first (now its ISA) 03083 // the check is put here. 03084 // 03085 03086 if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart) != 0) { 03087 03088 return AtapiFindController(HwDeviceExtension, 03089 Context, 03090 BusInformation, 03091 ArgumentString, 03092 ConfigInfo, 03093 Again); 03094 } 03095 03096 03097 // 03098 // Gronk PCI config space looking for the broken PCI IDE controllers that have only 03099 // one FIFO for both channels. 03100 // Don't do this. It's incorrect and nasty. It has to be done to work around these 03101 // broken parts, no other reason can justify this. 03102 // 03103 03104 for (i = controllers; i < BROKEN_ADAPTERS; i++) { 03105 03106 // 03107 // Determine if both channels are enabled and have devices. 03108 // 03109 03110 lastSlot = FALSE; 03111 03112 if (FindBrokenController(deviceExtension, 03113 (PUCHAR)BrokenAdapters[i].VendorId, 03114 BrokenAdapters[i].VendorIdLength, 03115 (PUCHAR)BrokenAdapters[i].DeviceId, 03116 BrokenAdapters[i].DeviceIdLength, 03117 &functionNumber, 03118 &slotNumber, 03119 ConfigInfo->SystemIoBusNumber, 03120 &lastSlot)) { 03121 03122 slotNumber++; 03123 functionNumber = 0; 03124 controllerFound = TRUE; 03125 03126 DebugPrint((1, 03127 "Found broken PCI IDE controller: VendorId %s, DeviceId %s\n", 03128 BrokenAdapters[i].VendorId, 03129 BrokenAdapters[i].DeviceId)); 03130 03131 if (AdapterAddresses[*adapterCount] != 0) { 03132 03133 for (j = 0; j < 2; j++) { 03134 03135 // 03136 // Get the system physical address for this IO range. 03137 // 03138 03139 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 03140 ConfigInfo->AdapterInterfaceType, 03141 ConfigInfo->SystemIoBusNumber, 03142 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]), 03143 8, 03144 TRUE); 03145 03146 // 03147 // Update the adapter count. 03148 // 03149 03150 (*adapterCount)++; 03151 03152 // 03153 // Check if ioSpace accessible. 03154 // 03155 03156 if (!ioSpace) { 03157 continue; 03158 } 03159 03160 // 03161 // Select master. 03162 // 03163 03164 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xA0); 03165 03166 // 03167 // Check if card at this address. 03168 // 03169 03170 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 03171 03172 // 03173 // Check if indentifier can be read back. 03174 // 03175 03176 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 03177 03178 DebugPrint((2, 03179 "AtapiFindPciController: Identifier read back from Master (%x)\n", 03180 statusByte)); 03181 03182 03183 // 03184 // Select slave. 03185 // 03186 03187 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xB0); 03188 03189 // 03190 // See if slave is present. 03191 // 03192 03193 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA); 03194 03195 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { 03196 03197 DebugPrint((2, 03198 "AtapiFindPciController: Identifier read back from Slave (%x)\n", 03199 statusByte)); 03200 03201 // 03202 // 03203 // No controller at this base address. 03204 // 03205 03206 ScsiPortFreeDeviceBase(HwDeviceExtension, 03207 ioSpace); 03208 03209 // 03210 // If the chip is there, but we couldn't find the primary channel, try the secondary. 03211 // If we couldn't find a secondary, who cares. 03212 // 03213 03214 if (j == 1) { 03215 03216 goto setStatusAndExit; 03217 03218 } else { 03219 continue; 03220 } 03221 } 03222 } 03223 03224 if (controllerFound) { 03225 03226 // 03227 // Record base IO address. 03228 // 03229 03230 deviceExtension->BaseIoAddress1[channel] = (PIDE_REGISTERS_1)(ioSpace); 03231 03232 // 03233 // Fill in the access array information. 03234 // 03235 03236 (*ConfigInfo->AccessRanges)[channel].RangeStart = 03237 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]); 03238 03239 (*ConfigInfo->AccessRanges)[channel].RangeLength = 8; 03240 (*ConfigInfo->AccessRanges)[channel].RangeInMemory = FALSE; 03241 03242 // 03243 // Indicate the interrupt level corresponding to this IO range. 03244 // 03245 03246 if (channel == 0) { 03247 ConfigInfo->BusInterruptLevel = InterruptLevels[*adapterCount - 1]; 03248 ConfigInfo->InterruptMode = Latched; 03249 } else { 03250 ConfigInfo->BusInterruptLevel2 = InterruptLevels[*adapterCount - 1]; 03251 ConfigInfo->InterruptMode2 = Latched; 03252 } 03253 03254 // 03255 // Get the system physical address for the second IO range. 03256 // 03257 03258 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, 03259 ConfigInfo->AdapterInterfaceType, 03260 ConfigInfo->SystemIoBusNumber, 03261 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1] + 0x206), 03262 1, 03263 TRUE); 03264 03265 deviceExtension->BaseIoAddress2[channel] = (PIDE_REGISTERS_2)(ioSpace); 03266 03267 deviceExtension->NumberChannels = 2; 03268 03269 // 03270 // Indicate only one bus. 03271 // 03272 03273 ConfigInfo->NumberOfBuses = 1; 03274 03275 // 03276 // Indicate four devices can be attached to the adapter, since we 03277 // have to serialize access to the two channels. 03278 // 03279 03280 ConfigInfo->MaximumNumberOfTargets = 4; 03281 03282 // 03283 // Indicate maximum transfer length is 64k. 03284 // 03285 03286 ConfigInfo->MaximumTransferLength = 0x10000; 03287 03288 DebugPrint((1, 03289 "AtapiFindPciController: Found broken IDE at %x\n", 03290 deviceExtension->BaseIoAddress1[channel])); 03291 03292 // 03293 // Since we will always pick up this part, and not atdisk, so indicate. 03294 // 03295 03296 atapiOnly = FALSE; 03297 03298 // 03299 // Save the Interrupe Mode for later use 03300 // 03301 deviceExtension->InterruptMode = ConfigInfo->InterruptMode; 03302 03303 // 03304 // Search for devices on this controller. 03305 // 03306 03307 if (FindDevices(HwDeviceExtension, 03308 atapiOnly, 03309 channel++)){ 03310 deviceFound = TRUE; 03311 } 03312 03313 // 03314 // Claim primary or secondary ATA IO range. 03315 // 03316 03317 if (*adapterCount == 1) { 03318 ConfigInfo->AtdiskPrimaryClaimed = TRUE; 03319 deviceExtension->PrimaryAddress = TRUE; 03320 03321 } else if (*adapterCount == 2) { 03322 ConfigInfo->AtdiskSecondaryClaimed = TRUE; 03323 deviceExtension->PrimaryAddress = FALSE; 03324 } 03325 } 03326 } 03327 } 03328 } 03329 03330 setStatusAndExit: 03331 03332 if (lastSlot) { 03333 slotNumber = 0; 03334 functionNumber = 0; 03335 } 03336 03337 controllers = i; 03338 03339 if (controllerFound && deviceFound) { 03340 03341 *Again = TRUE; 03342 return SP_RETURN_FOUND; 03343 } 03344 } 03345 03346 03347 // 03348 // The entire table has been searched and no adapters have been found. 03349 // 03350 03351 *Again = FALSE; 03352 03353 return SP_RETURN_NOT_FOUND; 03354 03355 } // end AtapiFindPCIController() 03356 03357 03358 ULONG 03359 NTAPI 03360 Atapi2Scsi( 03361 IN PSCSI_REQUEST_BLOCK Srb, 03362 IN char *DataBuffer, 03363 IN ULONG ByteCount 03364 ) 03365 { 03366 ULONG bytesAdjust = 0; 03367 if (Srb->Cdb[0] == ATAPI_MODE_SENSE) { 03368 03369 PMODE_PARAMETER_HEADER_10 header_10 = (PMODE_PARAMETER_HEADER_10)DataBuffer; 03370 PMODE_PARAMETER_HEADER header = (PMODE_PARAMETER_HEADER)DataBuffer; 03371 03372 header->ModeDataLength = header_10->ModeDataLengthLsb; 03373 header->MediumType = header_10->MediumType; 03374 03375 // 03376 // ATAPI Mode Parameter Header doesn't have these fields. 03377 // 03378 03379 header->DeviceSpecificParameter = header_10->Reserved[0]; 03380 header->BlockDescriptorLength = header_10->Reserved[1]; 03381 03382 ByteCount -= sizeof(MODE_PARAMETER_HEADER_10); 03383 if (ByteCount > 0) 03384 ScsiPortMoveMemory(DataBuffer+sizeof(MODE_PARAMETER_HEADER), 03385 DataBuffer+sizeof(MODE_PARAMETER_HEADER_10), 03386 ByteCount); 03387 03388 // 03389 // Change ATAPI_MODE_SENSE opcode back to SCSIOP_MODE_SENSE 03390 // so that we don't convert again. 03391 // 03392 03393 Srb->Cdb[0] = SCSIOP_MODE_SENSE; 03394 03395 bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) - 03396 sizeof(MODE_PARAMETER_HEADER); 03397 03398 03399 } 03400 03401 // 03402 // Convert to words. 03403 // 03404 03405 return bytesAdjust >> 1; 03406 } 03407 03408 03409 VOID 03410 NTAPI 03411 AtapiCallBack( 03412 IN PVOID HwDeviceExtension 03413 ) 03414 { 03415 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 03416 PSCSI_REQUEST_BLOCK srb = deviceExtension->CurrentSrb; 03417 PATAPI_REGISTERS_2 baseIoAddress2; 03418 UCHAR statusByte; 03419 03420 // 03421 // If the last command was DSC restrictive, see if it's set. If so, the device is 03422 // ready for a new request. Otherwise, reset the timer and come back to here later. 03423 // 03424 03425 if (srb && (!(deviceExtension->ExpectingInterrupt))) { 03426 #if DBG 03427 if (!IS_RDP((srb->Cdb[0]))) { 03428 DebugPrint((1, 03429 "AtapiCallBack: Invalid CDB marked as RDP - %x\n", 03430 srb->Cdb[0])); 03431 } 03432 #endif 03433 03434 baseIoAddress2 = (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[srb->TargetId >> 1]; 03435 if (deviceExtension->RDP) { 03436 GetStatus(baseIoAddress2, statusByte); 03437 if (statusByte & IDE_STATUS_DSC) { 03438 03439 ScsiPortNotification(RequestComplete, 03440 deviceExtension, 03441 srb); 03442 03443 // 03444 // Clear current SRB. 03445 // 03446 03447 deviceExtension->CurrentSrb = NULL; 03448 deviceExtension->RDP = FALSE; 03449 03450 // 03451 // Ask for next request. 03452 // 03453 03454 ScsiPortNotification(NextRequest, 03455 deviceExtension, 03456 NULL); 03457 03458 03459 return; 03460 03461 } else { 03462 03463 DebugPrint((3, 03464 "AtapiCallBack: Requesting another timer for Op %x\n", 03465 deviceExtension->CurrentSrb->Cdb[0])); 03466 03467 ScsiPortNotification(RequestTimerCall, 03468 HwDeviceExtension, 03469 AtapiCallBack, 03470 1000); 03471 return; 03472 } 03473 } 03474 } 03475 03476 DebugPrint((2, 03477 "AtapiCallBack: Calling ISR directly due to BUSY\n")); 03478 AtapiInterrupt(HwDeviceExtension); 03479 } 03480 03481 03482 BOOLEAN 03483 NTAPI 03484 AtapiInterrupt( 03485 IN PVOID HwDeviceExtension 03486 ) 03487 03488 /*++ 03489 03490 Routine Description: 03491 03492 This is the interrupt service routine for ATAPI IDE miniport driver. 03493 03494 Arguments: 03495 03496 HwDeviceExtension - HBA miniport driver's adapter data storage 03497 03498 Return Value: 03499 03500 TRUE if expecting an interrupt. 03501 03502 --*/ 03503 03504 { 03505 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 03506 PSCSI_REQUEST_BLOCK srb = deviceExtension->CurrentSrb; 03507 PATAPI_REGISTERS_1 baseIoAddress1; 03508 PATAPI_REGISTERS_2 baseIoAddress2; 03509 ULONG wordCount = 0, wordsThisInterrupt = 256; 03510 ULONG status; 03511 ULONG i; 03512 UCHAR statusByte,interruptReason; 03513 BOOLEAN atapiDev = FALSE; 03514 03515 if (srb) { 03516 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[srb->TargetId >> 1]; 03517 baseIoAddress2 = (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[srb->TargetId >> 1]; 03518 } else { 03519 DebugPrint((2, 03520 "AtapiInterrupt: CurrentSrb is NULL\n")); 03521 // 03522 // We can only support one ATAPI IDE master on Carolina, so find 03523 // the base address that is non NULL and clear its interrupt before 03524 // returning. 03525 // 03526 03527 #ifdef _PPC_ 03528 03529 if ((PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0] != NULL) { 03530 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0]; 03531 } else { 03532 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[1]; 03533 } 03534 03535 GetBaseStatus(baseIoAddress1, statusByte); 03536 #else 03537 03538 if (deviceExtension->InterruptMode == LevelSensitive) { 03539 if (deviceExtension->BaseIoAddress1[0] != NULL) { 03540 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0]; 03541 GetBaseStatus(baseIoAddress1, statusByte); 03542 } 03543 if (deviceExtension->BaseIoAddress1[1] != NULL) { 03544 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[1]; 03545 GetBaseStatus(baseIoAddress1, statusByte); 03546 } 03547 } 03548 #endif 03549 return FALSE; 03550 } 03551 03552 if (!(deviceExtension->ExpectingInterrupt)) { 03553 03554 DebugPrint((3, 03555 "AtapiInterrupt: Unexpected interrupt.\n")); 03556 return FALSE; 03557 } 03558 03559 // 03560 // Clear interrupt by reading status. 03561 // 03562 03563 GetBaseStatus(baseIoAddress1, statusByte); 03564 03565 DebugPrint((3, 03566 "AtapiInterrupt: Entered with status (%x)\n", 03567 statusByte)); 03568 03569 03570 if (statusByte & IDE_STATUS_BUSY) { 03571 if (deviceExtension->DriverMustPoll) { 03572 03573 // 03574 // Crashdump is polling and we got caught with busy asserted. 03575 // Just go away, and we will be polled again shortly. 03576 // 03577 03578 DebugPrint((3, 03579 "AtapiInterrupt: Hit BUSY while polling during crashdump.\n")); 03580 03581 return TRUE; 03582 } 03583 03584 // 03585 // Ensure BUSY is non-asserted. 03586 // 03587 03588 for (i = 0; i < 10; i++) { 03589 03590 GetBaseStatus(baseIoAddress1, statusByte); 03591 if (!(statusByte & IDE_STATUS_BUSY)) { 03592 break; 03593 } 03594 ScsiPortStallExecution(5000); 03595 } 03596 03597 if (i == 10) { 03598 03599 DebugPrint((2, 03600 "AtapiInterrupt: BUSY on entry. Status %x, Base IO %x\n", 03601 statusByte, 03602 baseIoAddress1)); 03603 03604 ScsiPortNotification(RequestTimerCall, 03605 HwDeviceExtension, 03606 AtapiCallBack, 03607 500); 03608 return TRUE; 03609 } 03610 } 03611 03612 03613 // 03614 // Check for error conditions. 03615 // 03616 03617 if (statusByte & IDE_STATUS_ERROR) { 03618 03619 if (srb->Cdb[0] != SCSIOP_REQUEST_SENSE) { 03620 03621 // 03622 // Fail this request. 03623 // 03624 03625 status = SRB_STATUS_ERROR; 03626 goto CompleteRequest; 03627 } 03628 } 03629 03630 // 03631 // check reason for this interrupt. 03632 // 03633 03634 if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 03635 03636 interruptReason = (ScsiPortReadPortUchar(&baseIoAddress1->InterruptReason) & 0x3); 03637 atapiDev = TRUE; 03638 wordsThisInterrupt = 256; 03639 03640 } else { 03641 03642 if (statusByte & IDE_STATUS_DRQ) { 03643 03644 if (deviceExtension->MaximumBlockXfer[srb->TargetId]) { 03645 wordsThisInterrupt = 256 * deviceExtension->MaximumBlockXfer[srb->TargetId]; 03646 03647 } 03648 03649 if (srb->SrbFlags & SRB_FLAGS_DATA_IN) { 03650 03651 interruptReason = 0x2; 03652 03653 } else if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) { 03654 interruptReason = 0x0; 03655 03656 } else { 03657 status = SRB_STATUS_ERROR; 03658 goto CompleteRequest; 03659 } 03660 03661 } else if (statusByte & IDE_STATUS_BUSY) { 03662 03663 return FALSE; 03664 03665 } else { 03666 03667 if (deviceExtension->WordsLeft) { 03668 03669 ULONG k; 03670 03671 // 03672 // Funky behaviour seen with PCI IDE (not all, just one). 03673 // The ISR hits with DRQ low, but comes up later. 03674 // 03675 03676 for (k = 0; k < 5000; k++) { 03677 GetStatus(baseIoAddress2,statusByte); 03678 if (!(statusByte & IDE_STATUS_DRQ)) { 03679 ScsiPortStallExecution(100); 03680 } else { 03681 break; 03682 } 03683 } 03684 03685 if (k == 5000) { 03686 03687 // 03688 // reset the controller. 03689 // 03690 03691 DebugPrint((1, 03692 "AtapiInterrupt: Resetting due to DRQ not up. Status %x, Base IO %x\n", 03693 statusByte, 03694 baseIoAddress1)); 03695 03696 AtapiResetController(HwDeviceExtension,srb->PathId); 03697 return TRUE; 03698 } else { 03699 03700 interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x2 : 0x0; 03701 } 03702 03703 } else { 03704 03705 // 03706 // Command complete - verify, write, or the SMART enable/disable. 03707 // 03708 // Also get_media_status 03709 03710 interruptReason = 0x3; 03711 } 03712 } 03713 } 03714 03715 if (interruptReason == 0x1 && (statusByte & IDE_STATUS_DRQ)) { 03716 03717 // 03718 // Write the packet. 03719 // 03720 03721 DebugPrint((2, 03722 "AtapiInterrupt: Writing Atapi packet.\n")); 03723 03724 // 03725 // Send CDB to device. 03726 // 03727 03728 WriteBuffer(baseIoAddress1, 03729 (PUSHORT)srb->Cdb, 03730 6); 03731 03732 return TRUE; 03733 03734 } else if (interruptReason == 0x0 && (statusByte & IDE_STATUS_DRQ)) { 03735 03736 // 03737 // Write the data. 03738 // 03739 03740 if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 03741 03742 // 03743 // Pick up bytes to transfer and convert to words. 03744 // 03745 03746 wordCount = 03747 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow); 03748 03749 wordCount |= 03750 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh) << 8; 03751 03752 // 03753 // Covert bytes to words. 03754 // 03755 03756 wordCount >>= 1; 03757 03758 if (wordCount != deviceExtension->WordsLeft) { 03759 DebugPrint((3, 03760 "AtapiInterrupt: %d words requested; %d words xferred\n", 03761 deviceExtension->WordsLeft, 03762 wordCount)); 03763 } 03764 03765 // 03766 // Verify this makes sense. 03767 // 03768 03769 if (wordCount > deviceExtension->WordsLeft) { 03770 wordCount = deviceExtension->WordsLeft; 03771 } 03772 03773 } else { 03774 03775 // 03776 // IDE path. Check if words left is at least 256. 03777 // 03778 03779 if (deviceExtension->WordsLeft < wordsThisInterrupt) { 03780 03781 // 03782 // Transfer only words requested. 03783 // 03784 03785 wordCount = deviceExtension->WordsLeft; 03786 03787 } else { 03788 03789 // 03790 // Transfer next block. 03791 // 03792 03793 wordCount = wordsThisInterrupt; 03794 } 03795 } 03796 03797 // 03798 // Ensure that this is a write command. 03799 // 03800 03801 if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) { 03802 03803 DebugPrint((3, 03804 "AtapiInterrupt: Write interrupt\n")); 03805 03806 WaitOnBusy(baseIoAddress2,statusByte); 03807 03808 if (atapiDev || !deviceExtension->DWordIO) { 03809 03810 WriteBuffer(baseIoAddress1, 03811 deviceExtension->DataBuffer, 03812 wordCount); 03813 } else { 03814 03815 PIDE_REGISTERS_3 address3 = (PIDE_REGISTERS_3)baseIoAddress1; 03816 03817 WriteBuffer2(address3, 03818 (PULONG)(deviceExtension->DataBuffer), 03819 wordCount / 2); 03820 } 03821 } else { 03822 03823 DebugPrint((1, 03824 "AtapiInterrupt: Int reason %x, but srb is for a write %x.\n", 03825 interruptReason, 03826 srb)); 03827 03828 // 03829 // Fail this request. 03830 // 03831 03832 status = SRB_STATUS_ERROR; 03833 goto CompleteRequest; 03834 } 03835 03836 03837 // 03838 // Advance data buffer pointer and bytes left. 03839 // 03840 03841 deviceExtension->DataBuffer += wordCount; 03842 deviceExtension->WordsLeft -= wordCount; 03843 03844 return TRUE; 03845 03846 } else if (interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) { 03847 03848 03849 if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 03850 03851 // 03852 // Pick up bytes to transfer and convert to words. 03853 // 03854 03855 wordCount = 03856 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow); 03857 03858 wordCount |= 03859 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh) << 8; 03860 03861 // 03862 // Covert bytes to words. 03863 // 03864 03865 wordCount >>= 1; 03866 03867 if (wordCount != deviceExtension->WordsLeft) { 03868 DebugPrint((3, 03869 "AtapiInterrupt: %d words requested; %d words xferred\n", 03870 deviceExtension->WordsLeft, 03871 wordCount)); 03872 } 03873 03874 // 03875 // Verify this makes sense. 03876 // 03877 03878 if (wordCount > deviceExtension->WordsLeft) { 03879 wordCount = deviceExtension->WordsLeft; 03880 } 03881 03882 } else { 03883 03884 // 03885 // Check if words left is at least 256. 03886 // 03887 03888 if (deviceExtension->WordsLeft < wordsThisInterrupt) { 03889 03890 // 03891 // Transfer only words requested. 03892 // 03893 03894 wordCount = deviceExtension->WordsLeft; 03895 03896 } else { 03897 03898 // 03899 // Transfer next block. 03900 // 03901 03902 wordCount = wordsThisInterrupt; 03903 } 03904 } 03905 03906 // 03907 // Ensure that this is a read command. 03908 // 03909 03910 if (srb->SrbFlags & SRB_FLAGS_DATA_IN) { 03911 03912 DebugPrint((3, 03913 "AtapiInterrupt: Read interrupt\n")); 03914 03915 WaitOnBusy(baseIoAddress2,statusByte); 03916 03917 if (atapiDev || !deviceExtension->DWordIO) { 03918 ReadBuffer(baseIoAddress1, 03919 deviceExtension->DataBuffer, 03920 wordCount); 03921 03922 } else { 03923 PIDE_REGISTERS_3 address3 = (PIDE_REGISTERS_3)baseIoAddress1; 03924 03925 ReadBuffer2(address3, 03926 (PULONG)(deviceExtension->DataBuffer), 03927 wordCount / 2); 03928 } 03929 } else { 03930 03931 DebugPrint((1, 03932 "AtapiInterrupt: Int reason %x, but srb is for a read %x.\n", 03933 interruptReason, 03934 srb)); 03935 03936 // 03937 // Fail this request. 03938 // 03939 03940 status = SRB_STATUS_ERROR; 03941 goto CompleteRequest; 03942 } 03943 03944 // 03945 // Translate ATAPI data back to SCSI data if needed 03946 // 03947 03948 if (srb->Cdb[0] == ATAPI_MODE_SENSE && 03949 deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 03950 03951 // 03952 //convert and adjust the wordCount 03953 // 03954 03955 wordCount -= Atapi2Scsi(srb, (char *)deviceExtension->DataBuffer, 03956 wordCount << 1); 03957 } 03958 // 03959 // Advance data buffer pointer and bytes left. 03960 // 03961 03962 deviceExtension->DataBuffer += wordCount; 03963 deviceExtension->WordsLeft -= wordCount; 03964 03965 // 03966 // Check for read command complete. 03967 // 03968 03969 if (deviceExtension->WordsLeft == 0) { 03970 03971 if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 03972 03973 // 03974 // Work around to make many atapi devices return correct sector size 03975 // of 2048. Also certain devices will have sector count == 0x00, check 03976 // for that also. 03977 // 03978 03979 if ((srb->Cdb[0] == 0x25) && 03980 ((deviceExtension->IdentifyData[srb->TargetId].GeneralConfiguration >> 8) & 0x1f) == 0x05) { 03981 03982 deviceExtension->DataBuffer -= wordCount; 03983 if (deviceExtension->DataBuffer[0] == 0x00) { 03984 03985 *((ULONG *) &(deviceExtension->DataBuffer[0])) = 0xFFFFFF7F; 03986 03987 } 03988 03989 *((ULONG *) &(deviceExtension->DataBuffer[2])) = 0x00080000; 03990 deviceExtension->DataBuffer += wordCount; 03991 } 03992 } else { 03993 03994 // 03995 // Completion for IDE drives. 03996 // 03997 03998 03999 if (deviceExtension->WordsLeft) { 04000 04001 status = SRB_STATUS_DATA_OVERRUN; 04002 04003 } else { 04004 04005 status = SRB_STATUS_SUCCESS; 04006 04007 } 04008 04009 goto CompleteRequest; 04010 04011 } 04012 } 04013 04014 return TRUE; 04015 04016 } else if (interruptReason == 0x3 && !(statusByte & IDE_STATUS_DRQ)) { 04017 04018 // 04019 // Command complete. 04020 // 04021 04022 if (deviceExtension->WordsLeft) { 04023 04024 status = SRB_STATUS_DATA_OVERRUN; 04025 04026 } else { 04027 04028 status = SRB_STATUS_SUCCESS; 04029 04030 } 04031 04032 CompleteRequest: 04033 04034 // 04035 // Check and see if we are processing our secret (mechanism status/request sense) srb 04036 // 04037 if (deviceExtension->OriginalSrb) { 04038 04039 ULONG srbStatus; 04040 04041 if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) { 04042 04043 if (status == SRB_STATUS_SUCCESS) { 04044 // Bingo!! 04045 AtapiHwInitializeChanger (HwDeviceExtension, 04046 srb->TargetId, 04047 (PMECHANICAL_STATUS_INFORMATION_HEADER) srb->DataBuffer); 04048 04049 // Get ready to issue the original srb 04050 srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb; 04051 deviceExtension->OriginalSrb = NULL; 04052 04053 } else { 04054 // failed! Get the sense key and maybe try again 04055 srb = deviceExtension->CurrentSrb = BuildRequestSenseSrb ( 04056 HwDeviceExtension, 04057 deviceExtension->OriginalSrb->PathId, 04058 deviceExtension->OriginalSrb->TargetId); 04059 } 04060 04061 srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb); 04062 if (srbStatus == SRB_STATUS_PENDING) { 04063 return TRUE; 04064 } 04065 04066 } else { // srb->Cdb[0] == SCSIOP_REQUEST_SENSE) 04067 04068 PSENSE_DATA senseData = (PSENSE_DATA) srb->DataBuffer; 04069 04070 if (status == SRB_STATUS_DATA_OVERRUN) { 04071 // Check to see if we at least get mininum number of bytes 04072 if ((srb->DataTransferLength - deviceExtension->WordsLeft) > 04073 (FIELD_OFFSET (SENSE_DATA, AdditionalSenseLength) + sizeof(senseData->AdditionalSenseLength))) { 04074 status = SRB_STATUS_SUCCESS; 04075 } 04076 } 04077 04078 if (status == SRB_STATUS_SUCCESS) { 04079 if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) && 04080 deviceExtension->MechStatusRetryCount) { 04081 04082 // The sense key doesn't say the last request is illegal, so try again 04083 deviceExtension->MechStatusRetryCount--; 04084 srb = deviceExtension->CurrentSrb = BuildMechanismStatusSrb ( 04085 HwDeviceExtension, 04086 deviceExtension->OriginalSrb->PathId, 04087 deviceExtension->OriginalSrb->TargetId); 04088 } else { 04089 04090 // last request was illegal. No point trying again 04091 04092 AtapiHwInitializeChanger (HwDeviceExtension, 04093 srb->TargetId, 04094 (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL); 04095 04096 // Get ready to issue the original srb 04097 srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb; 04098 deviceExtension->OriginalSrb = NULL; 04099 } 04100 04101 srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb); 04102 if (srbStatus == SRB_STATUS_PENDING) { 04103 return TRUE; 04104 } 04105 } 04106 } 04107 04108 // If we get here, it means AtapiSendCommand() has failed 04109 // Can't recover. Pretend the original srb has failed and complete it. 04110 04111 if (deviceExtension->OriginalSrb) { 04112 AtapiHwInitializeChanger (HwDeviceExtension, 04113 srb->TargetId, 04114 (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL); 04115 srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb; 04116 deviceExtension->OriginalSrb = NULL; 04117 } 04118 04119 // fake an error and read no data 04120 status = SRB_STATUS_ERROR; 04121 srb->ScsiStatus = 0; 04122 deviceExtension->DataBuffer = srb->DataBuffer; 04123 deviceExtension->WordsLeft = srb->DataTransferLength; 04124 deviceExtension->RDP = FALSE; 04125 04126 } else if (status == SRB_STATUS_ERROR) { 04127 04128 // 04129 // Map error to specific SRB status and handle request sense. 04130 // 04131 04132 status = MapError(deviceExtension, 04133 srb); 04134 04135 deviceExtension->RDP = FALSE; 04136 04137 } else { 04138 04139 // 04140 // Wait for busy to drop. 04141 // 04142 04143 for (i = 0; i < 30; i++) { 04144 GetStatus(baseIoAddress2,statusByte); 04145 if (!(statusByte & IDE_STATUS_BUSY)) { 04146 break; 04147 } 04148 ScsiPortStallExecution(500); 04149 } 04150 04151 if (i == 30) { 04152 04153 // 04154 // reset the controller. 04155 // 04156 04157 DebugPrint((1, 04158 "AtapiInterrupt: Resetting due to BSY still up - %x. Base Io %x\n", 04159 statusByte, 04160 baseIoAddress1)); 04161 AtapiResetController(HwDeviceExtension,srb->PathId); 04162 return TRUE; 04163 } 04164 04165 // 04166 // Check to see if DRQ is still up. 04167 // 04168 04169 if (statusByte & IDE_STATUS_DRQ) { 04170 04171 for (i = 0; i < 500; i++) { 04172 GetStatus(baseIoAddress2,statusByte); 04173 if (!(statusByte & IDE_STATUS_DRQ)) { 04174 break; 04175 } 04176 ScsiPortStallExecution(100); 04177 04178 } 04179 04180 if (i == 500) { 04181 04182 // 04183 // reset the controller. 04184 // 04185 04186 DebugPrint((1, 04187 "AtapiInterrupt: Resetting due to DRQ still up - %x\n", 04188 statusByte)); 04189 AtapiResetController(HwDeviceExtension,srb->PathId); 04190 return TRUE; 04191 } 04192 04193 } 04194 } 04195 04196 04197 // 04198 // Clear interrupt expecting flag. 04199 // 04200 04201 deviceExtension->ExpectingInterrupt = FALSE; 04202 04203 // 04204 // Sanity check that there is a current request. 04205 // 04206 04207 if (srb != NULL) { 04208 04209 // 04210 // Set status in SRB. 04211 // 04212 04213 srb->SrbStatus = (UCHAR)status; 04214 04215 // 04216 // Check for underflow. 04217 // 04218 04219 if (deviceExtension->WordsLeft) { 04220 04221 // 04222 // Subtract out residual words and update if filemark hit, 04223 // setmark hit , end of data, end of media... 04224 // 04225 04226 if (!(deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_TAPE_DEVICE)) { 04227 if (status == SRB_STATUS_DATA_OVERRUN) { 04228 srb->DataTransferLength -= deviceExtension->WordsLeft; 04229 } else { 04230 srb->DataTransferLength = 0; 04231 } 04232 } else { 04233 srb->DataTransferLength -= deviceExtension->WordsLeft; 04234 } 04235 } 04236 04237 if (srb->Function != SRB_FUNCTION_IO_CONTROL) { 04238 04239 // 04240 // Indicate command complete. 04241 // 04242 04243 if (!(deviceExtension->RDP)) { 04244 ScsiPortNotification(RequestComplete, 04245 deviceExtension, 04246 srb); 04247 04248 } 04249 } else { 04250 04251 PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 04252 UCHAR error = 0; 04253 04254 if (status != SRB_STATUS_SUCCESS) { 04255 error = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 04256 } 04257 04258 // 04259 // Build the SMART status block depending upon the completion status. 04260 // 04261 04262 cmdOutParameters->cBufferSize = wordCount; 04263 cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0; 04264 cmdOutParameters->DriverStatus.bIDEError = error; 04265 04266 // 04267 // If the sub-command is return smart status, jam the value from cylinder low and high, into the 04268 // data buffer. 04269 // 04270 04271 if (deviceExtension->SmartCommand == RETURN_SMART_STATUS) { 04272 cmdOutParameters->bBuffer[0] = RETURN_SMART_STATUS; 04273 cmdOutParameters->bBuffer[1] = ScsiPortReadPortUchar(&baseIoAddress1->InterruptReason); 04274 cmdOutParameters->bBuffer[2] = ScsiPortReadPortUchar(&baseIoAddress1->Unused1); 04275 cmdOutParameters->bBuffer[3] = ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow); 04276 cmdOutParameters->bBuffer[4] = ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh); 04277 cmdOutParameters->bBuffer[5] = ScsiPortReadPortUchar(&baseIoAddress1->DriveSelect); 04278 cmdOutParameters->bBuffer[6] = SMART_CMD; 04279 cmdOutParameters->cBufferSize = 8; 04280 } 04281 04282 // 04283 // Indicate command complete. 04284 // 04285 04286 ScsiPortNotification(RequestComplete, 04287 deviceExtension, 04288 srb); 04289 04290 } 04291 04292 } else { 04293 04294 DebugPrint((1, 04295 "AtapiInterrupt: No SRB!\n")); 04296 } 04297 04298 // 04299 // Indicate ready for next request. 04300 // 04301 04302 if (!(deviceExtension->RDP)) { 04303 04304 // 04305 // Clear current SRB. 04306 // 04307 04308 deviceExtension->CurrentSrb = NULL; 04309 04310 ScsiPortNotification(NextRequest, 04311 deviceExtension, 04312 NULL); 04313 } else { 04314 04315 ScsiPortNotification(RequestTimerCall, 04316 HwDeviceExtension, 04317 AtapiCallBack, 04318 2000); 04319 } 04320 04321 return TRUE; 04322 04323 } else { 04324 04325 // 04326 // Unexpected int. 04327 // 04328 04329 DebugPrint((3, 04330 "AtapiInterrupt: Unexpected interrupt. InterruptReason %x. Status %x.\n", 04331 interruptReason, 04332 statusByte)); 04333 return FALSE; 04334 } 04335 04336 return TRUE; 04337 04338 } // end AtapiInterrupt() 04339 04340 04341 ULONG 04342 NTAPI 04343 IdeSendSmartCommand( 04344 IN PVOID HwDeviceExtension, 04345 IN PSCSI_REQUEST_BLOCK Srb 04346 ) 04347 04348 /*++ 04349 04350 Routine Description: 04351 04352 This routine handles SMART enable, disable, read attributes and threshold commands. 04353 04354 Arguments: 04355 04356 HwDeviceExtension - HBA miniport driver's adapter data storage 04357 Srb - IO request packet 04358 04359 Return Value: 04360 04361 SRB status 04362 04363 --*/ 04364 04365 { 04366 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 04367 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 04368 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 04369 PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 04370 SENDCMDINPARAMS cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 04371 PIDEREGS regs = &cmdInParameters.irDriveRegs; 04372 ULONG i; 04373 UCHAR statusByte,targetId; 04374 04375 04376 if (cmdInParameters.irDriveRegs.bCommandReg == SMART_CMD) { 04377 04378 targetId = cmdInParameters.bDriveNumber; 04379 04380 //TODO optimize this check 04381 04382 if ((!(deviceExtension->DeviceFlags[targetId] & DFLAGS_DEVICE_PRESENT)) || 04383 (deviceExtension->DeviceFlags[targetId] & DFLAGS_ATAPI_DEVICE)) { 04384 04385 return SRB_STATUS_SELECTION_TIMEOUT; 04386 } 04387 04388 deviceExtension->SmartCommand = cmdInParameters.irDriveRegs.bFeaturesReg; 04389 04390 // 04391 // Determine which of the commands to carry out. 04392 // 04393 04394 if ((cmdInParameters.irDriveRegs.bFeaturesReg == READ_ATTRIBUTES) || 04395 (cmdInParameters.irDriveRegs.bFeaturesReg == READ_THRESHOLDS)) { 04396 04397 WaitOnBusy(baseIoAddress2,statusByte); 04398 04399 if (statusByte & IDE_STATUS_BUSY) { 04400 DebugPrint((1, 04401 "IdeSendSmartCommand: Returning BUSY status\n")); 04402 return SRB_STATUS_BUSY; 04403 } 04404 04405 // 04406 // Zero the ouput buffer as the input buffer info. has been saved off locally (the buffers are the same). 04407 // 04408 04409 for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1); i++) { 04410 ((PUCHAR)cmdOutParameters)[i] = 0; 04411 } 04412 04413 // 04414 // Set data buffer pointer and words left. 04415 // 04416 04417 deviceExtension->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer; 04418 deviceExtension->WordsLeft = READ_ATTRIBUTE_BUFFER_SIZE / 2; 04419 04420 // 04421 // Indicate expecting an interrupt. 04422 // 04423 04424 deviceExtension->ExpectingInterrupt = TRUE; 04425 04426 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,(UCHAR)(((targetId & 0x1) << 4) | 0xA0)); 04427 ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,regs->bFeaturesReg); 04428 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,regs->bSectorCountReg); 04429 ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,regs->bSectorNumberReg); 04430 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,regs->bCylLowReg); 04431 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,regs->bCylHighReg); 04432 ScsiPortWritePortUchar(&baseIoAddress1->Command,regs->bCommandReg); 04433 04434 // 04435 // Wait for interrupt. 04436 // 04437 04438 return SRB_STATUS_PENDING; 04439 04440 } else if ((cmdInParameters.irDriveRegs.bFeaturesReg == ENABLE_SMART) || 04441 (cmdInParameters.irDriveRegs.bFeaturesReg == DISABLE_SMART) || 04442 (cmdInParameters.irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) || 04443 (cmdInParameters.irDriveRegs.bFeaturesReg == ENABLE_DISABLE_AUTOSAVE) || 04444 (cmdInParameters.irDriveRegs.bFeaturesReg == EXECUTE_OFFLINE_DIAGS) || 04445 (cmdInParameters.irDriveRegs.bFeaturesReg == SAVE_ATTRIBUTE_VALUES)) { 04446 04447 WaitOnBusy(baseIoAddress2,statusByte); 04448 04449 if (statusByte & IDE_STATUS_BUSY) { 04450 DebugPrint((1, 04451 "IdeSendSmartCommand: Returning BUSY status\n")); 04452 return SRB_STATUS_BUSY; 04453 } 04454 04455 // 04456 // Zero the ouput buffer as the input buffer info. has been saved off locally (the buffers are the same). 04457 // 04458 04459 for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) - 1); i++) { 04460 ((PUCHAR)cmdOutParameters)[i] = 0; 04461 } 04462 04463 // 04464 // Set data buffer pointer and indicate no data transfer. 04465 // 04466 04467 deviceExtension->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer; 04468 deviceExtension->WordsLeft = 0; 04469 04470 // 04471 // Indicate expecting an interrupt. 04472 // 04473 04474 deviceExtension->ExpectingInterrupt = TRUE; 04475 04476 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,(UCHAR)(((targetId & 0x1) << 4) | 0xA0)); 04477 ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,regs->bFeaturesReg); 04478 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,regs->bSectorCountReg); 04479 ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,regs->bSectorNumberReg); 04480 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,regs->bCylLowReg); 04481 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,regs->bCylHighReg); 04482 ScsiPortWritePortUchar(&baseIoAddress1->Command,regs->bCommandReg); 04483 04484 // 04485 // Wait for interrupt. 04486 // 04487 04488 return SRB_STATUS_PENDING; 04489 } 04490 } 04491 04492 return SRB_STATUS_INVALID_REQUEST; 04493 04494 } // end IdeSendSmartCommand() 04495 04496 04497 ULONG 04498 NTAPI 04499 IdeReadWrite( 04500 IN PVOID HwDeviceExtension, 04501 IN PSCSI_REQUEST_BLOCK Srb 04502 ) 04503 04504 /*++ 04505 04506 Routine Description: 04507 04508 This routine handles IDE read and writes. 04509 04510 Arguments: 04511 04512 HwDeviceExtension - HBA miniport driver's adapter data storage 04513 Srb - IO request packet 04514 04515 Return Value: 04516 04517 SRB status 04518 04519 --*/ 04520 04521 { 04522 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 04523 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 04524 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 04525 ULONG startingSector,i; 04526 ULONG wordCount; 04527 UCHAR statusByte,statusByte2; 04528 UCHAR cylinderHigh,cylinderLow,drvSelect,sectorNumber; 04529 04530 // 04531 // Select device 0 or 1. 04532 // 04533 04534 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 04535 (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0)); 04536 04537 WaitOnBusy(baseIoAddress2,statusByte2); 04538 04539 if (statusByte2 & IDE_STATUS_BUSY) { 04540 DebugPrint((1, 04541 "IdeReadWrite: Returning BUSY status\n")); 04542 return SRB_STATUS_BUSY; 04543 } 04544 04545 // 04546 // Set data buffer pointer and words left. 04547 // 04548 04549 deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer; 04550 deviceExtension->WordsLeft = Srb->DataTransferLength / 2; 04551 04552 // 04553 // Indicate expecting an interrupt. 04554 // 04555 04556 deviceExtension->ExpectingInterrupt = TRUE; 04557 04558 // 04559 // Set up sector count register. Round up to next block. 04560 // 04561 04562 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount, 04563 (UCHAR)((Srb->DataTransferLength + 0x1FF) / 0x200)); 04564 04565 // 04566 // Get starting sector number from CDB. 04567 // 04568 04569 startingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 | 04570 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 | 04571 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 | 04572 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24; 04573 04574 DebugPrint((2, 04575 "IdeReadWrite: Starting sector is %x, Number of bytes %x\n", 04576 startingSector, 04577 Srb->DataTransferLength)); 04578 04579 // 04580 // Set up sector number register. 04581 // 04582 04583 sectorNumber = (UCHAR)((startingSector % deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) + 1); 04584 ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,sectorNumber); 04585 04586 // 04587 // Set up cylinder low register. 04588 // 04589 04590 cylinderLow = (UCHAR)(startingSector / (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 04591 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)); 04592 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,cylinderLow); 04593 04594 // 04595 // Set up cylinder high register. 04596 // 04597 04598 cylinderHigh = (UCHAR)((startingSector / (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 04599 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)) >> 8); 04600 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,cylinderHigh); 04601 04602 // 04603 // Set up head and drive select register. 04604 // 04605 04606 drvSelect = (UCHAR)(((startingSector / deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) % 04607 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads) |((Srb->TargetId & 0x1) << 4) | 0xA0); 04608 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,drvSelect); 04609 04610 DebugPrint((2, 04611 "IdeReadWrite: Cylinder %x Head %x Sector %x\n", 04612 startingSector / 04613 (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 04614 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads), 04615 (startingSector / 04616 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) % 04617 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads, 04618 startingSector % 04619 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack + 1)); 04620 04621 // 04622 // Check if write request. 04623 // 04624 04625 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) { 04626 04627 // 04628 // Send read command. 04629 // 04630 04631 if (deviceExtension->MaximumBlockXfer[Srb->TargetId]) { 04632 ScsiPortWritePortUchar(&baseIoAddress1->Command, 04633 IDE_COMMAND_READ_MULTIPLE); 04634 04635 } else { 04636 ScsiPortWritePortUchar(&baseIoAddress1->Command, 04637 IDE_COMMAND_READ); 04638 } 04639 } else { 04640 04641 04642 // 04643 // Send write command. 04644 // 04645 04646 if (deviceExtension->MaximumBlockXfer[Srb->TargetId]) { 04647 wordCount = 256 * deviceExtension->MaximumBlockXfer[Srb->TargetId]; 04648 04649 if (deviceExtension->WordsLeft < wordCount) { 04650 04651 // 04652 // Transfer only words requested. 04653 // 04654 04655 wordCount = deviceExtension->WordsLeft; 04656 04657 } 04658 ScsiPortWritePortUchar(&baseIoAddress1->Command, 04659 IDE_COMMAND_WRITE_MULTIPLE); 04660 04661 } else { 04662 wordCount = 256; 04663 ScsiPortWritePortUchar(&baseIoAddress1->Command, 04664 IDE_COMMAND_WRITE); 04665 } 04666 04667 // 04668 // Wait for BSY and DRQ. 04669 // 04670 04671 WaitOnBaseBusy(baseIoAddress1,statusByte); 04672 04673 if (statusByte & IDE_STATUS_BUSY) { 04674 04675 DebugPrint((1, 04676 "IdeReadWrite 2: Returning BUSY status %x\n", 04677 statusByte)); 04678 return SRB_STATUS_BUSY; 04679 } 04680 04681 for (i = 0; i < 1000; i++) { 04682 GetBaseStatus(baseIoAddress1, statusByte); 04683 if (statusByte & IDE_STATUS_DRQ) { 04684 break; 04685 } 04686 ScsiPortStallExecution(200); 04687 04688 } 04689 04690 if (!(statusByte & IDE_STATUS_DRQ)) { 04691 04692 DebugPrint((1, 04693 "IdeReadWrite: DRQ never asserted (%x) original status (%x)\n", 04694 statusByte, 04695 statusByte2)); 04696 04697 deviceExtension->WordsLeft = 0; 04698 04699 // 04700 // Clear interrupt expecting flag. 04701 // 04702 04703 deviceExtension->ExpectingInterrupt = FALSE; 04704 04705 // 04706 // Clear current SRB. 04707 // 04708 04709 deviceExtension->CurrentSrb = NULL; 04710 04711 return SRB_STATUS_TIMEOUT; 04712 } 04713 04714 // 04715 // Write next 256 words. 04716 // 04717 04718 WriteBuffer(baseIoAddress1, 04719 deviceExtension->DataBuffer, 04720 wordCount); 04721 04722 // 04723 // Adjust buffer address and words left count. 04724 // 04725 04726 deviceExtension->WordsLeft -= wordCount; 04727 deviceExtension->DataBuffer += wordCount; 04728 04729 } 04730 04731 // 04732 // Wait for interrupt. 04733 // 04734 04735 return SRB_STATUS_PENDING; 04736 04737 } // end IdeReadWrite() 04738 04739 04740 04741 ULONG 04742 NTAPI 04743 IdeVerify( 04744 IN PVOID HwDeviceExtension, 04745 IN PSCSI_REQUEST_BLOCK Srb 04746 ) 04747 04748 /*++ 04749 04750 Routine Description: 04751 04752 This routine handles IDE Verify. 04753 04754 Arguments: 04755 04756 HwDeviceExtension - HBA miniport driver's adapter data storage 04757 Srb - IO request packet 04758 04759 Return Value: 04760 04761 SRB status 04762 04763 --*/ 04764 04765 { 04766 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 04767 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 04768 //PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 04769 ULONG startingSector; 04770 ULONG sectors; 04771 ULONG endSector; 04772 USHORT sectorCount; 04773 04774 // 04775 // Drive has these number sectors. 04776 // 04777 04778 sectors = deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 04779 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads * 04780 deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders; 04781 04782 DebugPrint((3, 04783 "IdeVerify: Total sectors %x\n", 04784 sectors)); 04785 04786 // 04787 // Get starting sector number from CDB. 04788 // 04789 04790 startingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 | 04791 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 | 04792 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 | 04793 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24; 04794 04795 DebugPrint((3, 04796 "IdeVerify: Starting sector %x. Number of blocks %x\n", 04797 startingSector, 04798 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb)); 04799 04800 sectorCount = (USHORT)(((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8 | 04801 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb ); 04802 endSector = startingSector + sectorCount; 04803 04804 DebugPrint((3, 04805 "IdeVerify: Ending sector %x\n", 04806 endSector)); 04807 04808 if (endSector > sectors) { 04809 04810 // 04811 // Too big, round down. 04812 // 04813 04814 DebugPrint((1, 04815 "IdeVerify: Truncating request to %x blocks\n", 04816 sectors - startingSector - 1)); 04817 04818 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount, 04819 (UCHAR)(sectors - startingSector - 1)); 04820 04821 } else { 04822 04823 // 04824 // Set up sector count register. Round up to next block. 04825 // 04826 04827 if (sectorCount > 0xFF) { 04828 sectorCount = (USHORT)0xFF; 04829 } 04830 04831 ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,(UCHAR)sectorCount); 04832 } 04833 04834 // 04835 // Set data buffer pointer and words left. 04836 // 04837 04838 deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer; 04839 deviceExtension->WordsLeft = Srb->DataTransferLength / 2; 04840 04841 // 04842 // Indicate expecting an interrupt. 04843 // 04844 04845 deviceExtension->ExpectingInterrupt = TRUE; 04846 04847 // 04848 // Set up sector number register. 04849 // 04850 04851 ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber, 04852 (UCHAR)((startingSector % 04853 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) + 1)); 04854 04855 // 04856 // Set up cylinder low register. 04857 // 04858 04859 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow, 04860 (UCHAR)(startingSector / 04861 (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 04862 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads))); 04863 04864 // 04865 // Set up cylinder high register. 04866 // 04867 04868 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh, 04869 (UCHAR)((startingSector / 04870 (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 04871 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)) >> 8)); 04872 04873 // 04874 // Set up head and drive select register. 04875 // 04876 04877 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 04878 (UCHAR)(((startingSector / 04879 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) % 04880 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads) | 04881 ((Srb->TargetId & 0x1) << 4) | 0xA0)); 04882 04883 DebugPrint((2, 04884 "IdeVerify: Cylinder %x Head %x Sector %x\n", 04885 startingSector / 04886 (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack * 04887 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads), 04888 (startingSector / 04889 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) % 04890 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads, 04891 startingSector % 04892 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack + 1)); 04893 04894 04895 // 04896 // Send verify command. 04897 // 04898 04899 ScsiPortWritePortUchar(&baseIoAddress1->Command, 04900 IDE_COMMAND_VERIFY); 04901 04902 // 04903 // Wait for interrupt. 04904 // 04905 04906 return SRB_STATUS_PENDING; 04907 04908 } // end IdeVerify() 04909 04910 04911 VOID 04912 NTAPI 04913 Scsi2Atapi( 04914 IN PSCSI_REQUEST_BLOCK Srb 04915 ) 04916 04917 /*++ 04918 04919 Routine Description: 04920 04921 Convert SCSI packet command to Atapi packet command. 04922 04923 Arguments: 04924 04925 Srb - IO request packet 04926 04927 Return Value: 04928 04929 None 04930 04931 --*/ 04932 { 04933 // 04934 // Change the cdb length 04935 // 04936 04937 Srb->CdbLength = 12; 04938 04939 switch (Srb->Cdb[0]) { 04940 case SCSIOP_MODE_SENSE: { 04941 PMODE_SENSE_10 modeSense10 = (PMODE_SENSE_10)Srb->Cdb; 04942 UCHAR PageCode = ((PCDB)Srb->Cdb)->MODE_SENSE.PageCode; 04943 UCHAR Length = ((PCDB)Srb->Cdb)->MODE_SENSE.AllocationLength; 04944 04945 AtapiZeroMemory(Srb->Cdb,MAXIMUM_CDB_SIZE); 04946 04947 modeSense10->OperationCode = ATAPI_MODE_SENSE; 04948 modeSense10->PageCode = PageCode; 04949 modeSense10->ParameterListLengthMsb = 0; 04950 modeSense10->ParameterListLengthLsb = Length; 04951 break; 04952 } 04953 04954 case SCSIOP_MODE_SELECT: { 04955 PMODE_SELECT_10 modeSelect10 = (PMODE_SELECT_10)Srb->Cdb; 04956 UCHAR Length = ((PCDB)Srb->Cdb)->MODE_SELECT.ParameterListLength; 04957 04958 // 04959 // Zero the original cdb 04960 // 04961 04962 AtapiZeroMemory(Srb->Cdb,MAXIMUM_CDB_SIZE); 04963 04964 modeSelect10->OperationCode = ATAPI_MODE_SELECT; 04965 modeSelect10->PFBit = 1; 04966 modeSelect10->ParameterListLengthMsb = 0; 04967 modeSelect10->ParameterListLengthLsb = Length; 04968 break; 04969 } 04970 04971 case SCSIOP_FORMAT_UNIT: 04972 Srb->Cdb[0] = ATAPI_FORMAT_UNIT; 04973 break; 04974 } 04975 } 04976 04977 04978 04979 ULONG 04980 NTAPI 04981 AtapiSendCommand( 04982 IN PVOID HwDeviceExtension, 04983 IN PSCSI_REQUEST_BLOCK Srb 04984 ) 04985 04986 /*++ 04987 04988 Routine Description: 04989 04990 Send ATAPI packet command to device. 04991 04992 Arguments: 04993 04994 HwDeviceExtension - HBA miniport driver's adapter data storage 04995 Srb - IO request packet 04996 04997 Return Value: 04998 04999 05000 --*/ 05001 05002 { 05003 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 05004 PATAPI_REGISTERS_1 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 05005 PATAPI_REGISTERS_2 baseIoAddress2 = (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 05006 ULONG i; 05007 ULONG flags; 05008 UCHAR statusByte,byteCountLow,byteCountHigh; 05009 05010 // 05011 // We need to know how many platters our atapi cd-rom device might have. 05012 // Before anyone tries to send a srb to our target for the first time, 05013 // we must "secretly" send down a separate mechanism status srb in order to 05014 // initialize our device extension changer data. That's how we know how 05015 // many platters our target has. 05016 // 05017 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_CHANGER_INITED) && 05018 !deviceExtension->OriginalSrb) { 05019 05020 ULONG srbStatus; 05021 05022 // 05023 // Set this flag now. If the device hangs on the mech. status 05024 // command, we will not have the change to set it. 05025 // 05026 deviceExtension->DeviceFlags[Srb->TargetId] |= DFLAGS_CHANGER_INITED; 05027 05028 deviceExtension->MechStatusRetryCount = 3; 05029 deviceExtension->CurrentSrb = BuildMechanismStatusSrb ( 05030 HwDeviceExtension, 05031 Srb->PathId, 05032 Srb->TargetId); 05033 deviceExtension->OriginalSrb = Srb; 05034 05035 srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb); 05036 if (srbStatus == SRB_STATUS_PENDING) { 05037 return srbStatus; 05038 } else { 05039 deviceExtension->CurrentSrb = deviceExtension->OriginalSrb; 05040 deviceExtension->OriginalSrb = NULL; 05041 AtapiHwInitializeChanger (HwDeviceExtension, 05042 Srb->TargetId, 05043 (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL); 05044 // fall out 05045 } 05046 } 05047 05048 DebugPrint((2, 05049 "AtapiSendCommand: Command %x to TargetId %d lun %d\n", 05050 Srb->Cdb[0], 05051 Srb->TargetId, 05052 Srb->Lun)); 05053 05054 // 05055 // Make sure command is to ATAPI device. 05056 // 05057 05058 flags = deviceExtension->DeviceFlags[Srb->TargetId]; 05059 if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) { 05060 if ((Srb->Lun) > (deviceExtension->DiscsPresent[Srb->TargetId] - 1)) { 05061 05062 // 05063 // Indicate no device found at this address. 05064 // 05065 05066 return SRB_STATUS_SELECTION_TIMEOUT; 05067 } 05068 } else if (Srb->Lun > 0) { 05069 return SRB_STATUS_SELECTION_TIMEOUT; 05070 } 05071 05072 if (!(flags & DFLAGS_ATAPI_DEVICE)) { 05073 return SRB_STATUS_SELECTION_TIMEOUT; 05074 } 05075 05076 // 05077 // Select device 0 or 1. 05078 // 05079 05080 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 05081 (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0)); 05082 05083 // 05084 // Verify that controller is ready for next command. 05085 // 05086 05087 GetStatus(baseIoAddress2,statusByte); 05088 05089 DebugPrint((2, 05090 "AtapiSendCommand: Entered with status %x\n", 05091 statusByte)); 05092 05093 if (statusByte & IDE_STATUS_BUSY) { 05094 DebugPrint((1, 05095 "AtapiSendCommand: Device busy (%x)\n", 05096 statusByte)); 05097 return SRB_STATUS_BUSY; 05098 05099 } 05100 05101 if (statusByte & IDE_STATUS_ERROR) { 05102 if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) { 05103 05104 DebugPrint((1, 05105 "AtapiSendCommand: Error on entry: (%x)\n", 05106 statusByte)); 05107 // 05108 // Read the error reg. to clear it and fail this request. 05109 // 05110 05111 return MapError(deviceExtension, 05112 Srb); 05113 } 05114 } 05115 05116 // 05117 // If a tape drive has doesn't have DSC set and the last command is restrictive, don't send 05118 // the next command. See discussion of Restrictive Delayed Process commands in QIC-157. 05119 // 05120 05121 if ((!(statusByte & IDE_STATUS_DSC)) && 05122 (flags & DFLAGS_TAPE_DEVICE) && deviceExtension->RDP) { 05123 ScsiPortStallExecution(1000); 05124 DebugPrint((2,"AtapiSendCommand: DSC not set. %x\n",statusByte)); 05125 return SRB_STATUS_BUSY; 05126 } 05127 05128 if (IS_RDP(Srb->Cdb[0])) { 05129 05130 deviceExtension->RDP = TRUE; 05131 05132 DebugPrint((3, 05133 "AtapiSendCommand: %x mapped as DSC restrictive\n", 05134 Srb->Cdb[0])); 05135 05136 } else { 05137 05138 deviceExtension->RDP = FALSE; 05139 } 05140 05141 if (statusByte & IDE_STATUS_DRQ) { 05142 05143 DebugPrint((1, 05144 "AtapiSendCommand: Entered with status (%x). Attempting to recover.\n", 05145 statusByte)); 05146 // 05147 // Try to drain the data that one preliminary device thinks that it has 05148 // to transfer. Hopefully this random assertion of DRQ will not be present 05149 // in production devices. 05150 // 05151 05152 for (i = 0; i < 0x10000; i++) { 05153 05154 GetStatus(baseIoAddress2, statusByte); 05155 05156 if (statusByte & IDE_STATUS_DRQ) { 05157 05158 ScsiPortReadPortUshort(&baseIoAddress1->Data); 05159 05160 } else { 05161 05162 break; 05163 } 05164 } 05165 05166 if (i == 0x10000) { 05167 05168 DebugPrint((1, 05169 "AtapiSendCommand: DRQ still asserted.Status (%x)\n", 05170 statusByte)); 05171 05172 AtapiSoftReset(baseIoAddress1,Srb->TargetId); 05173 05174 DebugPrint((1, 05175 "AtapiSendCommand: Issued soft reset to Atapi device. \n")); 05176 05177 // 05178 // Re-initialize Atapi device. 05179 // 05180 05181 IssueIdentify(HwDeviceExtension, 05182 (Srb->TargetId & 0x1), 05183 (Srb->TargetId >> 1), 05184 IDE_COMMAND_ATAPI_IDENTIFY); 05185 05186 // 05187 // Inform the port driver that the bus has been reset. 05188 // 05189 05190 ScsiPortNotification(ResetDetected, HwDeviceExtension, 0); 05191 05192 // 05193 // Clean up device extension fields that AtapiStartIo won't. 05194 // 05195 05196 deviceExtension->ExpectingInterrupt = FALSE; 05197 deviceExtension->RDP = FALSE; 05198 05199 return SRB_STATUS_BUS_RESET; 05200 05201 } 05202 } 05203 05204 if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) { 05205 05206 // 05207 // As the cdrom driver sets the LUN field in the cdb, it must be removed. 05208 // 05209 05210 Srb->Cdb[1] &= ~0xE0; 05211 05212 if ((Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY) && (flags & DFLAGS_SANYO_ATAPI_CHANGER)) { 05213 05214 // 05215 // Torisan changer. TUR's are overloaded to be platter switches. 05216 // 05217 05218 Srb->Cdb[7] = Srb->Lun; 05219 05220 } 05221 } 05222 05223 // 05224 // Convert SCSI to ATAPI commands if needed 05225 // 05226 05227 switch (Srb->Cdb[0]) { 05228 case SCSIOP_MODE_SENSE: 05229 case SCSIOP_MODE_SELECT: 05230 case SCSIOP_FORMAT_UNIT: 05231 if (!(flags & DFLAGS_TAPE_DEVICE)) { 05232 Scsi2Atapi(Srb); 05233 } 05234 05235 break; 05236 } 05237 05238 // 05239 // Set data buffer pointer and words left. 05240 // 05241 05242 deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer; 05243 deviceExtension->WordsLeft = Srb->DataTransferLength / 2; 05244 05245 WaitOnBusy(baseIoAddress2,statusByte); 05246 05247 // 05248 // Write transfer byte count to registers. 05249 // 05250 05251 byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF); 05252 byteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8); 05253 05254 if (Srb->DataTransferLength >= 0x10000) { 05255 byteCountLow = byteCountHigh = 0xFF; 05256 } 05257 05258 ScsiPortWritePortUchar(&baseIoAddress1->ByteCountLow,byteCountLow); 05259 ScsiPortWritePortUchar(&baseIoAddress1->ByteCountHigh, byteCountHigh); 05260 05261 ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,0); 05262 05263 05264 if (flags & DFLAGS_INT_DRQ) { 05265 05266 // 05267 // This device interrupts when ready to receive the packet. 05268 // 05269 // Write ATAPI packet command. 05270 // 05271 05272 ScsiPortWritePortUchar(&baseIoAddress1->Command, 05273 IDE_COMMAND_ATAPI_PACKET); 05274 05275 DebugPrint((3, 05276 "AtapiSendCommand: Wait for int. to send packet. Status (%x)\n", 05277 statusByte)); 05278 05279 deviceExtension->ExpectingInterrupt = TRUE; 05280 05281 return SRB_STATUS_PENDING; 05282 05283 } else { 05284 05285 // 05286 // Write ATAPI packet command. 05287 // 05288 05289 ScsiPortWritePortUchar(&baseIoAddress1->Command, 05290 IDE_COMMAND_ATAPI_PACKET); 05291 05292 // 05293 // Wait for DRQ. 05294 // 05295 05296 WaitOnBusy(baseIoAddress2, statusByte); 05297 WaitForDrq(baseIoAddress2, statusByte); 05298 05299 if (!(statusByte & IDE_STATUS_DRQ)) { 05300 05301 DebugPrint((1, 05302 "AtapiSendCommand: DRQ never asserted (%x)\n", 05303 statusByte)); 05304 return SRB_STATUS_ERROR; 05305 } 05306 } 05307 05308 // 05309 // Need to read status register. 05310 // 05311 05312 GetBaseStatus(baseIoAddress1, statusByte); 05313 05314 // 05315 // Send CDB to device. 05316 // 05317 05318 WaitOnBusy(baseIoAddress2,statusByte); 05319 05320 WriteBuffer(baseIoAddress1, 05321 (PUSHORT)Srb->Cdb, 05322 6); 05323 05324 // 05325 // Indicate expecting an interrupt and wait for it. 05326 // 05327 05328 deviceExtension->ExpectingInterrupt = TRUE; 05329 05330 return SRB_STATUS_PENDING; 05331 05332 } // end AtapiSendCommand() 05333 05334 ULONG 05335 NTAPI 05336 IdeSendCommand( 05337 IN PVOID HwDeviceExtension, 05338 IN PSCSI_REQUEST_BLOCK Srb 05339 ) 05340 05341 /*++ 05342 05343 Routine Description: 05344 05345 Program ATA registers for IDE disk transfer. 05346 05347 Arguments: 05348 05349 HwDeviceExtension - ATAPI driver storage. 05350 Srb - System request block. 05351 05352 Return Value: 05353 05354 SRB status (pending if all goes well). 05355 05356 --*/ 05357 05358 { 05359 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 05360 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1]; 05361 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1]; 05362 PCDB cdb; 05363 05364 UCHAR statusByte,errorByte; 05365 ULONG status; 05366 ULONG i; 05367 PMODE_PARAMETER_HEADER modeData; 05368 05369 DebugPrint((2, 05370 "IdeSendCommand: Command %x to device %d\n", 05371 Srb->Cdb[0], 05372 Srb->TargetId)); 05373 05374 05375 05376 switch (Srb->Cdb[0]) { 05377 case SCSIOP_INQUIRY: 05378 05379 // 05380 // Filter out all TIDs but 0 and 1 since this is an IDE interface 05381 // which support up to two devices. 05382 // 05383 05384 if ((Srb->Lun != 0) || 05385 (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT))) { 05386 05387 // 05388 // Indicate no device found at this address. 05389 // 05390 05391 status = SRB_STATUS_SELECTION_TIMEOUT; 05392 break; 05393 05394 } else { 05395 05396 PINQUIRYDATA inquiryData = Srb->DataBuffer; 05397 PIDENTIFY_DATA2 identifyData = &deviceExtension->IdentifyData[Srb->TargetId]; 05398 05399 // 05400 // Zero INQUIRY data structure. 05401 // 05402 05403 for (i = 0; i < Srb->DataTransferLength; i++) { 05404 ((PUCHAR)Srb->DataBuffer)[i] = 0; 05405 } 05406 05407 // 05408 // Standard IDE interface only supports disks. 05409 // 05410 05411 inquiryData->DeviceType = DIRECT_ACCESS_DEVICE; 05412 05413 // 05414 // Set the removable bit, if applicable. 05415 // 05416 05417 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_REMOVABLE_DRIVE) { 05418 inquiryData->RemovableMedia = 1; 05419 } 05420 05421 // 05422 // Fill in vendor identification fields. 05423 // 05424 05425 for (i = 0; i < 8; i += 2) { 05426 inquiryData->VendorId[i] = 05427 ((PUCHAR)identifyData->ModelNumber)[i + 1]; 05428 inquiryData->VendorId[i+1] = 05429 ((PUCHAR)identifyData->ModelNumber)[i]; 05430 } 05431 05432 for (i = 0; i < 12; i += 2) { 05433 inquiryData->ProductId[i] = 05434 ((PUCHAR)identifyData->ModelNumber)[i + 8 + 1]; 05435 inquiryData->ProductId[i+1] = 05436 ((PUCHAR)identifyData->ModelNumber)[i + 8]; 05437 } 05438 05439 // 05440 // Initialize unused portion of product id. 05441 // 05442 05443 for (i = 0; i < 4; i++) { 05444 inquiryData->ProductId[12+i] = ' '; 05445 } 05446 05447 // 05448 // Move firmware revision from IDENTIFY data to 05449 // product revision in INQUIRY data. 05450 // 05451 05452 for (i = 0; i < 4; i += 2) { 05453 inquiryData->ProductRevisionLevel[i] = 05454 ((PUCHAR)identifyData->FirmwareRevision)[i+1]; 05455 inquiryData->ProductRevisionLevel[i+1] = 05456 ((PUCHAR)identifyData->FirmwareRevision)[i]; 05457 } 05458 05459 status = SRB_STATUS_SUCCESS; 05460 } 05461 05462 break; 05463 05464 case SCSIOP_MODE_SENSE: 05465 05466 // 05467 // This is used to determine of the media is write-protected. 05468 // Since IDE does not support mode sense then we will modify just the portion we need 05469 // so the higher level driver can determine if media is protected. 05470 // 05471 05472 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) { 05473 05474 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 05475 (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0)); 05476 ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_GET_MEDIA_STATUS); 05477 WaitOnBusy(baseIoAddress2,statusByte); 05478 05479 if (!(statusByte & IDE_STATUS_ERROR)){ 05480 05481 // 05482 // no error occured return success, media is not protected 05483 // 05484 05485 deviceExtension->ExpectingInterrupt = FALSE; 05486 status = SRB_STATUS_SUCCESS; 05487 05488 } else { 05489 05490 // 05491 // error occured, handle it locally, clear interrupt 05492 // 05493 05494 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 05495 05496 GetBaseStatus(baseIoAddress1, statusByte); 05497 deviceExtension->ExpectingInterrupt = FALSE; 05498 status = SRB_STATUS_SUCCESS; 05499 05500 if (errorByte & IDE_ERROR_DATA_ERROR) { 05501 05502 // 05503 //media is write-protected, set bit in mode sense buffer 05504 // 05505 05506 modeData = (PMODE_PARAMETER_HEADER)Srb->DataBuffer; 05507 05508 Srb->DataTransferLength = sizeof(MODE_PARAMETER_HEADER); 05509 modeData->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT; 05510 } 05511 } 05512 status = SRB_STATUS_SUCCESS; 05513 } else { 05514 status = SRB_STATUS_INVALID_REQUEST; 05515 } 05516 break; 05517 05518 case SCSIOP_TEST_UNIT_READY: 05519 05520 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) { 05521 05522 // 05523 // Select device 0 or 1. 05524 // 05525 05526 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 05527 (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0)); 05528 ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_GET_MEDIA_STATUS); 05529 05530 // 05531 // Wait for busy. If media has not changed, return success 05532 // 05533 05534 WaitOnBusy(baseIoAddress2,statusByte); 05535 05536 if (!(statusByte & IDE_STATUS_ERROR)){ 05537 deviceExtension->ExpectingInterrupt = FALSE; 05538 status = SRB_STATUS_SUCCESS; 05539 } else { 05540 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1); 05541 if (errorByte == IDE_ERROR_DATA_ERROR){ 05542 05543 // 05544 // Special case: If current media is write-protected, 05545 // the 0xDA command will always fail since the write-protect bit 05546 // is sticky,so we can ignore this error 05547 // 05548 05549 GetBaseStatus(baseIoAddress1, statusByte); 05550 deviceExtension->ExpectingInterrupt = FALSE; 05551 status = SRB_STATUS_SUCCESS; 05552 05553 } else { 05554 05555 // 05556 // Request sense buffer to be build 05557 // 05558 deviceExtension->ExpectingInterrupt = TRUE; 05559 status = SRB_STATUS_PENDING; 05560 } 05561 } 05562 } else { 05563 status = SRB_STATUS_SUCCESS; 05564 } 05565 05566 break; 05567 05568 case SCSIOP_READ_CAPACITY: 05569 05570 // 05571 // Claim 512 byte blocks (big-endian). 05572 // 05573 05574 ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000; 05575 05576 // 05577 // Calculate last sector. 05578 // 05579 05580 05581 i = (deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads * 05582 deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders * 05583 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) - 1; 05584 05585 ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress = 05586 (((PUCHAR)&i)[0] << 24) | (((PUCHAR)&i)[1] << 16) | 05587 (((PUCHAR)&i)[2] << 8) | ((PUCHAR)&i)[3]; 05588 05589 DebugPrint((1, 05590 "IDE disk %x - #sectors %x, #heads %x, #cylinders %x\n", 05591 Srb->TargetId, 05592 deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack, 05593 deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads, 05594 deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders)); 05595 05596 05597 status = SRB_STATUS_SUCCESS; 05598 break; 05599 05600 case SCSIOP_VERIFY: 05601 status = IdeVerify(HwDeviceExtension,Srb); 05602 05603 break; 05604 05605 case SCSIOP_READ: 05606 case SCSIOP_WRITE: 05607 05608 status = IdeReadWrite(HwDeviceExtension, 05609 Srb); 05610 break; 05611 05612 case SCSIOP_START_STOP_UNIT: 05613 05614 // 05615 //Determine what type of operation we should perform 05616 // 05617 cdb = (PCDB)Srb->Cdb; 05618 05619 if (cdb->START_STOP.LoadEject == 1){ 05620 05621 // 05622 // Eject media, 05623 // first select device 0 or 1. 05624 // 05625 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 05626 (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0)); 05627 ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_MEDIA_EJECT); 05628 } 05629 status = SRB_STATUS_SUCCESS; 05630 break; 05631 05632 case SCSIOP_REQUEST_SENSE: 05633 // this function makes sense buffers to report the results 05634 // of the original GET_MEDIA_STATUS command 05635 05636 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) { 05637 status = IdeBuildSenseBuffer(HwDeviceExtension,Srb); 05638 break; 05639 } 05640 05641 default: 05642 05643 DebugPrint((1, 05644 "IdeSendCommand: Unsupported command %x\n", 05645 Srb->Cdb[0])); 05646 05647 status = SRB_STATUS_INVALID_REQUEST; 05648 05649 } // end switch 05650 05651 return status; 05652 05653 } // end IdeSendCommand() 05654 05655 VOID 05656 NTAPI 05657 IdeMediaStatus( 05658 BOOLEAN EnableMSN, 05659 IN PVOID HwDeviceExtension, 05660 ULONG Channel 05661 ) 05662 /*++ 05663 05664 Routine Description: 05665 05666 Enables disables media status notification 05667 05668 Arguments: 05669 05670 HwDeviceExtension - ATAPI driver storage. 05671 05672 --*/ 05673 05674 { 05675 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 05676 PIDE_REGISTERS_1 baseIoAddress = deviceExtension->BaseIoAddress1[Channel >> 1]; 05677 UCHAR statusByte,errorByte; 05678 05679 05680 if (EnableMSN == TRUE){ 05681 05682 // 05683 // If supported enable Media Status Notification support 05684 // 05685 05686 if ((deviceExtension->DeviceFlags[Channel] & DFLAGS_REMOVABLE_DRIVE)) { 05687 05688 // 05689 // enable 05690 // 05691 ScsiPortWritePortUchar((PUCHAR)baseIoAddress + 1,(UCHAR) (0x95)); 05692 ScsiPortWritePortUchar(&baseIoAddress->Command, 05693 IDE_COMMAND_ENABLE_MEDIA_STATUS); 05694 05695 WaitOnBaseBusy(baseIoAddress,statusByte); 05696 05697 if (statusByte & IDE_STATUS_ERROR) { 05698 // 05699 // Read the error register. 05700 // 05701 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress + 1); 05702 05703 DebugPrint((1, 05704 "IdeMediaStatus: Error enabling media status. Status %x, error byte %x\n", 05705 statusByte, 05706 errorByte)); 05707 } else { 05708 deviceExtension->DeviceFlags[Channel] |= DFLAGS_MEDIA_STATUS_ENABLED; 05709 DebugPrint((1,"IdeMediaStatus: Media Status Notification Supported\n")); 05710 deviceExtension->ReturningMediaStatus = 0; 05711 05712 } 05713 05714 } 05715 } else { // end if EnableMSN == TRUE 05716 05717 // 05718 // disable if previously enabled 05719 // 05720 if ((deviceExtension->DeviceFlags[Channel] & DFLAGS_MEDIA_STATUS_ENABLED)) { 05721 05722 ScsiPortWritePortUchar((PUCHAR)baseIoAddress + 1,(UCHAR) (0x31)); 05723 ScsiPortWritePortUchar(&baseIoAddress->Command, 05724 IDE_COMMAND_ENABLE_MEDIA_STATUS); 05725 05726 WaitOnBaseBusy(baseIoAddress,statusByte); 05727 deviceExtension->DeviceFlags[Channel] &= ~DFLAGS_MEDIA_STATUS_ENABLED; 05728 } 05729 05730 05731 } 05732 05733 05734 05735 } 05736 05737 ULONG 05738 NTAPI 05739 IdeBuildSenseBuffer( 05740 IN PVOID HwDeviceExtension, 05741 IN PSCSI_REQUEST_BLOCK Srb 05742 ) 05743 05744 /*++ 05745 05746 Routine Description: 05747 05748 Builts an artificial sense buffer to report the results of a GET_MEDIA_STATUS 05749 command. This function is invoked to satisfy the SCSIOP_REQUEST_SENSE. 05750 Arguments: 05751 05752 HwDeviceExtension - ATAPI driver storage. 05753 Srb - System request block. 05754 05755 Return Value: 05756 05757 SRB status (ALWAYS SUCCESS). 05758 05759 --*/ 05760 05761 { 05762 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 05763 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->DataBuffer; 05764 05765 05766 if (senseBuffer){ 05767 05768 05769 if(deviceExtension->ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE) { 05770 05771 senseBuffer->ErrorCode = 0x70; 05772 senseBuffer->Valid = 1; 05773 senseBuffer->AdditionalSenseLength = 0xb; 05774 senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; 05775 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED; 05776 senseBuffer->AdditionalSenseCodeQualifier = 0; 05777 } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE_REQ) { 05778 05779 senseBuffer->ErrorCode = 0x70; 05780 senseBuffer->Valid = 1; 05781 senseBuffer->AdditionalSenseLength = 0xb; 05782 senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; 05783 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED; 05784 senseBuffer->AdditionalSenseCodeQualifier = 0; 05785 } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_END_OF_MEDIA) { 05786 05787 senseBuffer->ErrorCode = 0x70; 05788 senseBuffer->Valid = 1; 05789 senseBuffer->AdditionalSenseLength = 0xb; 05790 senseBuffer->SenseKey = SCSI_SENSE_NOT_READY; 05791 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE; 05792 senseBuffer->AdditionalSenseCodeQualifier = 0; 05793 } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_DATA_ERROR) { 05794 05795 senseBuffer->ErrorCode = 0x70; 05796 senseBuffer->Valid = 1; 05797 senseBuffer->AdditionalSenseLength = 0xb; 05798 senseBuffer->SenseKey = SCSI_SENSE_DATA_PROTECT; 05799 senseBuffer->AdditionalSenseCode = 0; 05800 senseBuffer->AdditionalSenseCodeQualifier = 0; 05801 } 05802 return SRB_STATUS_SUCCESS; 05803 } 05804 return SRB_STATUS_ERROR; 05805 05806 }// End of IdeBuildSenseBuffer 05807 05808 05809 05810 05811 BOOLEAN 05812 NTAPI 05813 AtapiStartIo( 05814 IN PVOID HwDeviceExtension, 05815 IN PSCSI_REQUEST_BLOCK Srb 05816 ) 05817 05818 /*++ 05819 05820 Routine Description: 05821 05822 This routine is called from the SCSI port driver synchronized 05823 with the kernel to start an IO request. 05824 05825 Arguments: 05826 05827 HwDeviceExtension - HBA miniport driver's adapter data storage 05828 Srb - IO request packet 05829 05830 Return Value: 05831 05832 TRUE 05833 05834 --*/ 05835 05836 { 05837 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 05838 ULONG status; 05839 05840 // 05841 // Determine which function. 05842 // 05843 05844 switch (Srb->Function) { 05845 05846 case SRB_FUNCTION_EXECUTE_SCSI: 05847 05848 // 05849 // Sanity check. Only one request can be outstanding on a 05850 // controller. 05851 // 05852 05853 if (deviceExtension->CurrentSrb) { 05854 05855 DebugPrint((1, 05856 "AtapiStartIo: Already have a request!\n")); 05857 Srb->SrbStatus = SRB_STATUS_BUSY; 05858 ScsiPortNotification(RequestComplete, 05859 deviceExtension, 05860 Srb); 05861 return FALSE; 05862 } 05863 05864 // 05865 // Indicate that a request is active on the controller. 05866 // 05867 05868 deviceExtension->CurrentSrb = Srb; 05869 05870 // 05871 // Send command to device. 05872 // 05873 05874 if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE) { 05875 05876 status = AtapiSendCommand(HwDeviceExtension, 05877 Srb); 05878 05879 } else if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) { 05880 05881 status = IdeSendCommand(HwDeviceExtension, 05882 Srb); 05883 } else { 05884 05885 status = SRB_STATUS_SELECTION_TIMEOUT; 05886 } 05887 05888 break; 05889 05890 case SRB_FUNCTION_ABORT_COMMAND: 05891 05892 // 05893 // Verify that SRB to abort is still outstanding. 05894 // 05895 05896 if (!deviceExtension->CurrentSrb) { 05897 05898 DebugPrint((1, "AtapiStartIo: SRB to abort already completed\n")); 05899 05900 // 05901 // Complete abort SRB. 05902 // 05903 05904 status = SRB_STATUS_ABORT_FAILED; 05905 05906 break; 05907 } 05908 05909 // 05910 // Abort function indicates that a request timed out. 05911 // Call reset routine. Card will only be reset if 05912 // status indicates something is wrong. 05913 // Fall through to reset code. 05914 // 05915 05916 case SRB_FUNCTION_RESET_BUS: 05917 05918 // 05919 // Reset Atapi and SCSI bus. 05920 // 05921 05922 DebugPrint((1, "AtapiStartIo: Reset bus request received\n")); 05923 05924 if (!AtapiResetController(deviceExtension, 05925 Srb->PathId)) { 05926 05927 DebugPrint((1,"AtapiStartIo: Reset bus failed\n")); 05928 05929 // 05930 // Log reset failure. 05931 // 05932 05933 ScsiPortLogError( 05934 HwDeviceExtension, 05935 NULL, 05936 0, 05937 0, 05938 0, 05939 SP_INTERNAL_ADAPTER_ERROR, 05940 5 << 8 05941 ); 05942 05943 status = SRB_STATUS_ERROR; 05944 05945 } else { 05946 05947 status = SRB_STATUS_SUCCESS; 05948 } 05949 05950 break; 05951 05952 case SRB_FUNCTION_IO_CONTROL: 05953 05954 if (deviceExtension->CurrentSrb) { 05955 05956 DebugPrint((1, 05957 "AtapiStartIo: Already have a request!\n")); 05958 Srb->SrbStatus = SRB_STATUS_BUSY; 05959 ScsiPortNotification(RequestComplete, 05960 deviceExtension, 05961 Srb); 05962 return FALSE; 05963 } 05964 05965 // 05966 // Indicate that a request is active on the controller. 05967 // 05968 05969 deviceExtension->CurrentSrb = Srb; 05970 05971 if (AtapiStringCmp( (PCHAR)((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature,"SCSIDISK",strlen("SCSIDISK"))) { 05972 05973 DebugPrint((1, 05974 "AtapiStartIo: IoControl signature incorrect. Send %s, expected %s\n", 05975 ((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature, 05976 "SCSIDISK")); 05977 05978 status = SRB_STATUS_INVALID_REQUEST; 05979 break; 05980 } 05981 05982 switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) { 05983 05984 case IOCTL_SCSI_MINIPORT_SMART_VERSION: { 05985 05986 PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 05987 UCHAR deviceNumber; 05988 05989 // 05990 // Version and revision per SMART 1.03 05991 // 05992 05993 versionParameters->bVersion = 1; 05994 versionParameters->bRevision = 1; 05995 versionParameters->bReserved = 0; 05996 05997 // 05998 // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands. 05999 // 06000 06001 versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD); 06002 06003 // 06004 // This is done because of how the IOCTL_SCSI_MINIPORT 06005 // determines 'targetid's'. Disk.sys places the real target id value 06006 // in the DeviceMap field. Once we do some parameter checking, the value passed 06007 // back to the application will be determined. 06008 // 06009 06010 deviceNumber = versionParameters->bIDEDeviceMap; 06011 06012 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) || 06013 (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE)) { 06014 06015 status = SRB_STATUS_SELECTION_TIMEOUT; 06016 break; 06017 } 06018 06019 // 06020 // NOTE: This will only set the bit 06021 // corresponding to this drive's target id. 06022 // The bit mask is as follows: 06023 // 06024 // Sec Pri 06025 // S M S M 06026 // 3 2 1 0 06027 // 06028 06029 if (deviceExtension->NumberChannels == 1) { 06030 if (deviceExtension->PrimaryAddress) { 06031 deviceNumber = 1 << Srb->TargetId; 06032 } else { 06033 deviceNumber = 4 << Srb->TargetId; 06034 } 06035 } else { 06036 deviceNumber = 1 << Srb->TargetId; 06037 } 06038 06039 versionParameters->bIDEDeviceMap = deviceNumber; 06040 06041 status = SRB_STATUS_SUCCESS; 06042 break; 06043 } 06044 06045 case IOCTL_SCSI_MINIPORT_IDENTIFY: { 06046 06047 PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 06048 SENDCMDINPARAMS cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); 06049 ULONG i; 06050 UCHAR targetId; 06051 06052 06053 if (cmdInParameters.irDriveRegs.bCommandReg == ID_CMD) { 06054 06055 // 06056 // Extract the target. 06057 // 06058 06059 targetId = cmdInParameters.bDriveNumber; 06060 06061 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) || 06062 (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE)) { 06063 06064 status = SRB_STATUS_SELECTION_TIMEOUT; 06065 break; 06066 } 06067 06068 // 06069 // Zero the output buffer 06070 // 06071 06072 for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1); i++) { 06073 ((PUCHAR)cmdOutParameters)[i] = 0; 06074 } 06075 06076 // 06077 // Build status block. 06078 // 06079 06080 cmdOutParameters->cBufferSize = IDENTIFY_BUFFER_SIZE; 06081 cmdOutParameters->DriverStatus.bDriverError = 0; 06082 cmdOutParameters->DriverStatus.bIDEError = 0; 06083 06084 // 06085 // Extract the identify data from the device extension. 06086 // 06087 06088 ScsiPortMoveMemory (cmdOutParameters->bBuffer, &deviceExtension->IdentifyData[targetId], IDENTIFY_DATA_SIZE); 06089 06090 status = SRB_STATUS_SUCCESS; 06091 06092 06093 } else { 06094 status = SRB_STATUS_INVALID_REQUEST; 06095 } 06096 break; 06097 } 06098 06099 case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS: 06100 case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS: 06101 case IOCTL_SCSI_MINIPORT_ENABLE_SMART: 06102 case IOCTL_SCSI_MINIPORT_DISABLE_SMART: 06103 case IOCTL_SCSI_MINIPORT_RETURN_STATUS: 06104 case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE: 06105 case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES: 06106 case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS: 06107 06108 status = IdeSendSmartCommand(HwDeviceExtension,Srb); 06109 break; 06110 06111 default : 06112 06113 status = SRB_STATUS_INVALID_REQUEST; 06114 break; 06115 06116 } 06117 06118 break; 06119 06120 default: 06121 06122 // 06123 // Indicate unsupported command. 06124 // 06125 06126 status = SRB_STATUS_INVALID_REQUEST; 06127 06128 break; 06129 06130 } // end switch 06131 06132 // 06133 // Check if command complete. 06134 // 06135 06136 if (status != SRB_STATUS_PENDING) { 06137 06138 DebugPrint((2, 06139 "AtapiStartIo: Srb %x complete with status %x\n", 06140 Srb, 06141 status)); 06142 06143 // 06144 // Clear current SRB. 06145 // 06146 06147 deviceExtension->CurrentSrb = NULL; 06148 06149 // 06150 // Set status in SRB. 06151 // 06152 06153 Srb->SrbStatus = (UCHAR)status; 06154 06155 // 06156 // Indicate command complete. 06157 // 06158 06159 ScsiPortNotification(RequestComplete, 06160 deviceExtension, 06161 Srb); 06162 06163 // 06164 // Indicate ready for next request. 06165 // 06166 06167 ScsiPortNotification(NextRequest, 06168 deviceExtension, 06169 NULL); 06170 } 06171 06172 return TRUE; 06173 06174 } // end AtapiStartIo() 06175 06176 06177 ULONG 06178 NTAPI 06179 DriverEntry( 06180 IN PVOID DriverObject, 06181 IN PVOID Argument2 06182 ) 06183 06184 /*++ 06185 06186 Routine Description: 06187 06188 Installable driver initialization entry point for system. 06189 06190 Arguments: 06191 06192 Driver Object 06193 06194 Return Value: 06195 06196 Status from ScsiPortInitialize() 06197 06198 --*/ 06199 06200 { 06201 HW_INITIALIZATION_DATA hwInitializationData; 06202 ULONG adapterCount; 06203 ULONG i; 06204 ULONG statusToReturn, newStatus; 06205 06206 DebugPrint((1,"\n\nATAPI IDE MiniPort Driver\n")); 06207 06208 statusToReturn = 0xffffffff; 06209 06210 // 06211 // Zero out structure. 06212 // 06213 06214 AtapiZeroMemory(((PUCHAR)&hwInitializationData), sizeof(HW_INITIALIZATION_DATA)); 06215 06216 // 06217 // Set size of hwInitializationData. 06218 // 06219 06220 hwInitializationData.HwInitializationDataSize = 06221 sizeof(HW_INITIALIZATION_DATA); 06222 06223 // 06224 // Set entry points. 06225 // 06226 06227 hwInitializationData.HwInitialize = AtapiHwInitialize; 06228 hwInitializationData.HwResetBus = AtapiResetController; 06229 hwInitializationData.HwStartIo = AtapiStartIo; 06230 hwInitializationData.HwInterrupt = AtapiInterrupt; 06231 06232 // 06233 // Specify size of extensions. 06234 // 06235 06236 hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION); 06237 hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION); 06238 06239 // 06240 // Indicate PIO device. 06241 // 06242 06243 hwInitializationData.MapBuffers = TRUE; 06244 06245 // 06246 // Native Mode Devices 06247 // 06248 for (i=0; i <NUM_NATIVE_MODE_ADAPTERS; i++) { 06249 hwInitializationData.HwFindAdapter = AtapiFindNativeModeController; 06250 hwInitializationData.NumberOfAccessRanges = 4; 06251 hwInitializationData.AdapterInterfaceType = PCIBus; 06252 06253 hwInitializationData.VendorId = NativeModeAdapters[i].VendorId; 06254 hwInitializationData.VendorIdLength = (USHORT) NativeModeAdapters[i].VendorIdLength; 06255 hwInitializationData.DeviceId = NativeModeAdapters[i].DeviceId; 06256 hwInitializationData.DeviceIdLength = (USHORT) NativeModeAdapters[i].DeviceIdLength; 06257 06258 newStatus = ScsiPortInitialize(DriverObject, 06259 Argument2, 06260 &hwInitializationData, 06261 (PVOID)(ULONG_PTR)i); 06262 if (newStatus < statusToReturn) 06263 statusToReturn = newStatus; 06264 } 06265 06266 hwInitializationData.VendorId = 0; 06267 hwInitializationData.VendorIdLength = 0; 06268 hwInitializationData.DeviceId = 0; 06269 hwInitializationData.DeviceIdLength = 0; 06270 06271 // 06272 // The adapter count is used by the find adapter routine to track how 06273 // which adapter addresses have been tested. 06274 // 06275 06276 adapterCount = 0; 06277 06278 hwInitializationData.HwFindAdapter = AtapiFindPCIController; 06279 hwInitializationData.NumberOfAccessRanges = 4; 06280 hwInitializationData.AdapterInterfaceType = Isa; 06281 06282 newStatus = ScsiPortInitialize(DriverObject, 06283 Argument2, 06284 &hwInitializationData, 06285 &adapterCount); 06286 if (newStatus < statusToReturn) 06287 statusToReturn = newStatus; 06288 06289 // 06290 // Indicate 2 access ranges and reset FindAdapter. 06291 // 06292 06293 hwInitializationData.NumberOfAccessRanges = 2; 06294 hwInitializationData.HwFindAdapter = AtapiFindController; 06295 06296 // 06297 // Indicate ISA bustype. 06298 // 06299 06300 hwInitializationData.AdapterInterfaceType = Isa; 06301 06302 // 06303 // Call initialization for ISA bustype. 06304 // 06305 06306 newStatus = ScsiPortInitialize(DriverObject, 06307 Argument2, 06308 &hwInitializationData, 06309 &adapterCount); 06310 if (newStatus < statusToReturn) 06311 statusToReturn = newStatus; 06312 06313 // 06314 // Set up for MCA 06315 // 06316 06317 hwInitializationData.AdapterInterfaceType = MicroChannel; 06318 adapterCount = 0; 06319 06320 newStatus = ScsiPortInitialize(DriverObject, 06321 Argument2, 06322 &hwInitializationData, 06323 &adapterCount); 06324 if (newStatus < statusToReturn) 06325 statusToReturn = newStatus; 06326 06327 return statusToReturn; 06328 06329 } // end DriverEntry() 06330 06331 06332 06333 LONG 06334 NTAPI 06335 AtapiStringCmp ( 06336 PCHAR FirstStr, 06337 PCHAR SecondStr, 06338 ULONG Count 06339 ) 06340 { 06341 UCHAR first ,last; 06342 06343 if (Count) { 06344 do { 06345 06346 // 06347 // Get next char. 06348 // 06349 06350 first = *FirstStr++; 06351 last = *SecondStr++; 06352 06353 if (first != last) { 06354 06355 // 06356 // If no match, try lower-casing. 06357 // 06358 06359 if (first>='A' && first<='Z') { 06360 first = first - 'A' + 'a'; 06361 } 06362 if (last>='A' && last<='Z') { 06363 last = last - 'A' + 'a'; 06364 } 06365 if (first != last) { 06366 06367 // 06368 // No match 06369 // 06370 06371 return first - last; 06372 } 06373 } 06374 }while (--Count && first); 06375 } 06376 06377 return 0; 06378 } 06379 06380 06381 VOID 06382 NTAPI 06383 AtapiZeroMemory( 06384 IN PUCHAR Buffer, 06385 IN ULONG Count 06386 ) 06387 { 06388 ULONG i; 06389 06390 for (i = 0; i < Count; i++) { 06391 Buffer[i] = 0; 06392 } 06393 } 06394 06395 06396 VOID 06397 NTAPI 06398 AtapiHexToString ( 06399 IN ULONG Value, 06400 IN OUT PCHAR *Buffer 06401 ) 06402 { 06403 PCHAR string; 06404 PCHAR firstdig; 06405 CHAR temp; 06406 ULONG i; 06407 USHORT digval; 06408 06409 string = *Buffer; 06410 06411 firstdig = string; 06412 06413 for (i = 0; i < 4; i++) { 06414 digval = (USHORT)(Value % 16); 06415 Value /= 16; 06416 06417 // 06418 // convert to ascii and store. Note this will create 06419 // the buffer with the digits reversed. 06420 // 06421 06422 if (digval > 9) { 06423 *string++ = (char) (digval - 10 + 'a'); 06424 } else { 06425 *string++ = (char) (digval + '0'); 06426 } 06427 06428 } 06429 06430 // 06431 // Reverse the digits. 06432 // 06433 06434 *string-- = '\0'; 06435 06436 do { 06437 temp = *string; 06438 *string = *firstdig; 06439 *firstdig = temp; 06440 --string; 06441 ++firstdig; 06442 } while (firstdig < string); 06443 } 06444 06445 06446 06447 PSCSI_REQUEST_BLOCK 06448 NTAPI 06449 BuildMechanismStatusSrb ( 06450 IN PVOID HwDeviceExtension, 06451 IN ULONG PathId, 06452 IN ULONG TargetId 06453 ) 06454 { 06455 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 06456 PSCSI_REQUEST_BLOCK srb; 06457 PCDB cdb; 06458 06459 srb = &deviceExtension->InternalSrb; 06460 06461 AtapiZeroMemory((PUCHAR) srb, sizeof(SCSI_REQUEST_BLOCK)); 06462 06463 srb->PathId = (UCHAR) PathId; 06464 srb->TargetId = (UCHAR) TargetId; 06465 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 06466 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 06467 06468 // 06469 // Set flags to disable synchronous negociation. 06470 // 06471 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 06472 06473 // 06474 // Set timeout to 2 seconds. 06475 // 06476 srb->TimeOutValue = 4; 06477 06478 srb->CdbLength = 6; 06479 srb->DataBuffer = &deviceExtension->MechStatusData; 06480 srb->DataTransferLength = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER); 06481 06482 // 06483 // Set CDB operation code. 06484 // 06485 cdb = (PCDB)srb->Cdb; 06486 cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS; 06487 cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER); 06488 06489 return srb; 06490 } 06491 06492 06493 PSCSI_REQUEST_BLOCK 06494 NTAPI 06495 BuildRequestSenseSrb ( 06496 IN PVOID HwDeviceExtension, 06497 IN ULONG PathId, 06498 IN ULONG TargetId 06499 ) 06500 { 06501 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; 06502 PSCSI_REQUEST_BLOCK srb; 06503 PCDB cdb; 06504 06505 srb = &deviceExtension->InternalSrb; 06506 06507 AtapiZeroMemory((PUCHAR) srb, sizeof(SCSI_REQUEST_BLOCK)); 06508 06509 srb->PathId = (UCHAR) PathId; 06510 srb->TargetId = (UCHAR) TargetId; 06511 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 06512 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 06513 06514 // 06515 // Set flags to disable synchronous negociation. 06516 // 06517 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 06518 06519 // 06520 // Set timeout to 2 seconds. 06521 // 06522 srb->TimeOutValue = 4; 06523 06524 srb->CdbLength = 6; 06525 srb->DataBuffer = &deviceExtension->MechStatusSense; 06526 srb->DataTransferLength = sizeof(SENSE_DATA); 06527 06528 // 06529 // Set CDB operation code. 06530 // 06531 cdb = (PCDB)srb->Cdb; 06532 cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE; 06533 cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA); 06534 06535 return srb; 06536 } 06537 06538 06539 06540 06541 Generated on Sat May 26 2012 04:26:54 for ReactOS by
1.7.6.1
|