2a4b8006a384a8a67abb2a97811513c86a3022a9
[reactos.git] / reactos / drivers / dd / ide / ide.c
1 /* $Id: ide.c,v 1.46 2001/11/01 00:28:57 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 up to 4 controllers with up to 2 drives each.
9 * The device names are assigned as follows:
10 * \Devices\HarddiskX\Partition0
11 * for the raw device, and
12 * \Devices\HarddiskX\PartitionY
13 * for partitions
14 * where:
15 * X is computed by counting the available drives from the following
16 * sequence: the controller number (0=0x1f0, 1=0x170, 2=0x1e8,
17 * 3=0x168) * 2 plus the drive number (0,1)
18 * Y is the partition number
19 *
20 * The driver exports the following function:
21 *
22 * DriverEntry() - NT device driver initialization routine
23 *
24 * And the following functions are exported implicitly:
25 *
26 * IDEStartIo() - called to start an I/O request packet
27 * IDEDispatchOpenClose() - Called to open/close the device. a NOOP
28 * IDEDispatchReadWrite() - Called to read/write the device.
29 * IDEDispatchQueryInformation() - Called to get device information
30 * IDEDispatchSetInformation() - Called to set device information
31 * IDEDispatchDeviceControl() - Called to execute device control requests
32 *
33 * Modification History:
34 * 05/25/98 RJJ Created.
35 * 05/30/98 RJJ Removed IRQ handler and inserted busy waits
36 * just to get something working...
37 * 07/18/98 RJJ Made drastic changes so that the driver
38 * resembles a WinNT driver.
39 * 08/05/98 RJJ Changed to .C extension
40 * 09/19/98 RJJ First release (run for cover!)
41 *
42 * Test List:
43 * 09/17/98 RJJ Pri/MST: 14.12X19 WDC AC31000H Test Passed
44 * Pri/SLV: None.
45 *
46 *
47 * To Do:
48 * FIXME: a timer should be used to watch for device timeouts and errors
49 * FIXME: errors should be retried
50 * FIXME: a drive reset/recalibrate should be attempted if errors occur
51 * FIXME: Use DMA for transfers if drives support it
52 * FIXME: should we support unloading of this driver???
53 * FIXME: the device information should come from AUTODETECT (via registry)
54 * FIXME: really big devices need to be handled correctly
55 * FIXME: should get device info from the registry
56 * FIXME: should report hardware usage to iomgr
57 * FIXME: finish implementation of QueryInformation
58 * FIXME: finish implementation of SetInformation
59 * FIXME: finish implementation of DeviceControl
60 * FIXME: bring up to ATA-3 spec
61 * FIXME: add general support for ATAPI devices
62 * FIXME: add support for ATAPI CDROMs
63 * FIXME: add support for ATAPI ZIP drives/RHDs
64 * FIXME: add support for ATAPI tape drives
65 */
66
67 // -------------------------------------------------------------------------
68
69 #include <ddk/ntddk.h>
70
71 #define NDEBUG
72 #include <debug.h>
73
74 #include "ide.h"
75 #include "partitio.h"
76
77 #define VERSION "V0.1.4"
78
79 /* remove this to activate the old behaviour of partition chain code (EK) */
80 #define PARTITION_FIX
81
82 // ------------------------------------------------------- File Static Data
83
84
85 typedef struct _IDE_CONTROLLER_PARAMETERS
86 {
87 int CommandPortBase;
88 int CommandPortSpan;
89 int ControlPortBase;
90 int ControlPortSpan;
91 int Vector;
92 int IrqL;
93 int SynchronizeIrqL;
94 KINTERRUPT_MODE InterruptMode;
95 KAFFINITY Affinity;
96 } IDE_CONTROLLER_PARAMETERS, *PIDE_CONTROLLER_PARAMETERS;
97
98 // NOTE: Do not increase max drives above 2
99
100 #define IDE_MAX_DRIVES 2
101
102 #define IDE_MAX_CONTROLLERS 2
103 IDE_CONTROLLER_PARAMETERS Controllers[IDE_MAX_CONTROLLERS] =
104 {
105 {0x01f0, 8, 0x03f6, 1, 14, 14, 15, LevelSensitive, 0xffff},
106 {0x0170, 8, 0x0376, 1, 15, 15, 15, LevelSensitive, 0xffff}
107 /* {0x01E8, 8, 0x03ee, 1, 11, 11, 15, LevelSensitive, 0xffff},
108 {0x0168, 8, 0x036e, 1, 10, 10, 15, LevelSensitive, 0xffff}*/
109 };
110
111 static BOOLEAN IDEInitialized = FALSE;
112
113 // ----------------------------------------------- Discardable Declarations
114
115 #ifdef ALLOC_PRAGMA
116
117 // make the initialization routines discardable, so that they
118 // don't waste space
119
120 #pragma alloc_text(init, DriverEntry)
121 #pragma alloc_text(init, IDECreateController)
122 #pragma alloc_text(init, IDECreateDevices)
123 #pragma alloc_text(init, IDECreateDevice)
124 #pragma alloc_text(init, IDEPolledRead)
125
126 // make the PASSIVE_LEVEL routines pageable, so that they don't
127 // waste nonpaged memory
128
129 #pragma alloc_text(page, IDEShutdown)
130 #pragma alloc_text(page, IDEDispatchOpenClose)
131 #pragma alloc_text(page, IDEDispatchRead)
132 #pragma alloc_text(page, IDEDispatchWrite)
133
134 #endif /* ALLOC_PRAGMA */
135
136 // ---------------------------------------------------- Forward Declarations
137
138 static NTSTATUS
139 IdeFindControllers(IN PDRIVER_OBJECT DriverObject);
140
141 static NTSTATUS
142 IdeCreateController(IN PDRIVER_OBJECT DriverObject,
143 IN PIDE_CONTROLLER_PARAMETERS ControllerParams,
144 IN int ControllerIdx);
145
146 static BOOLEAN IDEResetController(IN WORD CommandPort, IN WORD ControlPort);
147 static BOOLEAN IDECreateDevices(IN PDRIVER_OBJECT DriverObject,
148 IN PCONTROLLER_OBJECT ControllerObject,
149 IN PIDE_CONTROLLER_EXTENSION ControllerExtension,
150 IN int DriveIdx,
151 IN int HarddiskIdx);
152 static BOOLEAN IDEGetDriveIdentification(IN int CommandPort,
153 IN int DriveNum,
154 OUT PIDE_DRIVE_IDENTIFY DrvParms);
155 static NTSTATUS IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject,
156 OUT PDEVICE_OBJECT *DeviceObject,
157 IN PCONTROLLER_OBJECT ControllerObject,
158 IN int UnitNumber,
159 IN ULONG DiskNumber,
160 IN PIDE_DRIVE_IDENTIFY DrvParms,
161 IN ULONG SectorCount);
162 static NTSTATUS IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject,
163 OUT PDEVICE_OBJECT *DeviceObject,
164 IN PCONTROLLER_OBJECT ControllerObject,
165 IN PVOID DiskDeviceExtension,
166 IN int UnitNumber,
167 IN ULONG DiskNumber,
168 IN PIDE_DRIVE_IDENTIFY DrvParms,
169 IN PPARTITION_INFORMATION PartitionInfo);
170 static int IDEPolledRead(IN WORD Address,
171 IN BYTE PreComp,
172 IN BYTE SectorCnt,
173 IN BYTE SectorNum ,
174 IN BYTE CylinderLow,
175 IN BYTE CylinderHigh,
176 IN BYTE DrvHead,
177 IN BYTE Command,
178 OUT BYTE *Buffer);
179 static NTSTATUS STDCALL IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO, IN PIRP Irp);
180 static NTSTATUS STDCALL IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO, IN PIRP Irp);
181 static NTSTATUS STDCALL IDEDispatchDeviceControl(IN PDEVICE_OBJECT pDO, IN PIRP Irp);
182 static VOID STDCALL IDEStartIo(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
183 static IO_ALLOCATION_ACTION STDCALL
184 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject,
185 IN PIRP Irp,
186 IN PVOID MapRegisterBase,
187 IN PVOID Ccontext);
188 static BOOLEAN STDCALL
189 IDEStartController(IN OUT PVOID Context);
190 VOID IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension);
191 static BOOLEAN STDCALL IDEIsr(IN PKINTERRUPT Interrupt, IN PVOID ServiceContext);
192 static VOID IDEDpcForIsr(IN PKDPC Dpc,
193 IN PDEVICE_OBJECT DpcDeviceObject,
194 IN PIRP DpcIrp,
195 IN PVOID DpcContext);
196 static VOID IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension);
197 static VOID STDCALL IDEIoTimer(PDEVICE_OBJECT DeviceObject, PVOID Context);
198
199 // ---------------------------------------------------------------- Inlines
200
201 void
202 IDESwapBytePairs(char *Buf,
203 int Cnt)
204 {
205 char t;
206 int i;
207
208 for (i = 0; i < Cnt; i += 2)
209 {
210 t = Buf[i];
211 Buf[i] = Buf[i+1];
212 Buf[i+1] = t;
213 }
214 }
215
216 // ------------------------------------------------------- Public Interface
217
218 // DriverEntry
219 //
220 // DESCRIPTION:
221 // This function initializes the driver, locates and claims
222 // hardware resources, and creates various NT objects needed
223 // to process I/O requests.
224 //
225 // RUN LEVEL:
226 // PASSIVE_LEVEL
227 //
228 // ARGUMENTS:
229 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
230 // for this driver
231 // IN PUNICODE_STRING RegistryPath Name of registry driver service
232 // key
233 //
234 // RETURNS:
235 // NTSTATUS
236
237 STDCALL NTSTATUS
238 DriverEntry(IN PDRIVER_OBJECT DriverObject,
239 IN PUNICODE_STRING RegistryPath)
240 {
241 NTSTATUS Status;
242
243 DbgPrint("IDE Driver %s\n", VERSION);
244
245 // Export other driver entry points...
246 DriverObject->DriverStartIo = IDEStartIo;
247 DriverObject->MajorFunction[IRP_MJ_CREATE] = IDEDispatchOpenClose;
248 DriverObject->MajorFunction[IRP_MJ_CLOSE] = IDEDispatchOpenClose;
249 DriverObject->MajorFunction[IRP_MJ_READ] = IDEDispatchReadWrite;
250 DriverObject->MajorFunction[IRP_MJ_WRITE] = IDEDispatchReadWrite;
251 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = IDEDispatchQueryInformation;
252 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = IDEDispatchSetInformation;
253 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IDEDispatchDeviceControl;
254
255 Status = IdeFindControllers(DriverObject);
256 if (NT_SUCCESS(Status))
257 {
258 IDEInitialized = TRUE;
259 }
260 return Status;
261 }
262
263 // ---------------------------------------------------- Discardable statics
264
265 static NTSTATUS
266 IdeFindControllers(IN PDRIVER_OBJECT DriverObject)
267 {
268 PCI_COMMON_CONFIG PciConfig;
269 ULONG Bus;
270 ULONG Slot;
271 ULONG Size;
272 ULONG i;
273 NTSTATUS ReturnedStatus = STATUS_NO_SUCH_DEVICE;
274 NTSTATUS Status;
275 INT ControllerIdx = 0;
276 PCONFIGURATION_INFORMATION ConfigInfo;
277
278 DPRINT("IdeFindControllers() called!\n");
279
280 ConfigInfo = IoGetConfigurationInformation();
281
282 /* Search PCI busses for IDE controllers */
283 for (Bus = 0; Bus < 8; Bus++)
284 {
285 for (Slot = 0; Slot < 256; Slot++)
286 {
287 Size = HalGetBusData(PCIConfiguration,
288 Bus,
289 Slot,
290 &PciConfig,
291 sizeof(PCI_COMMON_CONFIG));
292 if (Size != 0)
293 {
294 if ((PciConfig.BaseClass == 0x01) &&
295 (PciConfig.SubClass == 0x01))
296 {
297 DPRINT("IDE controller found!\n");
298
299 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
300 Bus,
301 Slot>>3,
302 Slot & 0x07,
303 PciConfig.VendorID,
304 PciConfig.DeviceID);
305 if ((PciConfig.HeaderType & 0x7FFFFFFF) == 0)
306 {
307 DPRINT(" IPR 0x%X ILR 0x%X\n",
308 PciConfig.u.type0.InterruptPin,
309 PciConfig.u.type0.InterruptLine);
310 }
311
312 if (PciConfig.ProgIf & 0x01)
313 {
314 DPRINT("Primary channel: PCI native mode\n");
315 }
316 else
317 {
318 DPRINT("Primary channel: Compatibility mode\n");
319 if (ConfigInfo->AtDiskPrimaryAddressClaimed == FALSE)
320 {
321 Status = IdeCreateController(DriverObject,
322 &Controllers[0],
323 ControllerIdx);
324 if (NT_SUCCESS(Status))
325 {
326 ControllerIdx++;
327 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
328 ConfigInfo->ScsiPortCount++;
329 ReturnedStatus = Status;
330 }
331 }
332 else
333 {
334 /*
335 * FIXME: Switch controller to native pci mode
336 * if it is programmable.
337 */
338 }
339 }
340 if (PciConfig.ProgIf & 0x02)
341 {
342 DPRINT("Primary channel: programmable\n");
343 }
344 else
345 {
346 DPRINT("Primary channel: not programmable\n");
347 }
348
349 if (PciConfig.ProgIf & 0x04)
350 {
351 DPRINT("Secondary channel: PCI native mode\n");
352 }
353 else
354 {
355 DPRINT("Secondary channel: Compatibility mode\n");
356 #if 0
357 Status = IdeCreateController(DriverObject,
358 &Controllers[1],
359 ControllerIdx);
360 if (NT_SUCCESS(Status))
361 {
362 ControllerIdx++;
363 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
364 ConfigInfo->ScsiPortCount++;
365 ReturnedStatus = Status;
366 }
367 #endif
368 }
369 if (PciConfig.ProgIf & 0x08)
370 {
371 DPRINT("Secondary channel: programmable\n");
372 }
373 else
374 {
375 DPRINT("Secondary channel: not programmable\n");
376 }
377
378 if (PciConfig.ProgIf & 0x80)
379 {
380 DPRINT("Master IDE device: 1\n");
381 }
382 else
383 {
384 DPRINT("Master IDE device: 0\n");
385 }
386
387 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
388 {
389 DPRINT("BaseAddress: 0x%08X\n", PciConfig.u.type0.BaseAddresses[i]);
390 }
391 }
392 }
393 }
394 }
395
396 /* Search for ISA IDE controller if no primary controller was found */
397 if (ConfigInfo->AtDiskPrimaryAddressClaimed == FALSE)
398 {
399 DPRINT("Searching for primary ISA IDE controller!\n");
400
401 if (IDEResetController(Controllers[0].CommandPortBase,
402 Controllers[0].ControlPortBase))
403 {
404 Status = IdeCreateController(DriverObject,
405 &Controllers[0],
406 ControllerIdx);
407 if (NT_SUCCESS(Status))
408 {
409 DPRINT(" Found primary ISA IDE controller!\n");
410 ControllerIdx++;
411 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
412 ConfigInfo->ScsiPortCount++;
413 ReturnedStatus = Status;
414 }
415 }
416 }
417
418 #if 0
419 if (ConfigInfo->AtDiskSecondaryAddressClaimed == FALSE)
420 {
421 DPRINT("Searching for secondary ISA IDE controller!\n");
422
423 if (IDEResetController(Controllers[1].CommandPortBase,
424 Controllers[1].ControlPortBase))
425 {
426 Status = IdeCreateController(DriverObject,
427 &Controllers[1],
428 ControllerIdx);
429 if (NT_SUCCESS(Status))
430 {
431 DPRINT(" Found secondary ISA IDE controller!\n");
432 ControllerIdx++;
433 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
434 ConfigInfo->ScsiPortCount++;
435 ReturnedStatus = Status;
436 }
437 }
438 }
439 #endif
440
441 DPRINT("IdeFindControllers() done!\n");
442
443 return(ReturnedStatus);
444 }
445
446
447 // IdeCreateController
448 //
449 // DESCRIPTION:
450 // Creates a controller object and a device object for each valid
451 // device on the controller
452 //
453 // RUN LEVEL:
454 // PASSIVE LEVEL
455 //
456 // ARGUMENTS:
457 // IN PDRIVER_OBJECT DriverObject The system created driver object
458 // IN PIDE_CONTROLLER_PARAMETERS The parameter block for this
459 // ControllerParams controller
460 // IN int ControllerIdx The index of this controller
461 //
462 // RETURNS:
463 // TRUE Devices where found on this controller
464 // FALSE The controller does not respond or there are no devices on it
465 //
466
467 static NTSTATUS
468 IdeCreateController(IN PDRIVER_OBJECT DriverObject,
469 IN PIDE_CONTROLLER_PARAMETERS ControllerParams,
470 IN int ControllerIdx)
471 {
472 BOOLEAN CreatedDevices, ThisDriveExists;
473 int DriveIdx;
474 NTSTATUS RC;
475 PCONTROLLER_OBJECT ControllerObject;
476 PIDE_CONTROLLER_EXTENSION ControllerExtension;
477
478 ControllerObject = IoCreateController(sizeof(IDE_CONTROLLER_EXTENSION));
479 if (ControllerObject == NULL)
480 {
481 DbgPrint ("Could not create controller object for controller %d\n",
482 ControllerIdx);
483 return STATUS_NO_SUCH_DEVICE;
484 }
485
486 // Fill out Controller extension data
487 ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
488 ControllerObject->ControllerExtension;
489 ControllerExtension->Number = ControllerIdx;
490 ControllerExtension->CommandPortBase = ControllerParams->CommandPortBase;
491 ControllerExtension->ControlPortBase = ControllerParams->ControlPortBase;
492 ControllerExtension->Vector = ControllerParams->Vector;
493 ControllerExtension->DMASupported = FALSE;
494 ControllerExtension->ControllerInterruptBug = FALSE;
495 ControllerExtension->OperationInProgress = FALSE;
496
497 // Initialize the spin lock in the controller extension
498 KeInitializeSpinLock(&ControllerExtension->SpinLock);
499
500 // Register an interrupt handler for this controller
501 RC = IoConnectInterrupt(&ControllerExtension->Interrupt,
502 IDEIsr,
503 ControllerExtension,
504 &ControllerExtension->SpinLock,
505 ControllerExtension->Vector,
506 ControllerParams->IrqL,
507 ControllerParams->SynchronizeIrqL,
508 ControllerParams->InterruptMode,
509 FALSE,
510 ControllerParams->Affinity,
511 FALSE);
512 if (!NT_SUCCESS(RC))
513 {
514 DbgPrint ("Could not Connect Interrupt %d\n",
515 ControllerExtension->Vector);
516 IoDeleteController (ControllerObject);
517 return RC;
518 }
519
520 /* TEST */
521 IDEInitialized = TRUE;
522
523 // Create device objects for each raw device (and for partitions)
524 CreatedDevices = FALSE;
525 for (DriveIdx = 0; DriveIdx < IDE_MAX_DRIVES; DriveIdx++)
526 {
527 ThisDriveExists = IDECreateDevices(DriverObject,
528 ControllerObject,
529 ControllerExtension,
530 DriveIdx,
531 ControllerIdx * 2 + DriveIdx);
532 if (ThisDriveExists)
533 {
534 CreatedDevices = TRUE;
535 }
536 }
537
538 if (!CreatedDevices)
539 {
540 DbgPrint ("Did not find any devices for controller %d\n",
541 ControllerIdx);
542 IoDisconnectInterrupt (ControllerExtension->Interrupt);
543 IoDeleteController (ControllerObject);
544 }
545 else
546 {
547 IDEResetController(ControllerParams->CommandPortBase,
548 ControllerParams->ControlPortBase);
549 IoStartTimer(ControllerExtension->TimerDevice);
550 }
551
552 return((CreatedDevices == TRUE)?STATUS_SUCCESS:STATUS_NO_SUCH_DEVICE);
553 }
554
555
556 // IDEResetController
557 //
558 // DESCRIPTION:
559 // Reset the controller and report completion status
560 //
561 // RUN LEVEL:
562 // PASSIVE_LEVEL
563 //
564 // ARGUMENTS:
565 // IN WORD CommandPort The address of the command port
566 // IN WORD ControlPort The address of the control port
567 //
568 // RETURNS:
569 //
570
571 BOOLEAN
572 IDEResetController(IN WORD CommandPort,
573 IN WORD ControlPort)
574 {
575 int Retries;
576
577 // Assert drive reset line
578 IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
579
580 // Wait for min. 25 microseconds
581 KeStallExecutionProcessor(IDE_RESET_PULSE_LENGTH);
582
583 // Negate drive reset line
584 IDEWriteDriveControl(ControlPort, 0);
585
586 // Wait for BUSY negation
587 for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
588 {
589 if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
590 {
591 break;
592 }
593 KeStallExecutionProcessor(10);
594 }
595 CHECKPOINT;
596 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
597 {
598 return FALSE;
599 }
600 CHECKPOINT;
601 // return TRUE if controller came back to life. and
602 // the registers are initialized correctly
603 return IDEReadError(CommandPort) == 1;
604 }
605
606
607 // IDECreateDevices
608 //
609 // DESCRIPTION:
610 // Create the raw device and any partition devices on this drive
611 //
612 // RUN LEVEL:
613 // PASSIVE_LEVEL
614 //
615 // ARGUMENTS:
616 // IN PDRIVER_OBJECT DriverObject The system created driver object
617 // IN PCONTROLLER_OBJECT ControllerObject
618 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
619 // The IDE controller extension for
620 // this device
621 // IN int DriveIdx The index of the drive on this
622 // controller
623 // IN int HarddiskIdx The NT device number for this
624 // drive
625 //
626 // RETURNS:
627 // TRUE Drive exists and devices were created
628 // FALSE no devices were created for this device
629 //
630
631 BOOLEAN
632 IDECreateDevices(IN PDRIVER_OBJECT DriverObject,
633 IN PCONTROLLER_OBJECT ControllerObject,
634 IN PIDE_CONTROLLER_EXTENSION ControllerExtension,
635 IN int DriveIdx,
636 IN int HarddiskIdx)
637 {
638 WCHAR NameBuffer[IDE_MAX_NAME_LENGTH];
639 int CommandPort;
640 NTSTATUS Status;
641 IDE_DRIVE_IDENTIFY DrvParms;
642 PDEVICE_OBJECT DiskDeviceObject;
643 PDEVICE_OBJECT PartitionDeviceObject;
644 PIDE_DEVICE_EXTENSION DiskDeviceExtension;
645 UNICODE_STRING UnicodeDeviceDirName;
646 OBJECT_ATTRIBUTES DeviceDirAttributes;
647 HANDLE Handle;
648 ULONG SectorCount = 0;
649 PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
650 PPARTITION_INFORMATION PartitionEntry;
651 ULONG i;
652
653 // Copy I/O port offsets for convenience
654 CommandPort = ControllerExtension->CommandPortBase;
655 // ControlPort = ControllerExtension->ControlPortBase;
656 DPRINT("probing IDE controller %d Addr %04lx Drive %d\n",
657 ControllerExtension->Number,
658 CommandPort,
659 DriveIdx);
660
661 /* Get the Drive Identification Data */
662 if (!IDEGetDriveIdentification(CommandPort, DriveIdx, &DrvParms))
663 {
664 CHECKPOINT1;
665 DbgPrint("Giving up on drive %d on controller %d...\n",
666 DriveIdx,
667 ControllerExtension->Number);
668 return FALSE;
669 }
670
671 /* Create the harddisk device directory */
672 swprintf (NameBuffer,
673 L"\\Device\\Harddisk%d",
674 HarddiskIdx);
675 RtlInitUnicodeString(&UnicodeDeviceDirName,
676 NameBuffer);
677 InitializeObjectAttributes(&DeviceDirAttributes,
678 &UnicodeDeviceDirName,
679 0,
680 NULL,
681 NULL);
682 Status = ZwCreateDirectoryObject(&Handle, 0, &DeviceDirAttributes);
683 if (!NT_SUCCESS(Status))
684 {
685 DbgPrint("Could not create device dir object\n");
686 return FALSE;
687 }
688
689 /* Create the disk device */
690 if (DrvParms.Capabilities & IDE_DRID_LBA_SUPPORTED)
691 {
692 SectorCount =
693 (ULONG)((DrvParms.TMSectorCountHi << 16) + DrvParms.TMSectorCountLo);
694 }
695 else
696 {
697 SectorCount =
698 (ULONG)(DrvParms.LogicalCyls * DrvParms.LogicalHeads * DrvParms.SectorsPerTrack);
699 }
700 DPRINT("SectorCount %lu\n", SectorCount);
701
702 Status = IDECreateDiskDevice(DriverObject,
703 &DiskDeviceObject,
704 ControllerObject,
705 DriveIdx,
706 HarddiskIdx,
707 &DrvParms,
708 SectorCount);
709 if (!NT_SUCCESS(Status))
710 {
711 DbgPrint("IDECreateDevice call failed for raw device\n");
712 return FALSE;
713 }
714
715 /* Increase number of available physical disk drives */
716 IoGetConfigurationInformation()->DiskCount++;
717
718 /*
719 * Initialize the controller timer here
720 * (since it has to be tied to a device)
721 */
722 if (DriveIdx == 0)
723 {
724 ControllerExtension->TimerState = IDETimerIdle;
725 ControllerExtension->TimerCount = 0;
726 ControllerExtension->TimerDevice = DiskDeviceObject;
727 IoInitializeTimer(DiskDeviceObject,
728 IDEIoTimer,
729 ControllerExtension);
730 }
731
732 DPRINT("DrvParms.BytesPerSector %ld\n",DrvParms.BytesPerSector);
733
734 /* Read partition table */
735 Status = IoReadPartitionTable(DiskDeviceObject,
736 DrvParms.BytesPerSector,
737 TRUE,
738 &PartitionList);
739 if (!NT_SUCCESS(Status))
740 {
741 DbgPrint("IoReadPartitionTable() failed\n");
742 return FALSE;
743 }
744
745 DPRINT(" Number of partitions: %u\n", PartitionList->PartitionCount);
746 for (i=0;i < PartitionList->PartitionCount; i++)
747 {
748 PartitionEntry = &PartitionList->PartitionEntry[i];
749
750 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
751 i,
752 PartitionEntry->PartitionNumber,
753 PartitionEntry->BootIndicator,
754 PartitionEntry->PartitionType,
755 PartitionEntry->StartingOffset.QuadPart / 512 /*DrvParms.BytesPerSector*/,
756 PartitionEntry->PartitionLength.QuadPart / 512 /* DrvParms.BytesPerSector*/);
757
758 /* Create device for partition */
759 Status = IDECreatePartitionDevice(DriverObject,
760 &PartitionDeviceObject,
761 ControllerObject,
762 DiskDeviceObject->DeviceExtension, //DiskDeviceExtension,
763 DriveIdx,
764 HarddiskIdx,
765 &DrvParms,
766 PartitionEntry);
767 if (!NT_SUCCESS(Status))
768 {
769 DbgPrint("IDECreateDevice() failed\n");
770 break;
771 }
772 }
773
774 if (PartitionList != NULL)
775 ExFreePool(PartitionList);
776
777 return TRUE;
778 }
779
780 // IDEGetDriveIdentification
781 //
782 // DESCRIPTION:
783 // Get the identification block from the drive
784 //
785 // RUN LEVEL:
786 // PASSIVE_LEVEL
787 //
788 // ARGUMENTS:
789 // IN int CommandPort Address of the command port
790 // IN int DriveNum The drive index (0,1)
791 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
792 //
793 // RETURNS:
794 // TRUE The drive identification block was retrieved successfully
795 //
796
797 BOOLEAN
798 IDEGetDriveIdentification(IN int CommandPort,
799 IN int DriveNum,
800 OUT PIDE_DRIVE_IDENTIFY DrvParms)
801 {
802
803 // Get the Drive Identify block from drive or die
804 if (IDEPolledRead(CommandPort, 0, 0, 0, 0, 0, (DriveNum ? IDE_DH_DRV1 : 0),
805 IDE_CMD_IDENT_DRV, (BYTE *)DrvParms) != 0)
806 {
807 CHECKPOINT1;
808 return FALSE;
809 }
810
811 // Report on drive parameters if debug mode
812 IDESwapBytePairs(DrvParms->SerialNumber, 20);
813 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
814 IDESwapBytePairs(DrvParms->ModelNumber, 40);
815 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
816 DrvParms->ConfigBits,
817 DrvParms->LogicalCyls,
818 DrvParms->LogicalHeads,
819 DrvParms->SectorsPerTrack,
820 DrvParms->InterSectorGap,
821 DrvParms->InterSectorGapSize);
822 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
823 DrvParms->BytesInPLO,
824 DrvParms->VendorUniqueCnt,
825 DrvParms->SerialNumber);
826 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
827 DrvParms->ControllerType,
828 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
829 DrvParms->ECCByteCnt,
830 DrvParms->FirmwareRev);
831 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
832 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
833 (DrvParms->RWMultImplemented) & 0xff,
834 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
835 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
836 DrvParms->MinPIOTransTime,
837 DrvParms->MinDMATransTime);
838 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
839 DrvParms->TMCylinders,
840 DrvParms->TMHeads,
841 DrvParms->TMSectorsPerTrk,
842 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
843 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
844 DrvParms->TMSectorCountHi,
845 DrvParms->TMSectorCountLo,
846 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
847
848 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
849 DrvParms->BytesPerSector = 512; /* FIXME !!!*/
850 return TRUE;
851 }
852
853
854 // IDECreateDiskDevice
855 //
856 // DESCRIPTION:
857 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
858 //
859 // RUN LEVEL:
860 // PASSIVE_LEVEL
861 //
862 // ARGUMENTS:
863 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
864 // OUT PDEVICE_OBJECT *DeviceObject The created device object
865 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
866 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
867 // IN BOOLEAN DMASupported Does the drive support DMA?
868 // IN int SectorsPerLogCyl Sectors per cylinder
869 // IN int SectorsPerLogTrk Sectors per track
870 // IN DWORD Offset First valid sector for this device
871 // IN DWORD Size Count of valid sectors for this device
872 //
873 // RETURNS:
874 // NTSTATUS
875 //
876
877 NTSTATUS
878 IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject,
879 OUT PDEVICE_OBJECT *DeviceObject,
880 IN PCONTROLLER_OBJECT ControllerObject,
881 IN int UnitNumber,
882 IN ULONG DiskNumber,
883 IN PIDE_DRIVE_IDENTIFY DrvParms,
884 IN ULONG SectorCount)
885 {
886 WCHAR NameBuffer[IDE_MAX_NAME_LENGTH];
887 WCHAR ArcNameBuffer[IDE_MAX_NAME_LENGTH + 15];
888 UNICODE_STRING DeviceName;
889 UNICODE_STRING ArcName;
890 NTSTATUS RC;
891 PIDE_DEVICE_EXTENSION DeviceExtension;
892
893 // Create a unicode device name
894 swprintf(NameBuffer,
895 L"\\Device\\Harddisk%d\\Partition0",
896 DiskNumber);
897 RtlInitUnicodeString(&DeviceName,
898 NameBuffer);
899
900 // Create the device
901 RC = IoCreateDevice(DriverObject,
902 sizeof(IDE_DEVICE_EXTENSION),
903 &DeviceName,
904 FILE_DEVICE_DISK,
905 0,
906 TRUE,
907 DeviceObject);
908 if (!NT_SUCCESS(RC))
909 {
910 DbgPrint ("IoCreateDevice call failed\n");
911 return RC;
912 }
913
914 // Set the buffering strategy here...
915 (*DeviceObject)->Flags |= DO_DIRECT_IO;
916 (*DeviceObject)->AlignmentRequirement = FILE_WORD_ALIGNMENT;
917
918 // Fill out Device extension data
919 DeviceExtension = (PIDE_DEVICE_EXTENSION) (*DeviceObject)->DeviceExtension;
920 DeviceExtension->DeviceObject = (*DeviceObject);
921 DeviceExtension->ControllerObject = ControllerObject;
922 DeviceExtension->DiskDeviceExtension = DeviceExtension;
923 DeviceExtension->UnitNumber = UnitNumber;
924 DeviceExtension->LBASupported =
925 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0;
926 DeviceExtension->DMASupported =
927 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0;
928 // FIXME: deal with bizarre sector sizes
929 DeviceExtension->BytesPerSector = 512 /* DrvParms->BytesPerSector */;
930 DeviceExtension->SectorsPerLogCyl = DrvParms->LogicalHeads *
931 DrvParms->SectorsPerTrack;
932 DeviceExtension->SectorsPerLogTrk = DrvParms->SectorsPerTrack;
933 DeviceExtension->LogicalHeads = DrvParms->LogicalHeads;
934 DeviceExtension->LogicalCylinders =
935 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? DrvParms->TMCylinders : DrvParms->LogicalCyls;
936 DeviceExtension->Offset = 0;
937 DeviceExtension->Size = SectorCount;
938 DPRINT("%wZ: offset %lu size %lu \n",
939 &DeviceName,
940 DeviceExtension->Offset,
941 DeviceExtension->Size);
942
943 /* Initialize the DPC object here */
944 IoInitializeDpcRequest(*DeviceObject,
945 IDEDpcForIsr);
946
947 /* assign arc name */
948 swprintf(ArcNameBuffer,
949 L"\\ArcName\\multi(0)disk(0)rdisk(%d)",
950 DiskNumber);
951 RtlInitUnicodeString(&ArcName,
952 ArcNameBuffer);
953 DPRINT("%wZ ==> %wZ\n", &ArcName, &DeviceName);
954 RC = IoAssignArcName(&ArcName,
955 &DeviceName);
956 if (!NT_SUCCESS(RC))
957 {
958 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName, RC);
959 }
960
961 return RC;
962 }
963
964
965 // IDECreatePartitionDevice
966 //
967 // DESCRIPTION:
968 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
969 //
970 // RUN LEVEL:
971 // PASSIVE_LEVEL
972 //
973 // ARGUMENTS:
974 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
975 // OUT PDEVICE_OBJECT *DeviceObject The created device object
976 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
977 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
978 // IN BOOLEAN DMASupported Does the drive support DMA?
979 // IN int SectorsPerLogCyl Sectors per cylinder
980 // IN int SectorsPerLogTrk Sectors per track
981 // IN DWORD Offset First valid sector for this device
982 // IN DWORD Size Count of valid sectors for this device
983 //
984 // RETURNS:
985 // NTSTATUS
986 //
987
988 NTSTATUS
989 IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject,
990 OUT PDEVICE_OBJECT *DeviceObject,
991 IN PCONTROLLER_OBJECT ControllerObject,
992 IN PVOID DiskDeviceExtension,
993 IN int UnitNumber,
994 IN ULONG DiskNumber,
995 IN PIDE_DRIVE_IDENTIFY DrvParms,
996 IN PPARTITION_INFORMATION PartitionInfo)
997 {
998 WCHAR NameBuffer[IDE_MAX_NAME_LENGTH];
999 WCHAR ArcNameBuffer[IDE_MAX_NAME_LENGTH + 15];
1000 UNICODE_STRING DeviceName;
1001 UNICODE_STRING ArcName;
1002 NTSTATUS RC;
1003 PIDE_DEVICE_EXTENSION DeviceExtension;
1004
1005 // Create a unicode device name
1006 swprintf(NameBuffer,
1007 L"\\Device\\Harddisk%d\\Partition%d",
1008 DiskNumber,
1009 PartitionInfo->PartitionNumber);
1010 RtlInitUnicodeString(&DeviceName,
1011 NameBuffer);
1012
1013 // Create the device
1014 RC = IoCreateDevice(DriverObject, sizeof(IDE_DEVICE_EXTENSION),
1015 &DeviceName, FILE_DEVICE_DISK, 0, TRUE, DeviceObject);
1016 if (!NT_SUCCESS(RC))
1017 {
1018 DbgPrint ("IoCreateDevice call failed\n");
1019 return RC;
1020 }
1021
1022 // Set the buffering strategy here...
1023 (*DeviceObject)->Flags |= DO_DIRECT_IO;
1024 (*DeviceObject)->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1025
1026 // Fill out Device extension data
1027 DeviceExtension = (PIDE_DEVICE_EXTENSION) (*DeviceObject)->DeviceExtension;
1028 DeviceExtension->DeviceObject = (*DeviceObject);
1029 DeviceExtension->ControllerObject = ControllerObject;
1030 DeviceExtension->DiskDeviceExtension = DiskDeviceExtension;
1031 DeviceExtension->UnitNumber = UnitNumber;
1032 DeviceExtension->LBASupported =
1033 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0;
1034 DeviceExtension->DMASupported =
1035 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0;
1036 // FIXME: deal with bizarre sector sizes
1037 DeviceExtension->BytesPerSector = 512 /* DrvParms->BytesPerSector */;
1038 DeviceExtension->SectorsPerLogCyl = DrvParms->LogicalHeads *
1039 DrvParms->SectorsPerTrack;
1040 DeviceExtension->SectorsPerLogTrk = DrvParms->SectorsPerTrack;
1041 DeviceExtension->LogicalHeads = DrvParms->LogicalHeads;
1042 DeviceExtension->LogicalCylinders =
1043 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? DrvParms->TMCylinders : DrvParms->LogicalCyls;
1044 // DeviceExtension->Offset = Offset;
1045 // DeviceExtension->Size = Size;
1046
1047 DeviceExtension->Offset = PartitionInfo->StartingOffset.QuadPart / 512; /* DrvParms.BytesPerSector*/
1048 DeviceExtension->Size = PartitionInfo->PartitionLength.QuadPart / 512; /*DrvParms.BytesPerSector*/
1049
1050 DPRINT("%wZ: offset %lu size %lu \n",
1051 &DeviceName,
1052 DeviceExtension->Offset,
1053 DeviceExtension->Size);
1054
1055 /* Initialize the DPC object here */
1056 IoInitializeDpcRequest(*DeviceObject, IDEDpcForIsr);
1057
1058 DbgPrint("%wZ %luMB\n", &DeviceName, DeviceExtension->Size / 2048);
1059
1060 /* assign arc name */
1061 swprintf(ArcNameBuffer,
1062 L"\\ArcName\\multi(0)disk(0)rdisk(%d)partition(%d)",
1063 DiskNumber,
1064 PartitionInfo->PartitionNumber);
1065 RtlInitUnicodeString(&ArcName,
1066 ArcNameBuffer);
1067 DPRINT("%wZ ==> %wZ\n", &ArcName, &DeviceName);
1068 RC = IoAssignArcName(&ArcName,
1069 &DeviceName);
1070 if (!NT_SUCCESS(RC))
1071 {
1072 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName, RC);
1073 }
1074
1075 return RC;
1076 }
1077
1078
1079 // IDEPolledRead
1080 //
1081 // DESCRIPTION:
1082 // Read a sector of data from the drive in a polled fashion.
1083 //
1084 // RUN LEVEL:
1085 // PASSIVE_LEVEL
1086 //
1087 // ARGUMENTS:
1088 // IN WORD Address Address of command port for drive
1089 // IN BYTE PreComp Value to write to precomp register
1090 // IN BYTE SectorCnt Value to write to sectorCnt register
1091 // IN BYTE SectorNum Value to write to sectorNum register
1092 // IN BYTE CylinderLow Value to write to CylinderLow register
1093 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1094 // IN BYTE DrvHead Value to write to Drive/Head register
1095 // IN BYTE Command Value to write to Command register
1096 // OUT BYTE *Buffer Buffer for output data
1097 //
1098 // RETURNS:
1099 // int 0 is success, non 0 is an error code
1100 //
1101
1102 static int
1103 IDEPolledRead(IN WORD Address,
1104 IN BYTE PreComp,
1105 IN BYTE SectorCnt,
1106 IN BYTE SectorNum,
1107 IN BYTE CylinderLow,
1108 IN BYTE CylinderHigh,
1109 IN BYTE DrvHead,
1110 IN BYTE Command,
1111 OUT BYTE *Buffer)
1112 {
1113 BYTE Status;
1114 int RetryCount;
1115
1116 /* Wait for STATUS.BUSY to clear */
1117 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1118 {
1119 Status = IDEReadStatus(Address);
1120 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1121 // if (!(Status & IDE_SR_BUSY))
1122 {
1123 break;
1124 }
1125 KeStallExecutionProcessor(10);
1126 }
1127 if (RetryCount == IDE_MAX_BUSY_RETRIES)
1128 {
1129 return IDE_ER_ABRT;
1130 }
1131
1132 /* Write Drive/Head to select drive */
1133 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
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 CHECKPOINT1;
1148 return IDE_ER_ABRT;
1149 }
1150
1151 /* Issue command to drive */
1152 if (DrvHead & IDE_DH_LBA)
1153 {
1154 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1155 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1156 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1157 SectorCnt,
1158 Command);
1159 }
1160 else
1161 {
1162 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1163 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1164 CylinderHigh,
1165 CylinderLow,
1166 DrvHead & 0x0f,
1167 SectorNum,
1168 SectorCnt,
1169 Command);
1170 }
1171
1172 /* Setup command parameters */
1173 IDEWritePrecomp(Address, PreComp);
1174 IDEWriteSectorCount(Address, SectorCnt);
1175 IDEWriteSectorNum(Address, SectorNum);
1176 IDEWriteCylinderHigh(Address, CylinderHigh);
1177 IDEWriteCylinderLow(Address, CylinderLow);
1178 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
1179
1180 /* Issue the command */
1181 IDEWriteCommand(Address, Command);
1182 KeStallExecutionProcessor(50);
1183
1184 while (1)
1185 {
1186 /* wait for DRQ or error */
1187 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1188 {
1189 Status = IDEReadStatus(Address);
1190 if (!(Status & IDE_SR_BUSY))
1191 {
1192 if (Status & IDE_SR_DRQ)
1193 {
1194 break;
1195 }
1196 else
1197 {
1198 return IDE_ER_ABRT;
1199 }
1200 }
1201 KeStallExecutionProcessor(10);
1202 }
1203 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1204 {
1205 return IDE_ER_ABRT;
1206 }
1207
1208 /* Read data into buffer */
1209 IDEReadBlock(Address, Buffer, IDE_SECTOR_BUF_SZ);
1210 Buffer += IDE_SECTOR_BUF_SZ;
1211
1212 /* Check for more sectors to read */
1213 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1214 {
1215 Status = IDEReadStatus(Address);
1216 if (!(Status & IDE_SR_BUSY))
1217 {
1218 if (Status & IDE_SR_DRQ)
1219 {
1220 break;
1221 }
1222 else
1223 {
1224 return 0;
1225 }
1226 }
1227 }
1228 }
1229 }
1230
1231 // ------------------------------------------- Nondiscardable statics
1232
1233 // IDEDispatchOpenClose
1234 //
1235 // DESCRIPTION:
1236 // Answer requests for Open/Close calls: a null operation
1237 //
1238 // RUN LEVEL:
1239 // PASSIVE_LEVEL
1240 //
1241 // ARGUMENTS:
1242 // Standard dispatch arguments
1243 //
1244 // RETURNS:
1245 // NTSTATUS
1246 //
1247
1248 static NTSTATUS
1249 STDCALL IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO,
1250 IN PIRP Irp)
1251 {
1252 Irp->IoStatus.Status = STATUS_SUCCESS;
1253 Irp->IoStatus.Information = FILE_OPENED;
1254 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1255
1256 return STATUS_SUCCESS;
1257 }
1258
1259 // IDEDispatchReadWrite
1260 //
1261 // DESCRIPTION:
1262 // Answer requests for reads and writes
1263 //
1264 // RUN LEVEL:
1265 // PASSIVE_LEVEL
1266 //
1267 // ARGUMENTS:
1268 // Standard dispatch arguments
1269 //
1270 // RETURNS:
1271 // NTSTATUS
1272 //
1273
1274 static NTSTATUS
1275 STDCALL IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO,
1276 IN PIRP Irp)
1277 {
1278 ULONG IrpInsertKey;
1279 LARGE_INTEGER AdjustedOffset, AdjustedExtent, PartitionExtent, InsertKeyLI;
1280 PIO_STACK_LOCATION IrpStack;
1281 PIDE_DEVICE_EXTENSION DeviceExtension;
1282
1283 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1284 DeviceExtension = (PIDE_DEVICE_EXTENSION)pDO->DeviceExtension;
1285
1286 // Validate operation parameters
1287 AdjustedOffset = RtlEnlargedIntegerMultiply(DeviceExtension->Offset,
1288 DeviceExtension->BytesPerSector);
1289 DPRINT("Offset:%ld * BytesPerSector:%ld = AdjOffset:%ld:%ld\n",
1290 DeviceExtension->Offset,
1291 DeviceExtension->BytesPerSector,
1292 (unsigned long) AdjustedOffset.u.HighPart,
1293 (unsigned long) AdjustedOffset.u.LowPart);
1294 DPRINT("AdjOffset:%ld:%ld + ByteOffset:%ld:%ld\n",
1295 (unsigned long) AdjustedOffset.u.HighPart,
1296 (unsigned long) AdjustedOffset.u.LowPart,
1297 (unsigned long) IrpStack->Parameters.Read.ByteOffset.u.HighPart,
1298 (unsigned long) IrpStack->Parameters.Read.ByteOffset.u.LowPart);
1299 AdjustedOffset = RtlLargeIntegerAdd(AdjustedOffset,
1300 IrpStack->Parameters.Read.ByteOffset);
1301 DPRINT(" = AdjOffset:%ld:%ld\n",
1302 (unsigned long) AdjustedOffset.u.HighPart,
1303 (unsigned long) AdjustedOffset.u.LowPart);
1304 AdjustedExtent = RtlLargeIntegerAdd(AdjustedOffset,
1305 RtlConvertLongToLargeInteger(IrpStack->Parameters.Read.Length));
1306 DPRINT("AdjOffset:%ld:%ld + Length:%ld = AdjExtent:%ld:%ld\n",
1307 (unsigned long) AdjustedOffset.u.HighPart,
1308 (unsigned long) AdjustedOffset.u.LowPart,
1309 IrpStack->Parameters.Read.Length,
1310 (unsigned long) AdjustedExtent.u.HighPart,
1311 (unsigned long) AdjustedExtent.u.LowPart);
1312 /*FIXME: this assumption will fail on drives bigger than 1TB */
1313 PartitionExtent.QuadPart = DeviceExtension->Offset + DeviceExtension->Size;
1314 PartitionExtent = RtlExtendedIntegerMultiply(PartitionExtent,
1315 DeviceExtension->BytesPerSector);
1316 if ((AdjustedExtent.QuadPart > PartitionExtent.QuadPart) ||
1317 (IrpStack->Parameters.Read.Length & (DeviceExtension->BytesPerSector - 1)))
1318 {
1319 DPRINT("Request failed on bad parameters\n",0);
1320 DPRINT("AdjustedExtent=%d:%d PartitionExtent=%d:%d ReadLength=%d\n",
1321 (unsigned int) AdjustedExtent.u.HighPart,
1322 (unsigned int) AdjustedExtent.u.LowPart,
1323 (unsigned int) PartitionExtent.u.HighPart,
1324 (unsigned int) PartitionExtent.u.LowPart,
1325 IrpStack->Parameters.Read.Length);
1326 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1327 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1328 return STATUS_INVALID_PARAMETER;
1329 }
1330
1331 // Adjust operation to absolute sector offset
1332 IrpStack->Parameters.Read.ByteOffset = AdjustedOffset;
1333
1334 // Start the packet and insert the request in order of sector offset
1335 assert(DeviceExtension->BytesPerSector == 512);
1336 InsertKeyLI = RtlLargeIntegerShiftRight(IrpStack->Parameters.Read.ByteOffset, 9);
1337 IrpInsertKey = InsertKeyLI.u.LowPart;
1338 IoStartPacket(DeviceExtension->DeviceObject, Irp, &IrpInsertKey, NULL);
1339
1340 DPRINT("Returning STATUS_PENDING\n");
1341 return STATUS_PENDING;
1342 }
1343
1344 // IDEDispatchDeviceControl
1345 //
1346 // DESCRIPTION:
1347 // Answer requests for device control calls
1348 //
1349 // RUN LEVEL:
1350 // PASSIVE_LEVEL
1351 //
1352 // ARGUMENTS:
1353 // Standard dispatch arguments
1354 //
1355 // RETURNS:
1356 // NTSTATUS
1357 //
1358
1359 static NTSTATUS STDCALL
1360 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1361 IN PIRP Irp)
1362 {
1363 NTSTATUS RC;
1364 ULONG ControlCode, InputLength, OutputLength;
1365 PIO_STACK_LOCATION IrpStack;
1366 PIDE_DEVICE_EXTENSION DeviceExtension;
1367 PIDE_DEVICE_EXTENSION DiskDeviceExtension;
1368 CCHAR Increment;
1369
1370 RC = STATUS_SUCCESS;
1371 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1372 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
1373 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
1374 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
1375 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1376 DiskDeviceExtension = (PIDE_DEVICE_EXTENSION)DeviceExtension->DiskDeviceExtension;
1377 Increment = IO_NO_INCREMENT;
1378
1379 // A huge switch statement in a Windows program?! who would have thought?
1380 switch (ControlCode)
1381 {
1382 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
1383 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
1384 {
1385 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1386 }
1387 else
1388 {
1389 PDISK_GEOMETRY Geometry;
1390
1391 Geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
1392
1393 Geometry->MediaType = FixedMedia;
1394 Geometry->Cylinders.QuadPart = DiskDeviceExtension->LogicalCylinders;
1395 Geometry->TracksPerCylinder = DiskDeviceExtension->SectorsPerLogCyl /
1396 DiskDeviceExtension->SectorsPerLogTrk;
1397 Geometry->SectorsPerTrack = DiskDeviceExtension->SectorsPerLogTrk;
1398 Geometry->BytesPerSector = DiskDeviceExtension->BytesPerSector;
1399
1400 Irp->IoStatus.Status = STATUS_SUCCESS;
1401 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1402 }
1403 break;
1404
1405 case IOCTL_DISK_GET_PARTITION_INFO:
1406 case IOCTL_DISK_SET_PARTITION_INFO:
1407 RC = STATUS_INVALID_DEVICE_REQUEST;
1408 Irp->IoStatus.Status = RC;
1409 Irp->IoStatus.Information = 0;
1410 break;
1411
1412 case IOCTL_DISK_GET_DRIVE_LAYOUT:
1413 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
1414 sizeof(DRIVE_LAYOUT_INFORMATION))
1415 {
1416 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
1417 }
1418 else
1419 {
1420 PDRIVE_LAYOUT_INFORMATION PartitionList;
1421
1422 RC = IoReadPartitionTable(DiskDeviceExtension->DeviceObject,
1423 DiskDeviceExtension->BytesPerSector,
1424 FALSE,
1425 &PartitionList);
1426 if (!NT_SUCCESS(RC))
1427 {
1428 Irp->IoStatus.Status = RC;
1429 }
1430 else
1431 {
1432 ULONG BufferSize;
1433
1434 BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
1435 PartitionEntry[0]);
1436 BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
1437
1438 if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
1439 {
1440 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
1441 }
1442 else
1443 {
1444 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
1445 PartitionList,
1446 BufferSize);
1447 Irp->IoStatus.Status = STATUS_SUCCESS;
1448 Irp->IoStatus.Information = BufferSize;
1449 }
1450 ExFreePool(PartitionList);
1451 }
1452 }
1453 Increment = IO_DISK_INCREMENT;
1454 break;
1455
1456 case IOCTL_DISK_SET_DRIVE_LAYOUT:
1457 case IOCTL_DISK_VERIFY:
1458 case IOCTL_DISK_FORMAT_TRACKS:
1459 case IOCTL_DISK_PERFORMANCE:
1460 case IOCTL_DISK_IS_WRITABLE:
1461 case IOCTL_DISK_LOGGING:
1462 case IOCTL_DISK_FORMAT_TRACKS_EX:
1463 case IOCTL_DISK_HISTOGRAM_STRUCTURE:
1464 case IOCTL_DISK_HISTOGRAM_DATA:
1465 case IOCTL_DISK_HISTOGRAM_RESET:
1466 case IOCTL_DISK_REQUEST_STRUCTURE:
1467 case IOCTL_DISK_REQUEST_DATA:
1468
1469 // If we get here, something went wrong. inform the requestor
1470 default:
1471 RC = STATUS_INVALID_DEVICE_REQUEST;
1472 Irp->IoStatus.Status = RC;
1473 Irp->IoStatus.Information = 0;
1474 break;
1475 }
1476
1477 IoCompleteRequest(Irp, Increment);
1478
1479 return RC;
1480 }
1481
1482 // IDEStartIo
1483 //
1484 // DESCRIPTION:
1485 // Get the next requested I/O packet started
1486 //
1487 // RUN LEVEL:
1488 // DISPATCH_LEVEL
1489 //
1490 // ARGUMENTS:
1491 // Dispatch routine standard arguments
1492 //
1493 // RETURNS:
1494 // NTSTATUS
1495 //
1496
1497 static VOID
1498 STDCALL IDEStartIo(IN PDEVICE_OBJECT DeviceObject,
1499 IN PIRP Irp)
1500 {
1501 LARGE_INTEGER SectorLI;
1502 PIO_STACK_LOCATION IrpStack;
1503 PIDE_DEVICE_EXTENSION DeviceExtension;
1504 KIRQL OldIrql;
1505
1506 DPRINT("IDEStartIo() called!\n");
1507
1508 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1509 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1510
1511 // FIXME: implement the supported functions
1512
1513 switch (IrpStack->MajorFunction)
1514 {
1515 case IRP_MJ_READ:
1516 case IRP_MJ_WRITE:
1517 DeviceExtension->Operation = IrpStack->MajorFunction;
1518 DeviceExtension->BytesRequested = IrpStack->Parameters.Read.Length;
1519 assert(DeviceExtension->BytesPerSector == 512);
1520 SectorLI = RtlLargeIntegerShiftRight(IrpStack->Parameters.Read.ByteOffset, 9);
1521 DeviceExtension->StartingSector = SectorLI.u.LowPart;
1522 if (DeviceExtension->BytesRequested > DeviceExtension->BytesPerSector *
1523 IDE_MAX_SECTORS_PER_XFER)
1524 {
1525 DeviceExtension->BytesToTransfer = DeviceExtension->BytesPerSector *
1526 IDE_MAX_SECTORS_PER_XFER;
1527 }
1528 else
1529 {
1530 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
1531 }
1532 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1533 DeviceExtension->SectorsTransferred = 0;
1534 DeviceExtension->TargetAddress = (BYTE *)MmGetSystemAddressForMdl(Irp->MdlAddress);
1535 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1536 IoAllocateController(DeviceExtension->ControllerObject,
1537 DeviceObject,
1538 IDEAllocateController,
1539 NULL);
1540 KeLowerIrql(OldIrql);
1541 break;
1542
1543 default:
1544 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1545 Irp->IoStatus.Information = 0;
1546 KeBugCheck((ULONG)Irp);
1547 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1548 IoStartNextPacket(DeviceObject, FALSE);
1549 break;
1550 }
1551 DPRINT("IDEStartIo() finished!\n");
1552 }
1553
1554 // IDEAllocateController
1555
1556 static IO_ALLOCATION_ACTION STDCALL
1557 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject,
1558 IN PIRP Irp,
1559 IN PVOID MapRegisterBase,
1560 IN PVOID Ccontext)
1561 {
1562 PIDE_DEVICE_EXTENSION DeviceExtension;
1563 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1564
1565 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1566 ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
1567 DeviceExtension->ControllerObject->ControllerExtension;
1568 ControllerExtension->CurrentIrp = Irp;
1569 ControllerExtension->Retries = 0;
1570 return KeSynchronizeExecution(ControllerExtension->Interrupt,
1571 IDEStartController,
1572 DeviceExtension) ? KeepObject :
1573 DeallocateObject;
1574 }
1575
1576 // IDEStartController
1577
1578 BOOLEAN STDCALL
1579 IDEStartController(IN OUT PVOID Context)
1580 {
1581 BYTE SectorCnt, SectorNum, CylinderLow, CylinderHigh;
1582 BYTE DrvHead, Command;
1583 BYTE Status;
1584 int Retries;
1585 ULONG StartingSector;
1586 PIDE_DEVICE_EXTENSION DeviceExtension;
1587 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1588 PIRP Irp;
1589
1590 DeviceExtension = (PIDE_DEVICE_EXTENSION) Context;
1591 ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
1592 DeviceExtension->ControllerObject->ControllerExtension;
1593 ControllerExtension->OperationInProgress = TRUE;
1594 ControllerExtension->DeviceForOperation = DeviceExtension;
1595
1596 // Write controller registers to start opteration
1597 StartingSector = DeviceExtension->StartingSector;
1598 SectorCnt = DeviceExtension->BytesToTransfer /
1599 DeviceExtension->BytesPerSector;
1600 if (DeviceExtension->LBASupported)
1601 {
1602 SectorNum = StartingSector & 0xff;
1603 CylinderLow = (StartingSector >> 8) & 0xff;
1604 CylinderHigh = (StartingSector >> 16) & 0xff;
1605 DrvHead = ((StartingSector >> 24) & 0x0f) |
1606 (DeviceExtension->UnitNumber ? IDE_DH_DRV1 : 0) |
1607 IDE_DH_LBA;
1608 }
1609 else
1610 {
1611 SectorNum = (StartingSector % DeviceExtension->SectorsPerLogTrk) + 1;
1612 StartingSector /= DeviceExtension->SectorsPerLogTrk;
1613 DrvHead = (StartingSector % DeviceExtension->LogicalHeads) |
1614 (DeviceExtension->UnitNumber ? IDE_DH_DRV1 : 0);
1615 StartingSector /= DeviceExtension->LogicalHeads;
1616 CylinderLow = StartingSector & 0xff;
1617 CylinderHigh = StartingSector >> 8;
1618 }
1619 Command = DeviceExtension->Operation == IRP_MJ_READ ?
1620 IDE_CMD_READ : IDE_CMD_WRITE;
1621 if (DrvHead & IDE_DH_LBA)
1622 {
1623 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1624 DeviceExtension->Operation == IRP_MJ_READ ? "READ" : "WRITE",
1625 ControllerExtension->CommandPortBase,
1626 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1627 ((DrvHead & 0x0f) << 24) +
1628 (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1629 SectorCnt,
1630 Command);
1631 }
1632 else
1633 {
1634 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1635 DeviceExtension->Operation == IRP_MJ_READ ? "READ" : "WRITE",
1636 ControllerExtension->CommandPortBase,
1637 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1638 CylinderHigh,
1639 CylinderLow,
1640 DrvHead & 0x0f,
1641 SectorNum,
1642 SectorCnt,
1643 Command);
1644 }
1645
1646 /* wait for BUSY to clear */
1647 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1648 {
1649 Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1650 if (!(Status & IDE_SR_BUSY))
1651 {
1652 break;
1653 }
1654 KeStallExecutionProcessor(10);
1655 }
1656 DPRINT ("status=%02x\n", Status);
1657 DPRINT ("waited %ld usecs for busy to clear\n", Retries * 10);
1658 if (Retries >= IDE_MAX_BUSY_RETRIES)
1659 {
1660 DPRINT ("Drive is BUSY for too long\n");
1661 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1662 {
1663 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1664 Irp = ControllerExtension->CurrentIrp;
1665 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1666 Irp->IoStatus.Information = 0;
1667
1668 return FALSE;
1669 }
1670 else
1671 {
1672 DPRINT ("Beginning drive reset sequence\n");
1673 IDEBeginControllerReset(ControllerExtension);
1674
1675 return TRUE;
1676 }
1677 }
1678
1679 /* Select the desired drive */
1680 IDEWriteDriveHead(ControllerExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1681
1682 /* wait for BUSY to clear and DRDY to assert */
1683 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1684 {
1685 Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1686 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1687 {
1688 break;
1689 }
1690 KeStallExecutionProcessor(10);
1691 }
1692 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1693 if (Retries >= IDE_MAX_BUSY_RETRIES)
1694 {
1695 DPRINT ("Drive is BUSY for too long after drive select\n");
1696 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1697 {
1698 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1699 Irp = ControllerExtension->CurrentIrp;
1700 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1701 Irp->IoStatus.Information = 0;
1702
1703 return FALSE;
1704 }
1705 else
1706 {
1707 DPRINT ("Beginning drive reset sequence\n");
1708 IDEBeginControllerReset(ControllerExtension);
1709
1710 return TRUE;
1711 }
1712 }
1713
1714 /* Setup command parameters */
1715 IDEWritePrecomp(ControllerExtension->CommandPortBase, 0);
1716 IDEWriteSectorCount(ControllerExtension->CommandPortBase, SectorCnt);
1717 IDEWriteSectorNum(ControllerExtension->CommandPortBase, SectorNum);
1718 IDEWriteCylinderHigh(ControllerExtension->CommandPortBase, CylinderHigh);
1719 IDEWriteCylinderLow(ControllerExtension->CommandPortBase, CylinderLow);
1720 IDEWriteDriveHead(ControllerExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1721
1722 /* Issue command to drive */
1723 IDEWriteCommand(ControllerExtension->CommandPortBase, Command);
1724 ControllerExtension->TimerState = IDETimerCmdWait;
1725 ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1726
1727 if (DeviceExtension->Operation == IRP_MJ_WRITE)
1728 {
1729
1730 // Wait for controller ready
1731 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
1732 {
1733 BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1734 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
1735 {
1736 break;
1737 }
1738 KeStallExecutionProcessor(10);
1739 }
1740 if (Retries >= IDE_MAX_BUSY_RETRIES)
1741 {
1742 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1743 {
1744 Irp = ControllerExtension->CurrentIrp;
1745 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1746 Irp->IoStatus.Information = 0;
1747
1748 return FALSE;
1749 }
1750 else
1751 {
1752 IDEBeginControllerReset(ControllerExtension);
1753
1754 return TRUE;
1755 }
1756 }
1757
1758 // Load the first sector of data into the controller
1759 IDEWriteBlock(ControllerExtension->CommandPortBase,
1760 DeviceExtension->TargetAddress,
1761 IDE_SECTOR_BUF_SZ);
1762 DeviceExtension->TargetAddress += IDE_SECTOR_BUF_SZ;
1763 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1764 DeviceExtension->SectorsTransferred++;
1765 }
1766 DPRINT ("Command issued to drive, IDEStartController done\n");
1767
1768 return TRUE;
1769 }
1770
1771 // IDEBeginControllerReset
1772
1773 VOID
1774 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension)
1775 {
1776 int Retries;
1777
1778 DPRINT("Controller Reset initiated on %04x\n",
1779 ControllerExtension->ControlPortBase);
1780
1781 /* Assert drive reset line */
1782 DPRINT("Asserting reset line\n");
1783 IDEWriteDriveControl(ControllerExtension->ControlPortBase, IDE_DC_SRST);
1784
1785 /* Wait for BSY assertion */
1786 DPRINT("Waiting for BSY assertion\n");
1787 for (Retries = 0; Retries < IDE_MAX_RESET_RETRIES; Retries++)
1788 {
1789 BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1790 if ((Status & IDE_SR_BUSY))
1791 {
1792 break;
1793 }
1794 KeStallExecutionProcessor(10);
1795 }
1796 if (Retries == IDE_MAX_RESET_RETRIES)
1797 {
1798 DPRINT("Timeout on BSY assertion\n");
1799 }
1800
1801 /* Negate drive reset line */
1802 DPRINT("Negating reset line\n");
1803 IDEWriteDriveControl(ControllerExtension->ControlPortBase, 0);
1804
1805 // FIXME: handle case of no device 0
1806
1807 /* Set timer to check for end of reset */
1808 ControllerExtension->TimerState = IDETimerResetWaitForBusyNegate;
1809 ControllerExtension->TimerCount = IDE_RESET_BUSY_TIMEOUT;
1810 }
1811
1812 // IDEIsr
1813 //
1814 // DESCIPTION:
1815 // Handle interrupts for IDE devices
1816 //
1817 // RUN LEVEL:
1818 // DIRQL
1819 //
1820 // ARGUMENTS:
1821 // IN PKINTERRUPT Interrupt The interrupt level in effect
1822 // IN PVOID ServiceContext The driver supplied context
1823 // (the controller extension)
1824 // RETURNS:
1825 // TRUE This ISR handled the interrupt
1826 // FALSE Another ISR must handle this interrupt
1827
1828 static BOOLEAN STDCALL
1829 IDEIsr(IN PKINTERRUPT Interrupt,
1830 IN PVOID ServiceContext)
1831 {
1832 BOOLEAN IsLastBlock, AnErrorOccured, RequestIsComplete;
1833 BYTE *TargetAddress;
1834 int Retries;
1835 NTSTATUS ErrorStatus;
1836 ULONG ErrorInformation;
1837 PIRP Irp;
1838 PIDE_DEVICE_EXTENSION DeviceExtension;
1839 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1840
1841 if (IDEInitialized == FALSE)
1842 {
1843 return FALSE;
1844 }
1845 DPRINT ("IDEIsr called\n");
1846
1847 ControllerExtension = (PIDE_CONTROLLER_EXTENSION) ServiceContext;
1848
1849 // Read the status port to clear the interrtupt (even if it's not ours).
1850 ControllerExtension->DeviceStatus = IDEReadStatus(ControllerExtension->CommandPortBase);
1851
1852 // If the interrupt is not ours, get the heck outta dodge.
1853 if (!ControllerExtension->OperationInProgress)
1854 {
1855 return FALSE;
1856 }
1857
1858 DeviceExtension = ControllerExtension->DeviceForOperation;
1859 IsLastBlock = FALSE;
1860 AnErrorOccured = FALSE;
1861 RequestIsComplete = FALSE;
1862 ErrorStatus = STATUS_SUCCESS;
1863 ErrorInformation = 0;
1864
1865 // Handle error condition if it exists
1866 if (ControllerExtension->DeviceStatus & IDE_SR_ERR)
1867 {
1868 BYTE ErrorReg, SectorCount, SectorNum, CylinderLow, CylinderHigh;
1869 BYTE DriveHead;
1870
1871 // Log the error
1872 ErrorReg = IDEReadError(ControllerExtension->CommandPortBase);
1873 CylinderLow = IDEReadCylinderLow(ControllerExtension->CommandPortBase);
1874 CylinderHigh = IDEReadCylinderHigh(ControllerExtension->CommandPortBase);
1875 DriveHead = IDEReadDriveHead(ControllerExtension->CommandPortBase);
1876 SectorCount = IDEReadSectorCount(ControllerExtension->CommandPortBase);
1877 SectorNum = IDEReadSectorNum(ControllerExtension->CommandPortBase);
1878 // FIXME: should use the NT error logging facility
1879 DbgPrint ("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1880 DeviceExtension->Operation,
1881 ControllerExtension->DeviceStatus,
1882 ErrorReg,
1883 CylinderLow,
1884 CylinderHigh,
1885 SectorCount,
1886 SectorNum);
1887
1888 // FIXME: should retry the command and perhaps recalibrate the drive
1889
1890 // Set error status information
1891 AnErrorOccured = TRUE;
1892 ErrorStatus = STATUS_DISK_OPERATION_FAILED;
1893 ErrorInformation =
1894 (((((((CylinderHigh << 8) + CylinderLow) *
1895 DeviceExtension->LogicalHeads) +
1896 (DriveHead % DeviceExtension->LogicalHeads)) *
1897 DeviceExtension->SectorsPerLogTrk) + SectorNum - 1) -
1898 DeviceExtension->StartingSector) * DeviceExtension->BytesPerSector;
1899 }
1900 else
1901 {
1902
1903 // Check controller and setup for next transfer
1904 switch (DeviceExtension->Operation)
1905 {
1906 case IRP_MJ_READ:
1907
1908 // Update controller/device state variables
1909 TargetAddress = DeviceExtension->TargetAddress;
1910 DeviceExtension->TargetAddress += DeviceExtension->BytesPerSector;
1911 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1912 DeviceExtension->SectorsTransferred++;
1913
1914 // Remember whether DRQ should be low at end (last block read)
1915 IsLastBlock = DeviceExtension->BytesToTransfer == 0;
1916
1917 // Wait for DRQ assertion
1918 for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
1919 !(IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ);
1920 Retries++)
1921 {
1922 KeStallExecutionProcessor(10);
1923 }
1924
1925 // Copy the block of data
1926 IDEReadBlock(ControllerExtension->CommandPortBase,
1927 TargetAddress,
1928 IDE_SECTOR_BUF_SZ);
1929
1930 // check DRQ
1931 if (IsLastBlock)
1932 {
1933 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
1934 (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_BUSY);
1935 Retries++)
1936 {
1937 KeStallExecutionProcessor(10);
1938 }
1939
1940 // Check for data overrun
1941 if (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ)
1942 {
1943 AnErrorOccured = TRUE;
1944 ErrorStatus = STATUS_DATA_OVERRUN;
1945 ErrorInformation = 0;
1946 }
1947 else
1948 {
1949
1950 // Setup next transfer or set RequestIsComplete
1951 if (DeviceExtension->BytesRequested >
1952 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
1953 {
1954 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
1955 DeviceExtension->SectorsTransferred = 0;
1956 DeviceExtension->BytesToTransfer =
1957 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
1958 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1959 }
1960 else if (DeviceExtension->BytesRequested > 0)
1961 {
1962 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
1963 DeviceExtension->SectorsTransferred = 0;
1964 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
1965 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1966 }
1967 else
1968 {
1969 RequestIsComplete = TRUE;
1970 }
1971 }
1972 }
1973 break;
1974
1975 case IRP_MJ_WRITE:
1976
1977 // check DRQ
1978 if (DeviceExtension->BytesToTransfer == 0)
1979 {
1980 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
1981 (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_BUSY);
1982 Retries++)
1983 {
1984 KeStallExecutionProcessor(10);
1985 }
1986
1987 // Check for data overrun
1988 if (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ)
1989 {
1990 AnErrorOccured = TRUE;
1991 ErrorStatus = STATUS_DATA_OVERRUN;
1992 ErrorInformation = 0;
1993 }
1994 else
1995 {
1996
1997 // Setup next transfer or set RequestIsComplete
1998 IsLastBlock = TRUE;
1999 if (DeviceExtension->BytesRequested >
2000 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
2001 {
2002 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
2003 DeviceExtension->SectorsTransferred = 0;
2004 DeviceExtension->BytesToTransfer =
2005 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
2006 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
2007 }
2008 else if (DeviceExtension->BytesRequested > 0)
2009 {
2010 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
2011 DeviceExtension->SectorsTransferred = 0;
2012 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
2013 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
2014 }
2015 else
2016 {
2017 RequestIsComplete = TRUE;
2018 }
2019 }
2020 }
2021 else
2022 {
2023
2024 // Update controller/device state variables
2025 TargetAddress = DeviceExtension->TargetAddress;
2026 DeviceExtension->TargetAddress += DeviceExtension->BytesPerSector;
2027 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
2028 DeviceExtension->SectorsTransferred++;
2029
2030 // Write block to controller
2031 IDEWriteBlock(ControllerExtension->CommandPortBase,
2032 TargetAddress,
2033 IDE_SECTOR_BUF_SZ);
2034 }
2035 break;
2036 }
2037 }
2038
2039 // If there was an error or the request is done, complete the packet
2040 if (AnErrorOccured || RequestIsComplete)
2041 {
2042 // Set the return status and info values
2043 Irp = ControllerExtension->CurrentIrp;
2044 Irp->IoStatus.Status = ErrorStatus;
2045 Irp->IoStatus.Information = ErrorInformation;
2046
2047 // Clear out controller fields
2048 ControllerExtension->OperationInProgress = FALSE;
2049 ControllerExtension->DeviceStatus = 0;
2050
2051 // Queue the Dpc to finish up
2052 IoRequestDpc(DeviceExtension->DeviceObject,
2053 Irp,
2054 ControllerExtension);
2055 }
2056 else if (IsLastBlock)
2057 {
2058 // Else more data is needed, setup next device I/O
2059 IDEStartController((PVOID)DeviceExtension);
2060 }
2061
2062 return TRUE;
2063 }
2064
2065 // IDEDpcForIsr
2066 // DESCRIPTION:
2067 //
2068 // RUN LEVEL:
2069 //
2070 // ARGUMENTS:
2071 // IN PKDPC Dpc
2072 // IN PDEVICE_OBJECT DpcDeviceObject
2073 // IN PIRP DpcIrp
2074 // IN PVOID DpcContext
2075 //
2076 static VOID
2077 IDEDpcForIsr(IN PKDPC Dpc,
2078 IN PDEVICE_OBJECT DpcDeviceObject,
2079 IN PIRP DpcIrp,
2080 IN PVOID DpcContext)
2081 {
2082 DPRINT("IDEDpcForIsr()\n");
2083 IDEFinishOperation((PIDE_CONTROLLER_EXTENSION) DpcContext);
2084 }
2085
2086 // IDEFinishOperation
2087
2088 static VOID
2089 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension)
2090 {
2091 PIDE_DEVICE_EXTENSION DeviceExtension;
2092 PIRP Irp;
2093 ULONG Operation;
2094
2095 DeviceExtension = ControllerExtension->DeviceForOperation;
2096 Irp = ControllerExtension->CurrentIrp;
2097 Operation = DeviceExtension->Operation;
2098 ControllerExtension->OperationInProgress = FALSE;
2099 ControllerExtension->DeviceForOperation = 0;
2100 ControllerExtension->CurrentIrp = 0;
2101
2102 // Deallocate the controller
2103 IoFreeController(DeviceExtension->ControllerObject);
2104
2105 // Start the next packet
2106 IoStartNextPacketByKey(DeviceExtension->DeviceObject,
2107 FALSE,
2108 DeviceExtension->StartingSector);
2109
2110 // Issue completion of the current packet
2111 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2112
2113 // Flush cache if necessary
2114 if (Operation == IRP_MJ_READ)
2115 {
2116 KeFlushIoBuffers(Irp->MdlAddress, TRUE, FALSE);
2117 }
2118 }
2119
2120 // IDEIoTimer
2121 // DESCRIPTION:
2122 // This function handles timeouts and other time delayed processing
2123 //
2124 // RUN LEVEL:
2125 //
2126 // ARGUMENTS:
2127 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
2128 // IN PVOID Context the Controller extension for the
2129 // controller the device is on
2130 //
2131 static VOID STDCALL
2132 IDEIoTimer(PDEVICE_OBJECT DeviceObject,
2133 PVOID Context)
2134 {
2135 PIDE_CONTROLLER_EXTENSION ControllerExtension;
2136
2137 // Setup Extension pointer
2138 ControllerExtension = (PIDE_CONTROLLER_EXTENSION) Context;
2139 DPRINT("Timer activated for %04lx\n", ControllerExtension->CommandPortBase);
2140
2141 // Handle state change if necessary
2142 switch (ControllerExtension->TimerState)
2143 {
2144 case IDETimerResetWaitForBusyNegate:
2145 if (!(IDEReadStatus(ControllerExtension->CommandPortBase) &
2146 IDE_SR_BUSY))
2147 {
2148 DPRINT("Busy line has negated, waiting for DRDY assert\n");
2149 ControllerExtension->TimerState = IDETimerResetWaitForDrdyAssert;
2150 ControllerExtension->TimerCount = IDE_RESET_DRDY_TIMEOUT;
2151 return;
2152 }
2153 break;
2154
2155 case IDETimerResetWaitForDrdyAssert:
2156 if (IDEReadStatus(ControllerExtension->CommandPortBase) &
2157 IDE_SR_DRQ)
2158 {
2159 DPRINT("DRDY has asserted, reset complete\n");
2160 ControllerExtension->TimerState = IDETimerIdle;
2161 ControllerExtension->TimerCount = 0;
2162
2163 // FIXME: get diagnostic code from drive 0
2164
2165 /* Start current packet command again */
2166 if (!KeSynchronizeExecution(ControllerExtension->Interrupt,
2167 IDEStartController,
2168 ControllerExtension->DeviceForOperation))
2169 {
2170 IDEFinishOperation(ControllerExtension);
2171 }
2172 return;
2173 }
2174 break;
2175
2176 default:
2177 break;
2178 }
2179
2180 // If we're counting down, then count.
2181 if (ControllerExtension->TimerCount > 0)
2182 {
2183 ControllerExtension->TimerCount--;
2184
2185 // Else we'll check the state and process if necessary
2186 }
2187 else
2188 {
2189 switch (ControllerExtension->TimerState)
2190 {
2191 case IDETimerIdle:
2192 break;
2193
2194 case IDETimerCmdWait:
2195 /* Command timed out, reset drive and try again or fail */
2196 DPRINT("Timeout waiting for command completion\n");
2197 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
2198 {
2199 if (ControllerExtension->CurrentIrp != NULL)
2200 {
2201 DbgPrint ("Max retries has been reached, IRP finished with error\n");
2202 ControllerExtension->CurrentIrp->IoStatus.Status = STATUS_IO_TIMEOUT;
2203 ControllerExtension->CurrentIrp->IoStatus.Information = 0;
2204 IDEFinishOperation(ControllerExtension);
2205 }
2206 ControllerExtension->TimerState = IDETimerIdle;
2207 ControllerExtension->TimerCount = 0;
2208 }
2209 else
2210 {
2211 IDEBeginControllerReset(ControllerExtension);
2212 }
2213 break;
2214
2215 case IDETimerResetWaitForBusyNegate:
2216 case IDETimerResetWaitForDrdyAssert:
2217 if (ControllerExtension->CurrentIrp != NULL)
2218 {
2219 DbgPrint ("Timeout waiting for drive reset, giving up on IRP\n");
2220 ControllerExtension->CurrentIrp->IoStatus.Status =
2221 STATUS_IO_TIMEOUT;
2222 ControllerExtension->CurrentIrp->IoStatus.Information = 0;
2223 IDEFinishOperation(ControllerExtension);
2224 }
2225 ControllerExtension->TimerState = IDETimerIdle;
2226 ControllerExtension->TimerCount = 0;
2227 break;
2228 }
2229 }
2230 }
2231
2232