aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r--drivers/scsi/scsi_scan.c49
1 files changed, 33 insertions, 16 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 94b86d5b1469..84f01fd0c8fd 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -349,6 +349,8 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
349 starget->channel = channel; 349 starget->channel = channel;
350 INIT_LIST_HEAD(&starget->siblings); 350 INIT_LIST_HEAD(&starget->siblings);
351 INIT_LIST_HEAD(&starget->devices); 351 INIT_LIST_HEAD(&starget->devices);
352 starget->state = STARGET_RUNNING;
353 retry:
352 spin_lock_irqsave(shost->host_lock, flags); 354 spin_lock_irqsave(shost->host_lock, flags);
353 355
354 found_target = __scsi_find_target(parent, channel, id); 356 found_target = __scsi_find_target(parent, channel, id);
@@ -381,8 +383,15 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
381 found_target->reap_ref++; 383 found_target->reap_ref++;
382 spin_unlock_irqrestore(shost->host_lock, flags); 384 spin_unlock_irqrestore(shost->host_lock, flags);
383 put_device(parent); 385 put_device(parent);
384 kfree(starget); 386 if (found_target->state != STARGET_DEL) {
385 return found_target; 387 kfree(starget);
388 return found_target;
389 }
390 /* Unfortunately, we found a dying target; need to
391 * wait until it's dead before we can get a new one */
392 put_device(&found_target->dev);
393 flush_scheduled_work();
394 goto retry;
386} 395}
387 396
388static void scsi_target_reap_usercontext(void *data) 397static void scsi_target_reap_usercontext(void *data)
@@ -391,21 +400,13 @@ static void scsi_target_reap_usercontext(void *data)
391 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 400 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
392 unsigned long flags; 401 unsigned long flags;
393 402
403 transport_remove_device(&starget->dev);
404 device_del(&starget->dev);
405 transport_destroy_device(&starget->dev);
394 spin_lock_irqsave(shost->host_lock, flags); 406 spin_lock_irqsave(shost->host_lock, flags);
395 407 list_del_init(&starget->siblings);
396 if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
397 list_del_init(&starget->siblings);
398 spin_unlock_irqrestore(shost->host_lock, flags);
399 transport_remove_device(&starget->dev);
400 device_del(&starget->dev);
401 transport_destroy_device(&starget->dev);
402 put_device(&starget->dev);
403 return;
404
405 }
406 spin_unlock_irqrestore(shost->host_lock, flags); 408 spin_unlock_irqrestore(shost->host_lock, flags);
407 409 put_device(&starget->dev);
408 return;
409} 410}
410 411
411/** 412/**
@@ -419,7 +420,23 @@ static void scsi_target_reap_usercontext(void *data)
419 */ 420 */
420void scsi_target_reap(struct scsi_target *starget) 421void scsi_target_reap(struct scsi_target *starget)
421{ 422{
422 scsi_execute_in_process_context(scsi_target_reap_usercontext, starget); 423 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
424 unsigned long flags;
425
426 spin_lock_irqsave(shost->host_lock, flags);
427
428 if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
429 BUG_ON(starget->state == STARGET_DEL);
430 starget->state = STARGET_DEL;
431 spin_unlock_irqrestore(shost->host_lock, flags);
432 execute_in_process_context(scsi_target_reap_usercontext,
433 starget, &starget->ew);
434 return;
435
436 }
437 spin_unlock_irqrestore(shost->host_lock, flags);
438
439 return;
423} 440}
424 441
425/** 442/**