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

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

unix.superglobalmegacorp.com

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