Relative include path fixed to absolute path.
[reactos.git] / reactos / drivers / dd / ide / ide.c
1 /* $Id: ide.c,v 1.56 2002/09/08 10:22:04 chorns 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 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