aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-07-03 03:07:26 -0400
committerJeff Garzik <jeff@garzik.org>2006-07-05 22:16:28 -0400
commitd6f26d1f1f1128a896f38a7f8426daed0a1205a2 (patch)
treeee86bb8f6fff0e1c8df78978ae7f402fbc1dc454
parent02670bf379267f55a43aa57f6895689697e90eb3 (diff)
[PATCH] libata: reimplement per-dev PM
Reimplement per-dev PM. The original implementation directly put the device into suspended mode and didn't synchronize w/ EH operations including hotplug. This patch reimplements ata_scsi_device_suspend() and ata_scsi_device_resume() such that they request EH to perform the respective operations. Both functions synchronize with hotplug such that it doesn't operate on detached devices. Suspend waits for completion but resume just issues request and returns. This allows parallel wake up of devices and thus speeds up system resume. Due to sdev detach synchronization, it's not feasible to separate out EH requesting from sdev handling; thus, ata_device_suspend/resume() are removed and everything is implemented in the respective libata-scsi functions. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/scsi/libata-core.c84
-rw-r--r--drivers/scsi/libata-scsi.c121
-rw-r--r--include/linux/libata.h2
3 files changed, 115 insertions, 92 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index ad5cac79627c..51dbc5221934 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5009,88 +5009,6 @@ int ata_flush_cache(struct ata_device *dev)
5009 return 0; 5009 return 0;
5010} 5010}
5011 5011
5012static int ata_standby_drive(struct ata_device *dev)
5013{
5014 unsigned int err_mask;
5015
5016 err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
5017 if (err_mask) {
5018 ata_dev_printk(dev, KERN_ERR, "failed to standby drive "
5019 "(err_mask=0x%x)\n", err_mask);
5020 return -EIO;
5021 }
5022
5023 return 0;
5024}
5025
5026static int ata_start_drive(struct ata_device *dev)
5027{
5028 unsigned int err_mask;
5029
5030 err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
5031 if (err_mask) {
5032 ata_dev_printk(dev, KERN_ERR, "failed to start drive "
5033 "(err_mask=0x%x)\n", err_mask);
5034 return -EIO;
5035 }
5036
5037 return 0;
5038}
5039
5040/**
5041 * ata_device_resume - wakeup a previously suspended devices
5042 * @dev: the device to resume
5043 *
5044 * Kick the drive back into action, by sending it an idle immediate
5045 * command and making sure its transfer mode matches between drive
5046 * and host.
5047 *
5048 */
5049int ata_device_resume(struct ata_device *dev)
5050{
5051 struct ata_port *ap = dev->ap;
5052
5053 if (ap->pflags & ATA_PFLAG_SUSPENDED) {
5054 struct ata_device *failed_dev;
5055
5056 ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
5057 ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
5058
5059 ap->pflags &= ~ATA_PFLAG_SUSPENDED;
5060 while (ata_set_mode(ap, &failed_dev))
5061 ata_dev_disable(failed_dev);
5062 }
5063 if (!ata_dev_enabled(dev))
5064 return 0;
5065 if (dev->class == ATA_DEV_ATA)
5066 ata_start_drive(dev);
5067
5068 return 0;
5069}
5070
5071/**
5072 * ata_device_suspend - prepare a device for suspend
5073 * @dev: the device to suspend
5074 * @state: target power management state
5075 *
5076 * Flush the cache on the drive, if appropriate, then issue a
5077 * standbynow command.
5078 */
5079int ata_device_suspend(struct ata_device *dev, pm_message_t state)
5080{
5081 struct ata_port *ap = dev->ap;
5082
5083 if (!ata_dev_enabled(dev))
5084 return 0;
5085 if (dev->class == ATA_DEV_ATA)
5086 ata_flush_cache(dev);
5087
5088 if (state.event != PM_EVENT_FREEZE)
5089 ata_standby_drive(dev);
5090 ap->pflags |= ATA_PFLAG_SUSPENDED;
5091 return 0;
5092}
5093
5094/** 5012/**
5095 * ata_port_start - Set port up for dma. 5013 * ata_port_start - Set port up for dma.
5096 * @ap: Port to initialize 5014 * @ap: Port to initialize
@@ -5946,8 +5864,6 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
5946EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); 5864EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
5947#endif /* CONFIG_PCI */ 5865#endif /* CONFIG_PCI */
5948 5866
5949EXPORT_SYMBOL_GPL(ata_device_suspend);
5950EXPORT_SYMBOL_GPL(ata_device_resume);
5951EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); 5867EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
5952EXPORT_SYMBOL_GPL(ata_scsi_device_resume); 5868EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
5953 5869
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index ba3e515f2b9d..7ced41ecde86 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -397,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
397 } 397 }
398} 398}
399 399
400int ata_scsi_device_resume(struct scsi_device *sdev) 400/**
401 * ata_scsi_device_suspend - suspend ATA device associated with sdev
402 * @sdev: the SCSI device to suspend
403 * @state: target power management state
404 *
405 * Request suspend EH action on the ATA device associated with
406 * @sdev and wait for the operation to complete.
407 *
408 * LOCKING:
409 * Kernel thread context (may sleep).
410 *
411 * RETURNS:
412 * 0 on success, -errno otherwise.
413 */
414int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
401{ 415{
402 struct ata_port *ap = ata_shost_to_port(sdev->host); 416 struct ata_port *ap = ata_shost_to_port(sdev->host);
403 struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); 417 struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
418 unsigned long flags;
419 unsigned int action;
420 int rc = 0;
421
422 if (!dev)
423 goto out;
424
425 spin_lock_irqsave(ap->lock, flags);
426
427 /* wait for the previous resume to complete */
428 while (dev->flags & ATA_DFLAG_SUSPENDED) {
429 spin_unlock_irqrestore(ap->lock, flags);
430 ata_port_wait_eh(ap);
431 spin_lock_irqsave(ap->lock, flags);
432 }
433
434 /* if @sdev is already detached, nothing to do */
435 if (sdev->sdev_state == SDEV_OFFLINE ||
436 sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
437 goto out_unlock;
438
439 /* request suspend */
440 action = ATA_EH_SUSPEND;
441 if (state.event != PM_EVENT_SUSPEND)
442 action |= ATA_EH_PM_FREEZE;
443 ap->eh_info.dev_action[dev->devno] |= action;
444 ap->eh_info.flags |= ATA_EHI_QUIET;
445 ata_port_schedule_eh(ap);
446
447 spin_unlock_irqrestore(ap->lock, flags);
448
449 /* wait for EH to do the job */
450 ata_port_wait_eh(ap);
451
452 spin_lock_irqsave(ap->lock, flags);
453
454 /* If @sdev is still attached but the associated ATA device
455 * isn't suspended, the operation failed.
456 */
457 if (sdev->sdev_state != SDEV_OFFLINE &&
458 sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
459 !(dev->flags & ATA_DFLAG_SUSPENDED))
460 rc = -EIO;
404 461
405 return ata_device_resume(dev); 462 out_unlock:
463 spin_unlock_irqrestore(ap->lock, flags);
464 out:
465 if (rc == 0)
466 sdev->sdev_gendev.power.power_state = state;
467 return rc;
406} 468}
407 469
408int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) 470/**
471 * ata_scsi_device_resume - resume ATA device associated with sdev
472 * @sdev: the SCSI device to resume
473 *
474 * Request resume EH action on the ATA device associated with
475 * @sdev and return immediately. This enables parallel
476 * wakeup/spinup of devices.
477 *
478 * LOCKING:
479 * Kernel thread context (may sleep).
480 *
481 * RETURNS:
482 * 0.
483 */
484int ata_scsi_device_resume(struct scsi_device *sdev)
409{ 485{
410 struct ata_port *ap = ata_shost_to_port(sdev->host); 486 struct ata_port *ap = ata_shost_to_port(sdev->host);
411 struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); 487 struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
488 struct ata_eh_info *ehi = &ap->eh_info;
489 unsigned long flags;
490 unsigned int action;
491
492 if (!dev)
493 goto out;
494
495 spin_lock_irqsave(ap->lock, flags);
496
497 /* if @sdev is already detached, nothing to do */
498 if (sdev->sdev_state == SDEV_OFFLINE ||
499 sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
500 goto out_unlock;
412 501
413 return ata_device_suspend(dev, state); 502 /* request resume */
503 action = ATA_EH_RESUME;
504 if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
505 __ata_ehi_hotplugged(ehi);
506 else
507 action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
508 ehi->dev_action[dev->devno] |= action;
509
510 /* We don't want autopsy and verbose EH messages. Disable
511 * those if we're the only device on this link.
512 */
513 if (ata_port_max_devices(ap) == 1)
514 ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
515
516 ata_port_schedule_eh(ap);
517
518 out_unlock:
519 spin_unlock_irqrestore(ap->lock, flags);
520 out:
521 sdev->sdev_gendev.power.power_state = PMSG_ON;
522 return 0;
414} 523}
415 524
416/** 525/**
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 363c7501843a..5ac262608199 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -687,8 +687,6 @@ extern int ata_port_online(struct ata_port *ap);
687extern int ata_port_offline(struct ata_port *ap); 687extern int ata_port_offline(struct ata_port *ap);
688extern int ata_scsi_device_resume(struct scsi_device *); 688extern int ata_scsi_device_resume(struct scsi_device *);
689extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state); 689extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
690extern int ata_device_resume(struct ata_device *);
691extern int ata_device_suspend(struct ata_device *, pm_message_t state);
692extern int ata_ratelimit(void); 690extern int ata_ratelimit(void);
693extern unsigned int ata_busy_sleep(struct ata_port *ap, 691extern unsigned int ata_busy_sleep(struct ata_port *ap,
694 unsigned long timeout_pat, 692 unsigned long timeout_pat,