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