diff options
-rw-r--r-- | drivers/scsi/libata-core.c | 84 | ||||
-rw-r--r-- | drivers/scsi/libata-scsi.c | 121 | ||||
-rw-r--r-- | include/linux/libata.h | 2 |
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 | ||
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 | /** | 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); | |||
5946 | EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); | 5864 | EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); |
5947 | #endif /* CONFIG_PCI */ | 5865 | #endif /* CONFIG_PCI */ |
5948 | 5866 | ||
5949 | EXPORT_SYMBOL_GPL(ata_device_suspend); | ||
5950 | EXPORT_SYMBOL_GPL(ata_device_resume); | ||
5951 | EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); | 5867 | EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); |
5952 | EXPORT_SYMBOL_GPL(ata_scsi_device_resume); | 5868 | EXPORT_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 | ||
400 | int 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 | */ | ||
414 | int 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 | ||
408 | int 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 | */ | ||
484 | int 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); | |||
687 | extern int ata_port_offline(struct ata_port *ap); | 687 | extern int ata_port_offline(struct ata_port *ap); |
688 | extern int ata_scsi_device_resume(struct scsi_device *); | 688 | extern int ata_scsi_device_resume(struct scsi_device *); |
689 | extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state); | 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); | 690 | extern int ata_ratelimit(void); |
693 | extern unsigned int ata_busy_sleep(struct ata_port *ap, | 691 | extern unsigned int ata_busy_sleep(struct ata_port *ap, |
694 | unsigned long timeout_pat, | 692 | unsigned long timeout_pat, |