aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2006-01-13 13:04:00 -0500
committerJames Bottomley <jejb@mulgrave.(none)>2006-01-14 11:55:05 -0500
commite02f3f59225d8c3b2a0ad0dc941a09865e27da61 (patch)
tree37d2931f5d24dc063d9606ec6b5e8db359b439c7
parent6d5b0c315e0c14f8a0fe274eda7676d62cbd8584 (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>
-rw-r--r--drivers/scsi/scsi_priv.h6
-rw-r--r--drivers/scsi/scsi_proc.c6
-rw-r--r--drivers/scsi/scsi_scan.c16
-rw-r--r--drivers/scsi/scsi_sysfs.c5
-rw-r--r--drivers/scsi/scsi_transport_fc.c22
-rw-r--r--drivers/scsi/scsi_transport_sas.c42
-rw-r--r--include/scsi/scsi.h6
-rw-r--r--include/scsi/scsi_transport.h7
8 files changed, 57 insertions, 53 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 */
36extern int scsi_init_hosts(void); 30extern int scsi_init_hosts(void);
37extern void scsi_exit_hosts(void); 31extern 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 */
1096static struct device *fc_target_parent(struct Scsi_Host *shost, 1096static 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
1109struct scsi_transport_template * 1115struct 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
63struct sas_host_attrs { 64struct 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
734static struct device *sas_target_parent(struct Scsi_Host *shost, 735static 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;
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 6cb1e2788d8b..c60b8ff2f5e4 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -32,6 +32,12 @@ extern const unsigned char scsi_command_size[8];
32extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; 32extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
33 33
34/* 34/*
35 * Special value for scanning to specify scanning or rescanning of all
36 * possible channels, (target) ids, or luns on a given shost.
37 */
38#define SCAN_WILD_CARD ~0
39
40/*
35 * SCSI opcodes 41 * SCSI opcodes
36 */ 42 */
37 43
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
index f6e0bb484c63..e7b1054adf86 100644
--- a/include/scsi/scsi_transport.h
+++ b/include/scsi/scsi_transport.h
@@ -30,12 +30,9 @@ struct scsi_transport_template {
30 struct transport_container device_attrs; 30 struct transport_container device_attrs;
31 31
32 /* 32 /*
33 * If set, call target_parent prior to allocating a scsi_target, 33 * If set, called from sysfs and legacy procfs rescanning code.
34 * so we get the appropriate parent for the target. This function
35 * is required for transports like FC and iSCSI that do not put the
36 * scsi_target under scsi_host.
37 */ 34 */
38 struct device *(*target_parent)(struct Scsi_Host *, int, uint); 35 int (*user_scan)(struct Scsi_Host *, uint, uint, uint);
39 36
40 /* The size of the specific transport attribute structure (a 37 /* The size of the specific transport attribute structure (a
41 * space of this size will be left at the end of the 38 * space of this size will be left at the end of the