diff options
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 374853df9cca..4e6709f448e1 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -266,8 +266,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, | |||
266 | /* | 266 | /* |
267 | * if LLDD reports slave not present, don't clutter | 267 | * if LLDD reports slave not present, don't clutter |
268 | * console with alloc failure messages | 268 | * console with alloc failure messages |
269 | |||
270 | |||
271 | */ | 269 | */ |
272 | if (ret == -ENXIO) | 270 | if (ret == -ENXIO) |
273 | display_failure_msg = 0; | 271 | display_failure_msg = 0; |
@@ -279,7 +277,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, | |||
279 | 277 | ||
280 | out_device_destroy: | 278 | out_device_destroy: |
281 | transport_destroy_device(&sdev->sdev_gendev); | 279 | transport_destroy_device(&sdev->sdev_gendev); |
282 | scsi_free_queue(sdev->request_queue); | ||
283 | put_device(&sdev->sdev_gendev); | 280 | put_device(&sdev->sdev_gendev); |
284 | out: | 281 | out: |
285 | if (display_failure_msg) | 282 | if (display_failure_msg) |
@@ -403,6 +400,36 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
403 | return found_target; | 400 | return found_target; |
404 | } | 401 | } |
405 | 402 | ||
403 | struct work_queue_wrapper { | ||
404 | struct work_struct work; | ||
405 | struct scsi_target *starget; | ||
406 | }; | ||
407 | |||
408 | static void scsi_target_reap_work(void *data) { | ||
409 | struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; | ||
410 | struct scsi_target *starget = wqw->starget; | ||
411 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
412 | unsigned long flags; | ||
413 | |||
414 | kfree(wqw); | ||
415 | |||
416 | spin_lock_irqsave(shost->host_lock, flags); | ||
417 | |||
418 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | ||
419 | list_del_init(&starget->siblings); | ||
420 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
421 | transport_remove_device(&starget->dev); | ||
422 | device_del(&starget->dev); | ||
423 | transport_destroy_device(&starget->dev); | ||
424 | put_device(&starget->dev); | ||
425 | return; | ||
426 | |||
427 | } | ||
428 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
429 | |||
430 | return; | ||
431 | } | ||
432 | |||
406 | /** | 433 | /** |
407 | * scsi_target_reap - check to see if target is in use and destroy if not | 434 | * scsi_target_reap - check to see if target is in use and destroy if not |
408 | * | 435 | * |
@@ -414,19 +441,18 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
414 | */ | 441 | */ |
415 | void scsi_target_reap(struct scsi_target *starget) | 442 | void scsi_target_reap(struct scsi_target *starget) |
416 | { | 443 | { |
417 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 444 | struct work_queue_wrapper *wqw = |
418 | unsigned long flags; | 445 | kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); |
419 | spin_lock_irqsave(shost->host_lock, flags); | ||
420 | 446 | ||
421 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | 447 | if (!wqw) { |
422 | list_del_init(&starget->siblings); | 448 | starget_printk(KERN_ERR, starget, |
423 | spin_unlock_irqrestore(shost->host_lock, flags); | 449 | "Failed to allocate memory in scsi_reap_target()\n"); |
424 | device_del(&starget->dev); | ||
425 | transport_unregister_device(&starget->dev); | ||
426 | put_device(&starget->dev); | ||
427 | return; | 450 | return; |
428 | } | 451 | } |
429 | spin_unlock_irqrestore(shost->host_lock, flags); | 452 | |
453 | INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); | ||
454 | wqw->starget = starget; | ||
455 | schedule_work(&wqw->work); | ||
430 | } | 456 | } |
431 | 457 | ||
432 | /** | 458 | /** |