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