diff options
Diffstat (limited to 'drivers/scsi/libata-scsi.c')
-rw-r--r-- | drivers/scsi/libata-scsi.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 3dc6188af0e8..12563998d97c 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c | |||
@@ -2786,3 +2786,119 @@ int ata_scsi_offline_dev(struct ata_device *dev) | |||
2786 | } | 2786 | } |
2787 | return 0; | 2787 | return 0; |
2788 | } | 2788 | } |
2789 | |||
2790 | /** | ||
2791 | * ata_scsi_remove_dev - remove attached SCSI device | ||
2792 | * @dev: ATA device to remove attached SCSI device for | ||
2793 | * | ||
2794 | * This function is called from ata_eh_scsi_hotplug() and | ||
2795 | * responsible for removing the SCSI device attached to @dev. | ||
2796 | * | ||
2797 | * LOCKING: | ||
2798 | * Kernel thread context (may sleep). | ||
2799 | */ | ||
2800 | static void ata_scsi_remove_dev(struct ata_device *dev) | ||
2801 | { | ||
2802 | struct ata_port *ap = dev->ap; | ||
2803 | struct scsi_device *sdev; | ||
2804 | unsigned long flags; | ||
2805 | |||
2806 | /* Alas, we need to grab scan_mutex to ensure SCSI device | ||
2807 | * state doesn't change underneath us and thus | ||
2808 | * scsi_device_get() always succeeds. The mutex locking can | ||
2809 | * be removed if there is __scsi_device_get() interface which | ||
2810 | * increments reference counts regardless of device state. | ||
2811 | */ | ||
2812 | mutex_lock(&ap->host->scan_mutex); | ||
2813 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
2814 | |||
2815 | /* clearing dev->sdev is protected by host_set lock */ | ||
2816 | sdev = dev->sdev; | ||
2817 | dev->sdev = NULL; | ||
2818 | |||
2819 | if (sdev) { | ||
2820 | /* If user initiated unplug races with us, sdev can go | ||
2821 | * away underneath us after the host_set lock and | ||
2822 | * scan_mutex are released. Hold onto it. | ||
2823 | */ | ||
2824 | if (scsi_device_get(sdev) == 0) { | ||
2825 | /* The following ensures the attached sdev is | ||
2826 | * offline on return from ata_scsi_offline_dev() | ||
2827 | * regardless it wins or loses the race | ||
2828 | * against this function. | ||
2829 | */ | ||
2830 | scsi_device_set_state(sdev, SDEV_OFFLINE); | ||
2831 | } else { | ||
2832 | WARN_ON(1); | ||
2833 | sdev = NULL; | ||
2834 | } | ||
2835 | } | ||
2836 | |||
2837 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
2838 | mutex_unlock(&ap->host->scan_mutex); | ||
2839 | |||
2840 | if (sdev) { | ||
2841 | ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n", | ||
2842 | sdev->sdev_gendev.bus_id); | ||
2843 | |||
2844 | scsi_remove_device(sdev); | ||
2845 | scsi_device_put(sdev); | ||
2846 | } | ||
2847 | } | ||
2848 | |||
2849 | /** | ||
2850 | * ata_scsi_hotplug - SCSI part of hotplug | ||
2851 | * @data: Pointer to ATA port to perform SCSI hotplug on | ||
2852 | * | ||
2853 | * Perform SCSI part of hotplug. It's executed from a separate | ||
2854 | * workqueue after EH completes. This is necessary because SCSI | ||
2855 | * hot plugging requires working EH and hot unplugging is | ||
2856 | * synchronized with hot plugging with a mutex. | ||
2857 | * | ||
2858 | * LOCKING: | ||
2859 | * Kernel thread context (may sleep). | ||
2860 | */ | ||
2861 | void ata_scsi_hotplug(void *data) | ||
2862 | { | ||
2863 | struct ata_port *ap = data; | ||
2864 | int i; | ||
2865 | |||
2866 | if (ap->flags & ATA_FLAG_UNLOADING) { | ||
2867 | DPRINTK("ENTER/EXIT - unloading\n"); | ||
2868 | return; | ||
2869 | } | ||
2870 | |||
2871 | DPRINTK("ENTER\n"); | ||
2872 | |||
2873 | /* unplug detached devices */ | ||
2874 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
2875 | struct ata_device *dev = &ap->device[i]; | ||
2876 | unsigned long flags; | ||
2877 | |||
2878 | if (!(dev->flags & ATA_DFLAG_DETACHED)) | ||
2879 | continue; | ||
2880 | |||
2881 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
2882 | dev->flags &= ~ATA_DFLAG_DETACHED; | ||
2883 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
2884 | |||
2885 | ata_scsi_remove_dev(dev); | ||
2886 | } | ||
2887 | |||
2888 | /* scan for new ones */ | ||
2889 | ata_scsi_scan_host(ap); | ||
2890 | |||
2891 | /* If we scanned while EH was in progress, scan would have | ||
2892 | * failed silently. Requeue if there are enabled but | ||
2893 | * unattached devices. | ||
2894 | */ | ||
2895 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
2896 | struct ata_device *dev = &ap->device[i]; | ||
2897 | if (ata_dev_enabled(dev) && !dev->sdev) { | ||
2898 | queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ); | ||
2899 | break; | ||
2900 | } | ||
2901 | } | ||
2902 | |||
2903 | DPRINTK("EXIT\n"); | ||
2904 | } | ||