Fixed drive identification bug.
[reactos.git] / reactos / drivers / dd / ide / ide.c
1 /* $Id: ide.c,v 1.50 2002/01/24 10:04:50 ekohl Exp $
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 DbgPrint("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 ControllerIdx);
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 ControllerIdx);
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 DbgPrint("No ATA drive %d found on controller %d...\n",
678 DriveIdx,
679 ControllerExtension->Number);
680 return(FALSE);
681 }
682
683 DbgPrint("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 DPRINT1("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 a device by calling IoCreateDevice and a sylbolic link for Win32
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 WCHAR ArcNameBuffer[IDE_MAX_NAME_LENGTH + 15];
909 UNICODE_STRING DeviceName;
910 UNICODE_STRING ArcName;
911 NTSTATUS RC;
912 PIDE_DEVICE_EXTENSION DeviceExtension;
913
914 /* Create a unicode device name */
915 swprintf(NameBuffer,
916 L"\\Device\\Harddisk%d\\Partition0",
917 DiskNumber);
918 RtlInitUnicodeString(&DeviceName,
919 NameBuffer);
920
921 /* Create the device */
922 RC = IoCreateDevice(DriverObject,
923 sizeof(IDE_DEVICE_EXTENSION),
924 &DeviceName,
925 FILE_DEVICE_DISK,
926 0,
927 TRUE,
928 DeviceObject);
929 if (!NT_SUCCESS(RC))
930 {
931 DbgPrint("IoCreateDevice call failed\n");
932 return(RC);
933 }
934
935 /* Set the buffering strategy here... */
936 (*DeviceObject)->Flags |= DO_DIRECT_IO;
937 (*DeviceObject)->AlignmentRequirement = FILE_WORD_ALIGNMENT;
938
939 /* Fill out Device extension data */
940 DeviceExtension = (PIDE_DEVICE_EXTENSION) (*DeviceObject)->DeviceExtension;
941 DeviceExtension->DeviceObject = (*DeviceObject);
942 DeviceExtension->ControllerObject = ControllerObject;
943 DeviceExtension->DiskDeviceExtension = DeviceExtension;
944 DeviceExtension->UnitNumber = UnitNumber;
945 DeviceExtension->LBASupported =
946 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0;
947 DeviceExtension->DMASupported =
948 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0;
949 DeviceExtension->BytesPerSector = DrvParms->BytesPerSector;
950 DeviceExtension->SectorsPerLogCyl =
951 DrvParms->LogicalHeads * DrvParms->SectorsPerTrack;
952 DeviceExtension->SectorsPerLogTrk = DrvParms->SectorsPerTrack;
953 DeviceExtension->LogicalHeads = DrvParms->LogicalHeads;
954 DeviceExtension->LogicalCylinders =
955 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? DrvParms->TMCylinders : DrvParms->LogicalCyls;
956 DeviceExtension->Offset = 0;
957 DeviceExtension->Size = SectorCount;
958 DPRINT("%wZ: offset %lu size %lu \n",
959 &DeviceName,
960 DeviceExtension->Offset,
961 DeviceExtension->Size);
962
963 /* Initialize the DPC object here */
964 IoInitializeDpcRequest(*DeviceObject,
965 IDEDpcForIsr);
966
967 /* assign arc name */
968 swprintf(ArcNameBuffer,
969 L"\\ArcName\\multi(0)disk(0)rdisk(%d)",
970 DiskNumber);
971 RtlInitUnicodeString(&ArcName,
972 ArcNameBuffer);
973 DPRINT("%wZ ==> %wZ\n", &ArcName, &DeviceName);
974 RC = IoAssignArcName(&ArcName,
975 &DeviceName);
976 if (!NT_SUCCESS(RC))
977 {
978 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName, RC);
979 }
980
981 return RC;
982 }
983
984
985 // IDECreatePartitionDevice
986 //
987 // DESCRIPTION:
988 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
989 //
990 // RUN LEVEL:
991 // PASSIVE_LEVEL
992 //
993 // ARGUMENTS:
994 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
995 // OUT PDEVICE_OBJECT *DeviceObject The created device object
996 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
997 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
998 // IN BOOLEAN DMASupported Does the drive support DMA?
999 // IN int SectorsPerLogCyl Sectors per cylinder
1000 // IN int SectorsPerLogTrk Sectors per track
1001 // IN DWORD Offset First valid sector for this device
1002 // IN DWORD Size Count of valid sectors for this device
1003 //
1004 // RETURNS:
1005 // NTSTATUS
1006 //
1007
1008 NTSTATUS
1009 IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject,
1010 OUT PDEVICE_OBJECT *DeviceObject,
1011 IN PCONTROLLER_OBJECT ControllerObject,
1012 IN PVOID DiskDeviceExtension,
1013 IN int UnitNumber,
1014 IN ULONG DiskNumber,
1015 IN PIDE_DRIVE_IDENTIFY DrvParms,
1016 IN PPARTITION_INFORMATION PartitionInfo)
1017 {
1018 WCHAR NameBuffer[IDE_MAX_NAME_LENGTH];
1019 WCHAR ArcNameBuffer[IDE_MAX_NAME_LENGTH + 15];
1020 UNICODE_STRING DeviceName;
1021 UNICODE_STRING ArcName;
1022 NTSTATUS RC;
1023 PIDE_DEVICE_EXTENSION DeviceExtension;
1024
1025 /* Create a unicode device name */
1026 swprintf(NameBuffer,
1027 L"\\Device\\Harddisk%d\\Partition%d",
1028 DiskNumber,
1029 PartitionInfo->PartitionNumber);
1030 RtlInitUnicodeString(&DeviceName,
1031 NameBuffer);
1032
1033 /* Create the device */
1034 RC = IoCreateDevice(DriverObject, sizeof(IDE_DEVICE_EXTENSION),
1035 &DeviceName, FILE_DEVICE_DISK, 0, TRUE, DeviceObject);
1036 if (!NT_SUCCESS(RC))
1037 {
1038 DbgPrint ("IoCreateDevice call failed\n");
1039 return RC;
1040 }
1041
1042 /* Set the buffering strategy here... */
1043 (*DeviceObject)->Flags |= DO_DIRECT_IO;
1044 (*DeviceObject)->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1045
1046 /* Fill out Device extension data */
1047 DeviceExtension = (PIDE_DEVICE_EXTENSION)(*DeviceObject)->DeviceExtension;
1048 DeviceExtension->DeviceObject = (*DeviceObject);
1049 DeviceExtension->ControllerObject = ControllerObject;
1050 DeviceExtension->DiskDeviceExtension = DiskDeviceExtension;
1051 DeviceExtension->UnitNumber = UnitNumber;
1052 DeviceExtension->LBASupported =
1053 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0;
1054 DeviceExtension->DMASupported =
1055 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0;
1056 DeviceExtension->BytesPerSector = DrvParms->BytesPerSector;
1057 DeviceExtension->SectorsPerLogCyl = DrvParms->LogicalHeads *
1058 DrvParms->SectorsPerTrack;
1059 DeviceExtension->SectorsPerLogTrk = DrvParms->SectorsPerTrack;
1060 DeviceExtension->LogicalHeads = DrvParms->LogicalHeads;
1061 DeviceExtension->LogicalCylinders =
1062 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? DrvParms->TMCylinders : DrvParms->LogicalCyls;
1063
1064 DeviceExtension->Offset = PartitionInfo->StartingOffset.QuadPart / 512; /* DrvParms->BytesPerSector */
1065 DeviceExtension->Size = PartitionInfo->PartitionLength.QuadPart / 512; /* DrvParms->BytesPerSector */
1066
1067 DPRINT("%wZ: offset %lu size %lu \n",
1068 &DeviceName,
1069 DeviceExtension->Offset,
1070 DeviceExtension->Size);
1071
1072 /* Initialize the DPC object here */
1073 IoInitializeDpcRequest(*DeviceObject, IDEDpcForIsr);
1074
1075 DbgPrint("%wZ %luMB\n", &DeviceName, DeviceExtension->Size / 2048);
1076
1077 /* assign arc name */
1078 swprintf(ArcNameBuffer,
1079 L"\\ArcName\\multi(0)disk(0)rdisk(%d)partition(%d)",
1080 DiskNumber,
1081 PartitionInfo->PartitionNumber);
1082 RtlInitUnicodeString(&ArcName,
1083 ArcNameBuffer);
1084 DPRINT("%wZ ==> %wZ\n", &ArcName, &DeviceName);
1085 RC = IoAssignArcName(&ArcName,
1086 &DeviceName);
1087 if (!NT_SUCCESS(RC))
1088 {
1089 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName, RC);
1090 }
1091
1092 return RC;
1093 }
1094
1095
1096 // IDEPolledRead
1097 //
1098 // DESCRIPTION:
1099 // Read a sector of data from the drive in a polled fashion.
1100 //
1101 // RUN LEVEL:
1102 // PASSIVE_LEVEL
1103 //
1104 // ARGUMENTS:
1105 // IN WORD Address Address of command port for drive
1106 // IN BYTE PreComp Value to write to precomp register
1107 // IN BYTE SectorCnt Value to write to sectorCnt register
1108 // IN BYTE SectorNum Value to write to sectorNum register
1109 // IN BYTE CylinderLow Value to write to CylinderLow register
1110 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1111 // IN BYTE DrvHead Value to write to Drive/Head register
1112 // IN BYTE Command Value to write to Command register
1113 // OUT BYTE *Buffer Buffer for output data
1114 //
1115 // RETURNS:
1116 // int 0 is success, non 0 is an error code
1117 //
1118
1119 static int
1120 IDEPolledRead(IN WORD Address,
1121 IN BYTE PreComp,
1122 IN BYTE SectorCnt,
1123 IN BYTE SectorNum,
1124 IN BYTE CylinderLow,
1125 IN BYTE CylinderHigh,
1126 IN BYTE DrvHead,
1127 IN BYTE Command,
1128 OUT BYTE *Buffer)
1129 {
1130 BYTE Status;
1131 int RetryCount;
1132 BOOLEAN ReadJunk = FALSE;
1133 ULONG SectorCount = 0;
1134
1135 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1136 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1137 {
1138 Status = IDEReadStatus(Address);
1139 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1140 {
1141 break;
1142 }
1143 KeStallExecutionProcessor(10);
1144 }
1145 if (RetryCount == IDE_MAX_BUSY_RETRIES)
1146 {
1147 return IDE_ER_ABRT;
1148 }
1149
1150 /* Write Drive/Head to select drive */
1151 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
1152
1153 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1154 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1155 {
1156 Status = IDEReadStatus(Address);
1157 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1158 {
1159 break;
1160 }
1161 KeStallExecutionProcessor(10);
1162 }
1163 if (RetryCount == IDE_MAX_BUSY_RETRIES)
1164 {
1165 return IDE_ER_ABRT;
1166 }
1167
1168 /* Issue command to drive */
1169 if (DrvHead & IDE_DH_LBA)
1170 {
1171 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1172 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1173 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1174 SectorCnt,
1175 Command);
1176 }
1177 else
1178 {
1179 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1180 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1181 CylinderHigh,
1182 CylinderLow,
1183 DrvHead & 0x0f,
1184 SectorNum,
1185 SectorCnt,
1186 Command);
1187 }
1188
1189 /* Setup command parameters */
1190 IDEWritePrecomp(Address, PreComp);
1191 IDEWriteSectorCount(Address, SectorCnt);
1192 IDEWriteSectorNum(Address, SectorNum);
1193 IDEWriteCylinderHigh(Address, CylinderHigh);
1194 IDEWriteCylinderLow(Address, CylinderLow);
1195 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
1196
1197 /* Issue the command */
1198 IDEWriteCommand(Address, Command);
1199 KeStallExecutionProcessor(50);
1200
1201 /* wait for DRQ or error */
1202 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1203 {
1204 Status = IDEReadStatus(Address);
1205 if (!(Status & IDE_SR_BUSY))
1206 {
1207 if (Status & IDE_SR_ERR)
1208 {
1209 DPRINT1("IDE_SR_ERR asserted!\n");
1210 }
1211 if ((Status & IDE_SR_DRQ) && !(Status & IDE_SR_ERR))
1212 {
1213 break;
1214 }
1215 else
1216 {
1217 return IDE_ER_ABRT;
1218 }
1219 }
1220 KeStallExecutionProcessor(10);
1221 }
1222 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1223 {
1224 return IDE_ER_ABRT;
1225 }
1226
1227 while (1)
1228 {
1229 /* Read data into buffer */
1230 if (ReadJunk == TRUE)
1231 {
1232 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1233 IDEReadBlock(Address, JunkBuffer, IDE_SECTOR_BUF_SZ);
1234 }
1235 else
1236 {
1237 IDEReadBlock(Address, Buffer, IDE_SECTOR_BUF_SZ);
1238 Buffer += IDE_SECTOR_BUF_SZ;
1239 }
1240 SectorCount++;
1241
1242 /* Check for more sectors to read */
1243 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1244 {
1245 Status = IDEReadStatus(Address);
1246 if (!(Status & IDE_SR_BUSY))
1247 {
1248 if (Status & IDE_SR_ERR)
1249 {
1250 DPRINT1("IDE_SR_ERR asserted!\n");
1251 }
1252 if (Status & IDE_SR_DRQ)
1253 {
1254 if (SectorCount >= SectorCnt)
1255 ReadJunk = TRUE;
1256 break;
1257 }
1258 else
1259 {
1260 return 0;
1261 }
1262 }
1263 }
1264 }
1265 }
1266
1267 // ------------------------------------------- Nondiscardable statics
1268
1269 // IDEDispatchOpenClose
1270 //
1271 // DESCRIPTION:
1272 // Answer requests for Open/Close calls: a null operation
1273 //
1274 // RUN LEVEL:
1275 // PASSIVE_LEVEL
1276 //
1277 // ARGUMENTS:
1278 // Standard dispatch arguments
1279 //
1280 // RETURNS:
1281 // NTSTATUS
1282 //
1283
1284 static NTSTATUS STDCALL
1285 IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO,
1286 IN PIRP Irp)
1287 {
1288 Irp->IoStatus.Status = STATUS_SUCCESS;
1289 Irp->IoStatus.Information = FILE_OPENED;
1290 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1291
1292 return STATUS_SUCCESS;
1293 }
1294
1295 // IDEDispatchReadWrite
1296 //
1297 // DESCRIPTION:
1298 // Answer requests for reads and writes
1299 //
1300 // RUN LEVEL:
1301 // PASSIVE_LEVEL
1302 //
1303 // ARGUMENTS:
1304 // Standard dispatch arguments
1305 //
1306 // RETURNS:
1307 // NTSTATUS
1308 //
1309
1310 static NTSTATUS
1311 STDCALL IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO,
1312 IN PIRP Irp)
1313 {
1314 ULONG IrpInsertKey;
1315 LARGE_INTEGER AdjustedOffset, AdjustedExtent, PartitionExtent, InsertKeyLI;
1316 PIO_STACK_LOCATION IrpStack;
1317 PIDE_DEVICE_EXTENSION DeviceExtension;
1318
1319 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1320 DeviceExtension = (PIDE_DEVICE_EXTENSION)pDO->DeviceExtension;
1321
1322 // Validate operation parameters
1323 AdjustedOffset = RtlEnlargedIntegerMultiply(DeviceExtension->Offset,
1324 DeviceExtension->BytesPerSector);
1325 DPRINT("Offset:%ld * BytesPerSector:%ld = AdjOffset:%ld:%ld\n",
1326 DeviceExtension->Offset,
1327 DeviceExtension->BytesPerSector,
1328 (unsigned long) AdjustedOffset.u.HighPart,
1329 (unsigned long) AdjustedOffset.u.LowPart);
1330 DPRINT("AdjOffset:%ld:%ld + ByteOffset:%ld:%ld\n",
1331 (unsigned long) AdjustedOffset.u.HighPart,
1332 (unsigned long) AdjustedOffset.u.LowPart,
1333 (unsigned long) IrpStack->Parameters.Read.ByteOffset.u.HighPart,
1334 (unsigned long) IrpStack->Parameters.Read.ByteOffset.u.LowPart);
1335 AdjustedOffset = RtlLargeIntegerAdd(AdjustedOffset,
1336 IrpStack->Parameters.Read.ByteOffset);
1337 DPRINT(" = AdjOffset:%ld:%ld\n",
1338 (unsigned long) AdjustedOffset.u.HighPart,
1339 (unsigned long) AdjustedOffset.u.LowPart);
1340 AdjustedExtent = RtlLargeIntegerAdd(AdjustedOffset,
1341 RtlConvertLongToLargeInteger(IrpStack->Parameters.Read.Length));
1342 DPRINT("AdjOffset:%ld:%ld + Length:%ld = AdjExtent:%ld:%ld\n",
1343 (unsigned long) AdjustedOffset.u.HighPart,
1344 (unsigned long) AdjustedOffset.u.LowPart,
1345 IrpStack->Parameters.Read.Length,
1346 (unsigned long) AdjustedExtent.u.HighPart,
1347 (unsigned long) AdjustedExtent.u.LowPart);
1348 /*FIXME: this assumption will fail on drives bigger than 1TB */
1349 PartitionExtent.QuadPart = DeviceExtension->Offset + DeviceExtension->Size;
1350 PartitionExtent = RtlExtendedIntegerMultiply(PartitionExtent,
1351 DeviceExtension->BytesPerSector);
1352 if ((AdjustedExtent.QuadPart > PartitionExtent.QuadPart) ||
1353 (IrpStack->Parameters.Read.Length & (DeviceExtension->BytesPerSector - 1)))
1354 {
1355 DPRINT("Request failed on bad parameters\n",0);
1356 DPRINT("AdjustedExtent=%d:%d PartitionExtent=%d:%d ReadLength=%d\n",
1357 (unsigned int) AdjustedExtent.u.HighPart,
1358 (unsigned int) AdjustedExtent.u.LowPart,
1359 (unsigned int) PartitionExtent.u.HighPart,
1360 (unsigned int) PartitionExtent.u.LowPart,
1361 IrpStack->Parameters.Read.Length);
1362 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1363 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1364 return STATUS_INVALID_PARAMETER;
1365 }
1366
1367 // Adjust operation to absolute sector offset
1368 IrpStack->Parameters.Read.ByteOffset = AdjustedOffset;
1369
1370 // Start the packet and insert the request in order of sector offset
1371 assert(DeviceExtension->BytesPerSector == 512);
1372 InsertKeyLI = RtlLargeIntegerShiftRight(IrpStack->Parameters.Read.ByteOffset, 9);
1373 IrpInsertKey = InsertKeyLI.u.LowPart;
1374 IoStartPacket(DeviceExtension->DeviceObject, Irp, &IrpInsertKey, NULL);
1375
1376 DPRINT("Returning STATUS_PENDING\n");
1377 return STATUS_PENDING;
1378 }
1379
1380 // IDEDispatchDeviceControl
1381 //
1382 // DESCRIPTION:
1383 // Answer requests for device control calls
1384 //
1385 // RUN LEVEL:
1386 // PASSIVE_LEVEL
1387 //
1388 // ARGUMENTS:
1389 // Standard dispatch arguments
1390 //
1391 // RETURNS:
1392 // NTSTATUS
1393 //
1394
1395 static NTSTATUS STDCALL
1396 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1397 IN PIRP Irp)
1398 {
1399 NTSTATUS RC;
1400 ULONG ControlCode, InputLength, OutputLength;
1401 PIO_STACK_LOCATION IrpStack;
1402 PIDE_DEVICE_EXTENSION DeviceExtension;
1403 PIDE_DEVICE_EXTENSION DiskDeviceExtension;
1404 CCHAR Increment;
1405
1406 RC = STATUS_SUCCESS;
1407 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1408 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
1409 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
1410 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
1411 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1412 DiskDeviceExtension = (PIDE_DEVICE_EXTENSION)DeviceExtension->DiskDeviceExtension;
1413 Increment = IO_NO_INCREMENT;
1414
1415 // A huge switch statement in a Windows program?! who would have thought?
1416 switch (ControlCode)
1417 {
1418 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
1419 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
1420 {
1421 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1422 }
1423 else
1424 {
1425 PDISK_GEOMETRY Geometry;
1426
1427 Geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
1428
1429 Geometry->MediaType = FixedMedia;
1430 Geometry->Cylinders.QuadPart = DiskDeviceExtension->LogicalCylinders;
1431 Geometry->TracksPerCylinder = DiskDeviceExtension->SectorsPerLogCyl /
1432 DiskDeviceExtension->SectorsPerLogTrk;
1433 Geometry->SectorsPerTrack = DiskDeviceExtension->SectorsPerLogTrk;
1434 Geometry->BytesPerSector = DiskDeviceExtension->BytesPerSector;
1435 DPRINT1("DiskDeviceExtension->BytesPerSector %lu\n", DiskDeviceExtension->BytesPerSector);
1436 Irp->IoStatus.Status = STATUS_SUCCESS;
1437 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1438 }
1439 break;
1440
1441 case IOCTL_DISK_GET_PARTITION_INFO:
1442 case IOCTL_DISK_SET_PARTITION_INFO:
1443 RC = STATUS_INVALID_DEVICE_REQUEST;
1444 Irp->IoStatus.Status = RC;
1445 Irp->IoStatus.Information = 0;
1446 break;
1447
1448 case IOCTL_DISK_GET_DRIVE_LAYOUT:
1449 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
1450 sizeof(DRIVE_LAYOUT_INFORMATION))
1451 {
1452 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
1453 }
1454 else
1455 {
1456 PDRIVE_LAYOUT_INFORMATION PartitionList;
1457
1458 RC = IoReadPartitionTable(DiskDeviceExtension->DeviceObject,
1459 DiskDeviceExtension->BytesPerSector,
1460 FALSE,
1461 &PartitionList);
1462 if (!NT_SUCCESS(RC))
1463 {
1464 Irp->IoStatus.Status = RC;
1465 }
1466 else
1467 {
1468 ULONG BufferSize;
1469
1470 BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
1471 PartitionEntry[0]);
1472 BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
1473
1474 if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
1475 {
1476 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
1477 }
1478 else
1479 {
1480 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
1481 PartitionList,
1482 BufferSize);
1483 Irp->IoStatus.Status = STATUS_SUCCESS;
1484 Irp->IoStatus.Information = BufferSize;
1485 }
1486 ExFreePool(PartitionList);
1487 }
1488 }
1489 Increment = IO_DISK_INCREMENT;
1490 break;
1491
1492 case IOCTL_DISK_SET_DRIVE_LAYOUT:
1493 case IOCTL_DISK_VERIFY:
1494 case IOCTL_DISK_FORMAT_TRACKS:
1495 case IOCTL_DISK_PERFORMANCE:
1496 case IOCTL_DISK_IS_WRITABLE:
1497 case IOCTL_DISK_LOGGING:
1498 case IOCTL_DISK_FORMAT_TRACKS_EX:
1499 case IOCTL_DISK_HISTOGRAM_STRUCTURE:
1500 case IOCTL_DISK_HISTOGRAM_DATA:
1501 case IOCTL_DISK_HISTOGRAM_RESET:
1502 case IOCTL_DISK_REQUEST_STRUCTURE:
1503 case IOCTL_DISK_REQUEST_DATA:
1504
1505 // If we get here, something went wrong. inform the requestor
1506 default:
1507 RC = STATUS_INVALID_DEVICE_REQUEST;
1508 Irp->IoStatus.Status = RC;
1509 Irp->IoStatus.Information = 0;
1510 break;
1511 }
1512
1513 IoCompleteRequest(Irp, Increment);
1514
1515 return RC;
1516 }
1517
1518 // IDEStartIo
1519 //
1520 // DESCRIPTION:
1521 // Get the next requested I/O packet started
1522 //
1523 // RUN LEVEL:
1524 // DISPATCH_LEVEL
1525 //
1526 // ARGUMENTS:
1527 // Dispatch routine standard arguments
1528 //
1529 // RETURNS:
1530 // NTSTATUS
1531 //
1532
1533 static VOID
1534 STDCALL IDEStartIo(IN PDEVICE_OBJECT DeviceObject,
1535 IN PIRP Irp)
1536 {
1537 LARGE_INTEGER SectorLI;
1538 PIO_STACK_LOCATION IrpStack;
1539 PIDE_DEVICE_EXTENSION DeviceExtension;
1540 KIRQL OldIrql;
1541
1542 DPRINT("IDEStartIo() called!\n");
1543
1544 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1545 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1546
1547 // FIXME: implement the supported functions
1548
1549 switch (IrpStack->MajorFunction)
1550 {
1551 case IRP_MJ_READ:
1552 case IRP_MJ_WRITE:
1553 DeviceExtension->Operation = IrpStack->MajorFunction;
1554 DeviceExtension->BytesRequested = IrpStack->Parameters.Read.Length;
1555 assert(DeviceExtension->BytesPerSector == 512);
1556 SectorLI = RtlLargeIntegerShiftRight(IrpStack->Parameters.Read.ByteOffset, 9);
1557 DeviceExtension->StartingSector = SectorLI.u.LowPart;
1558 if (DeviceExtension->BytesRequested > DeviceExtension->BytesPerSector *
1559 IDE_MAX_SECTORS_PER_XFER)
1560 {
1561 DeviceExtension->BytesToTransfer = DeviceExtension->BytesPerSector *
1562 IDE_MAX_SECTORS_PER_XFER;
1563 }
1564 else
1565 {
1566 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
1567 }
1568 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1569 DeviceExtension->SectorsTransferred = 0;
1570 DeviceExtension->TargetAddress = (BYTE *)MmGetSystemAddressForMdl(Irp->MdlAddress);
1571 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1572 IoAllocateController(DeviceExtension->ControllerObject,
1573 DeviceObject,
1574 IDEAllocateController,
1575 NULL);
1576 KeLowerIrql(OldIrql);
1577 break;
1578
1579 default:
1580 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1581 Irp->IoStatus.Information = 0;
1582 KeBugCheck((ULONG)Irp);
1583 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1584 IoStartNextPacket(DeviceObject, FALSE);
1585 break;
1586 }
1587 DPRINT("IDEStartIo() finished!\n");
1588 }
1589
1590 // IDEAllocateController
1591
1592 static IO_ALLOCATION_ACTION STDCALL
1593 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject,
1594 IN PIRP Irp,
1595 IN PVOID MapRegisterBase,
1596 IN PVOID Ccontext)
1597 {
1598 PIDE_DEVICE_EXTENSION DeviceExtension;
1599 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1600
1601 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1602 ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
1603 DeviceExtension->ControllerObject->ControllerExtension;
1604 ControllerExtension->CurrentIrp = Irp;
1605 ControllerExtension->Retries = 0;
1606 return KeSynchronizeExecution(ControllerExtension->Interrupt,
1607 IDEStartController,
1608 DeviceExtension) ? KeepObject :
1609 DeallocateObject;
1610 }
1611
1612 // IDEStartController
1613
1614 BOOLEAN STDCALL
1615 IDEStartController(IN OUT PVOID Context)
1616 {
1617 BYTE SectorCnt, SectorNum, CylinderLow, CylinderHigh;
1618 BYTE DrvHead, Command;
1619 BYTE Status;
1620 int Retries;
1621 ULONG StartingSector;
1622 PIDE_DEVICE_EXTENSION DeviceExtension;
1623 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1624 PIRP Irp;
1625
1626 DeviceExtension = (PIDE_DEVICE_EXTENSION) Context;
1627 ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
1628 DeviceExtension->ControllerObject->ControllerExtension;
1629 ControllerExtension->OperationInProgress = TRUE;
1630 ControllerExtension->DeviceForOperation = DeviceExtension;
1631
1632 // Write controller registers to start opteration
1633 StartingSector = DeviceExtension->StartingSector;
1634 SectorCnt = DeviceExtension->BytesToTransfer /
1635 DeviceExtension->BytesPerSector;
1636 if (DeviceExtension->LBASupported)
1637 {
1638 SectorNum = StartingSector & 0xff;
1639 CylinderLow = (StartingSector >> 8) & 0xff;
1640 CylinderHigh = (StartingSector >> 16) & 0xff;
1641 DrvHead = ((StartingSector >> 24) & 0x0f) |
1642 (DeviceExtension->UnitNumber ? IDE_DH_DRV1 : 0) |
1643 IDE_DH_LBA;
1644 }
1645 else
1646 {
1647 SectorNum = (StartingSector % DeviceExtension->SectorsPerLogTrk) + 1;
1648 StartingSector /= DeviceExtension->SectorsPerLogTrk;
1649 DrvHead = (StartingSector % DeviceExtension->LogicalHeads) |
1650 (DeviceExtension->UnitNumber ? IDE_DH_DRV1 : 0);
1651 StartingSector /= DeviceExtension->LogicalHeads;
1652 CylinderLow = StartingSector & 0xff;
1653 CylinderHigh = StartingSector >> 8;
1654 }
1655 Command = DeviceExtension->Operation == IRP_MJ_READ ?
1656 IDE_CMD_READ : IDE_CMD_WRITE;
1657 if (DrvHead & IDE_DH_LBA)
1658 {
1659 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1660 DeviceExtension->Operation == IRP_MJ_READ ? "READ" : "WRITE",
1661 ControllerExtension->CommandPortBase,
1662 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1663 ((DrvHead & 0x0f) << 24) +
1664 (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1665 SectorCnt,
1666 Command);
1667 }
1668 else
1669 {
1670 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1671 DeviceExtension->Operation == IRP_MJ_READ ? "READ" : "WRITE",
1672 ControllerExtension->CommandPortBase,
1673 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1674 CylinderHigh,
1675 CylinderLow,
1676 DrvHead & 0x0f,
1677 SectorNum,
1678 SectorCnt,
1679 Command);
1680 }
1681
1682 /* wait for BUSY to clear */
1683 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1684 {
1685 Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1686 if (!(Status & IDE_SR_BUSY))
1687 {
1688 break;
1689 }
1690 KeStallExecutionProcessor(10);
1691 }
1692 DPRINT ("status=%02x\n", Status);
1693 DPRINT ("waited %ld usecs for busy to clear\n", Retries * 10);
1694 if (Retries >= IDE_MAX_BUSY_RETRIES)
1695 {
1696 DPRINT ("Drive is BUSY for too long\n");
1697 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1698 {
1699 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1700 Irp = ControllerExtension->CurrentIrp;
1701 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1702 Irp->IoStatus.Information = 0;
1703
1704 return FALSE;
1705 }
1706 else
1707 {
1708 DPRINT ("Beginning drive reset sequence\n");
1709 IDEBeginControllerReset(ControllerExtension);
1710
1711 return TRUE;
1712 }
1713 }
1714
1715 /* Select the desired drive */
1716 IDEWriteDriveHead(ControllerExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1717
1718 /* wait for BUSY to clear and DRDY to assert */
1719 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1720 {
1721 Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1722 // if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1723 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1724 {
1725 break;
1726 }
1727 KeStallExecutionProcessor(10);
1728 }
1729 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1730 if (Retries >= IDE_MAX_BUSY_RETRIES)
1731 {
1732 DPRINT ("Drive is BUSY for too long after drive select\n");
1733 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1734 {
1735 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1736 Irp = ControllerExtension->CurrentIrp;
1737 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1738 Irp->IoStatus.Information = 0;
1739
1740 return FALSE;
1741 }
1742 else
1743 {
1744 DPRINT ("Beginning drive reset sequence\n");
1745 IDEBeginControllerReset(ControllerExtension);
1746
1747 return TRUE;
1748 }
1749 }
1750
1751 /* Setup command parameters */
1752 IDEWritePrecomp(ControllerExtension->CommandPortBase, 0);
1753 IDEWriteSectorCount(ControllerExtension->CommandPortBase, SectorCnt);
1754 IDEWriteSectorNum(ControllerExtension->CommandPortBase, SectorNum);
1755 IDEWriteCylinderHigh(ControllerExtension->CommandPortBase, CylinderHigh);
1756 IDEWriteCylinderLow(ControllerExtension->CommandPortBase, CylinderLow);
1757 IDEWriteDriveHead(ControllerExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1758
1759 /* Issue command to drive */
1760 IDEWriteCommand(ControllerExtension->CommandPortBase, Command);
1761 ControllerExtension->TimerState = IDETimerCmdWait;
1762 ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1763
1764 if (DeviceExtension->Operation == IRP_MJ_WRITE)
1765 {
1766
1767 // Wait for controller ready
1768 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
1769 {
1770 BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1771 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
1772 {
1773 break;
1774 }
1775 KeStallExecutionProcessor(10);
1776 }
1777 if (Retries >= IDE_MAX_BUSY_RETRIES)
1778 {
1779 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1780 {
1781 Irp = ControllerExtension->CurrentIrp;
1782 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1783 Irp->IoStatus.Information = 0;
1784
1785 return FALSE;
1786 }
1787 else
1788 {
1789 IDEBeginControllerReset(ControllerExtension);
1790
1791 return TRUE;
1792 }
1793 }
1794
1795 // Load the first sector of data into the controller
1796 IDEWriteBlock(ControllerExtension->CommandPortBase,
1797 DeviceExtension->TargetAddress,
1798 IDE_SECTOR_BUF_SZ);
1799 DeviceExtension->TargetAddress += IDE_SECTOR_BUF_SZ;
1800 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1801 DeviceExtension->SectorsTransferred++;
1802 }
1803 DPRINT ("Command issued to drive, IDEStartController done\n");
1804
1805 return TRUE;
1806 }
1807
1808 // IDEBeginControllerReset
1809
1810 VOID
1811 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension)
1812 {
1813 int Retries;
1814
1815 DPRINT("Controller Reset initiated on %04x\n",
1816 ControllerExtension->ControlPortBase);
1817
1818 /* Assert drive reset line */
1819 DPRINT("Asserting reset line\n");
1820 IDEWriteDriveControl(ControllerExtension->ControlPortBase, IDE_DC_SRST);
1821
1822 /* Wait for BSY assertion */
1823 DPRINT("Waiting for BSY assertion\n");
1824 for (Retries = 0; Retries < IDE_MAX_RESET_RETRIES; Retries++)
1825 {
1826 BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1827 if ((Status & IDE_SR_BUSY))
1828 {
1829 break;
1830 }
1831 KeStallExecutionProcessor(10);
1832 }
1833 if (Retries == IDE_MAX_RESET_RETRIES)
1834 {
1835 DPRINT("Timeout on BSY assertion\n");
1836 }
1837
1838 /* Negate drive reset line */
1839 DPRINT("Negating reset line\n");
1840 IDEWriteDriveControl(ControllerExtension->ControlPortBase, 0);
1841
1842 // FIXME: handle case of no device 0
1843
1844 /* Set timer to check for end of reset */
1845 ControllerExtension->TimerState = IDETimerResetWaitForBusyNegate;
1846 ControllerExtension->TimerCount = IDE_RESET_BUSY_TIMEOUT;
1847 }
1848
1849 // IDEIsr
1850 //
1851 // DESCIPTION:
1852 // Handle interrupts for IDE devices
1853 //
1854 // RUN LEVEL:
1855 // DIRQL
1856 //
1857 // ARGUMENTS:
1858 // IN PKINTERRUPT Interrupt The interrupt level in effect
1859 // IN PVOID ServiceContext The driver supplied context
1860 // (the controller extension)
1861 // RETURNS:
1862 // TRUE This ISR handled the interrupt
1863 // FALSE Another ISR must handle this interrupt
1864
1865 static BOOLEAN STDCALL
1866 IDEIsr(IN PKINTERRUPT Interrupt,
1867 IN PVOID ServiceContext)
1868 {
1869 BOOLEAN IsLastBlock, AnErrorOccured, RequestIsComplete;
1870 BYTE *TargetAddress;
1871 int Retries;
1872 NTSTATUS ErrorStatus;
1873 ULONG ErrorInformation;
1874 PIRP Irp;
1875 PIDE_DEVICE_EXTENSION DeviceExtension;
1876 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1877
1878 if (IDEInitialized == FALSE)
1879 {
1880 return FALSE;
1881 }
1882 DPRINT ("IDEIsr called\n");
1883
1884 ControllerExtension = (PIDE_CONTROLLER_EXTENSION) ServiceContext;
1885
1886 // Read the status port to clear the interrtupt (even if it's not ours).
1887 ControllerExtension->DeviceStatus = IDEReadStatus(ControllerExtension->CommandPortBase);
1888
1889 // If the interrupt is not ours, get the heck outta dodge.
1890 if (!ControllerExtension->OperationInProgress)
1891 {
1892 return FALSE;
1893 }
1894
1895 DeviceExtension = ControllerExtension->DeviceForOperation;
1896 IsLastBlock = FALSE;
1897 AnErrorOccured = FALSE;
1898 RequestIsComplete = FALSE;
1899 ErrorStatus = STATUS_SUCCESS;
1900 ErrorInformation = 0;
1901
1902 // Handle error condition if it exists
1903 if (ControllerExtension->DeviceStatus & IDE_SR_ERR)
1904 {
1905 BYTE ErrorReg, SectorCount, SectorNum, CylinderLow, CylinderHigh;
1906 BYTE DriveHead;
1907
1908 // Log the error
1909 ErrorReg = IDEReadError(ControllerExtension->CommandPortBase);
1910 CylinderLow = IDEReadCylinderLow(ControllerExtension->CommandPortBase);
1911 CylinderHigh = IDEReadCylinderHigh(ControllerExtension->CommandPortBase);
1912 DriveHead = IDEReadDriveHead(ControllerExtension->CommandPortBase);
1913 SectorCount = IDEReadSectorCount(ControllerExtension->CommandPortBase);
1914 SectorNum = IDEReadSectorNum(ControllerExtension->CommandPortBase);
1915 // FIXME: should use the NT error logging facility
1916 DbgPrint ("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1917 DeviceExtension->Operation,
1918 ControllerExtension->DeviceStatus,
1919 ErrorReg,
1920 CylinderLow,
1921 CylinderHigh,
1922 SectorCount,
1923 SectorNum);
1924
1925 // FIXME: should retry the command and perhaps recalibrate the drive
1926
1927 // Set error status information
1928 AnErrorOccured = TRUE;
1929 ErrorStatus = STATUS_DISK_OPERATION_FAILED;
1930 ErrorInformation =
1931 (((((((CylinderHigh << 8) + CylinderLow) *
1932 DeviceExtension->LogicalHeads) +
1933 (DriveHead % DeviceExtension->LogicalHeads)) *
1934 DeviceExtension->SectorsPerLogTrk) + SectorNum - 1) -
1935 DeviceExtension->StartingSector) * DeviceExtension->BytesPerSector;
1936 }
1937 else
1938 {
1939
1940 // Check controller and setup for next transfer
1941 switch (DeviceExtension->Operation)
1942 {
1943 case IRP_MJ_READ:
1944
1945 // Update controller/device state variables
1946 TargetAddress = DeviceExtension->TargetAddress;
1947 DeviceExtension->TargetAddress += DeviceExtension->BytesPerSector;
1948 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1949 DeviceExtension->SectorsTransferred++;
1950
1951 // Remember whether DRQ should be low at end (last block read)
1952 IsLastBlock = DeviceExtension->BytesToTransfer == 0;
1953
1954 // Wait for DRQ assertion
1955 for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
1956 !(IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ);
1957 Retries++)
1958 {
1959 KeStallExecutionProcessor(10);
1960 }
1961
1962 // Copy the block of data
1963 IDEReadBlock(ControllerExtension->CommandPortBase,
1964 TargetAddress,
1965 IDE_SECTOR_BUF_SZ);
1966
1967 // check DRQ
1968 if (IsLastBlock)
1969 {
1970 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
1971 (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_BUSY);
1972 Retries++)
1973 {
1974 KeStallExecutionProcessor(10);
1975 }
1976
1977 // Check for data overrun
1978 if (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ)
1979 {
1980 AnErrorOccured = TRUE;
1981 ErrorStatus = STATUS_DATA_OVERRUN;
1982 ErrorInformation = 0;
1983 }
1984 else
1985 {
1986
1987 // Setup next transfer or set RequestIsComplete
1988 if (DeviceExtension->BytesRequested >
1989 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
1990 {
1991 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
1992 DeviceExtension->SectorsTransferred = 0;
1993 DeviceExtension->BytesToTransfer =
1994 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
1995 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1996 }
1997 else if (DeviceExtension->BytesRequested > 0)
1998 {
1999 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
2000 DeviceExtension->SectorsTransferred = 0;
2001 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
2002 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
2003 }
2004 else
2005 {
2006 RequestIsComplete = TRUE;
2007 }
2008 }
2009 }
2010 break;
2011
2012 case IRP_MJ_WRITE:
2013
2014 // check DRQ
2015 if (DeviceExtension->BytesToTransfer == 0)
2016 {
2017 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
2018 (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_BUSY);
2019 Retries++)
2020 {
2021 KeStallExecutionProcessor(10);
2022 }
2023
2024 // Check for data overrun
2025 if (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ)
2026 {
2027 AnErrorOccured = TRUE;
2028 ErrorStatus = STATUS_DATA_OVERRUN;
2029 ErrorInformation = 0;
2030 }
2031 else
2032 {
2033
2034 // Setup next transfer or set RequestIsComplete
2035 IsLastBlock = TRUE;
2036 if (DeviceExtension->BytesRequested >
2037 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
2038 {
2039 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
2040 DeviceExtension->SectorsTransferred = 0;
2041 DeviceExtension->BytesToTransfer =
2042 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
2043 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
2044 }
2045 else if (DeviceExtension->BytesRequested > 0)
2046 {
2047 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
2048 DeviceExtension->SectorsTransferred = 0;
2049 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
2050 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
2051 }
2052 else
2053 {
2054 RequestIsComplete = TRUE;
2055 }
2056 }
2057 }
2058 else
2059 {
2060
2061 // Update controller/device state variables
2062 TargetAddress = DeviceExtension->TargetAddress;
2063 DeviceExtension->TargetAddress += DeviceExtension->BytesPerSector;
2064 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
2065 DeviceExtension->SectorsTransferred++;
2066
2067 // Write block to controller
2068 IDEWriteBlock(ControllerExtension->CommandPortBase,
2069 TargetAddress,
2070 IDE_SECTOR_BUF_SZ);
2071 }
2072 break;
2073 }
2074 }
2075
2076 // If there was an error or the request is done, complete the packet
2077 if (AnErrorOccured || RequestIsComplete)
2078 {
2079 // Set the return status and info values
2080 Irp = ControllerExtension->CurrentIrp;
2081 Irp->IoStatus.Status = ErrorStatus;
2082 Irp->IoStatus.Information = ErrorInformation;
2083
2084 // Clear out controller fields
2085 ControllerExtension->OperationInProgress = FALSE;
2086 ControllerExtension->DeviceStatus = 0;
2087
2088 // Queue the Dpc to finish up
2089 IoRequestDpc(DeviceExtension->DeviceObject,
2090 Irp,
2091 ControllerExtension);
2092 }
2093 else if (IsLastBlock)
2094 {
2095 // Else more data is needed, setup next device I/O
2096 IDEStartController((PVOID)DeviceExtension);
2097 }
2098
2099 return TRUE;
2100 }
2101
2102 // IDEDpcForIsr
2103 // DESCRIPTION:
2104 //
2105 // RUN LEVEL:
2106 //
2107 // ARGUMENTS:
2108 // IN PKDPC Dpc
2109 // IN PDEVICE_OBJECT DpcDeviceObject
2110 // IN PIRP DpcIrp
2111 // IN PVOID DpcContext
2112 //
2113 static VOID
2114 IDEDpcForIsr(IN PKDPC Dpc,
2115 IN PDEVICE_OBJECT DpcDeviceObject,
2116 IN PIRP DpcIrp,
2117 IN PVOID DpcContext)
2118 {
2119 DPRINT("IDEDpcForIsr()\n");
2120 IDEFinishOperation((PIDE_CONTROLLER_EXTENSION) DpcContext);
2121 }
2122
2123 // IDEFinishOperation
2124
2125 static VOID
2126 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension)
2127 {
2128 PIDE_DEVICE_EXTENSION DeviceExtension;
2129 PIRP Irp;
2130 ULONG Operation;
2131
2132 DeviceExtension = ControllerExtension->DeviceForOperation;
2133 Irp = ControllerExtension->CurrentIrp;
2134 Operation = DeviceExtension->Operation;
2135 ControllerExtension->OperationInProgress = FALSE;
2136 ControllerExtension->DeviceForOperation = 0;
2137 ControllerExtension->CurrentIrp = 0;
2138
2139 // Deallocate the controller
2140 IoFreeController(DeviceExtension->ControllerObject);
2141
2142 // Start the next packet
2143 IoStartNextPacketByKey(DeviceExtension->DeviceObject,
2144 FALSE,
2145 DeviceExtension->StartingSector);
2146
2147 // Issue completion of the current packet
2148 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2149
2150 // Flush cache if necessary
2151 if (Operation == IRP_MJ_READ)
2152 {
2153 KeFlushIoBuffers(Irp->MdlAddress, TRUE, FALSE);
2154 }
2155 }
2156
2157 // IDEIoTimer
2158 // DESCRIPTION:
2159 // This function handles timeouts and other time delayed processing
2160 //
2161 // RUN LEVEL:
2162 //
2163 // ARGUMENTS:
2164 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
2165 // IN PVOID Context the Controller extension for the
2166 // controller the device is on
2167 //
2168 static VOID STDCALL
2169 IDEIoTimer(PDEVICE_OBJECT DeviceObject,
2170 PVOID Context)
2171 {
2172 PIDE_CONTROLLER_EXTENSION ControllerExtension;
2173
2174 // Setup Extension pointer
2175 ControllerExtension = (PIDE_CONTROLLER_EXTENSION) Context;
2176 DPRINT("Timer activated for %04lx\n", ControllerExtension->CommandPortBase);
2177
2178 // Handle state change if necessary
2179 switch (ControllerExtension->TimerState)
2180 {
2181 case IDETimerResetWaitForBusyNegate:
2182 if (!(IDEReadStatus(ControllerExtension->CommandPortBase) &
2183 IDE_SR_BUSY))
2184 {
2185 DPRINT("Busy line has negated, waiting for DRDY assert\n");
2186 ControllerExtension->TimerState = IDETimerResetWaitForDrdyAssert;
2187 ControllerExtension->TimerCount = IDE_RESET_DRDY_TIMEOUT;
2188 return;
2189 }
2190 break;
2191
2192 case IDETimerResetWaitForDrdyAssert:
2193 if (IDEReadStatus(ControllerExtension->CommandPortBase) &
2194 IDE_SR_DRQ)
2195 {
2196 DPRINT("DRDY has asserted, reset complete\n");
2197 ControllerExtension->TimerState = IDETimerIdle;
2198 ControllerExtension->TimerCount = 0;
2199
2200 // FIXME: get diagnostic code from drive 0
2201
2202 /* Start current packet command again */
2203 if (!KeSynchronizeExecution(ControllerExtension->Interrupt,
2204 IDEStartController,
2205 ControllerExtension->DeviceForOperation))
2206 {
2207 IDEFinishOperation(ControllerExtension);
2208 }
2209 return;
2210 }
2211 break;
2212
2213 default:
2214 break;
2215 }
2216
2217 // If we're counting down, then count.
2218 if (ControllerExtension->TimerCount > 0)
2219 {
2220 ControllerExtension->TimerCount--;
2221
2222 // Else we'll check the state and process if necessary
2223 }
2224 else
2225 {
2226 switch (ControllerExtension->TimerState)
2227 {
2228 case IDETimerIdle:
2229 break;
2230
2231 case IDETimerCmdWait:
2232 /* Command timed out, reset drive and try again or fail */
2233 DPRINT("Timeout waiting for command completion\n");
2234 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
2235 {
2236 if (ControllerExtension->CurrentIrp != NULL)
2237 {
2238 DbgPrint ("Max retries has been reached, IRP finished with error\n");
2239 ControllerExtension->CurrentIrp->IoStatus.Status = STATUS_IO_TIMEOUT;
2240 ControllerExtension->CurrentIrp->IoStatus.Information = 0;
2241 IDEFinishOperation(ControllerExtension);
2242 }
2243 ControllerExtension->TimerState = IDETimerIdle;
2244 ControllerExtension->TimerCount = 0;
2245 }
2246 else
2247 {
2248 IDEBeginControllerReset(ControllerExtension);
2249 }
2250 break;
2251
2252 case IDETimerResetWaitForBusyNegate:
2253 case IDETimerResetWaitForDrdyAssert:
2254 if (ControllerExtension->CurrentIrp != NULL)
2255 {
2256 DbgPrint ("Timeout waiting for drive reset, giving up on IRP\n");
2257 ControllerExtension->CurrentIrp->IoStatus.Status =
2258 STATUS_IO_TIMEOUT;
2259 ControllerExtension->CurrentIrp->IoStatus.Information = 0;
2260 IDEFinishOperation(ControllerExtension);
2261 }
2262 ControllerExtension->TimerState = IDETimerIdle;
2263 ControllerExtension->TimerCount = 0;
2264 break;
2265 }
2266 }
2267 }
2268
2269