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