aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2008-12-04 22:38:54 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-12-29 12:24:25 -0500
commit3a55b5327b80d805eb3c9720092fd24f15193696 (patch)
tree0276c0d71f087d4976929f01eb2432ba08c5f75f /drivers
parentddcc50f0f3538e4771c8ab9e8ec685a22c90d88c (diff)
[SCSI] lpfc 8.3.0 : Add support for Power Management Suspend/Resume operations
Implement lpfc_pci_suspend_one() and lpfc_pci_resume_one() and register them in the pci_driver table. Signed-off-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c13
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c109
2 files changed, 117 insertions, 5 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 65fddf4ac3cf..58ed6859c921 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -585,20 +585,25 @@ lpfc_do_work(void *p)
585 set_user_nice(current, -20); 585 set_user_nice(current, -20);
586 phba->data_flags = 0; 586 phba->data_flags = 0;
587 587
588 while (1) { 588 while (!kthread_should_stop()) {
589 /* wait and check worker queue activities */ 589 /* wait and check worker queue activities */
590 rc = wait_event_interruptible(phba->work_waitq, 590 rc = wait_event_interruptible(phba->work_waitq,
591 (test_and_clear_bit(LPFC_DATA_READY, 591 (test_and_clear_bit(LPFC_DATA_READY,
592 &phba->data_flags) 592 &phba->data_flags)
593 || kthread_should_stop())); 593 || kthread_should_stop()));
594 BUG_ON(rc); 594 /* Signal wakeup shall terminate the worker thread */
595 595 if (rc) {
596 if (kthread_should_stop()) 596 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
597 "0433 Wakeup on signal: rc=x%x\n", rc);
597 break; 598 break;
599 }
598 600
599 /* Attend pending lpfc data processing */ 601 /* Attend pending lpfc data processing */
600 lpfc_work_done(phba); 602 lpfc_work_done(phba);
601 } 603 }
604 phba->worker_thread = NULL;
605 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
606 "0432 Worker thread stopped.\n");
602 return 0; 607 return 0;
603} 608}
604 609
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 1e2a9521853f..b213d1d01fee 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -2708,7 +2708,7 @@ out:
2708 * @pdev: pointer to PCI device 2708 * @pdev: pointer to PCI device
2709 * 2709 *
2710 * This routine is to be registered to the kernel's PCI subsystem. When an 2710 * This routine is to be registered to the kernel's PCI subsystem. When an
2711 * Emulex HBA is removed from PCI bus. It perform all the necessary cleanup 2711 * Emulex HBA is removed from PCI bus, it performs all the necessary cleanup
2712 * for the HBA device to be removed from the PCI subsystem properly. 2712 * for the HBA device to be removed from the PCI subsystem properly.
2713 **/ 2713 **/
2714static void __devexit 2714static void __devexit
@@ -2785,6 +2785,111 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
2785} 2785}
2786 2786
2787/** 2787/**
2788 * lpfc_pci_suspend_one: lpfc PCI func to suspend device for power management.
2789 * @pdev: pointer to PCI device
2790 * @msg: power management message
2791 *
2792 * This routine is to be registered to the kernel's PCI subsystem to support
2793 * system Power Management (PM). When PM invokes this method, it quiesces the
2794 * device by stopping the driver's worker thread for the device, turning off
2795 * device's interrupt and DMA, and bring the device offline. Note that as the
2796 * driver implements the minimum PM requirements to a power-aware driver's PM
2797 * support for suspend/resume -- all the possible PM messages (SUSPEND,
2798 * HIBERNATE, FREEZE) to the suspend() method call will be treated as SUSPEND
2799 * and the driver will fully reinitialize its device during resume() method
2800 * call, the driver will set device to PCI_D3hot state in PCI config space
2801 * instead of setting it according to the @msg provided by the PM.
2802 *
2803 * Return code
2804 * 0 - driver suspended the device
2805 * Error otherwise
2806 **/
2807static int
2808lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg)
2809{
2810 struct Scsi_Host *shost = pci_get_drvdata(pdev);
2811 struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
2812
2813 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2814 "0473 PCI device Power Management suspend.\n");
2815
2816 /* Bring down the device */
2817 lpfc_offline_prep(phba);
2818 lpfc_offline(phba);
2819 kthread_stop(phba->worker_thread);
2820
2821 /* Disable interrupt from device */
2822 lpfc_disable_intr(phba);
2823
2824 /* Save device state to PCI config space */
2825 pci_save_state(pdev);
2826 pci_set_power_state(pdev, PCI_D3hot);
2827
2828 return 0;
2829}
2830
2831/**
2832 * lpfc_pci_resume_one: lpfc PCI func to resume device for power management.
2833 * @pdev: pointer to PCI device
2834 *
2835 * This routine is to be registered to the kernel's PCI subsystem to support
2836 * system Power Management (PM). When PM invokes this method, it restores
2837 * the device's PCI config space state and fully reinitializes the device
2838 * and brings it online. Note that as the driver implements the minimum PM
2839 * requirements to a power-aware driver's PM for suspend/resume -- all
2840 * the possible PM messages (SUSPEND, HIBERNATE, FREEZE) to the suspend()
2841 * method call will be treated as SUSPEND and the driver will fully
2842 * reinitialize its device during resume() method call, the device will be
2843 * set to PCI_D0 directly in PCI config space before restoring the state.
2844 *
2845 * Return code
2846 * 0 - driver suspended the device
2847 * Error otherwise
2848 **/
2849static int
2850lpfc_pci_resume_one(struct pci_dev *pdev)
2851{
2852 struct Scsi_Host *shost = pci_get_drvdata(pdev);
2853 struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
2854 int error;
2855
2856 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2857 "0452 PCI device Power Management resume.\n");
2858
2859 /* Restore device state from PCI config space */
2860 pci_set_power_state(pdev, PCI_D0);
2861 pci_restore_state(pdev);
2862 if (pdev->is_busmaster)
2863 pci_set_master(pdev);
2864
2865 /* Startup the kernel thread for this host adapter. */
2866 phba->worker_thread = kthread_run(lpfc_do_work, phba,
2867 "lpfc_worker_%d", phba->brd_no);
2868 if (IS_ERR(phba->worker_thread)) {
2869 error = PTR_ERR(phba->worker_thread);
2870 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2871 "0434 PM resume failed to start worker "
2872 "thread: error=x%x.\n", error);
2873 return error;
2874 }
2875
2876 /* Enable interrupt from device */
2877 error = lpfc_enable_intr(phba);
2878 if (error) {
2879 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2880 "0430 PM resume Failed to enable interrupt: "
2881 "error=x%x.\n", error);
2882 return error;
2883 }
2884
2885 /* Restart HBA and bring it online */
2886 lpfc_sli_brdrestart(phba);
2887 lpfc_online(phba);
2888
2889 return 0;
2890}
2891
2892/**
2788 * lpfc_io_error_detected: Driver method for handling PCI I/O error detected. 2893 * lpfc_io_error_detected: Driver method for handling PCI I/O error detected.
2789 * @pdev: pointer to PCI device. 2894 * @pdev: pointer to PCI device.
2790 * @state: the current PCI connection state. 2895 * @state: the current PCI connection state.
@@ -3036,6 +3141,8 @@ static struct pci_driver lpfc_driver = {
3036 .id_table = lpfc_id_table, 3141 .id_table = lpfc_id_table,
3037 .probe = lpfc_pci_probe_one, 3142 .probe = lpfc_pci_probe_one,
3038 .remove = __devexit_p(lpfc_pci_remove_one), 3143 .remove = __devexit_p(lpfc_pci_remove_one),
3144 .suspend = lpfc_pci_suspend_one,
3145 .resume = lpfc_pci_resume_one,
3039 .err_handler = &lpfc_err_handler, 3146 .err_handler = &lpfc_err_handler,
3040}; 3147};
3041 3148