Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 32139
b: refs/heads/master
c: d6f26d1
h: refs/heads/master
i:
  32137: b0f5b24
  32135: 00cbc77
v: v3
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed Jul 6, 2006
1 parent 9ac60ea commit 626c94f
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 93 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 02670bf379267f55a43aa57f6895689697e90eb3
refs/heads/master: d6f26d1f1f1128a896f38a7f8426daed0a1205a2
84 changes: 0 additions & 84 deletions trunk/drivers/scsi/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5009,88 +5009,6 @@ int ata_flush_cache(struct ata_device *dev)
return 0;
}

static int ata_standby_drive(struct ata_device *dev)
{
unsigned int err_mask;

err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to standby drive "
"(err_mask=0x%x)\n", err_mask);
return -EIO;
}

return 0;
}

static int ata_start_drive(struct ata_device *dev)
{
unsigned int err_mask;

err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to start drive "
"(err_mask=0x%x)\n", err_mask);
return -EIO;
}

return 0;
}

/**
* ata_device_resume - wakeup a previously suspended devices
* @dev: the device to resume
*
* Kick the drive back into action, by sending it an idle immediate
* command and making sure its transfer mode matches between drive
* and host.
*
*/
int ata_device_resume(struct ata_device *dev)
{
struct ata_port *ap = dev->ap;

if (ap->pflags & ATA_PFLAG_SUSPENDED) {
struct ata_device *failed_dev;

ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);

ap->pflags &= ~ATA_PFLAG_SUSPENDED;
while (ata_set_mode(ap, &failed_dev))
ata_dev_disable(failed_dev);
}
if (!ata_dev_enabled(dev))
return 0;
if (dev->class == ATA_DEV_ATA)
ata_start_drive(dev);

return 0;
}

/**
* ata_device_suspend - prepare a device for suspend
* @dev: the device to suspend
* @state: target power management state
*
* Flush the cache on the drive, if appropriate, then issue a
* standbynow command.
*/
int ata_device_suspend(struct ata_device *dev, pm_message_t state)
{
struct ata_port *ap = dev->ap;

if (!ata_dev_enabled(dev))
return 0;
if (dev->class == ATA_DEV_ATA)
ata_flush_cache(dev);

if (state.event != PM_EVENT_FREEZE)
ata_standby_drive(dev);
ap->pflags |= ATA_PFLAG_SUSPENDED;
return 0;
}

/**
* ata_port_start - Set port up for dma.
* @ap: Port to initialize
Expand Down Expand Up @@ -5946,8 +5864,6 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */

EXPORT_SYMBOL_GPL(ata_device_suspend);
EXPORT_SYMBOL_GPL(ata_device_resume);
EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
EXPORT_SYMBOL_GPL(ata_scsi_device_resume);

Expand Down
121 changes: 115 additions & 6 deletions trunk/drivers/scsi/libata-scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
}
}

int ata_scsi_device_resume(struct scsi_device *sdev)
/**
* ata_scsi_device_suspend - suspend ATA device associated with sdev
* @sdev: the SCSI device to suspend
* @state: target power management state
*
* Request suspend EH action on the ATA device associated with
* @sdev and wait for the operation to complete.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, -errno otherwise.
*/
int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
unsigned long flags;
unsigned int action;
int rc = 0;

if (!dev)
goto out;

spin_lock_irqsave(ap->lock, flags);

/* wait for the previous resume to complete */
while (dev->flags & ATA_DFLAG_SUSPENDED) {
spin_unlock_irqrestore(ap->lock, flags);
ata_port_wait_eh(ap);
spin_lock_irqsave(ap->lock, flags);
}

/* if @sdev is already detached, nothing to do */
if (sdev->sdev_state == SDEV_OFFLINE ||
sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
goto out_unlock;

/* request suspend */
action = ATA_EH_SUSPEND;
if (state.event != PM_EVENT_SUSPEND)
action |= ATA_EH_PM_FREEZE;
ap->eh_info.dev_action[dev->devno] |= action;
ap->eh_info.flags |= ATA_EHI_QUIET;
ata_port_schedule_eh(ap);

spin_unlock_irqrestore(ap->lock, flags);

/* wait for EH to do the job */
ata_port_wait_eh(ap);

spin_lock_irqsave(ap->lock, flags);

/* If @sdev is still attached but the associated ATA device
* isn't suspended, the operation failed.
*/
if (sdev->sdev_state != SDEV_OFFLINE &&
sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
!(dev->flags & ATA_DFLAG_SUSPENDED))
rc = -EIO;

return ata_device_resume(dev);
out_unlock:
spin_unlock_irqrestore(ap->lock, flags);
out:
if (rc == 0)
sdev->sdev_gendev.power.power_state = state;
return rc;
}

int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
/**
* ata_scsi_device_resume - resume ATA device associated with sdev
* @sdev: the SCSI device to resume
*
* Request resume EH action on the ATA device associated with
* @sdev and return immediately. This enables parallel
* wakeup/spinup of devices.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0.
*/
int ata_scsi_device_resume(struct scsi_device *sdev)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
struct ata_eh_info *ehi = &ap->eh_info;
unsigned long flags;
unsigned int action;

if (!dev)
goto out;

spin_lock_irqsave(ap->lock, flags);

/* if @sdev is already detached, nothing to do */
if (sdev->sdev_state == SDEV_OFFLINE ||
sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
goto out_unlock;

return ata_device_suspend(dev, state);
/* request resume */
action = ATA_EH_RESUME;
if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
__ata_ehi_hotplugged(ehi);
else
action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
ehi->dev_action[dev->devno] |= action;

/* We don't want autopsy and verbose EH messages. Disable
* those if we're the only device on this link.
*/
if (ata_port_max_devices(ap) == 1)
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;

ata_port_schedule_eh(ap);

out_unlock:
spin_unlock_irqrestore(ap->lock, flags);
out:
sdev->sdev_gendev.power.power_state = PMSG_ON;
return 0;
}

/**
Expand Down
2 changes: 0 additions & 2 deletions trunk/include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -687,8 +687,6 @@ extern int ata_port_online(struct ata_port *ap);
extern int ata_port_offline(struct ata_port *ap);
extern int ata_scsi_device_resume(struct scsi_device *);
extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
extern int ata_device_resume(struct ata_device *);
extern int ata_device_suspend(struct ata_device *, pm_message_t state);
extern int ata_ratelimit(void);
extern unsigned int ata_busy_sleep(struct ata_port *ap,
unsigned long timeout_pat,
Expand Down

0 comments on commit 626c94f

Please sign in to comment.