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