Commit 2f9c4d52 authored by Kashyap Desai's avatar Kashyap Desai Committed by Martin K. Petersen
Browse files

scsi: mpi3mr: Add support for PM suspend and resume

parent 44dc724f
Loading
Loading
Loading
Loading
+84 −0
Original line number Diff line number Diff line
@@ -3389,6 +3389,86 @@ static void mpi3mr_shutdown(struct pci_dev *pdev)
	mpi3mr_cleanup_ioc(mrioc, 0);
}

#ifdef CONFIG_PM
/**
 * mpi3mr_suspend - PCI power management suspend callback
 * @pdev: PCI device instance
 * @state: New power state
 *
 * Change the power state to the given value and cleanup the IOC
 * by issuing MUR and shutdown notification
 *
 * Return: 0 always.
 */
static int mpi3mr_suspend(struct pci_dev *pdev, pm_message_t state)
{
	struct Scsi_Host *shost = pci_get_drvdata(pdev);
	struct mpi3mr_ioc *mrioc;
	pci_power_t device_state;

	if (!shost)
		return 0;

	mrioc = shost_priv(shost);
	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
		ssleep(1);
	mrioc->stop_drv_processing = 1;
	mpi3mr_cleanup_fwevt_list(mrioc);
	scsi_block_requests(shost);
	mpi3mr_stop_watchdog(mrioc);
	mpi3mr_cleanup_ioc(mrioc, 1);

	device_state = pci_choose_state(pdev, state);
	ioc_info(mrioc, "pdev=0x%p, slot=%s, entering operating state [D%d]\n",
	    pdev, pci_name(pdev), device_state);
	pci_save_state(pdev);
	pci_set_power_state(pdev, device_state);
	mpi3mr_cleanup_resources(mrioc);

	return 0;
}

/**
 * mpi3mr_resume - PCI power management resume callback
 * @pdev: PCI device instance
 *
 * Restore the power state to D0 and reinitialize the controller
 * and resume I/O operations to the target devices
 *
 * Return: 0 on success, non-zero on failure
 */
static int mpi3mr_resume(struct pci_dev *pdev)
{
	struct Scsi_Host *shost = pci_get_drvdata(pdev);
	struct mpi3mr_ioc *mrioc;
	pci_power_t device_state = pdev->current_state;
	int r;

	mrioc = shost_priv(shost);

	ioc_info(mrioc, "pdev=0x%p, slot=%s, previous operating state [D%d]\n",
	    pdev, pci_name(pdev), device_state);
	pci_set_power_state(pdev, PCI_D0);
	pci_enable_wake(pdev, PCI_D0, 0);
	pci_restore_state(pdev);
	mrioc->pdev = pdev;
	mrioc->cpu_count = num_online_cpus();
	r = mpi3mr_setup_resources(mrioc);
	if (r) {
		ioc_info(mrioc, "%s: Setup resources failed[%d]\n",
		    __func__, r);
		return r;
	}

	mrioc->stop_drv_processing = 0;
	mpi3mr_init_ioc(mrioc, 1);
	scsi_unblock_requests(shost);
	mpi3mr_start_watchdog(mrioc);

	return 0;
}
#endif

static const struct pci_device_id mpi3mr_pci_id_table[] = {
	{
		PCI_DEVICE_SUB(PCI_VENDOR_ID_LSI_LOGIC, 0x00A5,
@@ -3404,6 +3484,10 @@ static struct pci_driver mpi3mr_pci_driver = {
	.probe = mpi3mr_probe,
	.remove = mpi3mr_remove,
	.shutdown = mpi3mr_shutdown,
#ifdef CONFIG_PM
	.suspend = mpi3mr_suspend,
	.resume = mpi3mr_resume,
#endif
};

static int __init mpi3mr_init(void)