On Wed, 16 Feb 2005, Andrew Vasquez wrote:
> On Tue, 15 Feb 2005, James Bottomley wrote:
> > Well, how about a different format for this, so there's a
> > scsi_remove_target that takes a generic device (analogous to the
> > scsi_scan_target) except that this time if the device isn't a target, we
> > remove all the children of the device that are targets?
> >
>
> along the same vein, we'll also need generic-device accessors to block
> and unblock all scsi_device children of an scsi_target. currently,
> scsi_internal_devive_[block|unblock]() is issued across all sdevs for
> a given starget:
>
> void scsi_block_target(struct device *)
> void scsi_unblock_target(struct device *)
>
> one caveat with these parent-accessors is that we also lose
> 'per-starget' (un)blocking/removal granualarity -- not sure if that's
> going to be a problem for other interfaces in the future.
>
Does the following seem reasonable?
* add scsi_target_block() and scsi_target_unblock() routines which
take a generic-device. Side note: there are mixture of
scsi_<object>_<action>() and scsi_<action>_<noun>() functions defined
in the scsi APIs -- going forward are there any 'guides' or
suggestions on which to choose?
* modify scsi_remove_target() to take a generic-device.
--
Andrew Vasquez
===== drivers/scsi/scsi_lib.c 1.149 vs edited =====
--- 1.149/drivers/scsi/scsi_lib.c 2005-02-15 23:48:33 -08:00
+++ edited/drivers/scsi/scsi_lib.c 2005-02-17 11:17:22 -08:00
@@ -1889,3 +1889,55 @@ scsi_internal_device_unblock(struct scsi
return 0;
}
EXPORT_SYMBOL_GPL(scsi_internal_device_unblock);
+
+static void
+device_block(struct scsi_device *sdev, void *data)
+{
+ scsi_internal_device_block(sdev);
+}
+
+static int
+target_block(struct device *dev, void *data)
+{
+ if (scsi_is_target_device(dev))
+ starget_for_each_device(to_scsi_target(dev), NULL,
+ device_block);
+ return 0;
+}
+
+void
+scsi_target_block(struct device *dev)
+{
+ if (scsi_is_target_device(dev))
+ starget_for_each_device(to_scsi_target(dev), NULL,
+ device_block);
+ else
+ device_for_each_child(dev, NULL, target_block);
+}
+EXPORT_SYMBOL_GPL(scsi_target_block);
+
+static void
+device_unblock(struct scsi_device *sdev, void *data)
+{
+ scsi_internal_device_unblock(sdev);
+}
+
+static int
+target_unblock(struct device *dev, void *data)
+{
+ if (scsi_is_target_device(dev))
+ starget_for_each_device(to_scsi_target(dev), NULL,
+ device_unblock);
+ return 0;
+}
+
+void
+scsi_target_unblock(struct device *dev)
+{
+ if (scsi_is_target_device(dev))
+ starget_for_each_device(to_scsi_target(dev), NULL,
+ device_unblock);
+ else
+ device_for_each_child(dev, NULL, target_unblock);
+}
+EXPORT_SYMBOL_GPL(scsi_target_unblock);
===== drivers/scsi/scsi_scan.c 1.141 vs edited =====
--- 1.141/drivers/scsi/scsi_scan.c 2005-02-15 23:48:33 -08:00
+++ edited/drivers/scsi/scsi_scan.c 2005-02-16 10:21:35 -08:00
@@ -1385,7 +1385,7 @@ void scsi_forget_host(struct Scsi_Host *
spin_lock_irqsave(shost->host_lock, flags);
list_for_each_entry_safe(starget, tmp, &shost->__targets, siblings) {
spin_unlock_irqrestore(shost->host_lock, flags);
- scsi_remove_target(starget);
+ scsi_remove_target(&starget->dev);
spin_lock_irqsave(shost->host_lock, flags);
}
spin_unlock_irqrestore(shost->host_lock, flags);
===== drivers/scsi/scsi_sysfs.c 1.65 vs edited =====
--- 1.65/drivers/scsi/scsi_sysfs.c 2005-02-15 23:48:33 -08:00
+++ edited/drivers/scsi/scsi_sysfs.c 2005-02-16 17:05:37 -08:00
@@ -634,15 +634,7 @@ void scsi_remove_device(struct scsi_devi
}
EXPORT_SYMBOL(scsi_remove_device);
-/**
- * scsi_remove_target - try to remove a target and all its devices
- * @starget: the target to remove
- *
- * Note: This is slightly racy. It is possible that if the user
- * requests the addition of another device then the target won't be
- * removed.
- */
-void scsi_remove_target(struct scsi_target *starget)
+void __scsi_remove_target(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
unsigned long flags;
@@ -660,6 +652,31 @@ void scsi_remove_target(struct scsi_targ
}
spin_unlock_irqrestore(shost->host_lock, flags);
scsi_target_reap(starget);
+}
+
+/**
+ * scsi_remove_target - try to remove a target and all its devices
+ * @dev: generic starget or parent of generic stargets to be removed
+ *
+ * Note: This is slightly racy. It is possible that if the user
+ * requests the addition of another device then the target won't be
+ * removed.
+ */
+void scsi_remove_target(struct device *dev)
+{
+ struct device *rdev, *idev, *next;
+
+ if (scsi_is_target_device(dev)) {
+ __scsi_remove_target(to_scsi_target(dev));
+ return;
+ }
+
+ rdev = get_device(dev);
+ list_for_each_entry_safe(idev, next, &dev->children, node) {
+ if (scsi_is_target_device(idev))
+ __scsi_remove_target(to_scsi_target(idev));
+ }
+ put_device(rdev);
}
EXPORT_SYMBOL(scsi_remove_target);
===== include/scsi/scsi_device.h 1.30 vs edited =====
--- 1.30/include/scsi/scsi_device.h 2005-02-15 23:48:33 -08:00
+++ edited/include/scsi/scsi_device.h 2005-02-17 11:15:51 -08:00
@@ -227,7 +227,9 @@ extern void scsi_device_resume(struct sc
extern void scsi_target_quiesce(struct scsi_target *);
extern void scsi_target_resume(struct scsi_target *);
extern void scsi_target_reap(struct scsi_target *);
-extern void scsi_remove_target(struct scsi_target *);
+extern void scsi_target_block(struct device *);
+extern void scsi_target_unblock(struct device *);
+extern void scsi_remove_target(struct device *);
extern const char *scsi_device_state_name(enum scsi_device_state);
extern int scsi_is_sdev_device(const struct device *);
extern int scsi_is_target_device(const struct device *);
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html