return ret;
 }
 
+
+static struct pci_device_id eeh_reset_ids[] = {
+       { PCI_DEVICE(0x19a2, 0x0710) }, /* Emulex, BE     */
+       { PCI_DEVICE(0x10df, 0xe220) }, /* Emulex, Lancer */
+       { 0 }
+};
+
+static int eeh_pe_change_owner(struct eeh_pe *pe)
+{
+       struct eeh_dev *edev, *tmp;
+       struct pci_dev *pdev;
+       struct pci_device_id *id;
+       int flags, ret;
+
+       /* Check PE state */
+       flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
+       ret = eeh_ops->get_state(pe, NULL);
+       if (ret < 0 || ret == EEH_STATE_NOT_SUPPORT)
+               return 0;
+
+       /* Unfrozen PE, nothing to do */
+       if ((ret & flags) == flags)
+               return 0;
+
+       /* Frozen PE, check if it needs PE level reset */
+       eeh_pe_for_each_dev(pe, edev, tmp) {
+               pdev = eeh_dev_to_pci_dev(edev);
+               if (!pdev)
+                       continue;
+
+               for (id = &eeh_reset_ids[0]; id->vendor != 0; id++) {
+                       if (id->vendor != PCI_ANY_ID &&
+                           id->vendor != pdev->vendor)
+                               continue;
+                       if (id->device != PCI_ANY_ID &&
+                           id->device != pdev->device)
+                               continue;
+                       if (id->subvendor != PCI_ANY_ID &&
+                           id->subvendor != pdev->subsystem_vendor)
+                               continue;
+                       if (id->subdevice != PCI_ANY_ID &&
+                           id->subdevice != pdev->subsystem_device)
+                               continue;
+
+                       goto reset;
+               }
+       }
+
+       return eeh_unfreeze_pe(pe, true);
+
+reset:
+       return eeh_pe_reset_and_recover(pe);
+}
+
 /**
  * eeh_dev_open - Increase count of pass through devices for PE
  * @pdev: PCI device
         * in frozen PE won't work properly. Clear the frozen state
         * in advance.
         */
-       ret = eeh_unfreeze_pe(edev->pe, true);
+       ret = eeh_pe_change_owner(edev->pe);
        if (ret)
                goto out;
 
        /* Decrease PE's pass through count */
        atomic_dec(&edev->pe->pass_dev_cnt);
        WARN_ON(atomic_read(&edev->pe->pass_dev_cnt) < 0);
+       eeh_pe_change_owner(edev->pe);
 out:
        mutex_unlock(&eeh_dev_mutex);
 }
        switch (option) {
        case EEH_OPT_ENABLE:
                if (eeh_enabled()) {
-                       ret = eeh_unfreeze_pe(pe, true);
+                       ret = eeh_pe_change_owner(pe);
                        break;
                }
                ret = -EIO;
 
        return false;
 }
 
+static void *eeh_dev_save_state(void *data, void *userdata)
+{
+       struct eeh_dev *edev = data;
+       struct pci_dev *pdev;
+
+       if (!edev)
+               return NULL;
+
+       pdev = eeh_dev_to_pci_dev(edev);
+       if (!pdev)
+               return NULL;
+
+       pci_save_state(pdev);
+       return NULL;
+}
+
 /**
  * eeh_report_error - Report pci error to each device driver
  * @data: eeh device
        return NULL;
 }
 
+static void *eeh_dev_restore_state(void *data, void *userdata)
+{
+       struct eeh_dev *edev = data;
+       struct pci_dev *pdev;
+
+       if (!edev)
+               return NULL;
+
+       pdev = eeh_dev_to_pci_dev(edev);
+       if (!pdev)
+               return NULL;
+
+       pci_restore_state(pdev);
+       return NULL;
+}
+
 /**
  * eeh_report_resume - Tell device to resume normal operations
  * @data: eeh device
 static void *__eeh_clear_pe_frozen_state(void *data, void *flag)
 {
        struct eeh_pe *pe = (struct eeh_pe *)data;
+       bool *clear_sw_state = flag;
        int i, rc = 1;
 
        for (i = 0; rc && i < 3; i++)
-               rc = eeh_unfreeze_pe(pe, false);
+               rc = eeh_unfreeze_pe(pe, clear_sw_state);
 
        /* Stop immediately on any errors */
        if (rc) {
        return NULL;
 }
 
-static int eeh_clear_pe_frozen_state(struct eeh_pe *pe)
+static int eeh_clear_pe_frozen_state(struct eeh_pe *pe,
+                                    bool clear_sw_state)
 {
        void *rc;
 
-       rc = eeh_pe_traverse(pe, __eeh_clear_pe_frozen_state, NULL);
+       rc = eeh_pe_traverse(pe, __eeh_clear_pe_frozen_state, &clear_sw_state);
        if (!rc)
                eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
 
        return rc ? -EIO : 0;
 }
 
+int eeh_pe_reset_and_recover(struct eeh_pe *pe)
+{
+       int result, ret;
+
+       /* Bail if the PE is being recovered */
+       if (pe->state & EEH_PE_RECOVERING)
+               return 0;
+
+       /* Put the PE into recovery mode */
+       eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
+
+       /* Save states */
+       eeh_pe_dev_traverse(pe, eeh_dev_save_state, NULL);
+
+       /* Report error */
+       eeh_pe_dev_traverse(pe, eeh_report_error, &result);
+
+       /* Issue reset */
+       eeh_pe_state_mark(pe, EEH_PE_RESET);
+       ret = eeh_reset_pe(pe);
+       if (ret) {
+               eeh_pe_state_clear(pe, EEH_PE_RECOVERING | EEH_PE_RESET);
+               return ret;
+       }
+       eeh_pe_state_clear(pe, EEH_PE_RESET);
+
+       /* Unfreeze the PE */
+       ret = eeh_clear_pe_frozen_state(pe, true);
+       if (ret) {
+               eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
+               return ret;
+       }
+
+       /* Notify completion of reset */
+       eeh_pe_dev_traverse(pe, eeh_report_reset, &result);
+
+       /* Restore device state */
+       eeh_pe_dev_traverse(pe, eeh_dev_restore_state, NULL);
+
+       /* Resume */
+       eeh_pe_dev_traverse(pe, eeh_report_resume, NULL);
+
+       /* Clear recovery mode */
+       eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
+
+       return 0;
+}
+
 /**
  * eeh_reset_device - Perform actual reset of a pci slot
  * @pe: EEH PE
        eeh_pe_state_clear(pe, EEH_PE_RESET);
 
        /* Clear frozen state */
-       rc = eeh_clear_pe_frozen_state(pe);
+       rc = eeh_clear_pe_frozen_state(pe, false);
        if (rc)
                return rc;