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