ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

atapi.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.