diff options
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 84 |
1 files changed, 44 insertions, 40 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index e67c14e31bab..fcd7455ffc39 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -322,6 +322,21 @@ out: | |||
322 | return NULL; | 322 | return NULL; |
323 | } | 323 | } |
324 | 324 | ||
325 | static void scsi_target_destroy(struct scsi_target *starget) | ||
326 | { | ||
327 | struct device *dev = &starget->dev; | ||
328 | struct Scsi_Host *shost = dev_to_shost(dev->parent); | ||
329 | unsigned long flags; | ||
330 | |||
331 | transport_destroy_device(dev); | ||
332 | spin_lock_irqsave(shost->host_lock, flags); | ||
333 | if (shost->hostt->target_destroy) | ||
334 | shost->hostt->target_destroy(starget); | ||
335 | list_del_init(&starget->siblings); | ||
336 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
337 | put_device(dev); | ||
338 | } | ||
339 | |||
325 | static void scsi_target_dev_release(struct device *dev) | 340 | static void scsi_target_dev_release(struct device *dev) |
326 | { | 341 | { |
327 | struct device *parent = dev->parent; | 342 | struct device *parent = dev->parent; |
@@ -331,9 +346,14 @@ static void scsi_target_dev_release(struct device *dev) | |||
331 | put_device(parent); | 346 | put_device(parent); |
332 | } | 347 | } |
333 | 348 | ||
349 | struct device_type scsi_target_type = { | ||
350 | .name = "scsi_target", | ||
351 | .release = scsi_target_dev_release, | ||
352 | }; | ||
353 | |||
334 | int scsi_is_target_device(const struct device *dev) | 354 | int scsi_is_target_device(const struct device *dev) |
335 | { | 355 | { |
336 | return dev->release == scsi_target_dev_release; | 356 | return dev->type == &scsi_target_type; |
337 | } | 357 | } |
338 | EXPORT_SYMBOL(scsi_is_target_device); | 358 | EXPORT_SYMBOL(scsi_is_target_device); |
339 | 359 | ||
@@ -391,14 +411,17 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
391 | device_initialize(dev); | 411 | device_initialize(dev); |
392 | starget->reap_ref = 1; | 412 | starget->reap_ref = 1; |
393 | dev->parent = get_device(parent); | 413 | dev->parent = get_device(parent); |
394 | dev->release = scsi_target_dev_release; | ||
395 | sprintf(dev->bus_id, "target%d:%d:%d", | 414 | sprintf(dev->bus_id, "target%d:%d:%d", |
396 | shost->host_no, channel, id); | 415 | shost->host_no, channel, id); |
416 | #ifndef CONFIG_SYSFS_DEPRECATED | ||
417 | dev->bus = &scsi_bus_type; | ||
418 | #endif | ||
419 | dev->type = &scsi_target_type; | ||
397 | starget->id = id; | 420 | starget->id = id; |
398 | starget->channel = channel; | 421 | starget->channel = channel; |
399 | INIT_LIST_HEAD(&starget->siblings); | 422 | INIT_LIST_HEAD(&starget->siblings); |
400 | INIT_LIST_HEAD(&starget->devices); | 423 | INIT_LIST_HEAD(&starget->devices); |
401 | starget->state = STARGET_RUNNING; | 424 | starget->state = STARGET_CREATED; |
402 | starget->scsi_level = SCSI_2; | 425 | starget->scsi_level = SCSI_2; |
403 | retry: | 426 | retry: |
404 | spin_lock_irqsave(shost->host_lock, flags); | 427 | spin_lock_irqsave(shost->host_lock, flags); |
@@ -411,18 +434,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
411 | spin_unlock_irqrestore(shost->host_lock, flags); | 434 | spin_unlock_irqrestore(shost->host_lock, flags); |
412 | /* allocate and add */ | 435 | /* allocate and add */ |
413 | transport_setup_device(dev); | 436 | transport_setup_device(dev); |
414 | error = device_add(dev); | ||
415 | if (error) { | ||
416 | dev_err(dev, "target device_add failed, error %d\n", error); | ||
417 | spin_lock_irqsave(shost->host_lock, flags); | ||
418 | list_del_init(&starget->siblings); | ||
419 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
420 | transport_destroy_device(dev); | ||
421 | put_device(parent); | ||
422 | kfree(starget); | ||
423 | return NULL; | ||
424 | } | ||
425 | transport_add_device(dev); | ||
426 | if (shost->hostt->target_alloc) { | 437 | if (shost->hostt->target_alloc) { |
427 | error = shost->hostt->target_alloc(starget); | 438 | error = shost->hostt->target_alloc(starget); |
428 | 439 | ||
@@ -430,9 +441,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
430 | dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error); | 441 | dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error); |
431 | /* don't want scsi_target_reap to do the final | 442 | /* don't want scsi_target_reap to do the final |
432 | * put because it will be under the host lock */ | 443 | * put because it will be under the host lock */ |
433 | get_device(dev); | 444 | scsi_target_destroy(starget); |
434 | scsi_target_reap(starget); | ||
435 | put_device(dev); | ||
436 | return NULL; | 445 | return NULL; |
437 | } | 446 | } |
438 | } | 447 | } |
@@ -459,18 +468,10 @@ static void scsi_target_reap_usercontext(struct work_struct *work) | |||
459 | { | 468 | { |
460 | struct scsi_target *starget = | 469 | struct scsi_target *starget = |
461 | container_of(work, struct scsi_target, ew.work); | 470 | container_of(work, struct scsi_target, ew.work); |
462 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
463 | unsigned long flags; | ||
464 | 471 | ||
465 | transport_remove_device(&starget->dev); | 472 | transport_remove_device(&starget->dev); |
466 | device_del(&starget->dev); | 473 | device_del(&starget->dev); |
467 | transport_destroy_device(&starget->dev); | 474 | scsi_target_destroy(starget); |
468 | spin_lock_irqsave(shost->host_lock, flags); | ||
469 | if (shost->hostt->target_destroy) | ||
470 | shost->hostt->target_destroy(starget); | ||
471 | list_del_init(&starget->siblings); | ||
472 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
473 | put_device(&starget->dev); | ||
474 | } | 475 | } |
475 | 476 | ||
476 | /** | 477 | /** |
@@ -485,21 +486,25 @@ void scsi_target_reap(struct scsi_target *starget) | |||
485 | { | 486 | { |
486 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 487 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
487 | unsigned long flags; | 488 | unsigned long flags; |
489 | enum scsi_target_state state; | ||
490 | int empty; | ||
488 | 491 | ||
489 | spin_lock_irqsave(shost->host_lock, flags); | 492 | spin_lock_irqsave(shost->host_lock, flags); |
493 | state = starget->state; | ||
494 | empty = --starget->reap_ref == 0 && | ||
495 | list_empty(&starget->devices) ? 1 : 0; | ||
496 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
490 | 497 | ||
491 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | 498 | if (!empty) |
492 | BUG_ON(starget->state == STARGET_DEL); | ||
493 | starget->state = STARGET_DEL; | ||
494 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
495 | execute_in_process_context(scsi_target_reap_usercontext, | ||
496 | &starget->ew); | ||
497 | return; | 499 | return; |
498 | 500 | ||
499 | } | 501 | BUG_ON(state == STARGET_DEL); |
500 | spin_unlock_irqrestore(shost->host_lock, flags); | 502 | starget->state = STARGET_DEL; |
501 | 503 | if (state == STARGET_CREATED) | |
502 | return; | 504 | scsi_target_destroy(starget); |
505 | else | ||
506 | execute_in_process_context(scsi_target_reap_usercontext, | ||
507 | &starget->ew); | ||
503 | } | 508 | } |
504 | 509 | ||
505 | /** | 510 | /** |
@@ -1048,8 +1053,9 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, | |||
1048 | scsi_inq_str(vend, result, 8, 16), | 1053 | scsi_inq_str(vend, result, 8, 16), |
1049 | scsi_inq_str(mod, result, 16, 32)); | 1054 | scsi_inq_str(mod, result, 16, 32)); |
1050 | }); | 1055 | }); |
1056 | |||
1051 | } | 1057 | } |
1052 | 1058 | ||
1053 | res = SCSI_SCAN_TARGET_PRESENT; | 1059 | res = SCSI_SCAN_TARGET_PRESENT; |
1054 | goto out_free_result; | 1060 | goto out_free_result; |
1055 | } | 1061 | } |
@@ -1489,7 +1495,6 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, | |||
1489 | if (scsi_host_scan_allowed(shost)) | 1495 | if (scsi_host_scan_allowed(shost)) |
1490 | scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); | 1496 | scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); |
1491 | mutex_unlock(&shost->scan_mutex); | 1497 | mutex_unlock(&shost->scan_mutex); |
1492 | transport_configure_device(&starget->dev); | ||
1493 | scsi_target_reap(starget); | 1498 | scsi_target_reap(starget); |
1494 | put_device(&starget->dev); | 1499 | put_device(&starget->dev); |
1495 | 1500 | ||
@@ -1570,7 +1575,6 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, | |||
1570 | out_reap: | 1575 | out_reap: |
1571 | /* now determine if the target has any children at all | 1576 | /* now determine if the target has any children at all |
1572 | * and if not, nuke it */ | 1577 | * and if not, nuke it */ |
1573 | transport_configure_device(&starget->dev); | ||
1574 | scsi_target_reap(starget); | 1578 | scsi_target_reap(starget); |
1575 | 1579 | ||
1576 | put_device(&starget->dev); | 1580 | put_device(&starget->dev); |