3 * IDE.C - IDE Disk driver
4 * written by Rex Jolliff
5 * with help from various documentation sources and a few peeks at
6 * linux and freebsd sources.
8 * This driver supports PCI controllers and up to 4 ISA controllers
9 * with up to 2 drives each.
10 * The device names are assigned as follows:
11 * \Devices\HarddiskX\Partition0
12 * for the raw device, and
13 * \Devices\HarddiskX\PartitionY
16 * X is computed by counting the available drives from the following
17 * sequence: the controller number (0=0x1f0, 1=0x170, 2=0x1e8,
18 * 3=0x168) * 2 plus the drive number (0,1)
19 * Y is the partition number
21 * The driver exports the following function:
23 * DriverEntry() - NT device driver initialization routine
25 * And the following functions are exported implicitly:
27 * IDEStartIo() - called to start an I/O request packet
28 * IDEDispatchOpenClose() - Called to open/close the device. a NOOP
29 * IDEDispatchReadWrite() - Called to read/write the device.
30 * IDEDispatchQueryInformation() - Called to get device information
31 * IDEDispatchSetInformation() - Called to set device information
32 * IDEDispatchDeviceControl() - Called to execute device control requests
34 * Modification History:
35 * 05/25/98 RJJ Created.
36 * 05/30/98 RJJ Removed IRQ handler and inserted busy waits
37 * just to get something working...
38 * 07/18/98 RJJ Made drastic changes so that the driver
39 * resembles a WinNT driver.
40 * 08/05/98 RJJ Changed to .C extension
41 * 09/19/98 RJJ First release (run for cover!)
44 * 09/17/98 RJJ Pri/MST: 14.12X19 WDC AC31000H Test Passed
49 * FIXME: a timer should be used to watch for device timeouts and errors
50 * FIXME: errors should be retried
51 * FIXME: a drive reset/recalibrate should be attempted if errors occur
52 * FIXME: Use DMA for transfers if drives support it
53 * FIXME: should we support unloading of this driver???
54 * FIXME: the device information should come from AUTODETECT (via registry)
55 * FIXME: really big devices need to be handled correctly
56 * FIXME: should get device info from the registry
57 * FIXME: should report hardware usage to iomgr
58 * FIXME: finish implementation of QueryInformation
59 * FIXME: finish implementation of SetInformation
60 * FIXME: finish implementation of DeviceControl
61 * FIXME: bring up to ATA-3 spec
62 * FIXME: add general support for ATAPI devices
63 * FIXME: add support for ATAPI CDROMs
64 * FIXME: add support for ATAPI ZIP drives/RHDs
65 * FIXME: add support for ATAPI tape drives
68 // -------------------------------------------------------------------------
70 #include <ddk/ntddk.h>
78 #define VERSION "V0.1.5"
80 /* uncomment the following line to enable the secondary ide channel */
81 //#define ENABLE_SECONDARY_IDE_CHANNEL
83 // ------------------------------------------------------- File Static Data
86 typedef struct _IDE_CONTROLLER_PARAMETERS
95 KINTERRUPT_MODE InterruptMode;
97 } IDE_CONTROLLER_PARAMETERS, *PIDE_CONTROLLER_PARAMETERS;
99 // NOTE: Do not increase max drives above 2
101 #define IDE_MAX_DRIVES 2
103 #define IDE_MAX_CONTROLLERS 2
104 IDE_CONTROLLER_PARAMETERS Controllers[IDE_MAX_CONTROLLERS] =
106 {0x01f0, 8, 0x03f6, 1, 14, 14, 15, LevelSensitive, 0xffff},
107 {0x0170, 8, 0x0376, 1, 15, 15, 15, LevelSensitive, 0xffff}
108 /* {0x01E8, 8, 0x03ee, 1, 11, 11, 15, LevelSensitive, 0xffff},
109 {0x0168, 8, 0x036e, 1, 10, 10, 15, LevelSensitive, 0xffff}*/
112 static BOOLEAN IDEInitialized = FALSE;
114 // ----------------------------------------------- Discardable Declarations
118 // make the initialization routines discardable, so that they
121 #pragma alloc_text(init, DriverEntry)
122 #pragma alloc_text(init, IDECreateController)
123 #pragma alloc_text(init, IDECreateDevices)
124 #pragma alloc_text(init, IDECreateDevice)
125 #pragma alloc_text(init, IDEPolledRead)
127 // make the PASSIVE_LEVEL routines pageable, so that they don't
128 // waste nonpaged memory
130 #pragma alloc_text(page, IDEShutdown)
131 #pragma alloc_text(page, IDEDispatchOpenClose)
132 #pragma alloc_text(page, IDEDispatchRead)
133 #pragma alloc_text(page, IDEDispatchWrite)
135 #endif /* ALLOC_PRAGMA */
137 // ---------------------------------------------------- Forward Declarations
140 IdeFindControllers(IN PDRIVER_OBJECT DriverObject);
143 IdeCreateController(IN PDRIVER_OBJECT DriverObject,
144 IN PIDE_CONTROLLER_PARAMETERS ControllerParams,
145 IN int ControllerIdx);
147 static BOOLEAN IDEResetController(IN WORD CommandPort, IN WORD ControlPort);
148 static BOOLEAN IDECreateDevices(IN PDRIVER_OBJECT DriverObject,
149 IN PCONTROLLER_OBJECT ControllerObject,
150 IN PIDE_CONTROLLER_EXTENSION ControllerExtension,
153 static BOOLEAN IDEGetDriveIdentification(IN int CommandPort,
155 OUT PIDE_DRIVE_IDENTIFY DrvParms);
156 static NTSTATUS IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject,
157 OUT PDEVICE_OBJECT *DeviceObject,
158 IN PCONTROLLER_OBJECT ControllerObject,
161 IN PIDE_DRIVE_IDENTIFY DrvParms,
162 IN ULONG SectorCount);
163 static NTSTATUS IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject,
164 OUT PDEVICE_OBJECT *DeviceObject,
165 IN PCONTROLLER_OBJECT ControllerObject,
166 IN PVOID DiskDeviceExtension,
169 IN PIDE_DRIVE_IDENTIFY DrvParms,
170 IN PPARTITION_INFORMATION PartitionInfo);
171 static int IDEPolledRead(IN WORD Address,
176 IN BYTE CylinderHigh,
180 static NTSTATUS STDCALL IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO, IN PIRP Irp);
181 static NTSTATUS STDCALL IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO, IN PIRP Irp);
182 static NTSTATUS STDCALL IDEDispatchDeviceControl(IN PDEVICE_OBJECT pDO, IN PIRP Irp);
183 static VOID STDCALL IDEStartIo(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
184 static IO_ALLOCATION_ACTION STDCALL
185 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject,
187 IN PVOID MapRegisterBase,
189 static BOOLEAN STDCALL
190 IDEStartController(IN OUT PVOID Context);
191 VOID IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension);
192 static BOOLEAN STDCALL IDEIsr(IN PKINTERRUPT Interrupt, IN PVOID ServiceContext);
193 static VOID IDEDpcForIsr(IN PKDPC Dpc,
194 IN PDEVICE_OBJECT DpcDeviceObject,
196 IN PVOID DpcContext);
197 static VOID IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension);
198 static VOID STDCALL IDEIoTimer(PDEVICE_OBJECT DeviceObject, PVOID Context);
200 // ---------------------------------------------------------------- Inlines
203 IDESwapBytePairs(char *Buf,
209 for (i = 0; i < Cnt; i += 2)
217 // ------------------------------------------------------- Public Interface
222 // This function initializes the driver, locates and claims
223 // hardware resources, and creates various NT objects needed
224 // to process I/O requests.
230 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
232 // IN PUNICODE_STRING RegistryPath Name of registry driver service
239 DriverEntry(IN PDRIVER_OBJECT DriverObject,
240 IN PUNICODE_STRING RegistryPath)
244 DPRINT("IDE Driver %s\n", VERSION);
246 /* Export other driver entry points... */
247 DriverObject->DriverStartIo = IDEStartIo;
248 DriverObject->MajorFunction[IRP_MJ_CREATE] = IDEDispatchOpenClose;
249 DriverObject->MajorFunction[IRP_MJ_CLOSE] = IDEDispatchOpenClose;
250 DriverObject->MajorFunction[IRP_MJ_READ] = IDEDispatchReadWrite;
251 DriverObject->MajorFunction[IRP_MJ_WRITE] = IDEDispatchReadWrite;
252 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = IDEDispatchQueryInformation;
253 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = IDEDispatchSetInformation;
254 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IDEDispatchDeviceControl;
256 Status = IdeFindControllers(DriverObject);
257 if (NT_SUCCESS(Status))
259 IDEInitialized = TRUE;
265 // ---------------------------------------------------- Discardable statics
268 IdeFindControllers(IN PDRIVER_OBJECT DriverObject)
270 PCI_COMMON_CONFIG PciConfig;
275 NTSTATUS ReturnedStatus = STATUS_NO_SUCH_DEVICE;
277 INT ControllerIdx = 0;
278 PCONFIGURATION_INFORMATION ConfigInfo;
280 DPRINT("IdeFindControllers() called!\n");
282 ConfigInfo = IoGetConfigurationInformation();
284 /* Search PCI busses for IDE controllers */
285 for (Bus = 0; Bus < 8; Bus++)
287 for (Slot = 0; Slot < 256; Slot++)
289 Size = HalGetBusData(PCIConfiguration,
293 sizeof(PCI_COMMON_CONFIG));
296 if ((PciConfig.BaseClass == 0x01) &&
297 (PciConfig.SubClass == 0x01))
299 DPRINT("IDE controller found!\n");
301 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
307 if ((PciConfig.HeaderType & 0x7FFFFFFF) == 0)
309 DPRINT(" IPR 0x%X ILR 0x%X\n",
310 PciConfig.u.type0.InterruptPin,
311 PciConfig.u.type0.InterruptLine);
314 if (PciConfig.ProgIf & 0x01)
316 DPRINT("Primary channel: PCI native mode\n");
320 DPRINT("Primary channel: Compatibility mode\n");
321 if (ConfigInfo->AtDiskPrimaryAddressClaimed == FALSE)
323 Status = IdeCreateController(DriverObject,
326 if (NT_SUCCESS(Status))
329 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
330 ConfigInfo->ScsiPortCount++;
331 ReturnedStatus = Status;
337 * FIXME: Switch controller to native pci mode
338 * if it is programmable.
342 if (PciConfig.ProgIf & 0x02)
344 DPRINT("Primary channel: programmable\n");
348 DPRINT("Primary channel: not programmable\n");
351 #ifdef ENABLE_SECONDARY_IDE_CHANNEL
352 if (PciConfig.ProgIf & 0x04)
354 DPRINT("Secondary channel: PCI native mode\n");
358 DPRINT("Secondary channel: Compatibility mode\n");
359 if (ConfigInfo->AtDiskSecondaryAddressClaimed == FALSE)
361 Status = IdeCreateController(DriverObject,
364 if (NT_SUCCESS(Status))
367 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
368 ConfigInfo->ScsiPortCount++;
369 ReturnedStatus = Status;
375 * FIXME: Switch controller to native pci mode
376 * if it is programmable.
380 if (PciConfig.ProgIf & 0x08)
382 DPRINT("Secondary channel: programmable\n");
386 DPRINT("Secondary channel: not programmable\n");
389 if (PciConfig.ProgIf & 0x80)
391 DPRINT("Master IDE device: 1\n");
395 DPRINT("Master IDE device: 0\n");
398 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
400 DPRINT("BaseAddress: 0x%08X\n", PciConfig.u.type0.BaseAddresses[i]);
408 /* Search for ISA IDE controller if no primary controller was found */
409 if (ConfigInfo->AtDiskPrimaryAddressClaimed == FALSE)
411 DPRINT("Searching for primary ISA IDE controller!\n");
413 if (IDEResetController(Controllers[0].CommandPortBase,
414 Controllers[0].ControlPortBase))
416 Status = IdeCreateController(DriverObject,
419 if (NT_SUCCESS(Status))
421 DPRINT(" Found primary ISA IDE controller!\n");
423 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
424 ConfigInfo->ScsiPortCount++;
425 ReturnedStatus = Status;
430 /* Search for ISA IDE controller if no secondary controller was found */
431 #ifdef ENABLE_SECONDARY_IDE_CHANNEL
432 if (ConfigInfo->AtDiskSecondaryAddressClaimed == FALSE)
434 DPRINT("Searching for secondary ISA IDE controller!\n");
436 if (IDEResetController(Controllers[1].CommandPortBase,
437 Controllers[1].ControlPortBase))
439 Status = IdeCreateController(DriverObject,
442 if (NT_SUCCESS(Status))
444 DPRINT(" Found secondary ISA IDE controller!\n");
446 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
447 ConfigInfo->ScsiPortCount++;
448 ReturnedStatus = Status;
454 DPRINT("IdeFindControllers() done!\n");
456 return(ReturnedStatus);
460 // IdeCreateController
463 // Creates a controller object and a device object for each valid
464 // device on the controller
470 // IN PDRIVER_OBJECT DriverObject The system created driver object
471 // IN PIDE_CONTROLLER_PARAMETERS The parameter block for this
472 // ControllerParams controller
473 // IN int ControllerIdx The index of this controller
476 // TRUE Devices where found on this controller
477 // FALSE The controller does not respond or there are no devices on it
481 IdeCreateController(IN PDRIVER_OBJECT DriverObject,
482 IN PIDE_CONTROLLER_PARAMETERS ControllerParams,
483 IN int ControllerIdx)
485 BOOLEAN CreatedDevices, ThisDriveExists;
488 PCONTROLLER_OBJECT ControllerObject;
489 PIDE_CONTROLLER_EXTENSION ControllerExtension;
491 ControllerObject = IoCreateController(sizeof(IDE_CONTROLLER_EXTENSION));
492 if (ControllerObject == NULL)
494 DbgPrint ("Could not create controller object for controller %d\n",
496 return STATUS_NO_SUCH_DEVICE;
499 // Fill out Controller extension data
500 ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
501 ControllerObject->ControllerExtension;
502 ControllerExtension->Number = ControllerIdx;
503 ControllerExtension->CommandPortBase = ControllerParams->CommandPortBase;
504 ControllerExtension->ControlPortBase = ControllerParams->ControlPortBase;
505 ControllerExtension->Vector = ControllerParams->Vector;
506 ControllerExtension->DMASupported = FALSE;
507 ControllerExtension->ControllerInterruptBug = FALSE;
508 ControllerExtension->OperationInProgress = FALSE;
510 // Initialize the spin lock in the controller extension
511 KeInitializeSpinLock(&ControllerExtension->SpinLock);
513 // Register an interrupt handler for this controller
514 RC = IoConnectInterrupt(&ControllerExtension->Interrupt,
517 &ControllerExtension->SpinLock,
518 ControllerExtension->Vector,
519 ControllerParams->IrqL,
520 ControllerParams->SynchronizeIrqL,
521 ControllerParams->InterruptMode,
523 ControllerParams->Affinity,
527 DbgPrint ("Could not Connect Interrupt %d\n",
528 ControllerExtension->Vector);
529 IoDeleteController (ControllerObject);
534 IDEInitialized = TRUE;
536 // Create device objects for each raw device (and for partitions)
537 CreatedDevices = FALSE;
538 for (DriveIdx = 0; DriveIdx < IDE_MAX_DRIVES; DriveIdx++)
540 ThisDriveExists = IDECreateDevices(DriverObject,
544 ControllerIdx * 2 + DriveIdx);
547 CreatedDevices = TRUE;
553 DbgPrint ("Did not find any devices for controller %d\n",
555 IoDisconnectInterrupt (ControllerExtension->Interrupt);
556 IoDeleteController (ControllerObject);
560 IDEResetController(ControllerParams->CommandPortBase,
561 ControllerParams->ControlPortBase);
562 IoStartTimer(ControllerExtension->TimerDevice);
565 return((CreatedDevices == TRUE)?STATUS_SUCCESS:STATUS_NO_SUCH_DEVICE);
569 // IDEResetController
572 // Reset the controller and report completion status
578 // IN WORD CommandPort The address of the command port
579 // IN WORD ControlPort The address of the control port
585 IDEResetController(IN WORD CommandPort,
590 // Assert drive reset line
591 IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
593 // Wait for min. 25 microseconds
594 KeStallExecutionProcessor(IDE_RESET_PULSE_LENGTH);
596 // Negate drive reset line
597 IDEWriteDriveControl(ControlPort, 0);
599 // Wait for BUSY negation
600 for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
602 if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
606 KeStallExecutionProcessor(10);
609 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
614 // return TRUE if controller came back to life. and
615 // the registers are initialized correctly
616 return IDEReadError(CommandPort) == 1;
623 // Create the raw device and any partition devices on this drive
629 // IN PDRIVER_OBJECT DriverObject The system created driver object
630 // IN PCONTROLLER_OBJECT ControllerObject
631 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
632 // The IDE controller extension for
634 // IN int DriveIdx The index of the drive on this
636 // IN int HarddiskIdx The NT device number for this
640 // TRUE Drive exists and devices were created
641 // FALSE no devices were created for this device
645 IDECreateDevices(IN PDRIVER_OBJECT DriverObject,
646 IN PCONTROLLER_OBJECT ControllerObject,
647 IN PIDE_CONTROLLER_EXTENSION ControllerExtension,
651 WCHAR NameBuffer[IDE_MAX_NAME_LENGTH];
654 IDE_DRIVE_IDENTIFY DrvParms;
655 PDEVICE_OBJECT DiskDeviceObject;
656 PDEVICE_OBJECT PartitionDeviceObject;
657 PIDE_DEVICE_EXTENSION DiskDeviceExtension;
658 UNICODE_STRING UnicodeDeviceDirName;
659 OBJECT_ATTRIBUTES DeviceDirAttributes;
661 ULONG SectorCount = 0;
662 PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
663 PPARTITION_INFORMATION PartitionEntry;
666 /* Copy I/O port offsets for convenience */
667 CommandPort = ControllerExtension->CommandPortBase;
668 // ControlPort = ControllerExtension->ControlPortBase;
669 DPRINT("probing IDE controller %d Addr %04lx Drive %d\n",
670 ControllerExtension->Number,
674 /* Get the Drive Identification Data */
675 if (!IDEGetDriveIdentification(CommandPort, DriveIdx, &DrvParms))
677 DPRINT("No ATA drive %d found on controller %d...\n",
679 ControllerExtension->Number);
683 DPRINT("Found ATA drive %d on controller %d...\n",
685 ControllerExtension->Number);
687 /* Create the harddisk device directory */
688 swprintf (NameBuffer,
689 L"\\Device\\Harddisk%d",
691 RtlInitUnicodeString(&UnicodeDeviceDirName,
693 InitializeObjectAttributes(&DeviceDirAttributes,
694 &UnicodeDeviceDirName,
698 Status = ZwCreateDirectoryObject(&Handle, 0, &DeviceDirAttributes);
699 if (!NT_SUCCESS(Status))
701 DbgPrint("Could not create device dir object\n");
705 /* Create the disk device */
706 if (DrvParms.Capabilities & IDE_DRID_LBA_SUPPORTED)
709 (ULONG)((DrvParms.TMSectorCountHi << 16) + DrvParms.TMSectorCountLo);
714 (ULONG)(DrvParms.LogicalCyls * DrvParms.LogicalHeads * DrvParms.SectorsPerTrack);
716 DPRINT("SectorCount %lu\n", SectorCount);
718 Status = IDECreateDiskDevice(DriverObject,
725 if (!NT_SUCCESS(Status))
727 DbgPrint("IDECreateDevice call failed for raw device\n");
731 /* Increase number of available physical disk drives */
732 IoGetConfigurationInformation()->DiskCount++;
735 * Initialize the controller timer here
736 * (since it has to be tied to a device)
740 ControllerExtension->TimerState = IDETimerIdle;
741 ControllerExtension->TimerCount = 0;
742 ControllerExtension->TimerDevice = DiskDeviceObject;
743 IoInitializeTimer(DiskDeviceObject,
745 ControllerExtension);
748 DPRINT("DrvParms.BytesPerSector %ld\n",DrvParms.BytesPerSector);
750 /* Read partition table */
751 Status = IoReadPartitionTable(DiskDeviceObject,
752 DrvParms.BytesPerSector,
755 if (!NT_SUCCESS(Status))
757 DbgPrint("IoReadPartitionTable() failed\n");
761 DPRINT(" Number of partitions: %u\n", PartitionList->PartitionCount);
762 for (i=0;i < PartitionList->PartitionCount; i++)
764 PartitionEntry = &PartitionList->PartitionEntry[i];
766 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
768 PartitionEntry->PartitionNumber,
769 PartitionEntry->BootIndicator,
770 PartitionEntry->PartitionType,
771 PartitionEntry->StartingOffset.QuadPart / DrvParms.BytesPerSector,
772 PartitionEntry->PartitionLength.QuadPart / DrvParms.BytesPerSector);
774 /* Create device for partition */
775 Status = IDECreatePartitionDevice(DriverObject,
776 &PartitionDeviceObject,
778 DiskDeviceObject->DeviceExtension,
783 if (!NT_SUCCESS(Status))
785 DbgPrint("IDECreateDevice() failed\n");
790 if (PartitionList != NULL)
791 ExFreePool(PartitionList);
796 // IDEGetDriveIdentification
799 // Get the identification block from the drive
805 // IN int CommandPort Address of the command port
806 // IN int DriveNum The drive index (0,1)
807 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
810 // TRUE The drive identification block was retrieved successfully
814 IDEGetDriveIdentification(IN int CommandPort,
816 OUT PIDE_DRIVE_IDENTIFY DrvParms)
819 /* Get the Drive Identify block from drive or die */
820 if (IDEPolledRead(CommandPort, 0, 1, 0, 0, 0, (DriveNum ? IDE_DH_DRV1 : 0),
821 IDE_CMD_IDENT_DRV, (BYTE *)DrvParms) != 0)
826 /* Report on drive parameters if debug mode */
827 IDESwapBytePairs(DrvParms->SerialNumber, 20);
828 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
829 IDESwapBytePairs(DrvParms->ModelNumber, 40);
830 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
831 DrvParms->ConfigBits,
832 DrvParms->LogicalCyls,
833 DrvParms->LogicalHeads,
834 DrvParms->SectorsPerTrack,
835 DrvParms->InterSectorGap,
836 DrvParms->InterSectorGapSize);
837 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
838 DrvParms->BytesInPLO,
839 DrvParms->VendorUniqueCnt,
840 DrvParms->SerialNumber);
841 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
842 DrvParms->ControllerType,
843 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
844 DrvParms->ECCByteCnt,
845 DrvParms->FirmwareRev);
846 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
847 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
848 (DrvParms->RWMultImplemented) & 0xff,
849 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
850 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
851 DrvParms->MinPIOTransTime,
852 DrvParms->MinDMATransTime);
853 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
854 DrvParms->TMCylinders,
856 DrvParms->TMSectorsPerTrk,
857 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
858 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
859 DrvParms->TMSectorCountHi,
860 DrvParms->TMSectorCountLo,
861 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
864 * Fix default ATA sector size.
865 * Attention: Default ATAPI sector size is 2048 bytes!!
867 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
868 DrvParms->BytesPerSector = 512;
869 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
875 // IDECreateDiskDevice
878 // Creates the disk device object
884 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
885 // OUT PDEVICE_OBJECT *DeviceObject The created device object
886 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
887 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
888 // IN BOOLEAN DMASupported Does the drive support DMA?
889 // IN int SectorsPerLogCyl Sectors per cylinder
890 // IN int SectorsPerLogTrk Sectors per track
891 // IN DWORD Offset First valid sector for this device
892 // IN DWORD Size Count of valid sectors for this device
899 IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject,
900 OUT PDEVICE_OBJECT *DeviceObject,
901 IN PCONTROLLER_OBJECT ControllerObject,
904 IN PIDE_DRIVE_IDENTIFY DrvParms,
905 IN ULONG SectorCount)
907 WCHAR NameBuffer[IDE_MAX_NAME_LENGTH];
908 UNICODE_STRING DeviceName;
910 PIDE_DEVICE_EXTENSION DeviceExtension;
912 /* Create a unicode device name */
914 L"\\Device\\Harddisk%d\\Partition0",
916 RtlInitUnicodeString(&DeviceName,
919 /* Create the device */
920 RC = IoCreateDevice(DriverObject,
921 sizeof(IDE_DEVICE_EXTENSION),
929 DbgPrint("IoCreateDevice call failed\n");
933 /* Set the buffering strategy here... */
934 (*DeviceObject)->Flags |= DO_DIRECT_IO;
935 (*DeviceObject)->AlignmentRequirement = FILE_WORD_ALIGNMENT;
937 /* Fill out Device extension data */
938 DeviceExtension = (PIDE_DEVICE_EXTENSION) (*DeviceObject)->DeviceExtension;
939 DeviceExtension->DeviceObject = (*DeviceObject);
940 DeviceExtension->ControllerObject = ControllerObject;
941 DeviceExtension->DiskDeviceExtension = DeviceExtension;
942 DeviceExtension->UnitNumber = UnitNumber;
943 DeviceExtension->LBASupported =
944 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0;
945 DeviceExtension->DMASupported =
946 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0;
947 DeviceExtension->BytesPerSector = DrvParms->BytesPerSector;
948 DeviceExtension->SectorsPerLogCyl =
949 DrvParms->LogicalHeads * DrvParms->SectorsPerTrack;
950 DeviceExtension->SectorsPerLogTrk = DrvParms->SectorsPerTrack;
951 DeviceExtension->LogicalHeads = DrvParms->LogicalHeads;
952 DeviceExtension->LogicalCylinders =
953 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? DrvParms->TMCylinders : DrvParms->LogicalCyls;
955 DeviceExtension->StartingOffset.QuadPart = 0;
956 DeviceExtension->PartitionLength.QuadPart = (ULONGLONG)SectorCount *
957 (ULONGLONG)DrvParms->BytesPerSector;
958 DeviceExtension->HiddenSectors = 0;
959 DeviceExtension->PartitionNumber = 0;
960 DeviceExtension->PartitionType = 0;
961 DeviceExtension->BootIndicator = FALSE;
963 DPRINT("%wZ: offset %I64d length %I64d\n",
965 DeviceExtension->StartingOffset.QuadPart,
966 DeviceExtension->PartitionLength.QuadPart);
968 /* Initialize the DPC object here */
969 IoInitializeDpcRequest(*DeviceObject,
976 // IDECreatePartitionDevice
979 // Creates a partition device object
985 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
986 // OUT PDEVICE_OBJECT *DeviceObject The created device object
987 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
988 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
989 // IN BOOLEAN DMASupported Does the drive support DMA?
990 // IN int SectorsPerLogCyl Sectors per cylinder
991 // IN int SectorsPerLogTrk Sectors per track
992 // IN DWORD Offset First valid sector for this device
993 // IN DWORD Size Count of valid sectors for this device
1000 IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject,
1001 OUT PDEVICE_OBJECT *DeviceObject,
1002 IN PCONTROLLER_OBJECT ControllerObject,
1003 IN PVOID DiskDeviceExtension,
1005 IN ULONG DiskNumber,
1006 IN PIDE_DRIVE_IDENTIFY DrvParms,
1007 IN PPARTITION_INFORMATION PartitionInfo)
1009 WCHAR NameBuffer[IDE_MAX_NAME_LENGTH];
1010 UNICODE_STRING DeviceName;
1012 PIDE_DEVICE_EXTENSION DeviceExtension;
1014 /* Create a unicode device name */
1015 swprintf(NameBuffer,
1016 L"\\Device\\Harddisk%d\\Partition%d",
1018 PartitionInfo->PartitionNumber);
1019 RtlInitUnicodeString(&DeviceName,
1022 /* Create the device */
1023 RC = IoCreateDevice(DriverObject, sizeof(IDE_DEVICE_EXTENSION),
1024 &DeviceName, FILE_DEVICE_DISK, 0, TRUE, DeviceObject);
1025 if (!NT_SUCCESS(RC))
1027 DbgPrint ("IoCreateDevice call failed\n");
1031 /* Set the buffering strategy here... */
1032 (*DeviceObject)->Flags |= DO_DIRECT_IO;
1033 (*DeviceObject)->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1035 /* Fill out Device extension data */
1036 DeviceExtension = (PIDE_DEVICE_EXTENSION)(*DeviceObject)->DeviceExtension;
1037 DeviceExtension->DeviceObject = (*DeviceObject);
1038 DeviceExtension->ControllerObject = ControllerObject;
1039 DeviceExtension->DiskDeviceExtension = DiskDeviceExtension;
1040 DeviceExtension->UnitNumber = UnitNumber;
1041 DeviceExtension->LBASupported =
1042 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0;
1043 DeviceExtension->DMASupported =
1044 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0;
1045 DeviceExtension->BytesPerSector = DrvParms->BytesPerSector;
1046 DeviceExtension->SectorsPerLogCyl = DrvParms->LogicalHeads *
1047 DrvParms->SectorsPerTrack;
1048 DeviceExtension->SectorsPerLogTrk = DrvParms->SectorsPerTrack;
1049 DeviceExtension->LogicalHeads = DrvParms->LogicalHeads;
1050 DeviceExtension->LogicalCylinders =
1051 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? DrvParms->TMCylinders : DrvParms->LogicalCyls;
1053 DeviceExtension->StartingOffset = PartitionInfo->StartingOffset;
1054 DeviceExtension->PartitionLength = PartitionInfo->PartitionLength;
1055 DeviceExtension->HiddenSectors = PartitionInfo->HiddenSectors;
1056 DeviceExtension->PartitionNumber = PartitionInfo->PartitionNumber;
1057 DeviceExtension->PartitionType = PartitionInfo->PartitionType;
1058 DeviceExtension->BootIndicator = PartitionInfo->BootIndicator;
1060 DPRINT("%wZ: offset %I64d size %I64d\n",
1062 DeviceExtension->StartingOffset.QuadPart,
1063 DeviceExtension->PartitionLength.QuadPart);
1065 /* Initialize the DPC object here */
1066 IoInitializeDpcRequest(*DeviceObject, IDEDpcForIsr);
1068 DPRINT("%wZ %I64dMB\n",
1070 DeviceExtension->PartitionLength.QuadPart >> 20);
1079 // Read a sector of data from the drive in a polled fashion.
1085 // IN WORD Address Address of command port for drive
1086 // IN BYTE PreComp Value to write to precomp register
1087 // IN BYTE SectorCnt Value to write to sectorCnt register
1088 // IN BYTE SectorNum Value to write to sectorNum register
1089 // IN BYTE CylinderLow Value to write to CylinderLow register
1090 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1091 // IN BYTE DrvHead Value to write to Drive/Head register
1092 // IN BYTE Command Value to write to Command register
1093 // OUT BYTE *Buffer Buffer for output data
1096 // int 0 is success, non 0 is an error code
1100 IDEPolledRead(IN WORD Address,
1104 IN BYTE CylinderLow,
1105 IN BYTE CylinderHigh,
1112 BOOLEAN ReadJunk = FALSE;
1113 ULONG SectorCount = 0;
1115 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1116 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1118 Status = IDEReadStatus(Address);
1119 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1123 KeStallExecutionProcessor(10);
1125 if (RetryCount == IDE_MAX_BUSY_RETRIES)
1130 /* Write Drive/Head to select drive */
1131 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
1133 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1134 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1136 Status = IDEReadStatus(Address);
1137 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1141 KeStallExecutionProcessor(10);
1143 if (RetryCount == IDE_MAX_BUSY_RETRIES)
1148 /* Issue command to drive */
1149 if (DrvHead & IDE_DH_LBA)
1151 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1152 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1153 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1159 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1160 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1169 /* Setup command parameters */
1170 IDEWritePrecomp(Address, PreComp);
1171 IDEWriteSectorCount(Address, SectorCnt);
1172 IDEWriteSectorNum(Address, SectorNum);
1173 IDEWriteCylinderHigh(Address, CylinderHigh);
1174 IDEWriteCylinderLow(Address, CylinderLow);
1175 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
1177 /* Issue the command */
1178 IDEWriteCommand(Address, Command);
1179 KeStallExecutionProcessor(50);
1181 /* wait for DRQ or error */
1182 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1184 Status = IDEReadStatus(Address);
1185 if (!(Status & IDE_SR_BUSY))
1187 if (Status & IDE_SR_ERR)
1189 DPRINT("IDE_SR_ERR asserted!\n");
1191 if ((Status & IDE_SR_DRQ) && !(Status & IDE_SR_ERR))
1200 KeStallExecutionProcessor(10);
1202 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1209 /* Read data into buffer */
1210 if (ReadJunk == TRUE)
1212 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1213 IDEReadBlock(Address, JunkBuffer, IDE_SECTOR_BUF_SZ);
1217 IDEReadBlock(Address, Buffer, IDE_SECTOR_BUF_SZ);
1218 Buffer += IDE_SECTOR_BUF_SZ;
1222 /* Check for more sectors to read */
1223 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1225 Status = IDEReadStatus(Address);
1226 if (!(Status & IDE_SR_BUSY))
1228 if (Status & IDE_SR_ERR)
1230 DPRINT("IDE_SR_ERR asserted!\n");
1232 if (Status & IDE_SR_DRQ)
1234 if (SectorCount >= SectorCnt)
1247 // ------------------------------------------- Nondiscardable statics
1249 // IDEDispatchOpenClose
1252 // Answer requests for Open/Close calls: a null operation
1258 // Standard dispatch arguments
1264 static NTSTATUS STDCALL
1265 IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO,
1268 Irp->IoStatus.Status = STATUS_SUCCESS;
1269 Irp->IoStatus.Information = FILE_OPENED;
1270 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1272 return STATUS_SUCCESS;
1275 // IDEDispatchReadWrite
1278 // Answer requests for reads and writes
1284 // Standard dispatch arguments
1290 static NTSTATUS STDCALL
1291 IDEDispatchReadWrite(IN PDEVICE_OBJECT DeviceObject,
1295 LARGE_INTEGER AdjustedOffset, AdjustedExtent, PartitionExtent, InsertKeyLI;
1296 PIO_STACK_LOCATION IrpStack;
1297 PIDE_DEVICE_EXTENSION DeviceExtension;
1299 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1300 DeviceExtension = (PIDE_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1302 // Validate operation parameters
1303 AdjustedOffset.QuadPart = DeviceExtension->StartingOffset.QuadPart +
1304 IrpStack->Parameters.Read.ByteOffset.QuadPart;
1305 DPRINT("AdjustedOffset: %I64x\n", AdjustedOffset.QuadPart);
1307 AdjustedExtent.QuadPart = AdjustedOffset.QuadPart +
1308 (ULONGLONG)IrpStack->Parameters.Read.Length;
1309 DPRINT("AdjustedExtent: %I64x\n", AdjustedExtent.QuadPart);
1311 PartitionExtent.QuadPart = DeviceExtension->StartingOffset.QuadPart +
1312 DeviceExtension->PartitionLength.QuadPart;
1313 DPRINT("PartitionExtent: %I64x\n", PartitionExtent.QuadPart);
1315 if ((AdjustedExtent.QuadPart > PartitionExtent.QuadPart) ||
1316 (IrpStack->Parameters.Read.Length & (DeviceExtension->BytesPerSector - 1)))
1318 DPRINT("Request failed on bad parameters\n",0);
1319 DPRINT("AdjustedExtent=%I64x PartitionExtent=%I64x ReadLength=%lx\n",
1320 AdjustedExtent.QuadPart,
1321 PartitionExtent.QuadPart,
1322 IrpStack->Parameters.Read.Length);
1323 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1324 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1325 return STATUS_INVALID_PARAMETER;
1328 // Adjust operation to absolute sector offset
1329 IrpStack->Parameters.Read.ByteOffset = AdjustedOffset;
1331 // Start the packet and insert the request in order of sector offset
1332 assert(DeviceExtension->BytesPerSector == 512);
1333 InsertKeyLI.QuadPart = IrpStack->Parameters.Read.ByteOffset.QuadPart >> 9;
1334 IrpInsertKey = InsertKeyLI.u.LowPart;
1335 IoStartPacket(DeviceObject, Irp, &IrpInsertKey, NULL);
1337 DPRINT("Returning STATUS_PENDING\n");
1338 return STATUS_PENDING;
1341 // IDEDispatchDeviceControl
1344 // Answer requests for device control calls
1350 // Standard dispatch arguments
1356 static NTSTATUS STDCALL
1357 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1361 ULONG ControlCode, InputLength, OutputLength;
1362 PIO_STACK_LOCATION IrpStack;
1363 PIDE_DEVICE_EXTENSION DeviceExtension;
1364 PIDE_DEVICE_EXTENSION DiskDeviceExtension;
1367 RC = STATUS_SUCCESS;
1368 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1369 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
1370 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
1371 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
1372 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1373 DiskDeviceExtension = (PIDE_DEVICE_EXTENSION)DeviceExtension->DiskDeviceExtension;
1374 Increment = IO_NO_INCREMENT;
1376 // A huge switch statement in a Windows program?! who would have thought?
1377 switch (ControlCode)
1379 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
1380 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
1382 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1386 PDISK_GEOMETRY Geometry;
1388 Geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
1390 Geometry->MediaType = FixedMedia;
1391 Geometry->Cylinders.QuadPart = DiskDeviceExtension->LogicalCylinders;
1392 Geometry->TracksPerCylinder = DiskDeviceExtension->SectorsPerLogCyl /
1393 DiskDeviceExtension->SectorsPerLogTrk;
1394 Geometry->SectorsPerTrack = DiskDeviceExtension->SectorsPerLogTrk;
1395 Geometry->BytesPerSector = DiskDeviceExtension->BytesPerSector;
1396 DPRINT("DiskDeviceExtension->BytesPerSector %lu\n", DiskDeviceExtension->BytesPerSector);
1397 Irp->IoStatus.Status = STATUS_SUCCESS;
1398 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1402 case IOCTL_DISK_GET_PARTITION_INFO:
1403 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
1404 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
1405 sizeof(PARTITION_INFORMATION))
1407 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
1409 else if (DeviceExtension->PartitionNumber == 0)
1411 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1415 PPARTITION_INFORMATION PartitionInfo;
1417 PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
1419 PartitionInfo->PartitionType = DeviceExtension->PartitionType;
1420 PartitionInfo->StartingOffset = DeviceExtension->StartingOffset;
1421 PartitionInfo->PartitionLength = DeviceExtension->PartitionLength;
1422 PartitionInfo->HiddenSectors = DeviceExtension->HiddenSectors;
1423 PartitionInfo->PartitionNumber = DeviceExtension->PartitionNumber;
1424 PartitionInfo->BootIndicator = DeviceExtension->BootIndicator;
1425 PartitionInfo->RewritePartition = FALSE;
1426 PartitionInfo->RecognizedPartition =
1427 IsRecognizedPartition(DeviceExtension->PartitionType);
1429 Irp->IoStatus.Status = STATUS_SUCCESS;
1430 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
1434 case IOCTL_DISK_SET_PARTITION_INFO:
1435 RC = STATUS_INVALID_DEVICE_REQUEST;
1436 Irp->IoStatus.Status = RC;
1437 Irp->IoStatus.Information = 0;
1440 case IOCTL_DISK_GET_DRIVE_LAYOUT:
1441 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
1442 sizeof(DRIVE_LAYOUT_INFORMATION))
1444 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
1448 PDRIVE_LAYOUT_INFORMATION PartitionList;
1450 RC = IoReadPartitionTable(DiskDeviceExtension->DeviceObject,
1451 DiskDeviceExtension->BytesPerSector,
1454 if (!NT_SUCCESS(RC))
1456 Irp->IoStatus.Status = RC;
1462 BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
1464 BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
1466 if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
1468 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
1472 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
1475 Irp->IoStatus.Status = STATUS_SUCCESS;
1476 Irp->IoStatus.Information = BufferSize;
1478 ExFreePool(PartitionList);
1481 Increment = IO_DISK_INCREMENT;
1484 case IOCTL_DISK_SET_DRIVE_LAYOUT:
1485 case IOCTL_DISK_VERIFY:
1486 case IOCTL_DISK_FORMAT_TRACKS:
1487 case IOCTL_DISK_PERFORMANCE:
1488 case IOCTL_DISK_IS_WRITABLE:
1489 case IOCTL_DISK_LOGGING:
1490 case IOCTL_DISK_FORMAT_TRACKS_EX:
1491 case IOCTL_DISK_HISTOGRAM_STRUCTURE:
1492 case IOCTL_DISK_HISTOGRAM_DATA:
1493 case IOCTL_DISK_HISTOGRAM_RESET:
1494 case IOCTL_DISK_REQUEST_STRUCTURE:
1495 case IOCTL_DISK_REQUEST_DATA:
1497 // If we get here, something went wrong. inform the requestor
1499 RC = STATUS_INVALID_DEVICE_REQUEST;
1500 Irp->IoStatus.Status = RC;
1501 Irp->IoStatus.Information = 0;
1505 IoCompleteRequest(Irp, Increment);
1513 // Get the next requested I/O packet started
1519 // Dispatch routine standard arguments
1526 STDCALL IDEStartIo(IN PDEVICE_OBJECT DeviceObject,
1529 LARGE_INTEGER SectorLI;
1530 PIO_STACK_LOCATION IrpStack;
1531 PIDE_DEVICE_EXTENSION DeviceExtension;
1534 DPRINT("IDEStartIo() called!\n");
1536 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1537 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1539 // FIXME: implement the supported functions
1541 switch (IrpStack->MajorFunction)
1545 DeviceExtension->Operation = IrpStack->MajorFunction;
1546 DeviceExtension->BytesRequested = IrpStack->Parameters.Read.Length;
1547 assert(DeviceExtension->BytesPerSector == 512);
1548 SectorLI = RtlLargeIntegerShiftRight(IrpStack->Parameters.Read.ByteOffset, 9);
1549 DeviceExtension->StartingSector = SectorLI.u.LowPart;
1550 if (DeviceExtension->BytesRequested > DeviceExtension->BytesPerSector *
1551 IDE_MAX_SECTORS_PER_XFER)
1553 DeviceExtension->BytesToTransfer = DeviceExtension->BytesPerSector *
1554 IDE_MAX_SECTORS_PER_XFER;
1558 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
1560 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1561 DeviceExtension->SectorsTransferred = 0;
1562 DeviceExtension->TargetAddress = (BYTE *)MmGetSystemAddressForMdl(Irp->MdlAddress);
1563 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1564 IoAllocateController(DeviceExtension->ControllerObject,
1566 IDEAllocateController,
1568 KeLowerIrql(OldIrql);
1572 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1573 Irp->IoStatus.Information = 0;
1574 KeBugCheck((ULONG)Irp);
1575 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1576 IoStartNextPacket(DeviceObject, FALSE);
1579 DPRINT("IDEStartIo() finished!\n");
1582 // IDEAllocateController
1584 static IO_ALLOCATION_ACTION STDCALL
1585 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject,
1587 IN PVOID MapRegisterBase,
1590 PIDE_DEVICE_EXTENSION DeviceExtension;
1591 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1593 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1594 ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
1595 DeviceExtension->ControllerObject->ControllerExtension;
1596 ControllerExtension->CurrentIrp = Irp;
1597 ControllerExtension->Retries = 0;
1598 return KeSynchronizeExecution(ControllerExtension->Interrupt,
1600 DeviceExtension) ? KeepObject :
1604 // IDEStartController
1607 IDEStartController(IN OUT PVOID Context)
1609 BYTE SectorCnt, SectorNum, CylinderLow, CylinderHigh;
1610 BYTE DrvHead, Command;
1613 ULONG StartingSector;
1614 PIDE_DEVICE_EXTENSION DeviceExtension;
1615 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1618 DeviceExtension = (PIDE_DEVICE_EXTENSION) Context;
1619 ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
1620 DeviceExtension->ControllerObject->ControllerExtension;
1621 ControllerExtension->OperationInProgress = TRUE;
1622 ControllerExtension->DeviceForOperation = DeviceExtension;
1624 // Write controller registers to start opteration
1625 StartingSector = DeviceExtension->StartingSector;
1626 SectorCnt = DeviceExtension->BytesToTransfer /
1627 DeviceExtension->BytesPerSector;
1628 if (DeviceExtension->LBASupported)
1630 SectorNum = StartingSector & 0xff;
1631 CylinderLow = (StartingSector >> 8) & 0xff;
1632 CylinderHigh = (StartingSector >> 16) & 0xff;
1633 DrvHead = ((StartingSector >> 24) & 0x0f) |
1634 (DeviceExtension->UnitNumber ? IDE_DH_DRV1 : 0) |
1639 SectorNum = (StartingSector % DeviceExtension->SectorsPerLogTrk) + 1;
1640 StartingSector /= DeviceExtension->SectorsPerLogTrk;
1641 DrvHead = (StartingSector % DeviceExtension->LogicalHeads) |
1642 (DeviceExtension->UnitNumber ? IDE_DH_DRV1 : 0);
1643 StartingSector /= DeviceExtension->LogicalHeads;
1644 CylinderLow = StartingSector & 0xff;
1645 CylinderHigh = StartingSector >> 8;
1647 Command = DeviceExtension->Operation == IRP_MJ_READ ?
1648 IDE_CMD_READ : IDE_CMD_WRITE;
1649 if (DrvHead & IDE_DH_LBA)
1651 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1652 DeviceExtension->Operation == IRP_MJ_READ ? "READ" : "WRITE",
1653 ControllerExtension->CommandPortBase,
1654 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1655 ((DrvHead & 0x0f) << 24) +
1656 (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1662 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1663 DeviceExtension->Operation == IRP_MJ_READ ? "READ" : "WRITE",
1664 ControllerExtension->CommandPortBase,
1665 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1674 /* wait for BUSY to clear */
1675 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1677 Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1678 if (!(Status & IDE_SR_BUSY))
1682 KeStallExecutionProcessor(10);
1684 DPRINT ("status=%02x\n", Status);
1685 DPRINT ("waited %ld usecs for busy to clear\n", Retries * 10);
1686 if (Retries >= IDE_MAX_BUSY_RETRIES)
1688 DPRINT ("Drive is BUSY for too long\n");
1689 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1691 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1692 Irp = ControllerExtension->CurrentIrp;
1693 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1694 Irp->IoStatus.Information = 0;
1700 DPRINT ("Beginning drive reset sequence\n");
1701 IDEBeginControllerReset(ControllerExtension);
1707 /* Select the desired drive */
1708 IDEWriteDriveHead(ControllerExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1710 /* wait for BUSY to clear and DRDY to assert */
1711 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1713 Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1714 // if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1715 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1719 KeStallExecutionProcessor(10);
1721 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1722 if (Retries >= IDE_MAX_BUSY_RETRIES)
1724 DPRINT ("Drive is BUSY for too long after drive select\n");
1725 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1727 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1728 Irp = ControllerExtension->CurrentIrp;
1729 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1730 Irp->IoStatus.Information = 0;
1736 DPRINT ("Beginning drive reset sequence\n");
1737 IDEBeginControllerReset(ControllerExtension);
1743 /* Setup command parameters */
1744 IDEWritePrecomp(ControllerExtension->CommandPortBase, 0);
1745 IDEWriteSectorCount(ControllerExtension->CommandPortBase, SectorCnt);
1746 IDEWriteSectorNum(ControllerExtension->CommandPortBase, SectorNum);
1747 IDEWriteCylinderHigh(ControllerExtension->CommandPortBase, CylinderHigh);
1748 IDEWriteCylinderLow(ControllerExtension->CommandPortBase, CylinderLow);
1749 IDEWriteDriveHead(ControllerExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1751 /* Issue command to drive */
1752 IDEWriteCommand(ControllerExtension->CommandPortBase, Command);
1753 ControllerExtension->TimerState = IDETimerCmdWait;
1754 ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1756 if (DeviceExtension->Operation == IRP_MJ_WRITE)
1759 // Wait for controller ready
1760 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
1762 BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1763 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
1767 KeStallExecutionProcessor(10);
1769 if (Retries >= IDE_MAX_BUSY_RETRIES)
1771 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1773 Irp = ControllerExtension->CurrentIrp;
1774 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1775 Irp->IoStatus.Information = 0;
1781 IDEBeginControllerReset(ControllerExtension);
1787 // Load the first sector of data into the controller
1788 IDEWriteBlock(ControllerExtension->CommandPortBase,
1789 DeviceExtension->TargetAddress,
1791 DeviceExtension->TargetAddress += IDE_SECTOR_BUF_SZ;
1792 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1793 DeviceExtension->SectorsTransferred++;
1795 DPRINT ("Command issued to drive, IDEStartController done\n");
1800 // IDEBeginControllerReset
1803 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension)
1807 DPRINT("Controller Reset initiated on %04x\n",
1808 ControllerExtension->ControlPortBase);
1810 /* Assert drive reset line */
1811 DPRINT("Asserting reset line\n");
1812 IDEWriteDriveControl(ControllerExtension->ControlPortBase, IDE_DC_SRST);
1814 /* Wait for BSY assertion */
1815 DPRINT("Waiting for BSY assertion\n");
1816 for (Retries = 0; Retries < IDE_MAX_RESET_RETRIES; Retries++)
1818 BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1819 if ((Status & IDE_SR_BUSY))
1823 KeStallExecutionProcessor(10);
1825 if (Retries == IDE_MAX_RESET_RETRIES)
1827 DPRINT("Timeout on BSY assertion\n");
1830 /* Negate drive reset line */
1831 DPRINT("Negating reset line\n");
1832 IDEWriteDriveControl(ControllerExtension->ControlPortBase, 0);
1834 // FIXME: handle case of no device 0
1836 /* Set timer to check for end of reset */
1837 ControllerExtension->TimerState = IDETimerResetWaitForBusyNegate;
1838 ControllerExtension->TimerCount = IDE_RESET_BUSY_TIMEOUT;
1844 // Handle interrupts for IDE devices
1850 // IN PKINTERRUPT Interrupt The interrupt level in effect
1851 // IN PVOID ServiceContext The driver supplied context
1852 // (the controller extension)
1854 // TRUE This ISR handled the interrupt
1855 // FALSE Another ISR must handle this interrupt
1857 static BOOLEAN STDCALL
1858 IDEIsr(IN PKINTERRUPT Interrupt,
1859 IN PVOID ServiceContext)
1861 BOOLEAN IsLastBlock, AnErrorOccured, RequestIsComplete;
1862 BYTE *TargetAddress;
1864 NTSTATUS ErrorStatus;
1865 ULONG ErrorInformation;
1867 PIDE_DEVICE_EXTENSION DeviceExtension;
1868 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1870 if (IDEInitialized == FALSE)
1874 DPRINT ("IDEIsr called\n");
1876 ControllerExtension = (PIDE_CONTROLLER_EXTENSION) ServiceContext;
1878 // Read the status port to clear the interrtupt (even if it's not ours).
1879 ControllerExtension->DeviceStatus = IDEReadStatus(ControllerExtension->CommandPortBase);
1881 // If the interrupt is not ours, get the heck outta dodge.
1882 if (!ControllerExtension->OperationInProgress)
1887 DeviceExtension = ControllerExtension->DeviceForOperation;
1888 IsLastBlock = FALSE;
1889 AnErrorOccured = FALSE;
1890 RequestIsComplete = FALSE;
1891 ErrorStatus = STATUS_SUCCESS;
1892 ErrorInformation = 0;
1894 // Handle error condition if it exists
1895 if (ControllerExtension->DeviceStatus & IDE_SR_ERR)
1897 BYTE ErrorReg, SectorCount, SectorNum, CylinderLow, CylinderHigh;
1901 ErrorReg = IDEReadError(ControllerExtension->CommandPortBase);
1902 CylinderLow = IDEReadCylinderLow(ControllerExtension->CommandPortBase);
1903 CylinderHigh = IDEReadCylinderHigh(ControllerExtension->CommandPortBase);
1904 DriveHead = IDEReadDriveHead(ControllerExtension->CommandPortBase);
1905 SectorCount = IDEReadSectorCount(ControllerExtension->CommandPortBase);
1906 SectorNum = IDEReadSectorNum(ControllerExtension->CommandPortBase);
1907 // FIXME: should use the NT error logging facility
1908 DbgPrint ("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1909 DeviceExtension->Operation,
1910 ControllerExtension->DeviceStatus,
1917 // FIXME: should retry the command and perhaps recalibrate the drive
1919 // Set error status information
1920 AnErrorOccured = TRUE;
1921 ErrorStatus = STATUS_DISK_OPERATION_FAILED;
1923 (((((((CylinderHigh << 8) + CylinderLow) *
1924 DeviceExtension->LogicalHeads) +
1925 (DriveHead % DeviceExtension->LogicalHeads)) *
1926 DeviceExtension->SectorsPerLogTrk) + SectorNum - 1) -
1927 DeviceExtension->StartingSector) * DeviceExtension->BytesPerSector;
1932 // Check controller and setup for next transfer
1933 switch (DeviceExtension->Operation)
1937 // Update controller/device state variables
1938 TargetAddress = DeviceExtension->TargetAddress;
1939 DeviceExtension->TargetAddress += DeviceExtension->BytesPerSector;
1940 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1941 DeviceExtension->SectorsTransferred++;
1943 // Remember whether DRQ should be low at end (last block read)
1944 IsLastBlock = DeviceExtension->BytesToTransfer == 0;
1946 // Wait for DRQ assertion
1947 for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
1948 !(IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ);
1951 KeStallExecutionProcessor(10);
1954 // Copy the block of data
1955 IDEReadBlock(ControllerExtension->CommandPortBase,
1962 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
1963 (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_BUSY);
1966 KeStallExecutionProcessor(10);
1969 // Check for data overrun
1970 if (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ)
1972 AnErrorOccured = TRUE;
1973 ErrorStatus = STATUS_DATA_OVERRUN;
1974 ErrorInformation = 0;
1979 // Setup next transfer or set RequestIsComplete
1980 if (DeviceExtension->BytesRequested >
1981 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
1983 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
1984 DeviceExtension->SectorsTransferred = 0;
1985 DeviceExtension->BytesToTransfer =
1986 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
1987 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1989 else if (DeviceExtension->BytesRequested > 0)
1991 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
1992 DeviceExtension->SectorsTransferred = 0;
1993 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
1994 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1998 RequestIsComplete = TRUE;
2007 if (DeviceExtension->BytesToTransfer == 0)
2009 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
2010 (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_BUSY);
2013 KeStallExecutionProcessor(10);
2016 // Check for data overrun
2017 if (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ)
2019 AnErrorOccured = TRUE;
2020 ErrorStatus = STATUS_DATA_OVERRUN;
2021 ErrorInformation = 0;
2026 // Setup next transfer or set RequestIsComplete
2028 if (DeviceExtension->BytesRequested >
2029 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
2031 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
2032 DeviceExtension->SectorsTransferred = 0;
2033 DeviceExtension->BytesToTransfer =
2034 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
2035 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
2037 else if (DeviceExtension->BytesRequested > 0)
2039 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
2040 DeviceExtension->SectorsTransferred = 0;
2041 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
2042 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
2046 RequestIsComplete = TRUE;
2053 // Update controller/device state variables
2054 TargetAddress = DeviceExtension->TargetAddress;
2055 DeviceExtension->TargetAddress += DeviceExtension->BytesPerSector;
2056 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
2057 DeviceExtension->SectorsTransferred++;
2059 // Write block to controller
2060 IDEWriteBlock(ControllerExtension->CommandPortBase,
2068 // If there was an error or the request is done, complete the packet
2069 if (AnErrorOccured || RequestIsComplete)
2071 // Set the return status and info values
2072 Irp = ControllerExtension->CurrentIrp;
2073 Irp->IoStatus.Status = ErrorStatus;
2074 Irp->IoStatus.Information = ErrorInformation;
2076 // Clear out controller fields
2077 ControllerExtension->OperationInProgress = FALSE;
2078 ControllerExtension->DeviceStatus = 0;
2080 // Queue the Dpc to finish up
2081 IoRequestDpc(DeviceExtension->DeviceObject,
2083 ControllerExtension);
2085 else if (IsLastBlock)
2087 // Else more data is needed, setup next device I/O
2088 IDEStartController((PVOID)DeviceExtension);
2101 // IN PDEVICE_OBJECT DpcDeviceObject
2103 // IN PVOID DpcContext
2106 IDEDpcForIsr(IN PKDPC Dpc,
2107 IN PDEVICE_OBJECT DpcDeviceObject,
2109 IN PVOID DpcContext)
2111 DPRINT("IDEDpcForIsr()\n");
2112 IDEFinishOperation((PIDE_CONTROLLER_EXTENSION) DpcContext);
2115 // IDEFinishOperation
2118 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension)
2120 PIDE_DEVICE_EXTENSION DeviceExtension;
2124 DeviceExtension = ControllerExtension->DeviceForOperation;
2125 Irp = ControllerExtension->CurrentIrp;
2126 Operation = DeviceExtension->Operation;
2127 ControllerExtension->OperationInProgress = FALSE;
2128 ControllerExtension->DeviceForOperation = 0;
2129 ControllerExtension->CurrentIrp = 0;
2131 // Deallocate the controller
2132 IoFreeController(DeviceExtension->ControllerObject);
2134 // Start the next packet
2135 IoStartNextPacketByKey(DeviceExtension->DeviceObject,
2137 DeviceExtension->StartingSector);
2139 // Flush cache if necessary
2140 if (Operation == IRP_MJ_READ)
2142 KeFlushIoBuffers(Irp->MdlAddress, TRUE, FALSE);
2144 // Issue completion of the current packet
2145 // return status information too
2146 Irp->IoStatus.Status = STATUS_SUCCESS;
2147 Irp->IoStatus.Information = DeviceExtension->SectorsTransferred * DeviceExtension->BytesPerSector;
2148 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2153 // This function handles timeouts and other time delayed processing
2158 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
2159 // IN PVOID Context the Controller extension for the
2160 // controller the device is on
2163 IDEIoTimer(PDEVICE_OBJECT DeviceObject,
2166 PIDE_CONTROLLER_EXTENSION ControllerExtension;
2168 // Setup Extension pointer
2169 ControllerExtension = (PIDE_CONTROLLER_EXTENSION) Context;
2170 DPRINT("Timer activated for %04lx\n", ControllerExtension->CommandPortBase);
2172 // Handle state change if necessary
2173 switch (ControllerExtension->TimerState)
2175 case IDETimerResetWaitForBusyNegate:
2176 if (!(IDEReadStatus(ControllerExtension->CommandPortBase) &
2179 DPRINT("Busy line has negated, waiting for DRDY assert\n");
2180 ControllerExtension->TimerState = IDETimerResetWaitForDrdyAssert;
2181 ControllerExtension->TimerCount = IDE_RESET_DRDY_TIMEOUT;
2186 case IDETimerResetWaitForDrdyAssert:
2187 if (IDEReadStatus(ControllerExtension->CommandPortBase) &
2190 DPRINT("DRDY has asserted, reset complete\n");
2191 ControllerExtension->TimerState = IDETimerIdle;
2192 ControllerExtension->TimerCount = 0;
2194 // FIXME: get diagnostic code from drive 0
2196 /* Start current packet command again */
2197 if (!KeSynchronizeExecution(ControllerExtension->Interrupt,
2199 ControllerExtension->DeviceForOperation))
2201 IDEFinishOperation(ControllerExtension);
2211 // If we're counting down, then count.
2212 if (ControllerExtension->TimerCount > 0)
2214 ControllerExtension->TimerCount--;
2216 // Else we'll check the state and process if necessary
2220 switch (ControllerExtension->TimerState)
2225 case IDETimerCmdWait:
2226 /* Command timed out, reset drive and try again or fail */
2227 DPRINT("Timeout waiting for command completion\n");
2228 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
2230 if (ControllerExtension->CurrentIrp != NULL)
2232 DbgPrint ("Max retries has been reached, IRP finished with error\n");
2233 ControllerExtension->CurrentIrp->IoStatus.Status = STATUS_IO_TIMEOUT;
2234 ControllerExtension->CurrentIrp->IoStatus.Information = 0;
2235 IDEFinishOperation(ControllerExtension);
2237 ControllerExtension->TimerState = IDETimerIdle;
2238 ControllerExtension->TimerCount = 0;
2242 IDEBeginControllerReset(ControllerExtension);
2246 case IDETimerResetWaitForBusyNegate:
2247 case IDETimerResetWaitForDrdyAssert:
2248 if (ControllerExtension->CurrentIrp != NULL)
2250 DbgPrint ("Timeout waiting for drive reset, giving up on IRP\n");
2251 ControllerExtension->CurrentIrp->IoStatus.Status =
2253 ControllerExtension->CurrentIrp->IoStatus.Information = 0;
2254 IDEFinishOperation(ControllerExtension);
2256 ControllerExtension->TimerState = IDETimerIdle;
2257 ControllerExtension->TimerCount = 0;