Re: VIA SATA Raid needs a long time to recover from suspend

From: Andrew Morton (akpm_at_osdl.org)
Date: 11/17/05

  • Next message: Bernd Eckenfels: "Re: virtual NICs"
    Date:	Wed, 16 Nov 2005 17:06:42 -0800
    To: Phillip Susi <psusi@cfl.rr.com>
    
    

    Phillip Susi <psusi@cfl.rr.com> wrote:
    >
    > I have been debugging a power management problem for a few days now, and
    > I believe I have finally solved the problem. Because it involved
    > patching the kernel, I felt I should share the fix here in hopes that it
    > can be improved and/or integrated into future kernels. Right now I am
    > running 2.6.14.2 on amd64, compiled myself, with the ubuntu breezy amd64
    > distribution.
    >
    > First I'll state the fix. It involved changing two lines in
    > include/linux/libata.h:
    >
    > static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,
    > unsigned int max)
    > {
    > u8 status;
    >
    > do {
    > udelay(100); <-- changed to 100
    > from 10
    > status = ata_chk_status(ap);
    > max--;
    > } while ((status & bits) && (max > 0));
    >
    > return status;
    > }
    >
    > and:
    >
    > static inline u8 ata_wait_idle(struct ata_port *ap)
    > {
    > u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ,
    > 10000); <-- changed to 10,000 from 1,000
    >
    > if (status & (ATA_BUSY | ATA_DRQ)) {
    > unsigned long l = ap->ioaddr.status_addr;
    > printk(KERN_WARNING
    > "ATA: abnormal status 0x%X on port 0x%lX\n",
    > status, l);
    > }
    >
    > return status;
    > }

    This change will increase the minimum delay in both ata_wait_idle() and
    ata_busy_wait() from 10 usec to 100 usec, which is not a good change.

    It would be less damaging to increase the delay in ata_wait_idle() from
    1000 to 100,000. A one second spin is a bit sad, but the hardware's bust,
    so that's the least of the user's worries.

    The best fix would be to identify the specific _callers_ of these functions
    which need their delay increased. You can do that by adding:

            if (max == 0)
                    dump_stack();

    at the end of ata_busy_wait(). The resulting stack dumps will tell you
    where the offending callsites are. With luck, it's just one. If we know
    which one, that might point us at some chipset-level delay which we're
    forgetting to do, or something like that.

    > The problem seems to be that my VIA SATA raid controller requires more
    > time to recover from being suspended. It looks like the code in
    > sata_via.c restores the task file after a resume, then calls
    > ata_wait_idle to wait for the busy bit to clear. The problem was that
    > this function timed out before the busy bit cleared, resulting in
    > messages like this:
    >
    > ATA: abnormal status 0x80 on port 0xE007
    >
    > Then if there was an IO request made immediately after resuming, it
    > would timeout and fail, because it was issued before the hardware was
    > ready. Changing the timeout resolved this. I tried changing both the
    > udelay and ata_busy_wait lines to increase the timeout, and it did not
    > seem to matter which I changed, as long as the total timeout was
    > increased by a factor of 100.
    >
    > Since increasing the maximum timeout, suspend and hibernate work great
    > for me. While experiencing this bug, it may have exposed another bug,
    > which I will mention now in passing. As I said before, after a resume,
    > if there was an IO request made immediately ( before the busy bit
    > finally did clear ) it would timeout and fail. It seemed the kernel
    > filled the buffer cache for the requested block with garbage rather than
    > retry the read. It seems to me that at some point, the read should have
    > been retried.

    Or should have returned an IO error.

    Yes, this might be a driver bug. Again, if we know precisely which
    callsite is experiencing the timeout then we're better situated to fix it.

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/


  • Next message: Bernd Eckenfels: "Re: virtual NICs"

    Relevant Pages

    • Re: How to ping in Python?
      ... > # Changed the struct.packcalls to pack the checksum and ID as ... > def receiveOnePing(mySocket, ID, timeout): ... > # Returns either the delay or none on timeout. ...
      (comp.lang.python)
    • Re: setTimeout only delays first time in loop
      ... I incremented the delay for each iteration and it worked. ... put it in a loop and set 20 timeouts - think about it: ... The way I figured, my original timeout said "delay 700ms, ... then execute the named function," then after funtest is ...
      (comp.lang.javascript)
    • Re: select & gettimeofday
      ... >> There is no bug, and in fact you cannot tell, in a user process, ... timeout is the approximate amount ... The measured delay was 1.00 milliseconds ...
      (comp.os.linux.development.system)
    • Re: System.IO.StringReader ReadToEnd()
      ... Here is my original code, below it is what I did to fix my problem. ... would be a tremendous help solve all timeout problems. ... I can control the timeout on the ProxyServer here and that's ...
      (microsoft.public.dotnet.framework)
    • Re: sleeping
      ... The simple one is that a positive timeout value means time since ... > I am trying to delay the actual program execution. ... > is in kernel space. ...
      (microsoft.public.development.device.drivers)