diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_iscsi.c')
-rw-r--r-- | drivers/scsi/scsi_transport_iscsi.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index f876b0ae521..af88955d0ec 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -128,11 +128,11 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, INIT_LIST_HEAD(&ihost->sessions); mutex_init(&ihost->mutex); - snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d", + snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", shost->host_no); - ihost->unbind_workq = create_singlethread_workqueue( - ihost->unbind_workq_name); - if (!ihost->unbind_workq) + ihost->scan_workq = create_singlethread_workqueue( + ihost->scan_workq_name); + if (!ihost->scan_workq) return -ENOMEM; return 0; } @@ -143,7 +143,7 @@ static int iscsi_remove_host(struct transport_container *tc, struct device *dev, struct Scsi_Host *shost = dev_to_shost(dev); struct iscsi_host *ihost = shost->shost_data; - destroy_workqueue(ihost->unbind_workq); + destroy_workqueue(ihost->scan_workq); return 0; } @@ -302,6 +302,23 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, return 0; } +static void iscsi_scan_session(struct work_struct *work) +{ + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, scan_work); + unsigned long flags; + + spin_lock_irqsave(&session->lock, flags); + if (session->state != ISCSI_SESSION_LOGGED_IN) { + spin_unlock_irqrestore(&session->lock, flags); + return; + } + spin_unlock_irqrestore(&session->lock, flags); + + scsi_scan_target(&session->dev, 0, session->target_id, + SCAN_WILD_CARD, 1); +} + static void session_recovery_timedout(struct work_struct *work) { struct iscsi_cls_session *session = @@ -340,6 +357,8 @@ void __iscsi_unblock_session(struct iscsi_cls_session *session) void iscsi_unblock_session(struct iscsi_cls_session *session) { + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost = shost->shost_data; unsigned long flags; spin_lock_irqsave(&session->lock, flags); @@ -347,6 +366,7 @@ void iscsi_unblock_session(struct iscsi_cls_session *session) spin_unlock_irqrestore(&session->lock, flags); __iscsi_unblock_session(session); + queue_work(ihost->scan_workq, &session->scan_work); } EXPORT_SYMBOL_GPL(iscsi_unblock_session); @@ -390,7 +410,7 @@ static int iscsi_unbind_session(struct iscsi_cls_session *session) struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost = shost->shost_data; - return queue_work(ihost->unbind_workq, &session->unbind_work); + return queue_work(ihost->scan_workq, &session->unbind_work); } struct iscsi_cls_session * @@ -411,6 +431,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); INIT_WORK(&session->unbind_work, __iscsi_unbind_session); + INIT_WORK(&session->scan_work, iscsi_scan_session); spin_lock_init(&session->lock); /* this is released in the dev's release function */ @@ -530,13 +551,15 @@ void iscsi_remove_session(struct iscsi_cls_session *session) spin_unlock_irqrestore(&session->lock, flags); __iscsi_unblock_session(session); iscsi_unbind_session(session); + + /* flush running scans */ + flush_workqueue(ihost->scan_workq); /* * If the session dropped while removing devices then we need to make * sure it is not blocked */ if (!cancel_delayed_work(&session->recovery_work)) flush_workqueue(iscsi_eh_timer_workq); - flush_workqueue(ihost->unbind_workq); /* hw iscsi may not have removed all connections from session */ err = device_for_each_child(&session->dev, NULL, |