Corrected additional object manager issues pointed by Philip Susi
[reactos.git] / reactos / drivers / dd / ide / ide.c
1 /* $Id: ide.c,v 1.24 1999/12/22 14:48:27 dwelch 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 DPRINT("Returning STATUS_PENDING\n");
1235 return STATUS_PENDING;
1236 }
1237
1238 // IDEDispatchDeviceControl
1239 //
1240 // DESCRIPTION:
1241 // Answer requests for device control calls
1242 //
1243 // RUN LEVEL:
1244 // PASSIVE_LEVEL
1245 //
1246 // ARGUMENTS:
1247 // Standard dispatch arguments
1248 //
1249 // RETURNS:
1250 // NTSTATUS
1251 //
1252
1253 static NTSTATUS
1254 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1255 IN PIRP Irp)
1256 {
1257 NTSTATUS RC;
1258 ULONG ControlCode, InputLength, OutputLength;
1259 PIO_STACK_LOCATION IrpStack;
1260 PIDE_DEVICE_EXTENSION DeviceExtension;
1261
1262 RC = STATUS_SUCCESS;
1263 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1264 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
1265 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
1266 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
1267 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1268
1269 // A huge switch statement in a Windows program?! who would have thought?
1270 switch (ControlCode)
1271 {
1272 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
1273 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
1274 {
1275 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1276 }
1277 else
1278 {
1279 PDISK_GEOMETRY Geometry;
1280
1281 Geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
1282 Geometry->MediaType = FixedMedia;
1283 // FIXME: should report for RawDevice even on partition
1284 Geometry->Cylinders.QuadPart = DeviceExtension->Size /
1285 DeviceExtension->SectorsPerLogCyl;
1286 Geometry->TracksPerCylinder = DeviceExtension->SectorsPerLogTrk /
1287 DeviceExtension->SectorsPerLogCyl;
1288 Geometry->SectorsPerTrack = DeviceExtension->SectorsPerLogTrk;
1289 Geometry->BytesPerSector = DeviceExtension->BytesPerSector;
1290
1291 Irp->IoStatus.Status = STATUS_SUCCESS;
1292 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1293 }
1294 break;
1295
1296 case IOCTL_DISK_GET_PARTITION_INFO:
1297 case IOCTL_DISK_SET_PARTITION_INFO:
1298 case IOCTL_DISK_GET_DRIVE_LAYOUT:
1299 case IOCTL_DISK_SET_DRIVE_LAYOUT:
1300 case IOCTL_DISK_VERIFY:
1301 case IOCTL_DISK_FORMAT_TRACKS:
1302 case IOCTL_DISK_PERFORMANCE:
1303 case IOCTL_DISK_IS_WRITABLE:
1304 case IOCTL_DISK_LOGGING:
1305 case IOCTL_DISK_FORMAT_TRACKS_EX:
1306 case IOCTL_DISK_HISTOGRAM_STRUCTURE:
1307 case IOCTL_DISK_HISTOGRAM_DATA:
1308 case IOCTL_DISK_HISTOGRAM_RESET:
1309 case IOCTL_DISK_REQUEST_STRUCTURE:
1310 case IOCTL_DISK_REQUEST_DATA:
1311
1312 // If we get here, something went wrong. inform the requestor
1313 default:
1314 RC = STATUS_INVALID_DEVICE_REQUEST;
1315 Irp->IoStatus.Status = RC;
1316 Irp->IoStatus.Information = 0;
1317 break;
1318 }
1319
1320 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1321
1322 return RC;
1323 }
1324
1325 // IDEStartIo
1326 //
1327 // DESCRIPTION:
1328 // Get the next requested I/O packet started
1329 //
1330 // RUN LEVEL:
1331 // DISPATCH_LEVEL
1332 //
1333 // ARGUMENTS:
1334 // Dispatch routine standard arguments
1335 //
1336 // RETURNS:
1337 // NTSTATUS
1338 //
1339
1340 static VOID
1341 IDEStartIo(IN PDEVICE_OBJECT DeviceObject,
1342 IN PIRP Irp)
1343 {
1344 LARGE_INTEGER SectorLI;
1345 PIO_STACK_LOCATION IrpStack;
1346 PIDE_DEVICE_EXTENSION DeviceExtension;
1347 KIRQL OldIrql;
1348
1349 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1350 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1351
1352 // FIXME: implement the supported functions
1353
1354 switch (IrpStack->MajorFunction)
1355 {
1356 case IRP_MJ_READ:
1357 case IRP_MJ_WRITE:
1358 DeviceExtension->Operation = IrpStack->MajorFunction;
1359 DeviceExtension->BytesRequested = IrpStack->Parameters.Read.Length;
1360 assert(DeviceExtension->BytesPerSector == 512);
1361 SectorLI = RtlLargeIntegerShiftRight(IrpStack->Parameters.Read.ByteOffset, 9);
1362 DeviceExtension->StartingSector = SectorLI.u.LowPart;
1363 if (DeviceExtension->BytesRequested > DeviceExtension->BytesPerSector *
1364 IDE_MAX_SECTORS_PER_XFER)
1365 {
1366 DeviceExtension->BytesToTransfer = DeviceExtension->BytesPerSector *
1367 IDE_MAX_SECTORS_PER_XFER;
1368 }
1369 else
1370 {
1371 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
1372 }
1373 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1374 DeviceExtension->SectorsTransferred = 0;
1375 DeviceExtension->TargetAddress = (BYTE *)MmGetSystemAddressForMdl(Irp->MdlAddress);
1376 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1377 IoAllocateController(DeviceExtension->ControllerObject,
1378 DeviceObject,
1379 IDEAllocateController,
1380 NULL);
1381 KeLowerIrql(OldIrql);
1382 break;
1383
1384 default:
1385 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1386 Irp->IoStatus.Information = 0;
1387 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1388 IoStartNextPacket(DeviceObject, FALSE);
1389 break;
1390 }
1391 }
1392
1393 // IDEAllocateController
1394
1395 static IO_ALLOCATION_ACTION
1396 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject,
1397 IN PIRP Irp,
1398 IN PVOID MapRegisterBase,
1399 IN PVOID Ccontext)
1400 {
1401 PIDE_DEVICE_EXTENSION DeviceExtension;
1402 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1403
1404 DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
1405 ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
1406 DeviceExtension->ControllerObject->ControllerExtension;
1407 ControllerExtension->CurrentIrp = Irp;
1408 ControllerExtension->Retries = 0;
1409 return KeSynchronizeExecution(ControllerExtension->Interrupt,
1410 IDEStartController,
1411 DeviceExtension) ? KeepObject :
1412 DeallocateObject;
1413 }
1414
1415 // IDEStartController
1416
1417 BOOLEAN
1418 IDEStartController(IN OUT PVOID Context)
1419 {
1420 BYTE SectorCnt, SectorNum, CylinderLow, CylinderHigh;
1421 BYTE DrvHead, Command;
1422 int Retries;
1423 ULONG StartingSector;
1424 PIDE_DEVICE_EXTENSION DeviceExtension;
1425 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1426 PIRP Irp;
1427
1428 DeviceExtension = (PIDE_DEVICE_EXTENSION) Context;
1429 ControllerExtension = (PIDE_CONTROLLER_EXTENSION)
1430 DeviceExtension->ControllerObject->ControllerExtension;
1431 ControllerExtension->OperationInProgress = TRUE;
1432 ControllerExtension->DeviceForOperation = DeviceExtension;
1433
1434 // Write controller registers to start opteration
1435 StartingSector = DeviceExtension->StartingSector;
1436 SectorCnt = DeviceExtension->BytesToTransfer /
1437 DeviceExtension->BytesPerSector;
1438 if (DeviceExtension->LBASupported)
1439 {
1440 SectorNum = StartingSector & 0xff;
1441 CylinderLow = (StartingSector >> 8) & 0xff;
1442 CylinderHigh = (StartingSector >> 16) & 0xff;
1443 DrvHead = ((StartingSector >> 24) & 0x0f) |
1444 (DeviceExtension->UnitNumber ? IDE_DH_DRV1 : 0) |
1445 IDE_DH_LBA;
1446 }
1447 else
1448 {
1449 SectorNum = (StartingSector % DeviceExtension->SectorsPerLogTrk) + 1;
1450 StartingSector /= DeviceExtension->SectorsPerLogTrk;
1451 DrvHead = (StartingSector % DeviceExtension->LogicalHeads) |
1452 (DeviceExtension->UnitNumber ? IDE_DH_DRV1 : 0);
1453 StartingSector /= DeviceExtension->LogicalHeads;
1454 CylinderLow = StartingSector & 0xff;
1455 CylinderHigh = StartingSector >> 8;
1456 }
1457 Command = DeviceExtension->Operation == IRP_MJ_READ ?
1458 IDE_CMD_READ_RETRY : IDE_CMD_WRITE_RETRY;
1459 if (DrvHead & IDE_DH_LBA)
1460 {
1461 DPRINT("%s:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1462 DeviceExtension->Operation == IRP_MJ_READ ? "READ" : "WRITE",
1463 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1464 ((DrvHead & 0x0f) << 24) +
1465 (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1466 SectorCnt,
1467 Command);
1468 }
1469 else
1470 {
1471 DPRINT("%s:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1472 DeviceExtension->Operation == IRP_MJ_READ ? "READ" : "WRITE",
1473 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1474 CylinderHigh,
1475 CylinderLow,
1476 DrvHead & 0x0f,
1477 SectorNum,
1478 SectorCnt,
1479 Command);
1480 }
1481
1482 /* wait for BUSY to clear */
1483 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1484 {
1485 BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1486 if (!(Status & IDE_SR_BUSY))
1487 {
1488 break;
1489 }
1490 KeStallExecutionProcessor(10);
1491 }
1492 if (Retries >= IDE_MAX_BUSY_RETRIES)
1493 {
1494 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1495 {
1496 Irp = ControllerExtension->CurrentIrp;
1497 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1498 Irp->IoStatus.Information = 0;
1499
1500 return FALSE;
1501 }
1502 else
1503 {
1504 IDEBeginControllerReset(ControllerExtension);
1505
1506 return TRUE;
1507 }
1508 }
1509
1510 /* Select the desired drive */
1511 IDEWriteDriveHead(ControllerExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1512
1513 /* wait for BUSY to clear and DRDY to assert */
1514 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1515 {
1516 BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1517 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1518 {
1519 break;
1520 }
1521 KeStallExecutionProcessor(10);
1522 }
1523 if (Retries >= IDE_MAX_BUSY_RETRIES)
1524 {
1525 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1526 {
1527 Irp = ControllerExtension->CurrentIrp;
1528 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1529 Irp->IoStatus.Information = 0;
1530
1531 return FALSE;
1532 }
1533 else
1534 {
1535 IDEBeginControllerReset(ControllerExtension);
1536
1537 return TRUE;
1538 }
1539 }
1540
1541 /* Setup command parameters */
1542 IDEWritePrecomp(ControllerExtension->CommandPortBase, 0);
1543 IDEWriteSectorCount(ControllerExtension->CommandPortBase, SectorCnt);
1544 IDEWriteSectorNum(ControllerExtension->CommandPortBase, SectorNum);
1545 IDEWriteCylinderHigh(ControllerExtension->CommandPortBase, CylinderHigh);
1546 IDEWriteCylinderLow(ControllerExtension->CommandPortBase, CylinderLow);
1547 IDEWriteDriveHead(ControllerExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1548
1549 /* Issue command to drive */
1550 IDEWriteCommand(ControllerExtension->CommandPortBase, Command);
1551 ControllerExtension->TimerState = IDETimerCmdWait;
1552 ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1553
1554 if (DeviceExtension->Operation == IRP_MJ_WRITE)
1555 {
1556
1557 // Wait for controller ready
1558 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
1559 {
1560 BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1561 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
1562 {
1563 break;
1564 }
1565 KeStallExecutionProcessor(10);
1566 }
1567 if (Retries >= IDE_MAX_BUSY_RETRIES)
1568 {
1569 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1570 {
1571 Irp = ControllerExtension->CurrentIrp;
1572 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1573 Irp->IoStatus.Information = 0;
1574
1575 return FALSE;
1576 }
1577 else
1578 {
1579 IDEBeginControllerReset(ControllerExtension);
1580
1581 return TRUE;
1582 }
1583 }
1584
1585 // Load the first sector of data into the controller
1586 IDEWriteBlock(ControllerExtension->CommandPortBase,
1587 DeviceExtension->TargetAddress,
1588 IDE_SECTOR_BUF_SZ);
1589 DeviceExtension->TargetAddress += IDE_SECTOR_BUF_SZ;
1590 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1591 DeviceExtension->SectorsTransferred++;
1592 }
1593
1594 return TRUE;
1595 }
1596
1597 // IDEBeginControllerReset
1598
1599 VOID
1600 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension)
1601 {
1602 int Retries;
1603
1604 DPRINT("Controller Reset initiated on %04x\n",
1605 ControllerExtension->ControlPortBase);
1606
1607 /* Assert drive reset line */
1608 DPRINT("Asserting reset line\n");
1609 IDEWriteDriveControl(ControllerExtension->ControlPortBase, IDE_DC_SRST);
1610
1611 /* Wait for BSY assertion */
1612 DPRINT("Waiting for BSY assertion\n");
1613 for (Retries = 0; Retries < IDE_MAX_RESET_RETRIES; Retries++)
1614 {
1615 BYTE Status = IDEReadStatus(ControllerExtension->CommandPortBase);
1616 if ((Status & IDE_SR_BUSY))
1617 {
1618 break;
1619 }
1620 KeStallExecutionProcessor(10);
1621 }
1622 if (Retries == IDE_MAX_RESET_RETRIES)
1623 {
1624 DPRINT("Timeout on BSY assertion\n");
1625 }
1626
1627 /* Negate drive reset line */
1628 DPRINT("Negating reset line\n");
1629 IDEWriteDriveControl(ControllerExtension->ControlPortBase, 0);
1630
1631 // FIXME: handle case of no device 0
1632
1633 /* Set timer to check for end of reset */
1634 ControllerExtension->TimerState = IDETimerResetWaitForBusyNegate;
1635 ControllerExtension->TimerCount = IDE_RESET_BUSY_TIMEOUT;
1636 }
1637
1638 // IDEIsr
1639 //
1640 // DESCIPTION:
1641 // Handle interrupts for IDE devices
1642 //
1643 // RUN LEVEL:
1644 // DIRQL
1645 //
1646 // ARGUMENTS:
1647 // IN PKINTERRUPT Interrupt The interrupt level in effect
1648 // IN PVOID ServiceContext The driver supplied context
1649 // (the controller extension)
1650 // RETURNS:
1651 // TRUE This ISR handled the interrupt
1652 // FALSE Another ISR must handle this interrupt
1653
1654 static BOOLEAN
1655 IDEIsr(IN PKINTERRUPT Interrupt,
1656 IN PVOID ServiceContext)
1657 {
1658 BOOLEAN IsLastBlock, AnErrorOccured, RequestIsComplete;
1659 BYTE *TargetAddress;
1660 int Retries;
1661 NTSTATUS ErrorStatus;
1662 ULONG ErrorInformation;
1663 PIRP Irp;
1664 PIDE_DEVICE_EXTENSION DeviceExtension;
1665 PIDE_CONTROLLER_EXTENSION ControllerExtension;
1666
1667 if (IDEInitialized == FALSE)
1668 {
1669 return FALSE;
1670 }
1671
1672 ControllerExtension = (PIDE_CONTROLLER_EXTENSION) ServiceContext;
1673
1674 // Read the status port to clear the interrtupt (even if it's not ours).
1675 ControllerExtension->DeviceStatus = IDEReadStatus(ControllerExtension->CommandPortBase);
1676
1677 // If the interrupt is not ours, get the heck outta dodge.
1678 if (!ControllerExtension->OperationInProgress)
1679 {
1680 return FALSE;
1681 }
1682
1683 DeviceExtension = ControllerExtension->DeviceForOperation;
1684 IsLastBlock = FALSE;
1685 AnErrorOccured = FALSE;
1686 RequestIsComplete = FALSE;
1687 ErrorStatus = STATUS_SUCCESS;
1688 ErrorInformation = 0;
1689
1690 // Handle error condition if it exists
1691 if (ControllerExtension->DeviceStatus & IDE_SR_ERR)
1692 {
1693 BYTE ErrorReg, SectorCount, SectorNum, CylinderLow, CylinderHigh;
1694 BYTE DriveHead;
1695
1696 // Log the error
1697 ErrorReg = IDEReadError(ControllerExtension->CommandPortBase);
1698 CylinderLow = IDEReadCylinderLow(ControllerExtension->CommandPortBase);
1699 CylinderHigh = IDEReadCylinderHigh(ControllerExtension->CommandPortBase);
1700 DriveHead = IDEReadDriveHead(ControllerExtension->CommandPortBase);
1701 SectorCount = IDEReadSectorCount(ControllerExtension->CommandPortBase);
1702 SectorNum = IDEReadSectorNum(ControllerExtension->CommandPortBase);
1703 // FIXME: should use the NT error logging facility
1704 DPRINT("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1705 DeviceExtension->Operation,
1706 ControllerExtension->DeviceStatus,
1707 ErrorReg,
1708 CylinderLow,
1709 CylinderHigh,
1710 SectorCount,
1711 SectorNum);
1712
1713 // FIXME: should retry the command and perhaps recalibrate the drive
1714
1715 // Set error status information
1716 AnErrorOccured = TRUE;
1717 ErrorStatus = STATUS_DISK_OPERATION_FAILED;
1718 ErrorInformation =
1719 (((((((CylinderHigh << 8) + CylinderLow) *
1720 DeviceExtension->LogicalHeads) +
1721 (DriveHead % DeviceExtension->LogicalHeads)) *
1722 DeviceExtension->SectorsPerLogTrk) + SectorNum - 1) -
1723 DeviceExtension->StartingSector) * DeviceExtension->BytesPerSector;
1724 }
1725 else
1726 {
1727
1728 // Check controller and setup for next transfer
1729 switch (DeviceExtension->Operation)
1730 {
1731 case IRP_MJ_READ:
1732
1733 // Update controller/device state variables
1734 TargetAddress = DeviceExtension->TargetAddress;
1735 DeviceExtension->TargetAddress += DeviceExtension->BytesPerSector;
1736 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1737 DeviceExtension->SectorsTransferred++;
1738
1739 // Remember whether DRQ should be low at end (last block read)
1740 IsLastBlock = DeviceExtension->BytesToTransfer == 0;
1741
1742 // Wait for DRQ assertion
1743 for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
1744 !(IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ);
1745 Retries++)
1746 {
1747 KeStallExecutionProcessor(10);
1748 }
1749
1750 // Copy the block of data
1751 IDEReadBlock(ControllerExtension->CommandPortBase,
1752 TargetAddress,
1753 IDE_SECTOR_BUF_SZ);
1754
1755 // check DRQ
1756 if (IsLastBlock)
1757 {
1758 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
1759 (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_BUSY);
1760 Retries++)
1761 {
1762 KeStallExecutionProcessor(10);
1763 }
1764
1765 // Check for data overrun
1766 if (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ)
1767 {
1768 AnErrorOccured = TRUE;
1769 ErrorStatus = STATUS_DATA_OVERRUN;
1770 ErrorInformation = 0;
1771 }
1772 else
1773 {
1774
1775 // Setup next transfer or set RequestIsComplete
1776 if (DeviceExtension->BytesRequested >
1777 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
1778 {
1779 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
1780 DeviceExtension->SectorsTransferred = 0;
1781 DeviceExtension->BytesToTransfer =
1782 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
1783 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1784 }
1785 else if (DeviceExtension->BytesRequested > 0)
1786 {
1787 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
1788 DeviceExtension->SectorsTransferred = 0;
1789 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
1790 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1791 }
1792 else
1793 {
1794 RequestIsComplete = TRUE;
1795 }
1796 }
1797 }
1798 break;
1799
1800 case IRP_MJ_WRITE:
1801
1802 // check DRQ
1803 if (DeviceExtension->BytesToTransfer == 0)
1804 {
1805 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
1806 (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_BUSY);
1807 Retries++)
1808 {
1809 KeStallExecutionProcessor(10);
1810 }
1811
1812 // Check for data overrun
1813 if (IDEReadStatus(ControllerExtension->CommandPortBase) & IDE_SR_DRQ)
1814 {
1815 AnErrorOccured = TRUE;
1816 ErrorStatus = STATUS_DATA_OVERRUN;
1817 ErrorInformation = 0;
1818 }
1819 else
1820 {
1821
1822 // Setup next transfer or set RequestIsComplete
1823 IsLastBlock = TRUE;
1824 if (DeviceExtension->BytesRequested >
1825 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
1826 {
1827 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
1828 DeviceExtension->SectorsTransferred = 0;
1829 DeviceExtension->BytesToTransfer =
1830 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
1831 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1832 }
1833 else if (DeviceExtension->BytesRequested > 0)
1834 {
1835 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
1836 DeviceExtension->SectorsTransferred = 0;
1837 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
1838 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
1839 }
1840 else
1841 {
1842 RequestIsComplete = TRUE;
1843 }
1844 }
1845 }
1846 else
1847 {
1848
1849 // Update controller/device state variables
1850 TargetAddress = DeviceExtension->TargetAddress;
1851 DeviceExtension->TargetAddress += DeviceExtension->BytesPerSector;
1852 DeviceExtension->BytesToTransfer -= DeviceExtension->BytesPerSector;
1853 DeviceExtension->SectorsTransferred++;
1854
1855 // Write block to controller
1856 IDEWriteBlock(ControllerExtension->CommandPortBase,
1857 TargetAddress,
1858 IDE_SECTOR_BUF_SZ);
1859 }
1860 break;
1861 }
1862 }
1863
1864 // If there was an error or the request is done, complete the packet
1865 if (AnErrorOccured || RequestIsComplete)
1866 {
1867 // Set the return status and info values
1868 Irp = ControllerExtension->CurrentIrp;
1869 Irp->IoStatus.Status = ErrorStatus;
1870 Irp->IoStatus.Information = ErrorInformation;
1871
1872 // Clear out controller fields
1873 ControllerExtension->OperationInProgress = FALSE;
1874 ControllerExtension->DeviceStatus = 0;
1875
1876 // Queue the Dpc to finish up
1877 IoRequestDpc(DeviceExtension->DeviceObject,
1878 Irp,
1879 ControllerExtension);
1880 }
1881 else if (IsLastBlock)
1882 {
1883 // Else more data is needed, setup next device I/O
1884 IDEStartController((PVOID)DeviceExtension);
1885 }
1886
1887 return TRUE;
1888 }
1889
1890 // IDEDpcForIsr
1891 // DESCRIPTION:
1892 //
1893 // RUN LEVEL:
1894 //
1895 // ARGUMENTS:
1896 // IN PKDPC Dpc
1897 // IN PDEVICE_OBJECT DpcDeviceObject
1898 // IN PIRP DpcIrp
1899 // IN PVOID DpcContext
1900 //
1901 static VOID
1902 IDEDpcForIsr(IN PKDPC Dpc,
1903 IN PDEVICE_OBJECT DpcDeviceObject,
1904 IN PIRP DpcIrp,
1905 IN PVOID DpcContext)
1906 {
1907 DPRINT("IDEDpcForIsr()\n");
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