Skip to content

Commit

Permalink
libata: track SLEEP state and issue SRST to wake it up
Browse files Browse the repository at this point in the history
ATA devices in SLEEP mode don't respond to any commands.  SRST is
necessary to wake it up.  Till now, when a command is issued to a
device in SLEEP mode, the command times out, which makes EH reset the
device and retry the command after that, causing a long delay.

This patch makes libata track SLEEP state and issue SRST automatically
if a command is about to be issued to a device in SLEEP.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Bruce Allen <ballen@gravity.phys.uwm.edu>
Cc: Andrew Paprocki <andrew@ishiboo.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed Oct 29, 2007
1 parent 4dbfa39 commit 054a5fb
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 1 deletion.
12 changes: 12 additions & 0 deletions drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5630,6 +5630,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
ehi->dev_action[dev->devno] |= ATA_EH_REVALIDATE;
ata_port_schedule_eh(ap);
break;

case ATA_CMD_SLEEP:
dev->flags |= ATA_DFLAG_SLEEPING;
break;
}

__ata_qc_complete(qc);
Expand Down Expand Up @@ -5769,6 +5773,14 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
qc->flags &= ~ATA_QCFLAG_DMAMAP;
}

/* if device is sleeping, schedule softreset and abort the link */
if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) {
link->eh_info.action |= ATA_EH_SOFTRESET;
ata_ehi_push_desc(&link->eh_info, "waking up from sleep");
ata_link_abort(link);
return;
}

ap->ops->qc_prep(qc);

qc->err_mask |= ap->ops->qc_issue(qc);
Expand Down
4 changes: 3 additions & 1 deletion drivers/ata/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -2208,9 +2208,11 @@ int ata_eh_reset(struct ata_link *link, int classify,
ata_link_for_each_dev(dev, link) {
/* After the reset, the device state is PIO 0
* and the controller state is undefined.
* Record the mode.
* Reset also wakes up drives from sleeping
* mode.
*/
dev->pio_mode = XFER_PIO_0;
dev->flags &= ~ATA_DFLAG_SLEEPING;

if (ata_link_offline(link))
continue;
Expand Down
1 change: 1 addition & 0 deletions include/linux/ata.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ enum {
ATA_CMD_VERIFY_EXT = 0x42,
ATA_CMD_STANDBYNOW1 = 0xE0,
ATA_CMD_IDLEIMMEDIATE = 0xE1,
ATA_CMD_SLEEP = 0xE6,
ATA_CMD_INIT_DEV_PARAMS = 0x91,
ATA_CMD_READ_NATIVE_MAX = 0xF8,
ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
Expand Down
1 change: 1 addition & 0 deletions include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ enum {
ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */
ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */
ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */
ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */
ATA_DFLAG_INIT_MASK = (1 << 16) - 1,

ATA_DFLAG_DETACH = (1 << 16),
Expand Down

0 comments on commit 054a5fb

Please sign in to comment.