|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991 Microsoft Corporation
4:
5: Module Name:
6:
7: floppy.c
8:
9: Abstract:
10:
11: This is the NEC PD756 (aka AT, aka ISA, aka ix86) and Intel 82077
12: (aka MIPS) floppy diskette driver for NT.
13:
14: Author:
15:
16: Chad Schwitters (chads) 14-Jul-1991.
17:
18: Environment:
19:
20: Kernel mode only.
21:
22: Revision History:
23:
24: 02-Aug-1991 (chads) Made driver work on MIPS as well as ix86.
25:
26: Notes:
27:
28: The NEC PD765 is the controller standard used on almost all ISA PCs
29: (Industry Standard Architecture, which use Intel x86 processors).
30: More advanced controllers like the Intel 82077 (which is used on
31: many MIPS machines) are supersets of the PD765 standard.
32:
33:
34: Overview of this driver:
35:
36: This driver must deal with floppy drives, and the media that may
37: or may not be in them. "Drive" and "controller" refer to the
38: hardware connected to the machine, and "media" or "diskette"
39: refers to the floppy that gets inserted into the drive.
40:
41: Communicating with the controller can involve a lot of delays,
42: so this driver creates a thread to talk to the controller (since
43: we can't wait in another thread's context). The initialization
44: and dispatch routines are executed in the context of the caller,
45: and the ISR and DPC routines could be anywhere, but everything
46: else is executed in the context of the thread. The dispatch
47: routines put requests into an interlocked queue and signal the
48: thread; the thread wakes up and processes the requests serially.
49:
50: A big advantage of the thread approach is that synchronization
51: problems are almost non-existent. Interrupts always come when
52: the floppy is blocked and waiting for them (well, there could be
53: a spurious interrupt, but the ISR won't do anything critical in
54: that event), so the only opening for contention is with the DPC
55: that turns off the drive motor. A spin lock is used to keep the
56: thread and the DPC from trying to access variables or registers
57: at the same time.
58:
59: Data structures include a controller extension that holds all
60: variables common to the controller, a device extension that
61: holds all variables common to the drive, and a read-only table
62: that holds parameters used for communicating with the controller
63: given a drive/media combination. The data structures will be
64: described in more detail later.
65:
66: Since this driver deals with removable media, it must do its
67: share of volume tracking. Before processing any packet, it must
68: check some flags - if the volume needs to be verified, the
69: packet must be returned with STATUS_VERIFY_REQUIRED. Then, the
70: disk's changeline must be checked. If it is set, it should be
71: reset, and the packet should be returned with
72: STATUS_VERIFY_REQUIRED. (If it can't be reset, then the packet
73: should be failed with STATUS_NO_MEDIA_IN_DEVICE).
74:
75: Before any operation, the motor timer must be cancelled, the
76: drive must be selected, its motor must be turned on and given a
77: chance to spin up, the changeline must be checked (and possibly
78: dealt with as mentioned above), write access (if requested) must
79: be checked, and the media type must be determined.
80:
81: Determining the media type is an unusual process. The drive
82: type is obtained from the configuration manager at
83: initialization time. Any time that the changeline is set (which
84: includes startup) the media type is unknown, and must be
85: determined. The DriveMediaLimits table is used to determine
86: which drive/media combinations are allowable, and the driver
87: assumes that the media with the largest capacity is in the
88: drive. It sets up the controller to read that media, and tries
89: to read an ID mark from the disk. As long as that fails, it
90: tries a lower media type. If no media type works, an error is
91: returned. If one works, it is assumed to properly indicate the
92: media in the drive, but it could be wrong because some
93: drive/media combinations use the same controller parameters. So
94: whenever we find that the first sector on the disk is being read
95: (which should be the first thing the file system does for a new
96: disk; this will work even if the media type assumption is wrong)
97: we sneak a peek at the media descriptor byte and change our
98: assumption about the media type if necessary.
99:
100: An operation passed in by the system is called a "request".
101: This driver often breaks the request into smaller pieces called
102: "transfers" because of limitations in the amount of data that
103: can be read or written at one time.
104:
105: At the end of any operation, the motor timer (MotorTimer in the
106: controller object) should be started. If the timer runs for a
107: couple of seconds without getting cancelled, it should turn the
108: motor off.
109:
110: Background on hardware operation:
111:
112: The following info was gathered from a number of technical
113: reference documents and existing device drivers. These sources
114: often did not agree; where there was a problem, I tried to
115: determine the answer by consensus or experimentation.
116:
117: At initialization, the following steps should be performed:
118:
119: reset the controller
120: wait for an interrupt
121: for each diskette
122: issue SENSE INTERRUPT STATUS command
123: optionally issue the CONFIGURE command
124: issue SPECIFY command
125: program the data rate
126:
127: The data rate, CONFIGURE and SPECIFY information should be
128: reprogrammed after every reset.
129:
130: To do a SEEK or RECALIBRATE, the motor should be turned on and
131: the command should be issued. After the interrupt comes, a
132: SENSE INTERRUPT STATUS command should be issued.
133:
134: To do a READ or WRITE, the motor should be turned on, and left
135: to spin up for at least 500ms. The recorded data rate of the
136: inserted media can then be determined by performing a READ ID at
137: each data rate until a successful status is returned. Then
138: there should be a seek, followed by at least a 15ms head
139: settling time. DMA is set up, and the command is issued. When
140: the data has been transferred, the controller will interrupt.
141:
142: If an error is encountered, two more retries should be performed
143: by reinitializing the DMA and re-issuing the command. If that
144: fails, the disk should be recalibrated and the seek repeated for
145: two more tries.
146:
147: The following registers can be used to program the floppy
148: controller. Each is discussed in detail below:
149:
150: AT JAZZ Read/ Register Name
151: Address Address Write (for this driver)
152:
153: 3f2 write DriveControl
154: 3f4 read Status
155: 3f5 both Fifo
156: 3f7 write DataRate
157: 3f7 read DiskChange
158:
159: Notes on other register usages:
160:
161: 3f0 is used by the Intel chip, but only for PS/2s.
162:
163: 3f1 is readable on Compaqs, and called "media id". The
164: Intel chip only uses 3f1 on PS/2s.
165:
166: 3f2 is readable on the Intel chip.
167:
168: 3f3 doesn't appear to be used by anybody.
169:
170: 3f4 is writable and called "data rate select" on the Intel
171: chip.
172:
173: 3f6 is used for fixed disk operations.
174:
175: 3f7 does not seem to be mentioned by one [old] reference,
176: but all the others do - and it seems to be essential, so I'm
177: going to use it.
178:
179: DriveControl (aka "digital output", aka "floppy operations"):
180:
181: bits 0-1: drive select (values 10 and 11 not always used)
182: bit 2: 0 = reset controller, 1 = enable controller
183: bit 3: 0 = interrupts and DMA disabled, 1 = enabled
184: bit 4: 0 = drive 1 motor off, 1 = on
185: bit 5: 0 = drive 2 motor off, 1 = on
186: bit 6: 0 = drive 3 motor off, 1 = on (not always used)
187: bit 7: 0 = drive 4 motor off, 1 = on (not always used)
188:
189: Note that a drive cannot be selected unless its motor is on
190: (setting the bits at the same time is acceptable).
191:
192: Status:
193:
194: bit 0: drive 0 busy (seeking or recalibrating)
195: bit 1: drive 1 busy
196: bit 2: drive 2 busy (not always used)
197: bit 3: drive 3 busy (not always used)
198: bit 4: controller busy (from command byte until result phase)
199: bit 5: DMA is not being used
200: bit 6: 0 = data from processor to controller, 1 = reverse
201: bit 7: 1 = data ready to be transferred
202:
203: Note that command bytes can't be written to the DATA
204: register unless bit 7 is 1 and bit 6 is 0. Similarly,
205: result bytes can't be read from the DATA register unless bit
206: 7 is 1 and bit 6 is 1. The delay for this to become true
207: could be 175us on the Intel chip; older chips may take
208: longer.
209:
210: Fifo (aka "data"):
211:
212: All commands are written here one byte at a time, and all
213: results are similarly read from here. Commands and results
214: are discussed below.
215:
216: Some controllers have a buffer and programmable threshold,
217: which allows the data to be sent in chunks rather than one
218: byte at a time. This reduces the chance of an overrun.
219:
220: After some commands, the values of status registers (and
221: other things) are returned through the Fifo register.
222: Here's the layout of the status registers:
223:
224: Status Register 0:
225:
226: bits 0-1: drive number
227: bit 2: head
228: bit 3: set if drive is not ready
229: bit 4: set if drive faults, or recalibrate didn't find
230: track 0
231: bit 5: set when seek is completed
232: bits 6-7: 00 = normal termination
233: 01 = abnormal termination, error
234: 10 = invalid command
235: 11 = abnormal termination, drive became not ready
236:
237: Status Register 1:
238:
239: bit 0: set if the ID address mark wasn't found
240: bit 1: set if write-protection detected during a write
241: bit 2: set if sector not found
242: bit 3: always 0
243: bit 4: set for data overrun
244: bit 5: set if CRC error detected in ID or data
245: bit 6: always 0
246: bit 7: set on attempt to access a sector beyond the end of a
247: cylinder
248:
249: Status Register 2:
250:
251: bit 0: set if data address or deleted data mark not found
252: bit 1: set if bad cylinder found
253: bit 2: set if SCAN fails to find sector meeting condition
254: bit 3: set if SCAN command meets "equal" condition
255: bit 4: set if wrong cylinder found
256: bit 5: set if CRC error detected in data
257: bit 6: set if deleted address data mark encountered during
258: READ or SCAN
259: bit 7: always 0
260:
261: Status Register 3:
262:
263: bits 0-1: drive number
264: bit 2: head
265: bit 3: set if drive is two-sided
266: bit 4: set if drive is on track 0
267: bit 5: set if the drive is ready
268: bit 6: set if the drive is write-protected
269: bit 7: set if the drive has faulted
270:
271: DataRate (aka "configuration control"):
272:
273: bits 0-1: 00 = 500 kb/s, 01 = 300, 10 = 250, 11 = 1 Mb/s for
274: 3.5" and 125 kb/s for 5.25"
275: bits 2-7: reserved, 0
276:
277: DiskChange (aka "digital input", aka "diskette status"):
278:
279: bits 0-6: reserved (often used for fixed disks)
280: bit 7: 1 = previous diskette has been removed
281:
282: Common Commands:
283:
284: Each command and its parameters are given to the controller
285: through the Data register. The controller then executes the
286: command. When finished, the results can be read from the
287: controller through the Data register.
288:
289: A drive's motor must be on before the drive can be
290: selected. Units 0 and 1 cannot have their motor on
291: simultaneously; neither can units 2 and 3.
292:
293: A drive cannot be accessed until <head load time> has passed
294: since selecting the drive.
295:
296: A drive cannot be accessed until <head settle time> has
297: passed since an earlier access.
298:
299: Fields used in commands:
300:
301: Multi-Track: if this bit is set, both tracks of the
302: cylinder will be operated on.
303:
304: MFM/FM Mode: if this bit is set, MFM mode (double
305: density) is selected if it's implemented; if not, FM
306: mode (single density) is selected.
307:
308: Skip: when this bit is set, sectors with a deleted data
309: address mark will be skipped for READ DATA or accessed
310: for READ DELETED DATA.
311:
312: Head: one bit, 0 or 1.
313:
314: Drive Select: two bits to select drive 0 through 3.
315:
316: Cylinder: 7 bits selecting the cylinder.
317:
318: Sector: 4 bits giving the number of the first sector to
319: be accessed.
320:
321: Sector Size Code: the sector size is 2^(this value) *
322: 128. Sometimes forced to be 2, for 512-byte sectors.
323:
324: Final Sector of Track: 4 bits giving the final sector
325: number of current track.
326:
327: Gap Length: 8 bits giving the size of the gap between
328: sectors excluding the VC0 synchronization field.
329:
330: Data Length: if Sector Size Code is 0, the sector size
331: is 128 but this value says how many bytes are actually
332: transferred (extra bytes dropped on READs, extra bytes
333: zeroed on WRITEs). If Sector Size code is not 0
334: (sometimes it's forced nonzero), this value should be
335: 0xff.
336:
337: Sectors per Track: 4 bits giving the number of sectors
338: per cylinder to be initialized by a FORMAT.
339:
340: Data Pattern: 8 bits giving the pattern to be written in
341: each sector data field during a FORMAT.
342:
343: Step Rate Interval: 4 bits. The time between step
344: pulses. From .5 to 8ms in .5ms increments at 1Mb data
345: rate. See the SPECIFY command.
346:
347: Head Unload Time: 4 bits. The time from the end of a
348: read or write until the head is unloaded. 0 to 480ms in
349: 32ms increments. See the SPECIFY command.
350:
351: Head Load Time: 7 bits. The time from loading the head
352: until starting the read or write operation. 4 to 512ms
353: in 4ms increments. See the SPECIFY command.
354:
355: Non-DMA Mode Flag: 0 = DMA mode, 1 = host is interrupted
356: for each data transfer.
357:
358: New Cylinder Number: 7 bits giving the desired cylinder
359: number.
360:
361: The commands are given below. For each commands, the bytes
362: that must be written to the controller are listed. When the
363: command is finished (after an interrupt for most commands)
364: the further listed bytes MUST be read from the controller.
365:
366: READ DATA - move sector from diskette to memory via DMA.
367: Heads are automatically loaded and unloaded.
368:
369: WRITE Multi-Track, MFM/FM Mode, Skip, 00110
370: WRITE 00000, Head, Drive Select
371: WRITE Cylinder
372: WRITE Head
373: WRITE Sector
374: WRITE Sector Size Code
375: WRITE Final Sector of Track
376: WRITE Gap Length
377: WRITE Data Length
378:
379: <interrupt>
380:
381: READ Status Register 0
382: READ Status Register 1
383: READ Status Register 2
384: READ Cylinder
385: READ Head
386: READ Sector
387: READ Sector Size Code
388:
389: READ DELETED DATA - same as READ DATA, but only sectors with
390: the deleted data address mark are read.
391:
392: WRITE Multi-Track, MFM/FM Mode, Skip, 01100
393: WRITE 00000, Head, Drive Select
394: WRITE Cylinder
395: WRITE Head
396: WRITE Sector
397: WRITE Sector Size Code
398: WRITE Final Sector of Track
399: WRITE Gap Length
400: WRITE Data Length
401:
402: <interrupt>
403:
404: READ Status Register 0
405: READ Status Register 1
406: READ Status Register 2
407: READ Cylinder
408: READ Head
409: READ Sector
410: READ Sector Size Code
411:
412: READ TRACK - same as READ DATA, but all sectors from the index
413: mark to the "end of track" sector are read.
414:
415: WRITE 0, MFM/FM Mode, 000010
416: WRITE 00000, Head, Drive Select
417: WRITE Cylinder
418: WRITE Head
419: WRITE Sector
420: WRITE Sector Size Code
421: WRITE Final Sector of Track
422: WRITE Gap Length
423: WRITE Data Length
424:
425: <interrupt>
426:
427: READ Status Register 0
428: READ Status Register 1
429: READ Status Register 2
430: READ Cylinder
431: READ Head
432: READ Sector
433: READ Sector Size Code
434:
435: WRITE DATA - move sector from memory to diskette via DMA.
436: Heads are automatically loaded and unloaded.
437:
438: WRITE Multi-Track, MFM/FM Mode, 000101
439: WRITE 00000, Head, Drive Select
440: WRITE Cylinder
441: WRITE Head
442: WRITE Sector
443: WRITE Sector Size Code
444: WRITE Final Sector of Track
445: WRITE Gap Length
446: WRITE Data Length
447:
448: <interrupt>
449:
450: READ Status Register 0
451: READ Status Register 1
452: READ Status Register 2
453: READ Cylinder
454: READ Head
455: READ Sector
456: READ Sector Size Code
457:
458:
459: WRITE DELETED DATA - same as WRITE DATA, except a deleted
460: data address mark is written at the beginning of the data
461: field instead of the normal data address mark.
462:
463: WRITE Multi-Track, MFM/FM Mode, 001001
464: WRITE 00000, Head, Drive Select
465: WRITE Cylinder
466: WRITE Head
467: WRITE Sector
468: WRITE Sector Size Code
469: WRITE Final Sector of Track
470: WRITE Gap Length
471: WRITE Data Length
472:
473: <interrupt>
474:
475: READ Status Register 0
476: READ Status Register 1
477: READ Status Register 2
478: READ Cylinder
479: READ Head
480: READ Sector
481: READ Sector Size Code
482:
483: READ ID - the first ID field is read, and the status registers
484: are updated.
485:
486: WRITE 0, MFM/FM Mode, 001010
487: WRITE 00000, Head, Drive Select
488:
489: <interrupt>
490:
491: READ Status Register 0
492: READ Status Register 1
493: READ Status Register 2
494: READ Cylinder
495: READ Head
496: READ Sector
497: READ Sector Size Code
498:
499: FORMAT TRACK - the selected track is formatted from index to
500: "end of track" sector with address marks, ID fields, data
501: fields and field gaps. The data field is filled with the
502: specified pattern. The ID field data is specified by the host
503: *for each sector*.
504:
505: The DMA must be set up to send four bytes for each sector to
506: be formatted. The bytes are Cylinder, Head, Sector, and Sector
507: Size Code.
508:
509: WRITE 0, MFM/FM Mode, 001101
510: WRITE 00000, Head, Drive Select
511: WRITE Sector Size Code
512: WRITE Sectors per Track
513: WRITE Gap Length
514: WRITE Data Pattern
515:
516: <interrupt>
517:
518: READ Status Register 0
519: READ Status Register 1
520: READ Status Register 2
521: READ Undefined
522: READ Undefined
523: READ Undefined
524: READ Undefined
525:
526: RECALIBRATE - the heads are stepped to track 0. But note
527: that some controllers give up before reaching track 0, so it
528: might be necessary to RECALIBRATE more than once. All
529: drives must be RECALIBRATEd at initialization time. There
530: are no result registers, so the ISR should issue a SENSE
531: INTERRUPT STATUS command - which will result in two result
532: registers.
533:
534: WRITE 00000111
535: WRITE 000000, Drive Select
536:
537: <interrupt>
538:
539: SENSE INTERRUPT STATUS - the interrupt level is cleared, and
540: the controller status is returned.
541:
542: WRITE 00001000
543:
544: READ Status Register 0
545: READ Cylinder
546:
547: SPECIFY - the head load and unload rates, the drive step rate,
548: and the DMA data transfer mode are set.
549:
550: WRITE 00000011
551: WRITE Step Rate Interval, Head Unload Time
552: WRITE Head Load Time, Non-DMA Mode Flag
553:
554: SENSE DRIVE STATUS - the status of the selected drive is
555: returned.
556:
557: WRITE 00000100
558: WRITE 00000, Head, Drive Select
559:
560: READ Status Register 3
561:
562: SEEK - the selected drive is stepped to the new cylinder.
563: Seeks generally must be explicit, but on some controllers
564: can be made implicit via the CONFIGURE command. When not
565: implicit, READs and WRITEs should be preceded by SEEK, SENSE
566: INTERRUPT STATUS, and READ ID. There are no result
567: registers, so the ISR should issue a SENSE INTERRUPT STATUS
568: command - which does have two result registers.
569:
570: WRITE 00001111
571: WRITE 00000, Head, Drive Select
572: WRITE New Cylinder Number
573:
574: <interrupt>
575:
576: Commands not always implemented:
577:
578: Any command not implemented by a controller will result in
579: Status Register 0 returning x80 - "invalid command".
580:
581: The following commands are implemented by some controllers,
582: but not by all of the ones studied:
583:
584: Scan Equal
585: Scan Low or Equal
586: Scan High or Equal
587: Verify
588: Version
589: Configure
590: Relative Seek
591: Dump Registers
592: Perpendicular Mode
593:
594:
595: Data structures:
596:
597: For each floppy controller in the system (there's seldom more
598: than one) a controller data area is allocated. This area holds
599: all information about the controller, and all information common
600: to all of the drives attached to it. It has the following
601: fields:
602:
603: FifoBuffer[10] - data is sent to and received from the
604: controller via a FIFO port. A single routine,
605: FlIssueCommand(), is used to send the command and
606: parameters, and receive the result bytes. Before calling
607: FlIssueCommand(), the parameters should be placed into the
608: FifoBuffer; and after the command, the result bytes can be
609: read from the buffer. Note that for commands with a result
610: phase, the first result byte is read into the buffer by the
611: ISR. For commands without a result phase, the ISR writes a
612: SENSE INTERRUPT STATUS command, which means that *that*
613: command's result bytes will have to be read by
614: FlIssueCommand().
615:
616: InterruptDelay - set to a few seconds. When we're waiting
617: for an interrupt, we use this as a time-out value.
618:
619: Minimum10msDelay - set to 10 milliseconds, which is the
620: smallest unit of time that the floppy thread can block. Used
621: when blocking to wait for the controller to become ready to
622: transfer bytes through the FIFO.
623:
624: ListEntry - the list of requests for the floppy driver to
625: process. The dispatch routines add requests to the tail of
626: the list, and the floppy thread takes them off at the head.
627: In some cases of hardware failure, the floppy thread will
628: reinsert a request at the head of the list to try the packet
629: again.
630:
631: InterruptEvent - the event that is waited on when we're
632: expecting the controller to interrupt. It should be reset
633: before programming the controller, and set in the DPC that
634: is queued by the ISR.
635:
636: AllocateAdapterChannelEvent - the event that is waited on
637: when we're allocating a DMA adapter channel. It should be
638: reset before requesting the adapter, and set by the DPC that
639: is queued by the IO system when the adapter channel is
640: available.
641:
642: RequestSemaphore - the semaphore that the floppy thread waits
643: on. It should be released by the dispatch routines whenever
644: they add a request to the list. Note that it can also be
645: released when the thread is supposed to terminate; see
646: "UnloadingDriver".
647:
648: TimerSpinLock - a spinlock that is used to protect access to
649: "MotorTimer" and the DriveControl register, since they are
650: accessed by FloppyMotorOffDpc() as well as by routines in
651: the floppy thread.
652:
653: ListSpinLock - a spinlock that is allocated and used when
654: manipulating the list of requests for the floppy thread in
655: an atomic fashion (via the ExInterlocked* routines).
656:
657: InterruptObject - a pointer to an interrupt object; it must
658: be passed to IoConnectInterrupt.
659:
660: MapRegisterBase - the base address of the map registers.
661: Whenever an adapter channel is allocated, this value is passed
662: to our DPC. It's stored in the controller object so it can
663: be used when we call IoMapTransfer() and
664: IoFlushAdapterBuffers().
665:
666: IoBuffer - this driver always needs to allocate at least a
667: page to format floppies. On systems where there might not
668: be enough map registers to map the largest possible transfer
669: (the size of the largest supported track on the system), a
670: contiguous buffer of that size is allocated. Transfers for
671: which there aren't enough map registers are copied to or from
672: this buffer, since it is contiguous.
673:
674: IoBufferMdl - an MDL (memory descriptor list) to describe
675: "IoBuffer". Used to lock the pages, flush the buffer, etc.
676:
677: AdapterObject - an object obtained from HalGetAdapter() that
678: must be used when allocating a DMA adapter channel.
679:
680: CurrentDeviceObject - set to the device object in question
681: whenever an interrupt is expected. This aids debugging and
682: lets the ISR know whether an interrupt was expected or not.
683:
684: DriverObject - We keep a pointer around to the driver object
685: so that we can log an error if the controller object. The reason
686: we don't use the CurrentDeviceObject is that we may not have one
687: when we get around to logging the error.
688:
689: ControllerAddress - the virtual or I/O space address of the
690: base of the floppy controller, which is obtained from
691: configuration management.
692:
693: LastDisketteExtension - this value is used with
694: CreatedArtificialDrive, below, to decide when to return an
695: error. If the system only has one drive, it uses this field
696: to determine whether the device object describing the drive
697: has changed, so it knows when to return an error so the user
698: will be prompted to insert the other diskette.
699:
700: IoBufferSize - the size of "IoBuffer"; it is either a single
701: page (if there's plenty of map registers) or the size of the
702: largest track supported by the drives in the system.
703:
704: IsrReentered - This is counter that is used to determine
705: if we are in a hang condition from the controller on a
706: level sensitive machine.
707:
708: MotorTimer - used to count how long the drive motor has been
709: on, to determine when to turn it off. At the end of every
710: operation, it's set to 3; MotorOffDpc() is called every
711: second to decrement it. When it reaches 0, the motor is
712: turned off. Whenever the motor doesn't need to be turned
713: off (ie the drive is in use, or already off) the value is
714: -1. Note that "3" is an upper boundary; the motor will be
715: turned off between 2 and 3 seconds after the last operation.
716:
717: SpanOfControllerAddress - Indicates the number of bytes
718: used by the controllers register set. This is only useful
719: when the device is being unloaded and the controller address
720: is being unmapped.
721:
722: LastDriveMediaType - every time FlDatarateSpecifyConfigure()
723: is called, this value is set to the DriveMediaType that it
724: configured the controller to handle. When FlStartDrive() is
725: preparing an operation, it checks to see if the current
726: drive/media combination is the same - if not,
727: FlDatarateSpecifyConfigure() must be called again.
728:
729: NumberOfMapRegisters - the number of map registers available
730: to this driver, obtained from HalGetAdapter(), and possibly
731: lowered to the maximum number needed. Each register allows
732: the driver to map a single page (or more if the pages are
733: contiguous, but that's only counted on when the driver
734: allocated the contiguous buffer itself). This value is used
735: to determine whether or not the driver needs to allocate a
736: contiguous buffer to accomodate a transfer the size of the
737: largest track, and it is passed to IoAllocateAdapterChannel().
738:
739: NumberOfDrives - the number of drives attached to this
740: controller, obtained from the configuration manager. This
741: is used when allocating device objects and resetting the
742: hardware.
743:
744: DriveControlImage - the image of the drive control register.
745: We must keep track of it since the register is read-only on
746: some systems. It should always be updated before writing to
747: the drive control register.
748:
749: ControllerConfigurable - indicates whether or not the
750: CONFIGURE command is available. Assumed to be TRUE, it's
751: set to FALSE if an attempt to issue the CONFIGURE command
752: fails. Controllers with the CONFIGURE command are configured
753: to SEEK implicitly.
754:
755: HardwareFailCount - this is only used in FlFinishOperation.
756: If an operation fails due to a hardware problem, we'll retry
757: a certain number of times, and this keeps track of how many
758: times we've retried.
759:
760: HardwareFailed - this Boolean is set to FALSE at
761: initialization time and when each packet starts (even if
762: it's a retry). Whenever a hardware problem is encountered,
763: it is set to TRUE. At initialization time, failure to
764: initialize the hardware on the first drive means we must try
765: again on subsequent drives - if we never succeed, the driver
766: is unloaded. For each packet, hardware errors mean we'll
767: reset the hardware and retry the packet until it succeeds or
768: we overrun HardwareFailCount.
769:
770: CommandHasResultPhase - whenever a command is issued,
771: FlIssueCommand() sets this to TRUE if the command will
772: return result bytes. FloppyInterruptService() uses this to
773: decide how to dismiss the interrupt. Note that the BUSY bit
774: in the STATUS register should give us this information, but
775: it's sometimes set when it shouldn't be.
776:
777: CreatedArtificialDrive - if there's only one drive in the
778: system, the initialization code will create a *two* device
779: objects to describe it, and set this to TRUE. Whenever a
780: drive is accessed, if this is TRUE and the device object
781: being used is different, an error is returned so the user
782: will be prompted to insert the other diskette.
783:
784: UnloadingDriver - set to TRUE when the driver is supposed to
785: unload itself; setting this and then signalling the request
786: semaphore tells the thread to terminate itself.
787:
788: MappedControllerAddress - Set to TRUE indicates that when
789: unloading the driver, the pointer to the device controller
790: base register should be unmapped.
791:
792: For each physical floppy drive, a device object is allocated so
793: that the I/O system can access the drive. Attached to each device
794: object is a diskette extension structure, which contains
795: information specific to the drive and the media in it. Each
796: diskette extension contains a pointer to the controller data area
797: for the controller that it's attached to. Fields in the structure:
798:
799: DeviceObject - a pointer to the device object to which this
800: diskette extension is appended.
801:
802: ControllerData - a pointer to the controller data area that
803: describes the controller this drive is attached to.
804:
805: DriveType - the type of the physical drive, as defined in
806: flo_data.h.
807:
808: BytesPerSector - the bytes per sector of the media that was
809: last identified in the drive. Used to validate access
810: requests in the dispatch routines.
811:
812: ByteCapacity - the total number of bytes on the media that
813: was last identified in the drive. Used to validate access
814: requests in the dispatch routines.
815:
816: MediaType - the last type of media identified in the drive
817: (or "Unknown") as defined in ntdddisk.h. This value is used
818: to determine whether other media values in the diskette
819: extension are valid, and whether or not
820: FlDetermineMediaType() needs to be called.
821:
822: DriveMediaType - the last drive/media combination value,
823: determined when the media in the drive was last identified.
824: This is used to index into the DriveMediaConstants table.
825:
826: DeviceUnit - the controller-relative diskette number, which
827: is needed for some controller commands.
828:
829: DriveOnValue - the value that must be written to the
830: Drive Control register to start up the drive in question.
831: It's the "DeviceUnit" plus a few bits.
832:
833: ArtificialVerifyRequired - if there's only one drive in the
834: system, the user is prompted to switch drives by returning
835: STATUS_NO_MEDIA_IN_DEVICE. At that time, this value is set
836: to TRUE, so that the next time STATUS_VERIFY_REQUIRED can be
837: returned, to tell the file system to clean out it's caches.
838:
839: The DriveMediaLimits table, which is read-only, tells the driver
840: which drive/media combinations are valid for a drive type. The
841: table is indexed by the drive type, and has LowestDriveMediaType
842: and HighestDriveMediaType fields. The drive/media types are
843: enumerated in ascending order, so the driver can start at the
844: highest possible combination and decrement the value until the
845: correct one is found (or it goes below the lowest valid
846: drive/media combination).
847:
848: The DriveMediaConstants table, which is read-only, tells the driver
849: values that it needs to use when communicating with the controller
850: given the drive and media type. The table is indexed by the
851: DriveMedia number (unique for each drive/media combination) and
852: has the following fields:
853:
854: MediaType - the type of media specified by this drive/media
855: combination. The drive type is stored in the diskette
856: extension, since it never changes.
857:
858: StepRateHeadUnloadTime - a combination value that is written
859: to the controller as part of the SPECIFY command. The step
860: rate is how fast the heads can be moved track-to-track, and
861: the head unload time is how long it takes for the heads to
862: be unloaded after a READ or WRITE.
863:
864: HeadLoadTime - a value that is written to the controller as
865: part of the SPECIFY command. The head load time is how long
866: it takes the heads to stabilize after a SEEK before a READ
867: or WRITE can be initiated.
868:
869: MotorOffTime - not used by this driver, but included to keep
870: the table complete.
871:
872: SectorLengthCode - a code number that specifies the sector
873: size. The sector size is 2 to the "code" power, times 128.
874: So 0 means 128 bytes, 1 means 256, 2 means 512, etc. This
875: number is needed to pass to the controller for several
876: commands.
877:
878: BytesPerSector - the bytes per sector, which can be
879: determined from SectorLengthCode. Included as a separate
880: field for simplicity and speed.
881:
882: SectorsPerTrack - the number of sectors on a track (one head
883: of a cylinder).
884:
885: ReadWriteGapLength - the space between sectors, not
886: including the synchronization field. Used for READ and
887: WRITE commands.
888:
889: FormatGapLength - gap length passed to the FORMAT command.
890:
891: FormatFillCharacter - passed to the FORMAT command; this
892: byte will be used to fill the data fields on the disk.
893:
894: HeadSettleTime - the amount of time, in milliseconds, that
895: the driver must wait after performing a seek.
896:
897: MotorSettleTimeRead - the amount of time, in milliseconds,
898: that the driver must wait for the drive to spin up before
899: performing a READ.
900:
901: MotorSettleTimeWrite - the amount of time, in milliseconds,
902: that the driver must wait for the drive to spin up before
903: performing a WRITE. Note that WRITEs are more picky about
904: stable rotation speeds, so the drive must always spin up for
905: a longer than it would for a READ.
906:
907: MaximumTrack - the number of the highest track, or cylinder
908: on disk (zero-based).
909:
910: CylinderShift - normally 0, so it does nothing. This field
911: is used as a shift for the cylinder number before a SEEK
912: command. This is because of a hardware bug; 1.2Mb drives
913: don't seek the proper distance for low-density media, so for
914: those drive/media combinations this value is 1.
915:
916: DataTransferRate - the number written to the Datarate
917: register before accessing the media.
918:
919: NumberOfHeads - number of heads on the media, always 1 or 2
920: for floppies.
921:
922: DataLength - always 0xff, this value must be given to the
923: controller for a READ or WRITE command.
924:
925: The CommandTable, which is read-only, tells the driver how many
926: bytes it has to send and receive when issuing a command to the
927: controller. It is indexed by the command itself (minus any extra
928: bits, like COMMND_MFM) and has the following fields:
929:
930: NumberOfParameters - the number of parameter bytes that must
931: be sent along with this command.
932:
933: FirstResultByte - if the command has a result phase, then the
934: ISR reads the first byte so this value is 1 (meaning that the
935: 0th byte has already been read). If there is no result phase,
936: then the ISR must give a SENSE INTERRUPT STATUS command, and
937: this value is 0.
938:
939: NumberOfResultBytes - the number of bytes that must be read
940: from the controller after this command. For commands with
941: a result phase, this is the number of bytes returned minus
942: one (which was read by the ISR); for commands without a result
943: phase, this is "2" since that many bytes are returned by the
944: SENSE INTERRUPT STATUS command that is issued by the ISR.
945:
946: InterruptExpected - a Boolean that indicates whether or not
947: this command will give an interrupt.
948:
949: AlwaysImplemented - a Boolean that indicates whether or not
950: this command will always work. The CONFIGURE command, for
951: example, is useful but not always available. This helps to
952: determine the correct course of action when the controller
953: returns an error.
954:
955: Hardware quirks:
956:
957: Many controllers will only step 77 tracks on a recalibrate
958: command. But many drives have more tracks than that, so two
959: recalibrates are sometimes needed.
960:
961: When a 40-track diskette is in a 1.2Mb drive, the cylinder
962: number must be *doubled* before seeking. The number returned by
963: the seek will be the fake number, but the number returned by a
964: READ ID will be the correct cylinder. This makes implied SEEKs
965: impossible on low-density 5.25" media.
966:
967: Some machines will give an unexpected interrupt during a
968: controller reset unless bit 2 of the drive control register is
969: set in BOTH of the bytes that are written to the register.
970:
971: On fast machines, the BUSY bit is sometimes set in the main
972: status register even though the command doesn't have a result
973: phase and the command is obviously finished (as evidenced by the
974: fact that it interrupted; the ISR is where this problem shows
975: up).
976:
977: On at least the NCR 8 processor machine, we have seen the driver's
978: system thread run before the floppy controller can start the
979: SENSE_INTERRUPT command. We have placed code in the ISR to spin
980: until the SENSE command starts. (Actually it will time
981: out after ISR_SENSE_RETRY_COUNT 1 microsecond stalls.)
982:
983: --*/
984:
985: //
986: // Include files.
987: //
988:
989: #include "ntddk.h" // various NT definitions
990: #include "ntdddisk.h" // disk device driver I/O control codes
991: #include <flo_data.h> // this driver's data declarations
992:
993:
994: //
995: // This is the actual definition of FloppyDebugLevel.
996: // Note that it is only defined if this is a "debug"
997: // build.
998: //
999: #if DBG
1000: extern ULONG FloppyDebugLevel = 0;
1001: #endif
1002:
1003: #ifdef ALLOC_PRAGMA
1004: #pragma alloc_text(init,DriverEntry)
1005: #pragma alloc_text(init,FlConfigCallBack)
1006: #pragma alloc_text(init,FlGetConfigurationInformation)
1007: #pragma alloc_text(init,FlReportResources)
1008: #pragma alloc_text(init,FlInitializeController)
1009: #pragma alloc_text(init,FlInitializeDrive)
1010: #pragma alloc_text(init,FlGetControllerBase)
1011: #endif
1012:
1013: // #define KEEP_COUNTERS 1
1014:
1015: #ifdef KEEP_COUNTERS
1016: ULONG FloppyUsedSeek = 0;
1017: ULONG FloppyNoSeek = 0;
1018: ULONG FloppyUsedBuffer = 0;
1019: ULONG FloppyInterrupts = 0;
1020: ULONG FloppySpurious = 0;
1021: ULONG FloppyIntrBitSet = 0;
1022: ULONG FloppyDPCs = 0;
1023: ULONG FloppyThreadWake = 0;
1024: LARGE_INTEGER FloppyIntrDelay = { 0, 0 };
1025: LARGE_INTEGER FloppyDPCDelay = { 0, 0 };
1026: LARGE_INTEGER FloppyThreadDelay = { 0, 0 };
1027: LARGE_INTEGER FloppyFromIntrDelay = { 0, 0 };
1028: LARGE_INTEGER FloppyThreadTime = { 0, 0 };
1029: LARGE_INTEGER FloppyIntrTime = { 0, 0 };
1030: LARGE_INTEGER FloppyEndIntrTime = { 0, 0 };
1031: LARGE_INTEGER FloppyDPCTime = { 0, 0 };
1032: #endif
1033:
1034:
1035: NTSTATUS
1036: DriverEntry(
1037: IN PDRIVER_OBJECT DriverObject,
1038: IN PUNICODE_STRING RegistryPath
1039: )
1040:
1041: /*++
1042:
1043: Routine Description:
1044:
1045: This routine is the driver's entry point, called by the I/O system
1046: to load the driver. This routine can be called any number of times,
1047: as long as the IO system and the configuration manager conspire to
1048: give it an unmanaged controller to support at each call. It could
1049: also be called a single time and given all of the controllers at
1050: once.
1051:
1052: It initializes the passed-in driver object, calls the configuration
1053: manager to learn about the devices that it is to support, and for
1054: each controller to be supported it calls a routine to initialize the
1055: controller (and all drives attached to it).
1056:
1057: Arguments:
1058:
1059: DriverObject - a pointer to the object that represents this device
1060: driver.
1061:
1062: Return Value:
1063:
1064: If we successfully initialize at least one drive, STATUS_SUCCESS is
1065: returned.
1066:
1067: If we don't (because the configuration manager returns an error, or
1068: the configuration manager says that there are no controllers or
1069: drives to support, or no controllers or drives can be successfully
1070: initialized), then the last error encountered is propogated.
1071:
1072: --*/
1073:
1074: {
1075: PCONFIG_DATA configData; // pointer to config mgr's returned data
1076: NTSTATUS ntStatus;
1077: UCHAR controllerNumber;
1078: BOOLEAN partlySuccessful = FALSE; // TRUE if any controller init'd properly
1079:
1080: //
1081: // We use this to query into the registry as to whether we
1082: // should break at driver entry.
1083: //
1084: RTL_QUERY_REGISTRY_TABLE paramTable[3];
1085: ULONG zero = 0;
1086: ULONG debugLevel = 0;
1087: ULONG shouldBreak = 0;
1088: PWCHAR path;
1089:
1090: UNREFERENCED_PARAMETER(RegistryPath);
1091:
1092: //
1093: // Since the registry path parameter is a "counted" UNICODE string, it
1094: // might not be zero terminated. For a very short time allocate memory
1095: // to hold the registry path zero terminated so that we can use it to
1096: // delve into the registry.
1097: //
1098: // NOTE NOTE!!!! This is not an architected way of breaking into
1099: // a driver. It happens to work for this driver because the author
1100: // likes to do things this way.
1101: //
1102:
1103: if (path = ExAllocatePool(
1104: PagedPool,
1105: RegistryPath->Length+sizeof(WCHAR)
1106: )) {
1107:
1108: RtlZeroMemory(
1109: ¶mTable[0],
1110: sizeof(paramTable)
1111: );
1112: RtlZeroMemory(
1113: path,
1114: RegistryPath->Length+sizeof(WCHAR)
1115: );
1116: RtlMoveMemory(
1117: path,
1118: RegistryPath->Buffer,
1119: RegistryPath->Length
1120: );
1121: paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1122: paramTable[0].Name = L"BreakOnEntry";
1123: paramTable[0].EntryContext = &shouldBreak;
1124: paramTable[0].DefaultType = REG_DWORD;
1125: paramTable[0].DefaultData = &zero;
1126: paramTable[0].DefaultLength = sizeof(ULONG);
1127: paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1128: paramTable[1].Name = L"DebugLevel";
1129: paramTable[1].EntryContext = &debugLevel;
1130: paramTable[1].DefaultType = REG_DWORD;
1131: paramTable[1].DefaultData = &zero;
1132: paramTable[1].DefaultLength = sizeof(ULONG);
1133:
1134: if (!NT_SUCCESS(RtlQueryRegistryValues(
1135: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
1136: path,
1137: ¶mTable[0],
1138: NULL,
1139: NULL
1140: ))) {
1141:
1142: shouldBreak = 0;
1143: debugLevel = 0;
1144:
1145: }
1146:
1147: }
1148:
1149: //
1150: // We don't need that path anymore.
1151: //
1152:
1153: if (path) {
1154:
1155: ExFreePool(path);
1156:
1157: }
1158:
1159: #if DBG
1160: FloppyDebugLevel = debugLevel;
1161: #endif
1162:
1163: if (shouldBreak) {
1164:
1165: DbgBreakPoint();
1166:
1167: }
1168:
1169: FloppyDump(
1170: FLOPSHOW,
1171: ("Floppy: DriverEntry...\n")
1172: );
1173:
1174: //
1175: // Ask configuration manager for information on the hardware that
1176: // we're supposed to support.
1177: //
1178:
1179: ntStatus = FlGetConfigurationInformation( &configData );
1180:
1181: //
1182: // If FlGetConfigurationInformation() failed, just exit and propogate
1183: // the error. If it said that there are no controllers to support,
1184: // return an error.
1185: // Otherwise, try to init the controllers. If at least one succeeds,
1186: // return STATUS_SUCCESS, otherwise return the last error.
1187: //
1188:
1189: if ( NT_SUCCESS( ntStatus ) ) {
1190:
1191: //
1192: // Call FlInitializeController() for each controller (and its
1193: // attached drives) that we're supposed to support.
1194: //
1195: // Return success if we successfully initialize at least one
1196: // device; propogate error otherwise. Set an error first in
1197: // case there aren't any controllers.
1198: //
1199:
1200: ntStatus = STATUS_NO_SUCH_DEVICE;
1201:
1202: for ( controllerNumber = 0;
1203: controllerNumber < configData->NumberOfControllers;
1204: controllerNumber++ ) {
1205:
1206: ntStatus = FlInitializeController(
1207: configData,
1208: controllerNumber,
1209: DriverObject );
1210:
1211: if ( NT_SUCCESS( ntStatus ) ) {
1212:
1213: partlySuccessful = TRUE;
1214: }
1215: }
1216:
1217: if ( partlySuccessful ) {
1218:
1219: ntStatus = STATUS_SUCCESS;
1220:
1221: //
1222: // Initialize the driver object with this driver's entry points.
1223: //
1224:
1225: DriverObject->MajorFunction[IRP_MJ_CREATE] =
1226: FloppyDispatchCreateClose;
1227: DriverObject->MajorFunction[IRP_MJ_CLOSE] =
1228: FloppyDispatchCreateClose;
1229: DriverObject->MajorFunction[IRP_MJ_READ] = FloppyDispatchReadWrite;
1230: DriverObject->MajorFunction[IRP_MJ_WRITE] = FloppyDispatchReadWrite;
1231: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
1232: FloppyDispatchDeviceControl;
1233: }
1234: }
1235:
1236: if ( !NT_SUCCESS( ntStatus ) ) {
1237:
1238: FloppyDump(
1239: FLOPDBGP,
1240: ("Floppy: exiting with error %lx\n", ntStatus)
1241: );
1242: }
1243:
1244: if (configData) {
1245:
1246: ExFreePool(configData);
1247:
1248: }
1249:
1250: return ntStatus;
1251: }
1252:
1253: NTSTATUS
1254: FlConfigCallBack(
1255: IN PVOID Context,
1256: IN PUNICODE_STRING PathName,
1257: IN INTERFACE_TYPE BusType,
1258: IN ULONG BusNumber,
1259: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
1260: IN CONFIGURATION_TYPE ControllerType,
1261: IN ULONG ControllerNumber,
1262: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
1263: IN CONFIGURATION_TYPE PeripheralType,
1264: IN ULONG PeripheralNumber,
1265: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
1266: )
1267:
1268: /*++
1269:
1270: Routine Description:
1271:
1272: This routine is used to acquire all of the configuration
1273: information for each floppy disk controller and the
1274: peripheral driver attached to that controller.
1275:
1276: Arguments:
1277:
1278: Context - Pointer to the confuration information we are building
1279: up.
1280:
1281: PathName - unicode registry path. Not Used.
1282:
1283: BusType - Internal, Isa, ...
1284:
1285: BusNumber - Which bus if we are on a multibus system.
1286:
1287: BusInformation - Configuration information about the bus. Not Used.
1288:
1289: ControllerType - Should always be DiskController.
1290:
1291: ControllerNumber - Which controller if there is more than one
1292: controller in the system.
1293:
1294: ControllerInformation - Array of pointers to the three pieces of
1295: registry information.
1296:
1297: PeripheralType - Should always be FloppyDiskPeripheral.
1298:
1299: PeripheralNumber - Which floppy if this controller is maintaining
1300: more than one.
1301:
1302: PeripheralInformation - Arrya of pointers to the three pieces of
1303: registry information.
1304:
1305: Return Value:
1306:
1307: STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
1308: if it couldn't map the base csr or acquire the adapter object, or
1309: all of the resource information couldn't be acquired.
1310:
1311: --*/
1312:
1313: {
1314:
1315: //
1316: // So we don't have to typecast the context.
1317: //
1318: PCONFIG_DATA config = Context;
1319:
1320: //
1321: // Simple iteration variable.
1322: //
1323: ULONG i;
1324:
1325: //
1326: // This boolean will be used to denote whether we've seen this
1327: // controller before.
1328: //
1329: BOOLEAN newController;
1330:
1331: //
1332: // This will be used to denote whether we even have room
1333: // for a new controller.
1334: //
1335: BOOLEAN outOfRoom;
1336:
1337: //
1338: // Iteration variable that will end up indexing to where
1339: // the controller information should be placed.
1340: //
1341: ULONG ControllerSlot;
1342:
1343: //
1344: // Short hand for referencing the particular controller config
1345: // information that we are building up.
1346: //
1347: PCONFIG_CONTROLLER_DATA controller;
1348:
1349: PCM_FULL_RESOURCE_DESCRIPTOR peripheralData;
1350:
1351: //
1352: // These three boolean will tell us whether we got all the
1353: // information that we needed.
1354: //
1355: BOOLEAN foundPort = FALSE;
1356: BOOLEAN foundInterrupt = FALSE;
1357: BOOLEAN foundDma = FALSE;
1358:
1359: ASSERT(ControllerType == DiskController);
1360: ASSERT(PeripheralType == FloppyDiskPeripheral);
1361:
1362: //
1363: // Check if the infprmation from the registry for this device
1364: // is valid.
1365: //
1366:
1367: if (!(((PUCHAR)PeripheralInformation[IoQueryDeviceConfigurationData]) +
1368: PeripheralInformation[IoQueryDeviceConfigurationData]->DataLength) ||
1369:
1370: !(((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
1371: ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset)) {
1372:
1373: ASSERT(FALSE);
1374: return STATUS_INVALID_PARAMETER;
1375:
1376: }
1377:
1378: peripheralData = (PCM_FULL_RESOURCE_DESCRIPTOR)
1379: (((PUCHAR)PeripheralInformation[IoQueryDeviceConfigurationData]) +
1380: PeripheralInformation[IoQueryDeviceConfigurationData]->DataOffset);
1381:
1382: //
1383: // Loop through the "slots" that we have for a new controller.
1384: // Determine if this is a controller that we've already seen,
1385: // or a new controller.
1386: //
1387:
1388: outOfRoom = TRUE;
1389: for (
1390: ControllerSlot = 0;
1391: ControllerSlot < MAXIMUM_CONTROLLERS_PER_MACHINE;
1392: ControllerSlot++
1393: ) {
1394:
1395: if (config->Controller[ControllerSlot].ActualControllerNumber == -1) {
1396:
1397: newController = TRUE;
1398: outOfRoom = FALSE;
1399: config->Controller[ControllerSlot].ActualControllerNumber =
1400: ControllerNumber;
1401: config->NumberOfControllers++;
1402: break;
1403:
1404: } else if (config->Controller[ControllerSlot].ActualControllerNumber
1405: == (LONG)ControllerNumber) {
1406:
1407: newController = FALSE;
1408: outOfRoom = FALSE;
1409: break;
1410:
1411: }
1412:
1413: }
1414:
1415: if (outOfRoom) {
1416:
1417: //
1418: // Just return and ignore the controller.
1419: //
1420:
1421: return STATUS_SUCCESS;
1422:
1423: }
1424:
1425: //
1426: // Make sure we have room for this floppy disk peripheral.
1427: //
1428:
1429: if (config->Controller[ControllerSlot].NumberOfDrives >=
1430: MAXIMUM_DISKETTES_PER_CONTROLLER) {
1431:
1432: return STATUS_SUCCESS;
1433:
1434: }
1435:
1436: controller = &config->Controller[ControllerSlot];
1437:
1438: if (newController) {
1439:
1440: PCM_FULL_RESOURCE_DESCRIPTOR controllerData =
1441: (PCM_FULL_RESOURCE_DESCRIPTOR)
1442: (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
1443: ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);
1444:
1445: //
1446: // We have the pointer. Save off the interface type and
1447: // the busnumber for use when we call the Hal and the
1448: // Io System.
1449: //
1450:
1451: controller->InterfaceType = BusType;
1452: controller->BusNumber = BusNumber;
1453: controller->SharableVector = TRUE;
1454: controller->SaveFloatState = FALSE;
1455:
1456: //
1457: // We need to get the following information out of the partial
1458: // resource descriptors.
1459: //
1460: // The irql and vector.
1461: //
1462: // The dma channel.
1463: //
1464: // The base address and span covered by the floppy controllers
1465: // registers.
1466: //
1467: // It is not defined how these appear in the partial resource
1468: // lists, so we will just loop over all of them. If we find
1469: // something we don't recognize, we drop that information on
1470: // the floor. When we have finished going through all the
1471: // partial information, we validate that we got the above
1472: // three.
1473: //
1474:
1475: for (
1476: i = 0;
1477: i < controllerData->PartialResourceList.Count;
1478: i++
1479: ) {
1480:
1481: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
1482: &controllerData->PartialResourceList.PartialDescriptors[i];
1483:
1484: switch (partial->Type) {
1485:
1486: case CmResourceTypePort: {
1487:
1488: foundPort = TRUE;
1489:
1490: //
1491: // Save of the pointer to the partial so
1492: // that we can later use it to report resources
1493: // and we can also use this later in the routine
1494: // to make sure that we got all of our resources.
1495: //
1496:
1497: controller->SpanOfControllerAddress =
1498: partial->u.Port.Length;
1499: controller->OriginalBaseAddress =
1500: partial->u.Port.Start;
1501: controller->ResourcePortType =
1502: !!partial->Flags;
1503: controller->ControllerBaseAddress =
1504: FlGetControllerBase(
1505: BusType,
1506: BusNumber,
1507: partial->u.Port.Start,
1508: controller->SpanOfControllerAddress,
1509: (BOOLEAN)!!partial->Flags,
1510: &controller->MappedAddress
1511: );
1512:
1513: if (!controller->ControllerBaseAddress) {
1514:
1515: return STATUS_INSUFFICIENT_RESOURCES;
1516:
1517: }
1518:
1519: break;
1520: }
1521: case CmResourceTypeInterrupt: {
1522:
1523: foundInterrupt = TRUE;
1524: if (partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
1525:
1526: controller->InterruptMode = Latched;
1527:
1528: } else {
1529:
1530: controller->InterruptMode = LevelSensitive;
1531:
1532: }
1533:
1534: controller->OriginalIrql = partial->u.Interrupt.Level;
1535: controller->OriginalVector = partial->u.Interrupt.Vector;
1536: controller->ControllerVector =
1537: HalGetInterruptVector(
1538: BusType,
1539: BusNumber,
1540: partial->u.Interrupt.Level,
1541: partial->u.Interrupt.Vector,
1542: &controller->ControllerIrql,
1543: &controller->ProcessorMask
1544: );
1545:
1546: break;
1547: }
1548: case CmResourceTypeDma: {
1549:
1550: DEVICE_DESCRIPTION deviceDesc = {0};
1551:
1552: foundDma = TRUE;
1553: controller->OriginalDmaChannel = partial->u.Dma.Channel;
1554: deviceDesc.Version = DEVICE_DESCRIPTION_VERSION;
1555: deviceDesc.DmaWidth = Width8Bits;
1556: deviceDesc.DemandMode = TRUE;
1557: deviceDesc.MaximumLength =
1558: DriveMediaConstants[NUMBER_OF_DRIVE_MEDIA_COMBINATIONS-1].
1559: BytesPerSector *
1560: DriveMediaConstants[NUMBER_OF_DRIVE_MEDIA_COMBINATIONS-1].
1561: SectorsPerTrack;
1562:
1563: //
1564: // Always ask for one more page than maximum transfer size.
1565: //
1566:
1567: deviceDesc.MaximumLength += PAGE_SIZE;
1568:
1569: deviceDesc.DmaChannel = partial->u.Dma.Channel;
1570: deviceDesc.InterfaceType = BusType;
1571: deviceDesc.DmaSpeed = TypeA;
1572: controller->AdapterObject =
1573: HalGetAdapter(
1574: &deviceDesc,
1575: &controller->NumberOfMapRegisters
1576: );
1577:
1578: if (!controller->AdapterObject) {
1579:
1580: return STATUS_INSUFFICIENT_RESOURCES;
1581:
1582: }
1583:
1584: break;
1585:
1586: }
1587: default: {
1588:
1589: break;
1590:
1591: }
1592:
1593: }
1594:
1595: }
1596:
1597: //
1598: // If we didn't get all the information then we return
1599: // insufficient resources.
1600: //
1601:
1602: if ((!foundPort) ||
1603: (!foundInterrupt) ||
1604: (!foundDma)) {
1605:
1606: return STATUS_INSUFFICIENT_RESOURCES;
1607:
1608: }
1609:
1610: }
1611:
1612: //
1613: // With Version 2.0 or greater for this resource list, we will get
1614: // the full int13 information for the drive. So get that if available.
1615: //
1616: // Otherwise, the only thing that we want out of the peripheral information
1617: // is the maximum drive capacity.
1618: //
1619:
1620: //
1621: // Drop any other information on the floor other then the
1622: // device specfic floppy information.
1623: //
1624:
1625: for (
1626: i = 0;
1627: i < peripheralData->PartialResourceList.Count;
1628: i++
1629: ) {
1630:
1631: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
1632: &peripheralData->PartialResourceList.PartialDescriptors[i];
1633:
1634: if (partial->Type == CmResourceTypeDeviceSpecific) {
1635:
1636: //
1637: // Point to right after this partial. This will take
1638: // us to the beginning of the "real" device specific.
1639: //
1640:
1641: PCM_FLOPPY_DEVICE_DATA fDeviceData;
1642: UCHAR driveType;
1643: PDRIVE_MEDIA_CONSTANTS biosDriveMediaConstants =
1644: &(controller->BiosDriveMediaConstants[controller->NumberOfDrives]);
1645:
1646:
1647: fDeviceData = (PCM_FLOPPY_DEVICE_DATA)(partial + 1);
1648:
1649: //
1650: // Get the driver density
1651: //
1652:
1653: switch ( fDeviceData->MaxDensity ) {
1654:
1655: case 360:
1656:
1657: driveType = DRIVE_TYPE_0360;
1658:
1659: break;
1660:
1661:
1662: case 1200:
1663:
1664: driveType = DRIVE_TYPE_1200;
1665:
1666: break;
1667:
1668:
1669: case 1185:
1670:
1671: driveType = DRIVE_TYPE_1200;
1672:
1673: break;
1674:
1675: case 1423:
1676:
1677: driveType = DRIVE_TYPE_1440;
1678:
1679: break;
1680:
1681: case 1440:
1682:
1683: driveType = DRIVE_TYPE_1440;
1684:
1685: break;
1686:
1687: case 2880:
1688:
1689: driveType = DRIVE_TYPE_2880;
1690:
1691: break;
1692:
1693: default:
1694:
1695: FloppyDump(
1696: FLOPDBGP,
1697: ("Floppy: Bad DriveCapacity!\n"
1698: "------ density is %d\n",
1699: fDeviceData->MaxDensity)
1700: );
1701:
1702: driveType = DRIVE_TYPE_1200;
1703:
1704: FloppyDump(
1705: FLOPDBGP,
1706: ("Floppy: run a setup program to set the floppy\n"
1707: "------ drive type; assuming 1.2mb\n"
1708: "------ (type is %x)\n",fDeviceData->MaxDensity)
1709: );
1710:
1711: break;
1712:
1713: }
1714:
1715: controller->DriveType[controller->NumberOfDrives] = driveType;
1716:
1717: //
1718: // Pick up all the default from our own table and override
1719: // with the BIOS information
1720: //
1721:
1722: *biosDriveMediaConstants = DriveMediaConstants[
1723: DriveMediaLimits[driveType].HighestDriveMediaType];
1724:
1725: //
1726: // If the version is high enough, get the rest of the information.
1727: // DeviceSpecific information with a version >= 2 should have
1728: // this information
1729: //
1730:
1731: if (fDeviceData->Version >= 2) {
1732:
1733: // biosDriveMediaConstants->MediaType =
1734:
1735: biosDriveMediaConstants->StepRateHeadUnloadTime =
1736: fDeviceData->StepRateHeadUnloadTime;
1737:
1738: biosDriveMediaConstants->HeadLoadTime =
1739: fDeviceData->HeadLoadTime;
1740:
1741: biosDriveMediaConstants->MotorOffTime =
1742: fDeviceData->MotorOffTime;
1743:
1744: biosDriveMediaConstants->SectorLengthCode =
1745: fDeviceData->SectorLengthCode;
1746:
1747: // biosDriveMediaConstants->BytesPerSector =
1748:
1749: biosDriveMediaConstants->SectorsPerTrack =
1750: fDeviceData->SectorPerTrack;
1751:
1752: biosDriveMediaConstants->ReadWriteGapLength =
1753: fDeviceData->ReadWriteGapLength;
1754:
1755: biosDriveMediaConstants->FormatGapLength =
1756: fDeviceData->FormatGapLength;
1757:
1758: biosDriveMediaConstants->FormatFillCharacter =
1759: fDeviceData->FormatFillCharacter;
1760:
1761: biosDriveMediaConstants->HeadSettleTime =
1762: fDeviceData->HeadSettleTime;
1763:
1764: biosDriveMediaConstants->MotorSettleTimeRead =
1765: fDeviceData->MotorSettleTime * 1000 / 8;
1766:
1767: biosDriveMediaConstants->MotorSettleTimeWrite =
1768: fDeviceData->MotorSettleTime * 1000 / 8;
1769:
1770: biosDriveMediaConstants->MaximumTrack =
1771: fDeviceData->MaximumTrackValue;
1772:
1773: // biosDriveMediaConstants->CylinderShift =
1774:
1775: // NOTE CHICAGO does not use this value
1776: //
1777: //biosDriveMediaConstants->DataTransferRate =
1778: // fDeviceData->DataTransferRate;
1779:
1780: // biosDriveMediaConstants->NumberOfHeads =
1781:
1782: biosDriveMediaConstants->DataLength =
1783: fDeviceData->DataTransferLength;
1784:
1785: }
1786:
1787: }
1788:
1789: }
1790:
1791: controller->NumberOfDrives++;
1792: controller->OkToUseThisController = TRUE;
1793:
1794: return STATUS_SUCCESS;
1795: }
1796:
1797: NTSTATUS
1798: FlGetConfigurationInformation(
1799: OUT PCONFIG_DATA *ConfigData
1800: )
1801:
1802: /*++
1803:
1804: Routine Description:
1805:
1806: This routine is called by DriverEntry() to get information about the
1807: devices to be supported from configuration mangement and/or the
1808: hardware architecture layer (HAL).
1809:
1810: Arguments:
1811:
1812: ConfigData - a pointer to the pointer to a data structure that
1813: describes the controllers and the drives attached to them
1814:
1815: Return Value:
1816:
1817: Returns STATUS_SUCCESS unless there is no drive 0 or we didn't get
1818: any configuration information.
1819:
1820: --*/
1821:
1822: {
1823:
1824: INTERFACE_TYPE InterfaceType;
1825: NTSTATUS Status;
1826: ULONG i;
1827:
1828: *ConfigData = ExAllocatePool(
1829: PagedPool,
1830: sizeof(CONFIG_DATA)
1831: );
1832:
1833: if (!*ConfigData) {
1834:
1835: return STATUS_INSUFFICIENT_RESOURCES;
1836:
1837: }
1838:
1839: //
1840: // Zero out the config structure and fill in the actual
1841: // controller numbers with -1's so that the callback routine
1842: // can recognize a new controller.
1843: //
1844:
1845: RtlZeroMemory(
1846: *ConfigData,
1847: sizeof(CONFIG_DATA)
1848: );
1849:
1850: for (
1851: i = 0;
1852: i < MAXIMUM_CONTROLLERS_PER_MACHINE;
1853: i++
1854: ) {
1855:
1856: (*ConfigData)->Controller[i].ActualControllerNumber = -1;
1857:
1858: }
1859:
1860: //
1861: // Go through all of the various bus types looking for
1862: // disk controllers. The disk controller sections of the
1863: // hardware registry only deal with the floppy drives.
1864: // The callout routine that can get called will then
1865: // look for information pertaining to a particular
1866: // device on the controller.
1867: //
1868:
1869: for (
1870: InterfaceType = 0;
1871: InterfaceType < MaximumInterfaceType;
1872: InterfaceType++
1873: ) {
1874:
1875: CONFIGURATION_TYPE Dc = DiskController;
1876: CONFIGURATION_TYPE Fp = FloppyDiskPeripheral;
1877:
1878: Status = IoQueryDeviceDescription(
1879: &InterfaceType,
1880: NULL,
1881: &Dc,
1882: NULL,
1883: &Fp,
1884: NULL,
1885: FlConfigCallBack,
1886: *ConfigData
1887: );
1888:
1889: if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) {
1890:
1891: ExFreePool(*ConfigData);
1892: *ConfigData = NULL;
1893: return Status;
1894:
1895: }
1896:
1897: }
1898:
1899: //
1900: // Get a pointer to the Io system location that is keeping
1901: // a count of all the floppy devices on the system.
1902: //
1903:
1904: if ( IoGetConfigurationInformation() == NULL ) {
1905:
1906: FloppyDump(
1907: FLOPDBGP,
1908: ("Floppy: configuration information is NULL\n")
1909: );
1910: ExFreePool(*ConfigData);
1911: *ConfigData = NULL;
1912: return STATUS_INSUFFICIENT_RESOURCES;
1913: }
1914:
1915: (*ConfigData)->FloppyCount = &IoGetConfigurationInformation()->FloppyCount;
1916:
1917: return STATUS_SUCCESS;
1918: }
1919:
1920: BOOLEAN
1921: FlReportResources(
1922: IN PDRIVER_OBJECT DriverObject,
1923: IN PCONFIG_DATA ConfigData,
1924: IN UCHAR ControllerNumber
1925: )
1926:
1927: /*++
1928:
1929: Routine Description:
1930:
1931: This routine will build up a resource list using the
1932: data for this particular controller as well as all
1933: previous *successfully* configured controllers.
1934:
1935: N.B. This routine assumes that it called in controller
1936: number order.
1937:
1938: Arguments:
1939:
1940: DriverObject - a pointer to the object that represents this device
1941: driver.
1942:
1943: ConfigData - a pointer to the structure that describes the
1944: controller and the disks attached to it, as given to us by the
1945: configuration manager.
1946:
1947: ControllerNumber - which controller in ConfigData we are
1948: about to try to report.
1949:
1950: Return Value:
1951:
1952: TRUE if no conflict was detected, FALSE otherwise.
1953:
1954: --*/
1955:
1956: {
1957:
1958:
1959: ULONG sizeOfResourceList;
1960: ULONG numberOfFrds;
1961: ULONG i;
1962: PCM_RESOURCE_LIST resourceList;
1963: PCM_FULL_RESOURCE_DESCRIPTOR nextFrd;
1964:
1965: //
1966: // Loop through all of the controllers previous to this
1967: // controller. If the controllers previous to this one
1968: // didn't have a conflict, then accumulate the size of the
1969: // CM_FULL_RESOURCE_DESCRIPTOR associated with it.
1970: //
1971:
1972: for (
1973: i = 0,numberOfFrds = 0,sizeOfResourceList = 0;
1974: i <= ControllerNumber;
1975: i++
1976: ) {
1977:
1978: if (ConfigData->Controller[i].OkToUseThisController) {
1979:
1980: sizeOfResourceList += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
1981:
1982: //
1983: // The full resource descriptor already contains one
1984: // partial. Make room for three more.
1985: //
1986: // It will hold the irq "prd", the controller "csr" "prd" which
1987: // is actually in two pieces since we don't use one of the
1988: // registers, and the controller dma "prd".
1989: //
1990:
1991: sizeOfResourceList += 3*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1992: numberOfFrds++;
1993:
1994: }
1995:
1996: }
1997:
1998: //
1999: // Now we increment the length of the resource list by field offset
2000: // of the first frd. This will give us the length of what preceeds
2001: // the first frd in the resource list.
2002: //
2003:
2004: sizeOfResourceList += FIELD_OFFSET(
2005: CM_RESOURCE_LIST,
2006: List[0]
2007: );
2008:
2009: resourceList = ExAllocatePool(
2010: PagedPool,
2011: sizeOfResourceList
2012: );
2013:
2014: if (!resourceList) {
2015:
2016: return FALSE;
2017:
2018: }
2019:
2020: //
2021: // Zero out the field
2022: //
2023:
2024: RtlZeroMemory(
2025: resourceList,
2026: sizeOfResourceList
2027: );
2028:
2029: resourceList->Count = numberOfFrds;
2030: nextFrd = &resourceList->List[0];
2031:
2032: for (
2033: i = 0;
2034: numberOfFrds;
2035: i++
2036: ) {
2037:
2038: if (ConfigData->Controller[i].OkToUseThisController) {
2039:
2040: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
2041:
2042: nextFrd->InterfaceType = ConfigData->Controller[i].InterfaceType;
2043: nextFrd->BusNumber = ConfigData->Controller[i].BusNumber;
2044:
2045: //
2046: // We are only going to report 4 items no matter what
2047: // was in the original.
2048: //
2049:
2050: nextFrd->PartialResourceList.Count = 4;
2051:
2052: //
2053: // Now fill in the port data. We don't wish to share
2054: // this port range with anyone
2055: //
2056:
2057: partial = &nextFrd->PartialResourceList.PartialDescriptors[0];
2058:
2059: partial->Type = CmResourceTypePort;
2060: partial->ShareDisposition = CmResourceShareShared;
2061: partial->Flags = (USHORT)ConfigData->Controller[i].ResourcePortType;
2062: partial->u.Port.Start =
2063: ConfigData->Controller[i].OriginalBaseAddress;
2064: partial->u.Port.Length = 6;
2065:
2066: partial++;
2067:
2068: partial->Type = CmResourceTypePort;
2069: partial->ShareDisposition = CmResourceShareShared;
2070: partial->Flags = (USHORT)ConfigData->Controller[i].ResourcePortType;
2071: partial->u.Port.Start = RtlLargeIntegerAdd(
2072: ConfigData->Controller[i].OriginalBaseAddress,
2073: RtlConvertUlongToLargeInteger((ULONG)7)
2074: );
2075: partial->u.Port.Length = 1;
2076:
2077: partial++;
2078:
2079: partial->Type = CmResourceTypeDma;
2080: partial->ShareDisposition = CmResourceShareShared;
2081: partial->Flags = 0;
2082: partial->u.Dma.Channel =
2083: ConfigData->Controller[i].OriginalDmaChannel;
2084:
2085: partial++;
2086:
2087: //
2088: // Now fill in the irq stuff.
2089: //
2090:
2091: partial->Type = CmResourceTypeInterrupt;
2092: partial->u.Interrupt.Level =
2093: ConfigData->Controller[i].OriginalIrql;
2094: partial->u.Interrupt.Vector =
2095: ConfigData->Controller[i].OriginalVector;
2096:
2097: // if (nextFrd->InterfaceType == MicroChannel) {
2098: //
2099: // partial->ShareDisposition = CmResourceShareShared;
2100: //
2101: // } else {
2102: //
2103: // partial->ShareDisposition = CmResourceShareDriverExclusive;
2104: //
2105: // }
2106:
2107: partial->ShareDisposition = CmResourceShareShared;
2108:
2109: if (ConfigData->Controller[i].InterruptMode == Latched) {
2110:
2111: partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
2112:
2113: } else {
2114:
2115: partial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
2116:
2117: }
2118:
2119: partial++;
2120:
2121: nextFrd = (PVOID)partial;
2122:
2123: numberOfFrds--;
2124:
2125: }
2126:
2127: }
2128:
2129: IoReportResourceUsage(
2130: NULL,
2131: DriverObject,
2132: resourceList,
2133: sizeOfResourceList,
2134: NULL,
2135: NULL,
2136: 0,
2137: FALSE,
2138: &ConfigData->Controller[ControllerNumber].OkToUseThisController
2139: );
2140:
2141: //
2142: // The above routine sets the boolean the parameter
2143: // to TRUE if a conflict was detected.
2144: //
2145:
2146: ConfigData->Controller[ControllerNumber].OkToUseThisController =
2147: !ConfigData->Controller[ControllerNumber].OkToUseThisController;
2148:
2149: ExFreePool(resourceList);
2150:
2151: return ConfigData->Controller[ControllerNumber].OkToUseThisController;
2152:
2153: }
2154:
2155: NTSTATUS
2156: FlInitializeController(
2157: IN PCONFIG_DATA ConfigData,
2158: IN UCHAR ControllerNumber,
2159: IN PDRIVER_OBJECT DriverObject
2160: )
2161:
2162: /*++
2163:
2164: Routine Description:
2165:
2166: This routine is called at initialization time by DriverEntry() -
2167: once for each controller that the configuration manager tells it we
2168: have to support.
2169:
2170: When this routine is called, the configuration data has already been
2171: filled in.
2172:
2173: Arguments:
2174:
2175: ConfigData - a pointer to the structure that describes the
2176: controller and the disks attached to it, as given to us by the
2177: configuration manager.
2178:
2179: ControllerNumber - which controller in ConfigData we are
2180: initializing.
2181:
2182: DriverObject - a pointer to the object that represents this device
2183: driver.
2184:
2185: Return Value:
2186:
2187: STATUS_SUCCESS if this controller and at least one of its disks were
2188: initialized; an error otherwise.
2189:
2190: --*/
2191:
2192: {
2193: PCONTROLLER_DATA controllerData;
2194: PVOID threadObject;
2195: CONFIG_CONTROLLER_DATA *tempData;
2196: NTSTATUS ntStatus;
2197: NTSTATUS ntStatus2;
2198: ULONG ioBufferSize;
2199: ULONG maximumDriveTrackSize;
2200: HANDLE threadHandle = 0;
2201: UCHAR driveNumber;
2202: BOOLEAN partlySuccessful;
2203: UCHAR ntNameBuffer[256];
2204: STRING ntNameString;
2205: UNICODE_STRING ntUnicodeString;
2206: OBJECT_ATTRIBUTES objectAttributes;
2207:
2208: FloppyDump(
2209: FLOPSHOW,
2210: ("Floppy: FlInitializeController...\n")
2211: );
2212:
2213: //
2214: // This routine will take attempt to "append" the resources
2215: // used by this controller into the resource map of the
2216: // registry. If there was a conflict with previously "declared"
2217: // data, then this routine will return false, in which case we
2218: // will NOT try to initialize this particular controller.
2219: //
2220:
2221: if (!FlReportResources(
2222: DriverObject,
2223: ConfigData,
2224: ControllerNumber
2225: )) {
2226:
2227: return STATUS_INSUFFICIENT_RESOURCES;
2228:
2229: }
2230:
2231: //
2232: // Allocate and zero-initialize data to describe this controller
2233: //
2234:
2235: controllerData = (PCONTROLLER_DATA) ExAllocatePool(
2236: NonPagedPool,
2237: sizeof( CONTROLLER_DATA ) );
2238:
2239: if ( controllerData == NULL ) {
2240:
2241: return STATUS_INSUFFICIENT_RESOURCES;
2242: }
2243:
2244: RtlZeroMemory( controllerData, sizeof( CONTROLLER_DATA ) );
2245:
2246: (VOID) sprintf(
2247: ntNameBuffer,
2248: "\\Device\\FloppyControllerEvent%d",
2249: ControllerNumber );
2250:
2251: RtlInitString( &ntNameString, ntNameBuffer );
2252:
2253: ntStatus = RtlAnsiStringToUnicodeString(
2254: &ntUnicodeString,
2255: &ntNameString,
2256: TRUE );
2257:
2258: InitializeObjectAttributes(
2259: &objectAttributes,
2260: &ntUnicodeString,
2261: OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
2262: NULL,
2263: NULL );
2264:
2265:
2266: controllerData->ControllerEvent = IoCreateSynchronizationEvent(
2267: &ntUnicodeString,
2268: &controllerData->ControllerEventHandle);
2269:
2270: RtlFreeUnicodeString( &ntUnicodeString );
2271:
2272: if ( !NT_SUCCESS( ntStatus ) ) {
2273: return STATUS_INSUFFICIENT_RESOURCES;
2274: }
2275:
2276: //
2277: // Stick the driver object into it so that we can use it to log
2278: // an error if the controller hangs up.
2279: //
2280:
2281: controllerData->DriverObject = DriverObject;
2282:
2283: //
2284: // Fill in some items that we got from configuration management and
2285: // the HAL.
2286: //
2287:
2288: controllerData->ControllerAddress =
2289: ConfigData->Controller[ControllerNumber].ControllerBaseAddress;
2290: controllerData->AdapterObject =
2291: ConfigData->Controller[ControllerNumber].AdapterObject;
2292: controllerData->NumberOfMapRegisters =
2293: ConfigData->Controller[ControllerNumber].NumberOfMapRegisters;
2294: controllerData->NumberOfDrives =
2295: ConfigData->Controller[ControllerNumber].NumberOfDrives;
2296:
2297: //
2298: // Set the time to wait for an interrupt before timing out to a
2299: // few seconds.
2300: //
2301:
2302: controllerData->InterruptDelay = RtlLargeIntegerNegate(
2303: RtlConvertLongToLargeInteger(
2304: (LONG)(10 * 1000 * 4000)
2305: )
2306: );
2307:
2308: //
2309: // Set the minimum time that we can delay (10ms according to system
2310: // rules). This will be used when we have to delay to, say, wait
2311: // for the FIFO - the FIFO should become ready is well under 10ms.
2312: //
2313:
2314: controllerData->Minimum10msDelay = RtlLargeIntegerNegate(
2315: RtlConvertLongToLargeInteger(
2316: (LONG)(10 * 1000 * 10)
2317: )
2318: );
2319:
2320: //
2321: // Occasionally during stress we've seen the device lock up.
2322: // We create a dpc so that we can log that the device lock up
2323: // occured and that we reset the device.
2324: //
2325:
2326: KeInitializeDpc(
2327: &controllerData->LogErrorDpc,
2328: FlLogErrorDpc,
2329: controllerData
2330: );
2331:
2332: //
2333: // Assume there is a CONFIGURE command until found otherwise.
2334: // Other Booleans were zero-initialized to FALSE.
2335: //
2336:
2337: controllerData->ControllerConfigurable = TRUE;
2338:
2339: //
2340: // Initialize and connect to the interrupt object in the controller
2341: // extension.
2342: //
2343:
2344: controllerData->CurrentInterrupt = TRUE;
2345:
2346: ntStatus = IoConnectInterrupt(
2347: &controllerData->InterruptObject,
2348: FloppyInterruptService,
2349: controllerData,
2350: NULL,
2351: ConfigData->Controller[ControllerNumber].ControllerVector,
2352: ConfigData->Controller[ControllerNumber].ControllerIrql,
2353: ConfigData->Controller[ControllerNumber].ControllerIrql,
2354: ConfigData->Controller[ControllerNumber].InterruptMode,
2355: ConfigData->Controller[ControllerNumber].SharableVector,
2356: ConfigData->Controller[ControllerNumber].ProcessorMask,
2357: ConfigData->Controller[ControllerNumber].SaveFloatState);
2358:
2359: controllerData->CurrentInterrupt = TRUE;
2360:
2361: if ( NT_SUCCESS( ntStatus ) ) {
2362:
2363: //
2364: // Allocate spinlock to protect controller and data
2365: //
2366:
2367: KeInitializeSpinLock( &controllerData->TimerSpinLock );
2368:
2369: //
2370: // Calculate the size of the largest track that we could possibly
2371: // deal with on this controller.
2372: //
2373:
2374: ioBufferSize = 0;
2375: tempData = &ConfigData->Controller[ControllerNumber];
2376:
2377: for ( driveNumber = 0;
2378: driveNumber < tempData->NumberOfDrives;
2379: driveNumber++ ) {
2380:
2381: //
2382: // Get the size out of the BIOS information store in the
2383: // diskette configuration information
2384: //
2385:
2386: maximumDriveTrackSize =
2387: tempData->BiosDriveMediaConstants[driveNumber].BytesPerSector *
2388: tempData->BiosDriveMediaConstants[driveNumber].SectorsPerTrack;
2389:
2390: if ( maximumDriveTrackSize > ioBufferSize ) {
2391:
2392: ioBufferSize = maximumDriveTrackSize;
2393: }
2394: }
2395:
2396: //
2397: // If we don't have enough map registers to handle the largest
2398: // possible track size, allocate a contiguous buffer to hold it.
2399: //
2400:
2401: if ( ( tempData->NumberOfMapRegisters * PAGE_SIZE ) < ioBufferSize ) {
2402:
2403: controllerData->IoBuffer = MmAllocateContiguousMemory(
2404: ioBufferSize,
2405: RtlConvertUlongToLargeInteger (MAXIMUM_DMA_ADDRESS) );
2406:
2407: }
2408:
2409: //
2410: // We need a single page to do FORMATs. If we already allocated a
2411: // buffer, we'll use that. If not, let's allocate a single page.
2412: // Note that we'd have to do this anyway if there's not enough map
2413: // registers.
2414: //
2415:
2416: if ( controllerData->IoBuffer == NULL ) {
2417:
2418: ioBufferSize = PAGE_SIZE;
2419:
2420: controllerData->IoBuffer = ExAllocatePool(
2421: NonPagedPool,
2422: ioBufferSize );
2423: }
2424:
2425: //
2426: // If we can't even get a page to use as a buffer, exit.
2427: //
2428:
2429: if ( controllerData->IoBuffer == NULL ) {
2430:
2431: ntStatus = STATUS_INSUFFICIENT_RESOURCES;
2432:
2433: } else {
2434:
2435: //
2436: // We have a buffer. Get and lock down an MDL for it now.
2437: //
2438:
2439: controllerData->IoBufferMdl = IoAllocateMdl(
2440: controllerData->IoBuffer,
2441: ioBufferSize,
2442: FALSE,
2443: FALSE,
2444: NULL );
2445:
2446: if ( controllerData->IoBufferMdl == NULL ) {
2447:
2448: ntStatus = STATUS_INSUFFICIENT_RESOURCES;
2449:
2450: } else {
2451:
2452: MmProbeAndLockPages(
2453: controllerData->IoBufferMdl,
2454: KernelMode,
2455: IoModifyAccess );
2456:
2457: FloppyDump(
2458: FLOPSHOW,
2459: ("Floppy: Buffer size = %x\n", ioBufferSize)
2460: );
2461:
2462: controllerData->IoBufferSize = ioBufferSize;
2463:
2464: //
2465: // Initialize the interlocked request queue, including a
2466: // counting semaphore to indicate items in the queue
2467: //
2468:
2469: KeInitializeSemaphore(
2470: &controllerData->RequestSemaphore,
2471: 0L,
2472: MAXLONG );
2473:
2474: KeInitializeSpinLock( &controllerData->ListSpinLock );
2475:
2476: InitializeListHead( &controllerData->ListEntry );
2477:
2478: //
2479: // Initialize events to signal interrupts and adapter object
2480: // allocation
2481: //
2482:
2483: KeInitializeEvent(
2484: &controllerData->InterruptEvent,
2485: SynchronizationEvent,
2486: FALSE);
2487:
2488: KeInitializeEvent(
2489: &controllerData->AllocateAdapterChannelEvent,
2490: NotificationEvent,
2491: FALSE );
2492:
2493: //
2494: // Create a thread with entry point FloppyThread()
2495: //
2496:
2497: ntStatus = PsCreateSystemThread(
2498: &threadHandle,
2499: (ACCESS_MASK) 0L,
2500: NULL,
2501: (HANDLE) 0L,
2502: NULL,
2503: FloppyThread,
2504: controllerData );
2505:
2506: if ( !NT_SUCCESS( ntStatus ) ) {
2507:
2508: FloppyDump(
2509: FLOPDBGP,
2510: ("Floppy: error %x creating thread\n",ntStatus)
2511: );
2512:
2513: }
2514:
2515: if ( NT_SUCCESS( ntStatus ) ) {
2516:
2517: //
2518: // Call FlInitializeDrive() for each drive on the
2519: // controller
2520: //
2521:
2522: ntStatus = STATUS_NO_SUCH_DEVICE;
2523: partlySuccessful = FALSE;
2524:
2525: for ( driveNumber = 0;
2526: driveNumber < controllerData->NumberOfDrives;
2527: driveNumber++ ) {
2528:
2529: ntStatus = FlInitializeDrive(
2530: ConfigData,
2531: controllerData,
2532: ControllerNumber,
2533: driveNumber,
2534: driveNumber,
2535: DriverObject );
2536:
2537: if ( NT_SUCCESS( ntStatus ) ) {
2538:
2539: ( *( ConfigData->FloppyCount ) )++;
2540: partlySuccessful = TRUE;
2541: }
2542: }
2543:
2544: if ( partlySuccessful ) {
2545:
2546: ntStatus = STATUS_SUCCESS;
2547: }
2548: }
2549: }
2550: }
2551: }
2552:
2553: //
2554: // If we're exiting with an error, clean up first.
2555: //
2556:
2557: if ( !NT_SUCCESS( ntStatus ) ) {
2558:
2559: FloppyDump(
2560: FLOPDBGP,
2561: ("Floppy: InitializeController failing\n")
2562: );
2563:
2564: //
2565: // If we created the thread, wake it up and tell it to kill itself.
2566: // Wait until it's dead. (Note that since it's a system thread,
2567: // it has to kill itself - we can't do it).
2568: //
2569:
2570: if ( threadHandle != 0 ) {
2571:
2572: controllerData->UnloadingDriver = TRUE;
2573:
2574: ntStatus2 = ObReferenceObjectByHandle(
2575: threadHandle,
2576: THREAD_ALL_ACCESS,
2577: NULL,
2578: KernelMode,
2579: (PVOID *) &threadObject,
2580: NULL );
2581:
2582: KeReleaseSemaphore(
2583: &controllerData->RequestSemaphore,
2584: (KPRIORITY) 0,
2585: 1,
2586: FALSE );
2587:
2588: if ( NT_SUCCESS( ntStatus2 ) ) {
2589:
2590: //
2591: // The thread object will be signalled when it dies.
2592: //
2593:
2594: ntStatus2 = KeWaitForSingleObject(
2595: threadObject,
2596: Suspended,
2597: KernelMode,
2598: FALSE,
2599: NULL );
2600:
2601: ASSERT( ntStatus2 == STATUS_SUCCESS );
2602:
2603: ObDereferenceObject( threadObject );
2604:
2605: } else {
2606:
2607: //
2608: // We can't get the thread object for some reason; just
2609: // block for a while to give the thread a chance to run
2610: // and die.
2611: //
2612:
2613: FloppyDump(
2614: FLOPDBGP,
2615: ("Floppy: couldn't get thread object\n")
2616: );
2617:
2618: KeDelayExecutionThread(
2619: KernelMode,
2620: FALSE,
2621: &controllerData->InterruptDelay );
2622: }
2623: }
2624:
2625: if ( controllerData->IoBufferMdl != NULL ) {
2626:
2627: MmUnlockPages( controllerData->IoBufferMdl );
2628: IoFreeMdl( controllerData->IoBufferMdl );
2629: }
2630:
2631: if ( controllerData->IoBuffer != NULL ) {
2632:
2633: if ( controllerData->IoBufferSize > PAGE_SIZE ) {
2634:
2635: MmFreeContiguousMemory( controllerData->IoBuffer );
2636:
2637: } else {
2638:
2639: ExFreePool( controllerData->IoBuffer );
2640: }
2641: }
2642:
2643: if ( controllerData->InterruptObject != NULL ) {
2644:
2645: IoDisconnectInterrupt( controllerData->InterruptObject );
2646: }
2647:
2648: ExFreePool( controllerData );
2649:
2650: //
2651: // Support for the ghost drive is being removed. If it
2652: // is needed later, then we can just "un" ifdef this
2653: // code.
2654: //
2655:
2656: #ifdef FLOPPY_ARTIFICIAL
2657:
2658: } else {
2659:
2660: //
2661: // Controller and drive initialization were successful. If
2662: // there's only 1 drive, set up an artificial second drive to
2663: // point to the same thing.
2664: //
2665:
2666: if ( ( ConfigData->NumberOfControllers == 1 ) &&
2667: ( controllerData->NumberOfDrives == 1 ) ) {
2668:
2669: //
2670: // Discard status, since we want to return success even
2671: // if this artificial creation fails.
2672: //
2673:
2674: ntStatus2 = FlInitializeDrive(
2675: ConfigData,
2676: controllerData,
2677: ControllerNumber,
2678: 1,
2679: 0,
2680: DriverObject );
2681:
2682: if ( NT_SUCCESS( ntStatus2 ) ) {
2683:
2684: controllerData->CreatedArtificialDrive = TRUE;
2685: }
2686: }
2687: #endif
2688: }
2689:
2690: return ntStatus;
2691: }
2692:
2693: NTSTATUS
2694: FlInitializeControllerHardware(
2695: IN PCONTROLLER_DATA ControllerData,
2696: IN PDEVICE_OBJECT DeviceObject
2697: )
2698:
2699: /*++
2700:
2701: Routine Description:
2702:
2703: This routine is called at initialization time by FlInitializeDrive()
2704: - once for each controller that we have to support. It is also
2705: called by FlFinishOperation() when an operation appears to have
2706: failed due to a hardware problem.
2707:
2708: When this routine is called, the controller data structures have all
2709: been allocated.
2710:
2711: Arguments:
2712:
2713: ControllerData - the completed data structure associated with the
2714: controller hardware being initialized.
2715:
2716: DeviceObject - a pointer to a device object; this routine will cause
2717: an interrupt, and the ISR requires CurrentDeviceObject to be filled
2718: in.
2719:
2720: Return Value:
2721:
2722: STATUS_SUCCESS if this controller appears to have been reset properly,
2723: error otherwise.
2724:
2725: --*/
2726:
2727: {
2728: NTSTATUS ntStatus;
2729: UCHAR statusRegister0;
2730: UCHAR cylinder;
2731: UCHAR driveNumber;
2732:
2733: FloppyDump(
2734: FLOPSHOW,
2735: ("Floppy: FlInitializeControllerHardware...\n")
2736: );
2737:
2738: //
2739: // Reset the controller. This will cause an interrupt. Reset
2740: // CurrentDeviceObject until after the 10ms wait, in case any
2741: // stray interrupts come in.
2742: //
2743:
2744: ControllerData->DriveControlImage |= DRVCTL_ENABLE_DMA_AND_INTERRUPTS;
2745: ControllerData->DriveControlImage &= ~( DRVCTL_ENABLE_CONTROLLER );
2746:
2747: WRITE_CONTROLLER(
2748: &ControllerData->ControllerAddress->DriveControl,
2749: ControllerData->DriveControlImage );
2750:
2751: KeStallExecutionProcessor( 10 );
2752:
2753: ControllerData->CurrentDeviceObject = DeviceObject;
2754: ControllerData->CommandHasResultPhase = FALSE;
2755: KeResetEvent( &ControllerData->InterruptEvent );
2756:
2757: ControllerData->DriveControlImage |= DRVCTL_ENABLE_CONTROLLER;
2758:
2759: WRITE_CONTROLLER(
2760: &ControllerData->ControllerAddress->DriveControl,
2761: ControllerData->DriveControlImage );
2762:
2763: //
2764: // Wait for an interrupt. Note that STATUS_TIMEOUT and STATUS_SUCCESS
2765: // are the only possible return codes, since we aren't alertable and
2766: // won't get APCs.
2767: //
2768:
2769: ntStatus = KeWaitForSingleObject(
2770: &ControllerData->InterruptEvent,
2771: Executive,
2772: KernelMode,
2773: FALSE,
2774: &ControllerData->InterruptDelay );
2775:
2776: if ( ntStatus == STATUS_TIMEOUT ) {
2777:
2778: //
2779: // Change info to an error.
2780: //
2781:
2782: ntStatus = STATUS_IO_TIMEOUT;
2783:
2784: ControllerData->HardwareFailed = TRUE;
2785: }
2786:
2787: #ifdef KEEP_COUNTERS
2788: FloppyThreadTime = KeQueryPerformanceCounter((PVOID)NULL);
2789: FloppyThreadDelay = RtlLargeIntegerAdd(FloppyThreadDelay,
2790: RtlLargeIntegerSubtract(FloppyDPCTime,
2791: FloppyThreadTime));
2792: FloppyFromIntrDelay = RtlLargeIntegerAdd(FloppyFromIntrDelay,
2793: RtlLargeIntegerSubtract(FloppyIntrTime,
2794: FloppyThreadTime));
2795: FloppyThreadWake++;
2796: #endif
2797:
2798: if ( !NT_SUCCESS( ntStatus ) ) {
2799:
2800: FloppyDump(
2801: FLOPDBGP,
2802: ("Floppy: controller didn't interrupt after reset\n")
2803: );
2804:
2805: return ntStatus;
2806: }
2807:
2808: //
2809: // Sense interrupt status for all drives.
2810: //
2811:
2812: for ( driveNumber = 0;
2813: ( driveNumber < ControllerData->NumberOfDrives ) &&
2814: ( NT_SUCCESS( ntStatus ) );
2815: driveNumber++ ) {
2816:
2817: if ( driveNumber != 0 ) {
2818:
2819: //
2820: // Note that the ISR issued first SENSE INTERRUPT for us.
2821: //
2822:
2823: ntStatus = FlSendByte( COMMND_SENSE_INTERRUPT, ControllerData );
2824: }
2825:
2826: if ( NT_SUCCESS( ntStatus ) ) {
2827:
2828: ntStatus = FlGetByte( &statusRegister0, ControllerData );
2829:
2830: if ( NT_SUCCESS( ntStatus ) ) {
2831:
2832: ntStatus = FlGetByte( &cylinder, ControllerData );
2833: }
2834: }
2835: }
2836:
2837: //
2838: // Set PERPENDICULAR MODE for all drives that are perpendicular.
2839: //
2840:
2841: if ( ControllerData->PerpendicularDrives != 0 ) {
2842: ntStatus = FlSendByte( COMMND_PERPENDICULAR_MODE, ControllerData );
2843:
2844: if ( NT_SUCCESS( ntStatus ) ) {
2845: ntStatus = FlSendByte( COMMND_PERPENDICULAR_MODE_OW |
2846: (ControllerData->PerpendicularDrives << 2),
2847: ControllerData );
2848: }
2849: }
2850:
2851: return ntStatus;
2852: }
2853:
2854: NTSTATUS
2855: FlInitializeDrive(
2856: IN PCONFIG_DATA ConfigData,
2857: IN PCONTROLLER_DATA ControllerData,
2858: IN UCHAR ControllerNum,
2859: IN UCHAR DisketteNum,
2860: IN UCHAR DisketteUnit,
2861: IN PDRIVER_OBJECT DriverObject
2862: )
2863:
2864: /*++
2865:
2866: Routine Description:
2867:
2868: This routine is called at initialization time by
2869: FlInitializeController(), once for each disk that we are supporting
2870: on the controller.
2871:
2872: Arguments:
2873:
2874: ConfigData - a pointer to the structure that describes the
2875: controller and the disks attached to it, as given to us by the
2876: configuration manager.
2877:
2878: ControllerData - a pointer to our data area for this controller.
2879:
2880: ControllerNum - which controller in ConfigData we're working on.
2881:
2882: DisketteNum - which logical disk on the current controller we're
2883: working on.
2884:
2885: DisketteUnit - which physical disk on the current controller we're
2886: working on. Only different from DisketteNum when we're creating a
2887: secondary device object for a previously initialized drive.
2888:
2889: DriverObject - a pointer to the object that represents this device
2890: driver.
2891:
2892: Return Value:
2893:
2894: STATUS_SUCCESS if this disk is initialized; an error otherwise.
2895:
2896: --*/
2897:
2898: {
2899: UCHAR ntNameBuffer[256];
2900: UCHAR arcNameBuffer[256];
2901: STRING ntNameString;
2902: STRING arcNameString;
2903: UNICODE_STRING ntUnicodeString;
2904: UNICODE_STRING arcUnicodeString;
2905: NTSTATUS ntStatus;
2906: PDEVICE_OBJECT deviceObject = NULL;
2907: PDISKETTE_EXTENSION disketteExtension;
2908:
2909: FloppyDump(
2910: FLOPSHOW,
2911: ("Floppy: FlInitializeDrive...\n")
2912: );
2913:
2914: sprintf(
2915: ntNameBuffer,
2916: "\\Device\\Floppy%d",
2917: *( ConfigData->FloppyCount ) );
2918:
2919: RtlInitString( &ntNameString, ntNameBuffer );
2920:
2921: ntStatus = RtlAnsiStringToUnicodeString(
2922: &ntUnicodeString,
2923: &ntNameString,
2924: TRUE );
2925:
2926: if ( NT_SUCCESS( ntStatus ) ) {
2927:
2928: //
2929: // Create a device object for this floppy drive.
2930: //
2931:
2932: ntStatus = IoCreateDevice(
2933: DriverObject,
2934: sizeof( DISKETTE_EXTENSION ),
2935: &ntUnicodeString,
2936: FILE_DEVICE_DISK,
2937: FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE,
2938: FALSE,
2939: &deviceObject );
2940:
2941: if ( NT_SUCCESS( ntStatus ) ) {
2942:
2943: //
2944: // Create a symbolic link from the disk name to the corresponding
2945: // ARC name, to be used if we're booting off the disk. This will
2946: // if it's not system initialization time; that's fine. The ARC
2947: // name looks something like \ArcName\multi(0)disk(0)rdisk(0).
2948: //
2949:
2950: sprintf(
2951: arcNameBuffer,
2952: "%s(%d)disk(%d)fdisk(%d)",
2953: "\\ArcName\\multi",
2954: ConfigData->Controller[ControllerNum].BusNumber,
2955: ConfigData->Controller[ControllerNum].ActualControllerNumber,
2956: DisketteNum );
2957:
2958: RtlInitString( &arcNameString, arcNameBuffer );
2959:
2960: ntStatus = RtlAnsiStringToUnicodeString(
2961: &arcUnicodeString,
2962: &arcNameString,
2963: TRUE );
2964:
2965: if ( !NT_SUCCESS( ntStatus ) ) {
2966:
2967: RtlFreeUnicodeString( &ntUnicodeString );
2968:
2969: } else {
2970:
2971: IoAssignArcName( &arcUnicodeString, &ntUnicodeString );
2972: RtlFreeUnicodeString( &ntUnicodeString );
2973: RtlFreeUnicodeString( &arcUnicodeString );
2974:
2975: //
2976: // Initialize the DPC structure in the device object, so that
2977: // the ISR can queue DPCs.
2978: //
2979:
2980: IoInitializeDpcRequest( deviceObject, FloppyDeferredProcedure );
2981:
2982: deviceObject->Flags |= DO_DIRECT_IO;
2983:
2984: if ( deviceObject->AlignmentRequirement < FILE_WORD_ALIGNMENT ) {
2985:
2986: deviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
2987: }
2988:
2989: //
2990: // Copy the drive type from the configuration info; note that
2991: // the media type has not been determined.
2992: //
2993:
2994: disketteExtension = deviceObject->DeviceExtension;
2995:
2996: //
2997: // In the event that the system only has one drive, we
2998: // want this variable to initially point to the extension
2999: // of the *first* device object that describes it, so the
3000: // user's initial access of the drive doesn't result in
3001: // a prompt to insert media.
3002: //
3003:
3004: if ( ( DisketteNum == 0 ) && ( DisketteUnit == 0 ) ) {
3005:
3006: ControllerData->LastDisketteExtension = disketteExtension;
3007: }
3008:
3009: disketteExtension->ControllerData = ControllerData;
3010: disketteExtension->DeviceObject = deviceObject;
3011: disketteExtension->DeviceUnit = DisketteUnit;
3012:
3013: disketteExtension->DriveOnValue = (UCHAR)( DisketteUnit |
3014: ( DRVCTL_ENABLE_CONTROLLER +
3015: DRVCTL_ENABLE_DMA_AND_INTERRUPTS ) |
3016: ( DRVCTL_DRIVE_0 << DisketteUnit ) );
3017:
3018: disketteExtension->DriveType = ConfigData->
3019: Controller[ControllerNum].DriveType[DisketteUnit];
3020:
3021: disketteExtension->MediaType = Undetermined;
3022:
3023: disketteExtension->BiosDriveMediaConstants = ConfigData->
3024: Controller[ControllerNum].BiosDriveMediaConstants[DisketteUnit];
3025:
3026: if ( disketteExtension->DriveType == DRIVE_TYPE_2880 ) {
3027: ControllerData->PerpendicularDrives |= 1 << DisketteUnit;
3028: }
3029:
3030: //
3031: // If this is the first drive, start the motor timer (this
3032: // would best be done in FlInitializeController(), but we
3033: // must have a device object to attach to it.)
3034: //
3035:
3036: if ( DisketteNum == 0 ) {
3037:
3038: ControllerData->MotorTimer = TIMER_CANCEL;
3039:
3040: IoInitializeTimer(
3041: deviceObject,
3042: FloppyMotorOffDpc,
3043: ControllerData );
3044:
3045: IoStartTimer( deviceObject );
3046: }
3047:
3048: //
3049: // FlInitializeControllerHardware() should logically be called
3050: // from FlInitializeController(). But the hardware can't be
3051: // initialized until a device object exists, since the ISR has
3052: // to queue a DPC. So we do it here, where we get a chance to
3053: // clean up easily if FlInitializeControllerHardware() fails.
3054: //
3055: // The controller is normally only reset once, when the first
3056: // diskette is initialized. But we'll try again on subsequent
3057: // diskettes if it failed on the first one.
3058: //
3059:
3060: if ( ( DisketteNum == 0 ) ||
3061: ( disketteExtension->DriveType == DRIVE_TYPE_2880 ) ||
3062: ( ControllerData->HardwareFailed ) ) {
3063:
3064: ControllerData->CurrentInterrupt = TRUE;
3065:
3066: ntStatus = FlInitializeControllerHardware(
3067: ControllerData,
3068: deviceObject );
3069:
3070: ControllerData->CurrentInterrupt = FALSE;
3071:
3072: if ( NT_SUCCESS( ntStatus ) ) {
3073:
3074: FloppyDump(
3075: FLOPSHOW,
3076: ("Floppy: DriveType = %x\n",
3077: disketteExtension->DriveType)
3078: );
3079:
3080: ControllerData->HardwareFailed = FALSE;
3081:
3082: } else {
3083:
3084: ControllerData->HardwareFailed = TRUE;
3085: }
3086: }
3087: }
3088: }
3089: }
3090:
3091: //
3092: // If we're failing, clean up - stop the timer (it doesn't hurt to
3093: // stop it even if it wasn't started) and delete the device object.
3094: //
3095:
3096: if ( !NT_SUCCESS( ntStatus ) ) {
3097:
3098: FloppyDump(
3099: FLOPDBGP,
3100: ("Floppy: InitiaiizeDrive failing\n")
3101: );
3102:
3103: if ( deviceObject != NULL ) {
3104:
3105: if ( DisketteNum == 0 ) {
3106:
3107: IoStopTimer( deviceObject );
3108: }
3109:
3110: IoDeleteDevice( deviceObject );
3111: }
3112: }
3113:
3114: return ntStatus;
3115: }
3116:
3117: NTSTATUS
3118: FloppyDispatchCreateClose(
3119: IN PDEVICE_OBJECT DeviceObject,
3120: IN PIRP Irp
3121: )
3122:
3123: /*++
3124:
3125: Routine Description:
3126:
3127: This routine is called only rarely by the I/O system; it's mainly
3128: for layered drivers to call. All it does is complete the IRP
3129: successfully.
3130:
3131: Arguments:
3132:
3133: DeviceObject - a pointer to the object that represents the device
3134: that I/O is to be done on.
3135:
3136: Irp - a pointer to the I/O Request Packet for this request.
3137:
3138: Return Value:
3139:
3140: Always returns STATUS_SUCCESS, since this is a null operation.
3141:
3142: --*/
3143:
3144: {
3145: UNREFERENCED_PARAMETER( DeviceObject );
3146:
3147: FloppyDump(
3148: FLOPSHOW,
3149: ("Floppy: DispatchCreateClose...\n")
3150: );
3151:
3152: //
3153: // Null operation. Do not give an I/O boost since
3154: // no I/O was actually done. IoStatus.Information should be
3155: // FILE_OPENED for an open; it's undefined for a close.
3156: //
3157:
3158: Irp->IoStatus.Status = STATUS_SUCCESS;
3159: Irp->IoStatus.Information = FILE_OPENED;
3160:
3161: IoCompleteRequest( Irp, IO_NO_INCREMENT );
3162:
3163: return STATUS_SUCCESS;
3164: }
3165:
3166: NTSTATUS
3167: FloppyDispatchDeviceControl(
3168: IN PDEVICE_OBJECT DeviceObject,
3169: IN PIRP Irp
3170: )
3171:
3172: /*++
3173:
3174: Routine Description:
3175:
3176: This routine is called by the I/O system to perform a device I/O
3177: control function.
3178:
3179: Arguments:
3180:
3181: DeviceObject - a pointer to the object that represents the device
3182: that I/O is to be done on.
3183:
3184: Irp - a pointer to the I/O Request Packet for this request.
3185:
3186: Return Value:
3187:
3188: STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code,
3189: STATUS_INVALID_DEVICE_REQUEST otherwise.
3190:
3191: --*/
3192:
3193: {
3194: PIO_STACK_LOCATION irpSp;
3195: PDISKETTE_EXTENSION disketteExtension;
3196: PDISK_GEOMETRY outputBuffer;
3197: NTSTATUS ntStatus;
3198: ULONG outputBufferLength;
3199: UCHAR i;
3200: DRIVE_MEDIA_TYPE lowestDriveMediaType;
3201: DRIVE_MEDIA_TYPE highestDriveMediaType;
3202:
3203: FloppyDump(
3204: FLOPSHOW,
3205: ("Floppy: DispatchDeviceControl...\n")
3206: );
3207:
3208: disketteExtension = DeviceObject->DeviceExtension;
3209: irpSp = IoGetCurrentIrpStackLocation( Irp );
3210:
3211: switch( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
3212:
3213: case IOCTL_DISK_FORMAT_TRACKS:
3214:
3215: //
3216: // Make sure that we got all the necessary format parameters.
3217: //
3218:
3219: if ( irpSp->Parameters.DeviceIoControl.InputBufferLength <
3220: sizeof( FORMAT_PARAMETERS ) ) {
3221:
3222: FloppyDump(
3223: FLOPDBGP,
3224: ("Floppy: invalid FORMAT buffer length\n")
3225: );
3226:
3227: ntStatus = STATUS_INVALID_PARAMETER;
3228: break;
3229: }
3230:
3231: //
3232: // Make sure the parameters we got are reasonable.
3233: //
3234:
3235: if ( !FlCheckFormatParameters(
3236: disketteExtension,
3237: (PFORMAT_PARAMETERS) Irp->AssociatedIrp.SystemBuffer ) ) {
3238:
3239: FloppyDump(
3240: FLOPDBGP,
3241: ("Floppy: invalid FORMAT parameters\n")
3242: );
3243:
3244: ntStatus = STATUS_INVALID_PARAMETER;
3245: break;
3246: }
3247:
3248: //
3249: // Fall through to queue the request.
3250: //
3251:
3252: case IOCTL_DISK_CHECK_VERIFY:
3253: case IOCTL_DISK_GET_DRIVE_GEOMETRY:
3254:
3255: //
3256: // The thread must know which diskette to operate on, but the
3257: // request list only passes the IRP. So we'll stick a pointer
3258: // to the diskette extension in Type3InputBuffer, which is
3259: // a field that isn't used for floppy ioctls.
3260: //
3261:
3262: //
3263: // Add the request to the queue, and wake up the thread to
3264: // process it.
3265: //
3266:
3267: IoMarkIrpPending( Irp );
3268:
3269: irpSp->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID)
3270: disketteExtension;
3271:
3272: FloppyDump(
3273: FLOPIRPPATH,
3274: ("Floppy: Enqueing up IRP: %x\n",Irp)
3275: );
3276: ExInterlockedInsertTailList(
3277: &disketteExtension->ControllerData->ListEntry,
3278: &Irp->Tail.Overlay.ListEntry,
3279: &disketteExtension->ControllerData->ListSpinLock );
3280:
3281: KeReleaseSemaphore(
3282: &disketteExtension->ControllerData->RequestSemaphore,
3283: (KPRIORITY) 0,
3284: 1,
3285: FALSE );
3286:
3287: ntStatus = STATUS_PENDING;
3288: break;
3289:
3290:
3291: case IOCTL_DISK_GET_MEDIA_TYPES: {
3292:
3293: FloppyDump(
3294: FLOPSHOW,
3295: ("Floppy: IOCTL_DISK_GET_MEDIA_TYPES called\n")
3296: );
3297:
3298: lowestDriveMediaType = DriveMediaLimits[
3299: disketteExtension->DriveType].LowestDriveMediaType;
3300: highestDriveMediaType = DriveMediaLimits[
3301: disketteExtension->DriveType].HighestDriveMediaType;
3302:
3303: outputBufferLength =
3304: irpSp->Parameters.DeviceIoControl.OutputBufferLength;
3305:
3306: //
3307: // Make sure that the input buffer has enough room to return
3308: // at least one descriptions of a supported media type.
3309: //
3310:
3311: if ( outputBufferLength < ( sizeof( DISK_GEOMETRY ) ) ) {
3312:
3313: FloppyDump(
3314: FLOPDBGP,
3315: ("Floppy: invalid GET_MEDIA_TYPES buffer size\n")
3316: );
3317:
3318: ntStatus = STATUS_BUFFER_TOO_SMALL;
3319: break;
3320: }
3321:
3322: //
3323: // Assume success, although we might modify it to a buffer
3324: // overflow warning below (if the buffer isn't big enough
3325: // to hold ALL of the media descriptions).
3326: //
3327:
3328: ntStatus = STATUS_SUCCESS;
3329:
3330: if ( outputBufferLength < ( sizeof( DISK_GEOMETRY ) *
3331: ( highestDriveMediaType - lowestDriveMediaType + 1 ) ) ) {
3332:
3333: //
3334: // The buffer is too small for all of the descriptions;
3335: // calculate what CAN fit in the buffer.
3336: //
3337:
3338: FloppyDump(
3339: FLOPDBGP,
3340: ("Floppy: GET_MEDIA_TYPES buffer size too small\n")
3341: );
3342:
3343: ntStatus = STATUS_BUFFER_OVERFLOW;
3344:
3345: highestDriveMediaType = (DRIVE_MEDIA_TYPE)( ( lowestDriveMediaType - 1 ) +
3346: ( outputBufferLength /
3347: sizeof( DISK_GEOMETRY ) ) );
3348: }
3349:
3350: outputBuffer = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
3351:
3352: for (
3353: i = (UCHAR)lowestDriveMediaType;
3354: i <= (UCHAR)highestDriveMediaType;
3355: i++ ) {
3356:
3357: outputBuffer->MediaType = DriveMediaConstants[i].MediaType;
3358: outputBuffer->Cylinders.LowPart =
3359: DriveMediaConstants[i].MaximumTrack + 1;
3360: outputBuffer->Cylinders.HighPart = 0;
3361: outputBuffer->TracksPerCylinder =
3362: DriveMediaConstants[i].NumberOfHeads;
3363: outputBuffer->SectorsPerTrack =
3364: DriveMediaConstants[i].SectorsPerTrack;
3365: outputBuffer->BytesPerSector =
3366: DriveMediaConstants[i].BytesPerSector;
3367: FloppyDump(
3368: FLOPSHOW,
3369: ("Floppy: media types supported [%d]\n"
3370: "------- Cylinders low: 0x%x\n"
3371: "------- Cylinders high: 0x%x\n"
3372: "------- Track/Cyl: 0x%x\n"
3373: "------- Sectors/Track: 0x%x\n"
3374: "------- Bytes/Sector: 0x%x\n"
3375: "------- Media Type: %d\n",
3376: i,
3377: outputBuffer->Cylinders.LowPart,
3378: outputBuffer->Cylinders.HighPart,
3379: outputBuffer->TracksPerCylinder,
3380: outputBuffer->SectorsPerTrack,
3381: outputBuffer->BytesPerSector,
3382: outputBuffer->MediaType)
3383: );
3384: outputBuffer++;
3385:
3386: Irp->IoStatus.Information += sizeof( DISK_GEOMETRY );
3387: }
3388:
3389: break;
3390: }
3391:
3392: default: {
3393:
3394: FloppyDump(
3395: FLOPDBGP,
3396: ("Floppy: invalid device request %x\n",
3397: irpSp->Parameters.DeviceIoControl.IoControlCode)
3398: );
3399:
3400: ntStatus = STATUS_INVALID_DEVICE_REQUEST;
3401: break;
3402: }
3403: }
3404:
3405: if ( ntStatus != STATUS_PENDING ) {
3406:
3407: Irp->IoStatus.Status = ntStatus;
3408: if (!NT_SUCCESS( ntStatus ) &&
3409: IoIsErrorUserInduced( ntStatus )) {
3410:
3411: IoSetHardErrorOrVerifyDevice( Irp, DeviceObject );
3412:
3413: }
3414: IoCompleteRequest( Irp, IO_NO_INCREMENT );
3415: }
3416:
3417: return ntStatus;
3418: }
3419:
3420: NTSTATUS
3421: FloppyDispatchReadWrite(
3422: IN PDEVICE_OBJECT DeviceObject,
3423: IN PIRP Irp
3424: )
3425:
3426: /*++
3427:
3428: Routine Description:
3429:
3430: This routine is called by the I/O system to read or write to a
3431: device that we control.
3432:
3433: Arguments:
3434:
3435: DeviceObject - a pointer to the object that represents the device
3436: that I/O is to be done on.
3437:
3438: Irp - a pointer to the I/O Request Packet for this request.
3439:
3440: Return Value:
3441:
3442: STATUS_INVALID_PARAMETER if parameters are invalid,
3443: STATUS_PENDING otherwise.
3444:
3445: --*/
3446:
3447: {
3448: PIO_STACK_LOCATION irpSp;
3449: NTSTATUS ntStatus;
3450: PDISKETTE_EXTENSION disketteExtension;
3451:
3452: FloppyDump(
3453: FLOPSHOW,
3454: ("Floppy: FloppyDispatchReadWrite...\n")
3455: );
3456:
3457: disketteExtension = DeviceObject->DeviceExtension;
3458:
3459: irpSp = IoGetCurrentIrpStackLocation( Irp );
3460:
3461: if ( ( disketteExtension->MediaType > Unknown ) &&
3462: ( ( ( irpSp->Parameters.Read.ByteOffset ).LowPart +
3463: irpSp->Parameters.Read.Length > disketteExtension->ByteCapacity ) ||
3464: ( ( irpSp->Parameters.Read.Length &
3465: ( disketteExtension->BytesPerSector - 1 ) ) != 0 ) ) ) {
3466:
3467: FloppyDump(
3468: FLOPDBGP,
3469: ("Floppy: Invalid Parameter, rejecting request\n")
3470: );
3471:
3472: FloppyDump(
3473: FLOPWARN,
3474: ("Floppy: Starting offset = %lx\n"
3475: "------ I/O Length = %lx\n"
3476: "------ ByteCapacity = %lx\n"
3477: "------ BytesPerSector = %lx\n",
3478: irpSp->Parameters.Read.ByteOffset.LowPart,
3479: irpSp->Parameters.Read.Length,
3480: disketteExtension->ByteCapacity,
3481: disketteExtension->BytesPerSector)
3482: );
3483:
3484: ntStatus = STATUS_INVALID_PARAMETER;
3485: Irp->IoStatus.Status = ntStatus;
3486: IoCompleteRequest(
3487: Irp,
3488: 0
3489: );
3490:
3491: } else {
3492:
3493: IoMarkIrpPending( Irp );
3494:
3495: //
3496: // We need to pass the disketteExtension somewhere in the irp.
3497: // The "Key" field in our stack location should be unused.
3498: //
3499:
3500: irpSp->Parameters.Read.Key = (ULONG) disketteExtension;
3501:
3502: FloppyDump(
3503: FLOPIRPPATH,
3504: ("Floppy: Enqueing up IRP: %x\n",Irp)
3505: );
3506: ExInterlockedInsertTailList(
3507: &disketteExtension->ControllerData->ListEntry,
3508: &Irp->Tail.Overlay.ListEntry,
3509: &disketteExtension->ControllerData->ListSpinLock );
3510:
3511: KeReleaseSemaphore(
3512: &disketteExtension->ControllerData->RequestSemaphore,
3513: (KPRIORITY) 0,
3514: 1,
3515: FALSE );
3516:
3517: ntStatus = STATUS_PENDING;
3518: }
3519:
3520: return ntStatus;
3521: }
3522:
3523: BOOLEAN
3524: FloppyInterruptService(
3525: IN PKINTERRUPT Interrupt,
3526: IN PVOID Context
3527: )
3528:
3529: /*++
3530:
3531: Routine Description:
3532:
3533: This routine is called at DIRQL by the system when the controller
3534: interrupts.
3535:
3536: Arguments:
3537:
3538: Interrupt - a pointer to the interrupt object.
3539:
3540: Context - a pointer to our controller data area for the controller
3541: that interrupted. (This was set up by the call to
3542: IoConnectInterrupt).
3543:
3544: Return Value:
3545:
3546: Normally returns TRUE, but will return FALSE if this interrupt was
3547: not expected.
3548:
3549: --*/
3550:
3551: {
3552: PCONTROLLER_DATA controllerData;
3553: PDEVICE_OBJECT currentDeviceObject;
3554: ULONG i;
3555: UCHAR statusByte;
3556: BOOLEAN controllerStateError = FALSE;
3557:
3558: UNREFERENCED_PARAMETER( Interrupt );
3559:
3560: #ifdef KEEP_COUNTERS
3561: FloppyIntrTime = KeQueryPerformanceCounter((PVOID)NULL);
3562: FloppyInterrupts++;
3563: #endif
3564:
3565: FloppyDump(
3566: FLOPSHOW,
3567: ("Floppy: FloppyInterruptService...\n")
3568: );
3569:
3570: KeStallExecutionProcessor(10);
3571:
3572: controllerData = (PCONTROLLER_DATA) Context;
3573:
3574: //
3575: // CurrentDeviceObject is set to the device object that is
3576: // expecting an interrupt.
3577: //
3578:
3579: currentDeviceObject = controllerData->CurrentDeviceObject;
3580: controllerData->CurrentDeviceObject = NULL;
3581:
3582: if (currentDeviceObject == NULL &&
3583: !controllerData->CurrentInterrupt) {
3584:
3585: return FALSE;
3586:
3587: } else {
3588:
3589: if ( controllerData->CommandHasResultPhase ) {
3590:
3591: //
3592: // Result phase of previous command. (Note that we can't trust
3593: // the CMD_BUSY bit in the status register to tell us whether
3594: // there's result bytes or not; it's sometimes wrong).
3595: // By reading the first result byte, we reset the interrupt.
3596: // The other result bytes will be read by a thread.
3597: // Note that we want to do this even if the interrupt is
3598: // unexpected, to make sure the interrupt is dismissed.
3599: //
3600:
3601: if ( ( READ_CONTROLLER( &controllerData->ControllerAddress->Status )
3602: & STATUS_IO_READY_MASK ) == STATUS_READ_READY ) {
3603:
3604: controllerData->FifoBuffer[0] =
3605: READ_CONTROLLER( &controllerData->ControllerAddress->Fifo );
3606:
3607: } else {
3608:
3609: //
3610: // Should never get here. If we do, DON'T wake up the thread;
3611: // let it time out and reset the controller, or let another
3612: // interrupt handle this.
3613: //
3614:
3615: FloppyDump(
3616: FLOPDBGP,
3617: ("Floppy: controller not ready to be read in ISR\n")
3618: );
3619:
3620: controllerStateError = TRUE;
3621: }
3622:
3623: } else {
3624:
3625: //
3626: // Previous command doesn't have a result phase. To read how it
3627: // completed, issue a sense interrupt command. Don't read
3628: // the result bytes from the sense interrupt; that is the
3629: // responsibility of the calling thread.
3630: // Note that we want to do this even if the interrupt is
3631: // unexpected, to make sure the interrupt is dismissed.
3632: //
3633:
3634: i = 0;
3635:
3636: do {
3637:
3638: KeStallExecutionProcessor( 1 );
3639: statusByte = READ_CONTROLLER(
3640: &controllerData->ControllerAddress->Status );
3641: i++;
3642:
3643: } while ( ( i < FIFO_ISR_TIGHTLOOP_RETRY_COUNT ) &&
3644: ( ( statusByte & STATUS_CONTROLLER_BUSY ) ||
3645: ( ( statusByte & STATUS_IO_READY_MASK ) != STATUS_WRITE_READY ) ) );
3646:
3647: if ( !( statusByte & STATUS_CONTROLLER_BUSY ) &&
3648: ( ( statusByte & STATUS_IO_READY_MASK ) == STATUS_WRITE_READY ) ) {
3649:
3650: WRITE_CONTROLLER(
3651: &controllerData->ControllerAddress->Fifo,
3652: COMMND_SENSE_INTERRUPT );
3653:
3654: //
3655: // Wait for the controller to ACK the SenseInterrupt command, by
3656: // showing busy. On very fast machines we can end up running
3657: // driver's system-thread before the controller has had time to
3658: // set the busy bit.
3659: //
3660:
3661: for (i = ISR_SENSE_RETRY_COUNT; i; i--) {
3662: statusByte = READ_CONTROLLER(
3663: &controllerData->ControllerAddress->Status );
3664:
3665: if (statusByte & STATUS_CONTROLLER_BUSY)
3666: break;
3667:
3668: KeStallExecutionProcessor( 1 );
3669: }
3670:
3671: if ( currentDeviceObject == NULL ) {
3672:
3673: //
3674: // This is an unexpected interrupt, so nobody's going to
3675: // read the result bytes. Read them now.
3676: //
3677:
3678: READ_CONTROLLER( &controllerData->ControllerAddress->Fifo );
3679: READ_CONTROLLER( &controllerData->ControllerAddress->Fifo );
3680: }
3681:
3682: } else {
3683:
3684: //
3685: // Shouldn't get here. If we do, DON'T wake up the thread;
3686: // let it time out and reset the controller, or let another
3687: // interrupt take care of it.
3688: //
3689:
3690: FloppyDump(
3691: FLOPDBGP,
3692: ("Floppy: no result, but can't write SenseIntr\n")
3693: );
3694:
3695: controllerStateError = TRUE;
3696: }
3697: }
3698:
3699: //
3700: // We've written to the controller, and we're about to leave. On
3701: // machines with levelsensitive interrupts, we'll get another interrupt
3702: // if we RETURN before the port is flushed. To make sure that doesn't
3703: // happen, we'll do a read here.
3704: //
3705:
3706: statusByte = READ_CONTROLLER( &controllerData->ControllerAddress->Status );
3707:
3708: //
3709: // Let the interrupt settle.
3710: //
3711:
3712: KeStallExecutionProcessor(10);
3713:
3714: #ifdef KEEP_COUNTERS
3715: FloppyEndIntrTime = KeQueryPerformanceCounter((PVOID)NULL);
3716: FloppyIntrDelay = RtlLargeIntegerAdd(FloppyIntrDelay,
3717: RtlLargeIntegerSubtract(FloppyEndIntrTime,
3718: FloppyIntrTime));
3719: #endif
3720: if ( currentDeviceObject == NULL ) {
3721:
3722: //
3723: // We didn't expect this interrupt. We've dismissed it just
3724: // in case, but now return FALSE withOUT waking up the thread.
3725: //
3726:
3727: FloppyDump(
3728: FLOPDBGP,
3729: ("Floppy: unexpected interrupt\n")
3730: );
3731:
3732: return FALSE;
3733: }
3734:
3735: if ( !controllerStateError ) {
3736:
3737: //
3738: // Request a DPC for execution later to get the remainder of the
3739: // floppy state.
3740: //
3741:
3742: IoRequestDpc(
3743: currentDeviceObject,
3744: currentDeviceObject->CurrentIrp,
3745: (PVOID) NULL );
3746: }
3747:
3748: }
3749:
3750: //
3751: // We've written to the controller, and we're about to leave. On
3752: // machines with levelsensitive interrupts, we'll get another interrupt
3753: // if we RETURN before the port is flushed. To make sure that doesn't
3754: // happen, we'll do a read here.
3755: //
3756:
3757: statusByte = READ_CONTROLLER( &controllerData->ControllerAddress->Status );
3758:
3759: //
3760: // Let the interrupt settle.
3761: //
3762:
3763: KeStallExecutionProcessor(10);
3764:
3765: #ifdef KEEP_COUNTERS
3766: FloppyEndIntrTime = KeQueryPerformanceCounter((PVOID)NULL);
3767: FloppyIntrDelay = RtlLargeIntegerAdd(FloppyIntrDelay,
3768: RtlLargeIntegerSubtract(FloppyEndIntrTime,
3769: FloppyIntrTime));
3770: #endif
3771: if ( currentDeviceObject == NULL ) {
3772:
3773: //
3774: // We didn't expect this interrupt. We've dismissed it just
3775: // in case, but now return FALSE withOUT waking up the thread.
3776: //
3777:
3778: FloppyDump(
3779: FLOPDBGP,
3780: ("Floppy: unexpected interrupt\n")
3781: );
3782:
3783: return FALSE;
3784: }
3785:
3786: if ( !controllerStateError ) {
3787:
3788: //
3789: // Request a DPC for execution later to get the remainder of the
3790: // floppy state.
3791: //
3792:
3793: controllerData->IsrReentered = 0;
3794: IoRequestDpc(
3795: currentDeviceObject,
3796: currentDeviceObject->CurrentIrp,
3797: (PVOID) NULL );
3798:
3799: } else {
3800:
3801: //
3802: // Running the floppy (at least on R4000 boxes) we've seen
3803: // examples where the device interrupts, yet it never says
3804: // it *ISN'T* busy. If this ever happens on non-MCA x86 boxes
3805: // it would be ok since we use latched interrupts. Even if
3806: // the device isn't touched so that the line would be pulled
3807: // down, on the latched machine, this ISR wouldn't be called
3808: // again. The normal timeout code for a request would eventually
3809: // reset the controller and retry the request.
3810: //
3811: // On the R4000 boxes and on MCA machines, the floppy is using
3812: // level sensitive interrupts. Therefore if we don't do something
3813: // to lower the interrupt line, we will be called over and over,
3814: // *forever*. This makes it look as though the machine is hung.
3815: // Unless we were lucky enough to be on a multiprocessor, the
3816: // normal timeout code would NEVER get a chance to run because
3817: // the timeout code runs at dispatch level, and we will never
3818: // leave device level.
3819: //
3820: // What we will do is keep a counter that is incremented every
3821: // time we reach this section of code. When the counter goes
3822: // over the threshold we will do a hard reset of the device
3823: // and reset the counter down to zero. The counter will be
3824: // initialized when the device is first initialized. It will
3825: // be set to zero in the other arm of this if, and it will be
3826: // reset to zero by the normal timeout logic.
3827: //
3828:
3829: controllerData->CurrentDeviceObject = currentDeviceObject;
3830: if (controllerData->IsrReentered > FLOPPY_RESET_ISR_THRESHOLD) {
3831:
3832: //
3833: // Reset the controller. This could cause an interrupt
3834: //
3835:
3836: controllerData->IsrReentered = 0;
3837:
3838: controllerData->DriveControlImage |= DRVCTL_ENABLE_DMA_AND_INTERRUPTS;
3839: controllerData->DriveControlImage &= ~( DRVCTL_ENABLE_CONTROLLER );
3840:
3841: WRITE_CONTROLLER(
3842: &controllerData->ControllerAddress->DriveControl,
3843: controllerData->DriveControlImage );
3844:
3845: KeStallExecutionProcessor( 10 );
3846:
3847: controllerData->DriveControlImage |= DRVCTL_ENABLE_CONTROLLER;
3848:
3849: WRITE_CONTROLLER(
3850: &controllerData->ControllerAddress->DriveControl,
3851: controllerData->DriveControlImage );
3852:
3853: //
3854: // Give the device plenty of time to be reset and
3855: // interrupt again. Then just do the sense interrupt.
3856: // this should quiet the device. We will then let
3857: // the normal timeout code do its work.
3858: //
3859:
3860: KeStallExecutionProcessor(500);
3861: WRITE_CONTROLLER(
3862: &controllerData->ControllerAddress->Fifo,
3863: COMMND_SENSE_INTERRUPT );
3864: KeStallExecutionProcessor(500);
3865:
3866: KeInsertQueueDpc(
3867: &controllerData->LogErrorDpc,
3868: NULL,
3869: NULL
3870: );
3871:
3872: } else {
3873:
3874: controllerData->IsrReentered++;
3875:
3876: }
3877:
3878: }
3879: return TRUE;
3880: }
3881:
3882: VOID
3883: FloppyDeferredProcedure(
3884: IN PKDPC Dpc,
3885: IN PVOID DeferredContext,
3886: IN PVOID SystemArgument1,
3887: IN PVOID SystemArgument2
3888: )
3889:
3890: /*++
3891:
3892: Routine Description:
3893:
3894: This routine is called at DISPATCH_LEVEL by the system at the
3895: request of FloppyInterruptService(). It simply sets the interrupt
3896: event, which wakes up the floppy thread.
3897:
3898: Arguments:
3899:
3900: Dpc - a pointer to the DPC object used to invoke this routine.
3901:
3902: DeferredContext - a pointer to the device object associated with this
3903: DPC.
3904:
3905: SystemArgument1 - unused.
3906:
3907: SystemArgument2 - unused.
3908:
3909: Return Value:
3910:
3911: None.
3912:
3913: --*/
3914:
3915: {
3916: PDEVICE_OBJECT deviceObject;
3917: PDISKETTE_EXTENSION disketteExtension;
3918:
3919: UNREFERENCED_PARAMETER( Dpc );
3920: UNREFERENCED_PARAMETER( SystemArgument1 );
3921: UNREFERENCED_PARAMETER( SystemArgument2 );
3922:
3923: #ifdef KEEP_COUNTERS
3924: FloppyDPCs++;
3925: FloppyDPCTime = KeQueryPerformanceCounter((PVOID)NULL);
3926:
3927: FloppyDPCDelay = RtlLargeIntegerAdd(FloppyDPCDelay,
3928: RtlLargeIntegerSubtract(FloppyDPCTime,
3929: FloppyIntrTime));
3930: #endif
3931:
3932: deviceObject = (PDEVICE_OBJECT) DeferredContext;
3933: disketteExtension = deviceObject->DeviceExtension;
3934:
3935: KeSetEvent(
3936: &disketteExtension->ControllerData->InterruptEvent,
3937: (KPRIORITY) 0,
3938: FALSE );
3939: }
3940:
3941: NTSTATUS
3942: FlSendByte(
3943: IN UCHAR ByteToSend,
3944: IN PCONTROLLER_DATA ControllerData
3945: )
3946:
3947: /*++
3948:
3949: Routine Description:
3950:
3951: This routine is called to send a byte to the controller. It won't
3952: send the byte unless the controller is ready to receive a byte; if
3953: it's not ready after checking FIFO_TIGHTLOOP_RETRY_COUNT times, we
3954: delay for the minimum possible time (10ms) and then try again. It
3955: should always be ready after waiting 10ms.
3956:
3957: Arguments:
3958:
3959: ByteToSend - the byte to send to the controller.
3960:
3961: ControllerData - a pointer to our data area for this controller.
3962:
3963: Return Value:
3964:
3965: STATUS_SUCCESS if the byte was sent to the controller;
3966: STATUS_DEVICE_NOT_READY otherwise.
3967:
3968: --*/
3969:
3970: {
3971: ULONG i = 0;
3972: BOOLEAN byteWritten = FALSE;
3973:
3974: //
3975: // Sit in a tight loop for a while. If the controller becomes ready,
3976: // send the byte.
3977: //
3978:
3979: do {
3980:
3981: if ( ( READ_CONTROLLER( &ControllerData->ControllerAddress->Status )
3982: & STATUS_IO_READY_MASK ) == STATUS_WRITE_READY ) {
3983:
3984: WRITE_CONTROLLER(
3985: &ControllerData->ControllerAddress->Fifo,
3986: ByteToSend );
3987:
3988: byteWritten = TRUE;
3989:
3990: }
3991:
3992: i++;
3993:
3994: } while ( (!byteWritten) && ( i < FIFO_TIGHTLOOP_RETRY_COUNT ) );
3995:
3996: //
3997: // We hope that in most cases the FIFO will become ready very quickly
3998: // and the above loop will have written the byte. But if the FIFO
3999: // is not yet ready, we'll loop a few times delaying for 10ms and then
4000: // try it again.
4001: //
4002:
4003: i = 0;
4004:
4005: while ( ( !byteWritten ) && ( i < FIFO_DELAY_RETRY_COUNT ) ) {
4006:
4007: FloppyDump(
4008: FLOPINFO,
4009: ("Floppy: waiting for 10ms for controller write\n")
4010: );
4011:
4012: KeDelayExecutionThread(
4013: KernelMode,
4014: FALSE,
4015: &ControllerData->Minimum10msDelay );
4016:
4017: i++;
4018:
4019: if ( (READ_CONTROLLER( &ControllerData->ControllerAddress->Status )
4020: & STATUS_IO_READY_MASK) == STATUS_WRITE_READY ) {
4021:
4022: WRITE_CONTROLLER(
4023: &ControllerData->ControllerAddress->Fifo,
4024: ByteToSend );
4025:
4026: byteWritten = TRUE;
4027: }
4028: }
4029:
4030: if ( byteWritten ) {
4031:
4032: return STATUS_SUCCESS;
4033:
4034: } else {
4035:
4036: //
4037: // We've waited over 30ms, and the FIFO *still* isn't ready.
4038: // Return an error.
4039: //
4040:
4041: FloppyDump(
4042: FLOPWARN,
4043: ("Floppy: FIFO not ready to write after 30ms\n")
4044: );
4045:
4046: ControllerData->HardwareFailed = TRUE;
4047:
4048: return STATUS_DEVICE_NOT_READY;
4049: }
4050: }
4051:
4052: NTSTATUS
4053: FlGetByte(
4054: OUT PUCHAR ByteToGet,
4055: IN PCONTROLLER_DATA ControllerData
4056: )
4057:
4058: /*++
4059:
4060: Routine Description:
4061:
4062: This routine is called to get a byte from the controller. It won't
4063: read the byte unless the controller is ready to send a byte; if
4064: it's not ready after checking FIFO_RETRY_COUNT times, we delay for
4065: the minimum possible time (10ms) and then try again. It should
4066: always be ready after waiting 10ms.
4067:
4068: Arguments:
4069:
4070: ByteToGet - the address in which the byte read from the controller
4071: is stored.
4072:
4073: ControllerData - a pointer to our data area for this controller.
4074:
4075: Return Value:
4076:
4077: STATUS_SUCCESS if a byte was read from the controller;
4078: STATUS_DEVICE_NOT_READY otherwise.
4079:
4080: --*/
4081:
4082: {
4083: ULONG i = 0;
4084: BOOLEAN byteRead = FALSE;
4085:
4086: //
4087: // Sit in a tight loop for a while. If the controller becomes ready,
4088: // read the byte.
4089: //
4090:
4091: do {
4092:
4093: if ( ( READ_CONTROLLER( &ControllerData->ControllerAddress->Status )
4094: & STATUS_IO_READY_MASK ) == STATUS_READ_READY ) {
4095:
4096: *ByteToGet = READ_CONTROLLER(
4097: &ControllerData->ControllerAddress->Fifo );
4098:
4099: byteRead = TRUE;
4100:
4101: }
4102:
4103: i++;
4104:
4105: } while ( ( !byteRead ) && ( i < FIFO_TIGHTLOOP_RETRY_COUNT ) );
4106:
4107: //
4108: // We hope that in most cases the FIFO will become ready very quickly
4109: // and the above loop will have read the byte. But if the FIFO
4110: // is not yet ready, we'll loop a few times delaying for 10ms and then
4111: // trying it again.
4112: //
4113:
4114: i = 0;
4115:
4116: while ( ( !byteRead ) && ( i < FIFO_DELAY_RETRY_COUNT ) ) {
4117:
4118: FloppyDump(
4119: FLOPINFO,
4120: ("Floppy: waiting for 10ms for controller read\n")
4121: );
4122:
4123: KeDelayExecutionThread(
4124: KernelMode,
4125: FALSE,
4126: &ControllerData->Minimum10msDelay );
4127:
4128: i++;
4129:
4130: if ( (READ_CONTROLLER( &ControllerData->ControllerAddress->Status )
4131: & STATUS_IO_READY_MASK) == STATUS_READ_READY ) {
4132:
4133: *ByteToGet = READ_CONTROLLER(
4134: &ControllerData->ControllerAddress->Fifo );
4135:
4136: byteRead = TRUE;
4137:
4138: }
4139: }
4140:
4141: if ( byteRead ) {
4142:
4143: return STATUS_SUCCESS;
4144:
4145: } else {
4146:
4147: //
4148: // We've waited over 30ms, and the FIFO *still* isn't ready.
4149: // Return an error.
4150: //
4151:
4152: FloppyDump(
4153: FLOPWARN,
4154: ("Floppy: FIFO not ready to read after 30ms\n")
4155: );
4156:
4157: ControllerData->HardwareFailed = TRUE;
4158:
4159: return STATUS_DEVICE_NOT_READY;
4160: }
4161:
4162: }
4163:
4164: NTSTATUS
4165: FlInterpretError(
4166: IN UCHAR StatusRegister1,
4167: IN UCHAR StatusRegister2
4168: )
4169:
4170: /*++
4171:
4172: Routine Description:
4173:
4174: This routine is called when the floppy controller returns an error.
4175: Status registers 1 and 2 are passed in, and this returns an appropriate
4176: error status.
4177:
4178: Arguments:
4179:
4180: StatusRegister1 - the controller's status register #1.
4181:
4182: StatusRegister2 - the controller's status register #2.
4183:
4184: Return Value:
4185:
4186: An NTSTATUS error determined from the status registers.
4187:
4188: --*/
4189:
4190: {
4191: if ( ( StatusRegister1 & STREG1_CRC_ERROR ) ||
4192: ( StatusRegister2 & STREG2_CRC_ERROR ) ) {
4193:
4194: return STATUS_CRC_ERROR;
4195: }
4196:
4197: if ( StatusRegister1 & STREG1_DATA_OVERRUN ) {
4198:
4199: return STATUS_DATA_OVERRUN;
4200: }
4201:
4202: if ( ( StatusRegister1 & STREG1_SECTOR_NOT_FOUND ) ||
4203: ( StatusRegister1 & STREG1_END_OF_DISKETTE ) ) {
4204:
4205: return STATUS_NONEXISTENT_SECTOR;
4206: }
4207:
4208: if ( ( StatusRegister2 & STREG2_DATA_NOT_FOUND ) ||
4209: ( StatusRegister2 & STREG2_BAD_CYLINDER ) ||
4210: ( StatusRegister2 & STREG2_DELETED_DATA ) ) {
4211:
4212: return STATUS_DEVICE_DATA_ERROR;
4213: }
4214:
4215: if ( StatusRegister1 & STREG1_WRITE_PROTECTED ) {
4216:
4217: return STATUS_MEDIA_WRITE_PROTECTED;
4218: }
4219:
4220: if ( StatusRegister1 & STREG1_ID_NOT_FOUND ) {
4221:
4222: return STATUS_FLOPPY_ID_MARK_NOT_FOUND;
4223:
4224: }
4225:
4226: if ( StatusRegister2 & STREG2_WRONG_CYLINDER ) {
4227:
4228: return STATUS_FLOPPY_WRONG_CYLINDER;
4229:
4230: }
4231:
4232: //
4233: // There's other error bits, but no good status values to map them
4234: // to. Just return a generic one.
4235: //
4236:
4237: return STATUS_FLOPPY_UNKNOWN_ERROR;
4238: }
4239:
4240: BOOLEAN
4241: FlClearIsrReentered(
4242: IN PVOID Context
4243: )
4244:
4245: /*++
4246:
4247: Routine Description:
4248:
4249: This routine is simply used to clear the reentered count of the isr.
4250:
4251: Arguments:
4252:
4253: Context - Simply a pointer to the re-entered count of the isr.
4254:
4255: Return Value:
4256:
4257: Always False.
4258:
4259: --*/
4260:
4261: {
4262:
4263: *((ULONG *)Context) = 0;
4264: return FALSE;
4265:
4266: }
4267:
4268: VOID
4269: FlFinishOperation(
4270: IN OUT PIRP Irp,
4271: IN PDISKETTE_EXTENSION DisketteExtension
4272: )
4273:
4274: /*++
4275:
4276: Routine Description:
4277:
4278: This routine is called by FloppyThread at the end of any operation
4279: whether it succeeded or not.
4280:
4281: If the packet is failing due to a hardware error, this routine will
4282: reinitialize the hardware and retry once.
4283:
4284: When the packet is done, this routine will start the timer to turn
4285: off the motor, and complete the IRP.
4286:
4287: Arguments:
4288:
4289: Irp - a pointer to the IO Request Packet being processed.
4290:
4291: DisketteExtension - a pointer to the diskette extension for the
4292: diskette on which the operation occurred.
4293:
4294: Return Value:
4295:
4296: None.
4297:
4298: --*/
4299:
4300: {
4301: KIRQL oldIrql;
4302: PCONTROLLER_DATA controllerData;
4303: NTSTATUS ntStatus;
4304: UCHAR driveStatus;
4305:
4306: FloppyDump(
4307: FLOPSHOW,
4308: ("Floppy: FloppyFinishOperation...\n")
4309: );
4310:
4311: controllerData = DisketteExtension->ControllerData;
4312:
4313: //
4314: // See if this packet is being failed due to a hardware error.
4315: //
4316:
4317: if ( ( Irp->IoStatus.Status != STATUS_SUCCESS ) &&
4318: ( controllerData->HardwareFailed ) ) {
4319:
4320: controllerData->HardwareFailCount++;
4321:
4322: if ( controllerData->HardwareFailCount < HARDWARE_RESET_RETRY_COUNT ) {
4323:
4324: KeSynchronizeExecution(
4325: controllerData->InterruptObject,
4326: FlClearIsrReentered,
4327: &controllerData->IsrReentered
4328: );
4329: //
4330: // This is our first time through (that is, we're not retrying
4331: // the packet after a hardware failure). If it failed this first
4332: // time because of a hardware problem, set the HardwareFailed flag
4333: // and put the IRP at the beginning of the request queue.
4334: //
4335:
4336: ntStatus = FlInitializeControllerHardware(
4337: controllerData,
4338: DisketteExtension->DeviceObject );
4339:
4340: if ( NT_SUCCESS( ntStatus ) ) {
4341:
4342: FloppyDump(
4343: FLOPINFO,
4344: ("Floppy: packet failed; hardware reset. Retry.\n")
4345: );
4346:
4347: //
4348: // Force media to be redetermined, in case we messed up
4349: // and to make sure FlDatarateSpecifyConfigure() gets
4350: // called.
4351: //
4352:
4353: DisketteExtension->MediaType = Undetermined;
4354:
4355: FloppyDump(
4356: FLOPIRPPATH,
4357: ("Floppy: irp %x failed - back on the queue with it\n",
4358: Irp)
4359: );
4360: ExInterlockedInsertHeadList(
4361: &controllerData->ListEntry,
4362: &Irp->Tail.Overlay.ListEntry,
4363: &controllerData->ListSpinLock );
4364:
4365: return;
4366: }
4367:
4368: FloppyDump(
4369: FLOPDBGP,
4370: ("Floppy: packet AND hardware reset failed.\n")
4371: );
4372: }
4373:
4374: }
4375:
4376: //
4377: // If we didn't already RETURN, we're done with this packet so
4378: // reset the HardwareFailCount for the next packet.
4379: //
4380:
4381: controllerData->HardwareFailCount = 0;
4382:
4383: //
4384: // If there's a motor on, set the timer so that it will be turned off
4385: // in a couple of seconds if nobody uses it.
4386: //
4387:
4388: driveStatus = controllerData->DriveControlImage;
4389:
4390: if ( ( driveStatus & DRVCTL_MOTOR_MASK ) != 0 ) {
4391:
4392: KeAcquireSpinLock( &controllerData->TimerSpinLock, &oldIrql );
4393:
4394: driveStatus = controllerData->DriveControlImage;
4395:
4396: if ( ( driveStatus & DRVCTL_MOTOR_MASK ) != 0 ) {
4397:
4398: controllerData->MotorTimer = TIMER_START;
4399: }
4400:
4401: KeReleaseSpinLock( &controllerData->TimerSpinLock, oldIrql );
4402: }
4403:
4404: //
4405: // If this request was unsuccessful and the error is one that can be
4406: // remedied by the user, save the Device Object so that the file system,
4407: // after reaching its original entry point, can know the real device.
4408: //
4409:
4410: if ( !NT_SUCCESS( Irp->IoStatus.Status ) &&
4411: IoIsErrorUserInduced( Irp->IoStatus.Status ) ) {
4412:
4413: IoSetHardErrorOrVerifyDevice( Irp, DisketteExtension->DeviceObject );
4414: }
4415:
4416: //
4417: // Even if the operation failed, it probably had to wait for the drive
4418: // to spin up or somesuch so we'll always complete the request with the
4419: // standard priority boost.
4420: //
4421:
4422: if ( ( Irp->IoStatus.Status != STATUS_SUCCESS ) &&
4423: ( Irp->IoStatus.Status != STATUS_VERIFY_REQUIRED ) &&
4424: ( Irp->IoStatus.Status != STATUS_NO_MEDIA_IN_DEVICE ) ) {
4425:
4426: FloppyDump(
4427: FLOPDBGP,
4428: ("Floppy: IRP failed with error %lx\n", Irp->IoStatus.Status)
4429: );
4430:
4431: } else {
4432:
4433: FloppyDump(
4434: FLOPINFO,
4435: ("Floppy: IoStatus.Status = %x\n", Irp->IoStatus.Status)
4436: );
4437: }
4438:
4439: FloppyDump(
4440: FLOPINFO,
4441: ("Floppy: IoStatus.Information = %x\n", Irp->IoStatus.Information)
4442: );
4443:
4444: FloppyDump(
4445: FLOPIRPPATH,
4446: ("Floppy: Finishing up IRP: %x\n",Irp)
4447: );
4448: IoCompleteRequest( Irp, IO_DISK_INCREMENT );
4449: }
4450:
4451: VOID
4452: FloppyMotorOffDpc(
4453: IN PDEVICE_OBJECT DeviceObject,
4454: IN PVOID Context
4455: )
4456:
4457: /*++
4458:
4459: Routine Description:
4460:
4461: This routine is called at DISPATCH_LEVEL once every second by the
4462: I/O system.
4463:
4464: If the timer is "set" (greater than 0) this routine will decrement
4465: it. If it ever reaches 0, the running motor is turned off.
4466:
4467: Arguments:
4468:
4469: DeviceObject - a pointer to the device object associated with this
4470: timer (always the first disk on the controller).
4471:
4472: Context - unused.
4473:
4474: Return Value:
4475:
4476: None.
4477:
4478: --*/
4479:
4480: {
4481: KIRQL oldIrql;
4482: PDISKETTE_EXTENSION disketteExtension;
4483: PCONTROLLER_DATA controllerData;
4484:
4485: UNREFERENCED_PARAMETER( Context );
4486:
4487: disketteExtension = (PDISKETTE_EXTENSION) DeviceObject->DeviceExtension;
4488: controllerData = disketteExtension->ControllerData;
4489:
4490: if ( controllerData->MotorTimer != TIMER_CANCEL ) {
4491:
4492: //
4493: // One of the motors is running - grab the timer spinlock and
4494: // decrement the timer counter. If it expires, turn off the
4495: // motor.
4496: //
4497:
4498: KeAcquireSpinLock( &controllerData->TimerSpinLock, &oldIrql );
4499:
4500: if ( controllerData->MotorTimer != TIMER_CANCEL ) {
4501:
4502: controllerData->MotorTimer--;
4503:
4504: if ( controllerData->MotorTimer == TIMER_EXPIRED ) {
4505:
4506: controllerData->MotorTimer = TIMER_CANCEL;
4507:
4508: controllerData->DriveControlImage =
4509: DRVCTL_ENABLE_DMA_AND_INTERRUPTS +
4510: DRVCTL_ENABLE_CONTROLLER;
4511:
4512: WRITE_CONTROLLER(
4513: &controllerData->ControllerAddress->DriveControl,
4514: controllerData->DriveControlImage );
4515: }
4516: }
4517:
4518: KeReleaseSpinLock( &controllerData->TimerSpinLock, oldIrql );
4519: }
4520: }
4521:
4522: NTSTATUS
4523: FlIssueCommand(
4524: IN UCHAR Command,
4525: IN OUT PDISKETTE_EXTENSION DisketteExtension
4526: )
4527:
4528: /*++
4529:
4530: Routine Description:
4531:
4532: This routine sends the command and all parameters to the controller,
4533: waits for the command to interrupt if necessary, and reads the result
4534: bytes from the controller, if any.
4535:
4536: Before calling this routine, the caller should put the parameters for
4537: the command in ControllerData->FifoBuffer[]. The result bytes will
4538: be returned in the same place.
4539:
4540: This routine runs off the CommandTable. For each command, this says
4541: how many parameters there are, whether or not there is an interrupt
4542: to wait for, and how many result bytes there are. Note that commands
4543: without result bytes actually have two, since the ISR will issue a
4544: SENSE INTERRUPT STATUS command on their behalf.
4545:
4546: Arguments:
4547:
4548: Command - a byte specifying the command to be sent to the controller.
4549:
4550: DisketteExtension - a pointer to our data area for the drive being
4551: accessed (any drive if a controller command is being given).
4552:
4553: Return Value:
4554:
4555: STATUS_SUCCESS if the command was sent and bytes received properly;
4556: appropriate error propogated otherwise.
4557:
4558: --*/
4559:
4560: {
4561: PCONTROLLER_DATA controllerData;
4562: NTSTATUS ntStatus;
4563: NTSTATUS ntStatus2;
4564: UCHAR i;
4565:
4566: FloppyDump(
4567: FLOPSHOW,
4568: ("Floppy: FloppyIssueCommand...\n")
4569: );
4570:
4571: controllerData = DisketteExtension->ControllerData;
4572:
4573: //
4574: // If this command causes an interrupt, set CurrentDeviceObject and
4575: // reset the interrupt event.
4576: //
4577:
4578: if ( CommandTable[Command & COMMAND_MASK].InterruptExpected ) {
4579:
4580: controllerData->CurrentDeviceObject = DisketteExtension->DeviceObject;
4581:
4582: controllerData->CommandHasResultPhase =
4583: !!CommandTable[Command & COMMAND_MASK].FirstResultByte;
4584:
4585: KeResetEvent( &controllerData->InterruptEvent );
4586: }
4587:
4588: //
4589: // Send the command to the controller.
4590: //
4591:
4592: ntStatus = FlSendByte( Command, controllerData );
4593:
4594: //
4595: // If the command was successfully sent, we can proceed.
4596: //
4597:
4598: if ( NT_SUCCESS( ntStatus ) ) {
4599:
4600: //
4601: // Send the parameters as long as we succeed.
4602: //
4603:
4604: for ( i = 0;
4605: ( i < CommandTable[Command & COMMAND_MASK].NumberOfParameters ) &&
4606: ( NT_SUCCESS( ntStatus ) );
4607: i++ ) {
4608:
4609: ntStatus = FlSendByte(
4610: controllerData->FifoBuffer[i],
4611: controllerData );
4612: }
4613:
4614: if ( NT_SUCCESS( ntStatus ) ) {
4615:
4616: //
4617: // If there is an interrupt, wait for it.
4618: //
4619:
4620: if ( CommandTable[Command & COMMAND_MASK].InterruptExpected ) {
4621:
4622: ntStatus = KeWaitForSingleObject(
4623: &controllerData->InterruptEvent,
4624: Executive,
4625: KernelMode,
4626: FALSE,
4627: &controllerData->InterruptDelay );
4628:
4629: if ( ntStatus == STATUS_TIMEOUT ) {
4630:
4631: //
4632: // Change info to an error. We'll just say
4633: // that the device isn't ready.
4634: //
4635:
4636: ntStatus = STATUS_DEVICE_NOT_READY;
4637:
4638: controllerData->HardwareFailed = TRUE;
4639: }
4640: #ifdef KEEP_COUNTERS
4641: FloppyThreadTime = KeQueryPerformanceCounter((PVOID)NULL);
4642: FloppyThreadDelay = RtlLargeIntegerAdd(FloppyThreadDelay,
4643: RtlLargeIntegerSubtract(FloppyThreadTime,
4644: FloppyDPCTime));
4645: FloppyFromIntrDelay = RtlLargeIntegerAdd(FloppyFromIntrDelay,
4646: RtlLargeIntegerSubtract(FloppyThreadTime,
4647: FloppyIntrTime));
4648: FloppyThreadWake++;
4649: #endif
4650: }
4651:
4652: //
4653: // If successful so far, get the result bytes.
4654: //
4655:
4656: if ( NT_SUCCESS( ntStatus ) ) {
4657:
4658: for ( i = CommandTable[Command & COMMAND_MASK].FirstResultByte;
4659: ( i < CommandTable[Command & COMMAND_MASK].
4660: NumberOfResultBytes ) && ( NT_SUCCESS( ntStatus ) );
4661: i++ ) {
4662:
4663: ntStatus = FlGetByte(
4664: &controllerData->FifoBuffer[i],
4665: controllerData );
4666: }
4667: }
4668: }
4669: }
4670:
4671: //
4672: // If there was a problem, check to see if it was caused by an
4673: // unimplemented command.
4674: //
4675:
4676: if ( !NT_SUCCESS( ntStatus ) ) {
4677:
4678: if ( ( i == 1 ) &&
4679: ( !CommandTable[Command & COMMAND_MASK].AlwaysImplemented ) ) {
4680:
4681: //
4682: // This error is probably caused by a command that's not
4683: // implemented on this controller. Read the error from the
4684: // controller, and we should be in a stable state.
4685: //
4686:
4687: ntStatus2 = FlGetByte(
4688: &controllerData->FifoBuffer[0],
4689: controllerData );
4690:
4691: //
4692: // If GetByte went as planned, we'll return the original error.
4693: //
4694:
4695: if ( NT_SUCCESS( ntStatus2 ) ) {
4696:
4697: if ( controllerData->FifoBuffer[0] !=
4698: STREG0_END_INVALID_COMMAND ) {
4699:
4700: //
4701: // Status isn't as we expect, so return generic error.
4702: //
4703:
4704: ntStatus = STATUS_FLOPPY_BAD_REGISTERS;
4705:
4706: controllerData->HardwareFailed = TRUE;
4707: }
4708:
4709: } else {
4710:
4711: //
4712: // GetByte returned an error, so propogate THAT.
4713: //
4714:
4715: ntStatus = ntStatus2;
4716: }
4717: }
4718: }
4719:
4720: if ( !NT_SUCCESS( ntStatus ) ) {
4721:
4722: //
4723: // Print an error message unless the command isn't always
4724: // implemented, ie CONFIGURE.
4725: //
4726:
4727: if ( !( ( ntStatus == STATUS_DEVICE_NOT_READY ) &&
4728: ( !CommandTable[Command & COMMAND_MASK].AlwaysImplemented ) ) ) {
4729:
4730: FloppyDump(
4731: FLOPDBGP,
4732: ("Floppy: err %x "
4733: "------ while giving command %x\n",
4734: ntStatus,
4735: Command)
4736: );
4737: }
4738: }
4739:
4740: return ntStatus;
4741: }
4742:
4743: NTSTATUS
4744: FlStartDrive(
4745: IN OUT PDISKETTE_EXTENSION DisketteExtension,
4746: IN BOOLEAN WriteOperation,
4747: IN BOOLEAN SetUpMedia,
4748: IN BOOLEAN IgnoreChange
4749: )
4750:
4751: /*++
4752:
4753: Routine Description:
4754:
4755: This routine is called at the beginning of every operation. It cancels
4756: the motor timer if it's on, turns the motor on and waits for it to
4757: spin up if it was off, resets the disk change line and returns
4758: VERIFY_REQUIRED if the disk has been changed, determines the diskette
4759: media type if it's not known and SetUpMedia=TRUE, and makes sure that
4760: the disk isn't write protected if WriteOperation = TRUE.
4761:
4762: Arguments:
4763:
4764: DisketteExtension - a pointer to our data area for the drive being
4765: started.
4766:
4767: WriteOperation - TRUE if the diskette will be written to, FALSE
4768: otherwise.
4769:
4770: SetUpMedia - TRUE if the media type of the diskette in the drive
4771: should be determined.
4772:
4773: IgnoreChange - Do not return VERIFY_REQUIRED eventhough we are mounting
4774: for the first time.
4775:
4776: Return Value:
4777:
4778: STATUS_SUCCESS if the drive is started properly; appropriate error
4779: propogated otherwise.
4780:
4781: --*/
4782:
4783: {
4784: LARGE_INTEGER motorOnDelay;
4785: KIRQL oldIrql;
4786: PCONTROLLER_DATA controllerData;
4787: NTSTATUS ntStatus = STATUS_SUCCESS;
4788: USHORT timeToWait;
4789: UCHAR driveStatus;
4790: BOOLEAN motorStarted = FALSE;
4791:
4792: FloppyDump(
4793: FLOPSHOW,
4794: ("Floppy: FloppyStartDrive...\n")
4795: );
4796:
4797: //
4798: // IMPORTANT
4799: // NOTE
4800: // COMMENT
4801: //
4802: // Here we will copy the BIOS floppy configuration on top of the
4803: // highest media value in our global array so that any type of processing
4804: // that will recalibrate the drive can have it done here.
4805: // An optimization would be to only do it when we will try to recalibrate
4806: // the driver or media in it.
4807: // At this point, we ensure that on any processing of a command we
4808: // are going to have the real values inthe first entry of the array for
4809: // driver constants.
4810: //
4811:
4812: DriveMediaConstants[DriveMediaLimits[DisketteExtension->DriveType].
4813: HighestDriveMediaType] = DisketteExtension->BiosDriveMediaConstants;
4814:
4815:
4816:
4817: controllerData = DisketteExtension->ControllerData;
4818:
4819: if ( ( controllerData->CreatedArtificialDrive ) &&
4820: ( controllerData->LastDisketteExtension != DisketteExtension ) ) {
4821:
4822: //
4823: // There's an artificial drive, and the user has switched, so
4824: // pretend there's no media so the user will be prompted to
4825: // insert the other diskette.
4826: //
4827:
4828: controllerData->LastDisketteExtension = DisketteExtension;
4829: DisketteExtension->ArtificialVerifyRequired = TRUE;
4830:
4831: FloppyDump(
4832: FLOPSHOW,
4833: ("Floppy: start drive - artificial drive needs verification\n")
4834: );
4835: return STATUS_NO_MEDIA_IN_DEVICE;
4836: }
4837:
4838: //
4839: // There is no override of the artifically induced verify.
4840: //
4841:
4842: if ( DisketteExtension->ArtificialVerifyRequired == TRUE ) {
4843:
4844: if ( DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED ) {
4845:
4846: DisketteExtension->DeviceObject->Flags |= DO_VERIFY_VOLUME;
4847: }
4848:
4849: DisketteExtension->ArtificialVerifyRequired = FALSE;
4850: FloppyDump(
4851: FLOPSHOW,
4852: ("Floppy: start drive - artificial verify required\n")
4853: );
4854: return STATUS_VERIFY_REQUIRED;
4855: }
4856:
4857: //
4858: // Grab the timer spin lock and cancel the timer, since we want the
4859: // motor to run for the whole operation. If the proper drive is
4860: // already running, great; if not, start the motor and wait for it
4861: // to spin up.
4862: //
4863:
4864: KeAcquireSpinLock( &controllerData->TimerSpinLock, &oldIrql );
4865:
4866: controllerData->MotorTimer = TIMER_CANCEL;
4867:
4868: driveStatus = controllerData->DriveControlImage;
4869:
4870: if ( driveStatus != DisketteExtension->DriveOnValue ) {
4871:
4872: controllerData->DriveControlImage = DisketteExtension->DriveOnValue;
4873:
4874: WRITE_CONTROLLER(
4875: &controllerData->ControllerAddress->DriveControl,
4876: controllerData->DriveControlImage );
4877:
4878: //
4879: // If this the drive media is unknown, initialize the diskette
4880: // extension. This is done to get the time to wait value so use
4881: // the slowest and oldest drive type.
4882: //
4883:
4884: if ((DisketteExtension->MediaType == Undetermined) ||
4885: (DisketteExtension->MediaType == Unknown)) {
4886:
4887: DisketteExtension->DriveMediaConstants = DriveMediaConstants[0];
4888: }
4889:
4890: KeReleaseSpinLock( &controllerData->TimerSpinLock, oldIrql );
4891:
4892: //
4893: // Wait the appropriate length of time for the drive to spin up.
4894: //
4895:
4896: if ( WriteOperation ) {
4897:
4898: timeToWait = DisketteExtension->DriveMediaConstants.MotorSettleTimeWrite;
4899:
4900: } else {
4901:
4902: timeToWait = DisketteExtension->DriveMediaConstants.MotorSettleTimeRead;
4903: }
4904:
4905: FloppyDump(
4906: FLOPSHOW,
4907: ("Floppy: Waiting for motor to spin up (0x%x)...\n", timeToWait)
4908: );
4909:
4910: motorOnDelay.LowPart = - ( 10 * 1000 * timeToWait );
4911: motorOnDelay.HighPart = -1;
4912:
4913: KeDelayExecutionThread( KernelMode, FALSE, &motorOnDelay );
4914:
4915: motorStarted = TRUE;
4916:
4917: } else {
4918:
4919: KeReleaseSpinLock( &controllerData->TimerSpinLock, oldIrql );
4920:
4921: }
4922:
4923: driveStatus = READ_CONTROLLER(
4924: &controllerData->ControllerAddress->DRDC.DiskChange );
4925:
4926: //
4927: // Support for 360K drives:
4928: // They have no change line, so we will assume a power up of the motor
4929: // to be equivalent to a change of floppy (we assume noone will
4930: // change the floppy while it is turning.
4931: // So force a VERIFY here (unless the file system explicitly turned
4932: // it off).
4933: //
4934:
4935: if ( ((DisketteExtension->DriveType == DRIVE_TYPE_0360) &&
4936: motorStarted) ||
4937: ((DisketteExtension->DriveType != DRIVE_TYPE_0360) &&
4938: (driveStatus & DSKCHG_DISKETTE_REMOVED)) ) {
4939:
4940: FloppyDump(
4941: FLOPSHOW,
4942: ("Floppy: disk changed...\n")
4943: );
4944:
4945: DisketteExtension->MediaType = Undetermined;
4946:
4947: //
4948: // If the volume is mounted, we must tell the filesystem to
4949: // verify that the media in the drive is the same volume.
4950: //
4951:
4952: if ( DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED ) {
4953:
4954: DisketteExtension->DeviceObject->Flags |= DO_VERIFY_VOLUME;
4955:
4956: }
4957:
4958: //
4959: // Only go through the device reset if we did get the flag set
4960: // We really only want to go throught here if the diskette changed,
4961: // but on 360 it will always say the diskette has changed.
4962: // So based on our previous test, only proceed if it is NOT
4963: // a 360K driver
4964:
4965: // if ( driveStatus & DSKCHG_DISKETTE_REMOVED ) {
4966:
4967: if (DisketteExtension->DriveType != DRIVE_TYPE_0360) {
4968:
4969: //
4970: // Now seek twice to reset the "disk changed" line. First
4971: // seek to 1.
4972: //
4973: // Normally we'd do a READ ID after a seek. However, we don't
4974: // even know if this disk is formatted. We're not really
4975: // trying to get anywhere; we're just doing this to reset the
4976: // "disk changed" line so we'll skip the READ ID.
4977: //
4978:
4979: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit;
4980: controllerData->FifoBuffer[1] = 1;
4981:
4982: ntStatus = FlIssueCommand( COMMND_SEEK, DisketteExtension );
4983:
4984: if ( !NT_SUCCESS( ntStatus ) ) {
4985:
4986: FloppyDump(
4987: FLOPWARN,
4988: ("Floppy: seek to 1 returned %x\n", ntStatus)
4989: );
4990:
4991: return ntStatus;
4992:
4993: } else {
4994:
4995: if ( !( controllerData->FifoBuffer[0] & STREG0_SEEK_COMPLETE )
4996: || ( controllerData->FifoBuffer[1] != 1 ) ) {
4997:
4998: FloppyDump(
4999: FLOPWARN,
5000: ("Floppy: Seek to 1 had bad return registers\n")
5001: );
5002:
5003: controllerData->HardwareFailed = TRUE;
5004:
5005: return STATUS_FLOPPY_BAD_REGISTERS;
5006: }
5007: }
5008:
5009: //
5010: // Seek back to 0. We can once again skip the READ ID.
5011: //
5012:
5013: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit;
5014: controllerData->FifoBuffer[1] = 0;
5015:
5016: ntStatus = FlIssueCommand( COMMND_SEEK, DisketteExtension );
5017:
5018: if ( !NT_SUCCESS( ntStatus ) ) {
5019:
5020: FloppyDump(
5021: FLOPWARN,
5022: ("Floppy: seek to 0 returned %x\n", ntStatus)
5023: );
5024:
5025: return ntStatus;
5026:
5027: } else {
5028:
5029: if ( !( controllerData->FifoBuffer[0] & STREG0_SEEK_COMPLETE )
5030: || ( controllerData->FifoBuffer[1] != 0 ) ) {
5031:
5032: FloppyDump(
5033: FLOPWARN,
5034: ("Floppy: Seek to 0 had bad return registers\n")
5035: );
5036:
5037: controllerData->HardwareFailed = TRUE;
5038:
5039: return STATUS_FLOPPY_BAD_REGISTERS;
5040: }
5041: }
5042:
5043: driveStatus = READ_CONTROLLER(
5044: &controllerData->ControllerAddress->DRDC.DiskChange );
5045:
5046: if ( driveStatus & DSKCHG_DISKETTE_REMOVED ) {
5047:
5048: //
5049: // If "disk changed" is still set after the double seek, the
5050: // drive door must be opened.
5051: //
5052:
5053: FloppyDump(
5054: FLOPINFO,
5055: ("Floppy: close the door!\n")
5056: );
5057:
5058: //
5059: // Turn off the flag for now so that we will not get so many
5060: // gratuitous verifys. It will be set again the next time.
5061: //
5062:
5063: if ( DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED ) {
5064:
5065: DisketteExtension->DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
5066:
5067: }
5068:
5069: return STATUS_NO_MEDIA_IN_DEVICE;
5070: }
5071: }
5072:
5073: //
5074: // IgnoreChange indicates the file system is in the process
5075: // of performing a verify so do not return verify required.
5076: //
5077:
5078: if (( IgnoreChange == FALSE ) &&
5079: ( DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED )) {
5080:
5081: //
5082: // Drive WAS mounted, but door was opened since the last time
5083: // we checked so tell the file system to verify the diskette.
5084: //
5085:
5086: FloppyDump(
5087: FLOPSHOW,
5088: ("Floppy: start drive - verify required because door opened\n")
5089: );
5090:
5091: return STATUS_VERIFY_REQUIRED;
5092: }
5093: }
5094:
5095: if ( SetUpMedia ) {
5096:
5097: if ( DisketteExtension->MediaType == Undetermined ) {
5098:
5099: ntStatus = FlDetermineMediaType( DisketteExtension );
5100:
5101: } else {
5102:
5103: if ( DisketteExtension->MediaType == Unknown ) {
5104:
5105: //
5106: // We've already tried to determine the media type and
5107: // failed. It's probably not formatted.
5108: //
5109:
5110: FloppyDump(
5111: FLOPSHOW,
5112: ("Floppy - start drive - media type was unknown\n")
5113: );
5114: return STATUS_UNRECOGNIZED_MEDIA;
5115:
5116: } else {
5117:
5118: if ( DisketteExtension->DriveMediaType !=
5119: controllerData->LastDriveMediaType ) {
5120:
5121: //
5122: // Last drive/media combination accessed by the
5123: // controller was different, so set up the controller.
5124: //
5125:
5126: ntStatus = FlDatarateSpecifyConfigure( DisketteExtension );
5127: if (!NT_SUCCESS(ntStatus)) {
5128:
5129: FloppyDump(
5130: FLOPWARN,
5131: ("Floppy: start drive - bad status from datarate"
5132: "------ specify %x\n",
5133: ntStatus)
5134: );
5135:
5136: }
5137: }
5138: }
5139: }
5140: }
5141:
5142: //
5143: // If this is a WRITE, check the drive to make sure it's not write
5144: // protected. If so, return an error.
5145: //
5146:
5147: if ( ( WriteOperation ) && ( NT_SUCCESS( ntStatus ) ) ) {
5148:
5149: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit;
5150:
5151: ntStatus = FlIssueCommand( COMMND_SENSE_DRIVE, DisketteExtension );
5152:
5153: if ( !NT_SUCCESS( ntStatus ) ) {
5154:
5155: FloppyDump(
5156: FLOPWARN,
5157: ("Floppy: SENSE_DRIVE returned %x\n", ntStatus)
5158: );
5159:
5160: return ntStatus;
5161: }
5162:
5163: if ( controllerData->FifoBuffer[0] & STREG3_WRITE_PROTECTED ) {
5164:
5165: FloppyDump(
5166: FLOPSHOW,
5167: ("Floppy: start drive - media is write protected\n")
5168: );
5169: return STATUS_MEDIA_WRITE_PROTECTED;
5170: }
5171: }
5172:
5173: return ntStatus;
5174: }
5175:
5176: NTSTATUS
5177: FlDatarateSpecifyConfigure(
5178: IN PDISKETTE_EXTENSION DisketteExtension
5179: )
5180:
5181: /*++
5182:
5183: Routine Description:
5184:
5185: This routine is called to set up the controller every time a new type
5186: of diskette is to be accessed. It issues the CONFIGURE command if
5187: it's available, does a SPECIFY, sets the data rate, and RECALIBRATEs
5188: the drive.
5189:
5190: The caller must set DisketteExtension->DriveMediaType before calling
5191: this routine.
5192:
5193: Arguments:
5194:
5195: DisketteExtension - pointer to our data area for the drive to be
5196: prepared.
5197:
5198: Return Value:
5199:
5200: STATUS_SUCCESS if the controller is properly prepared; appropriate
5201: error propogated otherwise.
5202:
5203: --*/
5204:
5205: {
5206: PCONTROLLER_DATA controllerData;
5207: NTSTATUS ntStatus = STATUS_SUCCESS;
5208:
5209: FloppyDump(
5210: FLOPSHOW,
5211: ("Floppy: FloppyDatarateSpecifyConfigure...\n")
5212: );
5213:
5214: controllerData = DisketteExtension->ControllerData;
5215:
5216: //
5217: // If the controller has a CONFIGURE command, use it to enable implied
5218: // seeks. If it doesn't, we'll find out here the first time through.
5219: //
5220:
5221: if ( controllerData->ControllerConfigurable ) {
5222:
5223: controllerData->FifoBuffer[0] = 0;
5224: controllerData->FifoBuffer[1] = COMMND_CONFIGURE_FIFO_THRESHOLD +
5225: COMMND_CONFIGURE_DISABLE_POLLING;
5226:
5227: if (!DisketteExtension->DriveMediaConstants.CylinderShift) {
5228:
5229: controllerData->FifoBuffer[1] += COMMND_CONFIGURE_IMPLIED_SEEKS;
5230:
5231: }
5232:
5233: controllerData->FifoBuffer[2] = 0;
5234:
5235: ntStatus = FlIssueCommand( COMMND_CONFIGURE, DisketteExtension );
5236:
5237: if ( ntStatus == STATUS_DEVICE_NOT_READY ) {
5238:
5239: //
5240: // Note the CONFIGURE command doesn't exist. Set status to
5241: // success, so we can issue the SPECIFY command below.
5242: //
5243:
5244: FloppyDump(
5245: FLOPINFO,
5246: ("Floppy: Ignore above error - no CONFIGURE command\n")
5247: );
5248:
5249: controllerData->ControllerConfigurable = FALSE;
5250:
5251: ntStatus = STATUS_SUCCESS;
5252: }
5253: }
5254:
5255: //
5256: // Issue SPECIFY command to program the head load and unload
5257: // rates, the drive step rate, and the DMA data transfer mode.
5258: //
5259:
5260: if ( NT_SUCCESS( ntStatus ) ) {
5261:
5262: controllerData->FifoBuffer[0] =
5263: DisketteExtension->DriveMediaConstants.StepRateHeadUnloadTime;
5264:
5265: controllerData->FifoBuffer[1] =
5266: DisketteExtension->DriveMediaConstants.HeadLoadTime;
5267:
5268: ntStatus = FlIssueCommand( COMMND_SPECIFY, DisketteExtension );
5269:
5270: if ( NT_SUCCESS( ntStatus ) ) {
5271:
5272: //
5273: // Program the data rate
5274: //
5275:
5276: WRITE_CONTROLLER(
5277: &controllerData->ControllerAddress->DRDC.DataRate,
5278: DisketteExtension->DriveMediaConstants.DataTransferRate );
5279:
5280: //
5281: // Recalibrate the drive, now that we've changed all its
5282: // parameters.
5283: //
5284:
5285: ntStatus = FlRecalibrateDrive( DisketteExtension );
5286: }
5287: }
5288:
5289: if ( NT_SUCCESS( ntStatus ) ) {
5290:
5291: controllerData->LastDriveMediaType = DisketteExtension->DriveMediaType;
5292:
5293: } else {
5294:
5295: controllerData->LastDriveMediaType = Unknown;
5296: }
5297:
5298: return ntStatus;
5299: }
5300:
5301: NTSTATUS
5302: FlRecalibrateDrive(
5303: IN PDISKETTE_EXTENSION DisketteExtension
5304: )
5305:
5306: /*++
5307:
5308: Routine Description:
5309:
5310: This routine recalibrates a drive. It is called whenever we're
5311: setting up to access a new diskette, and after certain errors. It
5312: will actually recalibrate twice, since many controllers stop after
5313: 77 steps and many disks have 80 tracks.
5314:
5315: Arguments:
5316:
5317: DisketteExtension - pointer to our data area for the drive to be
5318: recalibrated.
5319:
5320: Return Value:
5321:
5322: STATUS_SUCCESS if the drive is successfully recalibrated; appropriate
5323: error is propogated otherwise.
5324:
5325: --*/
5326:
5327: {
5328: PCONTROLLER_DATA controllerData;
5329: NTSTATUS ntStatus;
5330: UCHAR recalibrateCount;
5331:
5332: FloppyDump(
5333: FLOPSHOW,
5334: ("Floppy: FloppyRecalibrateDrive...\n")
5335: );
5336:
5337: controllerData = DisketteExtension->ControllerData;
5338:
5339: recalibrateCount = 0;
5340:
5341: do {
5342:
5343: //
5344: // Issue the recalibrate command
5345: //
5346:
5347: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit;
5348:
5349: ntStatus = FlIssueCommand( COMMND_RECALIBRATE, DisketteExtension );
5350:
5351: if ( !NT_SUCCESS( ntStatus ) ) {
5352:
5353: FloppyDump(
5354: FLOPWARN,
5355: ("Floppy: recalibrate returned %x\n", ntStatus)
5356: );
5357:
5358: }
5359:
5360: if ( NT_SUCCESS( ntStatus ) ) {
5361:
5362: if ( !( controllerData->FifoBuffer[0] & STREG0_SEEK_COMPLETE ) ||
5363: ( controllerData->FifoBuffer[1] != 0 ) ) {
5364:
5365: FloppyDump(
5366: FLOPWARN,
5367: ("Floppy: recalibrate had bad registers\n")
5368: );
5369:
5370: controllerData->HardwareFailed = TRUE;
5371:
5372: ntStatus = STATUS_FLOPPY_BAD_REGISTERS;
5373: }
5374: }
5375:
5376: recalibrateCount++;
5377:
5378: } while ( ( !NT_SUCCESS( ntStatus ) ) && ( recalibrateCount < 2 ) );
5379:
5380: return ntStatus;
5381: }
5382:
5383: NTSTATUS
5384: FlDetermineMediaType(
5385: IN OUT PDISKETTE_EXTENSION DisketteExtension
5386: )
5387:
5388: /*++
5389:
5390: Routine Description:
5391:
5392: This routine is called by FlStartDrive() when the media type is
5393: unknown. It assumes the largest media supported by the drive is
5394: available, and keeps trying lower values until it finds one that
5395: works.
5396:
5397: Arguments:
5398:
5399: DisketteExtension - pointer to our data area for the drive whose
5400: media is to checked.
5401:
5402: Return Value:
5403:
5404: STATUS_SUCCESS if the type of the media is determined; appropriate
5405: error propogated otherwise.
5406:
5407: --*/
5408:
5409: {
5410: NTSTATUS ntStatus;
5411: PCONTROLLER_DATA controllerData;
5412: PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
5413: BOOLEAN mediaTypesExhausted = FALSE;
5414: ULONG retries = 0;
5415:
5416: FloppyDump(
5417: FLOPSHOW,
5418: ("Floppy: FloppyDetermineMediaType...\n")
5419: );
5420:
5421: controllerData = DisketteExtension->ControllerData;
5422:
5423: //
5424: // Try up to three times for read the media id.
5425: //
5426:
5427: for (
5428: retries = 0;
5429: retries < 3;
5430: retries++
5431: ) {
5432:
5433: if (retries) {
5434:
5435: //
5436: // We're retrying the media determination because
5437: // some silly controllers don't always want to work
5438: // at setup. First we'll reset the device to give
5439: // it a better chance of working.
5440: //
5441:
5442: FlInitializeControllerHardware(
5443: controllerData,
5444: DisketteExtension->DeviceObject
5445: );
5446:
5447: }
5448:
5449: //
5450: // Assume that the largest supported media is in the drive. If that
5451: // turns out to be untrue, we'll try successively smaller media types
5452: // until we find what's really in there (or we run out and decide
5453: // that the media isn't formatted).
5454: //
5455:
5456: DisketteExtension->DriveMediaType =
5457: DriveMediaLimits[DisketteExtension->DriveType].HighestDriveMediaType;
5458: DisketteExtension->DriveMediaConstants =
5459: DriveMediaConstants[DisketteExtension->DriveMediaType];
5460:
5461: do {
5462:
5463: ntStatus = FlDatarateSpecifyConfigure( DisketteExtension );
5464:
5465: if ( !NT_SUCCESS( ntStatus ) ) {
5466:
5467: //
5468: // The SPECIFY or CONFIGURE commands resulted in an error.
5469: // Force ourselves out of this loop and return error.
5470: //
5471:
5472: mediaTypesExhausted = TRUE;
5473:
5474: } else {
5475:
5476: //
5477: // Use the media constants table when trying to determine
5478: // media type.
5479: //
5480:
5481: driveMediaConstants =
5482: &DriveMediaConstants[DisketteExtension->DriveMediaType];
5483:
5484: //
5485: // Now try to read the ID from wherever we're at.
5486: //
5487:
5488: controllerData->FifoBuffer[0] = (UCHAR)
5489: ( DisketteExtension->DeviceUnit |
5490: ( ( driveMediaConstants->NumberOfHeads - 1 ) << 2 ) );
5491:
5492: ntStatus = FlIssueCommand(
5493: COMMND_READ_ID + COMMND_MFM,
5494: DisketteExtension );
5495:
5496: if ( ( !NT_SUCCESS( ntStatus ) ) ||
5497: ( controllerData->FifoBuffer[0] !=
5498: (UCHAR)( ( DisketteExtension->DeviceUnit ) |
5499: ( ( driveMediaConstants->NumberOfHeads - 1 ) << 2 ) ) ) ||
5500: ( controllerData->FifoBuffer[1] != 0 ) ||
5501: ( controllerData->FifoBuffer[2] != 0 ) ) {
5502:
5503: FloppyDump(
5504: FLOPINFO,
5505: ("Floppy: READID failed trying lower media\n"
5506: "------ status = %x\n"
5507: "------ SR0 = %x\n"
5508: "------ SR1 = %x\n"
5509: "------ SR2 = %x\n",
5510: ntStatus,
5511: controllerData->FifoBuffer[0],
5512: controllerData->FifoBuffer[1],
5513: controllerData->FifoBuffer[2])
5514: );
5515:
5516: DisketteExtension->DriveMediaType--;
5517: DisketteExtension->DriveMediaConstants =
5518: DriveMediaConstants[DisketteExtension->DriveMediaType];
5519:
5520: if (ntStatus != STATUS_DEVICE_NOT_READY) {
5521:
5522: ntStatus = STATUS_UNRECOGNIZED_MEDIA;
5523:
5524: }
5525:
5526: //
5527: // Next comparison must be signed, for when
5528: // LowestDriveMediaType = 0.
5529: //
5530:
5531: if ( (CHAR)( DisketteExtension->DriveMediaType ) <
5532: (CHAR)( DriveMediaLimits[DisketteExtension->DriveType].
5533: LowestDriveMediaType ) ) {
5534:
5535: DisketteExtension->MediaType = Unknown;
5536: mediaTypesExhausted = TRUE;
5537:
5538: FloppyDump(
5539: FLOPINFO,
5540: ("Floppy: Unrecognized media.\n")
5541: );
5542:
5543: }
5544:
5545: }
5546:
5547: }
5548:
5549: } while ( ( !NT_SUCCESS( ntStatus ) ) && !( mediaTypesExhausted ) );
5550:
5551: if (NT_SUCCESS(ntStatus)) {
5552:
5553: //
5554: // We determined the media type. Time to move on.
5555: //
5556:
5557: break;
5558:
5559: }
5560:
5561: }
5562:
5563: if ( (!NT_SUCCESS( ntStatus )) || mediaTypesExhausted) {
5564:
5565: return ntStatus;
5566:
5567: }
5568:
5569: DisketteExtension->MediaType = driveMediaConstants->MediaType;
5570:
5571: DisketteExtension->BytesPerSector =
5572: driveMediaConstants->BytesPerSector;
5573:
5574: FloppyDump(
5575: FLOPINFO,
5576: ("Floppy: MediaType is %x\n", DisketteExtension->MediaType)
5577: );
5578:
5579: DisketteExtension->ByteCapacity =
5580: ( driveMediaConstants->BytesPerSector ) *
5581: driveMediaConstants->SectorsPerTrack *
5582: ( 1 + driveMediaConstants->MaximumTrack ) *
5583: driveMediaConstants->NumberOfHeads;
5584:
5585: //
5586: // Structure copy the media constants into the diskette extension.
5587: //
5588:
5589: DisketteExtension->DriveMediaConstants =
5590: DriveMediaConstants[DisketteExtension->DriveMediaType];
5591:
5592: return ntStatus;
5593: }
5594:
5595: VOID
5596: FloppyThread(
5597: PVOID Context
5598: )
5599:
5600: /*++
5601:
5602: Routine Description:
5603:
5604: This is the code executed by the system thread created when the
5605: floppy driver initializes. This thread loops forever (or until a
5606: flag is set telling the thread to kill itself) processing packets
5607: put into the queue by the dispatch routines.
5608:
5609: For each packet, this thread calls appropriate routines to process
5610: the request, and then calls FlFinishOperation() to complete the
5611: packet.
5612:
5613: Arguments:
5614:
5615: Context - a pointer to our data area for the controller being
5616: supported (there is one thread per controller).
5617:
5618: Return Value:
5619:
5620: None.
5621:
5622: --*/
5623:
5624: {
5625: PCONTROLLER_DATA controllerData = Context;
5626: PIRP irp;
5627: PIO_STACK_LOCATION irpSp;
5628: PLIST_ENTRY request;
5629: PDISKETTE_EXTENSION disketteExtension;
5630: KIRQL oldIrql;
5631: NTSTATUS ntStatus;
5632: NTSTATUS waitStatus;
5633: LARGE_INTEGER controllerWait;
5634:
5635: //
5636: // Set thread priority to lowest realtime level.
5637: //
5638:
5639: KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
5640:
5641: controllerWait = RtlLargeIntegerNegate(
5642: RtlConvertLongToLargeInteger(
5643: (LONG)(10 * 1000 * 3000)
5644: )
5645: );
5646:
5647: do {
5648:
5649: //
5650: // Wait for a request from the dispatch routines.
5651: // KeWaitForSingleObject won't return error here - this thread
5652: // isn't alertable and won't take APCs, and we're not passing in
5653: // a timeout.
5654: //
5655:
5656: KeWaitForSingleObject(
5657: (PVOID) &controllerData->RequestSemaphore,
5658: UserRequest,
5659: KernelMode,
5660: FALSE,
5661: (PLARGE_INTEGER) NULL );
5662:
5663: if ( controllerData->UnloadingDriver ) {
5664:
5665: FloppyDump(
5666: FLOPDBGP,
5667: ("Floppy: Thread asked to kill itself\n")
5668: );
5669:
5670: PsTerminateSystemThread( STATUS_SUCCESS );
5671: }
5672:
5673: waitStatus = STATUS_SUCCESS;
5674:
5675: waitStatus = KeWaitForSingleObject(
5676: controllerData->ControllerEvent,
5677: Executive,
5678: KernelMode,
5679: FALSE,
5680: &controllerWait);
5681:
5682:
5683: if (waitStatus == STATUS_TIMEOUT) {
5684:
5685: while ( !IsListEmpty( &( controllerData->ListEntry ) ) ) {
5686:
5687: //
5688: // Get the request from the queue. We know there is one,
5689: // because of the check above.
5690: //
5691:
5692: request = ExInterlockedRemoveHeadList(
5693: &controllerData->ListEntry,
5694: &controllerData->ListSpinLock );
5695:
5696: controllerData->HardwareFailed = FALSE;
5697:
5698: irp = CONTAINING_RECORD( request, IRP, Tail.Overlay.ListEntry );
5699:
5700: irp->IoStatus.Status = STATUS_DEVICE_BUSY;
5701:
5702: IoCompleteRequest( irp, IO_DISK_INCREMENT );
5703:
5704: } //while there's packets to process
5705:
5706: } else {
5707:
5708: controllerData->CurrentInterrupt = TRUE;
5709:
5710: while ( !IsListEmpty( &( controllerData->ListEntry ) ) ) {
5711:
5712: //
5713: // Get the request from the queue. We know there is one,
5714: // because of the check above.
5715: //
5716:
5717: request = ExInterlockedRemoveHeadList(
5718: &controllerData->ListEntry,
5719: &controllerData->ListSpinLock );
5720:
5721: controllerData->HardwareFailed = FALSE;
5722:
5723: irp = CONTAINING_RECORD( request, IRP, Tail.Overlay.ListEntry );
5724:
5725:
5726: irpSp = IoGetCurrentIrpStackLocation( irp );
5727:
5728: FloppyDump(
5729: FLOPIRPPATH,
5730: ("Floppy: Starting up IRP: %x for extension %x\n",
5731: irp,irpSp->Parameters.Read.Key)
5732: );
5733: switch ( irpSp->MajorFunction ) {
5734:
5735: case IRP_MJ_READ:
5736: case IRP_MJ_WRITE: {
5737:
5738: //
5739: // Get the diskette extension from where it was hidden
5740: // in the IRP.
5741: //
5742:
5743: disketteExtension = (PDISKETTE_EXTENSION)
5744: irpSp->Parameters.Read.Key;
5745:
5746: //
5747: // Until the file system clears the DO_VERIFY_VOLUME
5748: // flag, we should return all requests with error.
5749: //
5750:
5751: if (( disketteExtension->DeviceObject->Flags &
5752: DO_VERIFY_VOLUME ) &&
5753: !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME))
5754: {
5755:
5756: FloppyDump(
5757: FLOPINFO,
5758: ("Floppy: clearing queue; verify required\n")
5759: );
5760:
5761: //
5762: // The disk changed, and we set this bit. Fail
5763: // all current IRPs for this device; when all are
5764: // returned, the file system will clear
5765: // DO_VERIFY_VOLUME.
5766: //
5767:
5768: ntStatus = STATUS_VERIFY_REQUIRED;
5769:
5770: } else {
5771:
5772: //
5773: // Allocate an adapter channel for the I/O.
5774: //
5775:
5776: FloppyDump(
5777: FLOPIRPPATH,
5778: ("Floppy: About to allocate adapter channel %x\n",
5779: controllerData->AdapterObject)
5780: );
5781: KeResetEvent(
5782: &controllerData->AllocateAdapterChannelEvent );
5783:
5784: KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
5785:
5786: IoAllocateAdapterChannel(
5787: controllerData->AdapterObject,
5788: disketteExtension->DeviceObject,
5789: controllerData->NumberOfMapRegisters,
5790: FloppyAllocateAdapterChannel,
5791: controllerData );
5792:
5793: KeLowerIrql( oldIrql );
5794:
5795: //
5796: // Wait for the adapter to be allocated. No
5797: // timeout; we trust the system to do it
5798: // properly - so KeWaitForSingleObject can't
5799: // return an error.
5800: //
5801:
5802: KeWaitForSingleObject(
5803: &controllerData->AllocateAdapterChannelEvent,
5804: Executive,
5805: KernelMode,
5806: FALSE,
5807: (PLARGE_INTEGER) NULL );
5808:
5809: FloppyDump(
5810: FLOPIRPPATH,
5811: ("Floppy: Allocated adapter channel %x\n",
5812: controllerData->AdapterObject)
5813: );
5814: ntStatus = FlReadWrite( disketteExtension, irp );
5815:
5816: //
5817: // Free the adapter channel that we just used.
5818: //
5819:
5820: KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
5821:
5822: IoFreeAdapterChannel( controllerData->AdapterObject );
5823:
5824: KeLowerIrql( oldIrql );
5825: }
5826:
5827: break;
5828: }
5829:
5830: case IRP_MJ_DEVICE_CONTROL: {
5831:
5832: disketteExtension = (PDISKETTE_EXTENSION)
5833: irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
5834:
5835: //
5836: // Until the file system clears the DO_VERIFY_VOLUME
5837: // flag, we should return all requests with error.
5838: //
5839:
5840: if (( disketteExtension->DeviceObject->Flags &
5841: DO_VERIFY_VOLUME ) &&
5842: !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME))
5843: {
5844:
5845: FloppyDump(
5846: FLOPINFO,
5847: ("Floppy: clearing queue; verify required\n")
5848: );
5849:
5850: //
5851: // The disk changed, and we set this bit. Fail
5852: // all current IRPs; when all are returned, the
5853: // file system will clear DO_VERIFY_VOLUME.
5854: //
5855:
5856: ntStatus = STATUS_VERIFY_REQUIRED;
5857:
5858: } else {
5859:
5860: switch (
5861: irpSp->Parameters.DeviceIoControl.IoControlCode ) {
5862:
5863: case IOCTL_DISK_CHECK_VERIFY: {
5864:
5865: //
5866: // Just start the drive; it will
5867: // automatically check whether or not the
5868: // disk has been changed.
5869: //
5870:
5871: FloppyDump(
5872: FLOPSHOW,
5873: ("Floppy: IOCTL_DISK_CHECK_VERIFY called\n")
5874: );
5875:
5876: ntStatus = FlStartDrive(
5877: disketteExtension,
5878: FALSE,
5879: FALSE,
5880: FALSE);
5881:
5882: break;
5883: }
5884:
5885: case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
5886:
5887: FloppyDump(
5888: FLOPSHOW,
5889: ("Floppy: IOCTL_DISK_GET_DRIVE_GEOMETRY\n")
5890: );
5891:
5892: //
5893: // If there's enough room to write the
5894: // data, start the drive to make sure we
5895: // know what type of media is in the drive.
5896: //
5897:
5898: if ( irpSp->Parameters.DeviceIoControl.
5899: OutputBufferLength <
5900: sizeof( DISK_GEOMETRY ) ) {
5901:
5902: ntStatus = STATUS_INVALID_PARAMETER;
5903:
5904: } else {
5905:
5906: ntStatus = FlStartDrive(
5907: disketteExtension,
5908: FALSE,
5909: TRUE,
5910: (BOOLEAN)!!(irpSp->Flags &
5911: SL_OVERRIDE_VERIFY_VOLUME));
5912: }
5913:
5914: //
5915: // If the media wasn't formatted, FlStartDrive
5916: // returned STATUS_UNRECOGNIZED_MEDIA.
5917: //
5918:
5919: if ( NT_SUCCESS( ntStatus ) ||
5920: ( ntStatus == STATUS_UNRECOGNIZED_MEDIA ) ) {
5921:
5922: PDISK_GEOMETRY outputBuffer =
5923: (PDISK_GEOMETRY)
5924: irp->AssociatedIrp.SystemBuffer;
5925:
5926: //
5927: // Always return the media type, even if
5928: // it's unknown.
5929: //
5930:
5931: ntStatus = STATUS_SUCCESS;
5932:
5933: outputBuffer->MediaType =
5934: disketteExtension->MediaType;
5935:
5936: //
5937: // The rest of the fields only have meaning
5938: // if the media type is known.
5939: //
5940:
5941: if ( disketteExtension->MediaType ==
5942: Unknown ) {
5943:
5944: FloppyDump(
5945: FLOPSHOW,
5946: ("Floppy: geometry unknown\n")
5947: );
5948:
5949: //
5950: // Just zero out everything. The
5951: // caller shouldn't look at it.
5952: //
5953:
5954: outputBuffer->Cylinders.LowPart = 0;
5955: outputBuffer->Cylinders.HighPart = 0;
5956: outputBuffer->TracksPerCylinder = 0;
5957: outputBuffer->SectorsPerTrack = 0;
5958: outputBuffer->BytesPerSector = 0;
5959:
5960: } else {
5961:
5962: //
5963: // Return the geometry of the current
5964: // media.
5965: //
5966:
5967: FloppyDump(
5968: FLOPSHOW,
5969: ("Floppy: geomentry is known\n")
5970: );
5971: outputBuffer->Cylinders.LowPart =
5972: disketteExtension->DriveMediaConstants.MaximumTrack + 1;
5973:
5974: outputBuffer->Cylinders.HighPart = 0;
5975:
5976: outputBuffer->TracksPerCylinder =
5977: disketteExtension->DriveMediaConstants.NumberOfHeads;
5978:
5979: outputBuffer->SectorsPerTrack =
5980: disketteExtension->DriveMediaConstants.SectorsPerTrack;
5981:
5982: outputBuffer->BytesPerSector =
5983: disketteExtension->DriveMediaConstants.BytesPerSector;
5984: }
5985:
5986: FloppyDump(
5987: FLOPSHOW,
5988: ("Floppy: Geometry\n"
5989: "------- Cylinders low: 0x%x\n"
5990: "------- Cylinders high: 0x%x\n"
5991: "------- Track/Cyl: 0x%x\n"
5992: "------- Sectors/Track: 0x%x\n"
5993: "------- Bytes/Sector: 0x%x\n"
5994: "------- Media Type: %d\n",
5995: outputBuffer->Cylinders.LowPart,
5996: outputBuffer->Cylinders.HighPart,
5997: outputBuffer->TracksPerCylinder,
5998: outputBuffer->SectorsPerTrack,
5999: outputBuffer->BytesPerSector,
6000: outputBuffer->MediaType)
6001: );
6002:
6003: }
6004:
6005: irp->IoStatus.Information =
6006: sizeof( DISK_GEOMETRY );
6007:
6008: break;
6009: }
6010:
6011: case IOCTL_DISK_FORMAT_TRACKS: {
6012:
6013: FloppyDump(
6014: FLOPSHOW,
6015: ("Floppy: IOCTL_DISK_FORMAT_TRACKS\n")
6016: );
6017:
6018: //
6019: // Start the drive, and make sure it's not
6020: // write protected.
6021: //
6022:
6023: ntStatus = FlStartDrive(
6024: disketteExtension,
6025: TRUE,
6026: FALSE,
6027: FALSE );
6028:
6029: //
6030: // Note that FlStartDrive could have returned
6031: // STATUS_UNRECOGNIZED_MEDIA if the drive
6032: // wasn't formatted.
6033: //
6034:
6035: if ( NT_SUCCESS( ntStatus ) ||
6036: ( ntStatus == STATUS_UNRECOGNIZED_MEDIA ) ) {
6037:
6038: //
6039: // Allocate an adapter channel to do
6040: // the format.
6041: //
6042:
6043: KeResetEvent( &controllerData->
6044: AllocateAdapterChannelEvent );
6045:
6046: KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
6047:
6048: IoAllocateAdapterChannel(
6049: controllerData->AdapterObject,
6050: disketteExtension->DeviceObject,
6051: controllerData->NumberOfMapRegisters,
6052: FloppyAllocateAdapterChannel,
6053: controllerData );
6054:
6055: KeLowerIrql( oldIrql );
6056:
6057: //
6058: // Wait for the adapter to be allocated.
6059: // No timeout; we trust the system to do
6060: // it properly - so KeWaitForSingleObject
6061: // can't return an error.
6062: //
6063:
6064: KeWaitForSingleObject(
6065: &controllerData->
6066: AllocateAdapterChannelEvent,
6067: Executive,
6068: KernelMode,
6069: FALSE,
6070: (PLARGE_INTEGER) NULL );
6071:
6072: ntStatus = FlFormat(
6073: disketteExtension,
6074: irp );
6075:
6076: //
6077: // Free the adapter channel.
6078: //
6079:
6080: KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
6081:
6082: IoFreeAdapterChannel(
6083: controllerData->AdapterObject );
6084:
6085: KeLowerIrql( oldIrql );
6086: }
6087:
6088: break;
6089: } //end of case format
6090: } //end of switch controlcode
6091: }
6092:
6093: break;
6094: } //end of case IOCTL
6095:
6096: default: {
6097:
6098: FloppyDump(
6099: FLOPDBGP,
6100: ("Floppy: bad majorfunction %x\n",irpSp->MajorFunction)
6101: );
6102: }
6103:
6104: } //end of switch on majorfunction
6105:
6106: //
6107: // All operations leave a final status in ntStatus. Copy it
6108: // to the IRP, and then complete the operation.
6109: //
6110:
6111: irp->IoStatus.Status = ntStatus;
6112:
6113: FlFinishOperation( irp, disketteExtension );
6114:
6115: } //while there's packets to process
6116:
6117: controllerData->CurrentInterrupt = FALSE;
6118:
6119: (VOID) KeSetEvent(
6120: controllerData->ControllerEvent,
6121: (KPRIORITY) 0,
6122: FALSE);
6123:
6124: }
6125:
6126: } while ( TRUE );
6127: }
6128:
6129: IO_ALLOCATION_ACTION
6130: FloppyAllocateAdapterChannel(
6131: IN PDEVICE_OBJECT DeviceObject,
6132: IN PIRP Irp,
6133: IN PVOID MapRegisterBase,
6134: IN PVOID Context
6135: )
6136:
6137: /*++
6138:
6139: Routine Description:
6140:
6141: This DPC is called whenever the floppy thread is trying to allocate
6142: the adapter channel (like before doing a read or write). It saves
6143: the MapRegisterBase in the controller data area, and sets the
6144: AllocateAdapterChannelEvent to awaken the thread.
6145:
6146: Arguments:
6147:
6148: DeviceObject - unused.
6149:
6150: Irp - unused.
6151:
6152: MapRegisterBase - the base of the map registers that can be used
6153: for this transfer.
6154:
6155: Context - a pointer to our controller data area.
6156:
6157: Return Value:
6158:
6159: Returns Allocation Action 'KeepObject' which means that the adapter
6160: object will be held for now (to be released explicitly later).
6161:
6162: --*/
6163: {
6164: PCONTROLLER_DATA controllerData = Context;
6165:
6166: UNREFERENCED_PARAMETER( DeviceObject );
6167: UNREFERENCED_PARAMETER( Irp );
6168:
6169: controllerData->MapRegisterBase = MapRegisterBase;
6170:
6171: KeSetEvent(
6172: &controllerData->AllocateAdapterChannelEvent,
6173: 0L,
6174: FALSE );
6175:
6176: return KeepObject;
6177: }
6178:
6179: NTSTATUS
6180: FlReadWrite(
6181: IN OUT PDISKETTE_EXTENSION DisketteExtension,
6182: IN OUT PIRP Irp
6183: )
6184:
6185: /*++
6186:
6187: Routine Description:
6188:
6189: This routine is called by the floppy thread to read/write data
6190: to/from the diskette. It breaks the request into pieces called
6191: "transfers" (their size depends on the buffer size, where the end of
6192: the track is, etc) and retries each transfer until it succeeds or
6193: the retry count is exceeded.
6194:
6195: Arguments:
6196:
6197: DisketteExtension - a pointer to our data area for the drive to be
6198: accessed.
6199:
6200: Irp - a pointer to the IO Request Packet.
6201:
6202: Return Value:
6203:
6204: STATUS_SUCCESS if the packet was successfully read or written; the
6205: appropriate error is propogated otherwise.
6206:
6207: --*/
6208:
6209: {
6210: LARGE_INTEGER headSettleTime;
6211: PIO_STACK_LOCATION irpSp;
6212: PCONTROLLER_DATA controllerData;
6213: PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
6214: PUCHAR userBuffer;
6215: NTSTATUS ntStatus;
6216: NTSTATUS ntStatus2;
6217: ULONG startingSectorOfTransfer;
6218: ULONG totalBytesOfTransfer;
6219: ULONG bytesTransferredSoFar = 0;
6220: ULONG numberOfPagesInTransfer;
6221: UCHAR transferCylinder;
6222: UCHAR transferSector;
6223: UCHAR transferHead;
6224: UCHAR byteToSectorShift;
6225: UCHAR retryCount;
6226: UCHAR secondaryRetryCount;
6227: UCHAR mediaDescriptor;
6228: DRIVE_MEDIA_TYPE driveMediaType;
6229: MEDIA_TYPE mediaType;
6230: BOOLEAN writeOperation;
6231: BOOLEAN fatalError;
6232: BOOLEAN needToUseBuffer;
6233: BOOLEAN fifoDisabled = FALSE;
6234:
6235: FloppyDump(
6236: FLOPSHOW,
6237: ("Floppy: FloppyReadWrite...\n")
6238: );
6239:
6240: FloppyDump(
6241: FLOPIRPPATH,
6242: ("Floppy: Started read/write for irp %x extension %x\n",
6243: Irp,DisketteExtension)
6244: );
6245: //
6246: // Get some useful pointers.
6247: //
6248:
6249: controllerData = DisketteExtension->ControllerData;
6250: irpSp = IoGetCurrentIrpStackLocation( Irp );
6251:
6252: if ( irpSp->MajorFunction == IRP_MJ_WRITE ) {
6253:
6254: writeOperation = TRUE;
6255:
6256: } else {
6257:
6258: writeOperation = FALSE;
6259: }
6260:
6261: //
6262: // If the drive is not already running, wait for it to start up. If
6263: // we're writing, this will check to see if the diskette is protected.
6264: //
6265:
6266: FloppyDump(
6267: FLOPIRPPATH,
6268: ("Floppy: Waiting for drive to start for irp %x extension %x\n",
6269: Irp,DisketteExtension)
6270: );
6271: ntStatus = FlStartDrive( DisketteExtension,
6272: writeOperation,
6273: TRUE,
6274: (BOOLEAN)!!(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME));
6275: if ( !NT_SUCCESS( ntStatus ) ) {
6276:
6277: FloppyDump(
6278: FLOPIRPPATH,
6279: ("Floppy: Couldnt start drive for irp %x extension %x\n",
6280: Irp,DisketteExtension)
6281: );
6282: return ntStatus;
6283: }
6284:
6285: FloppyDump(
6286: FLOPIRPPATH,
6287: ("Floppy: Drive started for irp %x extension %x\n",
6288: Irp,DisketteExtension)
6289: );
6290:
6291: if ( DisketteExtension->MediaType == Unknown ) {
6292:
6293: FloppyDump(
6294: FLOPWARN,
6295: ("Floppy: read/write: media type not determined, failing\n")
6296: );
6297:
6298: FloppyDump(
6299: FLOPIRPPATH,
6300: ("Floppy: don't know media irp %x extension %x\n",
6301: Irp,DisketteExtension)
6302: );
6303: return STATUS_UNRECOGNIZED_MEDIA;
6304:
6305: }
6306:
6307: //
6308: // Must get this pointer AFTER FlStartDrive, since DriveMediaType may
6309: // have been newly determined there.
6310: //
6311:
6312: driveMediaConstants = &DisketteExtension->DriveMediaConstants;
6313:
6314: //
6315: // Initialize variables to be used in the loop that transfers
6316: // portions of the request.
6317: //
6318:
6319: byteToSectorShift = (UCHAR)( SECTORLENGTHCODE_TO_BYTESHIFT +
6320: driveMediaConstants->SectorLengthCode );
6321:
6322: fatalError = FALSE;
6323:
6324: userBuffer = (PUCHAR) MmGetSystemAddressForMdl( Irp->MdlAddress );
6325:
6326: FloppyDump(
6327: FLOPSHOW,
6328: ("Floppy: Length of I/O is : %x\n"
6329: "------ userBuffer is : %lx\n",
6330: irpSp->Parameters.Read.Length,
6331: userBuffer)
6332: );
6333:
6334: //
6335: // Transfer portions of the request until the request is done or failed
6336: //
6337:
6338: while ( ( bytesTransferredSoFar < irpSp->Parameters.Read.Length ) &&
6339: !( fatalError ) ) {
6340:
6341: //
6342: // Determine the initial sector to be read from the diskette.
6343: //
6344:
6345: startingSectorOfTransfer =
6346: ( ( irpSp->Parameters.Read.ByteOffset ).LowPart +
6347: bytesTransferredSoFar ) >> byteToSectorShift;
6348:
6349: transferCylinder = (UCHAR)( startingSectorOfTransfer /
6350: ( driveMediaConstants->SectorsPerTrack *
6351: driveMediaConstants->NumberOfHeads ) );
6352:
6353: transferSector = (UCHAR)( ( startingSectorOfTransfer %
6354: driveMediaConstants->SectorsPerTrack ) + 1 );
6355:
6356: transferHead = (UCHAR)( ( startingSectorOfTransfer /
6357: driveMediaConstants->SectorsPerTrack ) %
6358: driveMediaConstants->NumberOfHeads );
6359:
6360: totalBytesOfTransfer = irpSp->Parameters.Read.Length -
6361: bytesTransferredSoFar;
6362:
6363: FloppyDump(
6364: FLOPSHOW,
6365: ("Floppy: SectorsPerTrack = %x\n"
6366: "------ NumberOfHeads = %x\n"
6367: "------ startingSectorOfTransfer = %x\n"
6368: "------ transferCylinder = %x\n"
6369: "------ transferSector = %x\n"
6370: "------ transferHead = %x\n",
6371: driveMediaConstants->SectorsPerTrack,
6372: driveMediaConstants->NumberOfHeads,
6373: startingSectorOfTransfer,
6374: transferCylinder,
6375: transferSector,
6376: transferHead)
6377: );
6378:
6379: //
6380: // Make sure the transfer doesn't go past the end of the track
6381: //
6382:
6383: if ( ( totalBytesOfTransfer >> byteToSectorShift ) > (ULONG)
6384: ( driveMediaConstants->SectorsPerTrack - transferSector + 1 ) ) {
6385:
6386: totalBytesOfTransfer = ( driveMediaConstants->SectorsPerTrack -
6387: transferSector + 1 ) << byteToSectorShift;
6388: }
6389:
6390: //
6391: // If there aren't enough map registers to handle the whole
6392: // transfer, then make the transfer size equal to the size of the
6393: // contiguous buffer.
6394: //
6395:
6396: numberOfPagesInTransfer = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
6397: ( userBuffer + bytesTransferredSoFar ),
6398: totalBytesOfTransfer );
6399:
6400: if ( numberOfPagesInTransfer <=
6401: (ULONG) controllerData->NumberOfMapRegisters ) {
6402:
6403: needToUseBuffer = FALSE;
6404:
6405: } else {
6406:
6407: FloppyDump(
6408: FLOPSHOW,
6409: ("Floppy: Not enough map registers, using own buffer\n")
6410: );
6411:
6412: needToUseBuffer = TRUE;
6413:
6414: #ifdef KEEP_COUNTERS
6415: FloppyUsedBuffer++;
6416: #endif
6417: if ( totalBytesOfTransfer > controllerData->IoBufferSize ) {
6418:
6419: totalBytesOfTransfer = controllerData->IoBufferSize;
6420: }
6421: }
6422:
6423: FloppyDump(
6424: FLOPSHOW,
6425: ("Floppy: TransferLength = %lx\n", totalBytesOfTransfer)
6426: );
6427:
6428: //
6429: // If this is a write and we have to use the contiguous buffer
6430: // (because we don't have enough map registers) then copy the
6431: // data from the user's buffer to the contiguous buffer.
6432: //
6433:
6434: if ( ( needToUseBuffer ) &&
6435: ( writeOperation ) ) {
6436:
6437: FloppyDump(
6438: FLOPSHOW,
6439: ("Floppy: Writing from address %lx\n",
6440: userBuffer + bytesTransferredSoFar)
6441: );
6442:
6443: RtlMoveMemory(
6444: controllerData->IoBuffer,
6445: (PVOID)( userBuffer + bytesTransferredSoFar ),
6446: totalBytesOfTransfer );
6447: }
6448:
6449: retryCount = 0;
6450: secondaryRetryCount = 0;
6451:
6452: //
6453: // Try this transfer until it succeeds or is failed.
6454: //
6455:
6456: do {
6457:
6458: //
6459: // If the controller doesn't do an implicit seek, then do an
6460: // explicit one.
6461: //
6462: // Also do an explicit seek if this drive isn't set up to
6463: // seek properly on this media, as noted by CylinderShift.
6464: // (This happens for 360kb diskettes in 1.2Mb drives).
6465: //
6466:
6467: if ( ( !controllerData->ControllerConfigurable ) ||
6468: ( driveMediaConstants->CylinderShift != 0 ) ) {
6469:
6470: controllerData->FifoBuffer[0] = (UCHAR)
6471: ( ( transferHead << 2 ) | DisketteExtension->DeviceUnit );
6472: controllerData->FifoBuffer[1] = (UCHAR)( transferCylinder <<
6473: driveMediaConstants->CylinderShift );
6474:
6475: FloppyDump(
6476: FLOPSHOW,
6477: ("Floppy: Issuing SEEK to %x\n",
6478: controllerData->FifoBuffer[1])
6479: );
6480:
6481: #ifdef KEEP_COUNTERS
6482: FloppyUsedSeek++;
6483: #endif
6484:
6485: ntStatus = FlIssueCommand( COMMND_SEEK, DisketteExtension );
6486:
6487: if ( !NT_SUCCESS( ntStatus ) ) {
6488:
6489: FloppyDump(
6490: FLOPWARN,
6491: ("Floppy: SEEK returned %x\n", ntStatus)
6492: );
6493: }
6494:
6495: if ( NT_SUCCESS( ntStatus ) ) {
6496:
6497: FloppyDump(
6498: FLOPSHOW,
6499: ("Floppy: SEEK says we got to cylinder %x\n",
6500: controllerData->FifoBuffer[1])
6501: );
6502:
6503: if ( ( !( controllerData->FifoBuffer[0] &
6504: STREG0_SEEK_COMPLETE ) ||
6505: ( controllerData->FifoBuffer[1] != (UCHAR)
6506: ( transferCylinder <<
6507: driveMediaConstants->CylinderShift ) ) ) ) {
6508:
6509: FloppyDump(
6510: FLOPWARN,
6511: ("Floppy: Seek returned bad registers\n")
6512: );
6513:
6514: controllerData->HardwareFailed = TRUE;
6515:
6516: ntStatus = STATUS_FLOPPY_BAD_REGISTERS;
6517:
6518: } else {
6519:
6520: //
6521: // Must delay HeadSettleTime milliseconds before
6522: // doing anything after a SEEK.
6523: //
6524:
6525: headSettleTime.LowPart = - ( 10 * 1000 *
6526: driveMediaConstants->HeadSettleTime );
6527: headSettleTime.HighPart = -1;
6528:
6529: KeDelayExecutionThread(
6530: KernelMode,
6531: FALSE,
6532: &headSettleTime );
6533:
6534: //
6535: // SEEKs should always be followed by a READID.
6536: //
6537:
6538: controllerData->FifoBuffer[0] = (UCHAR)
6539: ( ( transferHead << 2 ) |
6540: DisketteExtension->DeviceUnit );
6541:
6542: ntStatus = FlIssueCommand(
6543: COMMND_READ_ID + COMMND_MFM,
6544: DisketteExtension );
6545:
6546: if ( !NT_SUCCESS( ntStatus ) ) {
6547:
6548: FloppyDump(
6549: FLOPWARN,
6550: ("Floppy: READID after seek returned %x\n",
6551: ntStatus)
6552: );
6553: }
6554:
6555: if ( NT_SUCCESS( ntStatus ) ) {
6556:
6557: FloppyDump(
6558: FLOPSHOW,
6559: ("Floppy: ReadID says we're on cylinder %x\n",
6560: controllerData->FifoBuffer[3])
6561: );
6562:
6563: if ( ( controllerData->FifoBuffer[0] != (UCHAR)
6564: ( ( transferHead << 2 ) |
6565: DisketteExtension->DeviceUnit ) ) ||
6566: ( controllerData->FifoBuffer[1] != 0 ) ||
6567: ( controllerData->FifoBuffer[2] != 0 ) ||
6568: ( controllerData->FifoBuffer[3] !=
6569: transferCylinder ) ) {
6570:
6571: FloppyDump(
6572: FLOPWARN,
6573: ("Floppy: READID returned bad registers\n"
6574: "------ StatusRegister0 = %x\n"
6575: "------ StatusRegister1 = %x\n"
6576: "------ StatusRegister2 = %x\n"
6577: "------ StatusRegister3 = %x\n"
6578: "------ actualCylinder = %x\n"
6579: "------ transferCylinder = %x\n",
6580: controllerData->FifoBuffer[0],
6581: controllerData->FifoBuffer[1],
6582: controllerData->FifoBuffer[2],
6583: controllerData->FifoBuffer[3],
6584: controllerData->FifoBuffer[3],
6585: transferCylinder)
6586: );
6587:
6588: controllerData->HardwareFailed = TRUE;
6589:
6590: ntStatus = FlInterpretError(
6591: controllerData->FifoBuffer[1],
6592: controllerData->FifoBuffer[2] );
6593:
6594: }
6595: }
6596: }
6597: }
6598: } else {
6599:
6600: #ifdef KEEP_COUNTERS
6601: FloppyNoSeek++;
6602: #endif
6603:
6604: }
6605:
6606: //
6607: // Start the operation on the DMA and floppy hardware.
6608: //
6609:
6610: if ( NT_SUCCESS( ntStatus ) ) {
6611:
6612: //
6613: // Map the transfer through the DMA hardware. How we do
6614: // it depends on whether we're using the user's buffer
6615: // or our own contiguous buffer.
6616: //
6617:
6618: if ( needToUseBuffer ) {
6619:
6620: KeFlushIoBuffers(
6621: controllerData->IoBufferMdl,
6622: !writeOperation,
6623: TRUE );
6624:
6625: //
6626: // We can ignore the logical address returned by
6627: // IoMapTransfer, since we're not using busmaster
6628: // stuff.
6629: //
6630:
6631: IoMapTransfer(
6632: controllerData->AdapterObject,
6633: controllerData->IoBufferMdl,
6634: controllerData->MapRegisterBase,
6635: controllerData->IoBuffer,
6636: &totalBytesOfTransfer,
6637: (BOOLEAN)writeOperation);
6638:
6639: } else {
6640:
6641: KeFlushIoBuffers( Irp->MdlAddress, !writeOperation, TRUE );
6642:
6643: IoMapTransfer(
6644: controllerData->AdapterObject,
6645: Irp->MdlAddress,
6646: controllerData->MapRegisterBase,
6647: (PVOID)( (ULONG) MmGetMdlVirtualAddress(Irp->MdlAddress)
6648: + bytesTransferredSoFar ),
6649: &totalBytesOfTransfer,
6650: (BOOLEAN)writeOperation);
6651: }
6652:
6653: //
6654: // Issue the READ or WRITE command
6655: //
6656:
6657: controllerData->FifoBuffer[0] = (UCHAR)
6658: ( ( transferHead << 2 ) | DisketteExtension->DeviceUnit );
6659: controllerData->FifoBuffer[1] = transferCylinder;
6660: controllerData->FifoBuffer[2] = transferHead;
6661: controllerData->FifoBuffer[3] = transferSector;
6662: controllerData->FifoBuffer[4] =
6663: driveMediaConstants->SectorLengthCode;
6664: controllerData->FifoBuffer[5] = (UCHAR)( transferSector - 1 +
6665: ( totalBytesOfTransfer >> byteToSectorShift ) );
6666: controllerData->FifoBuffer[6] =
6667: driveMediaConstants->ReadWriteGapLength;
6668: controllerData->FifoBuffer[7] = driveMediaConstants->DataLength;
6669:
6670: FloppyDump(
6671: FLOPSHOW,
6672: ("Floppy: R/W params:\n"
6673: "------ head+unit = %x\n"
6674: "------ cylinder = %x\n"
6675: "------ head = %x\n"
6676: "------ sector = %x\n"
6677: "------ seclen code = %x\n"
6678: "------ numsecs = %x\n"
6679: "------ rw gap len = %x\n"
6680: "------ datalen = %x\n",
6681: controllerData->FifoBuffer[0],
6682: controllerData->FifoBuffer[1],
6683: controllerData->FifoBuffer[2],
6684: controllerData->FifoBuffer[3],
6685: controllerData->FifoBuffer[4],
6686: controllerData->FifoBuffer[5],
6687: controllerData->FifoBuffer[6],
6688: controllerData->FifoBuffer[7])
6689: );
6690:
6691: if ( !writeOperation ) {
6692:
6693: ntStatus = FlIssueCommand(
6694: COMMND_READ_DATA + COMMND_MFM,
6695: DisketteExtension );
6696:
6697: } else {
6698:
6699: ntStatus = FlIssueCommand(
6700: COMMND_WRITE_DATA + COMMND_MFM,
6701: DisketteExtension );
6702: }
6703:
6704: if ( !NT_SUCCESS( ntStatus ) ) {
6705:
6706: FloppyDump(
6707: FLOPWARN,
6708: ("Floppy: read/write returned %x\n", ntStatus)
6709: );
6710: }
6711:
6712: }
6713:
6714: if ( NT_SUCCESS( ntStatus ) ) {
6715:
6716:
6717: if ( ( ( controllerData->FifoBuffer[0] & STREG0_END_MASK ) !=
6718: STREG0_END_NORMAL ) &&
6719: ( ( ( controllerData->FifoBuffer[0] & STREG0_END_MASK ) !=
6720: STREG0_END_ERROR ) ||
6721: ( controllerData->FifoBuffer[1] !=
6722: STREG1_END_OF_DISKETTE ) ||
6723: ( controllerData->FifoBuffer[2] != STREG2_SUCCESS ) ) ) {
6724:
6725: FloppyDump(
6726: FLOPWARN,
6727: ("Floppy: Status registers wrong after I/O\n")
6728: );
6729:
6730: controllerData->HardwareFailed = TRUE;
6731:
6732: ntStatus = FlInterpretError(
6733: controllerData->FifoBuffer[1],
6734: controllerData->FifoBuffer[2] );
6735:
6736: FloppyDump(
6737: FLOPWARN,
6738: ("Floppy: Register values are\n"
6739: "------ StatusRegister0 = %x\n"
6740: "------ StatusRegister1 = %x\n"
6741: "------ StatusRegister2 = %x\n"
6742: "------ actualCylinder = %x\n"
6743: "------ actualHead = %x\n"
6744: "------ actualSector = %x\n"
6745: "------ actualSectorLengthCode = %x\n",
6746: controllerData->FifoBuffer[0],
6747: controllerData->FifoBuffer[1],
6748: controllerData->FifoBuffer[2],
6749: controllerData->FifoBuffer[3],
6750: controllerData->FifoBuffer[4],
6751: controllerData->FifoBuffer[5],
6752: controllerData->FifoBuffer[6])
6753: );
6754: }
6755:
6756: }
6757:
6758: if ( !NT_SUCCESS( ntStatus ) ) {
6759:
6760: //
6761: // Operation failed. Recalibrate drive & try again.
6762: //
6763:
6764: FloppyDump(
6765: FLOPWARN,
6766: ("Floppy: operation failed. Recalibrating...\n")
6767: );
6768:
6769: ntStatus2 = FlRecalibrateDrive( DisketteExtension );
6770:
6771: if ( NT_SUCCESS( ntStatus2 ) ) {
6772:
6773: retryCount++;
6774:
6775: } else {
6776:
6777: //
6778: // Ugh, we can't even recalibrate the drive. Force
6779: // ourselves out of this nasty loop.
6780: //
6781:
6782: retryCount = RECALIBRATE_RETRY_COUNT;
6783:
6784: fatalError = TRUE;
6785:
6786: FloppyDump(
6787: FLOPWARN,
6788: ("Floppy: Operation AND recalibrate failed\n")
6789: );
6790: }
6791: }
6792:
6793: if ( retryCount == RECALIBRATE_RETRY_COUNT ) {
6794:
6795: //
6796: // The retry count is exhausted. If the FIFO has
6797: // overrun, reset the retry count and increment
6798: // the secondary retry count - FIFO overruns mean that
6799: // another device is hogging the DMA, so give the floppy
6800: // another chance to make good.
6801: //
6802:
6803: if ( controllerData->FifoBuffer[1] & STREG1_DATA_OVERRUN ) {
6804:
6805: if ( secondaryRetryCount < OVERRUN_RETRY_COUNT ) {
6806:
6807: secondaryRetryCount++;
6808:
6809: retryCount = 0;
6810:
6811: } else {
6812:
6813: //
6814: // It looks like another device is STILL hogging
6815: // the DMA. Before failing, try disabling the
6816: // FIFO, if it exists.
6817: //
6818:
6819: if ( controllerData->ControllerConfigurable ) {
6820:
6821: if ( fifoDisabled ) {
6822:
6823: //
6824: // We already disabled it, and still
6825: // failed. Exit with failure.
6826: //
6827:
6828: fatalError = TRUE;
6829:
6830: } else {
6831:
6832: FloppyDump(
6833: FLOPINFO,
6834: ("Floppy: disabling FIFO\n")
6835: );
6836:
6837: controllerData->FifoBuffer[0] = 0;
6838: controllerData->FifoBuffer[1] =
6839: COMMND_CONFIGURE_IMPLIED_SEEKS +
6840: COMMND_CONFIGURE_DISABLE_FIFO +
6841: COMMND_CONFIGURE_DISABLE_POLLING;
6842: controllerData->FifoBuffer[2] = 0;
6843:
6844: ntStatus = FlIssueCommand(
6845: COMMND_CONFIGURE,
6846: DisketteExtension );
6847:
6848: if ( NT_SUCCESS( ntStatus ) ) {
6849:
6850: fifoDisabled = TRUE;
6851: }
6852: }
6853:
6854: } else {
6855:
6856: //
6857: // No FIFO to disable. Just exit with error.
6858: //
6859:
6860: fatalError = TRUE;
6861: }
6862: }
6863:
6864: } else {
6865:
6866: //
6867: // Not an overrun error.
6868: //
6869:
6870: fatalError = TRUE;
6871: }
6872: }
6873:
6874: //
6875: // Flush the DMA adapter buffers.
6876: //
6877:
6878: if ( needToUseBuffer ) {
6879:
6880: IoFlushAdapterBuffers(
6881: controllerData->AdapterObject,
6882: controllerData->IoBufferMdl,
6883: controllerData->MapRegisterBase,
6884: controllerData->IoBuffer,
6885: totalBytesOfTransfer,
6886: (BOOLEAN)writeOperation);
6887:
6888: } else {
6889:
6890: IoFlushAdapterBuffers(
6891: controllerData->AdapterObject,
6892: Irp->MdlAddress,
6893: controllerData->MapRegisterBase,
6894: (PVOID)( (ULONG) MmGetMdlVirtualAddress( Irp->MdlAddress )
6895: + bytesTransferredSoFar ),
6896: totalBytesOfTransfer,
6897: (BOOLEAN)writeOperation);
6898: }
6899:
6900: } while ( ( !NT_SUCCESS( ntStatus ) ) &&
6901: ( retryCount < RECALIBRATE_RETRY_COUNT ) );
6902:
6903: if ( NT_SUCCESS( ntStatus ) ) {
6904:
6905: if ( ( !writeOperation ) && ( needToUseBuffer ) ) {
6906:
6907: //
6908: // copy data from contiguous buffer
6909: //
6910:
6911: FloppyDump(
6912: FLOPSHOW,
6913: ("Floppy: Reading to address %lx\n",
6914: userBuffer + bytesTransferredSoFar)
6915: );
6916:
6917: RtlMoveMemory(
6918: (PVOID)( userBuffer + bytesTransferredSoFar ),
6919: controllerData->IoBuffer,
6920: totalBytesOfTransfer );
6921: }
6922:
6923: //
6924: // If this was a read of the very first sector, check the
6925: // media descriptor byte to verify that we have the right
6926: // media type.
6927: //
6928:
6929: if ( ( startingSectorOfTransfer == 0 ) && ( !writeOperation ) ) {
6930:
6931: mediaDescriptor = *( userBuffer + MEDIA_DESCRIPTOR_OFFSET );
6932: FloppyDump(
6933: FLOPSHOW,
6934: ("Floppy: First sector read: media descriptor is: 0x%x\n",
6935: mediaDescriptor)
6936: );
6937:
6938: mediaType = 0;
6939:
6940: switch ( mediaDescriptor ) {
6941:
6942: case MEDIA_DESCRIPTOR_160K: {
6943:
6944: mediaType = F5_160_512;
6945: break;
6946: }
6947:
6948: case MEDIA_DESCRIPTOR_180K: {
6949:
6950: mediaType = F5_180_512;
6951: break;
6952: }
6953:
6954: case MEDIA_DESCRIPTOR_320K: {
6955:
6956: mediaType = F5_320_512;
6957: break;
6958: }
6959:
6960: case MEDIA_DESCRIPTOR_360K: {
6961:
6962: mediaType = F5_360_512;
6963: break;
6964: }
6965:
6966: case MEDIA_DESCRIPTOR_720K_OR_1220K: {
6967:
6968: if ( DisketteExtension->DriveType == DRIVE_TYPE_1200 ) {
6969:
6970: FloppyDump(
6971: FLOPSHOW,
6972: ("FLOPPY: 720K or 1220K ambiguity - going for "
6973: "1.2\n")
6974: );
6975: mediaType = F5_1Pt2_512;
6976:
6977: } else {
6978:
6979: FloppyDump(
6980: FLOPSHOW,
6981: ("FLOPPY: 720K or 1220K ambiguity - going for "
6982: "720\n")
6983: );
6984: mediaType = F3_720_512;
6985: }
6986:
6987: break;
6988: }
6989:
6990: case MEDIA_DESCRIPTOR_1440K_OR_2880K: {
6991:
6992: if (DisketteExtension->DriveType == DRIVE_TYPE_1440) {
6993:
6994: FloppyDump(
6995: FLOPSHOW,
6996: ("FLOPPY: 1440/2880KB ambiguity - going for "
6997: "1440KB\n")
6998: );
6999: mediaType = F3_1Pt44_512;
7000:
7001: } else {
7002:
7003: //
7004: // If the diskette media type is already 1.44
7005: // then leave it that way. The reasoning
7006: // here is that if it was a 2.88 then we
7007: // would have already figured that out.
7008: //
7009:
7010: if (DisketteExtension->MediaType !=
7011: F3_1Pt44_512) {
7012:
7013: FloppyDump(
7014: FLOPSHOW,
7015: ("FLOPPY: 1440/2880KB ambiguity - guess"
7016: " for 2880KB\n")
7017: );
7018: mediaType = F3_2Pt88_512;
7019:
7020: } else {
7021:
7022: FloppyDump(
7023: FLOPSHOW,
7024: ("FLOPPY: 1440/2880KB ambiguity - deduce"
7025: " 1440KB\n")
7026: );
7027:
7028: }
7029:
7030: }
7031:
7032: break;
7033: }
7034:
7035: default: {
7036:
7037: FloppyDump(
7038: FLOPDBGP,
7039: ("Floppy: unknown media descriptor %x\n",
7040: mediaDescriptor)
7041: );
7042: }
7043:
7044: }
7045: FloppyDump(
7046: FLOPSHOW,
7047: ("FLOPPY: After switch media type is: %x\n",mediaType)
7048: );
7049: if ( ( mediaType != 0 ) &&
7050: ( mediaType != DisketteExtension->MediaType ) ) {
7051:
7052: FloppyDump(
7053: FLOPSHOW,
7054: ("FLOPPY: media type doesn't agree with previous\n"
7055: "------ readid determination\n")
7056: );
7057:
7058:
7059: driveMediaType = DriveMediaLimits[
7060: DisketteExtension->DriveType].HighestDriveMediaType;
7061:
7062: while ( ( DriveMediaConstants[driveMediaType].MediaType !=
7063: mediaType ) &&
7064: ( driveMediaType > DriveMediaLimits[DisketteExtension->
7065: DriveType].LowestDriveMediaType ) ) {
7066:
7067: driveMediaType--;
7068: }
7069: // williamh - June 11 1993
7070: // make sure the data we read from the media are consistent
7071: // with the new media ID we are going to use.
7072: // if they do not match with the new media type,
7073: // we have a bogus media and should leave it unchanged.
7074: // Actually, the right thing to do here is to derive
7075: // a correct media type from what we read(sector 0).
7076: // I simply have no time for this.
7077:
7078: if (DriveMediaConstants[driveMediaType].MediaType ==
7079: mediaType &&
7080: *(userBuffer+MEDIA_DESCRIPTOR_SECTORS_PER_TRACK) ==
7081: DriveMediaConstants[driveMediaType].SectorsPerTrack &&
7082: *(userBuffer + MEDIA_DESCRIPTOR_NUM_OF_HEADS) ==
7083: DriveMediaConstants[driveMediaType].NumberOfHeads
7084: ){
7085:
7086: //
7087: // We only want to reset if the media types
7088: // actually match up. If they don't match
7089: // up, the maximum size is as good a guess.
7090: // as any.
7091: //
7092:
7093: FloppyDump(
7094: FLOPWARN,
7095: ("Floppy: New media type after lookup %x\n", mediaType)
7096: );
7097:
7098: DisketteExtension->MediaType = mediaType;
7099: DisketteExtension->DriveMediaType = driveMediaType;
7100:
7101: driveMediaConstants =
7102: &DriveMediaConstants[DisketteExtension->DriveMediaType];
7103:
7104: DisketteExtension->BytesPerSector =
7105: driveMediaConstants->BytesPerSector;
7106:
7107: DisketteExtension->ByteCapacity =
7108: ( driveMediaConstants->BytesPerSector ) *
7109: driveMediaConstants->SectorsPerTrack *
7110: ( 1 + driveMediaConstants->MaximumTrack ) *
7111: driveMediaConstants->NumberOfHeads;
7112:
7113: //
7114: // Since the I/O returned without failure, the gap,
7115: // density and wait times are correct. Only the
7116: // sectors, cylinders, and heads need to change.
7117: //
7118:
7119: if ((mediaDescriptor == MEDIA_DESCRIPTOR_720K_OR_1220K)
7120: ||
7121: (mediaDescriptor == MEDIA_DESCRIPTOR_1440K_OR_2880K)
7122: ) {
7123:
7124: //
7125: // The media indicator for 1.22 MB and 720KB are the
7126: // same, but it is possible to have a 1.44 floppy
7127: // formatted as a 1.22, so use the sectors per track
7128: // information from the floppy.
7129: //
7130:
7131: DisketteExtension->DriveMediaConstants
7132: .SectorsPerTrack =
7133: *( userBuffer + MEDIA_DESCRIPTOR_SECTORS_PER_TRACK );
7134:
7135: } else {
7136:
7137: DisketteExtension->DriveMediaConstants
7138: .SectorsPerTrack =
7139: driveMediaConstants->SectorsPerTrack;
7140:
7141: }
7142:
7143: DisketteExtension->DriveMediaConstants.NumberOfHeads =
7144: driveMediaConstants->NumberOfHeads;
7145: DisketteExtension->DriveMediaConstants.MaximumTrack =
7146: driveMediaConstants->MaximumTrack;
7147:
7148: } else {
7149:
7150: FloppyDump(
7151: FLOPDBGP,
7152: ("Floppy: Bogus media descriptor for size\n"
7153: "------ Guessing that max is ok\n")
7154: );
7155:
7156: }
7157: }
7158: }
7159:
7160: bytesTransferredSoFar += totalBytesOfTransfer;
7161: }
7162:
7163: } // while more transfers to be made for this request
7164:
7165: if ( fifoDisabled ) {
7166:
7167: //
7168: // We disabled the FIFO threshold. Restore it now.
7169: //
7170:
7171: controllerData->FifoBuffer[0] = 0;
7172: controllerData->FifoBuffer[1] = COMMND_CONFIGURE_IMPLIED_SEEKS +
7173: COMMND_CONFIGURE_FIFO_THRESHOLD + COMMND_CONFIGURE_DISABLE_POLLING;
7174: controllerData->FifoBuffer[2] = 0;
7175:
7176: ntStatus2 = FlIssueCommand( COMMND_CONFIGURE, DisketteExtension );
7177:
7178: if ( !NT_SUCCESS( ntStatus2 ) ) {
7179:
7180: FloppyDump(
7181: FLOPDBGP,
7182: ("Floppy: restoring FIFO after r/w gave %x\n", ntStatus2)
7183: );
7184: }
7185:
7186: }
7187:
7188: //
7189: // The bytesTransferred so far is correct even if there was an error.
7190: //
7191:
7192: Irp->IoStatus.Information = bytesTransferredSoFar;
7193:
7194: FloppyDump(
7195: FLOPIRPPATH,
7196: ("Floppy: done with read/write for irp %x extension %x\n",
7197: Irp,DisketteExtension)
7198: );
7199: return ntStatus;
7200: }
7201:
7202: NTSTATUS
7203: FlFormat(
7204: IN PDISKETTE_EXTENSION DisketteExtension,
7205: IN PIRP Irp
7206: )
7207:
7208: /*++
7209:
7210: Routine Description:
7211:
7212: This routine is called by the floppy thread to format some tracks on
7213: the diskette. This won't take TOO long because the FORMAT utility
7214: is written to only format a few tracks at a time so that it can keep
7215: a display of what percentage of the disk has been formatted.
7216:
7217: Arguments:
7218:
7219: DisketteExtension - pointer to our data area for the diskette to be
7220: formatted.
7221:
7222: Irp - pointer to the IO Request Packet.
7223:
7224: Return Value:
7225:
7226: STATUS_SUCCESS if the tracks were formatted; appropriate error
7227: propogated otherwise.
7228:
7229: --*/
7230:
7231: {
7232: LARGE_INTEGER headSettleTime;
7233: PCONTROLLER_DATA controllerData;
7234: PIO_STACK_LOCATION irpSp;
7235: PBAD_TRACK_NUMBER badTrackBuffer;
7236: PFORMAT_PARAMETERS formatParameters;
7237: PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
7238: NTSTATUS ntStatus;
7239: ULONG badTrackBufferLength;
7240: DRIVE_MEDIA_TYPE driveMediaType;
7241: UCHAR driveStatus;
7242: UCHAR numberOfBadTracks = 0;
7243: UCHAR currentTrack;
7244: UCHAR endTrack;
7245: UCHAR whichSector;
7246: UCHAR retryCount;
7247: BOOLEAN bufferOverflow = FALSE;
7248:
7249: FloppyDump(
7250: FLOPSHOW,
7251: ("Floppy: FlFormat...\n")
7252: );
7253:
7254: controllerData = DisketteExtension->ControllerData;
7255: formatParameters = (PFORMAT_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;
7256: FloppyDump(
7257: FLOPFORMAT,
7258: ("Floppy: Format Params - MediaType: %d\n"
7259: "------ Start Cyl: %x\n"
7260: "------ End Cyl: %x\n"
7261: "------ Start Hd: %d\n"
7262: "------ End Hd: %d\n",
7263: formatParameters->MediaType,
7264: formatParameters->StartCylinderNumber,
7265: formatParameters->EndCylinderNumber,
7266: formatParameters->StartHeadNumber,
7267: formatParameters->EndHeadNumber)
7268: );
7269:
7270: irpSp = IoGetCurrentIrpStackLocation( Irp );
7271: badTrackBufferLength =
7272: irpSp->Parameters.DeviceIoControl.OutputBufferLength;
7273:
7274: //
7275: // Figure out which entry in the DriveMediaConstants table to use.
7276: // We know we'll find one, or FlCheckFormatParameters() would have
7277: // rejected the request.
7278: //
7279:
7280: driveMediaType =
7281: DriveMediaLimits[DisketteExtension->DriveType].HighestDriveMediaType;
7282:
7283: while ( ( DriveMediaConstants[driveMediaType].MediaType !=
7284: formatParameters->MediaType ) &&
7285: ( driveMediaType > DriveMediaLimits[DisketteExtension->DriveType].
7286: LowestDriveMediaType ) ) {
7287:
7288: driveMediaType--;
7289: }
7290:
7291: driveMediaConstants = &DriveMediaConstants[driveMediaType];
7292:
7293: //
7294: // Set some values in the diskette extension to indicate what we
7295: // know about the media type.
7296: //
7297:
7298: DisketteExtension->MediaType = formatParameters->MediaType;
7299: DisketteExtension->DriveMediaType = driveMediaType;
7300: DisketteExtension->DriveMediaConstants = DriveMediaConstants[driveMediaType];
7301:
7302: driveMediaConstants =
7303: &DriveMediaConstants[DisketteExtension->DriveMediaType];
7304:
7305: DisketteExtension->BytesPerSector = driveMediaConstants->BytesPerSector;
7306:
7307: DisketteExtension->ByteCapacity =
7308: ( driveMediaConstants->BytesPerSector ) *
7309: driveMediaConstants->SectorsPerTrack *
7310: ( 1 + driveMediaConstants->MaximumTrack ) *
7311: driveMediaConstants->NumberOfHeads;
7312:
7313: currentTrack = (UCHAR)( ( formatParameters->StartCylinderNumber *
7314: driveMediaConstants->NumberOfHeads ) +
7315: formatParameters->StartHeadNumber );
7316:
7317: endTrack = (UCHAR)( ( formatParameters->EndCylinderNumber *
7318: driveMediaConstants->NumberOfHeads ) +
7319: formatParameters->EndHeadNumber );
7320:
7321: FloppyDump(
7322: FLOPFORMAT,
7323: ("Floppy: Format - Starting/ending tracks: %x/%x\n",
7324: currentTrack,
7325: endTrack)
7326: );
7327:
7328: //
7329: // Set the data rate (which depends on the drive/media
7330: // type).
7331: //
7332:
7333: if ( controllerData->LastDriveMediaType != driveMediaType ) {
7334:
7335: ntStatus = FlDatarateSpecifyConfigure( DisketteExtension );
7336:
7337: if ( !NT_SUCCESS( ntStatus ) ) {
7338:
7339: return ntStatus;
7340: }
7341: }
7342:
7343: //
7344: // Format each track.
7345: //
7346:
7347: do {
7348:
7349: //
7350: // Seek to proper cylinder
7351: //
7352:
7353: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit;
7354: controllerData->FifoBuffer[1] = (UCHAR)( ( currentTrack /
7355: driveMediaConstants->NumberOfHeads ) <<
7356: driveMediaConstants->CylinderShift );
7357:
7358: FloppyDump(
7359: FLOPFORMAT,
7360: ("Floppy: Format seek to cylinder: %x\n",
7361: controllerData->FifoBuffer[1])
7362: );
7363:
7364: ntStatus = FlIssueCommand( COMMND_SEEK, DisketteExtension );
7365:
7366: if ( NT_SUCCESS( ntStatus ) ) {
7367:
7368: if ( ( controllerData->FifoBuffer[0] & STREG0_SEEK_COMPLETE ) &&
7369: ( controllerData->FifoBuffer[1] == (UCHAR)( ( currentTrack /
7370: driveMediaConstants->NumberOfHeads ) <<
7371: driveMediaConstants->CylinderShift ) ) ) {
7372:
7373: //
7374: // Must delay HeadSettleTime milliseconds before
7375: // doing anything after a SEEK.
7376: //
7377:
7378: headSettleTime.LowPart = - ( 10 * 1000 *
7379: driveMediaConstants->HeadSettleTime );
7380: headSettleTime.HighPart = -1;
7381:
7382: KeDelayExecutionThread(
7383: KernelMode,
7384: FALSE,
7385: &headSettleTime );
7386:
7387: //
7388: // Read ID. Note that we don't bother checking the return
7389: // registers, because if this media wasn't formatted we'd
7390: // get an error.
7391: //
7392:
7393: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit;
7394:
7395: ntStatus = FlIssueCommand(
7396: COMMND_READ_ID + COMMND_MFM,
7397: DisketteExtension );
7398:
7399: } else {
7400:
7401: FloppyDump(
7402: FLOPWARN,
7403: ("Floppy: format's seek returned bad registers\n"
7404: "------ Statusreg0 = %x\n"
7405: "------ Statusreg1 = %x\n",
7406: controllerData->FifoBuffer[0],
7407: controllerData->FifoBuffer[1])
7408: );
7409:
7410: controllerData->HardwareFailed = TRUE;
7411:
7412: ntStatus = STATUS_FLOPPY_BAD_REGISTERS;
7413: }
7414: }
7415:
7416: if ( !NT_SUCCESS( ntStatus ) ) {
7417:
7418: FloppyDump(
7419: FLOPWARN,
7420: ("Floppy: format's seek/readid returned %x\n", ntStatus)
7421: );
7422:
7423: return ntStatus;
7424: }
7425:
7426: //
7427: // Fill the buffer with the format of this track.
7428: //
7429:
7430: for ( whichSector = 1;
7431: whichSector <=
7432: (UCHAR)( driveMediaConstants->SectorsPerTrack );
7433: whichSector++ ) {
7434:
7435: controllerData->IoBuffer[( whichSector - 1 ) * 4] =
7436: currentTrack / driveMediaConstants->NumberOfHeads;
7437: controllerData->IoBuffer[( whichSector - 1 ) * 4 + 1] =
7438: currentTrack % driveMediaConstants->NumberOfHeads;
7439: controllerData->IoBuffer[( whichSector - 1 ) * 4 + 2] =
7440: whichSector;
7441: controllerData->IoBuffer[( whichSector - 1 ) * 4 + 3] =
7442: driveMediaConstants->SectorLengthCode;
7443:
7444: FloppyDump(
7445: FLOPFORMAT,
7446: ("Floppy - Format table entry %x - %x/%x/%x/%x\n",
7447: whichSector-1,
7448: controllerData->IoBuffer[(whichSector -1)*4],
7449: controllerData->IoBuffer[(whichSector -1)*4 + 1],
7450: controllerData->IoBuffer[(whichSector -1)*4 + 2],
7451: controllerData->IoBuffer[(whichSector -1)*4 + 3])
7452: );
7453: }
7454:
7455: //
7456: // Retry until success or too many retries.
7457: //
7458:
7459: retryCount = 0;
7460:
7461: do {
7462:
7463: ULONG length;
7464:
7465: length = driveMediaConstants->BytesPerSector;
7466:
7467: //
7468: // Map the transfer from the buffer to the disk.
7469: //
7470:
7471: KeFlushIoBuffers( controllerData->IoBufferMdl, FALSE, TRUE );
7472:
7473: IoMapTransfer(
7474: controllerData->AdapterObject,
7475: controllerData->IoBufferMdl,
7476: controllerData->MapRegisterBase,
7477: controllerData->IoBuffer,
7478: &length,
7479: TRUE );
7480:
7481: //
7482: // Issue command to format track
7483: //
7484:
7485: controllerData->FifoBuffer[0] = (UCHAR)
7486: ( ( ( currentTrack % driveMediaConstants->NumberOfHeads ) << 2 )
7487: | DisketteExtension->DeviceUnit );
7488: controllerData->FifoBuffer[1] =
7489: driveMediaConstants->SectorLengthCode;
7490: controllerData->FifoBuffer[2] =
7491: driveMediaConstants->SectorsPerTrack;
7492: controllerData->FifoBuffer[3] =
7493: driveMediaConstants->FormatGapLength;
7494: controllerData->FifoBuffer[4] =
7495: driveMediaConstants->FormatFillCharacter;
7496:
7497: FloppyDump(
7498: FLOPFORMAT,
7499: ("Floppy: format command parameters\n"
7500: "------ Head/Unit: %x\n"
7501: "------ Bytes/Sector: %x\n"
7502: "------ Sectors/Cylinder: %x\n"
7503: "------ Gap 3: %x\n"
7504: "------ Filler Byte: %x\n",
7505: controllerData->FifoBuffer[0],
7506: controllerData->FifoBuffer[1],
7507: controllerData->FifoBuffer[2],
7508: controllerData->FifoBuffer[3],
7509: controllerData->FifoBuffer[4])
7510: );
7511: ntStatus = FlIssueCommand(
7512: COMMND_FORMAT_TRACK + COMMND_MFM,
7513: DisketteExtension );
7514:
7515: IoFlushAdapterBuffers(
7516: controllerData->AdapterObject,
7517: controllerData->IoBufferMdl,
7518: controllerData->MapRegisterBase,
7519: controllerData->IoBuffer,
7520: length,
7521: TRUE );
7522:
7523: if ( !NT_SUCCESS( ntStatus ) ) {
7524:
7525: FloppyDump(
7526: FLOPDBGP,
7527: ("Floppy: format returned %x\n", ntStatus)
7528: );
7529: }
7530:
7531: if ( NT_SUCCESS( ntStatus ) ) {
7532:
7533: //
7534: // Check the return bytes from the controller.
7535: //
7536:
7537: if ( ( controllerData->FifoBuffer[0] &
7538: ( STREG0_DRIVE_FAULT |
7539: STREG0_END_INVALID_COMMAND ) )
7540: || ( controllerData->FifoBuffer[1] &
7541: STREG1_DATA_OVERRUN ) ||
7542: ( controllerData->FifoBuffer[2] != 0 ) ) {
7543:
7544: FloppyDump(
7545: FLOPWARN,
7546: ("Floppy: format had bad registers\n"
7547: "------ Streg0 = %x\n"
7548: "------ Streg1 = %x\n"
7549: "------ Streg2 = %x\n",
7550: controllerData->FifoBuffer[0],
7551: controllerData->FifoBuffer[1],
7552: controllerData->FifoBuffer[2])
7553: );
7554:
7555: controllerData->HardwareFailed = TRUE;
7556:
7557: ntStatus = FlInterpretError(
7558: controllerData->FifoBuffer[1],
7559: controllerData->FifoBuffer[2] );
7560: }
7561: }
7562:
7563: } while ( ( !NT_SUCCESS( ntStatus ) ) &&
7564: ( retryCount++ < RECALIBRATE_RETRY_COUNT ) );
7565:
7566: if ( !NT_SUCCESS( ntStatus ) ) {
7567:
7568: driveStatus = READ_CONTROLLER(
7569: &controllerData->ControllerAddress->DRDC.DiskChange );
7570:
7571: if ( (DisketteExtension->DriveType != DRIVE_TYPE_0360) &&
7572: (driveStatus & DSKCHG_DISKETTE_REMOVED) ) {
7573:
7574: //
7575: // The user apparently popped the floppy. Return error
7576: // rather than logging bad track.
7577: //
7578:
7579: return ntStatus;
7580: }
7581:
7582: //
7583: // Log the bad track.
7584: //
7585:
7586: FloppyDump(
7587: FLOPDBGP,
7588: ("Floppy: track %x is bad\n", currentTrack)
7589: );
7590:
7591: if ( badTrackBufferLength >= (ULONG)
7592: ( ( numberOfBadTracks + 1 ) * sizeof( BAD_TRACK_NUMBER ) ) ) {
7593:
7594: badTrackBuffer = (PBAD_TRACK_NUMBER)
7595: Irp->AssociatedIrp.SystemBuffer;
7596:
7597: badTrackBuffer[numberOfBadTracks] = ( BAD_TRACK_NUMBER )
7598: currentTrack;
7599:
7600: } else {
7601:
7602: bufferOverflow = TRUE;
7603: }
7604:
7605: numberOfBadTracks++;
7606: }
7607:
7608: currentTrack++;
7609:
7610: } while ( currentTrack <= endTrack );
7611:
7612: if ( ( NT_SUCCESS( ntStatus ) ) && ( bufferOverflow ) ) {
7613:
7614: ntStatus = STATUS_BUFFER_OVERFLOW;
7615: }
7616:
7617: return ntStatus;
7618: }
7619:
7620: BOOLEAN
7621: FlCheckFormatParameters(
7622: IN PDISKETTE_EXTENSION DisketteExtension,
7623: IN PFORMAT_PARAMETERS FormatParameters
7624: )
7625:
7626: /*++
7627:
7628: Routine Description:
7629:
7630: This routine checks the supplied format parameters to make sure that
7631: they'll work on the drive to be formatted.
7632:
7633: Arguments:
7634:
7635: DisketteExtension - a pointer to our data area for the diskette to
7636: be formatted.
7637:
7638: FormatParameters - a pointer to the caller's parameters for the FORMAT.
7639:
7640: Return Value:
7641:
7642: TRUE if parameters are OK.
7643: FALSE if the parameters are bad.
7644:
7645: --*/
7646:
7647: {
7648: PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
7649: DRIVE_MEDIA_TYPE driveMediaType;
7650:
7651: //
7652: // Figure out which entry in the DriveMediaConstants table to use.
7653: //
7654:
7655: driveMediaType =
7656: DriveMediaLimits[DisketteExtension->DriveType].HighestDriveMediaType;
7657:
7658: while ( ( DriveMediaConstants[driveMediaType].MediaType !=
7659: FormatParameters->MediaType ) &&
7660: ( driveMediaType > DriveMediaLimits[DisketteExtension->DriveType].
7661: LowestDriveMediaType ) ) {
7662:
7663: driveMediaType--;
7664: }
7665:
7666: if ( DriveMediaConstants[driveMediaType].MediaType !=
7667: FormatParameters->MediaType ) {
7668:
7669: return FALSE;
7670:
7671: } else {
7672:
7673: driveMediaConstants = &DriveMediaConstants[driveMediaType];
7674:
7675: if ( ( FormatParameters->StartHeadNumber >
7676: (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) ||
7677: ( FormatParameters->EndHeadNumber >
7678: (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) ||
7679: ( FormatParameters->StartCylinderNumber >
7680: driveMediaConstants->MaximumTrack ) ||
7681: ( FormatParameters->EndCylinderNumber >
7682: driveMediaConstants->MaximumTrack ) ||
7683: ( FormatParameters->EndCylinderNumber <
7684: FormatParameters->StartCylinderNumber ) ) {
7685:
7686: return FALSE;
7687:
7688: } else {
7689:
7690: return TRUE;
7691: }
7692: }
7693: }
7694:
7695: VOID
7696: FloppyUnloadDriver(
7697: IN PDRIVER_OBJECT DriverObject
7698: )
7699:
7700: /*++
7701:
7702: Routine Description:
7703:
7704: This routine is called by the system to remove the driver from memory.
7705:
7706: When this routine is called, there is no I/O being done to this device.
7707: The driver object is passed in, and from this the driver can find and
7708: delete all of its device objects, extensions, etc.
7709:
7710: Arguments:
7711:
7712: DriverObject - a pointer to the object associated with this device
7713: driver.
7714:
7715: Return Value:
7716:
7717: None.
7718:
7719: --*/
7720:
7721: {
7722: UNREFERENCED_PARAMETER( DriverObject );
7723:
7724: // signal FloppyThread() to unload itself
7725: // disable interrupts from controller(s?)
7726: // delete everything that's been allocated
7727: }
7728:
7729: PCONTROLLER
7730: FlGetControllerBase(
7731: IN INTERFACE_TYPE BusType,
7732: IN ULONG BusNumber,
7733: PHYSICAL_ADDRESS IoAddress,
7734: ULONG NumberOfBytes,
7735: BOOLEAN InIoSpace,
7736: PBOOLEAN MappedAddress
7737: )
7738:
7739: /*++
7740:
7741: Routine Description:
7742:
7743: This routine maps an IO address to system address space.
7744:
7745: Arguments:
7746:
7747: BusType - what type of bus - eisa, mca, isa
7748: IoBusNumber - which IO bus (for machines with multiple buses).
7749: IoAddress - base device address to be mapped.
7750: NumberOfBytes - number of bytes for which address is valid.
7751: InIoSpace - indicates an IO address.
7752: MappedAddress - indicates whether the address was mapped.
7753: This only has meaning if the address returned
7754: is non-null.
7755:
7756: Return Value:
7757:
7758: Mapped address
7759:
7760: --*/
7761:
7762: {
7763: PHYSICAL_ADDRESS cardAddress;
7764: ULONG addressSpace = InIoSpace;
7765: PCONTROLLER Address;
7766:
7767: HalTranslateBusAddress(
7768: BusType,
7769: BusNumber,
7770: IoAddress,
7771: &addressSpace,
7772: &cardAddress
7773: );
7774:
7775: //
7776: // Map the device base address into the virtual address space
7777: // if the address is in memory space.
7778: //
7779:
7780: if (!addressSpace) {
7781:
7782: Address = MmMapIoSpace(
7783: cardAddress,
7784: NumberOfBytes,
7785: FALSE
7786: );
7787:
7788: *MappedAddress = !!Address;
7789:
7790:
7791: } else {
7792:
7793: Address = (PCONTROLLER)cardAddress.LowPart;
7794: *MappedAddress = FALSE;
7795:
7796: }
7797:
7798: return Address;
7799:
7800: }
7801:
7802: VOID
7803: FlLogErrorDpc(
7804: IN PKDPC Dpc,
7805: IN PVOID DeferredContext,
7806: IN PVOID SystemContext1,
7807: IN PVOID SystemContext2
7808: )
7809:
7810: /*++
7811:
7812: Routine Description:
7813:
7814: This routine is merely used to log an error that we had to reset the device.
7815:
7816: Arguments:
7817:
7818: Dpc - The dpc object.
7819:
7820: DeferredContext - A pointer to the controller data.
7821:
7822: SystemContext1 - Unused.
7823:
7824: SystemContext2 - Unused.
7825:
7826: Return Value:
7827:
7828: Mapped address
7829:
7830: --*/
7831:
7832: {
7833:
7834: PIO_ERROR_LOG_PACKET errorLogEntry;
7835: PCONTROLLER_DATA controllerData = DeferredContext;
7836:
7837: errorLogEntry = IoAllocateErrorLogEntry(
7838: controllerData->DriverObject,
7839: (UCHAR)(sizeof(IO_ERROR_LOG_PACKET))
7840: );
7841:
7842: if ( errorLogEntry != NULL) {
7843:
7844: errorLogEntry->ErrorCode = IO_ERR_RESET;
7845: errorLogEntry->SequenceNumber = 0;
7846: errorLogEntry->MajorFunctionCode = 0;
7847: errorLogEntry->RetryCount = 0;
7848: errorLogEntry->UniqueErrorValue = 0;
7849: errorLogEntry->FinalStatus = STATUS_SUCCESS;
7850: errorLogEntry->DumpDataSize = 0;
7851:
7852: IoWriteErrorLogEntry(errorLogEntry);
7853:
7854: }
7855:
7856: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.