Annotation of ntddk/src/scsi/floppy/floppy.c, revision 1.1.1.1

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:             &paramTable[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:                             &paramTable[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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.