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