static void __devexit fnic_remove(struct pci_dev *pdev) { struct fnic *fnic = pci_get_drvdata(pdev); unsigned long flags; spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->stop_rx_link_events = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) del_timer_sync(&fnic->notify_timer); flush_workqueue(fnic_event_queue); skb_queue_purge(&fnic->frame_queue); fc_fabric_logoff(fnic->lport); spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->in_remove = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); fc_lport_destroy(fnic->lport); fnic_cleanup(fnic); BUG_ON(!skb_queue_empty(&fnic->frame_queue)); spin_lock_irqsave(&fnic_list_lock, flags); list_del(&fnic->list); spin_unlock_irqrestore(&fnic_list_lock, flags); fc_remove_host(fnic->lport->host); scsi_remove_host(fnic->lport->host); fc_exch_mgr_free(fnic->lport); vnic_dev_notify_unset(fnic->vdev); fnic_free_vnic_resources(fnic); fnic_free_intr(fnic); fnic_clear_intr_mode(fnic); vnic_dev_close(fnic->vdev); vnic_dev_unregister(fnic->vdev); fnic_iounmap(fnic); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); scsi_host_put(fnic->lport->host); }
static void fnic_remove(struct pci_dev *pdev) { struct fnic *fnic = pci_get_drvdata(pdev); struct fc_lport *lp = fnic->lport; unsigned long flags; /* * Mark state so that the workqueue thread stops forwarding * received frames and link events to the local port. ISR and * other threads that can queue work items will also stop * creating work items on the fnic workqueue */ spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->stop_rx_link_events = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) del_timer_sync(&fnic->notify_timer); /* * Flush the fnic event queue. After this call, there should * be no event queued for this fnic device in the workqueue */ flush_workqueue(fnic_event_queue); skb_queue_purge(&fnic->frame_queue); skb_queue_purge(&fnic->tx_queue); if (fnic->config.flags & VFCF_FIP_CAPABLE) { del_timer_sync(&fnic->fip_timer); skb_queue_purge(&fnic->fip_frame_queue); fnic_fcoe_reset_vlans(fnic); fnic_fcoe_evlist_free(fnic); } /* * Log off the fabric. This stops all remote ports, dns port, * logs off the fabric. This flushes all rport, disc, lport work * before returning */ fc_fabric_logoff(fnic->lport); spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->in_remove = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); fcoe_ctlr_destroy(&fnic->ctlr); fc_lport_destroy(lp); fnic_stats_debugfs_remove(fnic); /* * This stops the fnic device, masks all interrupts. Completed * CQ entries are drained. Posted WQ/RQ/Copy-WQ entries are * cleaned up */ fnic_cleanup(fnic); BUG_ON(!skb_queue_empty(&fnic->frame_queue)); BUG_ON(!skb_queue_empty(&fnic->tx_queue)); spin_lock_irqsave(&fnic_list_lock, flags); list_del(&fnic->list); spin_unlock_irqrestore(&fnic_list_lock, flags); fc_remove_host(fnic->lport->host); scsi_remove_host(fnic->lport->host); fc_exch_mgr_free(fnic->lport); vnic_dev_notify_unset(fnic->vdev); fnic_free_intr(fnic); fnic_free_vnic_resources(fnic); fnic_clear_intr_mode(fnic); vnic_dev_close(fnic->vdev); vnic_dev_unregister(fnic->vdev); fnic_iounmap(fnic); pci_release_regions(pdev); pci_disable_device(pdev); scsi_host_put(lp->host); }
/* * fcoe_sw_destroy - FCoE software HBA tear-down function * @netdev: ptr to the associated net_device * * Returns: 0 if link is OK for use by FCoE. */ static int fcoe_sw_destroy(struct net_device *netdev) { int cpu; struct fc_lport *lp = NULL; struct fcoe_softc *fc; u8 flogi_maddr[ETH_ALEN]; BUG_ON(!netdev); printk(KERN_DEBUG "fcoe_sw_destroy:interface on %s\n", netdev->name); lp = fcoe_hostlist_lookup(netdev); if (!lp) return -ENODEV; fc = fcoe_softc(lp); /* Logout of the fabric */ fc_fabric_logoff(lp); /* Remove the instance from fcoe's list */ fcoe_hostlist_remove(lp); /* Don't listen for Ethernet packets anymore */ dev_remove_pack(&fc->fcoe_packet_type); /* Cleanup the fc_lport */ fc_lport_destroy(lp); fc_fcp_destroy(lp); /* Detach from the scsi-ml */ fc_remove_host(lp->host); scsi_remove_host(lp->host); /* There are no more rports or I/O, free the EM */ if (lp->emp) fc_exch_mgr_free(lp->emp); /* Delete secondary MAC addresses */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); rtnl_unlock(); /* Free the per-CPU revieve threads */ fcoe_percpu_clean(lp); /* Free existing skbs */ fcoe_clean_pending_queue(lp); /* Free memory used by statistical counters */ for_each_online_cpu(cpu) kfree(lp->dev_stats[cpu]); /* Release the net_device and Scsi_Host */ dev_put(fc->real_dev); scsi_host_put(lp->host); return 0; }