21

How do you request Windows to spin down a hard disk programmatically? Is there any user-mode function I can call (or kernel-mode function to call or IRP to send) in order to make this happen?

I've tried making a program to send an ATA STANDBY command directly to the hard disk, but the problem is that this method doesn't inform the system, and hence whenever the system needs to flush the cache, it'll wake up the hard disk again. How do I tell the system to do this for me? (If the system does it, it'll save up the cache and "burst" the data when it gets too large, instead of writing in small increments.)

(The entire point here is to do this directly, not by changing the system-wide spin-down timeout to a 1-second period and waiting for the disk to spin down. I need a function I can call at a specific moment in time when I'm using my laptop, not something generic that doesn't suit 95% of situations.)


How far I've gotten so far:

I have a feeling that PoCallDriver and IRP_MJ_POWER might be useful for this, but I have very limited kernel-mode programming experience (and pretty much zero driver experience) so I really have no idea.


Please read:

Update:

People seem to be repeatedly mentioning the solutions that I have already mentioned do not work. Like I said above, I've already tried "hacky" solutions that change the timeout value or that directly issue the drive a command, and the entire reason I've asked this question here is that those did not do what I needed. Please read the entire question (especially paragraphs 2 and 3) before repeating what I've already said inside your answers -- that's the entire difficulty in the question.


More info:

I've found this document about Disk Idle Detection to be useful, but my answer isn't in there. It states that the Power Manager sends an IRP to the disk driver (hence why I suspect IRP_MJ_POWER to be useful), but I have no idea how to use the information.

user541686
  • 205,094
  • 128
  • 528
  • 886
  • 3
    Now that's a hardcore question! – Fábio Batista Mar 20 '11 at 06:11
  • So you want to instruct the power management subsystem to put the HD to sleep, not directly instruct the HD to go to sleep? – Gabe Mar 20 '11 at 06:12
  • @Fábio: Thanks. :) @Gabe: Exactly. – user541686 Mar 20 '11 at 06:12
  • If you go to http://msdn.microsoft.com/en-us/library/aa373163 you'll see there's a `GetDevicePowerState` but no `SetDevicePowerState`, meaning either it's impossible or requires an undocumented API. – Gabe Mar 20 '11 at 06:40
  • @Gabe: How can it be impossible, if Windows itself spins down the hard disk when it's idle? And I doubt that the *kernel-mode* API would be undocumented -- it would definitely be needed by people who write disk drivers. (That page only lists the *user-mode* API.) – user541686 Mar 20 '11 at 06:44
  • 4
    Could you add a paragraph of explanation about why the normal approach (i.e., “let the OS manage this for you, in accordance with system and user policy”) is not suitable for your scenario? Thanks in advance! – Donal Fellows Mar 20 '11 at 07:21
  • @Donal: Because the torque that the hard disk puts on my laps is causing me to spin, injuring my spine. (Just kidding.) Seriously, it's because I want my computer to do what *I* want, simple as that. Whether the issue is saving battery life or preventing heat buildup or getting rid of the noise (it's all of them and more, by the way) shouldn't matter; the point isn't "*should* I do this?" but "*how* do I do this?". "User policy" and "system policy" only have a meaning if you're in a multiuser environment. When you have a personal laptop that no one else uses, those "policies" make no sense. – user541686 Mar 20 '11 at 07:26
  • If you don't care about "call-this-method-to-spin-down-hard-disk-now", you can achieve a similar effect by setting the spin down time. Look at docs for CallNtPowerInformation and SystemPowerPolicyAc – Zabba Mar 20 '11 at 07:38
  • @Zabba: Thanks, but just curious... did you happen to read my 3rd paragraph? – user541686 Mar 20 '11 at 07:42
  • @Mehrdad: Well, the way I control this sort of thing on my machines is via a power-management policy set in the OS (or is it in the motherboard drivers? I neither know nor care.) *irrespective of the number of users of said machine.* Policies are not just for sysadmins! – Donal Fellows Mar 20 '11 at 08:02
  • @Donal: Well, I guess the way *I* control this sort of thing on my own computer is different from yours. Your method works for you, but it doesn't work for me, because I desire absolute control over my laptop and you desire a "set it and forget it" approach. I'm not questioning your method, so I'd also rather we didn't argue about the validity of my question either, since neither is helpful to anyone. If you happen to have any *specific solutions*, I'd love to hear them. – user541686 Mar 20 '11 at 08:23
  • @Mehrdad: I'm not saying what you're doing is invalid. I was just curious as to why you're seeking this level of control, as there's very few use-cases that actually need it (i.e., I couldn't think of one offhand ;-)) – I know that it's likely to shorten the lifespan of the disk due to increased wear and tear because of the additional spin-down and spin-up cycles. Since I didn't know the answer to why you wanted it, I asked. :-D – Donal Fellows Mar 20 '11 at 10:33
  • @Donal: I wrote the answer a few comments ago: saving battery life, preventing heat buildup, and getting rid of the noise. It's not something I would use often (precisely because of the wear issue), but in certain situations it's very helpful, like when I'm studying something in a very quiet room... I could definitely use less noise and save some battery life. It might turn out to be less helpful than I thought, but I still want to give it a try; I'd rather have more control than less. – user541686 Mar 20 '11 at 10:39
  • So you want to continue _using_ the laptop and want the hard-drive to be not spinning? Good luck with that. –  Apr 05 '11 at 01:22
  • @Mehr: What makes you think it is Windows which is doing that? (Of course, I have no clue). –  Apr 05 '11 at 01:27
  • @Moron: Because Windows is the one detecting whether the system is idle? And like, why does it even make a difference? The point is that the hard disk has spinned down, irrespective of who actually did it. – user541686 Apr 05 '11 at 01:27
  • @Moron: Take a look at the link I just posted, and search for `hard disk burst ignore time` in it. This feature is completely dependent on Windows. – user541686 Apr 05 '11 at 01:31
  • @Mehrdad: It could be a _driver_ which is doing that. So if you are looking for a user mode API, or even a kernel API, you might find it difficult to find one. In any case, this might help: http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Disk_Idle_Detection.doc. And really, good luck with that. (THe powerdown paragraph notification on page 4 might help) –  Apr 05 '11 at 01:31
  • @Moron: It's funny how you just posted what I posted about ~30 seconds ago (see my previous comment). :) Also, the exact section you referred to says: *If no disk activity has occurred for at least the current disk idle time out, the **power manager** sends a power-down notification to the disk software driver stack indicating that the disk should spin down. The notification takes the form of a device power I/O request packet (IRP) for the D3 device power state.* The *power manager* is a part of the kernel, not driver-specific. – user541686 Apr 05 '11 at 01:34
  • @Moron: Supporting it is one thing, but issuing the command is driver-agnostic, since the kernel doesn't really care what particular driver is running. – user541686 Apr 05 '11 at 01:43
  • @Mehr: I had linked to a CE page, which seemed to have a protocol around it, so I deleted the previous comment. What I meant was, even though you call a kernel mode API, the driver might disagree and keep the disk spinning :-). And there is potential of the disk restarting on a context switch to your pdf reader etc (which is what I was getting at by my first comment). –  Apr 05 '11 at 01:44
  • @Moron: Ah... well, there's nothing I can do about that situation, but I'd still like to know the answer for the 90% of other cases when the driver *does* cooperate. – user541686 Apr 05 '11 at 01:46
  • 2
    I believe the easiest way to meet your stated goals: disk not spinning, saving battery life, preventing heat buildup, and getting rid of the noise would be to install a Solid State Disk. You even get a significant performance boost. – Ben Voigt Apr 05 '11 at 02:23
  • 1
    @Ben: I suppose a cheaper way would be to read from a book and hibernate the laptop :-) –  Apr 05 '11 at 02:26
  • @Ben: I'd be happy to do that if you could buy me a 256 GB SSD! :D @Moron: Lol, yeah, but then I'd have to go get it printed... and that's not really fun if it's something like the Intel Software Developer’s Manual, which is almost 4000 pages long, haha... – user541686 Apr 05 '11 at 03:58
  • @Mehr: 4000 pages? I hope you don't spend all your reading time trying to spin the disk down :-) –  Apr 05 '11 at 16:13
  • Probably doesn't help much, but [this freeware utility](http://hddscan.com/) claims to be able to spin down a HDD on demand. – StackExchange saddens dancek Apr 07 '11 at 13:36
  • @dancek: Interesting... it seems that this utility is also causing the spindown by sending a direct command, which doesn't play well with the power manager (it gets spinned up immediately after). Thanks nevertheless. – user541686 Apr 07 '11 at 17:45
  • What's up with all the votes downs on the answers to this question? - I haven't seen so many vote downs since the time I insulted C++ :-) – Danny Varod Apr 07 '11 at 23:38
  • @Danny: Lol. It's because people either (1) suggest something completely ridiculous (like powering down my boot disk) or (2) repeat what I already mentioned does **not** work in the question (meaning not only had they not even read the question, but they also hadn't learned from the other downvotes). :\ – user541686 Apr 07 '11 at 23:51

5 Answers5

5

I hope this helps:

This: http://msdn.microsoft.com/en-us/library/aa394173%28VS.85%29.aspx

Leads to this: http://msdn.microsoft.com/en-us/library/aa394132%28VS.85%29.aspx#properties

Then, you can browse to this: http://msdn.microsoft.com/en-us/library/aa393485(v=VS.85).aspx

This documentation seems to outline what you are looking for I think.

P.S. Just trying to help, don't shoot the messanger.

Dima
  • 655
  • 2
  • 8
  • 20
  • @Dima: Haha I liked your P.S. :) I don't downvote if it turns out unhelpful, I only do it if the answer is completely *wrong* (like "Power down your boot disk!") or if it repeats something I already mentioned doesn't work in the question (like "Set the timeout value"). Yours doesn't seem to be either, so you're safe. ;) (And btw, this is looking kinda helpful actually... let's see if it works.) – user541686 Apr 10 '11 at 06:11
  • 1
    :) good, *sigh of relief* - let me know if it does (kinda curious myself) - although the fact that MS didn't choose to implement the methods should tell us something about the problem. – Dima Apr 10 '11 at 06:15
  • @Dima: Haha glad you're relieved. :-) So I tried typing `CIM_Controller` into WMIC, and it just said `alias not found`... do you happen to know how to use it in WMIC and/or VBScript? – user541686 Apr 10 '11 at 06:20
  • @Dima: I can't figure out how to get it to work (I never figured out how to get WMI queries to work, actually)... any ideas? (I'm guessing I'll just run into a Not Implemented error anyway but it's worth a shot.) – user541686 Apr 10 '11 at 06:26
  • Check this out for an idea: http://include.wutils.com/wmi/ROOT%5Ccimv2/CIM_ManagedSystemElement/CIM_LogicalElement/CIM_LogicalDevice/CIM_Controller/CIM_USBController.html -- I have not spent much time working on this stuff - closest was working with printer drivers through wmi and directly with the printers themselves through some common framework (can't remember name, been too long). – Dima Apr 10 '11 at 06:31
  • @Dima: Ah, thanks for the link, at least I got access to the disk object this time. :) I tried [this](http://pastebin.com/HuEFhtZ6) but it says Type Mismatch; I'm guessing the `datetime` data type isn't getting passed correctly. Any thoughts? – user541686 Apr 10 '11 at 06:41
  • @Dima: Not sure what you mean by an interval value (not too familiar with VBS)... do you mean using `DateDiff`? I tried that but it didn't work. (It says "*when*" in the docs, so I assume it's not a time interval but a moment in time.) – user541686 Apr 10 '11 at 06:53
  • I was reading this: "Specifies when the power state should be set, either as a regular date-time value or **as an interval value (where the interval begins when the method invocation is received)**. " - I would assume an integer in sec? millisec? – Dima Apr 10 '11 at 06:55
  • @Dima: Tried that but I get type mismatch. :( – user541686 Apr 10 '11 at 06:58
  • The echo give you the correct datetime format? If so, I assume because it is not implemented as plain vanilla you are getting the error.. probably the hard drive driver implemented it - what drive do you have? – Dima Apr 10 '11 at 07:26
  • Wanted to edit previous comment to add: And, yes, lol, I know we do not want to issue the drive a direct command (just exploring options). – Dima Apr 10 '11 at 07:32
  • @Dima: Actually, now that you mention it, no -- the format wasn't correct; I got `00000101000000.000000+000`. I have a Seagate hard drive; however, it doesn't look like a deep issue, just a parameter type mismatch. It just keeps on telling me `Type mismatch`, so I don't think it's reaching the disk at all. – user541686 Apr 10 '11 at 07:34
  • @Dima: Lol. Actually, sending the **driver** a direct power state change command isn't quite so bad as sending the **drive** a direct command (which would use a pass-through request to bypass the driver). It's a step toward the goal, so it might not be such a bad idea if there's nothing else we can do. – user541686 Apr 10 '11 at 07:36
  • @Dima: Ahh... good idea. I tried it, and it worked! So now I got the error I expected: `This method is not implemented in any class`. So yeah, this doesn't work. Thanks though! – user541686 Apr 10 '11 at 07:48
  • Lol, I'll let you know if I find anything else in regards to Seagate implementation :) – Dima Apr 10 '11 at 07:50
  • @Dima: Lol, okay thanks. :) (I don't expect this to be disk-dependent, though... it's not like the power management subsystem cares about the disk type.) – user541686 Apr 10 '11 at 07:58
  • Actually, can you try to see if PowerManagementCapabilities property of CIM_DiskDrive returns anything useful? Details here: http://www.scriptinternals.de/new/us/Support/Internal/WMI_CIM_DiskDrive.htm – Dima Apr 10 '11 at 07:59
  • ... sigh, thats not promising – Dima Apr 10 '11 at 08:03
  • @Dima: lol, yeah... I'd tried to find the answer very hard before I finally gave up and posted on SO. :) – user541686 Apr 10 '11 at 08:04
  • Thanks for the bounty; sorry it didn't exactly work out ... and seeing how no one else knows either, it may not be possible without actually implementing this method :( – Dima Apr 12 '11 at 01:02
  • @Dima: Well I definitely don't think it's impossible, because if Windows manages to do it then it's possible. :-) I'll try to figure out if I can use some kernel mode trick to do it. – user541686 Apr 12 '11 at 01:13
  • If you do figure it out, please let us all know :) – Dima Apr 12 '11 at 02:26
2

Have you tried WMI? Based on MSDN documentation, you should be able to send spindown command to HDD via WMI:

http://msdn.microsoft.com/en-us/library/aa393493%28v=VS.85%29.aspx

uint32 SetPowerState(
  [in]  uint16 PowerState,
  [in]  datetime Time
);

EDIT:

This code lists all drives in system and drives that support this API:

strServer = "."

Set objWMI = GetObject("winmgmts://" & strServer & "/root\cimv2")
rem Set objInstances = objWMI.InstancesOf("CIM_DiskDrive",48)
Set objInstances = objWMI.ExecQuery("Select * from CIM_DiskDrive",,48) 
On Error Resume Next
For Each objInstance in objInstances
    With objInstance
        WScript.Echo Join(.Capabilities, ", ")
        WScript.Echo Join(.CapabilityDescriptions, ", ")
        WScript.Echo .Caption
        WScript.Echo .PNPDeviceID
        WScript.Echo "PowerManagementCapabilities: "  & .PowerManagementCapabilities
        WScript.Echo "PowerManagement Supported: " & .PowerManagementSupported
        WScript.Echo .Status
        WScript.Echo .StatusInfo
    End With
On Error Goto 0
Next

Just save this code as a .vbs file and run that from command line.

Shamit Verma
  • 3,839
  • 23
  • 22
1

I do not have an answer to the specific question that Mehrdad asked.

However, to help others who find this page when trying to figure out how to get their disk to standby when it should but doesn't:

  1. I found that on a USB disk, MS PwrTest claims that the disk is off, but actually it is still spinning. This occurs even with really short global disk timeouts in win 7. (This implies that even if the system thinks it has turned the disk off, it might not actually be off. Consequently, Mehrdad's original goal might not work even if the correct way to do it is found. This may relate to how various USB disk controllers implement power state.)

  2. I also found that the program HDDScan successfully can turn off the disk, and can successfully set a timeout value that the disk honors. Also, the disk spins up when it is accessed by the OS, a good thing if you need to use it, but not so good if you are worrying about it spinning up all the time to flush 1kB buffers. (I chose to set the idle timeout in HDDScan to 1 minute more than the system power manager timeout. This hopefully assures that the system will not think the disk is spun up when it is not.)

I note that powercfg has an option to prevent the idle clock from restarting from small infrequent disk writes. (Called "burst ignore time.")

You can get HDDScan here: HDDScan.com and PwrTest here: Windows Driver Kit. Unfortunately, the PwrTest thing forces you to have a lot of other MS stuff installed first, but it is all free if you can figure out how to download it from their confusing web pages.

0

While there is no apparent way to do what you're asking for (i.e. tell power management "act as if the timer for spinning down the disk has expired"), there may be a couple ways to simulate it:

  1. Call FlushFileBuffers on the drive (you need to be elevated to open \\.\C), then issue the STANDBY command to the drive.

  2. Make the API call that sets the timeout for spinning down the disk to 1 second, then increase it back to its former value after 1 second. Note that you may need to ramp up to the former value rather than immediately jump to it.

Gabe
  • 84,912
  • 12
  • 139
  • 238
  • Didn't you *yourself* ask, `So you want to instruct the power management subsystem to put the HD to sleep, not directly instruct the HD to go to sleep?`? I thought you'd understood the question very well... why did you just post what I'd already mentioned *doesn't work* in my question? – user541686 Mar 20 '11 at 18:45
-1

I believe the Devcon Command line utility should be able to accomplish what you need to do. If it does - the source code is available in the Windows Ddk.

quixver
  • 564
  • 1
  • 4
  • 11
  • That's interesting! Would you mind elaborating on which switch(es) I should use? – user541686 Apr 06 '11 at 00:12
  • Running devcon with the status switch lists the devices available. eg devcon status *. You can then disable the device you want with remove. For eg on my machine - devcon status * lists "IDE\DISKST31000528AS____________________________CC38____\5&5C6CFD6&0&1.1.0". I can eject this by doing "devcon remove IDE\DISKST3100*". – quixver Apr 06 '11 at 02:22
  • err - sorry about the formatting - cant quite figure out how to clean this up. please note that there must be a '*' at the end of the partial device name (wild card) or of course - you can provide the entire device name. – quixver Apr 06 '11 at 02:26
  • Uh... so you're suggesting I disable my boot disk? – user541686 Apr 06 '11 at 02:32
  • Disabling your boot disk may not be a very smart idea, you might want to try it out on a secondary drive. – quixver Apr 06 '11 at 02:49
  • @quixver: Huh???!!! The entire point of this question was to spin down the *only* drive in my laptop... – user541686 Apr 06 '11 at 03:02