diff options
-rw-r--r-- | drivers/scsi/scsi_transport_iscsi.c | 38 | ||||
-rw-r--r-- | include/scsi/scsi_transport_iscsi.h | 3 |
2 files changed, 37 insertions, 4 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index af88955d0ec1..af1799723e7b 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -127,6 +127,7 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, | |||
127 | memset(ihost, 0, sizeof(*ihost)); | 127 | memset(ihost, 0, sizeof(*ihost)); |
128 | INIT_LIST_HEAD(&ihost->sessions); | 128 | INIT_LIST_HEAD(&ihost->sessions); |
129 | mutex_init(&ihost->mutex); | 129 | mutex_init(&ihost->mutex); |
130 | atomic_set(&ihost->nr_scans, 0); | ||
130 | 131 | ||
131 | snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", | 132 | snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", |
132 | shost->host_no); | 133 | shost->host_no); |
@@ -284,6 +285,25 @@ static int iscsi_is_session_dev(const struct device *dev) | |||
284 | return dev->release == iscsi_session_release; | 285 | return dev->release == iscsi_session_release; |
285 | } | 286 | } |
286 | 287 | ||
288 | /** | ||
289 | * iscsi_scan_finished - helper to report when running scans are done | ||
290 | * @shost: scsi host | ||
291 | * @time: scan run time | ||
292 | * | ||
293 | * This function can be used by drives like qla4xxx to report to the scsi | ||
294 | * layer when the scans it kicked off at module load time are done. | ||
295 | */ | ||
296 | int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) | ||
297 | { | ||
298 | struct iscsi_host *ihost = shost->shost_data; | ||
299 | /* | ||
300 | * qla4xxx will have kicked off some session unblocks before calling | ||
301 | * scsi_scan_host, so just wait for them to complete. | ||
302 | */ | ||
303 | return !atomic_read(&ihost->nr_scans); | ||
304 | } | ||
305 | EXPORT_SYMBOL_GPL(iscsi_scan_finished); | ||
306 | |||
287 | static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, | 307 | static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, |
288 | uint id, uint lun) | 308 | uint id, uint lun) |
289 | { | 309 | { |
@@ -306,17 +326,21 @@ static void iscsi_scan_session(struct work_struct *work) | |||
306 | { | 326 | { |
307 | struct iscsi_cls_session *session = | 327 | struct iscsi_cls_session *session = |
308 | container_of(work, struct iscsi_cls_session, scan_work); | 328 | container_of(work, struct iscsi_cls_session, scan_work); |
329 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | ||
330 | struct iscsi_host *ihost = shost->shost_data; | ||
309 | unsigned long flags; | 331 | unsigned long flags; |
310 | 332 | ||
311 | spin_lock_irqsave(&session->lock, flags); | 333 | spin_lock_irqsave(&session->lock, flags); |
312 | if (session->state != ISCSI_SESSION_LOGGED_IN) { | 334 | if (session->state != ISCSI_SESSION_LOGGED_IN) { |
313 | spin_unlock_irqrestore(&session->lock, flags); | 335 | spin_unlock_irqrestore(&session->lock, flags); |
314 | return; | 336 | goto done; |
315 | } | 337 | } |
316 | spin_unlock_irqrestore(&session->lock, flags); | 338 | spin_unlock_irqrestore(&session->lock, flags); |
317 | 339 | ||
318 | scsi_scan_target(&session->dev, 0, session->target_id, | 340 | scsi_scan_target(&session->dev, 0, session->target_id, |
319 | SCAN_WILD_CARD, 1); | 341 | SCAN_WILD_CARD, 1); |
342 | done: | ||
343 | atomic_dec(&ihost->nr_scans); | ||
320 | } | 344 | } |
321 | 345 | ||
322 | static void session_recovery_timedout(struct work_struct *work) | 346 | static void session_recovery_timedout(struct work_struct *work) |
@@ -366,7 +390,15 @@ void iscsi_unblock_session(struct iscsi_cls_session *session) | |||
366 | spin_unlock_irqrestore(&session->lock, flags); | 390 | spin_unlock_irqrestore(&session->lock, flags); |
367 | 391 | ||
368 | __iscsi_unblock_session(session); | 392 | __iscsi_unblock_session(session); |
369 | queue_work(ihost->scan_workq, &session->scan_work); | 393 | /* |
394 | * Only do kernel scanning if the driver is properly hooked into | ||
395 | * the async scanning code (drivers like iscsi_tcp do login and | ||
396 | * scanning from userspace). | ||
397 | */ | ||
398 | if (shost->hostt->scan_finished) { | ||
399 | if (queue_work(ihost->scan_workq, &session->scan_work)) | ||
400 | atomic_inc(&ihost->nr_scans); | ||
401 | } | ||
370 | } | 402 | } |
371 | EXPORT_SYMBOL_GPL(iscsi_unblock_session); | 403 | EXPORT_SYMBOL_GPL(iscsi_unblock_session); |
372 | 404 | ||
@@ -550,7 +582,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session) | |||
550 | session->state = ISCSI_SESSION_FREE; | 582 | session->state = ISCSI_SESSION_FREE; |
551 | spin_unlock_irqrestore(&session->lock, flags); | 583 | spin_unlock_irqrestore(&session->lock, flags); |
552 | __iscsi_unblock_session(session); | 584 | __iscsi_unblock_session(session); |
553 | iscsi_unbind_session(session); | 585 | __iscsi_unbind_session(&session->unbind_work); |
554 | 586 | ||
555 | /* flush running scans */ | 587 | /* flush running scans */ |
556 | flush_workqueue(ihost->scan_workq); | 588 | flush_workqueue(ihost->scan_workq); |
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 1f0ec46b4f87..83693ba09c29 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h | |||
@@ -203,6 +203,7 @@ struct iscsi_cls_session { | |||
203 | 203 | ||
204 | struct iscsi_host { | 204 | struct iscsi_host { |
205 | struct list_head sessions; | 205 | struct list_head sessions; |
206 | atomic_t nr_scans; | ||
206 | struct mutex mutex; | 207 | struct mutex mutex; |
207 | struct workqueue_struct *scan_workq; | 208 | struct workqueue_struct *scan_workq; |
208 | char scan_workq_name[KOBJ_NAME_LEN]; | 209 | char scan_workq_name[KOBJ_NAME_LEN]; |
@@ -229,6 +230,6 @@ extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, | |||
229 | extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); | 230 | extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); |
230 | extern void iscsi_unblock_session(struct iscsi_cls_session *session); | 231 | extern void iscsi_unblock_session(struct iscsi_cls_session *session); |
231 | extern void iscsi_block_session(struct iscsi_cls_session *session); | 232 | extern void iscsi_block_session(struct iscsi_cls_session *session); |
232 | 233 | extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); | |
233 | 234 | ||
234 | #endif | 235 | #endif |