diff options
Diffstat (limited to 'drivers/scsi')
-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 f876b0ae521a..af88955d0ec1 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, | |||
128 | INIT_LIST_HEAD(&ihost->sessions); | 128 | INIT_LIST_HEAD(&ihost->sessions); |
129 | mutex_init(&ihost->mutex); | 129 | mutex_init(&ihost->mutex); |
130 | 130 | ||
131 | snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d", | 131 | snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", |
132 | shost->host_no); | 132 | shost->host_no); |
133 | ihost->unbind_workq = create_singlethread_workqueue( | 133 | ihost->scan_workq = create_singlethread_workqueue( |
134 | ihost->unbind_workq_name); | 134 | ihost->scan_workq_name); |
135 | if (!ihost->unbind_workq) | 135 | if (!ihost->scan_workq) |
136 | return -ENOMEM; | 136 | return -ENOMEM; |
137 | return 0; | 137 | return 0; |
138 | } | 138 | } |
@@ -143,7 +143,7 @@ static int iscsi_remove_host(struct transport_container *tc, struct device *dev, | |||
143 | struct Scsi_Host *shost = dev_to_shost(dev); | 143 | struct Scsi_Host *shost = dev_to_shost(dev); |
144 | struct iscsi_host *ihost = shost->shost_data; | 144 | struct iscsi_host *ihost = shost->shost_data; |
145 | 145 | ||
146 | destroy_workqueue(ihost->unbind_workq); | 146 | destroy_workqueue(ihost->scan_workq); |
147 | return 0; | 147 | return 0; |
148 | } | 148 | } |
149 | 149 | ||
@@ -302,6 +302,23 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, | |||
302 | return 0; | 302 | return 0; |
303 | } | 303 | } |
304 | 304 | ||
305 | static void iscsi_scan_session(struct work_struct *work) | ||
306 | { | ||
307 | struct iscsi_cls_session *session = | ||
308 | container_of(work, struct iscsi_cls_session, scan_work); | ||
309 | unsigned long flags; | ||
310 | |||
311 | spin_lock_irqsave(&session->lock, flags); | ||
312 | if (session->state != ISCSI_SESSION_LOGGED_IN) { | ||
313 | spin_unlock_irqrestore(&session->lock, flags); | ||
314 | return; | ||
315 | } | ||
316 | spin_unlock_irqrestore(&session->lock, flags); | ||
317 | |||
318 | scsi_scan_target(&session->dev, 0, session->target_id, | ||
319 | SCAN_WILD_CARD, 1); | ||
320 | } | ||
321 | |||
305 | static void session_recovery_timedout(struct work_struct *work) | 322 | static void session_recovery_timedout(struct work_struct *work) |
306 | { | 323 | { |
307 | struct iscsi_cls_session *session = | 324 | struct iscsi_cls_session *session = |
@@ -340,6 +357,8 @@ void __iscsi_unblock_session(struct iscsi_cls_session *session) | |||
340 | 357 | ||
341 | void iscsi_unblock_session(struct iscsi_cls_session *session) | 358 | void iscsi_unblock_session(struct iscsi_cls_session *session) |
342 | { | 359 | { |
360 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | ||
361 | struct iscsi_host *ihost = shost->shost_data; | ||
343 | unsigned long flags; | 362 | unsigned long flags; |
344 | 363 | ||
345 | spin_lock_irqsave(&session->lock, flags); | 364 | spin_lock_irqsave(&session->lock, flags); |
@@ -347,6 +366,7 @@ void iscsi_unblock_session(struct iscsi_cls_session *session) | |||
347 | spin_unlock_irqrestore(&session->lock, flags); | 366 | spin_unlock_irqrestore(&session->lock, flags); |
348 | 367 | ||
349 | __iscsi_unblock_session(session); | 368 | __iscsi_unblock_session(session); |
369 | queue_work(ihost->scan_workq, &session->scan_work); | ||
350 | } | 370 | } |
351 | EXPORT_SYMBOL_GPL(iscsi_unblock_session); | 371 | EXPORT_SYMBOL_GPL(iscsi_unblock_session); |
352 | 372 | ||
@@ -390,7 +410,7 @@ static int iscsi_unbind_session(struct iscsi_cls_session *session) | |||
390 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 410 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
391 | struct iscsi_host *ihost = shost->shost_data; | 411 | struct iscsi_host *ihost = shost->shost_data; |
392 | 412 | ||
393 | return queue_work(ihost->unbind_workq, &session->unbind_work); | 413 | return queue_work(ihost->scan_workq, &session->unbind_work); |
394 | } | 414 | } |
395 | 415 | ||
396 | struct iscsi_cls_session * | 416 | struct iscsi_cls_session * |
@@ -411,6 +431,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, | |||
411 | INIT_LIST_HEAD(&session->host_list); | 431 | INIT_LIST_HEAD(&session->host_list); |
412 | INIT_LIST_HEAD(&session->sess_list); | 432 | INIT_LIST_HEAD(&session->sess_list); |
413 | INIT_WORK(&session->unbind_work, __iscsi_unbind_session); | 433 | INIT_WORK(&session->unbind_work, __iscsi_unbind_session); |
434 | INIT_WORK(&session->scan_work, iscsi_scan_session); | ||
414 | spin_lock_init(&session->lock); | 435 | spin_lock_init(&session->lock); |
415 | 436 | ||
416 | /* this is released in the dev's release function */ | 437 | /* this is released in the dev's release function */ |
@@ -530,13 +551,15 @@ void iscsi_remove_session(struct iscsi_cls_session *session) | |||
530 | spin_unlock_irqrestore(&session->lock, flags); | 551 | spin_unlock_irqrestore(&session->lock, flags); |
531 | __iscsi_unblock_session(session); | 552 | __iscsi_unblock_session(session); |
532 | iscsi_unbind_session(session); | 553 | iscsi_unbind_session(session); |
554 | |||
555 | /* flush running scans */ | ||
556 | flush_workqueue(ihost->scan_workq); | ||
533 | /* | 557 | /* |
534 | * If the session dropped while removing devices then we need to make | 558 | * If the session dropped while removing devices then we need to make |
535 | * sure it is not blocked | 559 | * sure it is not blocked |
536 | */ | 560 | */ |
537 | if (!cancel_delayed_work(&session->recovery_work)) | 561 | if (!cancel_delayed_work(&session->recovery_work)) |
538 | flush_workqueue(iscsi_eh_timer_workq); | 562 | flush_workqueue(iscsi_eh_timer_workq); |
539 | flush_workqueue(ihost->unbind_workq); | ||
540 | 563 | ||
541 | /* hw iscsi may not have removed all connections from session */ | 564 | /* hw iscsi may not have removed all connections from session */ |
542 | err = device_for_each_child(&session->dev, NULL, | 565 | err = device_for_each_child(&session->dev, NULL, |