:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / dd / ide / ide.c
1 /* $Id$
2  *
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.
7  * 
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
14  *    for partitions
15  *    where:
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
20  * 
21  *     The driver exports the following function:
22  * 
23  *       DriverEntry() - NT device driver initialization routine
24  * 
25  *     And the following functions are exported implicitly:
26  * 
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
33  * 
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!)
42  *
43  *   Test List:
44  *     09/17/98  RJJ  Pri/MST: 14.12X19 WDC AC31000H  Test Passed
45  *                    Pri/SLV: None.
46  *     
47  *
48  *   To Do:
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
66  */
67
68 //  -------------------------------------------------------------------------
69
70 #include <ddk/ntddk.h>
71
72 #define NDEBUG
73 #include <debug.h>
74
75 #include "ide.h"
76 #include "partitio.h"
77
78 #define  VERSION  "V0.1.5"
79
80 /* uncomment the following line to enable the secondary ide channel */
81 //#define ENABLE_SECONDARY_IDE_CHANNEL
82
83 //  -------------------------------------------------------  File Static Data
84
85
86 typedef struct _IDE_CONTROLLER_PARAMETERS
87 {
88   int              CommandPortBase;
89   int              CommandPortSpan;
90   int              ControlPortBase;
91   int              ControlPortSpan;
92   int              Vector;
93   int              IrqL;
94   int              SynchronizeIrqL;
95   KINTERRUPT_MODE  InterruptMode;
96   KAFFINITY        Affinity;
97 } IDE_CONTROLLER_PARAMETERS, *PIDE_CONTROLLER_PARAMETERS;
98
99 //  NOTE: Do not increase max drives above 2
100
101 #define  IDE_MAX_DRIVES       2
102
103 #define  IDE_MAX_CONTROLLERS  2
104 IDE_CONTROLLER_PARAMETERS Controllers[IDE_MAX_CONTROLLERS] = 
105 {
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}*/
110 };
111
112 static BOOLEAN IDEInitialized = FALSE;
113
114 //  -----------------------------------------------  Discardable Declarations
115
116 #ifdef  ALLOC_PRAGMA
117
118 //  make the initialization routines discardable, so that they 
119 //  don't waste space
120
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)
126
127 //  make the PASSIVE_LEVEL routines pageable, so that they don't
128 //  waste nonpaged memory
129
130 #pragma  alloc_text(page, IDEShutdown)
131 #pragma  alloc_text(page, IDEDispatchOpenClose)
132 #pragma  alloc_text(page, IDEDispatchRead)
133 #pragma  alloc_text(page, IDEDispatchWrite)
134
135 #endif  /*  ALLOC_PRAGMA  */
136
137 //  ---------------------------------------------------- Forward Declarations
138
139 static NTSTATUS
140 IdeFindControllers(IN PDRIVER_OBJECT DriverObject);
141
142 static NTSTATUS
143 IdeCreateController(IN PDRIVER_OBJECT DriverObject,
144                     IN PIDE_CONTROLLER_PARAMETERS ControllerParams,
145                     IN int ControllerIdx);
146
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,
151                                 IN int DriveIdx,
152                                 IN int HarddiskIdx);
153 static BOOLEAN IDEGetDriveIdentification(IN int CommandPort,
154                                          IN int DriveNum,
155                                          OUT PIDE_DRIVE_IDENTIFY DrvParms);
156 static NTSTATUS IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject,
157                                 OUT PDEVICE_OBJECT *DeviceObject,
158                                 IN PCONTROLLER_OBJECT ControllerObject,
159                                 IN int UnitNumber,
160                                 IN ULONG DiskNumber,
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,
167                                          IN int UnitNumber,
168                                          IN ULONG DiskNumber,
169                                          IN PIDE_DRIVE_IDENTIFY DrvParms,
170                                          IN PPARTITION_INFORMATION PartitionInfo);
171 static int IDEPolledRead(IN WORD Address,
172                          IN BYTE PreComp,
173                          IN BYTE SectorCnt,
174                          IN BYTE SectorNum,
175                          IN BYTE CylinderLow,
176                          IN BYTE CylinderHigh,
177                          IN BYTE DrvHead,
178                          IN BYTE Command,
179                          OUT BYTE *Buffer);
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,
186                       IN PIRP Irp,
187                       IN PVOID MapRegisterBase,
188                       IN PVOID Ccontext);
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,
195                          IN PIRP DpcIrp,
196                          IN PVOID DpcContext);
197 static VOID IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension);
198 static VOID STDCALL IDEIoTimer(PDEVICE_OBJECT DeviceObject, PVOID Context);
199
200 //  ----------------------------------------------------------------  Inlines
201
202 void
203 IDESwapBytePairs(char *Buf,
204                  int Cnt)
205 {
206   char  t;
207   int   i;
208
209   for (i = 0; i < Cnt; i += 2)
210     {
211       t = Buf[i];
212       Buf[i] = Buf[i+1];
213       Buf[i+1] = t;
214     }
215 }
216
217 //  -------------------------------------------------------  Public Interface
218
219 //    DriverEntry
220 //
221 //  DESCRIPTION:
222 //    This function initializes the driver, locates and claims 
223 //    hardware resources, and creates various NT objects needed
224 //    to process I/O requests.
225 //
226 //  RUN LEVEL:
227 //    PASSIVE_LEVEL
228 //
229 //  ARGUMENTS:
230 //    IN  PDRIVER_OBJECT   DriverObject  System allocated Driver Object
231 //                                       for this driver
232 //    IN  PUNICODE_STRING  RegistryPath  Name of registry driver service 
233 //                                       key
234 //
235 //  RETURNS:
236 //    NTSTATUS  
237
238 STDCALL NTSTATUS
239 DriverEntry(IN PDRIVER_OBJECT DriverObject,
240             IN PUNICODE_STRING RegistryPath)
241 {
242   NTSTATUS Status;
243
244   DPRINT("IDE Driver %s\n", VERSION);
245
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;
255
256   Status = IdeFindControllers(DriverObject);
257   if (NT_SUCCESS(Status))
258     {
259       IDEInitialized = TRUE;
260     }
261
262   return(Status);
263 }
264
265 //  ----------------------------------------------------  Discardable statics
266
267 static NTSTATUS
268 IdeFindControllers(IN PDRIVER_OBJECT DriverObject)
269 {
270   PCI_COMMON_CONFIG PciConfig;
271   ULONG Bus;
272   ULONG Slot;
273   ULONG Size;
274   ULONG i;
275   NTSTATUS ReturnedStatus = STATUS_NO_SUCH_DEVICE;
276   NTSTATUS Status;
277   INT ControllerIdx = 0;
278   PCONFIGURATION_INFORMATION ConfigInfo;
279
280   DPRINT("IdeFindControllers() called!\n");
281
282   ConfigInfo = IoGetConfigurationInformation();
283
284   /* Search PCI busses for IDE controllers */
285   for (Bus = 0; Bus < 8; Bus++)
286     {
287       for (Slot = 0; Slot < 256; Slot++)
288         {
289           Size = HalGetBusData(PCIConfiguration,
290                                Bus,
291                                Slot,
292                                &PciConfig,
293                                sizeof(PCI_COMMON_CONFIG));
294           if (Size != 0)
295             {
296               if ((PciConfig.BaseClass == 0x01) &&
297                   (PciConfig.SubClass == 0x01))
298                 {
299                   DPRINT("IDE controller found!\n");
300
301                   DPRINT("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",
302                         Bus,
303                         Slot>>3,
304                         Slot & 0x07,
305                         PciConfig.VendorID,
306                         PciConfig.DeviceID);
307                   if ((PciConfig.HeaderType & 0x7FFFFFFF) == 0)
308                     {
309                       DPRINT("  IPR 0x%X  ILR 0x%X\n",
310                               PciConfig.u.type0.InterruptPin,
311                               PciConfig.u.type0.InterruptLine);
312                     }
313
314                   if (PciConfig.ProgIf & 0x01)
315                     {
316                       DPRINT("Primary channel: PCI native mode\n");
317                     }
318                   else
319                     {
320                       DPRINT("Primary channel: Compatibility mode\n");
321                       if (ConfigInfo->AtDiskPrimaryAddressClaimed == FALSE)
322                         {
323                           Status = IdeCreateController(DriverObject,
324                                                        &Controllers[0],
325                                                        ControllerIdx);
326                           if (NT_SUCCESS(Status))
327                             {
328                               ControllerIdx++;
329                               ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
330                               ConfigInfo->ScsiPortCount++;
331                               ReturnedStatus = Status;
332                             }
333                         }
334                       else
335                         {
336                           /*
337                            * FIXME: Switch controller to native pci mode
338                            *        if it is programmable.
339                            */
340                         }
341                     }
342                   if (PciConfig.ProgIf & 0x02)
343                     {
344                       DPRINT("Primary channel: programmable\n");
345                     }
346                   else
347                     {
348                       DPRINT("Primary channel: not programmable\n");
349                     }
350
351 #ifdef ENABLE_SECONDARY_IDE_CHANNEL
352                   if (PciConfig.ProgIf & 0x04)
353                     {
354                       DPRINT("Secondary channel: PCI native mode\n");
355                     }
356                   else
357                     {
358                       DPRINT("Secondary channel: Compatibility mode\n");
359                       if (ConfigInfo->AtDiskSecondaryAddressClaimed == FALSE)
360                         {
361                           Status = IdeCreateController(DriverObject,
362                                                        &Controllers[1],
363                                                        ControllerIdx);
364                           if (NT_SUCCESS(Status))
365                             {
366                               ControllerIdx++;
367                               ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
368                               ConfigInfo->ScsiPortCount++;
369                               ReturnedStatus = Status;
370                             }
371                         }
372                       else
373                         {
374                           /*
375                            * FIXME: Switch controller to native pci mode
376                            *        if it is programmable.
377                            */
378                         }
379                     }
380                   if (PciConfig.ProgIf & 0x08)
381                     {
382                       DPRINT("Secondary channel: programmable\n");
383                     }
384                   else
385                     {
386                       DPRINT("Secondary channel: not programmable\n");
387                     }
388
389                   if (PciConfig.ProgIf & 0x80)
390                     {
391                       DPRINT("Master IDE device: 1\n");
392                     }
393                   else
394                     {
395                       DPRINT("Master IDE device: 0\n");
396                     }
397
398                   for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
399                     {
400                       DPRINT("BaseAddress: 0x%08X\n", PciConfig.u.type0.BaseAddresses[i]);
401                     }
402 #endif
403                 }
404             }
405         }
406     }
407
408   /* Search for ISA IDE controller if no primary controller was found */
409   if (ConfigInfo->AtDiskPrimaryAddressClaimed == FALSE)
410     {
411       DPRINT("Searching for primary ISA IDE controller!\n");
412
413       if (IDEResetController(Controllers[0].CommandPortBase,
414                              Controllers[0].ControlPortBase))
415         {
416           Status = IdeCreateController(DriverObject,
417                                        &Controllers[0],
418                                        0);
419           if (NT_SUCCESS(Status))
420             {
421               DPRINT("  Found primary ISA IDE controller!\n");
422               ControllerIdx++;
423               ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
424               ConfigInfo->ScsiPortCount++;
425               ReturnedStatus = Status;
426             }
427         }
428     }
429
430   /* Search for ISA IDE controller if no secondary controller was found */
431 #ifdef ENABLE_SECONDARY_IDE_CHANNEL
432   if (ConfigInfo->AtDiskSecondaryAddressClaimed == FALSE)
433     {
434       DPRINT("Searching for secondary ISA IDE controller!\n");
435
436       if (IDEResetController(Controllers[1].CommandPortBase,
437                              Controllers[1].ControlPortBase))
438         {
439           Status = IdeCreateController(DriverObject,
440                                        &Controllers[1],
441                                        1);
442           if (NT_SUCCESS(Status))
443             {
444               DPRINT("  Found secondary ISA IDE controller!\n");
445               ControllerIdx++;
446               ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
447               ConfigInfo->ScsiPortCount++;
448               ReturnedStatus = Status;
449             }
450         }
451     }
452 #endif
453
454   DPRINT("IdeFindControllers() done!\n");
455
456   return(ReturnedStatus);
457 }
458
459
460 //    IdeCreateController
461 //
462 //  DESCRIPTION:
463 //    Creates a controller object and a device object for each valid
464 //    device on the controller
465 //
466 //  RUN LEVEL:
467 //    PASSIVE LEVEL
468 //
469 //  ARGUMENTS:
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
474 //
475 //  RETURNS:
476 //    TRUE   Devices where found on this controller
477 //    FALSE  The controller does not respond or there are no devices on it
478 //
479
480 static NTSTATUS
481 IdeCreateController(IN PDRIVER_OBJECT DriverObject,
482                     IN PIDE_CONTROLLER_PARAMETERS ControllerParams,
483                     IN int ControllerIdx)
484 {
485   BOOLEAN                    CreatedDevices, ThisDriveExists;
486   int                        DriveIdx;
487   NTSTATUS                   RC;
488   PCONTROLLER_OBJECT         ControllerObject;
489   PIDE_CONTROLLER_EXTENSION  ControllerExtension;
490
491   ControllerObject = IoCreateController(sizeof(IDE_CONTROLLER_EXTENSION));
492   if (ControllerObject == NULL)
493     {
494       DbgPrint ("Could not create controller object for controller %d\n",
495                 ControllerIdx);
496       return STATUS_NO_SUCH_DEVICE;
497     }
498
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;
509
510     //  Initialize the spin lock in the controller extension
511   KeInitializeSpinLock(&ControllerExtension->SpinLock);
512
513     //  Register an interrupt handler for this controller
514   RC = IoConnectInterrupt(&ControllerExtension->Interrupt,
515                           IDEIsr,
516                           ControllerExtension,
517                           &ControllerExtension->SpinLock,
518                           ControllerExtension->Vector,
519                           ControllerParams->IrqL,
520                           ControllerParams->SynchronizeIrqL,
521                           ControllerParams->InterruptMode,
522                           FALSE,
523                           ControllerParams->Affinity,
524                           FALSE);
525   if (!NT_SUCCESS(RC))
526     {
527       DbgPrint ("Could not Connect Interrupt %d\n", 
528                 ControllerExtension->Vector);
529       IoDeleteController (ControllerObject);
530       return RC;
531     }
532
533 /* TEST */
534    IDEInitialized = TRUE;
535
536     //  Create device objects for each raw device (and for partitions) 
537   CreatedDevices = FALSE;
538   for (DriveIdx = 0; DriveIdx < IDE_MAX_DRIVES; DriveIdx++) 
539     {
540       ThisDriveExists = IDECreateDevices(DriverObject, 
541                                          ControllerObject,
542                                          ControllerExtension, 
543                                          DriveIdx, 
544                                          ControllerIdx * 2 + DriveIdx);
545       if (ThisDriveExists) 
546         {
547           CreatedDevices = TRUE;
548         }
549     }
550
551   if (!CreatedDevices)
552     {
553       DbgPrint ("Did not find any devices for controller %d\n", 
554                 ControllerIdx);
555       IoDisconnectInterrupt (ControllerExtension->Interrupt);
556       IoDeleteController (ControllerObject);
557     }
558   else
559     {
560       IDEResetController(ControllerParams->CommandPortBase,
561                          ControllerParams->ControlPortBase);
562       IoStartTimer(ControllerExtension->TimerDevice);
563     }
564
565   return((CreatedDevices == TRUE)?STATUS_SUCCESS:STATUS_NO_SUCH_DEVICE);
566 }
567
568
569 //    IDEResetController
570 //
571 //  DESCRIPTION:
572 //    Reset the controller and report completion status
573 //
574 //  RUN LEVEL:
575 //    PASSIVE_LEVEL
576 //
577 //  ARGUMENTS:
578 //    IN  WORD  CommandPort  The address of the command port
579 //    IN  WORD  ControlPort  The address of the control port
580 //
581 //  RETURNS:
582 //
583
584 BOOLEAN  
585 IDEResetController(IN WORD CommandPort, 
586                    IN WORD ControlPort) 
587 {
588   int  Retries;
589
590     //  Assert drive reset line
591   IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
592
593     //  Wait for min. 25 microseconds
594   KeStallExecutionProcessor(IDE_RESET_PULSE_LENGTH);
595
596     //  Negate drive reset line
597   IDEWriteDriveControl(ControlPort, 0);
598
599     //  Wait for BUSY negation
600   for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
601     {
602       if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
603         {
604           break;
605         }
606       KeStallExecutionProcessor(10);
607     }
608   CHECKPOINT;
609   if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
610     {
611       return FALSE;
612     }
613   CHECKPOINT;
614     //  return TRUE if controller came back to life. and
615     //  the registers are initialized correctly
616   return  IDEReadError(CommandPort) == 1;
617 }
618
619
620 //    IDECreateDevices
621 //
622 //  DESCRIPTION:
623 //    Create the raw device and any partition devices on this drive
624 //
625 //  RUN LEVEL:
626 //    PASSIVE_LEVEL
627 //
628 //  ARGUMENTS:
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
633 //                                      this device
634 //    IN  int             DriveIdx      The index of the drive on this
635 //                                      controller
636 //    IN  int             HarddiskIdx   The NT device number for this
637 //                                      drive
638 //
639 //  RETURNS:
640 //    TRUE   Drive exists and devices were created
641 //    FALSE  no devices were created for this device
642 //
643
644 BOOLEAN
645 IDECreateDevices(IN PDRIVER_OBJECT DriverObject,
646                  IN PCONTROLLER_OBJECT ControllerObject,
647                  IN PIDE_CONTROLLER_EXTENSION ControllerExtension,
648                  IN int DriveIdx,
649                  IN int HarddiskIdx)
650 {
651   WCHAR                  NameBuffer[IDE_MAX_NAME_LENGTH];
652   int                    CommandPort;
653   NTSTATUS               Status;
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;
660   HANDLE                 Handle;
661   ULONG                  SectorCount = 0;
662   PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
663   PPARTITION_INFORMATION PartitionEntry;
664   ULONG i;
665
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,
671          CommandPort,
672          DriveIdx);
673
674   /* Get the Drive Identification Data */
675   if (!IDEGetDriveIdentification(CommandPort, DriveIdx, &DrvParms))
676     {
677       DPRINT("No ATA drive %d found on controller %d...\n",
678              DriveIdx,
679              ControllerExtension->Number);
680       return(FALSE);
681     }
682
683   DPRINT("Found ATA drive %d on controller %d...\n",
684            DriveIdx,
685            ControllerExtension->Number);
686
687   /* Create the harddisk device directory */
688   swprintf (NameBuffer,
689             L"\\Device\\Harddisk%d",
690             HarddiskIdx);
691   RtlInitUnicodeString(&UnicodeDeviceDirName,
692                        NameBuffer);
693   InitializeObjectAttributes(&DeviceDirAttributes,
694                              &UnicodeDeviceDirName,
695                              0,
696                              NULL,
697                              NULL);
698   Status = ZwCreateDirectoryObject(&Handle, 0, &DeviceDirAttributes);
699   if (!NT_SUCCESS(Status))
700     {
701       DbgPrint("Could not create device dir object\n");
702       return(FALSE);
703     }
704
705   /* Create the disk device */
706   if (DrvParms.Capabilities & IDE_DRID_LBA_SUPPORTED)
707     {
708       SectorCount =
709          (ULONG)((DrvParms.TMSectorCountHi << 16) + DrvParms.TMSectorCountLo);
710     }
711   else
712     {
713       SectorCount =
714          (ULONG)(DrvParms.LogicalCyls * DrvParms.LogicalHeads * DrvParms.SectorsPerTrack);
715     }
716   DPRINT("SectorCount %lu\n", SectorCount);
717
718   Status = IDECreateDiskDevice(DriverObject,
719                                &DiskDeviceObject,
720                                ControllerObject,
721                                DriveIdx,
722                                HarddiskIdx,
723                                &DrvParms,
724                                SectorCount);
725   if (!NT_SUCCESS(Status))
726     {
727       DbgPrint("IDECreateDevice call failed for raw device\n");
728       return FALSE;
729     }
730
731   /* Increase number of available physical disk drives */
732   IoGetConfigurationInformation()->DiskCount++;
733
734   /*
735    * Initialize the controller timer here
736    * (since it has to be tied to a device)
737    */
738   if (DriveIdx == 0)
739     {
740       ControllerExtension->TimerState = IDETimerIdle;
741       ControllerExtension->TimerCount = 0;
742       ControllerExtension->TimerDevice = DiskDeviceObject;
743       IoInitializeTimer(DiskDeviceObject,
744                         IDEIoTimer,
745                         ControllerExtension);
746     }
747
748   DPRINT("DrvParms.BytesPerSector %ld\n",DrvParms.BytesPerSector);
749
750   /* Read partition table */
751   Status = IoReadPartitionTable(DiskDeviceObject,
752                                 DrvParms.BytesPerSector,
753                                 TRUE,
754                                 &PartitionList);
755   if (!NT_SUCCESS(Status))
756     {
757       DbgPrint("IoReadPartitionTable() failed\n");
758       return FALSE;
759     }
760
761   DPRINT("  Number of partitions: %u\n", PartitionList->PartitionCount);
762   for (i=0;i < PartitionList->PartitionCount; i++)
763     {
764       PartitionEntry = &PartitionList->PartitionEntry[i];
765
766       DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
767              i,
768              PartitionEntry->PartitionNumber,
769              PartitionEntry->BootIndicator,
770              PartitionEntry->PartitionType,
771              PartitionEntry->StartingOffset.QuadPart / DrvParms.BytesPerSector,
772              PartitionEntry->PartitionLength.QuadPart / DrvParms.BytesPerSector);
773
774       /* Create device for partition */
775       Status = IDECreatePartitionDevice(DriverObject,
776                                         &PartitionDeviceObject,
777                                         ControllerObject,
778                                         DiskDeviceObject->DeviceExtension,
779                                         DriveIdx,
780                                         HarddiskIdx,
781                                         &DrvParms,
782                                         PartitionEntry);
783       if (!NT_SUCCESS(Status))
784         {
785           DbgPrint("IDECreateDevice() failed\n");
786           break;
787         }
788     }
789
790   if (PartitionList != NULL)
791     ExFreePool(PartitionList);
792
793   return  TRUE;
794 }
795
796 //    IDEGetDriveIdentification
797 //
798 //  DESCRIPTION:
799 //    Get the identification block from the drive
800 //
801 //  RUN LEVEL:
802 //    PASSIVE_LEVEL
803 //
804 //  ARGUMENTS:
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
808 //
809 //  RETURNS:
810 //    TRUE  The drive identification block was retrieved successfully
811 //
812
813 static BOOLEAN
814 IDEGetDriveIdentification(IN int CommandPort,
815                           IN int DriveNum,
816                           OUT PIDE_DRIVE_IDENTIFY DrvParms)
817 {
818
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)
822     {
823       return(FALSE);
824     }
825
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,
855          DrvParms->TMHeads,
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));
862
863   /*
864    * Fix default ATA sector size.
865    * Attention: Default ATAPI sector size is 2048 bytes!!
866    */
867   DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
868   DrvParms->BytesPerSector = 512;
869   DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
870
871   return(TRUE);
872 }
873
874
875 //    IDECreateDiskDevice
876 //
877 //  DESCRIPTION:
878 //    Creates the disk device object
879 //
880 //  RUN LEVEL:
881 //    PASSIVE_LEVEL
882 //
883 //  ARGUMENTS:
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
893 //
894 //  RETURNS:
895 //    NTSTATUS
896 //
897
898 NTSTATUS
899 IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject,
900                     OUT PDEVICE_OBJECT *DeviceObject,
901                     IN PCONTROLLER_OBJECT ControllerObject,
902                     IN int UnitNumber,
903                     IN ULONG DiskNumber,
904                     IN PIDE_DRIVE_IDENTIFY DrvParms,
905                     IN ULONG SectorCount)
906 {
907   WCHAR                  NameBuffer[IDE_MAX_NAME_LENGTH];
908   UNICODE_STRING         DeviceName;
909   NTSTATUS               RC;
910   PIDE_DEVICE_EXTENSION  DeviceExtension;
911
912   /* Create a unicode device name */
913   swprintf(NameBuffer,
914            L"\\Device\\Harddisk%d\\Partition0",
915            DiskNumber);
916   RtlInitUnicodeString(&DeviceName,
917                        NameBuffer);
918
919   /* Create the device */
920   RC = IoCreateDevice(DriverObject,
921                       sizeof(IDE_DEVICE_EXTENSION),
922                       &DeviceName,
923                       FILE_DEVICE_DISK,
924                       0,
925                       TRUE,
926                       DeviceObject);
927   if (!NT_SUCCESS(RC))
928     {
929       DbgPrint("IoCreateDevice call failed\n");
930       return(RC);
931     }
932
933   /* Set the buffering strategy here... */
934   (*DeviceObject)->Flags |= DO_DIRECT_IO;
935   (*DeviceObject)->AlignmentRequirement = FILE_WORD_ALIGNMENT;
936
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;
954
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;
962
963   DPRINT("%wZ: offset %I64d length %I64d\n",
964          &DeviceName,
965          DeviceExtension->StartingOffset.QuadPart,
966          DeviceExtension->PartitionLength.QuadPart);
967
968   /* Initialize the DPC object here */
969   IoInitializeDpcRequest(*DeviceObject,
970                          IDEDpcForIsr);
971
972   return  RC;
973 }
974
975
976 //    IDECreatePartitionDevice
977 //
978 //  DESCRIPTION:
979 //    Creates a partition device object
980 //
981 //  RUN LEVEL:
982 //    PASSIVE_LEVEL
983 //
984 //  ARGUMENTS:
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
994 //
995 //  RETURNS:
996 //    NTSTATUS
997 //
998
999 NTSTATUS
1000 IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject,
1001                          OUT PDEVICE_OBJECT *DeviceObject,
1002                          IN PCONTROLLER_OBJECT ControllerObject,
1003                          IN PVOID DiskDeviceExtension,
1004                          IN int UnitNumber,
1005                          IN ULONG DiskNumber,
1006                          IN PIDE_DRIVE_IDENTIFY DrvParms,
1007                          IN PPARTITION_INFORMATION PartitionInfo)
1008 {
1009   WCHAR                  NameBuffer[IDE_MAX_NAME_LENGTH];
1010   UNICODE_STRING         DeviceName;
1011   NTSTATUS               RC;
1012   PIDE_DEVICE_EXTENSION  DeviceExtension;
1013
1014   /* Create a unicode device name */
1015   swprintf(NameBuffer,
1016            L"\\Device\\Harddisk%d\\Partition%d",
1017            DiskNumber,
1018            PartitionInfo->PartitionNumber);
1019   RtlInitUnicodeString(&DeviceName,
1020                        NameBuffer);
1021
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))
1026     {
1027       DbgPrint ("IoCreateDevice call failed\n");
1028       return  RC;
1029     }
1030
1031   /* Set the buffering strategy here... */
1032   (*DeviceObject)->Flags |= DO_DIRECT_IO;
1033   (*DeviceObject)->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1034
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;
1052
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;
1059
1060   DPRINT("%wZ: offset %I64d size %I64d\n",
1061          &DeviceName,
1062          DeviceExtension->StartingOffset.QuadPart,
1063          DeviceExtension->PartitionLength.QuadPart);
1064
1065   /* Initialize the DPC object here */
1066   IoInitializeDpcRequest(*DeviceObject, IDEDpcForIsr);
1067
1068   DPRINT("%wZ %I64dMB\n",
1069          &DeviceName,
1070          DeviceExtension->PartitionLength.QuadPart >> 20);
1071
1072   return  RC;
1073 }
1074
1075
1076 //    IDEPolledRead
1077 //
1078 //  DESCRIPTION:
1079 //    Read a sector of data from the drive in a polled fashion.
1080 //
1081 //  RUN LEVEL:
1082 //    PASSIVE_LEVEL
1083 //
1084 //  ARGUMENTS:
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
1094 //
1095 //  RETURNS:
1096 //    int  0 is success, non 0 is an error code
1097 //
1098
1099 static int
1100 IDEPolledRead(IN WORD Address,
1101               IN BYTE PreComp,
1102               IN BYTE SectorCnt,
1103               IN BYTE SectorNum,
1104               IN BYTE CylinderLow,
1105               IN BYTE CylinderHigh,
1106               IN BYTE DrvHead,
1107               IN BYTE Command,
1108               OUT BYTE *Buffer)
1109 {
1110   BYTE    Status;
1111   int     RetryCount;
1112   BOOLEAN ReadJunk = FALSE;
1113   ULONG   SectorCount = 0;
1114
1115   /*  Wait for STATUS.BUSY and STATUS.DRQ to clear  */
1116   for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1117     {
1118       Status = IDEReadStatus(Address);
1119       if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1120         {
1121           break;
1122         }
1123       KeStallExecutionProcessor(10);
1124     }
1125   if (RetryCount == IDE_MAX_BUSY_RETRIES)
1126     {
1127       return IDE_ER_ABRT;
1128     }
1129
1130   /*  Write Drive/Head to select drive  */
1131   IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
1132
1133   /*  Wait for STATUS.BUSY and STATUS.DRQ to clear  */
1134   for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1135     {
1136       Status = IDEReadStatus(Address);
1137       if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1138         {
1139           break;
1140         }
1141       KeStallExecutionProcessor(10);
1142     }
1143   if (RetryCount == IDE_MAX_BUSY_RETRIES)
1144     {
1145       return IDE_ER_ABRT;
1146     }
1147
1148   /*  Issue command to drive  */
1149   if (DrvHead & IDE_DH_LBA)
1150     {
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,
1154              SectorCnt,
1155              Command);
1156     }
1157   else
1158     {
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,
1161              CylinderHigh,
1162              CylinderLow,
1163              DrvHead & 0x0f,
1164              SectorNum,
1165              SectorCnt,
1166              Command);
1167     }
1168
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);
1176
1177   /*  Issue the command  */
1178   IDEWriteCommand(Address, Command);
1179   KeStallExecutionProcessor(50);
1180
1181       /*  wait for DRQ or error  */
1182       for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1183         {
1184           Status = IDEReadStatus(Address);
1185           if (!(Status & IDE_SR_BUSY))
1186             {
1187               if (Status & IDE_SR_ERR)
1188                 {
1189                   DPRINT("IDE_SR_ERR asserted!\n");
1190                 }
1191               if ((Status & IDE_SR_DRQ) && !(Status & IDE_SR_ERR))
1192                 {
1193                   break;
1194                 }
1195               else
1196                 {
1197                   return IDE_ER_ABRT;
1198                 }
1199             }
1200           KeStallExecutionProcessor(10);
1201         }
1202       if (RetryCount >= IDE_MAX_POLL_RETRIES)
1203         {
1204           return IDE_ER_ABRT;
1205         }
1206
1207   while (1)
1208     {
1209       /*  Read data into buffer  */
1210       if (ReadJunk == TRUE)
1211         {
1212           UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1213           IDEReadBlock(Address, JunkBuffer, IDE_SECTOR_BUF_SZ);
1214         }
1215       else
1216         {
1217           IDEReadBlock(Address, Buffer, IDE_SECTOR_BUF_SZ);
1218           Buffer += IDE_SECTOR_BUF_SZ;
1219         }
1220       SectorCount++;
1221
1222       /*  Check for more sectors to read  */
1223       for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1224         {
1225           Status = IDEReadStatus(Address);
1226           if (!(Status & IDE_SR_BUSY))
1227             {
1228               if (Status & IDE_SR_ERR)
1229                 {
1230                   DPRINT("IDE_SR_ERR asserted!\n");
1231                 }
1232               if (Status & IDE_SR_DRQ)
1233                 {
1234                   if (SectorCount >= SectorCnt)
1235                     ReadJunk = TRUE;
1236                   break;
1237                 }
1238               else
1239                 {
1240                   return 0;
1241                 }
1242             }
1243         }
1244     }
1245 }
1246
1247 //  -------------------------------------------  Nondiscardable statics
1248
1249 //    IDEDispatchOpenClose
1250 //
1251 //  DESCRIPTION:
1252 //    Answer requests for Open/Close calls: a null operation
1253 //
1254 //  RUN LEVEL:
1255 //    PASSIVE_LEVEL
1256 //
1257 //  ARGUMENTS:
1258 //    Standard dispatch arguments
1259 //
1260 //  RETURNS:
1261 //    NTSTATUS
1262 //
1263
1264 static NTSTATUS STDCALL
1265 IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO,
1266                      IN PIRP Irp)
1267 {
1268   Irp->IoStatus.Status = STATUS_SUCCESS;
1269   Irp->IoStatus.Information = FILE_OPENED;
1270   IoCompleteRequest(Irp, IO_NO_INCREMENT);
1271
1272   return STATUS_SUCCESS;
1273 }
1274
1275 //    IDEDispatchReadWrite
1276 //
1277 //  DESCRIPTION:
1278 //    Answer requests for reads and writes
1279 //
1280 //  RUN LEVEL:
1281 //    PASSIVE_LEVEL
1282 //
1283 //  ARGUMENTS:
1284 //    Standard dispatch arguments
1285 //
1286 //  RETURNS:
1287 //    NTSTATUS
1288 //
1289
1290 static NTSTATUS STDCALL
1291 IDEDispatchReadWrite(IN PDEVICE_OBJECT DeviceObject,
1292                      IN PIRP Irp)
1293 {
1294   ULONG                 IrpInsertKey;
1295   LARGE_INTEGER         AdjustedOffset, AdjustedExtent, PartitionExtent, InsertKeyLI;
1296   PIO_STACK_LOCATION    IrpStack;
1297   PIDE_DEVICE_EXTENSION DeviceExtension;
1298
1299   IrpStack = IoGetCurrentIrpStackLocation(Irp);
1300   DeviceExtension = (PIDE_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1301
1302     //  Validate operation parameters
1303   AdjustedOffset.QuadPart = DeviceExtension->StartingOffset.QuadPart +
1304                             IrpStack->Parameters.Read.ByteOffset.QuadPart;
1305   DPRINT("AdjustedOffset: %I64x\n", AdjustedOffset.QuadPart);
1306
1307   AdjustedExtent.QuadPart = AdjustedOffset.QuadPart +
1308                             (ULONGLONG)IrpStack->Parameters.Read.Length;
1309   DPRINT("AdjustedExtent: %I64x\n", AdjustedExtent.QuadPart);
1310
1311   PartitionExtent.QuadPart = DeviceExtension->StartingOffset.QuadPart +
1312                              DeviceExtension->PartitionLength.QuadPart;
1313   DPRINT("PartitionExtent: %I64x\n", PartitionExtent.QuadPart);
1314
1315   if ((AdjustedExtent.QuadPart > PartitionExtent.QuadPart) ||
1316       (IrpStack->Parameters.Read.Length & (DeviceExtension->BytesPerSector - 1)))
1317     {
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;
1326     }
1327
1328     //  Adjust operation to absolute sector offset
1329   IrpStack->Parameters.Read.ByteOffset = AdjustedOffset;
1330
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);
1336   
1337   DPRINT("Returning STATUS_PENDING\n");
1338   return  STATUS_PENDING;
1339 }
1340
1341 //    IDEDispatchDeviceControl
1342 //
1343 //  DESCRIPTION:
1344 //    Answer requests for device control calls
1345 //
1346 //  RUN LEVEL:
1347 //    PASSIVE_LEVEL
1348 //
1349 //  ARGUMENTS:
1350 //    Standard dispatch arguments
1351 //
1352 //  RETURNS:
1353 //    NTSTATUS
1354 //
1355
1356 static NTSTATUS STDCALL
1357 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1358                          IN PIRP Irp)
1359 {
1360   NTSTATUS  RC;
1361   ULONG     ControlCode, InputLength, OutputLength;
1362   PIO_STACK_LOCATION     IrpStack;
1363   PIDE_DEVICE_EXTENSION  DeviceExtension;
1364   PIDE_DEVICE_EXTENSION  DiskDeviceExtension;
1365   CCHAR Increment;
1366
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;
1375
1376     //  A huge switch statement in a Windows program?! who would have thought?
1377   switch (ControlCode)
1378     {
1379     case IOCTL_DISK_GET_DRIVE_GEOMETRY:
1380       if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
1381         {
1382           Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1383         }
1384       else
1385         {
1386           PDISK_GEOMETRY Geometry;
1387
1388           Geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
1389
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);
1399         }
1400       break;
1401
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))
1406         {
1407           Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
1408         }
1409       else if (DeviceExtension->PartitionNumber == 0)
1410         {
1411           Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1412         }
1413       else
1414         {
1415           PPARTITION_INFORMATION PartitionInfo;
1416
1417           PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
1418
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);
1428
1429           Irp->IoStatus.Status = STATUS_SUCCESS;
1430           Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
1431         }
1432       break;
1433
1434     case IOCTL_DISK_SET_PARTITION_INFO:
1435       RC = STATUS_INVALID_DEVICE_REQUEST;
1436       Irp->IoStatus.Status = RC;
1437       Irp->IoStatus.Information = 0;
1438       break;
1439
1440     case IOCTL_DISK_GET_DRIVE_LAYOUT:
1441       if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
1442           sizeof(DRIVE_LAYOUT_INFORMATION))
1443         {
1444           Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
1445         }
1446       else
1447         {
1448           PDRIVE_LAYOUT_INFORMATION PartitionList;
1449
1450           RC = IoReadPartitionTable(DiskDeviceExtension->DeviceObject,
1451                                     DiskDeviceExtension->BytesPerSector,
1452                                     FALSE,
1453                                     &PartitionList);
1454           if (!NT_SUCCESS(RC))
1455             {
1456               Irp->IoStatus.Status = RC;
1457             }
1458           else
1459             {
1460               ULONG BufferSize;
1461
1462               BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
1463                                         PartitionEntry[0]);
1464               BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
1465
1466               if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
1467                 {
1468                   Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
1469                 }
1470               else
1471                 {
1472                   RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
1473                                 PartitionList,
1474                                 BufferSize);
1475                   Irp->IoStatus.Status = STATUS_SUCCESS;
1476                   Irp->IoStatus.Information = BufferSize;
1477                 }
1478               ExFreePool(PartitionList);
1479             }
1480         }
1481         Increment = IO_DISK_INCREMENT;
1482         break;
1483
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:
1496
1497       //  If we get here, something went wrong.  inform the requestor
1498     default:
1499       RC = STATUS_INVALID_DEVICE_REQUEST;
1500       Irp->IoStatus.Status = RC;
1501       Irp->IoStatus.Information = 0;
1502       break;
1503     }
1504
1505   IoCompleteRequest(Irp, Increment);
1506
1507   return  RC;
1508 }
1509
1510 //    IDEStartIo
1511 //
1512 //  DESCRIPTION:
1513 //    Get the next requested I/O packet started
1514 //
1515 //  RUN LEVEL:
1516 //    DISPATCH_LEVEL
1517 //
1518 //  ARGUMENTS:
1519 //    Dispatch routine standard arguments
1520 //
1521 //  RETURNS:
1522 //    NTSTATUS
1523 //
1524
1525 static  VOID  
1526 STDCALL IDEStartIo(IN PDEVICE_OBJECT DeviceObject, 
1527            IN PIRP Irp) 
1528 {
1529   LARGE_INTEGER              SectorLI;
1530   PIO_STACK_LOCATION         IrpStack;
1531   PIDE_DEVICE_EXTENSION      DeviceExtension;
1532   KIRQL                      OldIrql;
1533   
1534   DPRINT("IDEStartIo() called!\n");
1535   
1536   IrpStack = IoGetCurrentIrpStackLocation(Irp);
1537   DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1538
1539     // FIXME: implement the supported functions
1540
1541   switch (IrpStack->MajorFunction) 
1542     {
1543     case IRP_MJ_READ:
1544     case IRP_MJ_WRITE:
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) 
1552         {
1553           DeviceExtension->BytesToTransfer = DeviceExtension->BytesPerSector * 
1554               IDE_MAX_SECTORS_PER_XFER;
1555         } 
1556       else 
1557         {
1558           DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
1559         }
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,
1565                            DeviceObject, 
1566                            IDEAllocateController, 
1567                            NULL);
1568       KeLowerIrql(OldIrql);
1569       break;
1570
1571     default:
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);
1577       break;
1578     }
1579   DPRINT("IDEStartIo() finished!\n");
1580 }
1581
1582 //    IDEAllocateController
1583
1584 static IO_ALLOCATION_ACTION STDCALL
1585 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject,
1586                       IN PIRP Irp,
1587                       IN PVOID MapRegisterBase,
1588                       IN PVOID Ccontext) 
1589 {
1590   PIDE_DEVICE_EXTENSION  DeviceExtension;
1591   PIDE_CONTROLLER_EXTENSION  ControllerExtension;
1592
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, 
1599                                 IDEStartController,
1600                                 DeviceExtension) ? KeepObject : 
1601                                   DeallocateObject;
1602 }
1603
1604 //    IDEStartController
1605
1606 BOOLEAN STDCALL
1607 IDEStartController(IN OUT PVOID Context)
1608 {
1609   BYTE  SectorCnt, SectorNum, CylinderLow, CylinderHigh;
1610   BYTE  DrvHead, Command;
1611   BYTE  Status;
1612   int  Retries;
1613   ULONG  StartingSector;
1614   PIDE_DEVICE_EXTENSION  DeviceExtension;
1615   PIDE_CONTROLLER_EXTENSION  ControllerExtension;
1616   PIRP  Irp;
1617
1618   DeviceExtension = (PIDE_DEVICE_EXTENSION) Context;
1619   ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
1620       DeviceExtension->ControllerObject->ControllerExtension;
1621   ControllerExtension->OperationInProgress = TRUE;
1622   ControllerExtension->DeviceForOperation = DeviceExtension;
1623
1624     //  Write controller registers to start opteration
1625   StartingSector = DeviceExtension->StartingSector;
1626   SectorCnt = DeviceExtension->BytesToTransfer / 
1627       DeviceExtension->BytesPerSector;
1628   if (DeviceExtension->LBASupported) 
1629     {
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) |
1635           IDE_DH_LBA;
1636     } 
1637   else 
1638     {
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;
1646     }
1647   Command = DeviceExtension->Operation == IRP_MJ_READ ? 
1648      IDE_CMD_READ : IDE_CMD_WRITE;
1649   if (DrvHead & IDE_DH_LBA) 
1650     {
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,
1657              SectorCnt, 
1658              Command);
1659     } 
1660   else 
1661     {
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, 
1666              CylinderHigh, 
1667              CylinderLow, 
1668              DrvHead & 0x0f, 
1669              SectorNum, 
1670              SectorCnt, 
1671              Command);
1672     }
1673
1674   /*  wait for BUSY to clear  */
1675   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1676     {
1677       Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1678       if (!(Status & IDE_SR_BUSY)) 
1679         {
1680           break;
1681         }
1682       KeStallExecutionProcessor(10);
1683     }
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)
1687     {
1688       DPRINT ("Drive is BUSY for too long\n");
1689       if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1690         {
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;
1695
1696           return FALSE;
1697         }
1698       else
1699         {
1700           DPRINT ("Beginning drive reset sequence\n");
1701           IDEBeginControllerReset(ControllerExtension);
1702
1703           return TRUE;
1704         }
1705     }
1706
1707   /*  Select the desired drive  */
1708   IDEWriteDriveHead(ControllerExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1709
1710   /*  wait for BUSY to clear and DRDY to assert */
1711   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1712     {
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))
1716         {
1717           break;
1718         }
1719       KeStallExecutionProcessor(10);
1720     }
1721   DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1722   if (Retries >= IDE_MAX_BUSY_RETRIES)
1723     {
1724       DPRINT ("Drive is BUSY for too long after drive select\n");
1725       if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1726         {
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;
1731
1732           return FALSE;
1733         }
1734       else
1735         {
1736           DPRINT ("Beginning drive reset sequence\n");
1737           IDEBeginControllerReset(ControllerExtension);
1738
1739           return TRUE;
1740         }
1741     }
1742
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);
1750
1751   /*  Issue command to drive  */
1752   IDEWriteCommand(ControllerExtension->CommandPortBase, Command);
1753   ControllerExtension->TimerState = IDETimerCmdWait;
1754   ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1755   
1756   if (DeviceExtension->Operation == IRP_MJ_WRITE) 
1757     {
1758
1759         //  Wait for controller ready
1760       for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++) 
1761         {
1762           BYTE  Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1763           if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR)) 
1764             {
1765               break;
1766             }
1767           KeStallExecutionProcessor(10);
1768         }
1769       if (Retries >= IDE_MAX_BUSY_RETRIES)
1770         {
1771           if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1772             {
1773               Irp = ControllerExtension->CurrentIrp;
1774               Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1775               Irp->IoStatus.Information = 0;
1776
1777               return FALSE;
1778             }
1779           else
1780             {
1781               IDEBeginControllerReset(ControllerExtension);
1782
1783               return TRUE;
1784             }
1785         }
1786
1787         //  Load the first sector of data into the controller
1788       IDEWriteBlock(ControllerExtension->CommandPortBase, 
1789                     DeviceExtension->TargetAddress,
1790                     IDE_SECTOR_BUF_SZ);
1791       DeviceExtension->TargetAddress += IDE_SECTOR_BUF_SZ;
1792       DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1793       DeviceExtension->SectorsTransferred++;
1794     }
1795   DPRINT ("Command issued to drive, IDEStartController done\n");
1796
1797   return  TRUE;
1798 }
1799
1800 //    IDEBeginControllerReset
1801
1802 VOID 
1803 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension)
1804 {
1805   int Retries;
1806
1807   DPRINT("Controller Reset initiated on %04x\n", 
1808          ControllerExtension->ControlPortBase);
1809
1810     /*  Assert drive reset line  */
1811   DPRINT("Asserting reset line\n");
1812   IDEWriteDriveControl(ControllerExtension->ControlPortBase, IDE_DC_SRST);
1813
1814     /*  Wait for BSY assertion  */
1815   DPRINT("Waiting for BSY assertion\n");
1816   for (Retries = 0; Retries < IDE_MAX_RESET_RETRIES; Retries++) 
1817     {
1818       BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1819       if ((Status & IDE_SR_BUSY)) 
1820         {
1821           break;
1822         }
1823       KeStallExecutionProcessor(10);
1824     }
1825   if (Retries == IDE_MAX_RESET_RETRIES)
1826     {
1827       DPRINT("Timeout on BSY assertion\n");
1828     }
1829
1830     /*  Negate drive reset line  */
1831   DPRINT("Negating reset line\n");
1832   IDEWriteDriveControl(ControllerExtension->ControlPortBase, 0);
1833
1834   // FIXME: handle case of no device 0
1835
1836     /*  Set timer to check for end of reset  */
1837   ControllerExtension->TimerState = IDETimerResetWaitForBusyNegate;
1838   ControllerExtension->TimerCount = IDE_RESET_BUSY_TIMEOUT;
1839 }
1840
1841 //    IDEIsr
1842 //
1843 //  DESCIPTION:
1844 //    Handle interrupts for IDE devices
1845 //
1846 //  RUN LEVEL:
1847 //    DIRQL
1848 //
1849 //  ARGUMENTS:
1850 //    IN  PKINTERRUPT  Interrupt       The interrupt level in effect
1851 //    IN  PVOID        ServiceContext  The driver supplied context
1852 //                                     (the controller extension)
1853 //  RETURNS:
1854 //    TRUE   This ISR handled the interrupt
1855 //    FALSE  Another ISR must handle this interrupt
1856
1857 static BOOLEAN STDCALL
1858 IDEIsr(IN PKINTERRUPT Interrupt,
1859        IN PVOID ServiceContext)
1860 {
1861   BOOLEAN   IsLastBlock, AnErrorOccured, RequestIsComplete;
1862   BYTE     *TargetAddress;
1863   int       Retries;
1864   NTSTATUS  ErrorStatus;
1865   ULONG     ErrorInformation;
1866   PIRP  Irp;
1867   PIDE_DEVICE_EXTENSION  DeviceExtension;
1868   PIDE_CONTROLLER_EXTENSION  ControllerExtension;
1869
1870   if (IDEInitialized == FALSE)
1871     {
1872       return FALSE;
1873     }
1874   DPRINT ("IDEIsr called\n");
1875
1876   ControllerExtension = (PIDE_CONTROLLER_EXTENSION) ServiceContext;
1877
1878     //  Read the status port to clear the interrtupt (even if it's not ours).
1879   ControllerExtension->DeviceStatus = IDEReadStatus(ControllerExtension->CommandPortBase);
1880
1881     //  If the interrupt is not ours, get the heck outta dodge.
1882   if (!ControllerExtension->OperationInProgress)
1883     {
1884       return FALSE;
1885     }
1886
1887   DeviceExtension = ControllerExtension->DeviceForOperation;
1888   IsLastBlock = FALSE;
1889   AnErrorOccured = FALSE;
1890   RequestIsComplete = FALSE;
1891   ErrorStatus = STATUS_SUCCESS;
1892   ErrorInformation = 0;
1893
1894     //  Handle error condition if it exists
1895   if (ControllerExtension->DeviceStatus & IDE_SR_ERR) 
1896     {
1897       BYTE ErrorReg, SectorCount, SectorNum, CylinderLow, CylinderHigh;
1898       BYTE DriveHead;
1899
1900         //  Log the error
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, 
1911                 ErrorReg, 
1912                 CylinderLow,
1913                 CylinderHigh, 
1914                 SectorCount, 
1915                 SectorNum);
1916
1917         // FIXME: should retry the command and perhaps recalibrate the drive
1918
1919         //  Set error status information
1920       AnErrorOccured = TRUE;
1921       ErrorStatus = STATUS_DISK_OPERATION_FAILED;
1922       ErrorInformation = 
1923           (((((((CylinderHigh << 8) + CylinderLow) * 
1924               DeviceExtension->LogicalHeads) + 
1925               (DriveHead % DeviceExtension->LogicalHeads)) * 
1926               DeviceExtension->SectorsPerLogTrk) + SectorNum - 1) -
1927           DeviceExtension->StartingSector) * DeviceExtension->BytesPerSector;
1928     } 
1929   else 
1930     {
1931
1932         // Check controller and setup for next transfer
1933       switch (DeviceExtension->Operation) 
1934         {
1935         case  IRP_MJ_READ:
1936
1937             //  Update controller/device state variables
1938           TargetAddress = DeviceExtension->TargetAddress;
1939           DeviceExtension->TargetAddress += DeviceExtension->BytesPerSector;
1940           DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1941           DeviceExtension->SectorsTransferred++;
1942
1943             //  Remember whether DRQ should be low at end (last block read)
1944           IsLastBlock = DeviceExtension->BytesToTransfer == 0;
1945
1946             //  Wait for DRQ assertion
1947           for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
1948               !(IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ);
1949               Retries++) 
1950             {
1951               KeStallExecutionProcessor(10);
1952             }
1953
1954             //  Copy the block of data
1955           IDEReadBlock(ControllerExtension->CommandPortBase, 
1956                        TargetAddress,
1957                        IDE_SECTOR_BUF_SZ);
1958
1959             //  check DRQ
1960           if (IsLastBlock) 
1961             {
1962               for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
1963                   (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_BUSY);
1964                   Retries++) 
1965                 {
1966                   KeStallExecutionProcessor(10);
1967                 }
1968
1969                 //  Check for data overrun
1970               if (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ) 
1971                 {
1972                   AnErrorOccured = TRUE;
1973                   ErrorStatus = STATUS_DATA_OVERRUN;
1974                   ErrorInformation = 0;
1975                 } 
1976               else 
1977                 {
1978
1979                     //  Setup next transfer or set RequestIsComplete
1980                   if (DeviceExtension->BytesRequested > 
1981                       DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER) 
1982                     {
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;
1988                     } 
1989                   else if (DeviceExtension->BytesRequested > 0) 
1990                     {
1991                       DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
1992                       DeviceExtension->SectorsTransferred = 0;
1993                       DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
1994                       DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1995                     } 
1996                   else
1997                     {
1998                       RequestIsComplete = TRUE;
1999                     }
2000                 }
2001             }
2002           break;
2003
2004         case IRP_MJ_WRITE:
2005
2006             //  check DRQ
2007           if (DeviceExtension->BytesToTransfer == 0) 
2008             {
2009               for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
2010                   (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_BUSY);
2011                    Retries++) 
2012                 {
2013                   KeStallExecutionProcessor(10);
2014                 }
2015
2016                 //  Check for data overrun
2017               if (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ) 
2018                 {
2019                   AnErrorOccured = TRUE;
2020                   ErrorStatus = STATUS_DATA_OVERRUN;
2021                   ErrorInformation = 0;
2022                 } 
2023               else 
2024                 {
2025
2026                     //  Setup next transfer or set RequestIsComplete
2027                   IsLastBlock = TRUE;
2028                   if (DeviceExtension->BytesRequested > 
2029                       DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER) 
2030                     {
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;
2036                     } 
2037                   else if (DeviceExtension->BytesRequested > 0) 
2038                     {
2039                       DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
2040                       DeviceExtension->SectorsTransferred = 0;
2041                       DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
2042                       DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
2043                     } 
2044                   else 
2045                     {
2046                       RequestIsComplete = TRUE;
2047                     }
2048                 }
2049             } 
2050           else 
2051             {
2052
2053                 //  Update controller/device state variables
2054               TargetAddress = DeviceExtension->TargetAddress;
2055               DeviceExtension->TargetAddress += DeviceExtension->BytesPerSector;
2056               DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
2057               DeviceExtension->SectorsTransferred++;
2058
2059                 //  Write block to controller
2060               IDEWriteBlock(ControllerExtension->CommandPortBase, 
2061                             TargetAddress,
2062                             IDE_SECTOR_BUF_SZ);
2063             }
2064           break;
2065         }
2066     }
2067
2068   //  If there was an error or the request is done, complete the packet
2069   if (AnErrorOccured || RequestIsComplete) 
2070     {
2071       //  Set the return status and info values
2072       Irp = ControllerExtension->CurrentIrp;
2073       Irp->IoStatus.Status = ErrorStatus;
2074       Irp->IoStatus.Information = ErrorInformation;
2075
2076       //  Clear out controller fields
2077       ControllerExtension->OperationInProgress = FALSE;
2078       ControllerExtension->DeviceStatus = 0;
2079
2080       //  Queue the Dpc to finish up
2081       IoRequestDpc(DeviceExtension->DeviceObject, 
2082                    Irp, 
2083                    ControllerExtension);
2084     } 
2085   else if (IsLastBlock)
2086     {
2087       //  Else more data is needed, setup next device I/O
2088       IDEStartController((PVOID)DeviceExtension);
2089     }
2090
2091   return TRUE;
2092 }
2093
2094 //    IDEDpcForIsr
2095 //  DESCRIPTION:
2096 //
2097 //  RUN LEVEL:
2098 //
2099 //  ARGUMENTS:
2100 //    IN PKDPC          Dpc
2101 //    IN PDEVICE_OBJECT DpcDeviceObject
2102 //    IN PIRP           DpcIrp
2103 //    IN PVOID          DpcContext
2104 //
2105 static VOID
2106 IDEDpcForIsr(IN PKDPC Dpc,
2107              IN PDEVICE_OBJECT DpcDeviceObject,
2108              IN PIRP DpcIrp,
2109              IN PVOID DpcContext)
2110 {
2111   DPRINT("IDEDpcForIsr()\n");
2112   IDEFinishOperation((PIDE_CONTROLLER_EXTENSION) DpcContext);
2113 }
2114
2115 //    IDEFinishOperation
2116
2117 static VOID
2118 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension)
2119 {
2120   PIDE_DEVICE_EXTENSION DeviceExtension;
2121   PIRP Irp;
2122   ULONG Operation;
2123
2124   DeviceExtension = ControllerExtension->DeviceForOperation;
2125   Irp = ControllerExtension->CurrentIrp;
2126   Operation = DeviceExtension->Operation;
2127   ControllerExtension->OperationInProgress = FALSE;
2128   ControllerExtension->DeviceForOperation = 0;
2129   ControllerExtension->CurrentIrp = 0;
2130
2131   //  Deallocate the controller
2132   IoFreeController(DeviceExtension->ControllerObject);
2133
2134   //  Start the next packet
2135   IoStartNextPacketByKey(DeviceExtension->DeviceObject, 
2136                          FALSE, 
2137                          DeviceExtension->StartingSector);
2138
2139   //  Flush cache if necessary
2140   if (Operation == IRP_MJ_READ) 
2141     {
2142       KeFlushIoBuffers(Irp->MdlAddress, TRUE, FALSE);
2143     }
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);
2149 }
2150
2151 //    IDEIoTimer
2152 //  DESCRIPTION:
2153 //    This function handles timeouts and other time delayed processing
2154 //
2155 //  RUN LEVEL:
2156 //
2157 //  ARGUMENTS:
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
2161 //
2162 static VOID STDCALL
2163 IDEIoTimer(PDEVICE_OBJECT DeviceObject,
2164            PVOID Context)
2165 {
2166   PIDE_CONTROLLER_EXTENSION  ControllerExtension;
2167
2168     //  Setup Extension pointer
2169   ControllerExtension = (PIDE_CONTROLLER_EXTENSION) Context;
2170   DPRINT("Timer activated for %04lx\n", ControllerExtension->CommandPortBase);
2171
2172     //  Handle state change if necessary
2173   switch (ControllerExtension->TimerState) 
2174     {
2175       case IDETimerResetWaitForBusyNegate:
2176         if (!(IDEReadStatus(ControllerExtension->CommandPortBase) & 
2177             IDE_SR_BUSY))
2178           {
2179             DPRINT("Busy line has negated, waiting for DRDY assert\n");
2180             ControllerExtension->TimerState = IDETimerResetWaitForDrdyAssert;
2181             ControllerExtension->TimerCount = IDE_RESET_DRDY_TIMEOUT;
2182             return;
2183           }
2184         break;
2185         
2186       case IDETimerResetWaitForDrdyAssert:
2187         if (IDEReadStatus(ControllerExtension->CommandPortBase) & 
2188             IDE_SR_DRQ)
2189           {
2190             DPRINT("DRDY has asserted, reset complete\n");
2191             ControllerExtension->TimerState = IDETimerIdle;
2192             ControllerExtension->TimerCount = 0;
2193
2194               // FIXME: get diagnostic code from drive 0
2195
2196               /*  Start current packet command again  */
2197             if (!KeSynchronizeExecution(ControllerExtension->Interrupt, 
2198                                         IDEStartController,
2199                                         ControllerExtension->DeviceForOperation))
2200               {
2201                 IDEFinishOperation(ControllerExtension);
2202               }
2203             return;
2204           }
2205         break;
2206
2207       default:
2208         break;
2209     }
2210
2211     //  If we're counting down, then count.
2212   if (ControllerExtension->TimerCount > 0) 
2213     {
2214       ControllerExtension->TimerCount--;
2215
2216       //  Else we'll check the state and process if necessary
2217     } 
2218   else 
2219     {
2220       switch (ControllerExtension->TimerState) 
2221         {
2222           case IDETimerIdle:
2223             break;
2224
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)
2229               {
2230                  if (ControllerExtension->CurrentIrp != NULL)
2231                    {
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);
2236                    }
2237                 ControllerExtension->TimerState = IDETimerIdle;
2238                 ControllerExtension->TimerCount = 0;
2239               }
2240             else
2241               {
2242                 IDEBeginControllerReset(ControllerExtension);
2243               }
2244             break;
2245
2246           case IDETimerResetWaitForBusyNegate:
2247           case IDETimerResetWaitForDrdyAssert:
2248             if (ControllerExtension->CurrentIrp != NULL)
2249               {
2250                 DbgPrint ("Timeout waiting for drive reset, giving up on IRP\n");
2251                 ControllerExtension->CurrentIrp->IoStatus.Status = 
2252                   STATUS_IO_TIMEOUT;
2253                 ControllerExtension->CurrentIrp->IoStatus.Information = 0;
2254                 IDEFinishOperation(ControllerExtension);
2255               }
2256             ControllerExtension->TimerState = IDETimerIdle;
2257             ControllerExtension->TimerCount = 0;
2258             break;
2259         }
2260     }
2261 }
2262
2263