Annotation of ntddk/src/scsi/atdisk/atdisk.c, revision 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.