|
@@ -1005,7 +1005,6 @@ static void __scsi_remove_target(struct scsi_target *starget)
|
|
|
struct scsi_device *sdev;
|
|
|
|
|
|
spin_lock_irqsave(shost->host_lock, flags);
|
|
|
- starget->reap_ref++;
|
|
|
restart:
|
|
|
list_for_each_entry(sdev, &shost->__devices, siblings) {
|
|
|
if (sdev->channel != starget->channel ||
|
|
@@ -1019,14 +1018,6 @@ static void __scsi_remove_target(struct scsi_target *starget)
|
|
|
goto restart;
|
|
|
}
|
|
|
spin_unlock_irqrestore(shost->host_lock, flags);
|
|
|
- scsi_target_reap(starget);
|
|
|
-}
|
|
|
-
|
|
|
-static int __remove_child (struct device * dev, void * data)
|
|
|
-{
|
|
|
- if (scsi_is_target_device(dev))
|
|
|
- __scsi_remove_target(to_scsi_target(dev));
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1039,14 +1030,34 @@ static int __remove_child (struct device * dev, void * data)
|
|
|
*/
|
|
|
void scsi_remove_target(struct device *dev)
|
|
|
{
|
|
|
- if (scsi_is_target_device(dev)) {
|
|
|
- __scsi_remove_target(to_scsi_target(dev));
|
|
|
- return;
|
|
|
+ struct Scsi_Host *shost = dev_to_shost(dev->parent);
|
|
|
+ struct scsi_target *starget, *found;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ restart:
|
|
|
+ found = NULL;
|
|
|
+ spin_lock_irqsave(shost->host_lock, flags);
|
|
|
+ list_for_each_entry(starget, &shost->__targets, siblings) {
|
|
|
+ if (starget->state == STARGET_DEL)
|
|
|
+ continue;
|
|
|
+ if (starget->dev.parent == dev || &starget->dev == dev) {
|
|
|
+ found = starget;
|
|
|
+ found->reap_ref++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
+ spin_unlock_irqrestore(shost->host_lock, flags);
|
|
|
|
|
|
- get_device(dev);
|
|
|
- device_for_each_child(dev, NULL, __remove_child);
|
|
|
- put_device(dev);
|
|
|
+ if (found) {
|
|
|
+ __scsi_remove_target(found);
|
|
|
+ scsi_target_reap(found);
|
|
|
+ /* in the case where @dev has multiple starget children,
|
|
|
+ * continue removing.
|
|
|
+ *
|
|
|
+ * FIXME: does such a case exist?
|
|
|
+ */
|
|
|
+ goto restart;
|
|
|
+ }
|
|
|
}
|
|
|
EXPORT_SYMBOL(scsi_remove_target);
|
|
|
|