diff options
author | Tejun Heo <htejun@gmail.com> | 2007-02-02 02:50:52 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-05-01 07:49:54 -0400 |
commit | 9b89391cc861b8a1105551909eb66c024fe18ab2 (patch) | |
tree | f0783823927ea013c8d58c1041ad1e1d884eed9e /drivers/ata/libata-core.c | |
parent | d4b2bab4f26345ea1803feb23ea92fbe3f6b77bc (diff) |
libata: improve 0xff status handling
For PATA, 0xff status indicates empty port. For SATA, it depends on
how the controller emulates status register. On some controllers,
0xff is used to represent broken link or certain stage during reset.
libata currently deals SATA the same. This hasn't caused any problem
because problematic situations usually only occur after hotplug or
other link disruption events and libata blindly waited for the device
to spin up and settle after hotplug giving the link and device
whatever time to go through those stages.
libata is going to replace unconditional spinup wait with generic
timed sequence of resets, so not only getting 0xff handling right for
SATA is, well, the right thing to do, it's much more important now.
This patch makes the following changes.
* Make ata_bus_softreset() return -ENODEV if any of its wait fails
due to 0xff status.
* Fail soft/hardreset if status wait returns -ENODEV indicating 0xff
status while SStatus says the link is online. e.g. Reset fails if
status is 0xff after reset when SStatus reports the linke is online.
If SCR registers are not available, everything is the same as
before.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r-- | drivers/ata/libata-core.c | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 84e9448c12d4..49d26675932e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -3027,15 +3027,18 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, | |||
3027 | struct ata_ioports *ioaddr = &ap->ioaddr; | 3027 | struct ata_ioports *ioaddr = &ap->ioaddr; |
3028 | unsigned int dev0 = devmask & (1 << 0); | 3028 | unsigned int dev0 = devmask & (1 << 0); |
3029 | unsigned int dev1 = devmask & (1 << 1); | 3029 | unsigned int dev1 = devmask & (1 << 1); |
3030 | int rc; | 3030 | int rc, ret = 0; |
3031 | 3031 | ||
3032 | /* if device 0 was found in ata_devchk, wait for its | 3032 | /* if device 0 was found in ata_devchk, wait for its |
3033 | * BSY bit to clear | 3033 | * BSY bit to clear |
3034 | */ | 3034 | */ |
3035 | if (dev0) { | 3035 | if (dev0) { |
3036 | rc = ata_wait_ready(ap, deadline); | 3036 | rc = ata_wait_ready(ap, deadline); |
3037 | if (rc && rc != -ENODEV) | 3037 | if (rc) { |
3038 | return rc; | 3038 | if (rc != -ENODEV) |
3039 | return rc; | ||
3040 | ret = rc; | ||
3041 | } | ||
3039 | } | 3042 | } |
3040 | 3043 | ||
3041 | /* if device 1 was found in ata_devchk, wait for | 3044 | /* if device 1 was found in ata_devchk, wait for |
@@ -3055,8 +3058,11 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, | |||
3055 | } | 3058 | } |
3056 | if (dev1) { | 3059 | if (dev1) { |
3057 | rc = ata_wait_ready(ap, deadline); | 3060 | rc = ata_wait_ready(ap, deadline); |
3058 | if (rc && rc != -ENODEV) | 3061 | if (rc) { |
3059 | return rc; | 3062 | if (rc != -ENODEV) |
3063 | return rc; | ||
3064 | ret = rc; | ||
3065 | } | ||
3060 | } | 3066 | } |
3061 | 3067 | ||
3062 | /* is all this really necessary? */ | 3068 | /* is all this really necessary? */ |
@@ -3066,7 +3072,7 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, | |||
3066 | if (dev0) | 3072 | if (dev0) |
3067 | ap->ops->dev_select(ap, 0); | 3073 | ap->ops->dev_select(ap, 0); |
3068 | 3074 | ||
3069 | return 0; | 3075 | return ret; |
3070 | } | 3076 | } |
3071 | 3077 | ||
3072 | static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, | 3078 | static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, |
@@ -3100,7 +3106,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, | |||
3100 | * pulldown resistor. | 3106 | * pulldown resistor. |
3101 | */ | 3107 | */ |
3102 | if (ata_check_status(ap) == 0xFF) | 3108 | if (ata_check_status(ap) == 0xFF) |
3103 | return 0; | 3109 | return -ENODEV; |
3104 | 3110 | ||
3105 | return ata_bus_post_reset(ap, devmask, deadline); | 3111 | return ata_bus_post_reset(ap, devmask, deadline); |
3106 | } | 3112 | } |
@@ -3131,6 +3137,7 @@ void ata_bus_reset(struct ata_port *ap) | |||
3131 | unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; | 3137 | unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; |
3132 | u8 err; | 3138 | u8 err; |
3133 | unsigned int dev0, dev1 = 0, devmask = 0; | 3139 | unsigned int dev0, dev1 = 0, devmask = 0; |
3140 | int rc; | ||
3134 | 3141 | ||
3135 | DPRINTK("ENTER, host %u, port %u\n", ap->print_id, ap->port_no); | 3142 | DPRINTK("ENTER, host %u, port %u\n", ap->print_id, ap->port_no); |
3136 | 3143 | ||
@@ -3152,9 +3159,11 @@ void ata_bus_reset(struct ata_port *ap) | |||
3152 | ap->ops->dev_select(ap, 0); | 3159 | ap->ops->dev_select(ap, 0); |
3153 | 3160 | ||
3154 | /* issue bus reset */ | 3161 | /* issue bus reset */ |
3155 | if (ap->flags & ATA_FLAG_SRST) | 3162 | if (ap->flags & ATA_FLAG_SRST) { |
3156 | if (ata_bus_softreset(ap, devmask, jiffies + 40 * HZ)) | 3163 | rc = ata_bus_softreset(ap, devmask, jiffies + 40 * HZ); |
3164 | if (rc && rc != -ENODEV) | ||
3157 | goto err_out; | 3165 | goto err_out; |
3166 | } | ||
3158 | 3167 | ||
3159 | /* | 3168 | /* |
3160 | * determine by signature whether we have ATA or ATAPI devices | 3169 | * determine by signature whether we have ATA or ATAPI devices |
@@ -3417,7 +3426,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, | |||
3417 | /* issue bus reset */ | 3426 | /* issue bus reset */ |
3418 | DPRINTK("about to softreset, devmask=%x\n", devmask); | 3427 | DPRINTK("about to softreset, devmask=%x\n", devmask); |
3419 | rc = ata_bus_softreset(ap, devmask, deadline); | 3428 | rc = ata_bus_softreset(ap, devmask, deadline); |
3420 | if (rc) { | 3429 | /* if link is occupied, -ENODEV too is an error */ |
3430 | if (rc && (rc != -ENODEV || sata_scr_valid(ap))) { | ||
3421 | ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc); | 3431 | ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc); |
3422 | return rc; | 3432 | return rc; |
3423 | } | 3433 | } |
@@ -3534,7 +3544,8 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, | |||
3534 | msleep(150); | 3544 | msleep(150); |
3535 | 3545 | ||
3536 | rc = ata_wait_ready(ap, deadline); | 3546 | rc = ata_wait_ready(ap, deadline); |
3537 | if (rc && rc != -ENODEV) { | 3547 | /* link occupied, -ENODEV too is an error */ |
3548 | if (rc) { | ||
3538 | ata_port_printk(ap, KERN_ERR, | 3549 | ata_port_printk(ap, KERN_ERR, |
3539 | "COMRESET failed (errno=%d)\n", rc); | 3550 | "COMRESET failed (errno=%d)\n", rc); |
3540 | return rc; | 3551 | return rc; |