[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>

authored by Tejun Heo and committed by Jeff Garzik d6f26d1f 02670bf3

+119 -96
-84
drivers/scsi/libata-core.c
··· 5009 return 0; 5010 } 5011 5012 - static 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 - 5026 - static 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 - */ 5049 - int 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 - */ 5079 - int 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 /** 5095 * ata_port_start - Set port up for dma. 5096 * @ap: Port to initialize ··· 5864 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); 5865 #endif /* CONFIG_PCI */ 5866 5867 - EXPORT_SYMBOL_GPL(ata_device_suspend); 5868 - EXPORT_SYMBOL_GPL(ata_device_resume); 5869 EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); 5870 EXPORT_SYMBOL_GPL(ata_scsi_device_resume); 5871
··· 5009 return 0; 5010 } 5011 5012 /** 5013 * ata_port_start - Set port up for dma. 5014 * @ap: Port to initialize ··· 5946 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); 5947 #endif /* CONFIG_PCI */ 5948 5949 EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); 5950 EXPORT_SYMBOL_GPL(ata_scsi_device_resume); 5951
+119 -10
drivers/scsi/libata-scsi.c
··· 397 } 398 } 399 400 - int ata_scsi_device_resume(struct scsi_device *sdev) 401 - { 402 - struct ata_port *ap = ata_shost_to_port(sdev->host); 403 - struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); 404 - 405 - return ata_device_resume(dev); 406 - } 407 - 408 int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) 409 { 410 struct ata_port *ap = ata_shost_to_port(sdev->host); 411 - struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); 412 413 - return ata_device_suspend(dev, state); 414 } 415 416 /**
··· 397 } 398 } 399 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 + */ 414 int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) 415 { 416 struct ata_port *ap = ata_shost_to_port(sdev->host); 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; 461 + 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; 468 + } 469 + 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 + */ 484 + int ata_scsi_device_resume(struct scsi_device *sdev) 485 + { 486 + struct ata_port *ap = ata_shost_to_port(sdev->host); 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; 501 + 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; 523 } 524 525 /**
-2
include/linux/libata.h
··· 687 extern int ata_port_offline(struct ata_port *ap); 688 extern int ata_scsi_device_resume(struct scsi_device *); 689 extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state); 690 - extern int ata_device_resume(struct ata_device *); 691 - extern int ata_device_suspend(struct ata_device *, pm_message_t state); 692 extern int ata_ratelimit(void); 693 extern unsigned int ata_busy_sleep(struct ata_port *ap, 694 unsigned long timeout_pat,
··· 687 extern int ata_port_offline(struct ata_port *ap); 688 extern int ata_scsi_device_resume(struct scsi_device *); 689 extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state); 690 extern int ata_ratelimit(void); 691 extern unsigned int ata_busy_sleep(struct ata_port *ap, 692 unsigned long timeout_pat,