aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c38
-rw-r--r--include/scsi/scsi_transport_iscsi.h3
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 */
296int 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}
305EXPORT_SYMBOL_GPL(iscsi_scan_finished);
306
287static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, 307static 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);
342done:
343 atomic_dec(&ihost->nr_scans);
320} 344}
321 345
322static void session_recovery_timedout(struct work_struct *work) 346static 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}
371EXPORT_SYMBOL_GPL(iscsi_unblock_session); 403EXPORT_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
204struct iscsi_host { 204struct 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,
229extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); 230extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
230extern void iscsi_unblock_session(struct iscsi_cls_session *session); 231extern void iscsi_unblock_session(struct iscsi_cls_session *session);
231extern void iscsi_block_session(struct iscsi_cls_session *session); 232extern void iscsi_block_session(struct iscsi_cls_session *session);
232 233extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time);
233 234
234#endif 235#endif