diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-03-22 23:42:27 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-04-22 16:16:31 -0400 |
commit | 643eb2d932c97a0583381629d632d486934cf7ee (patch) | |
tree | 514d860d8b6c22f50b8fdd7afd25047707321650 | |
parent | f7120a4f75168df3c02efacd10403a4ba0bcb29d (diff) |
[SCSI] rework scsi_target allocation
The current target allocation code registeres each possible target
with sysfs; it will be deleted again if no useable LUN on this target
was found. This results in a string of 'target add/target remove' uevents.
Based on a patch by Hannes Reinecke <hare@suse.de> this patch reworks
the target allocation code so that only uevents for existing targets
are sent. The sysfs registration is split off from the existing
scsi_target_alloc() into a in a new scsi_add_target() function, which
should be called whenever an existing target is found. Only then a
uevent is sent, so we'll be generating events for existing targets
only.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/scsi_scan.c | 72 | ||||
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 27 | ||||
-rw-r--r-- | include/scsi/scsi_device.h | 3 |
3 files changed, 63 insertions, 39 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index e1644b270cdc..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; |
@@ -406,7 +421,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
406 | starget->channel = channel; | 421 | starget->channel = channel; |
407 | INIT_LIST_HEAD(&starget->siblings); | 422 | INIT_LIST_HEAD(&starget->siblings); |
408 | INIT_LIST_HEAD(&starget->devices); | 423 | INIT_LIST_HEAD(&starget->devices); |
409 | starget->state = STARGET_RUNNING; | 424 | starget->state = STARGET_CREATED; |
410 | starget->scsi_level = SCSI_2; | 425 | starget->scsi_level = SCSI_2; |
411 | retry: | 426 | retry: |
412 | spin_lock_irqsave(shost->host_lock, flags); | 427 | spin_lock_irqsave(shost->host_lock, flags); |
@@ -419,18 +434,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
419 | spin_unlock_irqrestore(shost->host_lock, flags); | 434 | spin_unlock_irqrestore(shost->host_lock, flags); |
420 | /* allocate and add */ | 435 | /* allocate and add */ |
421 | transport_setup_device(dev); | 436 | transport_setup_device(dev); |
422 | error = device_add(dev); | ||
423 | if (error) { | ||
424 | dev_err(dev, "target device_add failed, error %d\n", error); | ||
425 | spin_lock_irqsave(shost->host_lock, flags); | ||
426 | list_del_init(&starget->siblings); | ||
427 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
428 | transport_destroy_device(dev); | ||
429 | put_device(parent); | ||
430 | kfree(starget); | ||
431 | return NULL; | ||
432 | } | ||
433 | transport_add_device(dev); | ||
434 | if (shost->hostt->target_alloc) { | 437 | if (shost->hostt->target_alloc) { |
435 | error = shost->hostt->target_alloc(starget); | 438 | error = shost->hostt->target_alloc(starget); |
436 | 439 | ||
@@ -438,9 +441,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
438 | 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); |
439 | /* don't want scsi_target_reap to do the final | 442 | /* don't want scsi_target_reap to do the final |
440 | * put because it will be under the host lock */ | 443 | * put because it will be under the host lock */ |
441 | get_device(dev); | 444 | scsi_target_destroy(starget); |
442 | scsi_target_reap(starget); | ||
443 | put_device(dev); | ||
444 | return NULL; | 445 | return NULL; |
445 | } | 446 | } |
446 | } | 447 | } |
@@ -467,18 +468,10 @@ static void scsi_target_reap_usercontext(struct work_struct *work) | |||
467 | { | 468 | { |
468 | struct scsi_target *starget = | 469 | struct scsi_target *starget = |
469 | container_of(work, struct scsi_target, ew.work); | 470 | container_of(work, struct scsi_target, ew.work); |
470 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
471 | unsigned long flags; | ||
472 | 471 | ||
473 | transport_remove_device(&starget->dev); | 472 | transport_remove_device(&starget->dev); |
474 | device_del(&starget->dev); | 473 | device_del(&starget->dev); |
475 | transport_destroy_device(&starget->dev); | 474 | scsi_target_destroy(starget); |
476 | spin_lock_irqsave(shost->host_lock, flags); | ||
477 | if (shost->hostt->target_destroy) | ||
478 | shost->hostt->target_destroy(starget); | ||
479 | list_del_init(&starget->siblings); | ||
480 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
481 | put_device(&starget->dev); | ||
482 | } | 475 | } |
483 | 476 | ||
484 | /** | 477 | /** |
@@ -493,21 +486,25 @@ void scsi_target_reap(struct scsi_target *starget) | |||
493 | { | 486 | { |
494 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 487 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
495 | unsigned long flags; | 488 | unsigned long flags; |
489 | enum scsi_target_state state; | ||
490 | int empty; | ||
496 | 491 | ||
497 | 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); | ||
498 | 497 | ||
499 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | 498 | if (!empty) |
500 | BUG_ON(starget->state == STARGET_DEL); | ||
501 | starget->state = STARGET_DEL; | ||
502 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
503 | execute_in_process_context(scsi_target_reap_usercontext, | ||
504 | &starget->ew); | ||
505 | return; | 499 | return; |
506 | 500 | ||
507 | } | 501 | BUG_ON(state == STARGET_DEL); |
508 | spin_unlock_irqrestore(shost->host_lock, flags); | 502 | starget->state = STARGET_DEL; |
509 | 503 | if (state == STARGET_CREATED) | |
510 | return; | 504 | scsi_target_destroy(starget); |
505 | else | ||
506 | execute_in_process_context(scsi_target_reap_usercontext, | ||
507 | &starget->ew); | ||
511 | } | 508 | } |
512 | 509 | ||
513 | /** | 510 | /** |
@@ -1056,8 +1053,9 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, | |||
1056 | scsi_inq_str(vend, result, 8, 16), | 1053 | scsi_inq_str(vend, result, 8, 16), |
1057 | scsi_inq_str(mod, result, 16, 32)); | 1054 | scsi_inq_str(mod, result, 16, 32)); |
1058 | }); | 1055 | }); |
1056 | |||
1059 | } | 1057 | } |
1060 | 1058 | ||
1061 | res = SCSI_SCAN_TARGET_PRESENT; | 1059 | res = SCSI_SCAN_TARGET_PRESENT; |
1062 | goto out_free_result; | 1060 | goto out_free_result; |
1063 | } | 1061 | } |
@@ -1497,7 +1495,6 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, | |||
1497 | if (scsi_host_scan_allowed(shost)) | 1495 | if (scsi_host_scan_allowed(shost)) |
1498 | scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); | 1496 | scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); |
1499 | mutex_unlock(&shost->scan_mutex); | 1497 | mutex_unlock(&shost->scan_mutex); |
1500 | transport_configure_device(&starget->dev); | ||
1501 | scsi_target_reap(starget); | 1498 | scsi_target_reap(starget); |
1502 | put_device(&starget->dev); | 1499 | put_device(&starget->dev); |
1503 | 1500 | ||
@@ -1578,7 +1575,6 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, | |||
1578 | out_reap: | 1575 | out_reap: |
1579 | /* now determine if the target has any children at all | 1576 | /* now determine if the target has any children at all |
1580 | * and if not, nuke it */ | 1577 | * and if not, nuke it */ |
1581 | transport_configure_device(&starget->dev); | ||
1582 | scsi_target_reap(starget); | 1578 | scsi_target_reap(starget); |
1583 | 1579 | ||
1584 | put_device(&starget->dev); | 1580 | put_device(&starget->dev); |
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 84e2a8ad83c9..198aa4571e35 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -809,6 +809,27 @@ sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr, | |||
809 | return count; | 809 | return count; |
810 | } | 810 | } |
811 | 811 | ||
812 | static int scsi_target_add(struct scsi_target *starget) | ||
813 | { | ||
814 | int error; | ||
815 | |||
816 | if (starget->state != STARGET_CREATED) | ||
817 | return 0; | ||
818 | |||
819 | error = device_add(&starget->dev); | ||
820 | if (error) { | ||
821 | dev_err(&starget->dev, "target device_add failed, error %d\n", error); | ||
822 | get_device(&starget->dev); | ||
823 | scsi_target_reap(starget); | ||
824 | put_device(&starget->dev); | ||
825 | return error; | ||
826 | } | ||
827 | transport_add_device(&starget->dev); | ||
828 | starget->state = STARGET_RUNNING; | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
812 | static struct device_attribute sdev_attr_queue_type_rw = | 833 | static struct device_attribute sdev_attr_queue_type_rw = |
813 | __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, | 834 | __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, |
814 | sdev_store_queue_type_rw); | 835 | sdev_store_queue_type_rw); |
@@ -824,10 +845,16 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
824 | { | 845 | { |
825 | int error, i; | 846 | int error, i; |
826 | struct request_queue *rq = sdev->request_queue; | 847 | struct request_queue *rq = sdev->request_queue; |
848 | struct scsi_target *starget = sdev->sdev_target; | ||
827 | 849 | ||
828 | if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0) | 850 | if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0) |
829 | return error; | 851 | return error; |
830 | 852 | ||
853 | error = scsi_target_add(starget); | ||
854 | if (error) | ||
855 | return error; | ||
856 | |||
857 | transport_configure_device(&starget->dev); | ||
831 | error = device_add(&sdev->sdev_gendev); | 858 | error = device_add(&sdev->sdev_gendev); |
832 | if (error) { | 859 | if (error) { |
833 | put_device(sdev->sdev_gendev.parent); | 860 | put_device(sdev->sdev_gendev.parent); |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index b8b19e2f57bb..f6a9fe0ef09c 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
@@ -181,7 +181,8 @@ struct scsi_device { | |||
181 | sdev_printk(prefix, (scmd)->device, fmt, ##a) | 181 | sdev_printk(prefix, (scmd)->device, fmt, ##a) |
182 | 182 | ||
183 | enum scsi_target_state { | 183 | enum scsi_target_state { |
184 | STARGET_RUNNING = 1, | 184 | STARGET_CREATED = 1, |
185 | STARGET_RUNNING, | ||
185 | STARGET_DEL, | 186 | STARGET_DEL, |
186 | }; | 187 | }; |
187 | 188 | ||