Hides the xarray based lookup of a target given the channel and target identifiers within a shost. Use this and __sstarg_for_each_device() where useful. Break the pattern when deleting to jump back and restart the iteration as that seems to be a linked list quirk. May change semantics if elements can be added in the newly created holes in the xarray at the same time as the ongoing deletion. Signed-off-by: Douglas Gilbert <dgilbert@xxxxxxxxxxxx> --- drivers/scsi/scsi.c | 24 ++++++++++++++++++++++++ drivers/scsi/scsi_error.c | 34 +++++++++++++++++----------------- drivers/scsi/scsi_lib.c | 8 +++----- drivers/scsi/scsi_scan.c | 4 ++-- drivers/scsi/scsi_sysfs.c | 8 +++----- include/scsi/scsi_device.h | 2 ++ 6 files changed, 51 insertions(+), 29 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 9e7658aebdb7..1b1fc8d4e5c2 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -667,6 +667,30 @@ struct scsi_device *__scsi_target_iterate_devices(struct scsi_target *starg, } EXPORT_SYMBOL(__scsi_target_iterate_devices); +/** + * __scsi_target_lookup - helper to find target given channel and target_id + * @shost: host to search within + * @chan: channel number + * @t_id: target identifier + * + * No locks or references taken. Returns NULL if not found. + */ +struct scsi_target *__scsi_target_lookup(struct Scsi_Host *shost, + uint chan, uint t_id) +{ + unsigned long l_idx; + struct scsi_target *starg = NULL; + + if (shost) { + xa_for_each(&shost->__targets, l_idx, starg) { + if (chan == starg->channel && t_id == starg->id) + break; + } + } + return starg; +} +EXPORT_SYMBOL(__scsi_target_lookup); + /** * starget_for_each_device - helper to walk all devices of a target * @starg: target whose devices we want to iterate over. diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 978be1602f71..b2dbfa5f73a0 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -644,6 +644,7 @@ static void scsi_handle_queue_ramp_up(struct scsi_device *sdev) { struct scsi_host_template *sht = sdev->host->hostt; struct scsi_device *tmp_sdev; + struct scsi_target *starg = scsi_target(sdev); if (!sht->track_queue_depth || sdev->queue_depth >= sdev->max_queue_depth) @@ -658,13 +659,10 @@ static void scsi_handle_queue_ramp_up(struct scsi_device *sdev) return; /* - * Walk all devices of a target and do - * ramp up on them. + * Walk all devices of a target and do ramp up on them. */ - shost_for_each_device(tmp_sdev, sdev->host) { - if (tmp_sdev->channel != sdev->channel || - tmp_sdev->id != sdev->id || - tmp_sdev->queue_depth == sdev->max_queue_depth) + sstarg_for_each_device(tmp_sdev, starg) { + if (tmp_sdev->queue_depth == sdev->max_queue_depth) continue; scsi_change_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1); @@ -672,25 +670,26 @@ static void scsi_handle_queue_ramp_up(struct scsi_device *sdev) } } +/* + * queue_full corresponds to the SCSI status: "Task Set Full". Its scope is + * at the SCSI taret device level. + */ static void scsi_handle_queue_full(struct scsi_device *sdev) { struct scsi_host_template *sht = sdev->host->hostt; struct scsi_device *tmp_sdev; + struct scsi_target *starg = scsi_target(sdev); if (!sht->track_queue_depth) return; - shost_for_each_device(tmp_sdev, sdev->host) { - if (tmp_sdev->channel != sdev->channel || - tmp_sdev->id != sdev->id) - continue; + sstarg_for_each_device(tmp_sdev, starg) /* * We do not know the number of commands that were at - * the device when we got the queue full so we start + * the target when we got the queue full so we start * from the highest possible value and work our way down. */ scsi_track_queue_full(tmp_sdev, tmp_sdev->queue_depth - 1); - } } /** @@ -2305,12 +2304,13 @@ EXPORT_SYMBOL(scsi_report_bus_reset); void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target) { struct scsi_device *sdev; + struct scsi_target *starg = __scsi_target_lookup(shost, channel, + target); - __shost_for_each_device(sdev, shost) { - if (channel == sdev_channel(sdev) && - target == sdev_id(sdev)) - __scsi_report_device_reset(sdev, NULL); - } + if (!starg) + return; + __sstarg_for_each_device(sdev, starg) + __scsi_report_device_reset(sdev, NULL); } EXPORT_SYMBOL(scsi_report_device_reset); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f484bf2b5d7d..034ec2e57d1c 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -374,7 +374,7 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev) struct Scsi_Host *shost = current_sdev->host; struct scsi_device *sdev; struct scsi_target *starget = scsi_target(current_sdev); - unsigned long flags, l_idx; + unsigned long flags; spin_lock_irqsave(shost->host_lock, flags); starget->starget_sdev_user = NULL; @@ -392,7 +392,7 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev) if (starget->starget_sdev_user) goto out; /* XARRAY: was list_for_each_entry_safe(); is this safe ? */ - xa_for_each(&starget->devices, l_idx, sdev) { + __sstarg_for_each_device(sdev, starget) { if (sdev == current_sdev) continue; if (scsi_device_get(sdev)) @@ -2217,14 +2217,12 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, } EXPORT_SYMBOL(scsi_test_unit_ready); -/* Assume host_lock taken and that xahp->xa_lock is the same lock. */ static inline void scsi_adjust_non_sdev_del_mark(struct scsi_device *sdev, enum scsi_device_state old_state, enum scsi_device_state new_state) { - struct xarray *xatp = - &to_scsi_target(sdev->sdev_gendev.parent)->devices; + struct xarray *xatp = &scsi_target(sdev)->devices; struct xarray *xahp = &sdev->host->__devices; if (old_state == new_state) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index f5a5e48ca5ae..c055ee083ea9 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1880,13 +1880,13 @@ void scsi_forget_host(struct Scsi_Host *shost) struct scsi_device *sdev; unsigned long flags, l_idx; - restart: spin_lock_irqsave(shost->host_lock, flags); xa_for_each_marked(&shost->__devices, l_idx, sdev, SCSI_XA_NON_SDEV_DEL) { spin_unlock_irqrestore(shost->host_lock, flags); __scsi_remove_device(sdev); - goto restart; + /* XARRAY: was a goto to before first line */ + spin_lock_irqsave(shost->host_lock, flags); } spin_unlock_irqrestore(shost->host_lock, flags); } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 6fdd4648f374..394230d69afd 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1480,7 +1480,6 @@ static void __scsi_remove_target(struct scsi_target *starget) unsigned long flags, l_idx; spin_lock_irqsave(shost->host_lock, flags); - restart: xa_for_each_marked(&starget->devices, l_idx, sdev, SCSI_XA_NON_SDEV_DEL) { /* @@ -1496,8 +1495,7 @@ static void __scsi_remove_target(struct scsi_target *starget) scsi_remove_device(sdev); put_device(&sdev->sdev_gendev); spin_lock_irqsave(shost->host_lock, flags); - /* XARRAY: is this goto start of loop correct ? */ - goto restart; + /* XARRAY: was a goto to restart loop */ } spin_unlock_irqrestore(shost->host_lock, flags); } @@ -1516,7 +1514,6 @@ void scsi_remove_target(struct device *dev) struct scsi_target *starget; unsigned long flags, l_idx; -restart: spin_lock_irqsave(shost->host_lock, flags); xa_for_each(&shost->__targets, l_idx, starget) { if (starget->state == STARGET_DEL || @@ -1532,7 +1529,8 @@ void scsi_remove_target(struct device *dev) spin_unlock_irqrestore(shost->host_lock, flags); __scsi_remove_target(starget); scsi_target_reap(starget); - goto restart; + /* XARRAY: was a goto to before first line */ + spin_lock_irqsave(shost->host_lock, flags); } } spin_unlock_irqrestore(shost->host_lock, flags); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 23bf686cbabc..e019621416d5 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -362,6 +362,8 @@ extern struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *, u64); extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *, u64); +extern struct scsi_target *__scsi_target_lookup(struct Scsi_Host *shost, + uint chan, uint t_id); /* XARRAY: these visitor names too close to sstarg_for_each_device macros? */ extern void starget_for_each_device(struct scsi_target *, void *, void (*fn)(struct scsi_device *, void *)); -- 2.25.1