aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2008-03-22 23:42:27 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-04-22 16:16:31 -0400
commit643eb2d932c97a0583381629d632d486934cf7ee (patch)
tree514d860d8b6c22f50b8fdd7afd25047707321650
parentf7120a4f75168df3c02efacd10403a4ba0bcb29d (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.c72
-rw-r--r--drivers/scsi/scsi_sysfs.c27
-rw-r--r--include/scsi/scsi_device.h3
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
325static 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
325static void scsi_target_dev_release(struct device *dev) 340static 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
812static 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
812static struct device_attribute sdev_attr_queue_type_rw = 833static 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
183enum scsi_target_state { 183enum scsi_target_state {
184 STARGET_RUNNING = 1, 184 STARGET_CREATED = 1,
185 STARGET_RUNNING,
185 STARGET_DEL, 186 STARGET_DEL,
186}; 187};
187 188