|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: atdisk.c
8:
9: Abstract:
10:
11: This is the IBM AT disk (aka ST506) driver for NT.
12:
13: Author:
14:
15: Chad Schwitters (chads) 21-Feb-1991.
16:
17: Environment:
18:
19: Kernel mode only.
20:
21: Notes:
22:
23: The ST506 is the controller standard used on almost all ISA PCs
24: (Industry Standard Architecture, which use Intel x86 processors).
25: More advanced controllers, found on either ix86 or MIPS machines,
26: generally have at least an ST506-compatible mode.
27:
28: Things that this driver still needs to have done:
29:
30: Rework to allow for disks with more than 2^32 sectors.
31:
32: An I/O request passed in by the system is called a "request". This
33: driver often breaks the request into smaller pieces called "transfers"
34: to get around limitations and bugs in the controller.
35:
36: Each request is ordered by starting sector number when placed in the
37: device queue via IoStartPacket. When removed from the device queue
38: via IoStartNextPacket, the request at the next higher request is
39: started - or the lowest request, if there are none higher. This
40: implements a circular scan of the disk - requests sequentially
41: higher on the disk are serviced, until we come to the end and start
42: over again at the beginning of the disk. This functionality is
43: provided by the I/O system; all the driver has to do is pass in the
44: sector numbers. The advantage is greater throughput when the disk is
45: busy, since seek time is reduced. There are faster algorithms, but
46: they are not as inherently fair as C-SCAN. (Note that this driver
47: doesn't attempt to work by cylinder numbers; although seek times might
48: be further reduced, complexity goes up, it might be wrong if the drive
49: does physical translation, and the possibility of starvation is
50: introduced).
51:
52: Background on ST506 operation:
53:
54: The controller can be reset by
55:
56: o - writing 4 to the drive control register. This resets the
57: controller.
58: o - waiting at least 10us
59: o - writing 0 to the drive control register. This reenables
60: the controller and reenables interrupts.
61: o - issuing a SET PARAMETERS command for each drive attached
62: to the controller.
63:
64: Note that the SET PARAMETERS commands each cause an interrupt,
65: but the actual reset does not. The disk parameters to use in the
66: SET PARAMETERS command should be supplied by configuration
67: management.
68:
69: Commands are issued by writing parameters to relevant registers,
70: and then writing the command to the COMMAND register. At that
71: point, the controller generally sets the BUSY bit in its STATUS
72: register. While this bit is set, the driver can't read or write
73: any of the registers. Other STATUS register bits are undefined.
74: An exception is the WRITE command, which sets DRQ and expects
75: the cache to be filled.
76:
77: Many controllers are capable of operating in AT PIO, block, and
78: EISA "B" slave DMA data transfer modes. However, older
79: controllers don't have block mode and many target machines are
80: not EISA, so we will only consider AT PIO mode. We would use
81: block mode where available, but some controllers with block mode
82: have fatal bugs. We will implement block mode in this driver
83: once controller manufacturers notify us of a method for
84: determining which controllers can *correctly* do block mode.
85: BUGBUG FUTURE Note that the driver includes the variable
86: BytesPerInterrupt to help make this work; however, simply
87: multiplying the sectors per interrupt by the bytes per sector
88: and putting the value in BytesPerInterrupt will not work. This
89: driver does not take care of the case where the last interrupt
90: moves less than a full block.
91:
92: In AT PIO mode, bus transfers are performed by 16-bit I/O space
93: instructions. An interrupt is generated for each sector (512
94: bytes, or 256 words) that is transferred.
95:
96: When a READ is performed, the controller seeks to the correct
97: track (the seek is implicit, but can also be done explicitly),
98: reads the sector into an internal cache, sets the DRQ bit and
99: interrupts the host. As soon as the host transfers 256 words
100: from the cache (i.e. no action is necessary other than reading
101: the cache), the controller reads the next sector in the same
102: fashion as long as there is another sector to be read. If a
103: non-recoverable error occurs, the sector number register will
104: indicate which sector was at fault, and the sector count
105: register will indicate how many sectors weren't transferred.
106:
107: The WRITE command is the same, except DRQ is set after the
108: command is issued with no interrupt. This could take up 10 ms
109: if, for example, the disk has power saving features. The host
110: should fill the buffer, at which time it is immediately written,
111: and the interrupt occurs when the write is done.
112:
113: The controller registers are as follows:
114:
115: Register name ISA 1st ISA 2nd Access
116: address address
117:
118: DATA 0x1F0 0x170 read/write
119: ERROR 0x1F1 0x171 read only
120: WRITE PRECOMPENSATION 0x1F1 0x171 write only
121: SECTOR COUNT 0x1F2 0x172 read/write
122: SECTOR NUMBER 0x1F3 0x173 read/write
123: CYLINDER LOW 0x1F4 0x174 read/write
124: CYLINDER HIGH 0x1F5 0x175 read/write
125: DRIVE SELECT & HEAD 0x1F6 0x176 read/write
126: STATUS 0x1F7 0x177 read only
127: COMMAND 0x1F7 0x177 write only
128: DRIVE CONTROL 0x3f6 0x376 read/write
129:
130: The DATA register is the only 16-bit register of the bunch. It
131: is a window to the sector cache on the controller. Just write
132: 256 words to this port, and the cache will be filled. The
133: controller can tell when 256 words have been transferred.
134:
135: The bits of the ERROR register are defined as follows:
136:
137: 0 - data address mark not found after finding ID field
138: 1 - track 0 not found during RECALIBRATE command
139: 2 - command aborted; command invalid or drive status invalid
140: 3 - reserved, 0
141: 4 - requested sector ID field not found
142: 5 - reserved, 0
143: 6 - unrecoverable CRC data error
144: 7 - a bad-block mark was found in the requested sector ID field
145:
146: These bits are defined only when the error bit is set in the
147: STATUS register.
148:
149: The WRITE PRECOMPENSATION register specifies at which cylinder
150: to start bit recording timeshifts to compensate for an inherent
151: magnetic recording shift. The value in the register is actually
152: multiplied by 4 to determine which cylinder is the first to get
153: precompensation. A value of -1 (all bits set) indicates that
154: the drive does not use write precompensation.
155:
156: The SECTOR COUNT register usually indicates how many sectors are
157: to be read or written. It is the number of sectors per track
158: for the SET PARAMETERS and FORMAT commands. A value of 0
159: indicates 256, which is the maximum value.
160:
161: The SECTOR NUMBER register is programmed with the starting
162: sector for the command and is automatically updated by the
163: controller as sectors are transferred in a multi-sector
164: operation.
165:
166: The CYLINDER LOW register holds the 8 least significant bits of
167: the cylinder number.
168:
169: The CYLINDER HIGH register holds the 3 most significant bits of
170: the cylinder number in its low-order 3 bits. The high-order
171: bits are reserved.
172:
173: The DRIVE SELECT & HEAD register selects a drive, head, and sector
174: size. The bits are as follows:
175:
176: 0 - 3: choose head 0 through 15
177: 4: 0 = drive 1, 1 = drive 2
178: 5 - 6: always 01, which indicates 512 bytes/sector
179: 7: reserved, always 1
180:
181: Note that early controllers allowed 4 drives but only 8 heads;
182: ISA machines all allow this 2 drive/16 head alternate. Early
183: controllers also allowed a choice of 128-byte, 256-byte, 512-
184: byte or 1024-byte sectors, but ISA seems to allow only 512.
185:
186: The bits of the STATUS register are defined as follows:
187:
188: 0 - error (see ERROR register). Next command resets this bit
189: 1 - index - set to 1 each time the disk completes a rotation
190: 2 - data was corrected
191: 3 - data request (DRQ) - sector cache requires service
192: 4 - seek complete
193: 5 - write fault
194: 6 - drive ready
195: 7 - busy (all other bits unreliable; do not issue commands)
196:
197: This register should be read from an ISR to clear the interrupt
198: at the controller. Note that an alternate STATUS register,
199: which is the same but doesn't stop interrupts, is at 0x3f6.
200:
201: The following are common command values:
202:
203: SET DRIVE PARAMETERS 0x91
204: SEEK 0x70
205: RECALIBRATE 0x10
206: READ SECTOR 0x20
207: (0x21 without automatic retries)
208: WRITE SECTOR 0x30
209: (0x31 without automatic retries)
210: FORMAT TRACK 0x50
211: READ VERIFY 0x40
212: EXECUTE DIAGNOSTICS 0x90
213:
214: Many controllers define additional commands; a driver could try
215: them and then check bit 2 in the ERROR register to see if the
216: controller supports a particular command.
217:
218: SET DRIVE PARAMETERS should be issued after every controller
219: reset. The DRIVE SELECT & HEAD register should have a drive
220: selected and it should contain the maximum head number. The
221: SECTOR COUNT register should hold the number of sectors per
222: track. An interrupt is generated when the command is complete.
223:
224: SEEK is not necessary since seeks are implicit in the READ and
225: WRITE commands, but a driver can issue explicit SEEKs and then
226: operate on the other drive (since the busy bit in the STATUS
227: register is only set for the first ~35us to ~135us of the SEEK
228: command). Set the cylinder number in the CYLINDER HIGH and LOW
229: registers, and select the proper drive and head in the DRIVE
230: SELECT & HEAD register. An interrupt will be generated when an
231: explicit SEEK finishes.
232:
233: RECALIBRATE moves the heads to cylinder 0. The proper drive must
234: be selected in the DRIVE SELECT & HEAD register. An interrupt
235: is generated when the command is complete.
236:
237: READ SECTOR reads the number of sectors specified in the SECTOR
238: COUNT register, starting with the one specified by the DRIVE
239: SELECT & HEAD, CYLINDER HIGH & LOW, and SECTOR NUMBER registers.
240: An interrupt is generated for each sector read.
241:
242: WRITE SECTOR writes the number of sectors specified in the
243: SECTOR COUNT register, starting with the one specified by the
244: DRIVE SELECT & HEAD, CYLINDER HIGH & LOW, and SECTOR NUMBER
245: registers. An interrupt is generated for each sector written.
246: The WRITE PRECOMPENSATION register should be set to the proper
247: cylinder (div 4) for the disk before issuing this command.
248:
249: Rules on using objects and their variables:
250:
251: Since we expect this driver to run on a symmetric
252: multiprocessing system, we must ensure that there are no data
253: contention problems. Data can be associated with four things:
254: an IRP, a partition, a device, and a controller. IRP variables
255: are only modified when a request is made and completed (that is,
256: before and after I/O, not during). Since the IRPs aren't driver
257: specific we don't have to worry about contention. Partition
258: variables are really constants (they are set up during init and
259: never changed) so they can be read at any time. Device and
260: controller variables are of both kinds, constants and variable.
261: The constant values can, of course, be read at any time. So all
262: we have to worry about are the device and controller "real"
263: variables. Access to device variables is restricted by the
264: device queues, and access to controller variables (and
265: hardware!) is restricted by ownership of the controller object;
266: control flow is serial so multiple instances of a routine is not
267: a concern.
268:
269: A few variables are of special concern because they are modified
270: by AtDiskInterruptService() and/or AtCheckTimerSync(). For
271: example InterruptRequiresDpc, InterruptTimer, and
272: ResettingController. In general, these variables are only
273: modified by routines that have been called via
274: KeSynchronizeExecution(). There are some exceptions during
275: driver initialization and in AtDiskDeferredProcedure(), but
276: they are well documented (in short, they are safe because we are
277: sure that AtDiskInterruptService() and AtCheckTimerSync()
278: aren't going to run while we're modifying the variables).
279:
280: The device extension is the most-used object - it has variables
281: to track the I/O progressions. Each disk has a device extension
282: attached to the device object for partition 0.
283:
284: Variables in the device extension:
285:
286: CurrentAddress is a system-space pointer to where we're
287: currently at in the user's buffer. It is initially passed
288: in via the MDL, and updated after every copy to/from the
289: controller cache.
290:
291: FirstSectorOfRequest is the sector at which the current request
292: started. It is calculated the first time AtDiskStartIo() is
293: called for a request. When a request is completed, it is set
294: to MAXULONG so that we know to set it again for the next request.
295: The value is passed in to IoStartNextPacketByKey(), so that
296: the next packet in C-SCAN order will be processed.
297:
298: FirstSectorOfTransfer is the sector at which the current
299: transfer started. It is initially calculated in
300: AtDiskStartIo(), and updated in AtDiskDeferred() just
301: before calling AtStartDevice() when the controller needs to
302: be reprogrammed.
303:
304: RemainingRequestLength is the amount of this request that
305: still needs to be moved. It starts as the length requested
306: by the user and, after each interrupt, is decremented by the
307: number of bytes transferred for that interrupt.
308:
309: TotalTransferLength is the length of the current transfer
310: (which might only be a piece of the current request; it is
311: limited to MAX_SEC_TO_TRANS sectors). It is calculated as
312: RemainingRequestLength modulo hardware limitations initially
313: in AtDiskStartIo(), and again in AtDiskDeferred() before
314: calling AtStartDevice() to start a secondary transfer.
315:
316: RemainingTransferLength is the amount of the current
317: transfer that will remain after the current interrupt. It
318: starts as TotalTransferLength and, after each interrupt, is
319: decremented by the number of bytes transferred for that
320: interrupt.
321:
322: IrpRetryCount is initialized to 0 every time an IRP first
323: gets to AtDiskStartIo(). If the hardware gets reset and the
324: packet is restarted via AtDiskStartIo(), PacketIsBeingRetried
325: will be set to TRUE. AtDiskStartIo() will see this and
326: increment IrpRetryCount. AtDiskDeferredProcedure() checks
327: IrpRetryCount before restarting the packet, and returns the
328: packet with error if it has reached RETRY_IRP_MAXIMUM_COUNT.
329:
330: SequenceNumber is a value that is incremented each time
331: a new irp passes through start io. This is so that if we
332: need to log an error, we can uniquely identify a particular
333: irp.
334:
335: All other partitions have a partition extension attached to
336: their device object. The partition extension contains only the
337: information necessary to access and use the proper device
338: extension. The beginning of the device extension looks like the
339: beginning of a partition extension, so that the mainline code to
340: access the device extension will work whether the original
341: request was based on partition 0 or some other partition.
342:
343: The controller object has an attached controller extension.
344: Controller extensions contain variables that are specific to the
345: controller, rather than to the attached disks.
346:
347: The driver does not release the controller object until the
348: controller is finished with an operation. This means that when
349: the controller object is acquired, the controller can be
350: programmed immediately.
351:
352: The controller extension points to the device extensions (those
353: associated with partition 0) of the disks that are attached to
354: the controller. If two drives are successfully initialized, the
355: second one (DRIVE_2 to the controller) is pointed at by Disk2 -
356: this is the only time that Disk2 is not NULL. Disk1 always
357: points at the first device successfully initialized, whether
358: that be DRIVE_1 or DRIVE_2 to the controller.
359:
360: Variables in the controller extension:
361:
362: Whenever the code is about to do something that will cause
363: an interrupt, it starts the timer (via set InterruptTimer =
364: START_TIMER). This is always cancelled by
365: AtDiskInterruptService(). Note that "starting" the timer
366: simply means setting it to 2 (it's called once every second;
367: but the interval until the end of the current second is
368: unknown so 2 seconds is the minimum waiting time).
369: "Cancelling" the timer simply means to set it to -1 so that
370: the timer routine ignores it. The timer routine will
371: decrement the counter only if it is nonnegative, and if the
372: counter ever reaches zero the timer routine will log an
373: error, reset the controller, and restart the IRP.
374:
375: Whenever AtDiskInterruptService() should dispatch a DPC,
376: InterruptRequiresDpc should be set to TRUE at the same time
377: that InterruptTimer is started. This will be set to FALSE
378: by AtDiskInterruptService().
379:
380: WhichDeviceObject should be set to the device object of the
381: disk that is expecting an interrupt whenever InterruptTimer
382: is started.
383:
384: ResettingController is normally RESET_NOT_RESETTING. When
385: AtCheckTimerSync() determines that the timer has expired, it
386: sets ResettingController to RESET_FIRST_DRIVE_SET. It then
387: resets the controller and sets the drive parameters for the
388: drive that timed out. AtDiskDeferredProcedure() will notice
389: the state of ResettingController and take the appropriate
390: action. First, it logs an error; then it recalibrates the
391: failing drive, changing the state to
392: RESET_FIRST_DRIVE_RECALIBRATED. If there is only one drive
393: it will then restart the IRP, set ResettingController to
394: RESET_NOT_RESETTING and free the controller object. If
395: there are two drives, it will set ResettingController to
396: RESET_SECOND_DRIVE_SET and then set the drive parameters of
397: the second drive. When AtDiskDeferredProcedure() sees
398: ResettingController in this state, it will restart the IRP
399: that timed out, set ResettingController to
400: RESET_NOT_RESETTING, and free the controller object. Note
401: that the second drive was not recalibrated; we only need to
402: do this for the failing drive.
403:
404: Hardware quirks:
405:
406: The controller's IDENTIFY command does not always return the
407: correct number of sectors. The number observed was 1 too high
408: on a Compaq Deskpro 386/16.
409:
410: Early controllers allowed sector sizes of 128, 256, 512 or 1024
411: to be set by bits in the DRIVE SELECT & HEAD register. However,
412: more recent controllers insist that you set the bits to specify
413: 512 bytes. My driver is written to allow different values, but
414: it looks like they will never be used. I think I'll leave the
415: driver as it is; the speed gain from switching to a constant
416: would be incredibly tiny, and there's always the chance that
417: this driver will be used to drive Japanese machines that have
418: 1024k sectors (and obviously do NOT have the newer controllers).
419:
420: A few early controllers had a bug where if one drive had more
421: than 8 heads and the other drive had less than 8 heads, then the
422: controller would forget the number of heads on one drive when
423: the other drive was selected. Since these controllers were
424: fixed before any 386 machines were made, and even then they had
425: to have the proper combination of drives on them, this driver
426: does not include a workaround for the problem. The workaround
427: is to write a "0" to CONTROL_PORT before every I/O to a drive
428: with less than 8 heads, and to write "8" before every I/O to a
429: drive with 8 or more heads.
430:
431: Some machines need to have bit 3 set in CONTROL_PORT if they're
432: going to be used with disks with more than 8 heads. Unlike the
433: bug mentioned above, however, this only needs to be done when the
434: drive parameters are set, rather than at every I/O. Whether or
435: not this bit needs to be set has already been determined; this
436: driver reads a byte from the RAM table that describes the disk
437: parameters and uses that value ("ControlFlags") when writing to
438: CONTROL_PORT.
439:
440: A few early controllers had a bug where multi-sector transfers
441: across a 256*N cylinder boundary didn't work. Again, however,
442: we do not expect to find these controllers on systems that run
443: NT, so we will not include a workaround. The proper
444: workaround would be to make sure that all transfers end on or
445: before any 256*N cylinder boundaries.
446:
447: Controllers are supposed to decrement the sector count register
448: as they transfer data, so by the end of a successful transfer
449: the sector count register should always be 0. However, there
450: are some controllers that sometimes have the original value in
451: the sector count register when finished. This driver doesn't
452: query the sector count register in the normal case, so this is
453: of no consequence. However, when there is an error this driver
454: MUST query the sector count register, since controller buffering
455: makes it impossible to know how many sectors were successfully
456: moved. If the error occurs in that case, it's not a big deal -
457: the driver will just report that 0 of X sectors were moved,
458: rather than X-N of X. The file system will use the same
459: recovery method for either case.
460:
461: When a disk goes flaky and doesn't interrupt, on some
462: controllers you can't trust the DRIVE SELECT & HEAD register to
463: say which drive was last selected. The driver needs to keep
464: track of this information itself.
465:
466: Most controllers do things like assert DRQ for a WRITE or get
467: prepared after a SET DRIVE PARAMETERS pretty quickly - less than
468: 10us. However, a few older controllers seem to be MUCH slower.
469: This driver will wait a long time in places - longer than the
470: 50us generally given as an upper limit on driver stalling times
471: - however, it only waits a long time IF necessary, and then it's
472: generally only at initialization time, or during an error path.
473:
474: Using SETUP to set the IRQ on a Compaq secondary controller has
475: no effect on the IRQ register until after a powercycle - the
476: register isn't updated, so this driver will fail to access the
477: disks on the modified controller until the machine is
478: powercycled.
479:
480: Revision History:
481:
482:
483: 12-18-92 - Tonye - Changed controller initialization so that
484: the device is first reset (and consequently
485: interrupts are certain to be disabled), then
486: initialize the disk devices, only enabling
487: interrupts on the controller when we are about
488: to touch the first disk on the controller.
489:
490: Also changed the isr to return if there isn't
491: a valid WhichDeviceObject.
492:
493:
494: 12-30-93 - Tonye - Well the above seemed to work pretty well except that
495: some ide drives seemed to refuse to initially reset.
496: Fall back to the original initialization sequence,
497: and just let the isr return if there isn't a
498: valid WhichDeviceObject.
499:
500: --*/
501:
502:
503: //
504: // Include files.
505: //
506:
507: #include "ntddk.h" // various NT definitions
508: #include "ntdddisk.h" // disk device driver I/O control codes
509: #include <atd_plat.h> // this driver's platform dependent stuff
510: #include <atd_data.h> // this driver's data declarations
511:
512: #if DBG
513: extern ULONG AtDebugLevel = 0;
514: #endif
515: #ifdef ALLOC_PRAGMA
516: #pragma alloc_text(init,DriverEntry)
517: #pragma alloc_text(init,AtInitializeController)
518: #pragma alloc_text(init,AtInitializeDisk)
519: #pragma alloc_text(init,AtGetTranslatedMemory)
520: #pragma alloc_text(init,AtReportUsage)
521: #pragma alloc_text(init,AtDiskControllerInfo)
522: #endif
523:
524: NTSTATUS
525: AtGetConfigInfo(
526: IN PDRIVER_OBJECT DriverObject,
527: IN PUNICODE_STRING RegistryPath,
528: IN OUT PCONFIG_DATA ConfigData
529: );
530:
531: BOOLEAN
532: IssueIdentify(
533: PCONTROLLER_DATA ControllerData,
534: PUCHAR Buffer,
535: ULONG DiskNumber
536: );
537:
538: NTSTATUS
539: AtCreateNumericKey(
540: IN HANDLE Root,
541: IN ULONG Name,
542: IN PWSTR Prefix,
543: OUT PHANDLE NewKey
544: );
545:
546: #define MAX_SEC_TO_TRANS (128)
547:
548:
549: NTSTATUS
550: DriverEntry(
551: IN OUT PDRIVER_OBJECT DriverObject,
552: IN PUNICODE_STRING RegistryPath
553: )
554:
555: /*++
556:
557: Routine Description:
558:
559: This routine is the driver's entry point, called at initialization
560: time by the I/O system. This routine can be called any number of
561: times, as long as the IO system and the configuration manager
562: conspire to give it a different controller to support at each call.
563: It could also be called a single time and given all of the
564: controllers at once.
565:
566: It initializes the passed-in driver object, calls the configuration
567: manager to learn about the devices that it is to support, and for
568: each controller to be supported it calls a routine to initialize the
569: controller (and all disks attached to it).
570:
571: Arguments:
572:
573: DriverObject - a pointer to the object that represents this device
574: driver.
575:
576: Return Value:
577:
578: If we successfully initialize at least one disk, STATUS_SUCCESS is
579: returned.
580:
581: If we don't (because the configuration manager returns an error, or
582: the configuration manager says that there are no controllers or
583: drives to support, or no controllers or drives can be successfully
584: initialized), then the last error encountered is propogated.
585:
586: --*/
587:
588: {
589: PCONFIG_DATA configData; // pointer to config mgr's returned data
590: NTSTATUS ntStatus;
591: CCHAR i; // controller init loop index
592: BOOLEAN partlySuccessful; // TRUE when any controller init'd successfully
593:
594: //
595: // We use this to query into the registry as to whether we
596: // should break at driver entry.
597: //
598: RTL_QUERY_REGISTRY_TABLE paramTable[3];
599: ULONG zero = 0;
600: ULONG debugLevel = 0;
601: ULONG shouldBreak = 0;
602: PWCHAR path;
603:
604: //
605: // Since the registry path parameter is a "counted" UNICODE string, it
606: // might not be zero terminated. For a very short time allocate memory
607: // to hold the registry path zero terminated so that we can use it to
608: // delve into the registry.
609: //
610: // NOTE NOTE!!!! This is not an architected way of breaking into
611: // a driver. It happens to work for this driver because the author
612: // likes to do things this way.
613: //
614:
615: if (path = ExAllocatePool(
616: PagedPool,
617: RegistryPath->Length+sizeof(WCHAR)
618: )) {
619:
620: RtlZeroMemory(
621: ¶mTable[0],
622: sizeof(paramTable)
623: );
624: RtlZeroMemory(
625: path,
626: RegistryPath->Length+sizeof(WCHAR)
627: );
628: RtlMoveMemory(
629: path,
630: RegistryPath->Buffer,
631: RegistryPath->Length
632: );
633: paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
634: paramTable[0].Name = L"BreakOnEntry";
635: paramTable[0].EntryContext = &shouldBreak;
636: paramTable[0].DefaultType = REG_DWORD;
637: paramTable[0].DefaultData = &zero;
638: paramTable[0].DefaultLength = sizeof(ULONG);
639: paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
640: paramTable[1].Name = L"DebugLevel";
641: paramTable[1].EntryContext = &debugLevel;
642: paramTable[1].DefaultType = REG_DWORD;
643: paramTable[1].DefaultData = &zero;
644: paramTable[1].DefaultLength = sizeof(ULONG);
645:
646: if (!NT_SUCCESS(RtlQueryRegistryValues(
647: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
648: path,
649: ¶mTable[0],
650: NULL,
651: NULL
652: ))) {
653:
654: shouldBreak = 0;
655: debugLevel = 0;
656:
657: }
658:
659: }
660:
661: //
662: // We don't need that path anymore.
663: //
664:
665: if (path) {
666:
667: ExFreePool(path);
668:
669: }
670:
671: #if DBG
672: AtDebugLevel = debugLevel;
673: #endif
674:
675: if (shouldBreak) {
676:
677: DbgBreakPoint();
678:
679: }
680:
681: //
682: // Allocate and zero the data structure used during initialization.
683: //
684:
685: configData = ExAllocatePool( PagedPool, sizeof ( CONFIG_DATA ) );
686:
687: if ( configData == NULL ) {
688:
689: AtDump(
690: ATERRORS,
691: ("ATDISK: Can't allocate memory for config data\n")
692: );
693: return STATUS_INSUFFICIENT_RESOURCES;
694: }
695:
696: RtlZeroMemory( configData, sizeof( CONFIG_DATA ) );
697:
698: //
699: // Get information on the hardware that we're supposed to support.
700: //
701:
702: ntStatus = AtGetConfigInfo( DriverObject, RegistryPath, configData );
703:
704: //
705: // If AtGetConfigInfo() failed, just exit and propogate the error.
706: // If it said that there are no controllers to support, return
707: // STATUS_NO_SUCH_DEVICE.
708: // Otherwise, try to init the controllers. If at least one succeeds,
709: // return STATUS_SUCCESS, otherwise return the last error.
710: //
711:
712: if ( NT_SUCCESS( ntStatus ) ) {
713:
714: //
715: // Initialize the driver object with this driver's entry points.
716: //
717:
718: DriverObject->DriverStartIo = AtDiskStartIo;
719: // DriverObject->DriverUnload = AtDiskUnloadDriver;
720: DriverObject->MajorFunction[IRP_MJ_CREATE] = AtDiskDispatchCreateClose;
721: DriverObject->MajorFunction[IRP_MJ_CLOSE] = AtDiskDispatchCreateClose;
722: DriverObject->MajorFunction[IRP_MJ_READ] = AtDiskDispatchReadWrite;
723: DriverObject->MajorFunction[IRP_MJ_WRITE] = AtDiskDispatchReadWrite;
724: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
725: AtDiskDispatchDeviceControl;
726:
727: //
728: // Call AtInitializeController() for each controller (and its
729: // attached disks) that we're supposed to support.
730: //
731: // Return success if we successfully initialize at least one
732: // device; return error otherwise.
733: //
734:
735: ntStatus = STATUS_NO_SUCH_DEVICE;
736: partlySuccessful = FALSE;
737:
738: for ( i = 0;
739: i < MAXIMUM_NUMBER_OF_CONTROLLERS;
740: i++ ) {
741:
742: if (configData->Controller[i].OkToUseThisController) {
743:
744: //
745: // If the usage reporting doesn't report
746: // a conflict then try to initialize the
747: // controller.
748: //
749:
750: if (AtReportUsage(
751: configData,
752: (UCHAR)i,
753: DriverObject)) {
754:
755: ntStatus = AtInitializeController(
756: configData,
757: i,
758: DriverObject );
759:
760: } else {
761:
762: ntStatus = STATUS_INSUFFICIENT_RESOURCES;
763:
764: }
765:
766: if ( NT_SUCCESS( ntStatus ) ) {
767:
768: partlySuccessful = TRUE;
769: }
770: }
771: }
772:
773: if ( partlySuccessful ) {
774:
775: ntStatus = STATUS_SUCCESS;
776: }
777: }
778:
779: //
780: // Delete the data structure we used during initialization.
781: //
782:
783: ExFreePool( configData );
784:
785: return ntStatus;
786: }
787:
788: NTSTATUS
789: AtInitializeController(
790: IN PCONFIG_DATA ConfigData,
791: IN CCHAR ControllerNumber,
792: IN PDRIVER_OBJECT DriverObject
793: )
794:
795: /*++
796:
797: Routine Description:
798:
799: This routine is called at initialization time by
800: AtDiskInitialize() - once for each controller that the
801: configuration manager tells it we have to support.
802:
803: When this routine is called, the configuration data has already been
804: filled in.
805:
806: It creates a controller object complete with extension, calls
807: allocates an interrupt object, resets the controller, and calls
808: AtInitializeDisk() for each disk attached to the controller.
809:
810: Arguments:
811:
812: ConfigData - a pointer to the structure that describes the
813: controller and the disks attached to it, as given to us by the
814: configuration manager.
815:
816: ControllerNumber - which controller in ConfigData we are
817: initializing.
818:
819: DriverObject - a pointer to the object that represents this device
820: driver.
821:
822: Return Value:
823:
824: STATUS_SUCCESS if this controller and at least one of its disks were
825: initialized; an error otherwise.
826:
827: --*/
828:
829: {
830: PCONTROLLER_OBJECT controllerObject;
831: PCONTROLLER_EXTENSION controllerExtension;
832: NTSTATUS ntStatus;
833: CCHAR i; // which disk on this controller
834: BOOLEAN partlySuccessful; // TRUE when any disk init'd
835: USHORT MaximumBytesPerInterrupt;
836:
837: //
838: // Go through all of the disk configuration data for this
839: // controller. Find out the maximum value over all of
840: // the disks for bytes per interrupt. This will
841: // be used as the size of the read/write garbage can
842: // that is used to empty/fill the controller cache
843: // when an error occurs.
844: //
845:
846: for (
847: MaximumBytesPerInterrupt=0,i = 0;
848: i < MAXIMUM_NUMBER_OF_DISKS_PER_CONTROLLER;
849: i++
850: ) {
851:
852: if (ConfigData->Controller[ControllerNumber].Disk[i].BytesPerInterrupt
853: > MaximumBytesPerInterrupt) {
854:
855: MaximumBytesPerInterrupt = ConfigData->Controller[ControllerNumber].
856: Disk[i].
857: BytesPerInterrupt;
858:
859: }
860: }
861:
862: ASSERT(MaximumBytesPerInterrupt);
863:
864: //
865: // Create the controller object and extension. Make sure they point
866: // to each other.
867: //
868:
869: controllerObject = IoCreateController( sizeof( CONTROLLER_EXTENSION )+
870: (MaximumBytesPerInterrupt-1));
871:
872: if ( controllerObject == NULL ) {
873:
874: AtDump(
875: ATERRORS,
876: ("ATDISK: Couldn't create the controller object.\n")
877: );
878: return STATUS_INSUFFICIENT_RESOURCES;
879: }
880:
881: controllerExtension =
882: ( PCONTROLLER_EXTENSION )( controllerObject->ControllerExtension );
883:
884: //
885: // Make sure that the extension is clean.
886: //
887:
888: RtlZeroMemory(
889: controllerExtension,
890: sizeof(CONTROLLER_EXTENSION)
891: );
892:
893: controllerExtension->ControllerObject = controllerObject;
894:
895: controllerExtension->ControllerAddress =
896: ConfigData->Controller[ControllerNumber].ControllerBaseAddress;
897:
898: controllerExtension->ControlPortAddress =
899: ConfigData->Controller[ControllerNumber].ControlPortAddress;
900:
901: //
902: // Reset the controller here. We don't re-initialize interrupts YET.
903: // We don't want to enable interrupts yet, because we have no device objects
904: // for them. We'll enable the interrupts the first time we talk
905: // to first disk during disk initialization a little later. We are
906: // connecting to the interrupt because the disk device initialization code
907: // depends on reading the disk. So, we will delay the enable until
908: // we are totally ready with the disk device object.
909: //
910: // NOTE: We still aren't safe! Suppose we happen to be sharing this
911: // interrupt with another device. As soon as we connect, we could end
912: // up seeing an interrupt meant for another device, but, we won't
913: // be at all ready for it. We will have the interrupt service routine
914: // make sure that the controller is filled in. If it isn't, the
915: // ISR will assume that this interrupt is for another device.
916: //
917: // NOTE: Some specs say that the before accessing the controller
918: // after a reset we should wait 10us. Make sure we get that done
919: // here.
920: //
921: // NOTE: Some old ix86 machines need bit 3 set in CONTROL_PORT
922: // to access heads 8-15. The flag was read from CMOS; we'll grab it
923: // here and use it while writing to CONTROL_PORT.
924: //
925: // Sounds like a good plan right? Well it turns out not to work.
926: // Some IDE drives simply refuse to initialize if we do it this way.
927: // We will simply initialize the way we did before, and let the
928: // ISR return immediately if there isn't a valid WhichDevice.
929: //
930:
931: controllerExtension->ControlFlags =
932: ConfigData->Controller[ControllerNumber].ControlFlags;
933:
934: //
935: // Allocate and connect interrupt objects for this device to all of the
936: // processors on which this device can interrupt.
937: //
938:
939: if ( !( NT_SUCCESS( ntStatus = IoConnectInterrupt(
940: &controllerExtension->InterruptObject,
941: AtDiskInterruptService,
942: controllerExtension,
943: NULL,
944: ConfigData->Controller[ControllerNumber].ControllerVector,
945: ConfigData->Controller[ControllerNumber].ControllerIrql,
946: ConfigData->Controller[ControllerNumber].ControllerIrql,
947: ConfigData->Controller[ControllerNumber].InterruptMode,
948: ConfigData->Controller[ControllerNumber].SharableVector,
949: ConfigData->Controller[ControllerNumber].ProcessorNumber,
950: ConfigData->Controller[ControllerNumber].SaveFloatState
951: ) ) ) ) {
952:
953: AtDump(
954: ATERRORS,
955: ("ATDISK: Couldn't connect to the interrupt\n")
956: );
957: goto AtInitializeControllerExit;
958: }
959:
960: //
961: // It doesn't matter whether we have any devices yet. The interrupt
962: // service routine will simply dismiss any iterrupts until it's ready.
963: //
964: // Well wait up to 2 seconds for the controller to accept the reset.
965: //
966:
967: WRITE_CONTROLLER(
968: controllerExtension->ControlPortAddress,
969: RESET_CONTROLLER );
970:
971: AtWaitControllerBusy(
972: controllerExtension->ControllerAddress + STATUS_REGISTER,
973: 20,
974: 75000
975: );
976:
977: WRITE_CONTROLLER(
978: controllerExtension->ControlPortAddress,
979: ( ENABLE_INTERRUPTS | controllerExtension->ControlFlags ) );
980:
981: //
982: // For every disk on the controller, call AtInitializeDisk(). Note
983: // that because of ISA restrictions, there are a maximum of two.
984: //
985:
986: partlySuccessful = FALSE;
987: ntStatus = STATUS_NO_SUCH_DEVICE;
988: for ( i = 0;
989: i < MAXIMUM_NUMBER_OF_DISKS_PER_CONTROLLER;
990: i++ ) {
991:
992: if ( ConfigData->Controller[ControllerNumber].Disk[i].DriveType != 0 ) {
993:
994: ntStatus = AtInitializeDisk(
995: ConfigData,
996: ControllerNumber,
997: i,
998: DriverObject,
999: controllerExtension );
1000:
1001: if ( NT_SUCCESS( ntStatus ) ) {
1002:
1003: ( *( ConfigData->HardDiskCount ) )++;
1004: partlySuccessful = TRUE;
1005:
1006: }
1007:
1008: }
1009: } // FOR i = 0-> call AtInitializeDisk()
1010:
1011: if ( partlySuccessful ) {
1012:
1013: ntStatus = STATUS_SUCCESS;
1014:
1015: }
1016:
1017: AtInitializeControllerExit:
1018:
1019: if ( !NT_SUCCESS( ntStatus ) ) {
1020:
1021: //
1022: // Delete everything allocated by this routine. We know that the
1023: // controller object exists, or we would have already returned.
1024: //
1025:
1026: if ( controllerExtension->InterruptObject != NULL ) {
1027:
1028: IoDisconnectInterrupt( controllerExtension->InterruptObject );
1029: }
1030:
1031: IoDeleteController( controllerObject );
1032: }
1033:
1034: return ntStatus;
1035: }
1036:
1037: NTSTATUS
1038: AtInitializeDisk(
1039: IN PCONFIG_DATA ConfigData,
1040: IN CCHAR ControllerNum,
1041: IN CCHAR DiskNum,
1042: IN PDRIVER_OBJECT DriverObject,
1043: IN OUT PCONTROLLER_EXTENSION ControllerExtension
1044: )
1045:
1046: /*++
1047:
1048: Routine Description:
1049:
1050: This routine is called at initialization time by
1051: AtInitializeController(), once for each disk that we are supporting
1052: on the controller.
1053:
1054: When called, the controller has already been reset and interrupts are
1055: enabled.
1056:
1057: It creates a directory for the device objects, allocates and
1058: initializes a device object for the disk, sets the drive parameters,
1059: reads the partition table, and allocates partition objects (which
1060: are also device objects, but with a different extension) for each
1061: partition.
1062:
1063: Arguments:
1064:
1065: ConfigData - a pointer to the structure that describes the
1066: controller and the disks attached to it, as given to us by the
1067: configuration manager.
1068:
1069: ControllerNum - which controller in ConfigData we're working on.
1070:
1071: DiskNum - which disk on the current controller we're working on.
1072:
1073: DriverObject - a pointer to the object that represents this device
1074: driver.
1075:
1076: ControllerExtension - a pointer to the space allocated by this driver
1077: that is associated with the controller object.
1078:
1079: Return Value:
1080:
1081: STATUS_SUCCESS if this disk is initialized; an error otherwise.
1082:
1083: --*/
1084:
1085: {
1086: UCHAR ntNameBuffer[256];
1087: UCHAR arcNameBuffer[256];
1088: STRING ntNameString;
1089: STRING arcNameString;
1090: UNICODE_STRING ntUnicodeString;
1091: UNICODE_STRING arcUnicodeString;
1092: PDRIVE_LAYOUT_INFORMATION partitionList = NULL;
1093: OBJECT_ATTRIBUTES objectAttributes; // for the directory object
1094: HANDLE handle = NULL; // handle to the directory object
1095: PDEVICE_OBJECT deviceObject = NULL; // ptr to part 0 device object
1096: PDEVICE_OBJECT partitionObject; // ptr to a part x device object
1097: PDEVICE_OBJECT nextPartitionObject; // ptr for walking chain
1098: PDEVICE_OBJECT *partitionPointer;
1099: PDISK_EXTENSION diskExtension = NULL; // ptr to part 0 device extension
1100: PPARTITION_EXTENSION partitionExtension; // ptr to part x device extension
1101: NTSTATUS ntStatus;
1102: ULONG partitionNumber = 0; // which partition we're working on
1103: BOOLEAN timerWasStarted = FALSE; // TRUE when IoStartTimer called
1104:
1105: //
1106: // Create a permanent object directory for partitions, then make it
1107: // temporary so that we can close it at any time and it will go away.
1108: //
1109:
1110: sprintf(
1111: ntNameBuffer,
1112: "\\Device\\Harddisk%d",
1113: *( ConfigData->HardDiskCount ) );
1114:
1115: RtlInitString( &ntNameString, ntNameBuffer );
1116:
1117: ntStatus = RtlAnsiStringToUnicodeString(
1118: &ntUnicodeString,
1119: &ntNameString,
1120: TRUE );
1121:
1122: if ( !NT_SUCCESS( ntStatus ) ) {
1123:
1124: AtDump(
1125: ATERRORS,
1126: ("ATDISK: Couldn't create the unicode device name\n")
1127: );
1128: goto AtInitializeDiskExit;
1129: }
1130:
1131: InitializeObjectAttributes(
1132: &objectAttributes,
1133: &ntUnicodeString,
1134: OBJ_PERMANENT,
1135: NULL,
1136: NULL );
1137:
1138: ntStatus = ZwCreateDirectoryObject(
1139: &handle,
1140: DIRECTORY_ALL_ACCESS,
1141: &objectAttributes );
1142:
1143: RtlFreeUnicodeString( &ntUnicodeString );
1144:
1145: if ( !NT_SUCCESS( ntStatus ) ) {
1146:
1147: AtDump(
1148: ATERRORS,
1149: ("ATDISK: Couldn't create the directory object\n")
1150: );
1151: goto AtInitializeDiskExit;
1152: }
1153:
1154: ZwMakeTemporaryObject( handle );
1155:
1156: //
1157: // create partition 0 object
1158: //
1159:
1160: sprintf(
1161: ntNameBuffer,
1162: "\\Device\\Harddisk%d\\Partition0",
1163: *( ConfigData->HardDiskCount ) );
1164:
1165: RtlInitString( &ntNameString, ntNameBuffer );
1166:
1167: ntStatus = RtlAnsiStringToUnicodeString(
1168: &ntUnicodeString,
1169: &ntNameString,
1170: TRUE );
1171:
1172: if ( !NT_SUCCESS( ntStatus ) ) {
1173:
1174: AtDump(
1175: ATERRORS,
1176: ("ATDISK: Couldn't create the partition unicode name\n")
1177: );
1178: goto AtInitializeDiskExit;
1179: }
1180:
1181: ntStatus = IoCreateDevice(
1182: DriverObject,
1183: sizeof( DISK_EXTENSION ),
1184: &ntUnicodeString,
1185: FILE_DEVICE_DISK,
1186: 0,
1187: FALSE,
1188: &deviceObject );
1189:
1190: if ( !NT_SUCCESS( ntStatus ) ) {
1191:
1192: AtDump(
1193: ATERRORS,
1194: ("ATDISK: Couldn't create the device object\n")
1195: );
1196: goto AtInitializeDiskExit;
1197: }
1198:
1199: //
1200: // Create a symbolic link from the disk name to the corresponding
1201: // ARC name, to be used if we're booting off the disk. This will
1202: // if it's not system initialization time; that's fine. The ARC
1203: // name looks something like \ArcName\multi(0)disk(0)rdisk(0).
1204: //
1205:
1206: sprintf(
1207: arcNameBuffer,
1208: "%sdisk(%d)rdisk(%d)",
1209: ConfigData->ArcNamePrefix,
1210: ControllerNum,
1211: DiskNum );
1212:
1213: RtlInitString( &arcNameString, arcNameBuffer );
1214:
1215: ntStatus = RtlAnsiStringToUnicodeString(
1216: &arcUnicodeString,
1217: &arcNameString,
1218: TRUE );
1219:
1220: if ( !NT_SUCCESS( ntStatus ) ) {
1221:
1222: AtDump(
1223: ATERRORS,
1224: ("ATDISK: Couldn't create the arc name string\n")
1225: );
1226:
1227: RtlFreeUnicodeString( &ntUnicodeString );
1228: goto AtInitializeDiskExit;
1229: }
1230:
1231: IoAssignArcName( &arcUnicodeString, &ntUnicodeString );
1232:
1233: RtlFreeUnicodeString( &ntUnicodeString );
1234: RtlFreeUnicodeString( &arcUnicodeString );
1235:
1236: //
1237: // Initialize partition 0 device object and extension. Store pointer
1238: // to controller extension in partition 0's extension.
1239: //
1240:
1241: deviceObject->Flags |= DO_DIRECT_IO;
1242: deviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1243:
1244: diskExtension = ( PDISK_EXTENSION )( deviceObject->DeviceExtension );
1245:
1246: diskExtension->ControllerExtension = ControllerExtension;
1247: diskExtension->Partition0 = diskExtension;
1248: diskExtension->DeviceObject = deviceObject;
1249: diskExtension->DirectoryHandle = handle;
1250: diskExtension->PacketIsBeingRetried = FALSE;
1251:
1252: //
1253: // Set the device unit. We must examine DiskNum for the case
1254: // where the controller says this is drive 2, but we were unable to
1255: // initialize the first drive.
1256: //
1257:
1258: if ( DiskNum == 0 ) {
1259:
1260: diskExtension->DeviceUnit = DRIVE_1;
1261:
1262: } else {
1263:
1264: diskExtension->DeviceUnit = DRIVE_2;
1265: }
1266:
1267: //
1268: // Set up pointers between disks and from the controller extension.
1269: // We examine Disk1 rather than DiskNum because we never want
1270: // Disk1 to be NULL, regardless of which unit number the controller
1271: // considers it to be.
1272: //
1273:
1274: if ( ControllerExtension->Disk1 == NULL ) {
1275:
1276: ControllerExtension->Disk1 = diskExtension;
1277: diskExtension->OtherDiskExtension = NULL;
1278:
1279: //
1280: // Since this is the first device object we've successfully
1281: // initialized, let's attach the timer stuff (which actually
1282: // belongs with the controller extension, but requires a device
1283: // object) to this device object.
1284: //
1285:
1286: ControllerExtension->InterruptTimer = CANCEL_TIMER;
1287:
1288: IoInitializeTimer(
1289: deviceObject,
1290: AtDiskCheckTimer,
1291: ControllerExtension );
1292:
1293: IoStartTimer( deviceObject );
1294:
1295: timerWasStarted = TRUE;
1296:
1297: } else {
1298:
1299: //
1300: // This is the second disk we have initialized. Link the disk
1301: // extensions together.
1302: //
1303:
1304: ControllerExtension->Disk2 = diskExtension;
1305:
1306: diskExtension->OtherDiskExtension = ControllerExtension->Disk1;
1307: ControllerExtension->Disk1->OtherDiskExtension = diskExtension;
1308: }
1309:
1310: //
1311: // Fill in device-specific numbers that were obtained from the
1312: // configuration manager.
1313: // BUGBUG Dragon Master is working on a method to verify these numbers; may
1314: // involve reading from disk, may involve guessing. We should override
1315: // CM's numbers with those obtained by Andy's method.
1316: //
1317:
1318: diskExtension->PretendNumberOfCylinders =
1319: ConfigData->Controller[ControllerNum].Disk[DiskNum].PretendNumberOfCylinders;
1320: diskExtension->PretendTracksPerCylinder =
1321: ConfigData->Controller[ControllerNum].Disk[DiskNum].PretendTracksPerCylinder;
1322: diskExtension->PretendSectorsPerTrack =
1323: ConfigData->Controller[ControllerNum].Disk[DiskNum].PretendSectorsPerTrack;
1324: diskExtension->NumberOfCylinders =
1325: ConfigData->Controller[ControllerNum].Disk[DiskNum].NumberOfCylinders;
1326: diskExtension->TracksPerCylinder =
1327: ConfigData->Controller[ControllerNum].Disk[DiskNum].TracksPerCylinder;
1328: diskExtension->SectorsPerTrack =
1329: ConfigData->Controller[ControllerNum].Disk[DiskNum].SectorsPerTrack;
1330: diskExtension->BytesPerSector =
1331: ConfigData->Controller[ControllerNum].Disk[DiskNum].BytesPerSector;
1332: diskExtension->BytesPerInterrupt =
1333: ConfigData->Controller[ControllerNum].Disk[DiskNum].BytesPerInterrupt;
1334: diskExtension->WritePrecomp =
1335: ConfigData->Controller[ControllerNum].Disk[DiskNum].WritePrecomp;
1336: diskExtension->ReadCommand =
1337: ConfigData->Controller[ControllerNum].Disk[DiskNum].ReadCommand;
1338: diskExtension->WriteCommand =
1339: ConfigData->Controller[ControllerNum].Disk[DiskNum].WriteCommand;
1340: diskExtension->VerifyCommand =
1341: ConfigData->Controller[ControllerNum].Disk[DiskNum].VerifyCommand;
1342:
1343: AtDump(
1344: ATINIT,
1345: ("ATDISK: Controller %d Disk %d Geometry:\n"
1346: " Appa Cyl: %x\n"
1347: " Appa Hea: %x\n"
1348: " Appa Sec: %x\n"
1349: " Cyl: %x\n"
1350: " Hea: %x\n"
1351: " Sec: %x\n",
1352: ControllerNum,
1353: DiskNum,
1354: diskExtension->PretendNumberOfCylinders,
1355: diskExtension->PretendTracksPerCylinder,
1356: diskExtension->PretendSectorsPerTrack,
1357: diskExtension->NumberOfCylinders,
1358: diskExtension->TracksPerCylinder,
1359: diskExtension->SectorsPerTrack)
1360: );
1361:
1362: //
1363: // Determine the size of partition 0 (the whole disk).
1364: //
1365:
1366: diskExtension->StartingOffset = RtlConvertLongToLargeInteger( 0 );
1367:
1368: diskExtension->PartitionLength = RtlExtendedIntegerMultiply(
1369: RtlExtendedIntegerMultiply(
1370: RtlEnlargedIntegerMultiply( diskExtension->SectorsPerTrack,
1371: diskExtension->BytesPerSector ),
1372: diskExtension->NumberOfCylinders ),
1373: diskExtension->TracksPerCylinder );
1374:
1375: //
1376: // Given the sector size, figure out how many times we have to shift
1377: // a byte value to determine a sector value. Note that only there
1378: // are only four sector sizes allowed by the controller.
1379: //
1380:
1381: switch ( diskExtension->BytesPerSector ) {
1382:
1383: case 128: {
1384:
1385: diskExtension->ByteShiftToSector = 7;
1386: break;
1387: }
1388:
1389: case 256: {
1390:
1391: diskExtension->ByteShiftToSector = 8;
1392: break;
1393: }
1394:
1395: case 512: {
1396:
1397: diskExtension->ByteShiftToSector = 9;
1398: break;
1399: }
1400:
1401: case 1024: {
1402:
1403: diskExtension->ByteShiftToSector = 10;
1404: break;
1405: }
1406:
1407: default: {
1408:
1409: AtDump(
1410: ATBUGCHECK,
1411: ("AtDisk ERROR: unsupported sector size %x\n",
1412: diskExtension->BytesPerSector));
1413:
1414: diskExtension->ByteShiftToSector = 9;
1415: break;
1416: }
1417:
1418: }
1419:
1420: //
1421: // Initialize DPC in partition 0 object
1422: //
1423:
1424: IoInitializeDpcRequest( deviceObject, AtDiskDeferredProcedure );
1425:
1426: //
1427: // There is a very small chance that the controller is still busy
1428: // after the reset (the reset is very fast on most controllers, but
1429: // there are a few slow ones). It won't give an interrupt, so if
1430: // it's busy we'll just have to wait for it here. If it's not ready
1431: // after 3 seconds, just blast ahead anyway...we'll time out in
1432: // IoReadPartitionTable() and deal with it then.
1433: //
1434:
1435: ntStatus = AtWaitControllerReady( ControllerExtension, 20, 150000 );
1436:
1437: if (!NT_SUCCESS(ntStatus)) {
1438:
1439: AtDump(
1440: ATERRORS,
1441: ("ATDISK: Disk hasn't come back from the reset after 3 seconds\n")
1442: );
1443:
1444: }
1445:
1446: //
1447: // First we'll set up the disk so that it doesn't revert to power
1448: // on defaults after a controller reset. Then we'll set it up
1449: // so that the write cache is disabled. If this works great. If
1450: // not, well, we're no worse off then we were before.
1451: //
1452:
1453:
1454: ControllerExtension->WhichDeviceObject = diskExtension->DeviceObject;
1455:
1456:
1457: //
1458: // Select the right drive.
1459: //
1460:
1461: WRITE_CONTROLLER(
1462: ControllerExtension->ControllerAddress + DRIVE_HEAD_REGISTER,
1463: diskExtension->DeviceUnit
1464: );
1465:
1466: //
1467: // Disable the reverting to power on.
1468: //
1469:
1470: WRITE_CONTROLLER(
1471: ControllerExtension->ControllerAddress + WRITE_PRECOMP_REGISTER,
1472: 0x66
1473: );
1474:
1475: ControllerExtension->InterruptTimer = START_TIMER;
1476: WRITE_CONTROLLER(
1477: ControllerExtension->ControllerAddress + COMMAND_REGISTER,
1478: 0xef );
1479:
1480:
1481: AtWaitControllerReady( ControllerExtension, 10, 15000 );
1482:
1483: WRITE_CONTROLLER(
1484: ControllerExtension->ControllerAddress + DRIVE_HEAD_REGISTER,
1485: diskExtension->DeviceUnit
1486: );
1487:
1488: //
1489: // Disable the write cache.
1490: //
1491:
1492: WRITE_CONTROLLER(
1493: ControllerExtension->ControllerAddress + WRITE_PRECOMP_REGISTER,
1494: 0x82
1495: );
1496:
1497: ControllerExtension->InterruptTimer = START_TIMER;
1498: WRITE_CONTROLLER(
1499: ControllerExtension->ControllerAddress + COMMAND_REGISTER,
1500: 0xef );
1501:
1502: AtWaitControllerReady( ControllerExtension, 10, 15000 );
1503:
1504: if (ConfigData->Controller[ControllerNum].Disk[DiskNum].DisableReadCache) {
1505:
1506: //
1507: // Disable the read cache.
1508: //
1509:
1510: WRITE_CONTROLLER(
1511: ControllerExtension->ControllerAddress + WRITE_PRECOMP_REGISTER,
1512: 0x55
1513: );
1514:
1515: ControllerExtension->InterruptTimer = START_TIMER;
1516:
1517:
1518: WRITE_CONTROLLER(
1519: ControllerExtension->ControllerAddress + COMMAND_REGISTER,
1520: 0xef );
1521:
1522: AtWaitControllerReady( ControllerExtension, 10, 15000 );
1523:
1524: AtLogError(
1525: deviceObject,
1526: 0,
1527: 0,
1528: 0,
1529: 18,
1530: STATUS_SUCCESS,
1531: IO_WRN_BAD_FIRMWARE,
1532: ERROR_LOG_TYPE_TIMEOUT,
1533: 0,
1534: 0,
1535: 0,
1536: 0,
1537: 0,
1538: 0,
1539: 0
1540: );
1541:
1542: }
1543:
1544: //
1545: // Set up drive parameters. This will cause an interrupt.
1546: // Don't need to allocate controller, since this is init time and DPC
1547: // won't be invoked. Even though we're waiting here for the BUSY bit,
1548: // we need to start the timer since that's the ISR's indication that
1549: // the interrupt was expected.
1550: //
1551:
1552: ControllerExtension->WhichDeviceObject = diskExtension->DeviceObject;
1553:
1554: ControllerExtension->InterruptTimer = START_TIMER;
1555:
1556: if ( NT_SUCCESS( ntStatus ) ) {
1557:
1558: WRITE_CONTROLLER(
1559: ControllerExtension->ControllerAddress + DRIVE_HEAD_REGISTER,
1560: ( diskExtension->DeviceUnit |
1561: ( diskExtension->TracksPerCylinder - 1 ) ) );
1562:
1563: WRITE_CONTROLLER(
1564: ControllerExtension->ControllerAddress + SECTOR_COUNT_REGISTER,
1565: diskExtension->SectorsPerTrack );
1566:
1567: WRITE_CONTROLLER(
1568: ControllerExtension->ControllerAddress + COMMAND_REGISTER,
1569: SET_DRIVE_PARAMETERS_COMMAND );
1570: }
1571:
1572: //
1573: // We can't read the partition table until the controller is ready.
1574: // The SET_DRIVE_PARAMETERS command *should* be ~10us; let's wait
1575: // for it here. (It will interrupt, but we want to finish the
1576: // initialization here rather than in a DPC). Note that some machines
1577: // are way out of spec, and take a good portion of a second, so we'll
1578: // wait as long as 3 seconds. If we really get to 3 seconds, just
1579: // blast ahead; we'll time out in IoReadPartitionTable() and deal
1580: // with it there. We ordinarily wouldn't wait this long, but with
1581: // some controllers we HAVE to, and this is just init time.
1582: //
1583:
1584: ntStatus = AtWaitControllerReady( ControllerExtension, 20, 150000 );
1585:
1586: if (!NT_SUCCESS(ntStatus)) {
1587:
1588: AtDump(
1589: ATERRORS,
1590: ("ATDISK: Disk hasn't come back from setting the parameters after 3 seconds\n")
1591: );
1592:
1593: }
1594: //
1595: // Turn off the timer whether we succeeded or not - we don't have the
1596: // controller object, so we don't want the timer to expire yet. It
1597: // will when we try to read the partition table.
1598: //
1599:
1600: ControllerExtension->InterruptTimer = CANCEL_TIMER;
1601:
1602: //
1603: // Now recalibrate the drive. Many drives don't need this, but some
1604: // seem to go wacky later if this isn't done.
1605: //
1606:
1607: ControllerExtension->WhichDeviceObject = diskExtension->DeviceObject;
1608: ControllerExtension->InterruptTimer = START_TIMER_FOR_RECALIBRATE;
1609:
1610: if ( NT_SUCCESS( ntStatus ) ) {
1611:
1612: WRITE_CONTROLLER(
1613: ControllerExtension->ControllerAddress + DRIVE_HEAD_REGISTER,
1614: ( diskExtension->DeviceUnit |
1615: ( diskExtension->TracksPerCylinder - 1 ) ) );
1616:
1617: WRITE_CONTROLLER(
1618: ControllerExtension->ControllerAddress + COMMAND_REGISTER,
1619: RECALIBRATE_COMMAND );
1620: }
1621:
1622: ntStatus = AtWaitControllerReady( ControllerExtension, 20, 150000 );
1623:
1624: if (!NT_SUCCESS(ntStatus)) {
1625:
1626: AtDump(
1627: ATERRORS,
1628: ("ATDISK: Disk hasn't come back from the recal after 3 seconds\n")
1629: );
1630:
1631: }
1632:
1633: //
1634: // Turn off the timer whether we succeeded or not - we don't have the
1635: // controller object, so we don't want the timer to expire yet. It
1636: // will when we try to read the partition table.
1637: //
1638:
1639: ControllerExtension->InterruptTimer = CANCEL_TIMER;
1640:
1641: //
1642: // Read partition table
1643: //
1644:
1645: ntStatus = IoReadPartitionTable(
1646: diskExtension->DeviceObject,
1647: ConfigData->Controller[ControllerNum].Disk[DiskNum].BytesPerSector,
1648: TRUE,
1649: &partitionList );
1650:
1651: //
1652: // For each partition other than partition 0, create and initialize a
1653: // partition object. Chain the partition objects together so we can
1654: // delete them if necessary. If IoReadPartitionTable() failed, just
1655: // skip this section, but keep partition 0 around so the disk can be
1656: // formatted or somesuch.
1657: //
1658:
1659: if ( !NT_SUCCESS( ntStatus ) ) {
1660:
1661: //
1662: // IoReadPartitionTable() failed, but force success so we don't
1663: // unload since we still have partition 0 to support.
1664: //
1665:
1666: AtDump(
1667: ATERRORS,
1668: ("ATDISK: Couldn't read the partition table\n")
1669: );
1670: ntStatus = STATUS_SUCCESS;
1671:
1672: } else {
1673:
1674: //
1675: // IoReadPartitionTable() didn't return error, so initialize the
1676: // partitions.
1677: //
1678:
1679: partitionPointer = &diskExtension->PartitionObjects;
1680:
1681: for ( partitionNumber = 0;
1682: partitionNumber < partitionList->PartitionCount;
1683: partitionNumber++ ) {
1684:
1685: //
1686: // Create the device, with a UNICODE name such as
1687: // \\Device\Harddisk0\Partition1
1688: //
1689:
1690: sprintf(
1691: ntNameBuffer,
1692: "\\Device\\Harddisk%d\\Partition%d",
1693: *( ConfigData->HardDiskCount ),
1694: partitionNumber + 1 );
1695:
1696: RtlInitString ( &ntNameString, ntNameBuffer );
1697:
1698: ntStatus = RtlAnsiStringToUnicodeString(
1699: &ntUnicodeString,
1700: &ntNameString,
1701: TRUE );
1702:
1703: if ( !NT_SUCCESS( ntStatus ) ) {
1704:
1705: AtDump(
1706: ATERRORS,
1707: ("ATDISK: Couldn't create the partition 0"
1708: " partition objects\n")
1709: );
1710: goto AtInitializeDiskExit;
1711: }
1712:
1713: ntStatus = IoCreateDevice(
1714: DriverObject,
1715: sizeof( PARTITION_EXTENSION ),
1716: &ntUnicodeString,
1717: FILE_DEVICE_DISK,
1718: 0,
1719: FALSE,
1720: &partitionObject );
1721:
1722: if ( !NT_SUCCESS( ntStatus ) ) {
1723:
1724: AtDump(
1725: ATERRORS,
1726: ("ATDISK: Couldn't create the partition 0"
1727: " partition devices\n")
1728: );
1729: RtlFreeUnicodeString( &ntUnicodeString );
1730: goto AtInitializeDiskExit;
1731: }
1732:
1733: //
1734: // Create a symbolic link from the partition name to the
1735: // corresponding ARC name, to be used if we're booting off
1736: // the partition. This will fail if it's not system
1737: // initialization time; that's fine. The ARC name looks
1738: // something like \ArcName\multi(0)disk(0)rdisk(0)partition(1)
1739: //
1740:
1741: sprintf(
1742: arcNameBuffer,
1743: "%sdisk(%d)rdisk(%d)partition(%d)",
1744: ConfigData->ArcNamePrefix,
1745: ControllerNum,
1746: DiskNum,
1747: partitionNumber + 1 );
1748:
1749: RtlInitString( &arcNameString, arcNameBuffer );
1750:
1751: ntStatus = RtlAnsiStringToUnicodeString(
1752: &arcUnicodeString,
1753: &arcNameString,
1754: TRUE );
1755:
1756: if ( !NT_SUCCESS( ntStatus ) ) {
1757:
1758: AtDump(
1759: ATERRORS,
1760: ("ATDISK: Couldn't create the arc names for the"
1761: " partition 0 partition objects\n")
1762: );
1763: RtlFreeUnicodeString( &ntUnicodeString );
1764: goto AtInitializeDiskExit;
1765: }
1766:
1767: IoAssignArcName( &arcUnicodeString, &ntUnicodeString );
1768:
1769: RtlFreeUnicodeString( &ntUnicodeString );
1770: RtlFreeUnicodeString( &arcUnicodeString );
1771:
1772: //
1773: // Now initialize the partition object and extension.
1774: //
1775:
1776: partitionObject->Flags |= DO_DIRECT_IO;
1777:
1778: partitionExtension = partitionObject->DeviceExtension;
1779:
1780: partitionExtension->PartitionNumber = partitionNumber + 1;
1781:
1782: partitionExtension->PartitionType =
1783: partitionList->PartitionEntry[partitionNumber].PartitionType;
1784:
1785: partitionExtension->BootIndicator =
1786: partitionList->PartitionEntry[partitionNumber].BootIndicator;
1787:
1788: partitionExtension->StartingOffset =
1789: partitionList->PartitionEntry[partitionNumber].StartingOffset;
1790:
1791: partitionExtension->PartitionLength =
1792: partitionList->PartitionEntry[partitionNumber].PartitionLength;
1793:
1794: partitionExtension->HiddenSectors =
1795: partitionList->PartitionEntry[partitionNumber].HiddenSectors;
1796:
1797: partitionExtension->Partition0 = diskExtension;
1798:
1799: partitionExtension->NextPartitionObject = NULL;
1800:
1801: *partitionPointer = partitionObject;
1802: partitionPointer = &partitionExtension->NextPartitionObject;
1803:
1804: } // FOR partitionNumber = 1-> call IoCreateDevice, etc
1805: } // if IoReadPartitionTable() didn't return error
1806:
1807: AtInitializeDiskExit:
1808:
1809: if ( !NT_SUCCESS( ntStatus ) ) {
1810:
1811: //
1812: // Delete everything that this routine has allocated.
1813: //
1814: // We don't have to worry about the ARC symbolic links; we
1815: // already closed our handle to them, and the system will
1816: // delete them when boot is complete.
1817: //
1818: // First the chain of partition objects, then the device
1819: // object, then the object directory.
1820: //
1821:
1822: if ( diskExtension != NULL ) {
1823:
1824: nextPartitionObject = diskExtension->PartitionObjects;
1825:
1826: while ( nextPartitionObject != NULL ) {
1827:
1828: partitionObject = nextPartitionObject;
1829: partitionExtension =
1830: ( PPARTITION_EXTENSION )( partitionObject->DeviceExtension );
1831: nextPartitionObject = partitionExtension->NextPartitionObject;
1832: IoDeleteDevice( partitionObject );
1833: }
1834: }
1835:
1836: if ( timerWasStarted ) {
1837:
1838: IoStopTimer( deviceObject );
1839: }
1840:
1841: if ( deviceObject != NULL ) {
1842:
1843: IoDeleteDevice( deviceObject );
1844: }
1845:
1846: if ( handle != NULL ) {
1847:
1848: ZwClose( handle );
1849: }
1850:
1851: //
1852: // If this is the first disk, make sure Disk1 is null so that its
1853: // spot can be taken by the second disk when we initialize it.
1854: //
1855:
1856: if ( DiskNum == 0 ) {
1857:
1858: ControllerExtension->Disk1 = NULL;
1859: }
1860: } // if not success, delete everything
1861:
1862: //
1863: // Delete the buffer allocated for the partition list.
1864: //
1865:
1866: if ( partitionList != NULL ) {
1867:
1868: ExFreePool( partitionList );
1869: }
1870:
1871: return ntStatus;
1872: }
1873:
1874: NTSTATUS
1875: AtDiskDispatchCreateClose(
1876: IN PDEVICE_OBJECT DeviceObject,
1877: IN OUT PIRP Irp
1878: )
1879:
1880: /*++
1881:
1882: Routine Description:
1883:
1884: This routine is called only rarely by the I/O system; it's mainly
1885: for layered drivers to call. All it does is complete the IRP
1886: successfully.
1887:
1888: Arguments:
1889:
1890: DeviceObject - a pointer to the object that represents the device
1891: that I/O is to be done on.
1892:
1893: Irp - a pointer to the I/O Request Packet for this request.
1894:
1895: Return Value:
1896:
1897: Always returns STATUS_SUCCESS, since this is a null operation.
1898:
1899: --*/
1900:
1901: {
1902:
1903: UNREFERENCED_PARAMETER( DeviceObject );
1904:
1905: //
1906: // Null operation. Do not give an I/O boost since no I/O was
1907: // actually done. IoStatus.Information should be
1908: // FILE_OPENED for an open; it's undefined for a close.
1909: //
1910:
1911: Irp->IoStatus.Status = STATUS_SUCCESS;
1912: Irp->IoStatus.Information = FILE_OPENED;
1913:
1914: IoCompleteRequest( Irp, IO_NO_INCREMENT );
1915:
1916: return STATUS_SUCCESS;
1917: }
1918:
1919: NTSTATUS
1920: AtDiskDispatchDeviceControl(
1921: IN PDEVICE_OBJECT DeviceObject,
1922: IN OUT PIRP Irp
1923: )
1924:
1925: /*++
1926:
1927: Routine Description:
1928:
1929: This routine is called by the I/O system to perform a device I/O
1930: control function.
1931:
1932: Arguments:
1933:
1934: DeviceObject - a pointer to the object that represents the device
1935: that I/O is to be done on.
1936:
1937: Irp - a pointer to the I/O Request Packet for this request.
1938:
1939: Return Value:
1940:
1941: STATUS_SUCCESS if recognized I/O control code,
1942: STATUS_INVALID_DEVICE_REQUEST otherwise.
1943:
1944: --*/
1945:
1946: {
1947: PPARTITION_EXTENSION partitionExtension;
1948: PDISK_EXTENSION diskExtension;
1949: PIO_STACK_LOCATION irpSp;
1950: NTSTATUS ntStatus;
1951: CCHAR ioIncrement = IO_NO_INCREMENT; // assume no I/O will be done
1952:
1953: //
1954: // Set up necessary object and extension pointers.
1955: //
1956:
1957: partitionExtension = DeviceObject->DeviceExtension;
1958: diskExtension = partitionExtension->Partition0;
1959: irpSp = IoGetCurrentIrpStackLocation( Irp );
1960:
1961: //
1962: // Assume failure.
1963: //
1964:
1965: Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1966:
1967: //
1968: // Determine which I/O control code was specified.
1969: //
1970:
1971: switch ( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
1972:
1973: case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
1974:
1975: //
1976: // Return the drive geometry for the specified drive. Note that
1977: // we will return the geometry for the physical drive, regardless
1978: // of which partition was specified for the request.
1979: //
1980:
1981: if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
1982: sizeof( DISK_GEOMETRY ) ) {
1983:
1984: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1985:
1986: } else {
1987:
1988: PDISK_GEOMETRY outputBuffer;
1989:
1990: outputBuffer = ( PDISK_GEOMETRY )
1991: Irp->AssociatedIrp.SystemBuffer;
1992: outputBuffer->MediaType = FixedMedia;
1993: outputBuffer->Cylinders = RtlConvertUlongToLargeInteger(
1994: diskExtension->PretendNumberOfCylinders );
1995: outputBuffer->TracksPerCylinder =
1996: diskExtension->PretendTracksPerCylinder;
1997: outputBuffer->SectorsPerTrack =
1998: diskExtension->PretendSectorsPerTrack;
1999: outputBuffer->BytesPerSector = diskExtension->BytesPerSector;
2000:
2001: Irp->IoStatus.Status = STATUS_SUCCESS;
2002: Irp->IoStatus.Information = sizeof( DISK_GEOMETRY );
2003: }
2004:
2005: break;
2006: }
2007:
2008: case IOCTL_DISK_GET_PARTITION_INFO: {
2009:
2010: //
2011: // Return the information about the partition specified by the
2012: // device object. Note that no information is ever returned
2013: // about the size or partition type of the physical disk, as
2014: // this doesn't make any sense.
2015: //
2016:
2017: if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
2018: sizeof( PARTITION_INFORMATION ) ) {
2019:
2020: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2021:
2022: } else if ( partitionExtension ==
2023: ( PPARTITION_EXTENSION )diskExtension ) {
2024:
2025: Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2026:
2027: } else {
2028:
2029: PPARTITION_INFORMATION outputBuffer;
2030:
2031: outputBuffer =
2032: ( PPARTITION_INFORMATION )Irp->AssociatedIrp.SystemBuffer;
2033:
2034: outputBuffer->PartitionType = partitionExtension->PartitionType;
2035:
2036: outputBuffer->BootIndicator = partitionExtension->BootIndicator;
2037:
2038: outputBuffer->RecognizedPartition = TRUE;
2039:
2040: outputBuffer->RewritePartition = FALSE;
2041:
2042: outputBuffer->StartingOffset =
2043: partitionExtension->StartingOffset;
2044:
2045: outputBuffer->PartitionLength =
2046: partitionExtension->PartitionLength;
2047:
2048: outputBuffer->HiddenSectors =
2049: partitionExtension->HiddenSectors;
2050:
2051: Irp->IoStatus.Status = STATUS_SUCCESS;
2052: Irp->IoStatus.Information = sizeof( PARTITION_INFORMATION );
2053: }
2054:
2055: break;
2056: }
2057:
2058: case IOCTL_DISK_SET_PARTITION_INFO: {
2059:
2060: //
2061: // Validate input, then set the partition type.
2062: //
2063:
2064: if ( irpSp->Parameters.DeviceIoControl.InputBufferLength <
2065: sizeof( SET_PARTITION_INFORMATION ) ) {
2066:
2067: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2068:
2069: } else if ( partitionExtension ==
2070: ( PPARTITION_EXTENSION )diskExtension ) {
2071:
2072: Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2073:
2074: } else {
2075:
2076: PSET_PARTITION_INFORMATION inputBuffer;
2077:
2078: inputBuffer = ( PSET_PARTITION_INFORMATION )
2079: Irp->AssociatedIrp.SystemBuffer;
2080:
2081: if ( IoSetPartitionInformation(
2082: diskExtension->DeviceObject,
2083: diskExtension->BytesPerSector,
2084: partitionExtension->PartitionNumber,
2085: inputBuffer->PartitionType ) ) {
2086:
2087: //
2088: // Set the partition type in the partition extension.
2089: //
2090:
2091: partitionExtension->PartitionType =
2092: inputBuffer->PartitionType;
2093: }
2094:
2095: Irp->IoStatus.Status = STATUS_SUCCESS;
2096: }
2097:
2098: ioIncrement = IO_DISK_INCREMENT; // I/O was done, so boost thread
2099:
2100: break;
2101: }
2102:
2103: case IOCTL_DISK_GET_DRIVE_LAYOUT: {
2104:
2105: //
2106: // Return the partition layout for the physical drive. Note that
2107: // the layout is returned for the actual physical drive, regardless
2108: // of which partition was specified for the request.
2109: //
2110:
2111: if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
2112: sizeof( DRIVE_LAYOUT_INFORMATION ) ) {
2113:
2114: Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
2115:
2116: } else {
2117:
2118: PDRIVE_LAYOUT_INFORMATION partitionList;
2119:
2120: ntStatus = IoReadPartitionTable(
2121: diskExtension->DeviceObject,
2122: diskExtension->BytesPerSector,
2123: FALSE,
2124: &partitionList );
2125:
2126: if ( !NT_SUCCESS( ntStatus ) ) {
2127:
2128: Irp->IoStatus.Status = ntStatus;
2129:
2130: } else {
2131:
2132: ULONG tempSize;
2133:
2134: //
2135: // The disk layout has been returned in the partitionList
2136: // buffer. Determine its size and, if the data will fit
2137: // into the intermediary buffer, return it.
2138: //
2139:
2140: tempSize = FIELD_OFFSET(
2141: DRIVE_LAYOUT_INFORMATION,
2142: PartitionEntry[0] );
2143: tempSize += partitionList->PartitionCount *
2144: sizeof( PARTITION_INFORMATION );
2145:
2146: if (tempSize >
2147: irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
2148: Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
2149: } else {
2150: RtlMoveMemory( Irp->AssociatedIrp.SystemBuffer,
2151: partitionList,
2152: tempSize );
2153: Irp->IoStatus.Status = STATUS_SUCCESS;
2154: Irp->IoStatus.Information = tempSize;
2155: }
2156:
2157: //
2158: // Finally, free the buffer allocated by reading the
2159: // partition table.
2160: //
2161:
2162: ExFreePool( partitionList );
2163: }
2164: }
2165:
2166: ioIncrement = IO_DISK_INCREMENT; // I/O was done, so boost thread
2167:
2168: break;
2169: }
2170:
2171: case IOCTL_DISK_SET_DRIVE_LAYOUT: {
2172:
2173: //
2174: // Update the disk with new partition information.
2175: //
2176:
2177: PDRIVE_LAYOUT_INFORMATION partitionList =
2178: Irp->AssociatedIrp.SystemBuffer;
2179:
2180: Irp->IoStatus.Status = IoWritePartitionTable(
2181: diskExtension->DeviceObject,
2182: diskExtension->BytesPerSector,
2183: diskExtension->PretendSectorsPerTrack,
2184: diskExtension->PretendTracksPerCylinder,
2185: partitionList );
2186:
2187: ioIncrement = IO_DISK_INCREMENT; // I/O was done, so boost thread
2188:
2189: break;
2190: }
2191:
2192: case IOCTL_DISK_VERIFY: {
2193:
2194: //
2195: // Move parameters from the VerifyInformation structure to
2196: // the READ parameters area, so that we'll find them when
2197: // we try to treat this like a READ.
2198: //
2199:
2200: PVERIFY_INFORMATION verifyInformation;
2201:
2202: verifyInformation = Irp->AssociatedIrp.SystemBuffer;
2203:
2204: irpSp->Parameters.Read.ByteOffset.LowPart =
2205: verifyInformation->StartingOffset.LowPart;
2206: irpSp->Parameters.Read.ByteOffset.HighPart =
2207: verifyInformation->StartingOffset.HighPart;
2208: irpSp->Parameters.Read.Length = verifyInformation->Length;
2209:
2210: //
2211: // A VERIFY is identical to a READ, except for the fact that no
2212: // data gets transferred. So follow the READ code path.
2213: //
2214:
2215: ntStatus = AtDiskDispatchReadWrite( DeviceObject, Irp );
2216:
2217: return ntStatus;
2218: }
2219:
2220: default: {
2221:
2222: //
2223: // The specified I/O control code is unrecognized by this driver.
2224: // The I/O status field in the IRP has already been set to just
2225: // terminate the switch.
2226: //
2227:
2228: AtDump(
2229: ATDIAG2,
2230: ("Atdisk ERROR: unrecognized IOCTL %x\n",
2231: irpSp->Parameters.DeviceIoControl.IoControlCode));
2232:
2233: break;
2234: }
2235: }
2236:
2237: //
2238: // Finish the I/O operation by simply completing the packet and returning
2239: // the same status as in the packet itself.
2240: //
2241:
2242: ntStatus = Irp->IoStatus.Status;
2243:
2244: IoCompleteRequest( Irp, ioIncrement );
2245:
2246: return ntStatus;
2247: }
2248:
2249: NTSTATUS
2250: AtDiskDispatchReadWrite(
2251: IN PDEVICE_OBJECT DeviceObject,
2252: IN OUT PIRP Irp
2253: )
2254:
2255: /*++
2256:
2257: Routine Description:
2258:
2259: This routine is called by the I/O system to read or write to a
2260: device that we control. It can also be called by
2261: AtDiskDispatchDeviceControl() to do a VERIFY.
2262:
2263: This routine changes from the partition object to the device object,
2264: checks parameters for validity, marks the IRP pending, queues the
2265: IRP for processing by AtDiskStartIo(), and returns.
2266:
2267: This routine is not protected by device queues or controller object
2268: ownership, so it cannot change any device or controller extension
2269: variables, and it cannot touch the hardware.
2270:
2271: Arguments:
2272:
2273: DeviceObject - a pointer to the object that represents the device
2274: that I/O is to be done on.
2275:
2276: Irp - a pointer to the I/O Request Packet for this request.
2277:
2278: Return Value:
2279:
2280: STATUS_INVALID_PARAMETER if parameters are invalid,
2281: STATUS_PENDING otherwise.
2282:
2283: --*/
2284:
2285: {
2286: PPARTITION_EXTENSION partitionExtension;
2287: PDISK_EXTENSION diskExtension;
2288: PIO_STACK_LOCATION irpSp;
2289: ULONG firstSectorOfRequest;
2290:
2291: //
2292: // Set up necessary object and extension pointers.
2293: //
2294:
2295: partitionExtension = DeviceObject->DeviceExtension;
2296: diskExtension = partitionExtension->Partition0;
2297: irpSp = IoGetCurrentIrpStackLocation( Irp );
2298:
2299: //
2300: // Check for invalid parameters. It is an error for the starting offset
2301: // + length to go past the end of the partition, or for the length to
2302: // not be a proper multiple of the sector size.
2303: //
2304: // Others are possible, but we don't check them since we trust the
2305: // file system and they aren't deadly.
2306: //
2307:
2308: if ( RtlLargeIntegerGreaterThan(
2309: RtlLargeIntegerAdd( irpSp->Parameters.Read.ByteOffset,
2310: RtlConvertUlongToLargeInteger( irpSp->Parameters.Read.Length ) ),
2311: partitionExtension->PartitionLength ) ||
2312: ( irpSp->Parameters.Read.Length &
2313: ( diskExtension->BytesPerSector - 1 ) ) ) {
2314:
2315: //
2316: // Do not give an I/O boost for parameter errors.
2317: //
2318:
2319: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2320: IoCompleteRequest( Irp, IO_NO_INCREMENT );
2321:
2322: return STATUS_INVALID_PARAMETER;
2323: }
2324:
2325: //
2326: // The offset passed in is relative to the start of the partition.
2327: // We always work from partition 0 (the whole disk) so adjust the
2328: // offset.
2329: //
2330:
2331: irpSp->Parameters.Read.ByteOffset = RtlLargeIntegerAdd(
2332: irpSp->Parameters.Read.ByteOffset,
2333: partitionExtension->StartingOffset );
2334:
2335: //
2336: // Mark Irp pending and queue packet, passing sector number for C-SCAN
2337: //
2338:
2339: IoMarkIrpPending( Irp );
2340:
2341: firstSectorOfRequest = RtlLargeIntegerShiftRight(
2342: irpSp->Parameters.Read.ByteOffset,
2343: diskExtension->ByteShiftToSector ).LowPart;
2344:
2345: IoStartPacket(
2346: diskExtension->DeviceObject,
2347: Irp,
2348: &firstSectorOfRequest,
2349: NULL );
2350:
2351: return STATUS_PENDING;
2352: }
2353:
2354: VOID
2355: AtDiskStartIo(
2356: IN PDEVICE_OBJECT DeviceObject,
2357: IN PIRP Irp
2358: )
2359:
2360: /*++
2361:
2362: Routine Description:
2363:
2364: This routine is called at DISPATCH_LEVEL by the I/O system when the
2365: disk being serviced is not busy (i.e. the previous packet has been
2366: finished, which is indicated by calling IoStartNextPacket).
2367:
2368: It is also called by the DPC to restart requests when the controller
2369: has been reset due to a hardware glitch.
2370:
2371: When called, this device is not busy - so this is the only I/O request
2372: being processed for this disk.
2373:
2374: This routine sets up variables in the device extension that pertain
2375: to the operation, and then calls AtInitiate() via
2376: IoAllocateController() to avoid contention between disks for the
2377: controller.
2378:
2379: This routine is protected by device queues, but not by controller
2380: ownership. So it can alter device extension variables (there will
2381: be no interrupts until after AtInitiate() is called), but not those in
2382: the controller extension and it can't touch the hardware.
2383:
2384: Arguments:
2385:
2386: DeviceObject - a pointer to the object that represents the device that
2387: I/O is to be done on.
2388:
2389: Irp - a pointer to the I/O Request Packet for this request.
2390:
2391: Return Value:
2392:
2393: None.
2394:
2395: --*/
2396:
2397: {
2398: PDISK_EXTENSION diskExtension;
2399: PIO_STACK_LOCATION irpSp;
2400:
2401: //
2402: // Set up necessary object and extension pointers.
2403: //
2404:
2405: diskExtension = DeviceObject->DeviceExtension;
2406: diskExtension->SequenceNumber++;
2407: irpSp = IoGetCurrentIrpStackLocation( Irp );
2408:
2409: //
2410: // Copy the operation type (READ or WRITE, or IOCTL which means VERIFY)
2411: // and the total byte length of the operation from the IRP stack
2412: // location to the device extension.
2413: //
2414:
2415: diskExtension->OperationType = irpSp->MajorFunction;
2416: diskExtension->RemainingRequestLength = irpSp->Parameters.Read.Length;
2417:
2418: //
2419: // Calculate starting sector and length of the transfer.
2420: //
2421:
2422: diskExtension->FirstSectorOfTransfer = RtlLargeIntegerShiftRight(
2423: irpSp->Parameters.Read.ByteOffset,
2424: diskExtension->ByteShiftToSector ).LowPart;
2425:
2426: //
2427: // The first sector of each transfer of a request is greater than the
2428: // previous one, so the following test will only happen when we're
2429: // working on the first transfer of a request (since the completion
2430: // of the previous request set FirstSectorOfRequest to MAXULONG). That's
2431: // when we want to save the first sector of the request so that
2432: // IoStartNextPacketByKey will get the next packet for C-SCAN.
2433: //
2434:
2435: if ( diskExtension->FirstSectorOfTransfer <
2436: diskExtension->FirstSectorOfRequest ) {
2437:
2438: diskExtension->FirstSectorOfRequest =
2439: diskExtension->FirstSectorOfTransfer;
2440: }
2441:
2442: //
2443: // If possible, this transfer should be the same length as the
2444: // request. However, it is limited to MAX_SEC_TO_TRANS sectors.
2445: //
2446:
2447: if ( diskExtension->RemainingRequestLength >
2448: ( ULONG )( diskExtension->BytesPerSector * MAX_SEC_TO_TRANS ) ) {
2449:
2450: diskExtension->TotalTransferLength =
2451: diskExtension->BytesPerSector * MAX_SEC_TO_TRANS;
2452:
2453: } else {
2454:
2455: diskExtension->TotalTransferLength =
2456: diskExtension->RemainingRequestLength;
2457: }
2458:
2459: diskExtension->RemainingTransferLength = diskExtension->TotalTransferLength;
2460:
2461: //
2462: // Generally, we're not resetting the controller so the retry count
2463: // is initialized to 0. But if the controller is being reset because
2464: // of a failure on this disk, increment the retry count. Also don't
2465: // increment the sequence number if we are doing a retry.
2466: //
2467:
2468: if ( diskExtension->PacketIsBeingRetried ) {
2469:
2470: AtDump(
2471: ATDIAG2,
2472: ("ATDISK: *******************Retrying IRP: %x\n",
2473: Irp)
2474: );
2475: diskExtension->PacketIsBeingRetried = FALSE;
2476: diskExtension->IrpRetryCount++;
2477:
2478: } else {
2479:
2480: diskExtension->SequenceNumber++;
2481: diskExtension->IrpRetryCount = 0;
2482: }
2483:
2484: //
2485: // Get a system-space pointer to the user's buffer. A system
2486: // address must be used because we may already have left the
2487: // original caller's address space.
2488: //
2489:
2490: if ( Irp->MdlAddress != NULL ) {
2491:
2492: diskExtension->CurrentAddress = MmGetSystemAddressForMdl(
2493: Irp->MdlAddress );
2494: }
2495:
2496: AtDump(
2497: ATDIAG2,
2498: (
2499: "ATDISK: Irp of Request: %x\n"
2500: " Starting vmem Address of Transfer: %x\n"
2501: " Ending vmem Address of Transfer: %x\n"
2502: " Length of Transfer: %x\n",
2503: Irp,
2504: diskExtension->CurrentAddress,
2505: ((PUCHAR)diskExtension->CurrentAddress)+diskExtension->RemainingRequestLength,
2506: diskExtension->RemainingRequestLength
2507: ) );
2508:
2509: AtDump(
2510: ATDIAG2,
2511: ("ATDISK - Sector number is: %x\n"
2512: " CHS: %x-%x-%x\n",
2513: diskExtension->FirstSectorOfTransfer,
2514: diskExtension->FirstSectorOfTransfer /
2515: (diskExtension->SectorsPerTrack *
2516: diskExtension->TracksPerCylinder),
2517: (diskExtension->FirstSectorOfTransfer /
2518: diskExtension->SectorsPerTrack) %
2519: diskExtension->TracksPerCylinder,
2520: diskExtension->FirstSectorOfTransfer %
2521: diskExtension->TracksPerCylinder
2522: ) );
2523:
2524:
2525:
2526: //
2527: // Allocate the controller, and then program it to do the operation.
2528: //
2529:
2530: IoAllocateController(
2531: diskExtension->ControllerExtension->ControllerObject,
2532: DeviceObject,
2533: AtInitiate,
2534: NULL );
2535:
2536: return;
2537: }
2538:
2539: IO_ALLOCATION_ACTION
2540: AtInitiate(
2541: IN PDEVICE_OBJECT DeviceObject,
2542: IN PIRP Irp,
2543: IN PVOID MapRegisterBase,
2544: IN PVOID Context
2545: )
2546:
2547: /*++
2548:
2549: Routine Description:
2550:
2551: This routine is called at DISPATCH_LEVEL by the I/O system when the
2552: controller object is free - either directly from AtDiskStartIo(),
2553: or later if the controller object was held at that time.
2554:
2555: The free controller object was allocated on behalf of this IRP just
2556: before calling this routine. So this is the only I/O packet being
2557: processed on this controller. All of the variables in the device
2558: extension for the whole request and for the current transfer are
2559: filled in.
2560:
2561: This routine calls the AtStartDevice() to program the controller to
2562: do the operation. It does so via KeSynchronizeExecution() to avoid
2563: contention with interrupts.
2564:
2565: This routine is protected both by device queue serialization and by
2566: holding the controller object, so it can change variables in both the
2567: device extension and the controller extension. It does not have to
2568: worry about interrupts until after AtStartDevice() is called.
2569:
2570: Arguments:
2571:
2572: DeviceObject - a pointer to the object that represents the device
2573: that I/O is to be done on.
2574:
2575: Irp - a pointer to the I/O Request Packet for this request.
2576:
2577: MapRegisterBase - a reserved pointer.
2578:
2579: Context - a pointer to a record that could have been passed by the
2580: IoAllocateController call.
2581:
2582: Return Value:
2583:
2584: KeepObject is always returned because the controller object needs to
2585: be held while the controller is busy with the command. It will be
2586: released at the end of AtDiskDeferredProcedure().
2587:
2588: --*/
2589:
2590: {
2591: PDISK_EXTENSION diskExtension;
2592:
2593: UNREFERENCED_PARAMETER( Irp );
2594: UNREFERENCED_PARAMETER( MapRegisterBase );
2595: UNREFERENCED_PARAMETER( Context );
2596:
2597: diskExtension = DeviceObject->DeviceExtension;
2598: diskExtension->ControllerExtension->BusyCountDown = START_BUSY_COUNTDOWN;
2599:
2600: //
2601: // Since the controller object is owned, we can program the
2602: // controller. But that must be done via KeSynchronizeExecution, to
2603: // make sure no interrupts come in while we're touching the controller.
2604: //
2605: // AtStartDevice() might return TRUE or FALSE, but in either case we
2606: // just want to exit so we don't have to check the return code.
2607: //
2608:
2609: KeSynchronizeExecution(
2610: diskExtension->ControllerExtension->InterruptObject,
2611: AtStartDevice,
2612: diskExtension );
2613:
2614: return KeepObject;
2615: }
2616:
2617: BOOLEAN
2618: AtStartDevice(
2619: IN OUT PVOID Context
2620: )
2621:
2622: /*++
2623:
2624: Routine Description:
2625:
2626: This routine is called at DIRQL by AtInitiate() and
2627: AtDiskDeferredProcedure() to actually program the operation on the
2628: controller.
2629:
2630: When this routine is called, we don't have to worry about another
2631: processor executing this code or the ISR since it is always called
2632: via KeSynchronizeExecution. We are at DIRQL and we have the
2633: spinlock. Further, the controller object is owned so this is the
2634: only packet being processed on this controller.
2635:
2636: This routine is protected by both device queue serialization and by
2637: holding the controller object (as well as by DIRQL on the current
2638: processor and the interrupt spinlock for other processors), so it
2639: can change variables in both the device extension and the controller
2640: extension and touch the hardware as much as it wants.
2641:
2642: Arguments:
2643:
2644: Context - a pointer to the device extension, passed in by
2645: AtInitiate() when it called KeSynchronizeExecution.
2646:
2647: Return Value:
2648:
2649: Returns TRUE unless the controller hardware fails to respond.
2650:
2651: --*/
2652:
2653: {
2654: PDISK_EXTENSION diskExtension;
2655: PCONTROLLER_EXTENSION controllerExtension;
2656: NTSTATUS ntStatus;
2657: ULONG loopCount = 0;
2658: UCHAR controllerStatus;
2659:
2660: //
2661: // Set up necessary object and extension pointers.
2662: //
2663:
2664: diskExtension = Context;
2665: controllerExtension = diskExtension->ControllerExtension;
2666:
2667: controllerStatus = READ_CONTROLLER(
2668: diskExtension->ControllerExtension->ControllerAddress + STATUS_REGISTER
2669: );
2670:
2671: //
2672: // Make sure that the device isn't busy. It could be busy here
2673: // because power saving features on laptops might have spun
2674: // down the disk.
2675: //
2676:
2677: if (controllerStatus & BUSY_STATUS) {
2678:
2679: controllerExtension->BusyDevice = diskExtension;
2680:
2681: //
2682: // We don't want to let this go on forever though. If the
2683: // device hasn't come back within a minute then reset the controller.
2684: //
2685:
2686: controllerExtension->BusyCountDown--;
2687: if (controllerExtension->BusyCountDown <= 0) {
2688:
2689: controllerExtension->BusyCountDown = START_BUSY_COUNTDOWN;
2690: AtDiskStartReset(diskExtension);
2691:
2692: }
2693: return TRUE;
2694:
2695: } else {
2696:
2697: controllerExtension->BusyCountDown = START_BUSY_COUNTDOWN;
2698: controllerExtension->BusyDevice = NULL;
2699:
2700: }
2701:
2702:
2703: //
2704: // We will soon cause an interrupt that will require servicing by
2705: // the DPC, so set these variables accordingly.
2706: //
2707:
2708: controllerExtension->InterruptRequiresDpc = TRUE;
2709: controllerExtension->WhichDeviceObject = diskExtension->DeviceObject;
2710: controllerExtension->InterruptTimer = START_TIMER;
2711:
2712: AtDump(
2713: ATDIAG2,
2714: ("ATDISK - programming controller with:\n"
2715: " SC: %x\n"
2716: " SN: %x\n"
2717: " CL: %x\n"
2718: " CH: %x\n"
2719: " DH: %x\n",
2720: ( diskExtension->TotalTransferLength /
2721: diskExtension->BytesPerSector ),
2722: ( ( diskExtension->FirstSectorOfTransfer %
2723: diskExtension->SectorsPerTrack ) + 1 ),
2724: ( diskExtension->FirstSectorOfTransfer /
2725: ( diskExtension->SectorsPerTrack *
2726: diskExtension->TracksPerCylinder ) ) & 0xff,
2727: ( diskExtension->FirstSectorOfTransfer /
2728: ( diskExtension->SectorsPerTrack *
2729: diskExtension->TracksPerCylinder ) >> 8 ),
2730: ( CCHAR ) ( ( ( diskExtension->FirstSectorOfTransfer /
2731: diskExtension->SectorsPerTrack ) %
2732: diskExtension->TracksPerCylinder ) |
2733: diskExtension->DeviceUnit )
2734: ) );
2735:
2736:
2737: //
2738: // Program the operation on the controller.
2739: //
2740:
2741: WRITE_CONTROLLER(
2742: controllerExtension->ControllerAddress + SECTOR_COUNT_REGISTER,
2743: ( diskExtension->TotalTransferLength /
2744: diskExtension->BytesPerSector ) );
2745:
2746: WRITE_CONTROLLER(
2747: controllerExtension->ControllerAddress + SECTOR_NUMBER_REGISTER,
2748: ( ( diskExtension->FirstSectorOfTransfer %
2749: diskExtension->SectorsPerTrack ) + 1 ) );
2750:
2751: WRITE_CONTROLLER(
2752: controllerExtension->ControllerAddress + CYLINDER_LOW_REGISTER,
2753: ( diskExtension->FirstSectorOfTransfer /
2754: ( diskExtension->SectorsPerTrack *
2755: diskExtension->TracksPerCylinder ) ) );
2756:
2757: WRITE_CONTROLLER(
2758: controllerExtension->ControllerAddress + CYLINDER_HIGH_REGISTER,
2759: ( diskExtension->FirstSectorOfTransfer /
2760: ( diskExtension->SectorsPerTrack *
2761: diskExtension->TracksPerCylinder ) >> 8 ) );
2762:
2763: WRITE_CONTROLLER(
2764: controllerExtension->ControllerAddress + DRIVE_HEAD_REGISTER,
2765: ( CCHAR ) ( ( ( diskExtension->FirstSectorOfTransfer /
2766: diskExtension->SectorsPerTrack ) %
2767: diskExtension->TracksPerCylinder ) |
2768: diskExtension->DeviceUnit ) );
2769:
2770: switch ( diskExtension->OperationType ) {
2771:
2772: case IRP_MJ_READ: {
2773:
2774: WRITE_CONTROLLER(
2775: controllerExtension->ControllerAddress + COMMAND_REGISTER,
2776: diskExtension->ReadCommand );
2777:
2778: break;
2779: }
2780:
2781: case IRP_MJ_DEVICE_CONTROL: {
2782:
2783: //
2784: // The only way we can get this major code is if the VERIFY
2785: // ioctl called AtDiskDispatchReadWrite().
2786: //
2787:
2788: WRITE_CONTROLLER(
2789: controllerExtension->ControllerAddress + COMMAND_REGISTER,
2790: diskExtension->VerifyCommand );
2791:
2792: break;
2793: }
2794:
2795: case IRP_MJ_WRITE: {
2796:
2797: WRITE_CONTROLLER(
2798: controllerExtension->ControllerAddress + WRITE_PRECOMP_REGISTER,
2799: diskExtension->WritePrecomp );
2800:
2801: WRITE_CONTROLLER(
2802: controllerExtension->ControllerAddress + COMMAND_REGISTER,
2803: diskExtension->WriteCommand );
2804:
2805: //
2806: // We can't put data in the controller cache until it's ready
2807: // (it will turn off the BUSY_STATUS bit and then assert
2808: // DATA_REQUEST_STATUS; there's no interrupt, so we must wait
2809: // for that bit). That may take a long time on systems with
2810: // power saving features, but most systems should be a heck of
2811: // a lot faster.
2812: //
2813:
2814: ntStatus = AtWaitControllerReady( controllerExtension, 10, 5000 );
2815:
2816: //
2817: // Now wait for DATA_REQUEST_STATUS.
2818: //
2819:
2820: if ( NT_SUCCESS( ntStatus ) ) {
2821:
2822: while ( ( !( READ_CONTROLLER(
2823: controllerExtension->ControllerAddress + STATUS_REGISTER ) &
2824: DATA_REQUEST_STATUS ) ) &&
2825: ( loopCount++ < 5000 ) ) {
2826:
2827: //
2828: // Wait for 10us each time; 5000 times will be 50ms.
2829: //
2830:
2831: KeStallExecutionProcessor( 10L );
2832: }
2833:
2834: if ( loopCount >= 5000 ) {
2835: AtDump(
2836: ATERRORS,
2837: ( "AtDisk ERROR: Controller not setting DRQ\n" ));
2838: }
2839:
2840: //
2841: // We might have timed out. Blast ahead anyway - the hardware
2842: // won't interrupt since it won't get all of this information,
2843: // so we'll get a time-out since the timer is running.
2844: //
2845: // Copy the data to the cache. Update the user's address.
2846: //
2847:
2848: ASSERT(diskExtension->BytesPerInterrupt == 512);
2849: if ( loopCount < 5000 ) {
2850:
2851: WRITE_CONTROLLER_BUFFER(
2852: controllerExtension->ControllerAddress + DATA_REGISTER,
2853: diskExtension->CurrentAddress,
2854: diskExtension->BytesPerInterrupt );
2855:
2856: diskExtension->CurrentAddress +=
2857: diskExtension->BytesPerInterrupt;
2858: }
2859: }
2860:
2861: break;
2862: } // IRP_MJ_WRITE
2863:
2864: default: {
2865:
2866: //
2867: // We should never get here; READ or WRITE or VERIFY (via the
2868: // ioctl interface) should be the only possibilities.
2869: //
2870:
2871: AtDump(
2872: ATBUGCHECK,
2873: ("AtDisk ERROR: invalid operation type %x\n",
2874: diskExtension->OperationType ));
2875:
2876: }
2877:
2878: }
2879:
2880: return TRUE;
2881: }
2882:
2883: BOOLEAN
2884: AtDiskInterruptService(
2885: IN PKINTERRUPT Interrupt,
2886: IN OUT PVOID Context
2887: )
2888:
2889: /*++
2890:
2891: Routine Description:
2892:
2893: This routine is called at DIRQL by the system when the controller
2894: interrupts.
2895:
2896: When this routine is called, the timer is running and the controller
2897: object is owned (except at init time, but the DPC won't be invoked
2898: so it doesn't matter).
2899:
2900: It simply reads the status port to keep the controller from
2901: interrupting again, turns off the timer, and (if necessary) queues a
2902: DPC to the real work.
2903:
2904: This routine is protected by device queue serialization and by DIRQL
2905: on the current processor and the interrupt spinlock for other
2906: processors. So it can change variables in both the device extension
2907: and the controller extension and touch the hardware as much as it
2908: wants.
2909:
2910: Arguments:
2911:
2912: Interrupt - a pointer to the interrupt object.
2913:
2914: Context - a pointer to the controller extension (set up by the call
2915: to IoConnectInterrupt in AtInitializeController() ).
2916:
2917: Return Value:
2918:
2919: Normally returns TRUE, but will return FALSE if this interrupt was
2920: not expected.
2921:
2922: --*/
2923:
2924: {
2925: PCONTROLLER_EXTENSION controllerExtension;
2926: PDEVICE_OBJECT whichDeviceObject;
2927: PDISK_EXTENSION diskExtension;
2928: UCHAR controllerStatus;
2929:
2930: UNREFERENCED_PARAMETER( Interrupt );
2931:
2932: controllerExtension = Context;
2933:
2934: //
2935: // Read the controller's status port, which will stop it from interrupting.
2936: // We do this before checking to see whether the interrupt belongs to us
2937: // or not, since the hardware might have had a glitch that caused a
2938: // spurious interrupt.
2939: //
2940:
2941: controllerStatus = READ_CONTROLLER(
2942: controllerExtension->ControllerAddress + STATUS_REGISTER );
2943:
2944: //
2945: // If the interrupt doesn't belong to us (either we weren't expecting
2946: // one, or we were expecting one but our controller is still busy and
2947: // not yet ready to interrupt, or we haven't finished initializing the
2948: // device), return FALSE immediately so the next device in the chain
2949: // can claim it.
2950: //
2951:
2952: if ( ( controllerExtension->InterruptTimer == CANCEL_TIMER ) ||
2953: ( controllerStatus & BUSY_STATUS ) ||
2954: ( !controllerExtension->WhichDeviceObject) ) {
2955:
2956: return FALSE;
2957: }
2958:
2959: //
2960: // We just got the interrupt we expected, so clear the timer.
2961: //
2962:
2963: controllerExtension->InterruptTimer = CANCEL_TIMER;
2964: whichDeviceObject = controllerExtension->WhichDeviceObject;
2965: controllerExtension->WhichDeviceObject = NULL;
2966:
2967: diskExtension = whichDeviceObject->DeviceExtension;
2968:
2969: if ( ( diskExtension->OperationType == IRP_MJ_DEVICE_CONTROL ) &&
2970: ( controllerExtension->ResettingController == RESET_NOT_RESETTING ) ) {
2971:
2972: //
2973: // The VERIFY command only gives one interrupt per transfer,
2974: // rather than one interrupt per sector. Adjust the transfer
2975: // length so that the DPC will end the transfer, and adjust
2976: // the request length so that the DPC will end up reducing
2977: // the request length by the total transfer length.
2978: //
2979:
2980: ASSERT(diskExtension->BytesPerInterrupt == 512);
2981: diskExtension->RemainingRequestLength -=
2982: ( diskExtension->RemainingTransferLength -
2983: diskExtension->BytesPerInterrupt );
2984: diskExtension->RemainingTransferLength =
2985: diskExtension->BytesPerInterrupt;
2986: }
2987:
2988: //
2989: // Queue the DPC to actually do the work, if needed. Be sure to pass
2990: // the device object that caused the interrupt.
2991: //
2992:
2993: if ( controllerExtension->InterruptRequiresDpc ) {
2994:
2995: controllerExtension->InterruptRequiresDpc = FALSE;
2996:
2997: IoRequestDpc(
2998: whichDeviceObject,
2999: whichDeviceObject->CurrentIrp,
3000: ( PVOID )controllerStatus );
3001: }
3002:
3003: return TRUE;
3004: }
3005:
3006: VOID
3007: AtFinishPacket(
3008: IN PDISK_EXTENSION DiskExtension,
3009: IN NTSTATUS NtStatus
3010: )
3011:
3012: /*++
3013:
3014: Routine Description:
3015:
3016: All IRPs that aren't finished in a dispatch routine (that is, those
3017: that go through the StartIo interface) should be finished via this
3018: routine. The next packet (in C-SCAN order, sorted by starting
3019: sector number) will be started, the IoStatus is set to the value
3020: passed in, and the IRP is completed.
3021:
3022: Arguments:
3023:
3024: DiskExtension - a pointer to the device extension of the disk that
3025: just completed an operation.
3026:
3027: NtStatus - the status to complete the IRP with.
3028:
3029: Return Value:
3030:
3031: None.
3032:
3033: --*/
3034:
3035: {
3036: PIRP irp = DiskExtension->DeviceObject->CurrentIrp;
3037: ULONG firstSectorOfRequest;
3038:
3039: //
3040: // Need to pass current cylinder to ISNP so that it knows which
3041: // packet to start next for C-SCAN.
3042: //
3043:
3044: firstSectorOfRequest = DiskExtension->FirstSectorOfRequest;
3045: DiskExtension->FirstSectorOfRequest = MAXULONG;
3046:
3047: IoStartNextPacketByKey(
3048: DiskExtension->DeviceObject,
3049: FALSE,
3050: firstSectorOfRequest );
3051:
3052: irp->IoStatus.Status = NtStatus;
3053:
3054: AtDump(
3055: ATDIAG2,
3056: (
3057: "ATDISK: Finishing Request of Irp: %x\n",
3058: irp
3059: ) );
3060:
3061: //
3062: // For completing read requests we need to flush the io
3063: // buffers.
3064: //
3065:
3066: if (IoGetCurrentIrpStackLocation(irp)->MajorFunction ==
3067: IRP_MJ_READ) {
3068:
3069: KeFlushIoBuffers(
3070: irp->MdlAddress,
3071: TRUE,
3072: FALSE
3073: );
3074:
3075: }
3076:
3077: IoCompleteRequest( irp, IO_DISK_INCREMENT );
3078: }
3079:
3080: VOID
3081: AtDiskDeferredProcedure(
3082: IN PKDPC Dpc,
3083: IN PVOID DeferredContext,
3084: IN PVOID SystemArgument1,
3085: IN PVOID SystemArgument2
3086: )
3087:
3088: /*++
3089:
3090: Routine Description:
3091:
3092: This routine is called at DISPATCH_LEVEL by the system at the
3093: request of AtDiskInterruptService().
3094:
3095: When this routine is called, the controller object is owned so this
3096: procedure can change controller variables and touch the hardware.
3097:
3098: This routine is protected by device queue serialization, so it can
3099: change variables in the device extension. It is protected against
3100: interrupts since it was queued by an interrupt, and the next
3101: interrupt won't occur until something else happens (if there's a
3102: spurious interrupt, the ISR will return without queuing this DPC or
3103: changing any variables).
3104:
3105: This routine can cause another interrupt by reprogramming the
3106: controller, or by filling or emptying the cache. This could cause
3107: us to enter AtDiskInterruptService() and even to reenter this
3108: procedure, so after either of those operations variable usage should
3109: be (and is) avoided.
3110:
3111: This routine performs a number of functions - it helps reset the
3112: drive if there was a time-out, it logs errors, it transfers data to
3113: and from the controller cache, and it completes I/O operations and
3114: gets new ones started.
3115:
3116: Arguments:
3117:
3118: Dpc - a pointer to the DPC object used to invoke this routine.
3119:
3120: DeferredContext - a pointer to the device object associated with this
3121: DPC.
3122:
3123: SystemArgument1 - Actually a pointer to the current irp. We
3124: don't actually use this, as we get it directly from our own
3125: structures.
3126:
3127: SystemArgument2 - the controller status byte, passed to us by
3128: AtDiskInterruptService().
3129:
3130: Return Value:
3131:
3132: None.
3133:
3134: --*/
3135:
3136: {
3137: PDEVICE_OBJECT deviceObject;
3138: PDISK_EXTENSION diskExtension;
3139: PCONTROLLER_EXTENSION controllerExtension;
3140: PIRP irp; // save current IRP for IoCompleteRequest
3141: PIO_STACK_LOCATION irpSp;
3142: NTSTATUS returnStatus; // SUCCESS unless controller error
3143: UCHAR controllerStatus;
3144: BOOLEAN expectingAnInterrupt = FALSE; // TRUE iff we fill/empty the cache
3145: BOOLEAN logTheError = TRUE;
3146: ULONG loopCount = 0;
3147: //
3148: // We capture into the following controller values for logging when
3149: // there is an error.
3150: //
3151: UCHAR errorReg;
3152: UCHAR driveHead;
3153: UCHAR cylHigh;
3154: UCHAR cylLow;
3155: UCHAR sectorNumber;
3156: UCHAR sectorCount;
3157:
3158: UNREFERENCED_PARAMETER( Dpc );
3159: UNREFERENCED_PARAMETER( SystemArgument1 );
3160:
3161: deviceObject = DeferredContext;
3162: diskExtension = deviceObject->DeviceExtension;
3163: controllerExtension = diskExtension->ControllerExtension;
3164:
3165: ASSERT(controllerExtension->InterruptTimer == CANCEL_TIMER);
3166: //
3167: // If the power failed, exit quietly since the notification routine
3168: // will fix the hardware and restart the packet.
3169: //
3170:
3171: if ( controllerExtension->PowerFailed ) {
3172:
3173: return;
3174: }
3175:
3176: //
3177: // We will start another IRP before we complete the current one to
3178: // maximize overlap, so now that we've decided which disk we're working
3179: // on, let's get a pointer to the current IRP. Note that it could
3180: // be NULL if the controller is being reset.
3181: //
3182:
3183: controllerStatus = ( UCHAR ) SystemArgument2;
3184:
3185: //
3186: // If there is some kind of error (or correctable error) then capture the
3187: // register state of the controller
3188: //
3189:
3190: if (controllerStatus & ERROR_STATUS) {
3191:
3192: errorReg = READ_CONTROLLER( controllerExtension->ControllerAddress +
3193: ERROR_REGISTER );
3194: driveHead = READ_CONTROLLER( controllerExtension->ControllerAddress +
3195: DRIVE_HEAD_REGISTER );
3196: cylHigh = READ_CONTROLLER( controllerExtension->ControllerAddress +
3197: CYLINDER_HIGH_REGISTER );
3198: cylLow = READ_CONTROLLER( controllerExtension->ControllerAddress +
3199: CYLINDER_LOW_REGISTER ),
3200: sectorNumber = READ_CONTROLLER( controllerExtension->ControllerAddress +
3201: SECTOR_NUMBER_REGISTER );
3202: sectorCount = READ_CONTROLLER( controllerExtension->ControllerAddress +
3203: SECTOR_COUNT_REGISTER );
3204:
3205: AtDump(
3206: ATERRORS,
3207: ("ATDISK: Error regs that will be given to log\n"
3208: " Error Register: %x\n"
3209: " Drive Head: %x\n"
3210: " Cylinder High: %x\n"
3211: " Cylinder Low: %x\n"
3212: " Sector Number: %x\n"
3213: " Sector Count: %x\n"
3214: " Status: %x\n",
3215: errorReg,
3216: driveHead,
3217: cylHigh,
3218: cylLow,
3219: sectorNumber,
3220: sectorCount,
3221: controllerStatus)
3222: );
3223:
3224: }
3225:
3226: irp = deviceObject->CurrentIrp;
3227:
3228: if ( irp != NULL ) {
3229:
3230: irpSp = IoGetCurrentIrpStackLocation( irp );
3231: }
3232:
3233: //
3234: // If a timer expired, the controller was reset. We may have to set
3235: // drive parameters for a second drive, and/or restart an IRP.
3236: //
3237:
3238: switch ( controllerExtension->ResettingController ) {
3239:
3240: case RESET_NOT_RESETTING: {
3241:
3242: //
3243: // Things are normal; no resetting going on.
3244: //
3245:
3246: break;
3247: }
3248:
3249: case RESET_FIRST_DRIVE_SET: {
3250:
3251: //
3252: // The controller has just been reset, and the failing drive's
3253: // parameters have been set.
3254: //
3255: // Log an error. We couldn't do it in AtCheckTimerSync()
3256: // because that runs at DIRQL.
3257: //
3258:
3259: AtDump(
3260: ATERRORS,
3261: ("ATDISK: Reset the first drive\n")
3262: );
3263:
3264: //
3265: // Nothing should have failed at this point but it
3266: // doesn't hurt to check.
3267: //
3268:
3269: if (controllerStatus & ERROR_STATUS) {
3270:
3271: AtLogError(
3272: deviceObject,
3273: 0,
3274: 0,
3275: 0,
3276: 7,
3277: STATUS_SUCCESS,
3278: IO_ERR_CONTROLLER_ERROR,
3279: ERROR_LOG_TYPE_ERROR,
3280: errorReg,
3281: driveHead,
3282: cylHigh,
3283: cylLow,
3284: sectorNumber,
3285: sectorCount,
3286: controllerStatus
3287: );
3288: logTheError = FALSE;
3289: goto ResetCodePath;
3290:
3291: } else {
3292:
3293: AtLogError(
3294: deviceObject,
3295: ((irp)?(diskExtension->SequenceNumber):(0)),
3296: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
3297: diskExtension->IrpRetryCount,
3298: 1,
3299: STATUS_SUCCESS,
3300: IO_ERR_RESET,
3301: ERROR_LOG_TYPE_TIMEOUT,
3302: 0,
3303: 0,
3304: 0,
3305: 0,
3306: 0,
3307: 0,
3308: 0);
3309:
3310: }
3311:
3312: //
3313: // This is along the reset path. The ATA protocols state
3314: // that the only thing that should have happened here
3315: // is that the busy bit got turned off by the status register
3316: // read. We wouldn't have gotten here if busy was still set
3317: // (The ISR would simply dismiss the interrupt without queueing
3318: // us.)
3319: //
3320: // In any case give the poor disk a little time to calm down.
3321: //
3322:
3323: KeStallExecutionProcessor(25);
3324:
3325: //
3326: // Now recalibrate the first (failing) drive.
3327: //
3328:
3329: controllerExtension->ResettingController =
3330: RESET_FIRST_DRIVE_RECALIBRATED;
3331: controllerExtension->InterruptRequiresDpc = TRUE;
3332: controllerExtension->WhichDeviceObject =
3333: diskExtension->DeviceObject;
3334: AtDump(
3335: ATERRORS,
3336: ("ATDISK: About to recalibrate controller for ext: %x\n"
3337: " with a device unit of: %x\n",
3338: diskExtension,
3339: diskExtension->DeviceUnit)
3340: );
3341: controllerExtension->InterruptTimer = START_TIMER_FOR_RECALIBRATE;
3342:
3343: ( VOID ) AtWaitControllerReady( controllerExtension, 20, 150000 );
3344: WRITE_CONTROLLER(
3345: controllerExtension->ControllerAddress + DRIVE_HEAD_REGISTER,
3346: diskExtension->DeviceUnit
3347: );
3348:
3349: WRITE_CONTROLLER(
3350: controllerExtension->ControllerAddress + COMMAND_REGISTER,
3351: RECALIBRATE_COMMAND );
3352:
3353: return;
3354: }
3355:
3356: case RESET_FIRST_DRIVE_RECALIBRATED: {
3357:
3358: AtDump(
3359: ATERRORS,
3360: ("ATDISK: Recalibrated the first drive\n")
3361: );
3362:
3363: //
3364: // The only thing that could have gone wrong at this
3365: // point (at least according to ATA is that we couldn't
3366: // seek to track 0. Check the status first before we
3367: // go on.
3368: //
3369:
3370: if (controllerStatus & ERROR_STATUS) {
3371:
3372: AtLogError(
3373: deviceObject,
3374: 0,
3375: 0,
3376: 0,
3377: 8,
3378: STATUS_SUCCESS,
3379: IO_ERR_SEEK_ERROR,
3380: ERROR_LOG_TYPE_ERROR,
3381: errorReg,
3382: driveHead,
3383: cylHigh,
3384: cylLow,
3385: sectorNumber,
3386: sectorCount,
3387: controllerStatus
3388: );
3389: logTheError = FALSE;
3390: goto ResetCodePath;
3391:
3392: }
3393:
3394: if ( controllerExtension->Disk2 == NULL ) {
3395:
3396: //
3397: // There's only one drive, and it's ready to go.
3398: //
3399: // We need to restart the packet that was being worked
3400: // on when we timed out. We can't release the controller
3401: // until after we've cleared ResettingController. This
3402: // ensures that we won't get any interrupts (from
3403: // restarting the I/O) until we're ready to leave this
3404: // routine.
3405: //
3406:
3407: if ( irp != NULL ) {
3408:
3409: AtDump(
3410: ATERRORS,
3411: (
3412: "ATDISK: In first controller one drive restart\n"
3413: " Irp of Request: %x\n"
3414: " Starting vmem Address of Transfer: %x\n"
3415: " Ending vmem Address of Transfer: %x\n"
3416: " Length of Transfer: %x\n",
3417: irp,
3418: diskExtension->CurrentAddress,
3419: ((PUCHAR)diskExtension->CurrentAddress)+diskExtension->RemainingRequestLength,
3420: diskExtension->RemainingRequestLength
3421: ) );
3422: AtDump(
3423: ATERRORS,
3424: ("ATDISK - Sector number is: %x\n"
3425: " CHS: %x-%x-%x\n",
3426: diskExtension->FirstSectorOfTransfer,
3427: diskExtension->FirstSectorOfTransfer /
3428: (diskExtension->SectorsPerTrack *
3429: diskExtension->TracksPerCylinder),
3430: (diskExtension->FirstSectorOfTransfer /
3431: diskExtension->SectorsPerTrack) %
3432: diskExtension->TracksPerCylinder,
3433: diskExtension->FirstSectorOfTransfer %
3434: diskExtension->TracksPerCylinder
3435: ) );
3436:
3437: //
3438: // If the disk operation was a verify then don't
3439: // retry. We want this sector to be marked bad
3440: // if verify had a problem with it.
3441: //
3442:
3443: if ( (diskExtension->IrpRetryCount <
3444: RETRY_IRP_MAXIMUM_COUNT) &&
3445: (irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) ) {
3446:
3447: diskExtension->PacketIsBeingRetried = TRUE;
3448: diskExtension->FirstSectorOfRequest = MAXULONG;
3449:
3450: //
3451: // This is along the reset path. This shouldn't
3452: // happen too often. Let's give the poor disk
3453: // a little time to calm down before we hit
3454: // it with another request.
3455: //
3456:
3457: KeStallExecutionProcessor(25);
3458:
3459: AtDiskStartIo( deviceObject, irp );
3460:
3461: } else {
3462:
3463: //
3464: // We've retried too many times. Just return with
3465: // failure.
3466: //
3467:
3468: AtDump(
3469: ATERRORS,
3470: ("AtDisk ERROR: too many retries 1; will fail IRP\n" ));
3471:
3472: AtFinishPacket( diskExtension, STATUS_DISK_RECALIBRATE_FAILED );
3473: }
3474: }
3475:
3476: diskExtension->ControllerExtension->ResettingController =
3477: RESET_NOT_RESETTING;
3478:
3479: IoFreeController( controllerExtension->ControllerObject );
3480:
3481: } else {
3482:
3483: //
3484: // There are two drives; we've just reset the one that
3485: // timed out. Now set the drive params of the other one.
3486: //
3487: // Note that we are about to alter InterruptRequiresDpc,
3488: // ResettingController and InterruptTimer, and we are about
3489: // to write to the hardware. AtCheckTimerSync() and
3490: // AtDiskInterruptService() touch these items, so
3491: // generally we'd say we have to do the following from a
3492: // routine that has been KeSync'd. But it is not necessary
3493: // in this case since no activity is expected - no interrupts
3494: // are currently expected (we've only issued one command since
3495: // resetting the controller, and it has already interrupted),
3496: // so the ISR won't run (even if it does, it will exit
3497: // without doing anything); and further, since InterruptTimer
3498: // isn't set (it was cleared in the ISR) the timer routine
3499: // won't run either. The other disk is waiting for the
3500: // controller object. This operation will cause an
3501: // interrupt, but we exit immediately after causing it
3502: // so there will be no contention problems.
3503: //
3504:
3505: controllerExtension->ResettingController =
3506: RESET_SECOND_DRIVE_SET;
3507: controllerExtension->InterruptRequiresDpc = TRUE;
3508: controllerExtension->WhichDeviceObject =
3509: diskExtension->OtherDiskExtension->DeviceObject;
3510:
3511: //
3512: // This is along the reset path. This shouldn't
3513: // happen too often. Let's give the poor disk
3514: // a little time to calm down before we hit
3515: // it with another request.
3516: //
3517:
3518: KeStallExecutionProcessor(25);
3519:
3520: ( VOID ) AtWaitControllerReady( controllerExtension, 20, 150000 );
3521: WRITE_CONTROLLER(
3522: controllerExtension->ControllerAddress +
3523: DRIVE_HEAD_REGISTER,
3524: ( diskExtension->OtherDiskExtension->DeviceUnit |
3525: ( diskExtension->OtherDiskExtension->TracksPerCylinder
3526: - 1 ) ) );
3527:
3528: WRITE_CONTROLLER(
3529: controllerExtension->ControllerAddress +
3530: SECTOR_COUNT_REGISTER,
3531: diskExtension->OtherDiskExtension->SectorsPerTrack );
3532:
3533: AtDump(
3534: ATERRORS,
3535: ("ATDISK: About to set parms controller for ext: %x\n"
3536: " with a device unit of: %x\n",
3537: diskExtension->OtherDiskExtension,
3538: diskExtension->OtherDiskExtension->DeviceUnit)
3539: );
3540: controllerExtension->InterruptTimer = START_TIMER;
3541: WRITE_CONTROLLER(
3542: controllerExtension->ControllerAddress + COMMAND_REGISTER,
3543: SET_DRIVE_PARAMETERS_COMMAND );
3544: }
3545:
3546: return;
3547: }
3548:
3549: case RESET_SECOND_DRIVE_SET: {
3550:
3551: AtDump(
3552: ATERRORS,
3553: ("ATDISK: Reset second drive\n")
3554: );
3555:
3556: //
3557: // Nothing should have failed at this point but it
3558: // doesn't hurt to check.
3559: //
3560:
3561: if (controllerStatus & ERROR_STATUS) {
3562:
3563: AtDump(
3564: ATERRORS,
3565: ("ATDISK: Error from controller for non-fail parm set - stat: %x\n",
3566: controllerStatus)
3567: );
3568:
3569: AtLogError(
3570: deviceObject,
3571: 0,
3572: 0,
3573: 0,
3574: 9,
3575: STATUS_SUCCESS,
3576: IO_ERR_CONTROLLER_ERROR,
3577: ERROR_LOG_TYPE_ERROR,
3578: errorReg,
3579: driveHead,
3580: cylHigh,
3581: cylLow,
3582: sectorNumber,
3583: sectorCount,
3584: controllerStatus
3585: );
3586: logTheError = FALSE;
3587: goto ResetCodePath;
3588:
3589: } else {
3590:
3591: AtLogError(
3592: deviceObject,
3593: ((irp)?(diskExtension->SequenceNumber):(0)),
3594: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
3595: diskExtension->IrpRetryCount,
3596: 10,
3597: STATUS_SUCCESS,
3598: IO_ERR_RESET,
3599: ERROR_LOG_TYPE_TIMEOUT,
3600: 0,
3601: 0,
3602: 0,
3603: 0,
3604: 0,
3605: 0,
3606: 0);
3607:
3608: }
3609: //
3610: // Now recalibrate the second (ie nonfailing) drive.
3611: //
3612:
3613: controllerExtension->ResettingController =
3614: RESET_SECOND_DRIVE_RECALIBRATED;
3615: controllerExtension->InterruptRequiresDpc = TRUE;
3616: controllerExtension->WhichDeviceObject =
3617: diskExtension->DeviceObject;
3618: AtDump(
3619: ATERRORS,
3620: ("ATDISK: About to recal for non-failing for ext: %x\n"
3621: " with a device unit of: %x\n",
3622: diskExtension,
3623: diskExtension->DeviceUnit)
3624: );
3625:
3626: //
3627: // This is along the reset path. This shouldn't
3628: // happen too often. Let's give the poor disk
3629: // a little time to calm down before we hit
3630: // it with another request.
3631: //
3632:
3633: KeStallExecutionProcessor(25);
3634:
3635:
3636: ( VOID ) AtWaitControllerReady( controllerExtension, 20, 150000 );
3637: WRITE_CONTROLLER(
3638: controllerExtension->ControllerAddress + DRIVE_HEAD_REGISTER,
3639: diskExtension->DeviceUnit
3640: );
3641:
3642: controllerExtension->InterruptTimer = START_TIMER_FOR_RECALIBRATE;
3643: WRITE_CONTROLLER(
3644: controllerExtension->ControllerAddress + COMMAND_REGISTER,
3645: RECALIBRATE_COMMAND );
3646:
3647: return;
3648: }
3649:
3650: case RESET_SECOND_DRIVE_RECALIBRATED: {
3651:
3652: AtDump(
3653: ATERRORS,
3654: ("ATDISK: recalibrated second drive\n")
3655: );
3656:
3657: //
3658: // The only thing that could have gone wrong at this
3659: // point (at least according to ATA) is that we couldn't
3660: // seek to track 0. Check the status first before we
3661: // go on.
3662: //
3663:
3664: if (controllerStatus & ERROR_STATUS) {
3665:
3666: AtDump(
3667: ATERRORS,
3668: ("ATDISK: Error from controller for non-fail recal - stat: %x\n",
3669: controllerStatus)
3670: );
3671: AtLogError(
3672: deviceObject,
3673: 0,
3674: 0,
3675: 0,
3676: 11,
3677: STATUS_SUCCESS,
3678: IO_ERR_SEEK_ERROR,
3679: ERROR_LOG_TYPE_ERROR,
3680: errorReg,
3681: driveHead,
3682: cylHigh,
3683: cylLow,
3684: sectorNumber,
3685: sectorCount,
3686: controllerStatus
3687: );
3688: logTheError = FALSE;
3689: goto ResetCodePath;
3690:
3691: }
3692:
3693: //
3694: // We've reset and recalibrated both drives. So
3695: // now restart the packet that timed out, which was on the OTHER
3696: // drive. Don't clear ResettingController until after we've
3697: // called AtDiskStartIo(), so it knows not to remap the user's
3698: // buffer. And we can't release the controller until after
3699: // we've cleared ResettingController. This also ensures that
3700: // we won't get any interrupts (from restarting the I/O) until
3701: // we're ready to leave this routine.
3702: //
3703:
3704: diskExtension = diskExtension->OtherDiskExtension;
3705: irp = diskExtension->DeviceObject->CurrentIrp;
3706:
3707: if ( irp != NULL ) {
3708:
3709: irpSp = IoGetCurrentIrpStackLocation( irp );
3710: AtDump(
3711: ATERRORS,
3712: (
3713: "ATDISK: In controller two drive restart\n"
3714: " Irp of Request: %x\n"
3715: " Starting vmem Address of Transfer: %x\n"
3716: " Ending vmem Address of Transfer: %x\n"
3717: " Length of Transfer: %x\n",
3718: irp,
3719: diskExtension->CurrentAddress,
3720: ((PUCHAR)diskExtension->CurrentAddress)+diskExtension->RemainingRequestLength,
3721: diskExtension->RemainingRequestLength
3722: ) );
3723: AtDump(
3724: ATERRORS,
3725: ("ATDISK - Sector number is: %x\n"
3726: " CHS: %x-%x-%x\n",
3727: diskExtension->FirstSectorOfTransfer,
3728: diskExtension->FirstSectorOfTransfer /
3729: (diskExtension->SectorsPerTrack *
3730: diskExtension->TracksPerCylinder),
3731: (diskExtension->FirstSectorOfTransfer /
3732: diskExtension->SectorsPerTrack) %
3733: diskExtension->TracksPerCylinder,
3734: diskExtension->FirstSectorOfTransfer %
3735: diskExtension->TracksPerCylinder
3736: ) );
3737:
3738: //
3739: // If the disk operation was a verify then don't
3740: // retry. We want this sector to be marked bad
3741: // if verify had a problem with it.
3742: //
3743:
3744: if ( (diskExtension->IrpRetryCount <
3745: RETRY_IRP_MAXIMUM_COUNT) &&
3746: (irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) ) {
3747:
3748: diskExtension->PacketIsBeingRetried = TRUE;
3749: diskExtension->FirstSectorOfRequest = MAXULONG;
3750:
3751: //
3752: // This is along the reset path. This shouldn't
3753: // happen too often. Let's give the poor disk
3754: // a little time to calm down before we hit
3755: // it with another request.
3756: //
3757:
3758: KeStallExecutionProcessor(25);
3759:
3760: AtDiskStartIo(
3761: diskExtension->DeviceObject,
3762: irp );
3763:
3764: } else {
3765:
3766: AtDump(
3767: ATERRORS,
3768: ("AtDisk ERROR: too many retries 2; will fail IRP\n" ));
3769:
3770: AtFinishPacket( diskExtension, STATUS_DISK_RECALIBRATE_FAILED );
3771: }
3772: }
3773:
3774: diskExtension->ControllerExtension->ResettingController =
3775: RESET_NOT_RESETTING;
3776:
3777: IoFreeController( controllerExtension->ControllerObject );
3778:
3779: return;
3780: }
3781: }
3782:
3783: //
3784: // We want to update the remaining length and fill/empty the cache.
3785: // But if there was an error we don't want to update the remaining
3786: // length, even though we do have to fill/empty the cache.
3787: //
3788:
3789: if ( !( controllerStatus & ERROR_STATUS ) ) {
3790:
3791: ASSERT(diskExtension->BytesPerInterrupt == 512);
3792:
3793: if ((!diskExtension->RemainingTransferLength) ||
3794: (!diskExtension->RemainingRequestLength)) {
3795:
3796: AtLogError(
3797: deviceObject,
3798: ((irp)?(diskExtension->SequenceNumber):(0)),
3799: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
3800: diskExtension->IrpRetryCount,
3801: 12,
3802: STATUS_SUCCESS,
3803: IO_ERR_DRIVER_ERROR,
3804: ERROR_LOG_TYPE_ERROR,
3805: errorReg,
3806: driveHead,
3807: cylHigh,
3808: cylLow,
3809: sectorNumber,
3810: sectorCount,
3811: controllerStatus );
3812: logTheError = FALSE;
3813: controllerStatus |= ERROR_STATUS;
3814: goto ResetCodePath;
3815:
3816: }
3817: diskExtension->RemainingTransferLength -=
3818: diskExtension->BytesPerInterrupt;
3819:
3820: diskExtension->RemainingRequestLength -=
3821: diskExtension->BytesPerInterrupt;
3822:
3823: //
3824: // If there's more to the current transfer, servicing the
3825: // controller cache will cause it to start the next piece,
3826: // causing an interrupt.
3827: //
3828:
3829: if ( diskExtension->RemainingTransferLength > 0 ) {
3830:
3831: //
3832: // Note that we are about to alter InterruptRequiresDpc and
3833: // InterruptTimer. These are altered by
3834: // AtDiskInterruptService() and AtCheckTimerSync(), so
3835: // generally we'd say we have to do the following from a
3836: // routine that has been KeSync'd. But it is not necessary in
3837: // this case since no activity is expected - no interrupts are
3838: // currently expected (not until we empty or fill the buffer,
3839: // below), so the ISR won't run; and since InterruptTimer isn't
3840: // set (since it was cleared in the ISR) the timer routine
3841: // won't run either.
3842: //
3843:
3844: controllerExtension->InterruptRequiresDpc = TRUE;
3845: controllerExtension->WhichDeviceObject =
3846: diskExtension->DeviceObject;
3847: controllerExtension->InterruptTimer = START_TIMER;
3848: expectingAnInterrupt = TRUE;
3849: }
3850:
3851: }
3852:
3853: //
3854: // If this is a READ, we must empty the cache whether there was
3855: // an error or not. For WRITEs, we similarly must fill the cache
3856: // as long as there is more work to be done. Note that it is safe
3857: // to touch the hardware here since the controller won't do
3858: // anything until the buffer has been filled or emptied - so the
3859: // ISR won't run, and the timer won't touch the hardware for at
3860: // least another second (when the timer expires).
3861: //
3862:
3863: switch ( diskExtension->OperationType ) {
3864:
3865: case IRP_MJ_READ: {
3866:
3867: PVOID BufferToReadTo;
3868: BOOLEAN CheckDrq = FALSE;
3869:
3870: if (!diskExtension->RemainingTransferLength) {
3871:
3872: //
3873: // We want to make sure that the DRQ is low when
3874: // we think we are all done with the IO.
3875: //
3876:
3877: CheckDrq = TRUE;
3878:
3879: }
3880:
3881: //
3882: // Get the data that was just read, and update our position in
3883: // the user's buffer. Update before reading the cache, since
3884: // reading the buffer could cause an interrupt to come immediately.
3885: // After emptying the cache, we cannot access the hardware or
3886: // variables since AtDiskInterruptService() or even this routine
3887: // could be trying to access them.
3888: //
3889: // In case of an error we won't update the current address.
3890: //
3891:
3892: ASSERT(diskExtension->BytesPerInterrupt == 512);
3893: if ( !( controllerStatus & ERROR_STATUS ) ) {
3894: BufferToReadTo = diskExtension->CurrentAddress;
3895: diskExtension->CurrentAddress +=
3896: diskExtension->BytesPerInterrupt;
3897: } else {
3898: BufferToReadTo = &controllerExtension->GarbageCan[0];
3899: }
3900:
3901: //
3902: // Wait for DRQ assertion.
3903: //
3904:
3905: while ( ( !( READ_CONTROLLER(
3906: controllerExtension->ControllerAddress + STATUS_REGISTER ) &
3907: DATA_REQUEST_STATUS ) ) &&
3908: ( loopCount++ < 5000 ) ) {
3909:
3910: //
3911: // Wait for 10us each time; 5000 times will be 50ms.
3912: //
3913:
3914: KeStallExecutionProcessor( 10L );
3915: }
3916:
3917: if ( loopCount >= 5000 ) {
3918: AtDump(
3919: ATERRORS,
3920: ( "AtDisk ERROR: Controller not setting DRQ\n" ));
3921: controllerStatus &= ERROR_STATUS;
3922: AtLogError(
3923: deviceObject,
3924: ((irp)?(diskExtension->SequenceNumber):(0)),
3925: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
3926: diskExtension->IrpRetryCount,
3927: 13,
3928: STATUS_SUCCESS,
3929: IO_ERR_CONTROLLER_ERROR,
3930: ERROR_LOG_TYPE_ERROR,
3931: errorReg,
3932: driveHead,
3933: cylHigh,
3934: cylLow,
3935: sectorNumber,
3936: sectorCount,
3937: controllerStatus );
3938: logTheError = FALSE;
3939: controllerStatus |= ERROR_STATUS;
3940: goto ResetCodePath;
3941:
3942: }
3943:
3944: READ_CONTROLLER_BUFFER(
3945: controllerExtension->ControllerAddress + DATA_REGISTER,
3946: BufferToReadTo,
3947: diskExtension->BytesPerInterrupt );
3948:
3949: if (CheckDrq) {
3950:
3951: if (NT_SUCCESS(AtWaitControllerReady(controllerExtension,
3952: 10,
3953: 5000
3954: ))) {
3955:
3956: if (READ_CONTROLLER(
3957: controllerExtension->ControllerAddress + STATUS_REGISTER ) &
3958: DATA_REQUEST_STATUS ) {
3959:
3960: AtLogError(
3961: deviceObject,
3962: ((irp)?(diskExtension->SequenceNumber):(0)),
3963: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
3964: diskExtension->IrpRetryCount,
3965: 14,
3966: STATUS_SUCCESS,
3967: IO_ERR_OVERRUN_ERROR,
3968: ERROR_LOG_TYPE_ERROR,
3969: errorReg,
3970: driveHead,
3971: cylHigh,
3972: cylLow,
3973: sectorNumber,
3974: sectorCount,
3975: controllerStatus );
3976: logTheError = FALSE;
3977: controllerStatus |= ERROR_STATUS;
3978: goto ResetCodePath;
3979: }
3980:
3981: } else {
3982:
3983: AtLogError(
3984: deviceObject,
3985: ((irp)?(diskExtension->SequenceNumber):(0)),
3986: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
3987: diskExtension->IrpRetryCount,
3988: 15,
3989: STATUS_SUCCESS,
3990: IO_ERR_CONTROLLER_ERROR,
3991: ERROR_LOG_TYPE_ERROR,
3992: errorReg,
3993: driveHead,
3994: cylHigh,
3995: cylLow,
3996: sectorNumber,
3997: sectorCount,
3998: controllerStatus );
3999: logTheError = FALSE;
4000: controllerStatus |= ERROR_STATUS;
4001: goto ResetCodePath;
4002:
4003: }
4004:
4005: }
4006:
4007: break;
4008: }
4009:
4010: case IRP_MJ_WRITE: {
4011:
4012: PVOID BufferToWriteFrom;
4013:
4014: if (!diskExtension->RemainingTransferLength) {
4015:
4016: if (NT_SUCCESS(AtWaitControllerReady(controllerExtension,
4017: 10,
4018: 5000
4019: ))) {
4020:
4021: if (READ_CONTROLLER(
4022: controllerExtension->ControllerAddress + STATUS_REGISTER ) &
4023: DATA_REQUEST_STATUS ) {
4024:
4025: AtLogError(
4026: deviceObject,
4027: ((irp)?(diskExtension->SequenceNumber):(0)),
4028: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
4029: diskExtension->IrpRetryCount,
4030: 16,
4031: STATUS_SUCCESS,
4032: IO_ERR_OVERRUN_ERROR,
4033: ERROR_LOG_TYPE_ERROR,
4034: errorReg,
4035: driveHead,
4036: cylHigh,
4037: cylLow,
4038: sectorNumber,
4039: sectorCount,
4040: controllerStatus );
4041: logTheError = FALSE;
4042: controllerStatus |= ERROR_STATUS;
4043: goto ResetCodePath;
4044: }
4045: } else {
4046:
4047: AtLogError(
4048: deviceObject,
4049: ((irp)?(diskExtension->SequenceNumber):(0)),
4050: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
4051: diskExtension->IrpRetryCount,
4052: 17,
4053: STATUS_SUCCESS,
4054: IO_ERR_CONTROLLER_ERROR,
4055: ERROR_LOG_TYPE_ERROR,
4056: errorReg,
4057: driveHead,
4058: cylHigh,
4059: cylLow,
4060: sectorNumber,
4061: sectorCount,
4062: controllerStatus );
4063: logTheError = FALSE;
4064: controllerStatus |= ERROR_STATUS;
4065: goto ResetCodePath;
4066:
4067: }
4068:
4069: }
4070:
4071: //
4072: // IFF there is more to write, fill the sector cache and update
4073: // our position in the user's buffer. Update before writing the
4074: // cache, since writing the buffer could cause an interrupt to
4075: // come immediately.
4076: // After emptying the cache, we cannot access the hardware or
4077: // variables since AtDiskInterruptService() or even this routine
4078: // could be trying to access them.
4079: //
4080:
4081: if ( diskExtension->RemainingTransferLength > 0 ) {
4082:
4083: ASSERT(diskExtension->BytesPerInterrupt == 512);
4084: if ( !( controllerStatus & ERROR_STATUS ) ) {
4085: BufferToWriteFrom = diskExtension->CurrentAddress;
4086: diskExtension->CurrentAddress += diskExtension->BytesPerInterrupt;
4087: } else {
4088: BufferToWriteFrom = &controllerExtension->GarbageCan[0];
4089: }
4090:
4091: WRITE_CONTROLLER_BUFFER(
4092: controllerExtension->ControllerAddress + DATA_REGISTER,
4093: BufferToWriteFrom,
4094: diskExtension->BytesPerInterrupt );
4095: }
4096:
4097: break;
4098: }
4099:
4100: case IRP_MJ_DEVICE_CONTROL: {
4101:
4102: //
4103: // This is a VERIFY ioctl. There's nothing to do.
4104: //
4105:
4106: break;
4107: }
4108: }
4109:
4110: //
4111: // If there was a correctable error, then log it. But operations
4112: // should continue normally.
4113: //
4114:
4115: if ( controllerStatus & CORRECTED_ERROR_STATUS ) {
4116:
4117: AtDump(
4118: ATERRORS,
4119: (
4120: "ATDISK *******CORRECTABLE ERROR***********: Continueing Operation\n") );
4121: AtLogError(
4122: deviceObject,
4123: ((irp)?(diskExtension->SequenceNumber):(0)),
4124: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
4125: diskExtension->IrpRetryCount,
4126: 2,
4127: STATUS_SUCCESS,
4128: IO_ERR_RETRY_SUCCEEDED,
4129: ERROR_LOG_TYPE_ERROR,
4130: errorReg,
4131: driveHead,
4132: cylHigh,
4133: cylLow,
4134: sectorNumber,
4135: sectorCount,
4136: controllerStatus
4137: );
4138:
4139: }
4140:
4141: //
4142: // If there was a non-correctable error, then log it and make sure
4143: // we return the error status.
4144: //
4145: ResetCodePath:;
4146: returnStatus = STATUS_SUCCESS;
4147:
4148: if ( controllerStatus & ERROR_STATUS ) {
4149:
4150: AtDump(
4151: ATERRORS,
4152: (
4153: "ATDISK: In deferred irp recovery\n"
4154: " Irp of Request: %x\n"
4155: " Starting vmem Address of Transfer: %x\n"
4156: " Ending vmem Address of Transfer: %x\n"
4157: " Length of Transfer: %x\n",
4158: irp,
4159: diskExtension->CurrentAddress,
4160: ((PUCHAR)diskExtension->CurrentAddress)+diskExtension->RemainingRequestLength,
4161: diskExtension->RemainingRequestLength
4162: ) );
4163: AtDump(
4164: ATERRORS,
4165: ("ATDISK - Sector number is: %x\n"
4166: " CHS: %x-%x-%x\n",
4167: diskExtension->FirstSectorOfTransfer,
4168: diskExtension->FirstSectorOfTransfer /
4169: (diskExtension->SectorsPerTrack *
4170: diskExtension->TracksPerCylinder),
4171: (diskExtension->FirstSectorOfTransfer /
4172: diskExtension->SectorsPerTrack) %
4173: diskExtension->TracksPerCylinder,
4174: diskExtension->FirstSectorOfTransfer %
4175: diskExtension->TracksPerCylinder
4176: ) );
4177: AtDump(
4178: ATERRORS,
4179: ("AtDisk ******ERROR******: Disk error encountered - will retry %d more times.\n",RETRY_IRP_MAXIMUM_COUNT - diskExtension->IrpRetryCount));
4180:
4181: //
4182: // See if we've already exceeded the retry count on the
4183: // irp. If we haven't then retry it. Otherwise, fail
4184: // the request.
4185: //
4186:
4187: if ( diskExtension->IrpRetryCount < RETRY_IRP_MAXIMUM_COUNT ) {
4188:
4189: if (logTheError) {
4190:
4191: AtLogError(
4192: deviceObject,
4193: ((irp)?(diskExtension->SequenceNumber):(0)),
4194: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
4195: diskExtension->IrpRetryCount,
4196: 4,
4197: STATUS_SUCCESS,
4198: IO_ERR_CONTROLLER_ERROR,
4199: ERROR_LOG_TYPE_ERROR,
4200: errorReg,
4201: driveHead,
4202: cylHigh,
4203: cylLow,
4204: sectorNumber,
4205: sectorCount,
4206: controllerStatus );
4207:
4208: }
4209:
4210: //
4211: // Every time we get an error on the device, we
4212: // might as well reset it. This will hopefully
4213: // increase the chances that the io will succeed
4214: // this time.
4215: //
4216: // NOTE NOTE: This next call will almost certainly
4217: // cause an interrupt, and cause this
4218: // DPC to be re-entered. We aren't
4219: // doing anything after the call.
4220: //
4221:
4222: KeSynchronizeExecution(
4223: controllerExtension->InterruptObject,
4224: AtDiskStartReset,
4225: diskExtension
4226: );
4227:
4228: return;
4229:
4230: } else {
4231:
4232: KdPrint(("ATDISK: Disk Controller still fails after %d retries - FAILING operation\n",RETRY_IRP_MAXIMUM_COUNT));
4233:
4234: AtLogError(
4235: deviceObject,
4236: ((irp)?(diskExtension->SequenceNumber):(0)),
4237: (UCHAR)((irp)?(irpSp->MajorFunction):(0)),
4238: diskExtension->IrpRetryCount,
4239: 5,
4240: STATUS_DISK_OPERATION_FAILED,
4241: IO_ERR_CONTROLLER_ERROR,
4242: ERROR_LOG_TYPE_ERROR,
4243: errorReg,
4244: driveHead,
4245: cylHigh,
4246: cylLow,
4247: sectorNumber,
4248: sectorCount,
4249: controllerStatus);
4250:
4251: returnStatus = STATUS_DISK_OPERATION_FAILED;
4252:
4253: }
4254:
4255: }
4256:
4257: //
4258: // If we have finished the current transfer but there's more remaining
4259: // in the request, then go program the controller to do the next
4260: // transfer. Note that this code is only executed if we do NOT
4261: // expect an interrupt due to cache emptying or filling; so we do not
4262: // have to worry about contention with AtDiskInterruptService() or
4263: // reentry to this routine.
4264: //
4265:
4266: if ( ( returnStatus == STATUS_SUCCESS ) &&
4267: ( !expectingAnInterrupt ) &&
4268: ( diskExtension->RemainingRequestLength != 0 ) ) {
4269:
4270: //
4271: // First calculate starting sector and length of the new transfer.
4272: //
4273:
4274: diskExtension->FirstSectorOfTransfer +=
4275: diskExtension->TotalTransferLength >>
4276: diskExtension->ByteShiftToSector;
4277:
4278: //
4279: // If possible, this transfer should be the same length as the
4280: // request. However, it is limited to MAX_SEC_TO_TRANS sectors.
4281: //
4282:
4283: if ( diskExtension->RemainingRequestLength >
4284: ( ULONG )( diskExtension->BytesPerSector * MAX_SEC_TO_TRANS ) ) {
4285:
4286: diskExtension->TotalTransferLength =
4287: diskExtension->BytesPerSector * MAX_SEC_TO_TRANS;
4288:
4289: } else {
4290:
4291: diskExtension->TotalTransferLength =
4292: diskExtension->RemainingRequestLength;
4293: }
4294:
4295: diskExtension->RemainingTransferLength =
4296: diskExtension->TotalTransferLength;
4297:
4298:
4299: //
4300: // Give the poor disk some time to calm down between requests.
4301: //
4302:
4303: KeStallExecutionProcessor(100);
4304:
4305: //
4306: // No need to check whether TRUE or FALSE is returned, since we're
4307: // going to return with no value in either case. If it didn't
4308: // work due to power failure or a time-out, the controller reset
4309: // code will restart the packet for us.
4310: //
4311:
4312: KeSynchronizeExecution(
4313: controllerExtension->InterruptObject,
4314: AtStartDevice,
4315: diskExtension );
4316:
4317: return;
4318: } // transfer done, but request isn't
4319:
4320: //
4321: // If there was an error or the transfer is done, then
4322: // set status and info
4323: // deallocate controller
4324: // start next packet
4325: // complete I/O request
4326: // Note that if we filled or emptied the cache and are expecting an
4327: // interrupt, we will not execute this code. This way we do not have
4328: // to worry about RemainingRequestLength having been changed by an
4329: // instance of this routine queued by an interrupt we caused. (Note
4330: // that filling or emptying the cache does NOT cause an interrupt if
4331: // there was an error, which is why the IF statement checks for error
4332: // before checking to see if we're expecting an interrupt).
4333: //
4334:
4335: if ( ( returnStatus == STATUS_DISK_OPERATION_FAILED ) ||
4336: ( !expectingAnInterrupt ) &&
4337: ( diskExtension->RemainingRequestLength == 0 ) ) {
4338:
4339: if ( returnStatus == STATUS_SUCCESS ) {
4340:
4341: //
4342: // Success. Note that all of the data was transferred.
4343: //
4344:
4345: deviceObject->CurrentIrp->IoStatus.Information =
4346: irpSp->Parameters.Read.Length;
4347:
4348: } else {
4349:
4350: //
4351: // There was an error, so not all of the data was transferred.
4352: // Let the user know how much data WAS transferred before the
4353: // error. Variables like RemainingTransferLength might be
4354: // incorrect, since controller buffering might mean that we
4355: // didn't get an error on sector N until long after we've passed
4356: // it. So instead, we add the amount moved in previous transfers
4357: // of this request (the starting sector of the current transfer
4358: // minus the original starting sector, all times bytes per sector)
4359: // to the amount moved in the current transfer (the transfer length
4360: // minus the length after the sector with the error).
4361: //
4362:
4363: deviceObject->CurrentIrp->IoStatus.Information =
4364:
4365: ( ( diskExtension->FirstSectorOfTransfer -
4366: RtlLargeIntegerShiftRight(
4367: irpSp->Parameters.Read.ByteOffset,
4368: diskExtension->ByteShiftToSector ).LowPart ) >>
4369: diskExtension->ByteShiftToSector ) +
4370:
4371: ( diskExtension->TotalTransferLength -
4372: ( READ_CONTROLLER( controllerExtension->ControllerAddress +
4373: SECTOR_COUNT_REGISTER ) << diskExtension->ByteShiftToSector ) );
4374: }
4375:
4376: //
4377: // Since this operation is done, the controller object can be
4378: // released and the next operation can be started.
4379: //
4380:
4381: IoFreeController( controllerExtension->ControllerObject );
4382:
4383: AtFinishPacket( diskExtension, returnStatus );
4384: } // request done or error encountered
4385: }
4386:
4387: BOOLEAN
4388: AtDiskStartReset(
4389: IN PVOID Context
4390: )
4391:
4392: /*++
4393:
4394: Routine Description:
4395:
4396: This routine is used to start off the reset cycle for the controller.
4397: It is called at DIRQL.
4398:
4399: Arguments:
4400:
4401: Context - A pointer to the device extension for the "failing" drive.
4402:
4403: Return Value:
4404:
4405: Always FALSE.
4406:
4407: --*/
4408:
4409: {
4410:
4411: PDISK_EXTENSION diskExtension = Context;
4412: PCONTROLLER_EXTENSION controllerExtension =
4413: diskExtension->ControllerExtension;
4414:
4415: AtDump(
4416: ATERRORS,
4417: ("ATDISK: Starting reset with failing extension: %x\n",diskExtension));
4418: //
4419: // Let it Be Known that we are resetting the controller.
4420: //
4421:
4422: controllerExtension->ResettingController = RESET_FIRST_DRIVE_SET;
4423:
4424: //
4425: // Reset the controller, since its state isn't what we expect.
4426: // Wait up to 2 seconds between writes to the control port.
4427: // Normally we don't like to wait at DIRQL, but this won't generate
4428: // an interrupt and 10us isn't so bad.
4429: //
4430:
4431: WRITE_CONTROLLER(
4432: controllerExtension->ControlPortAddress,
4433: RESET_CONTROLLER );
4434:
4435: AtWaitControllerBusy(
4436: controllerExtension->ControllerAddress + STATUS_REGISTER,
4437: 20,
4438: 75000
4439: );
4440:
4441: WRITE_CONTROLLER(
4442: controllerExtension->ControlPortAddress,
4443: ( ENABLE_INTERRUPTS | controllerExtension->ControlFlags ) );
4444:
4445: //
4446: // Every controller reset must be followed by setting the drive
4447: // parameters of all attached drives. This DOES cause an
4448: // interrupt.
4449: //
4450:
4451: controllerExtension->InterruptRequiresDpc = TRUE;
4452: controllerExtension->InterruptTimer = START_TIMER;
4453: controllerExtension->WhichDeviceObject = diskExtension->DeviceObject;
4454:
4455: //
4456: // Before we write to the controller, wait until we're sure it's
4457: // not still busy setting itself up. We don't like waiting here,
4458: // but there's no interrupt to wait on, the wait should be very
4459: // short, and this code is only executed if the hardware gets
4460: // messed up. If it's not ready after 3 seconds, just blast ahead...
4461: // the operation won't work, but it will time out and be handled
4462: // later. Note that we ordinarily don't want to wait this long
4463: // in a driver, but we don't wait longer than we have to and we
4464: // may just have to. This isn't an ordinary event.
4465: //
4466:
4467: ( VOID ) AtWaitControllerReady( controllerExtension, 20, 150000 );
4468:
4469: WRITE_CONTROLLER(
4470: controllerExtension->ControllerAddress + DRIVE_HEAD_REGISTER,
4471: ( diskExtension->DeviceUnit |
4472: ( diskExtension->TracksPerCylinder - 1 ) ) );
4473:
4474: WRITE_CONTROLLER(
4475: controllerExtension->ControllerAddress + SECTOR_COUNT_REGISTER,
4476: diskExtension->SectorsPerTrack );
4477:
4478: WRITE_CONTROLLER(
4479: controllerExtension->ControllerAddress + COMMAND_REGISTER,
4480: SET_DRIVE_PARAMETERS_COMMAND );
4481:
4482: //
4483: // When the interrupt comes, the DPC will see ResettingController
4484: // and take care of setting parameters on the second drive and
4485: // restarting any packets that were in progress.
4486: //
4487:
4488: return FALSE;
4489: }
4490:
4491: VOID
4492: AtDiskUnloadDriver(
4493: IN PDRIVER_OBJECT DriverObject
4494: )
4495:
4496: /*++
4497:
4498: Routine Description:
4499:
4500: This routine is called by the system to remove the driver from memory.
4501:
4502: When this routine is called, there is no I/O being done to this device.
4503: The driver object is passed in, and from this the driver can find and
4504: delete all of its device objects, extensions, etc.
4505:
4506: BUGBUG this routine only deletes one controller, but deletes all device
4507: objects. We need to figure out how unload will work.
4508:
4509: Arguments:
4510:
4511: DriverObject - a pointer to the object associated with this device
4512: driver.
4513:
4514: Return Value:
4515:
4516: None.
4517:
4518: --*/
4519:
4520: {
4521: PCONTROLLER_EXTENSION controllerExtension;
4522: PDEVICE_OBJECT deviceObject, oldDeviceObject;
4523: PDISK_EXTENSION diskExtension;
4524:
4525: deviceObject = DriverObject->DeviceObject;
4526: diskExtension = deviceObject->DeviceExtension;
4527: controllerExtension = diskExtension->Partition0->ControllerExtension;
4528:
4529: //
4530: // First, get rid of the controller objects and associated items in
4531: // the controller extension.
4532: // The timer is stored in the device object of the first disk out of
4533: // necessity, but is a per-controller object.
4534: //
4535:
4536: IoStopTimer( controllerExtension->Disk1->DeviceObject );
4537: IoDisconnectInterrupt( controllerExtension->InterruptObject );
4538: IoDeleteController( controllerExtension->ControllerObject );
4539:
4540: //
4541: // Now follow the I/O system's chain of device objects. This will
4542: // include device objects (associated with partition 0) and "partition"
4543: // objects (associated with partition N, for N != 0). Deleting the
4544: // objects will automatically delete the extensions as well, regardless
4545: // of their type.
4546: //
4547:
4548: do {
4549:
4550: diskExtension = ( PDISK_EXTENSION )( deviceObject + 1 );
4551:
4552: //
4553: // If this extension is partition 0, then it has the handle to the
4554: // device directory. Close the handle to get rid of the directory
4555: // (which was made to be temporary).
4556: //
4557:
4558: if ( diskExtension->Partition0 == diskExtension ) {
4559:
4560: ZwClose( diskExtension->DirectoryHandle );
4561: }
4562:
4563: oldDeviceObject = deviceObject;
4564: deviceObject = oldDeviceObject->NextDevice;
4565: IoDeleteDevice( oldDeviceObject );
4566:
4567: } while ( deviceObject != NULL );
4568: }
4569:
4570: VOID
4571: AtDiskCheckTimer(
4572: IN PDEVICE_OBJECT DeviceObject,
4573: IN OUT PVOID Context
4574: )
4575:
4576: /*++
4577:
4578: Routine Description:
4579:
4580: This routine is called at DISPATCH_LEVEL once every second by the
4581: I/O system.
4582:
4583: If the timer is "set" (greater than 0) this routine will KeSync a
4584: routine to decrement it. If it ever reaches 0, the hardware is
4585: assumed to be in an unknown state, and so we log an error and
4586: initiate a reset.
4587:
4588: If a timeout occurs while resetting the controller, the KeSync'd
4589: routine will return an error, and this routine will fail any IRPs
4590: currently being processed. Future IRPs will try the hardware again.
4591:
4592: When this routine is called, the driver state is impossible to
4593: predict. However, when it is called and the timer is running, we
4594: know that one of the disks on the controller is expecting an
4595: interrupt. So no new packets are starting on the current disk due
4596: to device queues, and no code should be processing this packet since
4597: the packet is waiting for an interrupt.
4598:
4599: Arguments:
4600:
4601: DeviceObject - a pointer to the device object associated with this
4602: timer (always the first disk on the controller).
4603:
4604: ControllerExtension - a pointer to the controller extension data.
4605:
4606: Return Value:
4607:
4608: None.
4609:
4610: --*/
4611:
4612: {
4613: PCONTROLLER_EXTENSION controllerExtension;
4614: PDISK_EXTENSION diskExtension;
4615:
4616: UNREFERENCED_PARAMETER( DeviceObject );
4617:
4618: controllerExtension = Context;
4619:
4620: //
4621: // If the BusyOnStartDevice is true, then we KNOW that the counter below
4622: // is minus 1. We trust that hardware will reset the busy bit at some
4623: // time in the near future. We check to see if the pointer is non-NULL.
4624: // If it is !NULL then the ONLY way it will get set back to NULL is
4625: // by THIS routine calling AtStartDevice and having start device clear
4626: // the pointer and "restart" the IO. We don't need to proceed with this
4627: // timer routine if the pointer was !NULL because nothing could have
4628: // been happening.
4629: //
4630:
4631: if (controllerExtension->BusyDevice) {
4632:
4633: KeSynchronizeExecution(
4634: controllerExtension->InterruptObject,
4635: AtStartDevice,
4636: controllerExtension->BusyDevice );
4637:
4638: return;
4639:
4640: }
4641:
4642: //
4643: // When the counter is -1, the timer is "off" so we don't want to do
4644: // anything. If it's on, we'll have to synchronize execution with
4645: // other routines while we mess with the variables (and, potentially,
4646: // the hardware).
4647: //
4648:
4649: if ( controllerExtension->InterruptTimer == CANCEL_TIMER ) {
4650:
4651: return;
4652: }
4653:
4654: //
4655: // In the unlikely event that we attempt to reset the controller due
4656: // to a timeout AND that reset times out, we will need to fail the
4657: // IRP that was in progress at the first timeout occurred.
4658: // WhichDeviceObject might be different when the second timeout occurs,
4659: // so we save it here. Note that this routine can't, in general, alter
4660: // controller extension variables; however, FirstFailingDeviceObject
4661: // is safe since this is the only routine that touches it.
4662: //
4663:
4664: if ( controllerExtension->ResettingController == RESET_NOT_RESETTING ) {
4665:
4666: controllerExtension->FirstFailingDeviceObject =
4667: controllerExtension->WhichDeviceObject;
4668: }
4669:
4670: if ( !(KeSynchronizeExecution(
4671: controllerExtension->InterruptObject,
4672: AtCheckTimerSync,
4673: controllerExtension ) ) ) {
4674:
4675: UCHAR MajorFunctionCode = 0;
4676:
4677: diskExtension =
4678: controllerExtension->FirstFailingDeviceObject->DeviceExtension;
4679:
4680: if ( controllerExtension->FirstFailingDeviceObject->CurrentIrp ) {
4681:
4682: MajorFunctionCode =
4683: IoGetCurrentIrpStackLocation(
4684: controllerExtension->FirstFailingDeviceObject->CurrentIrp
4685: )->MajorFunction;
4686:
4687: }
4688:
4689: //
4690: // AtCheckTimerSync() only returns false if we get a timeout
4691: // while resetting the controller. This will probably never
4692: // happen. But just in case, fail the current IRP. Future
4693: // IRPs will probably do the same thing, unless the hardware
4694: // suddenly straightens itself out.
4695: //
4696:
4697: AtDump(
4698: ATERRORS,
4699: ( "AtDisk ERROR: time-out during reset, failing IRP\n" ));
4700:
4701: AtLogError(
4702: controllerExtension->FirstFailingDeviceObject,
4703: diskExtension->SequenceNumber,
4704: MajorFunctionCode,
4705: diskExtension->IrpRetryCount,
4706: 6,
4707: STATUS_DISK_RESET_FAILED,
4708: IO_ERR_TIMEOUT,
4709: ERROR_LOG_TYPE_TIMEOUT_DURING_RESET,
4710: 0,
4711: 0,
4712: 0,
4713: 0,
4714: 0,
4715: 0,
4716: 0);
4717:
4718:
4719: //
4720: // We're done with the reset. Return the IRP that was being
4721: // processed with an error, and release the controller object.
4722: //
4723:
4724: if ( controllerExtension->FirstFailingDeviceObject->CurrentIrp !=
4725: NULL ) {
4726:
4727: AtFinishPacket( diskExtension, STATUS_DISK_RESET_FAILED );
4728: }
4729:
4730: controllerExtension->ResettingController = RESET_NOT_RESETTING;
4731:
4732: IoFreeController( controllerExtension->ControllerObject );
4733: }
4734: }
4735:
4736: BOOLEAN
4737: AtCheckTimerSync(
4738: IN OUT PVOID Context
4739: )
4740:
4741: /*++
4742:
4743: Routine Description:
4744:
4745: This routine is called at DIRQL by AtDiskCheckTimer() when
4746: InterruptTimer is greater than 0.
4747:
4748: If the timer is "set" (greater than 0) this routine will decrement
4749: it. If it ever reaches 0, the hardware is assumed to be in an
4750: unknown state, and so we log an error and initiate a reset.
4751:
4752: When this routine is called, the driver state is impossible to
4753: predict. However, when it is called and the timer is running, we
4754: know that one of the disks on the controller is expecting an
4755: interrupt. So, no new packets are starting on the current disk due
4756: to device queues, and no code should be processing this packet since
4757: the packet is waiting for an interrupt. The controller object must
4758: be held.
4759:
4760: Arguments:
4761:
4762: Context - a pointer to the controller extension.
4763:
4764: Return Value:
4765:
4766: Generally TRUE.
4767:
4768: FALSE is only returned if the controller timed out while resetting
4769: the drive, so this means that the hardware state is unknown.
4770:
4771: --*/
4772:
4773: {
4774: PCONTROLLER_EXTENSION controllerExtension;
4775: PDISK_EXTENSION diskExtension;
4776:
4777: controllerExtension = Context;
4778:
4779: //
4780: // When the counter is -1, the timer is "off" so we don't want to do
4781: // anything. It may have changed since we last checked it in
4782: // AtDiskCheckTimer().
4783: //
4784:
4785: if ( controllerExtension->InterruptTimer == CANCEL_TIMER ) {
4786:
4787: return TRUE;
4788: }
4789:
4790: //
4791: // The timer is "on", so decrement it.
4792: //
4793:
4794: controllerExtension->InterruptTimer--;
4795:
4796: //
4797: // If we hit zero, the timer has expired and we'll reset the
4798: // controller.
4799: //
4800:
4801: if ( controllerExtension->InterruptTimer == EXPIRED_TIMER ) {
4802:
4803: //
4804: // Make sure that we're working with the device extension of the
4805: // drive that timed out. The device extension of Disk1 was passed
4806: // in.
4807: //
4808:
4809: diskExtension = controllerExtension->WhichDeviceObject->DeviceExtension;
4810:
4811: //
4812: // If we were ALREADY resetting the controller when it timed out,
4813: // there's something seriously wrong.
4814: //
4815:
4816: if ( controllerExtension->ResettingController != RESET_NOT_RESETTING ) {
4817:
4818: //
4819: // Returning FALSE will cause the current IRP to be completed
4820: // with an error. Future IRPs will probably get a timeout and
4821: // attempt to reset the controller again. This will probably
4822: // never happen.
4823: //
4824:
4825: controllerExtension->InterruptTimer = CANCEL_TIMER;
4826: return FALSE;
4827: }
4828:
4829: AtDiskStartReset(diskExtension);
4830:
4831: } // timer expired
4832:
4833: return TRUE;
4834: }
4835:
4836: NTSTATUS
4837: AtWaitControllerReady(
4838: PCONTROLLER_EXTENSION ControllerExtension,
4839: ULONG MicrosecondsToDelay,
4840: ULONG TimesToDelay
4841: )
4842:
4843: /*++
4844:
4845: Routine Description:
4846:
4847: This routine waits for the hard disk controller to turn off the BUSY
4848: bit in the status register.
4849:
4850: It waits any number of times (TimesToDelay) for any number of
4851: microseconds (MicroSecondsToDelay). In between waits, it checks to
4852: see if the busy bit has been turned off. If so, it returns early.
4853:
4854: Arguments:
4855:
4856: ControllerExtension - a pointer to the data area for the hard disk
4857: controller in question.
4858:
4859: MicrosecondsToDelay - the number of microseconds to delay each time
4860:
4861: TimesToDelay - the number of times to delay
4862:
4863: Return Value:
4864:
4865: STATUS_SUCCESS if the BUSY bit was turned off; STATUS_TIMEOUT if the
4866: BUSY bit was still on when we finished waiting.
4867:
4868: --*/
4869:
4870: {
4871: ULONG loopCount = 0;
4872:
4873: while ( ( READ_CONTROLLER(
4874: ControllerExtension->ControllerAddress + STATUS_REGISTER ) &
4875: BUSY_STATUS ) &&
4876: ( loopCount++ < TimesToDelay ) ) {
4877:
4878: KeStallExecutionProcessor( MicrosecondsToDelay );
4879: }
4880:
4881: if ( loopCount == TimesToDelay ) {
4882:
4883: AtDump(
4884: ATERRORS,
4885: ( "Atdisk ERROR: controller not ready\n" ));
4886:
4887: return STATUS_IO_TIMEOUT;
4888:
4889: } else {
4890:
4891: return STATUS_SUCCESS;
4892: }
4893: }
4894:
4895: NTSTATUS
4896: AtWaitControllerBusy(
4897: PUCHAR StatusRegisterAddress,
4898: ULONG MicrosecondsToDelay,
4899: ULONG TimesToDelay
4900: )
4901:
4902: /*++
4903:
4904: Routine Description:
4905:
4906: This routine waits for the hard disk controller to turn ON the BUSY
4907: bit in the status register.
4908:
4909: It waits any number of times (TimesToDelay) for any number of
4910: microseconds (MicroSecondsToDelay). In between waits, it checks to
4911: see if the busy bit has been turned on. If so, it returns early.
4912:
4913: Arguments:
4914:
4915: StatusRegisterAddress - Where to check for busy.
4916:
4917: MicrosecondsToDelay - the number of microseconds to delay each time
4918:
4919: TimesToDelay - the number of times to delay
4920:
4921: Return Value:
4922:
4923: STATUS_SUCCESS if the BUSY bit was turned on; STATUS_TIMEOUT if the
4924: BUSY bit was still off when we finished waiting.
4925:
4926: --*/
4927:
4928: {
4929: ULONG loopCount = 0;
4930:
4931: while ( !( READ_CONTROLLER(StatusRegisterAddress) & BUSY_STATUS ) &&
4932: ( loopCount++ < TimesToDelay ) ) {
4933:
4934: KeStallExecutionProcessor( MicrosecondsToDelay );
4935: }
4936:
4937: if ( loopCount == TimesToDelay ) {
4938:
4939: AtDump(
4940: ATERRORS,
4941: ( "Atdisk ERROR: controller not busy\n" ));
4942:
4943: return STATUS_IO_TIMEOUT;
4944:
4945: } else {
4946:
4947: return STATUS_SUCCESS;
4948: }
4949: }
4950:
4951: VOID
4952: AtLogError(
4953: IN PDEVICE_OBJECT DeviceObject,
4954: IN ULONG SequenceNumber,
4955: IN UCHAR MajorFunctionCode,
4956: IN UCHAR RetryCount,
4957: IN ULONG UniqueErrorValue,
4958: IN NTSTATUS FinalStatus,
4959: IN NTSTATUS SpecificIOStatus,
4960: IN CCHAR ErrorType,
4961: IN UCHAR Parameter1,
4962: IN UCHAR Parameter2,
4963: IN UCHAR Parameter3,
4964: IN UCHAR Parameter4,
4965: IN UCHAR Parameter5,
4966: IN UCHAR Parameter6,
4967: IN UCHAR Parameter7
4968: )
4969:
4970: /*++
4971:
4972: Routine Description:
4973:
4974: This routine is called at DISPATCH_LEVEL by either
4975: AtDiskDeferredProcedure() or AtDiskCheckTimer() if they
4976: encounter an error.
4977:
4978: This routine allocates an error log entry, copies the supplied text
4979: to it, and requests that it be written to the error log file.
4980:
4981: Arguments:
4982:
4983: DeviceObject - a pointer to the device object associated with the
4984: device that had the error.
4985:
4986: SequenceNumber - A ulong value that is unique to an IRP over the
4987: life of the irp in this driver - 0 generally means an error not
4988: associated with an irp.
4989:
4990: MajorFunctionCode - If there is an error associated with the irp,
4991: this is the major function code of that irp.
4992:
4993: RetryCount - The number of times a particular operation has been
4994: retried.
4995:
4996: UniqueErrorValue - A unique long word that identifies the particular
4997: call to this function.
4998:
4999: FinalStatus - The final status given to the irp that was associated
5000: with this error. If this log entry is being made during one of
5001: the retries this value will be STATUS_SUCCESS.
5002:
5003: SpecificIOStatus - The IO status for a particular error.
5004:
5005: ErrorType - the type of error being logged, defined by this driver.
5006: Most types do not use the following parameters.
5007:
5008: Parameter1 - for ERROR_LOG_TYPE_ERROR, this holds ERROR_REGISTER.
5009:
5010: Parameter2 - for ERROR_LOG_TYPE_ERROR, this holds DRIVE_HEAD_REGISTER.
5011:
5012: Parameter3 - for ERROR_LOG_TYPE_ERROR, this holds CYLINDER_HIGH_REGISTER.
5013:
5014: Parameter4 - for ERROR_LOG_TYPE_ERROR, this holds CYLINDER_LOW_REGISTER.
5015:
5016: Parameter5 - for ERROR_LOG_TYPE_ERROR, this holds SECTOR_NUMBER_REGISTER.
5017:
5018: Parameter6 - for ERROR_LOG_TYPE_ERROR, this holds SECTOR_COUNT_REGISTER
5019:
5020: Parameter7 - for ERROR_LOG_TYPE_ERROR, this holds STATUS_REGISTER.
5021:
5022: Return Value:
5023:
5024: None.
5025:
5026: --*/
5027:
5028: {
5029: PIO_ERROR_LOG_PACKET errorLogEntry;
5030: UCHAR extraAllocSize = 0;
5031: PDISK_EXTENSION diskExtension = DeviceObject->DeviceExtension;
5032:
5033: if (ErrorType == ERROR_LOG_TYPE_ERROR) {
5034:
5035: //
5036: // Allocate space for the seven parameters that came in as well
5037: // as the 5 parameters that were used to start out this transfer
5038: // and 4 bytes so that we can look at the geometry.
5039: //
5040: extraAllocSize = 16;
5041:
5042: }
5043:
5044: errorLogEntry = IoAllocateErrorLogEntry(
5045: DeviceObject,
5046: (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + extraAllocSize) );
5047:
5048: if ( errorLogEntry != NULL ) {
5049:
5050: errorLogEntry->ErrorCode = SpecificIOStatus;
5051: errorLogEntry->SequenceNumber = SequenceNumber;
5052: errorLogEntry->MajorFunctionCode = MajorFunctionCode;
5053: errorLogEntry->RetryCount = RetryCount;
5054: errorLogEntry->UniqueErrorValue = UniqueErrorValue;
5055: errorLogEntry->FinalStatus = FinalStatus;
5056:
5057: if (ErrorType == ERROR_LOG_TYPE_ERROR) {
5058:
5059: PUCHAR errorValues = (PVOID)&errorLogEntry->DumpData[0];
5060:
5061: errorLogEntry->DumpDataSize = 16;
5062:
5063: //
5064: // Give the geometry of the disk at the beginning of the dump data.
5065: //
5066:
5067: errorValues[0] = (UCHAR)diskExtension->SectorsPerTrack;
5068: errorValues[1] = (UCHAR)diskExtension->TracksPerCylinder;
5069: errorValues[2] = (UCHAR)diskExtension->NumberOfCylinders;
5070: errorValues[3] = (UCHAR)(diskExtension->NumberOfCylinders >> 8);
5071:
5072: //
5073: // Show the CHS that we started with in the log as one long word at
5074: // the beginning.
5075: //
5076:
5077: //
5078: // Sector on track
5079: //
5080:
5081: errorValues[4] = (UCHAR)((diskExtension->FirstSectorOfTransfer %
5082: diskExtension->SectorsPerTrack) + 1);
5083:
5084: //
5085: // Drive unit & head - for drive unit low bit of high nibble
5086: // 0 is master, 1 is slave.
5087: //
5088:
5089: errorValues[5] = (UCHAR)(((diskExtension->FirstSectorOfTransfer /
5090: diskExtension->SectorsPerTrack ) %
5091: diskExtension->TracksPerCylinder) |
5092: diskExtension->DeviceUnit);
5093: //
5094: // Low byte of cylinder
5095: //
5096:
5097: errorValues[6] = (UCHAR)((diskExtension->FirstSectorOfTransfer /
5098: (diskExtension->SectorsPerTrack *
5099: diskExtension->TracksPerCylinder)) & 0xff);
5100:
5101: //
5102: // High byte of cylinder.
5103: //
5104:
5105: errorValues[7] = (UCHAR)((diskExtension->FirstSectorOfTransfer /
5106: (diskExtension->SectorsPerTrack *
5107: diskExtension->TracksPerCylinder)) >> 8);
5108:
5109: //
5110: // Total of sectors in transfer.
5111: //
5112:
5113: errorValues[8] = (UCHAR)(diskExtension->TotalTransferLength /
5114: diskExtension->BytesPerSector);
5115:
5116: //
5117: // Sector Count
5118: //
5119:
5120: errorValues[9] = Parameter6;
5121:
5122: //
5123: // Status register
5124: //
5125:
5126: errorValues[10] = Parameter7;
5127:
5128: //
5129: // Error register.
5130: //
5131:
5132: errorValues[11] = Parameter1;
5133:
5134: //
5135: // sector on error
5136: //
5137:
5138: errorValues[12] = Parameter5;
5139:
5140: //
5141: // Drive unit & head - for drive unit low bit of high nibble
5142: // 0 is master, 1 is slave.
5143: //
5144:
5145: errorValues[13] = Parameter2;
5146:
5147: //
5148: // low byte of cylinder in error.
5149: //
5150:
5151: errorValues[14] = Parameter4;
5152:
5153: //
5154: // High byte of cylinder.
5155: //
5156:
5157: errorValues[15] = Parameter3;
5158: } else {
5159: errorLogEntry->DumpDataSize = 0;
5160: }
5161: IoWriteErrorLogEntry(errorLogEntry);
5162:
5163: }
5164: }
5165:
5166: PVOID
5167: AtGetTranslatedMemory(
5168: IN INTERFACE_TYPE BusType,
5169: IN ULONG BusNumber,
5170: PHYSICAL_ADDRESS IoAddress,
5171: ULONG NumberOfBytes,
5172: BOOLEAN InIoSpace,
5173: PBOOLEAN MappedAddress
5174: )
5175:
5176: /*++
5177:
5178: Routine Description:
5179:
5180: This routine maps an IO address to system address space.
5181:
5182: Arguments:
5183:
5184: BusType - what type of bus - eisa, mca, isa
5185: IoBusNumber - which IO bus (for machines with multiple buses).
5186: IoAddress - base device address to be mapped.
5187: NumberOfBytes - number of bytes for which address is valid.
5188: InIoSpace - indicates an IO address.
5189: MappedAddress - indicates whether the address was mapped.
5190: This only has meaning if the address returned
5191: is non-null.
5192:
5193: Return Value:
5194:
5195: Mapped address
5196:
5197: --*/
5198:
5199: {
5200: PHYSICAL_ADDRESS cardAddress;
5201: ULONG addressSpace = InIoSpace;
5202: PVOID Address;
5203:
5204: HalTranslateBusAddress(
5205: BusType,
5206: BusNumber,
5207: IoAddress,
5208: &addressSpace,
5209: &cardAddress
5210: );
5211:
5212: //
5213: // Map the device base address into the virtual address space
5214: // if the address is in memory space.
5215: //
5216:
5217: if (!addressSpace) {
5218:
5219: Address = MmMapIoSpace(
5220: cardAddress,
5221: NumberOfBytes,
5222: FALSE
5223: );
5224:
5225: *MappedAddress = (BOOLEAN)((Address)?(TRUE):(FALSE));
5226:
5227:
5228: } else {
5229:
5230: *MappedAddress = FALSE;
5231: Address = (PVOID)cardAddress.LowPart;
5232: }
5233:
5234: return Address;
5235:
5236: }
5237:
5238: BOOLEAN
5239: AtReportUsage(
5240: IN PCONFIG_DATA ConfigData,
5241: IN UCHAR ControllerNumber,
5242: IN PDRIVER_OBJECT DriverObject
5243: )
5244:
5245: /*++
5246:
5247: Routine Description:
5248:
5249: This routine will build up a resource list using the
5250: data for this particular controller as well as all
5251: previous *successfully* configured controllers.
5252:
5253: N.B. This routine assumes that it called in controller
5254: number order.
5255:
5256: Arguments:
5257:
5258: ConfigData - a pointer to the structure that describes the
5259: controller and the disks attached to it, as given to us by the
5260: configuration manager.
5261:
5262: ControllerNumber - which controller in ConfigData we are
5263: about to try to report.
5264:
5265: DriverObject - a pointer to the object that represents this device
5266: driver.
5267:
5268: Return Value:
5269:
5270: TRUE if no conflict was detected, FALSE otherwise.
5271:
5272: --*/
5273:
5274: {
5275:
5276: ULONG sizeOfResourceList;
5277: ULONG numberOfFrds;
5278: ULONG i;
5279: PCM_RESOURCE_LIST resourceList;
5280: PCM_FULL_RESOURCE_DESCRIPTOR nextFrd;
5281:
5282: //
5283: // Loop through all of the controllers previous to this
5284: // controller. If the controllers previous to this one
5285: // didn't have a conflict, then accumulate the size of the
5286: // CM_FULL_RESOURCE_DESCRIPTOR associated with it.
5287: //
5288:
5289: for (
5290: i = 0,numberOfFrds = 0,sizeOfResourceList = 0;
5291: i <= (ULONG)ControllerNumber;
5292: i++
5293: ) {
5294:
5295: if (ConfigData->Controller[i].OkToUseThisController) {
5296:
5297: sizeOfResourceList += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
5298:
5299: //
5300: // The full resource descriptor already contains one
5301: // partial. Make room for two more.
5302: //
5303: // It will hold the irq "prd", the controller "csr" "prd", and
5304: // the controller port "prd".
5305: //
5306:
5307: sizeOfResourceList += 2*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
5308: numberOfFrds++;
5309:
5310: }
5311:
5312: }
5313:
5314: //
5315: // Now we increment the length of the resource list by field offset
5316: // of the first frd. This will give us the length of what preceeds
5317: // the first frd in the resource list.
5318: //
5319:
5320: sizeOfResourceList += FIELD_OFFSET(
5321: CM_RESOURCE_LIST,
5322: List[0]
5323: );
5324:
5325: resourceList = ExAllocatePool(
5326: PagedPool,
5327: sizeOfResourceList
5328: );
5329:
5330: if (!resourceList) {
5331:
5332: return FALSE;
5333:
5334: }
5335:
5336: //
5337: // Zero out the field
5338: //
5339:
5340: RtlZeroMemory(
5341: resourceList,
5342: sizeOfResourceList
5343: );
5344:
5345: resourceList->Count = numberOfFrds;
5346: nextFrd = &resourceList->List[0];
5347:
5348: for (
5349: i = 0;
5350: numberOfFrds;
5351: i++
5352: ) {
5353:
5354: if (ConfigData->Controller[i].OkToUseThisController) {
5355:
5356: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
5357:
5358: nextFrd->InterfaceType = ConfigData->Controller[i].InterfaceType;
5359: nextFrd->BusNumber = ConfigData->Controller[i].BusNumber;
5360:
5361: //
5362: // We are only going to report 3 items no matter what
5363: // was in the original.
5364: //
5365:
5366: nextFrd->PartialResourceList.Count = 3;
5367:
5368: //
5369: // Now fill in the two port data. We don't wish to share
5370: // this port range with anyone
5371: //
5372:
5373: partial = &nextFrd->PartialResourceList.PartialDescriptors[0];
5374:
5375: partial->Type = CmResourceTypePort;
5376: partial->ShareDisposition = CmResourceShareDriverExclusive;
5377: partial->Flags = CM_RESOURCE_PORT_IO;
5378: partial->u.Port.Start =
5379: ConfigData->Controller[i].OriginalControllerBaseAddress;
5380: partial->u.Port.Length =
5381: ConfigData->Controller[i].RangeOfControllerBase;
5382:
5383: partial++;
5384:
5385: partial->Type = CmResourceTypePort;
5386: partial->ShareDisposition = CmResourceShareDriverExclusive;
5387: partial->Flags = CM_RESOURCE_PORT_IO;
5388: partial->u.Port.Start =
5389: ConfigData->Controller[i].OriginalControlPortAddress;
5390: partial->u.Port.Length =
5391: ConfigData->Controller[i].RangeOfControlPort;
5392:
5393: partial++;
5394:
5395: //
5396: // Now fill in the irq stuff.
5397: //
5398:
5399: partial->Type = CmResourceTypeInterrupt;
5400: partial->u.Interrupt.Level =
5401: ConfigData->Controller[i].OriginalControllerIrql;
5402: partial->u.Interrupt.Vector =
5403: ConfigData->Controller[i].OriginalControllerVector;
5404:
5405: if (nextFrd->InterfaceType == MicroChannel) {
5406:
5407: partial->ShareDisposition = CmResourceShareShared;
5408:
5409: } else {
5410:
5411: partial->ShareDisposition = CmResourceShareDriverExclusive;
5412:
5413: }
5414:
5415: if (ConfigData->Controller[i].InterruptMode == Latched) {
5416:
5417: partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
5418:
5419: } else {
5420:
5421: partial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
5422:
5423: }
5424:
5425: partial++;
5426:
5427: nextFrd = (PVOID)partial;
5428:
5429: numberOfFrds--;
5430:
5431: }
5432:
5433: }
5434:
5435: IoReportResourceUsage(
5436: NULL,
5437: DriverObject,
5438: resourceList,
5439: sizeOfResourceList,
5440: NULL,
5441: NULL,
5442: 0,
5443: FALSE,
5444: &ConfigData->Controller[ControllerNumber].OkToUseThisController
5445: );
5446:
5447: //
5448: // The above routine sets the boolean the parameter
5449: // to TRUE if a conflict was detected.
5450: //
5451:
5452: ConfigData->Controller[ControllerNumber].OkToUseThisController =
5453: !ConfigData->Controller[ControllerNumber].OkToUseThisController;
5454:
5455: ExFreePool(resourceList);
5456:
5457: return ConfigData->Controller[ControllerNumber].OkToUseThisController;
5458:
5459: }
5460:
5461:
5462:
5463: BOOLEAN
5464: GetGeometryFromIdentify(
5465: PCONTROLLER_DATA ControllerData,
5466: ULONG DiskNumber
5467: )
5468:
5469: /*++
5470:
5471: Routine Description:
5472:
5473: This updates geometry information in a disk extension
5474: from a BIOS parameter table entry.
5475:
5476: Arguments:
5477:
5478: ControllerData - Description of the controller.
5479: DiskNumber - Which disk on the controller (0 or 1).
5480:
5481: Return Value:
5482:
5483: Nothing.
5484:
5485: --*/
5486:
5487: {
5488: IDENTIFY_DATA identifyBuffer;
5489: PDRIVE_DATA driveData = &ControllerData->Disk[DiskNumber];
5490:
5491: //
5492: // Issue IDENTIFY command.
5493: //
5494:
5495: if (!IssueIdentify(ControllerData,
5496: (PUCHAR)&identifyBuffer,
5497: DiskNumber)) {
5498:
5499: return FALSE;
5500: }
5501:
5502: //
5503: // Initialize this drive.
5504: //
5505:
5506: driveData->BytesPerSector = 512;
5507: driveData->BytesPerInterrupt = 512;
5508:
5509: driveData->ReadCommand = 0x20;
5510: driveData->WriteCommand = 0x30;
5511: driveData->VerifyCommand = 0x40;
5512:
5513: driveData->PretendNumberOfCylinders =
5514: driveData->NumberOfCylinders =
5515: (USHORT)identifyBuffer.NumberOfCylinders;
5516: driveData->PretendTracksPerCylinder =
5517: driveData->TracksPerCylinder =
5518: identifyBuffer.NumberOfHeads;
5519: driveData->PretendSectorsPerTrack =
5520: driveData->SectorsPerTrack =
5521: identifyBuffer.SectorsPerTrack;
5522:
5523:
5524: //
5525: // Since we don't know any better, and no drives within recent memory
5526: // use write precomp, set it to MAXUSHORT so that we don't set it
5527: // anymore.
5528: //
5529:
5530: driveData->WritePrecomp = MAXUSHORT;
5531:
5532: return TRUE;
5533: }
5534:
5535:
5536: BOOLEAN
5537: IssueIdentify(
5538: PCONTROLLER_DATA ControllerData,
5539: PUCHAR Buffer,
5540: ULONG DiskNumber
5541: )
5542:
5543: /*++
5544:
5545: Routine Description:
5546:
5547: Issue 0xEC IDENTIFY command to collect disk information.
5548:
5549:
5550: Arguments:
5551:
5552: ControllerData - Description of controller.
5553: Buffer - A place to store geometry.
5554: DiskNumber - Which disk on the controller (0 or 1).
5555:
5556: Return Value:
5557:
5558: TRUE if IDENTIFY command successful.
5559:
5560: --*/
5561:
5562: {
5563: ULONG i;
5564: UCHAR statusByte;
5565:
5566: //
5567: // Select disk 0 or 1.
5568: //
5569:
5570: WRITE_CONTROLLER(ControllerData->ControllerBaseAddress + DRIVE_HEAD_REGISTER,
5571: (UCHAR)(DiskNumber << 4) | DRIVE_1);
5572:
5573: //
5574: // If the second drive is selected but it doesn't exist the controller
5575: // may behave randomly. Check that the status register makes sense.
5576: //
5577:
5578: statusByte = READ_CONTROLLER(ControllerData->ControllerBaseAddress + STATUS_REGISTER);
5579:
5580: //
5581: // Get rid of the IDX bit.
5582: //
5583:
5584: statusByte &= 0xfd;
5585:
5586: if (statusByte != 0x50) {
5587:
5588: //
5589: // Select drive zero again so that the controller
5590: // will return to normal behaviour.
5591: //
5592:
5593: WRITE_CONTROLLER(ControllerData->ControllerBaseAddress + DRIVE_HEAD_REGISTER,
5594: DRIVE_1);
5595:
5596: return FALSE;
5597: }
5598:
5599: //
5600: // Send IDENTIFY command.
5601: //
5602:
5603: WRITE_CONTROLLER(ControllerData->ControllerBaseAddress + COMMAND_REGISTER,
5604: IDENTIFY_COMMAND);
5605:
5606: //
5607: // Wait for up to 3 seconds for DRQ or ERROR.
5608: //
5609:
5610: for (i=0; i<300000; i++) {
5611:
5612: statusByte = READ_CONTROLLER(ControllerData->ControllerBaseAddress + STATUS_REGISTER);
5613:
5614: if (statusByte & ERROR_STATUS) {
5615: return FALSE;
5616: } else if (statusByte & DATA_REQUEST_STATUS) {
5617: break;
5618: } else {
5619: KeStallExecutionProcessor(10L);
5620: }
5621: }
5622:
5623: if (i == 10000) {
5624: return FALSE;
5625: }
5626:
5627: //
5628: // Suck out 256 words.
5629: //
5630:
5631: READ_CONTROLLER_BUFFER(
5632: ControllerData->ControllerBaseAddress + DATA_REGISTER,
5633: Buffer,
5634: 512);
5635:
5636: return TRUE;
5637: }
5638:
5639: VOID
5640: AtBuildDeviceMap(
5641: IN ULONG ControllerNumber,
5642: IN ULONG DiskNumber,
5643: IN PHYSICAL_ADDRESS ControllerAddress,
5644: IN KIRQL Irql,
5645: IN PDRIVE_DATA Disk,
5646: IN PIDENTIFY_DATA DiskData
5647: )
5648:
5649: /*++
5650:
5651: Routine Description:
5652:
5653: The routine puts vendor and model information from the IDENTIFY
5654: command into the device map in the registry.
5655:
5656: Arguments:
5657:
5658: ControllerNumber - Supplies the current controller number.
5659:
5660: DiskNumber - Supplies the current disk on the controller.
5661:
5662: ControllerAddress - The untranslated address of the disk controller.
5663:
5664: Irql - The untranslated interrupt of the controller.
5665:
5666: Disk - Address of the structure that holds our determined geometry
5667: data.
5668:
5669: DiskData - Address of disk IDENTIFY data.
5670:
5671: Return Value:
5672:
5673: None.
5674:
5675: --*/
5676:
5677: {
5678:
5679: UNICODE_STRING name;
5680: UNICODE_STRING unicodeString;
5681: ANSI_STRING ansiString;
5682: HANDLE key;
5683: HANDLE controllerKey;
5684: HANDLE diskKey;
5685: OBJECT_ATTRIBUTES objectAttributes;
5686: NTSTATUS status;
5687: ULONG disposition;
5688: ULONG tempLong;
5689: PCHAR junkPtr;
5690:
5691:
5692: RtlInitUnicodeString(
5693: &name,
5694: L"\\Registry\\Machine\\Hardware\\DeviceMap\\AtDisk"
5695: );
5696:
5697: //
5698: // Initialize the object for the key.
5699: //
5700:
5701: InitializeObjectAttributes( &objectAttributes,
5702: &name,
5703: OBJ_CASE_INSENSITIVE,
5704: NULL,
5705: (PSECURITY_DESCRIPTOR) NULL );
5706:
5707: //
5708: // Create the key or open it.
5709: //
5710:
5711: status = ZwCreateKey(&key,
5712: KEY_READ | KEY_WRITE,
5713: &objectAttributes,
5714: 0,
5715: (PUNICODE_STRING) NULL,
5716: REG_OPTION_VOLATILE,
5717: &disposition );
5718:
5719: if (!NT_SUCCESS(status)) {
5720: return;
5721: }
5722:
5723: status = AtCreateNumericKey(key, ControllerNumber, L"Controller ", &controllerKey);
5724: ZwClose(key);
5725:
5726: if (!NT_SUCCESS(status)) {
5727: return;
5728: }
5729:
5730:
5731: RtlInitUnicodeString(&name, L"Controller Address");
5732:
5733: status = ZwSetValueKey(
5734: controllerKey,
5735: &name,
5736: 0,
5737: REG_DWORD,
5738: &ControllerAddress.LowPart,
5739: sizeof(ControllerAddress.LowPart));
5740: RtlInitUnicodeString(&name, L"Controller Interrupt");
5741: tempLong = (ULONG)Irql;
5742: status = ZwSetValueKey(
5743: controllerKey,
5744: &name,
5745: 0,
5746: REG_DWORD,
5747: &tempLong,
5748: sizeof(ULONG));
5749:
5750: //
5751: // Create a key entry for the disk.
5752: //
5753:
5754: status = AtCreateNumericKey(controllerKey, DiskNumber, L"Disk ", &diskKey);
5755:
5756: if (!NT_SUCCESS(status)) {
5757: ZwClose(controllerKey);
5758: return;
5759: }
5760:
5761: //
5762: // Get the Identifier from the identify data.
5763: //
5764:
5765: RtlInitUnicodeString(&name, L"Identifier");
5766:
5767: ansiString.MaximumLength = 40;
5768: ansiString.Buffer = (PUCHAR)DiskData->ModelNumber;
5769:
5770: junkPtr = memchr(
5771: &ansiString.Buffer[0],
5772: 0x00,
5773: ansiString.MaximumLength
5774: );
5775:
5776: if (!junkPtr) {
5777:
5778: ansiString.Length = ansiString.MaximumLength;
5779:
5780: } else {
5781:
5782: ansiString.Length = junkPtr - &ansiString.Buffer[0];
5783:
5784: }
5785:
5786: status = RtlAnsiStringToUnicodeString(
5787: &unicodeString,
5788: &ansiString,
5789: TRUE
5790: );
5791:
5792: if (NT_SUCCESS(status)) {
5793:
5794: status = ZwSetValueKey(
5795: diskKey,
5796: &name,
5797: 0,
5798: REG_SZ,
5799: unicodeString.Buffer,
5800: unicodeString.Length + sizeof(wchar_t));
5801:
5802: RtlFreeUnicodeString(&unicodeString);
5803: }
5804:
5805: //
5806: // Write the firmware revision to the registry.
5807: //
5808:
5809: RtlInitUnicodeString(&name, L"Firmware revision");
5810:
5811: ansiString.MaximumLength = 8;
5812: ansiString.Buffer = (PUCHAR)DiskData->FirmwareRevision;
5813:
5814: junkPtr = memchr(
5815: &ansiString.Buffer[0],
5816: 0x00,
5817: ansiString.MaximumLength
5818: );
5819:
5820: if (!junkPtr) {
5821:
5822: ansiString.Length = ansiString.MaximumLength;
5823:
5824: } else {
5825:
5826: ansiString.Length = junkPtr - &ansiString.Buffer[0];
5827:
5828: }
5829:
5830:
5831: status = RtlAnsiStringToUnicodeString(
5832: &unicodeString,
5833: &ansiString,
5834: TRUE
5835: );
5836:
5837: if (NT_SUCCESS(status)) {
5838:
5839: status = ZwSetValueKey(
5840: diskKey,
5841: &name,
5842: 0,
5843: REG_SZ,
5844: unicodeString.Buffer,
5845: unicodeString.Length + sizeof(wchar_t));
5846:
5847: RtlFreeUnicodeString(&unicodeString);
5848: }
5849:
5850: //
5851: // Write the serial number to the registry.
5852: //
5853:
5854: RtlInitUnicodeString(&name, L"Serial number");
5855:
5856: ansiString.MaximumLength = 20;
5857: ansiString.Buffer = (PUCHAR)DiskData->SerialNumber;
5858:
5859: junkPtr = memchr(
5860: &ansiString.Buffer[0],
5861: 0x00,
5862: ansiString.MaximumLength
5863: );
5864:
5865: if (!junkPtr) {
5866:
5867: ansiString.Length = ansiString.MaximumLength;
5868:
5869: } else {
5870:
5871: ansiString.Length = junkPtr - &ansiString.Buffer[0];
5872:
5873: }
5874:
5875:
5876: status = RtlAnsiStringToUnicodeString(
5877: &unicodeString,
5878: &ansiString,
5879: TRUE
5880: );
5881:
5882: if (NT_SUCCESS(status)) {
5883:
5884: status = ZwSetValueKey(
5885: diskKey,
5886: &name,
5887: 0,
5888: REG_SZ,
5889: unicodeString.Buffer,
5890: unicodeString.Length + sizeof(wchar_t));
5891:
5892: RtlFreeUnicodeString(&unicodeString);
5893: }
5894:
5895: //
5896: // Writ the data that the identify command found.
5897: //
5898:
5899: //
5900: // Write number of cylinders to registry.
5901: //
5902:
5903: RtlInitUnicodeString(&name, L"Identify - Number of cylinders");
5904:
5905: tempLong = (ULONG)DiskData->NumberOfCylinders;
5906:
5907: status = ZwSetValueKey(
5908: diskKey,
5909: &name,
5910: 0,
5911: REG_DWORD,
5912: &tempLong,
5913: sizeof(ULONG));
5914:
5915: //
5916: // Write number of heads to registry.
5917: //
5918:
5919: RtlInitUnicodeString(&name, L"Identify - Number of heads");
5920:
5921: tempLong = DiskData->NumberOfHeads;
5922:
5923: status = ZwSetValueKey(
5924: diskKey,
5925: &name,
5926: 0,
5927: REG_DWORD,
5928: &tempLong,
5929: sizeof(ULONG));
5930:
5931: //
5932: // Write track size to registry.
5933: //
5934:
5935: RtlInitUnicodeString(&name, L"Identify - Sectors per track");
5936:
5937: tempLong = DiskData->SectorsPerTrack;
5938:
5939: status = ZwSetValueKey(
5940: diskKey,
5941: &name,
5942: 0,
5943: REG_DWORD,
5944: &tempLong,
5945: sizeof(ULONG));
5946:
5947: //
5948: // Write the apparent geometry data.
5949: //
5950:
5951: //
5952: // Write number of cylinders to registry.
5953: //
5954:
5955: RtlInitUnicodeString(&name, L"Apparent - Number of cylinders");
5956:
5957: tempLong = (ULONG)Disk->PretendNumberOfCylinders;
5958:
5959: status = ZwSetValueKey(
5960: diskKey,
5961: &name,
5962: 0,
5963: REG_DWORD,
5964: &tempLong,
5965: sizeof(ULONG));
5966:
5967: //
5968: // Write number of heads to registry.
5969: //
5970:
5971: RtlInitUnicodeString(&name, L"Apparent - Number of heads");
5972:
5973: tempLong = Disk->PretendTracksPerCylinder;
5974:
5975: status = ZwSetValueKey(
5976: diskKey,
5977: &name,
5978: 0,
5979: REG_DWORD,
5980: &tempLong,
5981: sizeof(ULONG));
5982:
5983: //
5984: // Write track size to registry.
5985: //
5986:
5987: RtlInitUnicodeString(&name, L"Apparent - Sectors per track");
5988:
5989: tempLong = Disk->PretendSectorsPerTrack;
5990:
5991: status = ZwSetValueKey(
5992: diskKey,
5993: &name,
5994: 0,
5995: REG_DWORD,
5996: &tempLong,
5997: sizeof(ULONG));
5998:
5999: //
6000: // Write the actual geometry data.
6001: //
6002:
6003: //
6004: // Write number of cylinders to registry.
6005: //
6006:
6007: RtlInitUnicodeString(&name, L"Actual - Number of cylinders");
6008:
6009: tempLong = (ULONG)Disk->NumberOfCylinders;
6010:
6011: status = ZwSetValueKey(
6012: diskKey,
6013: &name,
6014: 0,
6015: REG_DWORD,
6016: &tempLong,
6017: sizeof(ULONG));
6018:
6019: //
6020: // Write number of heads to registry.
6021: //
6022:
6023: RtlInitUnicodeString(&name, L"Actual - Number of heads");
6024:
6025: tempLong = Disk->TracksPerCylinder;
6026:
6027: status = ZwSetValueKey(
6028: diskKey,
6029: &name,
6030: 0,
6031: REG_DWORD,
6032: &tempLong,
6033: sizeof(ULONG));
6034:
6035: //
6036: // Write track size to registry.
6037: //
6038:
6039: RtlInitUnicodeString(&name, L"Actual - Sectors per track");
6040:
6041: tempLong = Disk->SectorsPerTrack;
6042:
6043: status = ZwSetValueKey(
6044: diskKey,
6045: &name,
6046: 0,
6047: REG_DWORD,
6048: &tempLong,
6049: sizeof(ULONG));
6050:
6051: ZwClose(diskKey);
6052: ZwClose(controllerKey);
6053:
6054: return;
6055: }
6056:
6057: NTSTATUS
6058: AtCreateNumericKey(
6059: IN HANDLE Root,
6060: IN ULONG Name,
6061: IN PWSTR Prefix,
6062: OUT PHANDLE NewKey
6063: )
6064:
6065: /*++
6066:
6067: Routine Description:
6068:
6069: This function creates a registry key. The name of the key is a string
6070: version of numeric value passed in.
6071:
6072: Arguments:
6073:
6074: RootKey - Supplies a handle to the key where the new key should be inserted.
6075:
6076: Name - Supplies the numeric value to name the key.
6077:
6078: Prefix - Supplies a prefix name to add to name.
6079:
6080: NewKey - Returns the handle for the new key.
6081:
6082: Return Value:
6083:
6084: Returns the status of the operation.
6085:
6086: --*/
6087:
6088: {
6089:
6090: UNICODE_STRING string;
6091: UNICODE_STRING stringNum;
6092: OBJECT_ATTRIBUTES objectAttributes;
6093: WCHAR bufferNum[16];
6094: WCHAR buffer[64];
6095: ULONG disposition;
6096: NTSTATUS status;
6097:
6098: //
6099: // Copy the Prefix into a string.
6100: //
6101:
6102: string.Length = 0;
6103: string.MaximumLength=64;
6104: string.Buffer = buffer;
6105:
6106: RtlInitUnicodeString(&stringNum, Prefix);
6107:
6108: RtlCopyUnicodeString(&string, &stringNum);
6109:
6110: //
6111: // Create a port number key entry.
6112: //
6113:
6114: stringNum.Length = 0;
6115: stringNum.MaximumLength = 16;
6116: stringNum.Buffer = bufferNum;
6117:
6118: status = RtlIntegerToUnicodeString(Name, 10, &stringNum);
6119:
6120: if (!NT_SUCCESS(status)) {
6121: return status;
6122: }
6123:
6124: //
6125: // Append the prefix and the numeric name.
6126: //
6127:
6128: RtlAppendUnicodeStringToString(&string, &stringNum);
6129:
6130: InitializeObjectAttributes( &objectAttributes,
6131: &string,
6132: OBJ_CASE_INSENSITIVE,
6133: Root,
6134: (PSECURITY_DESCRIPTOR) NULL );
6135:
6136: status = ZwCreateKey(NewKey,
6137: KEY_READ | KEY_WRITE,
6138: &objectAttributes,
6139: 0,
6140: (PUNICODE_STRING) NULL,
6141: REG_OPTION_VOLATILE,
6142: &disposition );
6143:
6144: return(status);
6145: }
6146:
6147: BOOLEAN
6148: AtDiskControllerInfo(
6149: IN PDRIVER_OBJECT DriverObject,
6150: IN PUNICODE_STRING RegistryPath,
6151: IN ULONG WhichController,
6152: IN OUT PCONTROLLER_DATA Controller,
6153: IN PHYSICAL_ADDRESS DefaultBaseAddress,
6154: IN PHYSICAL_ADDRESS DefaultPortAddress,
6155: IN KIRQL DefaultIrql,
6156: IN INTERFACE_TYPE DefaultInterfaceType,
6157: IN ULONG DefaultBusNumber,
6158: IN BOOLEAN UseDefaults
6159: )
6160:
6161: /*++
6162:
6163: Routine Description:
6164:
6165: This will go out to the registry and see if a
6166: specification exists for the particular controller.
6167:
6168: Arguments:
6169:
6170: DriverObject - Not used.
6171:
6172: RegistryPath - Path to this drivers service node in
6173: the current control set.
6174:
6175: WhichController - Used to create the string ControllerX where
6176: X is the value of WhichController.
6177:
6178: Controller - Points to the controller config structure which
6179: will get filled in if this routine sets up for a
6180: controller.
6181:
6182: DefaultBaseAddress - Holds the physical address that we should use
6183: for the 7 regular registers if the UseDefaults
6184: parameter is true.
6185:
6186: DefaultPortAddress - Holds the physical address that we should use
6187: for the drive control register if the UseDefaults
6188: parameter is true.
6189:
6190: DefaultIrql - Holds the "interrupt" that we should map if the UseDefaults
6191: parameter is true.
6192:
6193: DefaultInterfaceType - Holds the "bus type" that we should use if the
6194: UseDefaults parameter is true.
6195:
6196: DefaultBusNumber - Holds the bus number that we should use if the
6197: UseDefaults parameter is true.
6198:
6199: UseDefaults - If true, then map the default memory and vector even if
6200: nothing could be found in the current control set.
6201:
6202:
6203: ControllerBaseAddress - Holds the address of the data is received
6204: and send.
6205:
6206: ControllerPortAddress - Holds the address of the drive control
6207: register.
6208:
6209: Irql - The interrupt to be used for the controller.
6210:
6211: Return Value:
6212:
6213: FALSE if no data was found and UseDefaults was false.
6214:
6215: --*/
6216:
6217: {
6218:
6219: //
6220: // This will point to the structure that is used by RtlQueryRegistryValues
6221: // to "direct" its search and retrieval of values.
6222: //
6223: PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
6224: UNICODE_STRING parametersPath;
6225: UNICODE_STRING numberString;
6226: BOOLEAN returnValue;
6227:
6228:
6229: parametersPath.Buffer = NULL;
6230:
6231: //
6232: // Allocate the rtl query table.
6233: //
6234:
6235: parameters = ExAllocatePool(
6236: PagedPool,
6237: sizeof(RTL_QUERY_REGISTRY_TABLE)*6
6238: );
6239:
6240: if (!parameters) {
6241:
6242: returnValue = FALSE;
6243: goto FinishUp;
6244:
6245: }
6246:
6247: RtlZeroMemory(
6248: parameters,
6249: sizeof(RTL_QUERY_REGISTRY_TABLE)*6
6250: );
6251:
6252: //
6253: // Form a path to our drivers Parameters subkey.
6254: //
6255:
6256: RtlInitUnicodeString(
6257: ¶metersPath,
6258: NULL
6259: );
6260:
6261: //
6262: // Allocate the path plus 100 WCHARS to express the number
6263: // and 1 for the null pad.
6264: //
6265:
6266: parametersPath.MaximumLength = RegistryPath->Length +
6267: 2*sizeof(L"\\") +
6268: sizeof(L"Parameters") +
6269: 101*sizeof(WCHAR);
6270:
6271:
6272: parametersPath.Buffer = ExAllocatePool(
6273: PagedPool,
6274: parametersPath.MaximumLength
6275: );
6276:
6277: if (!parametersPath.Buffer) {
6278:
6279: returnValue = FALSE;
6280: goto FinishUp;
6281:
6282: }
6283:
6284: //
6285: // Form the parameters path.
6286: //
6287:
6288: RtlZeroMemory(
6289: parametersPath.Buffer,
6290: parametersPath.MaximumLength
6291: );
6292: RtlAppendUnicodeStringToString(
6293: ¶metersPath,
6294: RegistryPath
6295: );
6296: RtlAppendUnicodeToString(
6297: ¶metersPath,
6298: L"\\Parameters\\"
6299: );
6300:
6301: //
6302: // Now make a bogus unicode string that is the leftover
6303: // of what we formed of the path.
6304: //
6305:
6306: numberString.MaximumLength = parametersPath.MaximumLength -
6307: parametersPath.Length;
6308: numberString.Length = 0;
6309: numberString.Buffer = (PWSTR)(((PUCHAR)parametersPath.Buffer) +
6310: parametersPath.Length);
6311:
6312: if (!NT_SUCCESS(RtlIntegerToUnicodeString(
6313: WhichController,
6314: 10,
6315: &numberString
6316: ))) {
6317:
6318: returnValue = FALSE;
6319: goto FinishUp;
6320:
6321: }
6322:
6323: //
6324: // Gather all of the "user specified" information from
6325: // the registry.
6326: //
6327:
6328: parameters[0].Flags = RTL_QUERY_REGISTRY_REQUIRED |
6329: RTL_QUERY_REGISTRY_DIRECT;
6330: parameters[0].Name = L"BaseAddress";
6331: parameters[0].EntryContext =
6332: &Controller->OriginalControllerBaseAddress.LowPart;
6333:
6334: parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT |
6335: RTL_QUERY_REGISTRY_REQUIRED;
6336: parameters[1].Name = L"Interrupt";
6337: parameters[1].EntryContext = &Controller->OriginalControllerIrql;
6338:
6339: parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT |
6340: RTL_QUERY_REGISTRY_REQUIRED;
6341: parameters[2].Name = L"DriveControl";
6342: parameters[2].EntryContext =
6343: &Controller->OriginalControlPortAddress.LowPart;
6344:
6345: parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
6346: parameters[3].Name = L"BusNumber";
6347: parameters[3].EntryContext = &Controller->BusNumber;
6348: parameters[3].DefaultType = REG_DWORD;
6349: parameters[3].DefaultData = &DefaultBusNumber;
6350: parameters[3].DefaultLength = sizeof(ULONG);
6351:
6352: parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
6353: parameters[4].Name = L"InterfaceType";
6354: parameters[4].EntryContext = &Controller->InterfaceType;
6355: parameters[4].DefaultType = REG_DWORD;
6356: parameters[4].DefaultData = &DefaultInterfaceType;
6357: parameters[4].DefaultLength = sizeof(ULONG);
6358:
6359: if (!NT_SUCCESS(RtlQueryRegistryValues(
6360: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
6361: parametersPath.Buffer,
6362: parameters,
6363: NULL,
6364: NULL
6365: ))) {
6366:
6367: returnValue = FALSE;
6368:
6369: } else {
6370:
6371: returnValue = TRUE;
6372:
6373: }
6374:
6375: FinishUp: ;
6376:
6377: //
6378: // For some reason we couldn't get anything out of the registry
6379: // for the additional controllers. If the caller specified use
6380: // defaults then that means we should use the default values passed
6381: // in and map the stuff anyway (This could happen on the standard
6382: // atdisk controller addresses).
6383: //
6384:
6385: if (!returnValue && UseDefaults) {
6386:
6387: Controller->InterfaceType = DefaultInterfaceType;
6388: Controller->BusNumber = DefaultBusNumber;
6389: Controller->OriginalControllerBaseAddress = DefaultBaseAddress;
6390: Controller->OriginalControlPortAddress = DefaultPortAddress;
6391: Controller->OriginalControllerIrql = DefaultIrql;
6392:
6393: returnValue = TRUE;
6394:
6395: }
6396:
6397: if (returnValue) {
6398:
6399: Controller->OriginalControllerVector =
6400: Controller->OriginalControllerIrql;
6401: Controller->SharableVector = FALSE;
6402: Controller->InterruptMode = Latched;
6403: Controller->SaveFloatState = FALSE;
6404: Controller->RangeOfControllerBase = 8;
6405: Controller->RangeOfControlPort = 1;
6406:
6407: Controller->ControllerBaseAddress =
6408: AtGetTranslatedMemory(
6409: Controller->InterfaceType,
6410: Controller->BusNumber,
6411: Controller->OriginalControllerBaseAddress,
6412: Controller->RangeOfControllerBase,
6413: TRUE,
6414: &Controller->ControllerBaseMapped
6415: );
6416:
6417: Controller->ControlPortAddress =
6418: AtGetTranslatedMemory(
6419: Controller->InterfaceType,
6420: Controller->BusNumber,
6421: Controller->OriginalControlPortAddress,
6422: Controller->RangeOfControlPort,
6423: TRUE,
6424: &Controller->ControlPortMapped
6425: );
6426:
6427: Controller->ControllerVector = HalGetInterruptVector(
6428: Controller->InterfaceType,
6429: Controller->BusNumber,
6430: Controller->OriginalControllerIrql,
6431: Controller->OriginalControllerVector,
6432: &Controller->ControllerIrql,
6433: &Controller->ProcessorNumber );
6434:
6435: }
6436:
6437: if (parametersPath.Buffer) {
6438:
6439: ExFreePool(parametersPath.Buffer);
6440:
6441: }
6442:
6443: if (parameters) {
6444:
6445: ExFreePool(parameters);
6446:
6447: }
6448:
6449: return returnValue;
6450:
6451: }
6452:
6453: BOOLEAN
6454: AtControllerPresent(
6455: PCONTROLLER_DATA ControllerData
6456: )
6457:
6458: /*++
6459:
6460: Routine Description:
6461:
6462: This routine is used to determine if an AT controller exists.
6463:
6464: Arguments:
6465:
6466: ControllerData - Structure defining controller.
6467:
6468: Return Value:
6469:
6470: TRUE if controller exists.
6471:
6472: --*/
6473:
6474: {
6475: //
6476: // Write to indentifier to sector count register.
6477: //
6478:
6479: WRITE_PORT_UCHAR(ControllerData->ControllerBaseAddress + SECTOR_COUNT_REGISTER,
6480: 0xAA);
6481:
6482: //
6483: // Check if indentifier can be read back.
6484: //
6485:
6486: if (READ_PORT_UCHAR(ControllerData->ControllerBaseAddress + SECTOR_COUNT_REGISTER) == 0xAA) {
6487: return TRUE;
6488: } else {
6489: return FALSE;
6490: }
6491: }
6492:
6493: BOOLEAN
6494: AtResetController(
6495: IN PUCHAR StatusRegAddress,
6496: IN PUCHAR DriveControlAddress,
6497: IN CCHAR ControlFlags
6498: )
6499:
6500: /*++
6501:
6502: Routine Description:
6503:
6504: This routine will attempt to reset an atdisk controller.
6505:
6506: Arguments:
6507:
6508: StatusRegAddress - The address of the controllers status register.
6509:
6510: DriveControlAddress - The address of the controllers drive control register.
6511:
6512: ControlFlags - Values to OR into the the drive control register to
6513: initialize with.
6514:
6515: Return Value:
6516:
6517: TRUE if controller successfully reset.
6518:
6519: --*/
6520:
6521: {
6522:
6523: ULONG j;
6524:
6525: WRITE_PORT_UCHAR(
6526: DriveControlAddress,
6527: RESET_CONTROLLER
6528: );
6529:
6530: //
6531: // It shouldn't take it more than a tenth of a second to accept
6532: // the reset command
6533: //
6534:
6535:
6536: if (!NT_SUCCESS(AtWaitControllerBusy(
6537: StatusRegAddress,
6538: 10,
6539: 10000
6540: ))) {
6541:
6542: return FALSE;
6543:
6544: }
6545:
6546: WRITE_PORT_UCHAR(
6547: DriveControlAddress,
6548: (UCHAR)(ENABLE_INTERRUPTS | ControlFlags)
6549: );
6550:
6551: for (
6552: j = 0;
6553: j < 500000;
6554: j++
6555: ) {
6556:
6557: if (READ_PORT_UCHAR(StatusRegAddress) == 0x50) {
6558:
6559: return TRUE;
6560:
6561: }
6562:
6563: KeStallExecutionProcessor(10);
6564:
6565: }
6566:
6567: return FALSE;
6568: }
6569:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.