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