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