diff options
author | Christoph Hellwig <hch@lst.de> | 2006-01-13 13:04:00 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2006-01-14 11:55:05 -0500 |
commit | e02f3f59225d8c3b2a0ad0dc941a09865e27da61 (patch) | |
tree | 37d2931f5d24dc063d9606ec6b5e8db359b439c7 /drivers/scsi | |
parent | 6d5b0c315e0c14f8a0fe274eda7676d62cbd8584 (diff) |
[SCSI] remove target parent limitiation
When James Smart fixed the issue of the userspace scan atributes
crashing the system with the FC transport class he added a patch to
let the transport class check if the parent is valid for a given
transport class.
When adding support for the integrated raid of fusion sas devices
we ran into a problem with that, as it didn't allow adding virtual
raid volumes without the transport class knowing about it.
So this patch adds a user_scan attribute instead, that takes over from
scsi_scan_host_selected if the transport class sets it and thus lets
the transport class control the user-initiated scanning. As this
plugs the hole about user-initiated scanning the target_parent hook
goes away and we rely on callers of the scanning routines to do
something sensible.
For SAS this meant I had to switch from a spinlock to a mutex to
synchronize the topology linked lists, in FC they were completely
unsynchronized which seems wrong.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi_priv.h | 6 | ||||
-rw-r--r-- | drivers/scsi/scsi_proc.c | 6 | ||||
-rw-r--r-- | drivers/scsi/scsi_scan.c | 16 | ||||
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 5 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 22 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 42 |
6 files changed, 49 insertions, 48 deletions
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 14a6198cb8d2..27c48274e8cb 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
@@ -26,12 +26,6 @@ struct Scsi_Host; | |||
26 | #define SCSI_SENSE_VALID(scmd) \ | 26 | #define SCSI_SENSE_VALID(scmd) \ |
27 | (((scmd)->sense_buffer[0] & 0x70) == 0x70) | 27 | (((scmd)->sense_buffer[0] & 0x70) == 0x70) |
28 | 28 | ||
29 | /* | ||
30 | * Special value for scanning to specify scanning or rescanning of all | ||
31 | * possible channels, (target) ids, or luns on a given shost. | ||
32 | */ | ||
33 | #define SCAN_WILD_CARD ~0 | ||
34 | |||
35 | /* hosts.c */ | 29 | /* hosts.c */ |
36 | extern int scsi_init_hosts(void); | 30 | extern int scsi_init_hosts(void); |
37 | extern void scsi_exit_hosts(void); | 31 | extern void scsi_exit_hosts(void); |
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 1b5711e714a5..07be62bbaaea 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <scsi/scsi.h> | 31 | #include <scsi/scsi.h> |
32 | #include <scsi/scsi_device.h> | 32 | #include <scsi/scsi_device.h> |
33 | #include <scsi/scsi_host.h> | 33 | #include <scsi/scsi_host.h> |
34 | #include <scsi/scsi_transport.h> | ||
34 | 35 | ||
35 | #include "scsi_priv.h" | 36 | #include "scsi_priv.h" |
36 | #include "scsi_logging.h" | 37 | #include "scsi_logging.h" |
@@ -200,7 +201,10 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) | |||
200 | if (IS_ERR(shost)) | 201 | if (IS_ERR(shost)) |
201 | return PTR_ERR(shost); | 202 | return PTR_ERR(shost); |
202 | 203 | ||
203 | error = scsi_scan_host_selected(shost, channel, id, lun, 1); | 204 | if (shost->transportt->user_scan) |
205 | error = shost->transportt->user_scan(shost, channel, id, lun); | ||
206 | else | ||
207 | error = scsi_scan_host_selected(shost, channel, id, lun, 1); | ||
204 | scsi_host_put(shost); | 208 | scsi_host_put(shost); |
205 | return error; | 209 | return error; |
206 | } | 210 | } |
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index edcd80b749c1..752fb5da3de4 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -334,19 +334,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
334 | struct scsi_target *starget; | 334 | struct scsi_target *starget; |
335 | struct scsi_target *found_target; | 335 | struct scsi_target *found_target; |
336 | 336 | ||
337 | /* | ||
338 | * Obtain the real parent from the transport. The transport | ||
339 | * is allowed to fail (no error) if there is nothing at that | ||
340 | * target id. | ||
341 | */ | ||
342 | if (shost->transportt->target_parent) { | ||
343 | spin_lock_irqsave(shost->host_lock, flags); | ||
344 | parent = shost->transportt->target_parent(shost, channel, id); | ||
345 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
346 | if (!parent) | ||
347 | return NULL; | ||
348 | } | ||
349 | |||
350 | starget = kmalloc(size, GFP_KERNEL); | 337 | starget = kmalloc(size, GFP_KERNEL); |
351 | if (!starget) { | 338 | if (!starget) { |
352 | printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__); | 339 | printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__); |
@@ -1283,8 +1270,9 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, | |||
1283 | struct scsi_device *sdev; | 1270 | struct scsi_device *sdev; |
1284 | struct device *parent = &shost->shost_gendev; | 1271 | struct device *parent = &shost->shost_gendev; |
1285 | int res; | 1272 | int res; |
1286 | struct scsi_target *starget = scsi_alloc_target(parent, channel, id); | 1273 | struct scsi_target *starget; |
1287 | 1274 | ||
1275 | starget = scsi_alloc_target(parent, channel, id); | ||
1288 | if (!starget) | 1276 | if (!starget) |
1289 | return ERR_PTR(-ENOMEM); | 1277 | return ERR_PTR(-ENOMEM); |
1290 | 1278 | ||
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 2cb962751a7e..a77b32deaf8f 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -106,7 +106,10 @@ static int scsi_scan(struct Scsi_Host *shost, const char *str) | |||
106 | return -EINVAL; | 106 | return -EINVAL; |
107 | if (check_set(&lun, s3)) | 107 | if (check_set(&lun, s3)) |
108 | return -EINVAL; | 108 | return -EINVAL; |
109 | res = scsi_scan_host_selected(shost, channel, id, lun, 1); | 109 | if (shost->transportt->user_scan) |
110 | res = shost->transportt->user_scan(shost, channel, id, lun); | ||
111 | else | ||
112 | res = scsi_scan_host_selected(shost, channel, id, lun, 1); | ||
110 | return res; | 113 | return res; |
111 | } | 114 | } |
112 | 115 | ||
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 625f4a664d06..f2c9acf11bd0 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
@@ -1093,17 +1093,23 @@ static int fc_rport_match(struct attribute_container *cont, | |||
1093 | /* | 1093 | /* |
1094 | * Must be called with shost->host_lock held | 1094 | * Must be called with shost->host_lock held |
1095 | */ | 1095 | */ |
1096 | static struct device *fc_target_parent(struct Scsi_Host *shost, | 1096 | static int fc_user_scan(struct Scsi_Host *shost, uint channel, |
1097 | int channel, uint id) | 1097 | uint id, uint lun) |
1098 | { | 1098 | { |
1099 | struct fc_rport *rport; | 1099 | struct fc_rport *rport; |
1100 | 1100 | ||
1101 | list_for_each_entry(rport, &fc_host_rports(shost), peers) | 1101 | list_for_each_entry(rport, &fc_host_rports(shost), peers) { |
1102 | if ((rport->channel == channel) && | 1102 | if (rport->scsi_target_id == -1) |
1103 | (rport->scsi_target_id == id)) | 1103 | continue; |
1104 | return &rport->dev; | ||
1105 | 1104 | ||
1106 | return NULL; | 1105 | if ((channel == SCAN_WILD_CARD || channel == rport->channel) && |
1106 | (id == SCAN_WILD_CARD || id == rport->scsi_target_id)) { | ||
1107 | scsi_scan_target(&rport->dev, rport->channel, | ||
1108 | rport->scsi_target_id, lun, 1); | ||
1109 | } | ||
1110 | } | ||
1111 | |||
1112 | return 0; | ||
1107 | } | 1113 | } |
1108 | 1114 | ||
1109 | struct scsi_transport_template * | 1115 | struct scsi_transport_template * |
@@ -1142,7 +1148,7 @@ fc_attach_transport(struct fc_function_template *ft) | |||
1142 | /* Transport uses the shost workq for scsi scanning */ | 1148 | /* Transport uses the shost workq for scsi scanning */ |
1143 | i->t.create_work_queue = 1; | 1149 | i->t.create_work_queue = 1; |
1144 | 1150 | ||
1145 | i->t.target_parent = fc_target_parent; | 1151 | i->t.user_scan = fc_user_scan; |
1146 | 1152 | ||
1147 | /* | 1153 | /* |
1148 | * Setup SCSI Target Attributes. | 1154 | * Setup SCSI Target Attributes. |
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index e950435a11d8..fb6641b42dfa 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/string.h> | 30 | #include <linux/string.h> |
31 | 31 | ||
32 | #include <scsi/scsi.h> | ||
32 | #include <scsi/scsi_device.h> | 33 | #include <scsi/scsi_device.h> |
33 | #include <scsi/scsi_host.h> | 34 | #include <scsi/scsi_host.h> |
34 | #include <scsi/scsi_transport.h> | 35 | #include <scsi/scsi_transport.h> |
@@ -62,7 +63,7 @@ struct sas_internal { | |||
62 | 63 | ||
63 | struct sas_host_attrs { | 64 | struct sas_host_attrs { |
64 | struct list_head rphy_list; | 65 | struct list_head rphy_list; |
65 | spinlock_t lock; | 66 | struct mutex lock; |
66 | u32 next_target_id; | 67 | u32 next_target_id; |
67 | }; | 68 | }; |
68 | #define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) | 69 | #define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) |
@@ -165,7 +166,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev, | |||
165 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); | 166 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); |
166 | 167 | ||
167 | INIT_LIST_HEAD(&sas_host->rphy_list); | 168 | INIT_LIST_HEAD(&sas_host->rphy_list); |
168 | spin_lock_init(&sas_host->lock); | 169 | mutex_init(&sas_host->lock); |
169 | sas_host->next_target_id = 0; | 170 | sas_host->next_target_id = 0; |
170 | return 0; | 171 | return 0; |
171 | } | 172 | } |
@@ -626,7 +627,7 @@ int sas_rphy_add(struct sas_rphy *rphy) | |||
626 | transport_add_device(&rphy->dev); | 627 | transport_add_device(&rphy->dev); |
627 | transport_configure_device(&rphy->dev); | 628 | transport_configure_device(&rphy->dev); |
628 | 629 | ||
629 | spin_lock(&sas_host->lock); | 630 | mutex_lock(&sas_host->lock); |
630 | list_add_tail(&rphy->list, &sas_host->rphy_list); | 631 | list_add_tail(&rphy->list, &sas_host->rphy_list); |
631 | if (identify->device_type == SAS_END_DEVICE && | 632 | if (identify->device_type == SAS_END_DEVICE && |
632 | (identify->target_port_protocols & | 633 | (identify->target_port_protocols & |
@@ -634,7 +635,7 @@ int sas_rphy_add(struct sas_rphy *rphy) | |||
634 | rphy->scsi_target_id = sas_host->next_target_id++; | 635 | rphy->scsi_target_id = sas_host->next_target_id++; |
635 | else | 636 | else |
636 | rphy->scsi_target_id = -1; | 637 | rphy->scsi_target_id = -1; |
637 | spin_unlock(&sas_host->lock); | 638 | mutex_unlock(&sas_host->lock); |
638 | 639 | ||
639 | if (rphy->scsi_target_id != -1) { | 640 | if (rphy->scsi_target_id != -1) { |
640 | scsi_scan_target(&rphy->dev, parent->number, | 641 | scsi_scan_target(&rphy->dev, parent->number, |
@@ -661,9 +662,9 @@ void sas_rphy_free(struct sas_rphy *rphy) | |||
661 | struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); | 662 | struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); |
662 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); | 663 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); |
663 | 664 | ||
664 | spin_lock(&sas_host->lock); | 665 | mutex_lock(&sas_host->lock); |
665 | list_del(&rphy->list); | 666 | list_del(&rphy->list); |
666 | spin_unlock(&sas_host->lock); | 667 | mutex_unlock(&sas_host->lock); |
667 | 668 | ||
668 | transport_destroy_device(&rphy->dev); | 669 | transport_destroy_device(&rphy->dev); |
669 | put_device(rphy->dev.parent); | 670 | put_device(rphy->dev.parent); |
@@ -703,9 +704,9 @@ sas_rphy_delete(struct sas_rphy *rphy) | |||
703 | device_del(dev); | 704 | device_del(dev); |
704 | transport_destroy_device(dev); | 705 | transport_destroy_device(dev); |
705 | 706 | ||
706 | spin_lock(&sas_host->lock); | 707 | mutex_lock(&sas_host->lock); |
707 | list_del(&rphy->list); | 708 | list_del(&rphy->list); |
708 | spin_unlock(&sas_host->lock); | 709 | mutex_unlock(&sas_host->lock); |
709 | 710 | ||
710 | parent->rphy = NULL; | 711 | parent->rphy = NULL; |
711 | 712 | ||
@@ -731,23 +732,28 @@ EXPORT_SYMBOL(scsi_is_sas_rphy); | |||
731 | * SCSI scan helper | 732 | * SCSI scan helper |
732 | */ | 733 | */ |
733 | 734 | ||
734 | static struct device *sas_target_parent(struct Scsi_Host *shost, | 735 | static int sas_user_scan(struct Scsi_Host *shost, uint channel, |
735 | int channel, uint id) | 736 | uint id, uint lun) |
736 | { | 737 | { |
737 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); | 738 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); |
738 | struct sas_rphy *rphy; | 739 | struct sas_rphy *rphy; |
739 | struct device *dev = NULL; | ||
740 | 740 | ||
741 | spin_lock(&sas_host->lock); | 741 | mutex_lock(&sas_host->lock); |
742 | list_for_each_entry(rphy, &sas_host->rphy_list, list) { | 742 | list_for_each_entry(rphy, &sas_host->rphy_list, list) { |
743 | struct sas_phy *parent = dev_to_phy(rphy->dev.parent); | 743 | struct sas_phy *parent = dev_to_phy(rphy->dev.parent); |
744 | if (parent->number == channel && | 744 | |
745 | rphy->scsi_target_id == id) | 745 | if (rphy->scsi_target_id == -1) |
746 | dev = &rphy->dev; | 746 | continue; |
747 | |||
748 | if ((channel == SCAN_WILD_CARD || channel == parent->number) && | ||
749 | (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { | ||
750 | scsi_scan_target(&rphy->dev, parent->number, | ||
751 | rphy->scsi_target_id, lun, 1); | ||
752 | } | ||
747 | } | 753 | } |
748 | spin_unlock(&sas_host->lock); | 754 | mutex_unlock(&sas_host->lock); |
749 | 755 | ||
750 | return dev; | 756 | return 0; |
751 | } | 757 | } |
752 | 758 | ||
753 | 759 | ||
@@ -792,7 +798,7 @@ sas_attach_transport(struct sas_function_template *ft) | |||
792 | return NULL; | 798 | return NULL; |
793 | memset(i, 0, sizeof(struct sas_internal)); | 799 | memset(i, 0, sizeof(struct sas_internal)); |
794 | 800 | ||
795 | i->t.target_parent = sas_target_parent; | 801 | i->t.user_scan = sas_user_scan; |
796 | 802 | ||
797 | i->t.host_attrs.ac.attrs = &i->host_attrs[0]; | 803 | i->t.host_attrs.ac.attrs = &i->host_attrs[0]; |
798 | i->t.host_attrs.ac.class = &sas_host_class.class; | 804 | i->t.host_attrs.ac.class = &sas_host_class.class; |