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 |
