Commit e02f3f59 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by James Bottomley
Browse files

[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: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 6d5b0c31
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -26,12 +26,6 @@ struct Scsi_Host;
#define SCSI_SENSE_VALID(scmd) \
	(((scmd)->sense_buffer[0] & 0x70) == 0x70)

/*
 * Special value for scanning to specify scanning or rescanning of all
 * possible channels, (target) ids, or luns on a given shost.
 */
#define SCAN_WILD_CARD	~0

/* hosts.c */
extern int scsi_init_hosts(void);
extern void scsi_exit_hosts(void);
+5 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>

#include "scsi_priv.h"
#include "scsi_logging.h"
@@ -200,6 +201,9 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
	if (IS_ERR(shost))
		return PTR_ERR(shost);

	if (shost->transportt->user_scan)
		error = shost->transportt->user_scan(shost, channel, id, lun);
	else
		error = scsi_scan_host_selected(shost, channel, id, lun, 1);
	scsi_host_put(shost);
	return error;
+2 −14
Original line number Diff line number Diff line
@@ -334,19 +334,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
	struct scsi_target *starget;
	struct scsi_target *found_target;

	/*
	 * Obtain the real parent from the transport. The transport
	 * is allowed to fail (no error) if there is nothing at that
	 * target id.
	 */
	if (shost->transportt->target_parent) {
		spin_lock_irqsave(shost->host_lock, flags);
		parent = shost->transportt->target_parent(shost, channel, id);
		spin_unlock_irqrestore(shost->host_lock, flags);
		if (!parent)
			return NULL;
	}

	starget = kmalloc(size, GFP_KERNEL);
	if (!starget) {
		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
@@ -1283,8 +1270,9 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
	struct scsi_device *sdev;
	struct device *parent = &shost->shost_gendev;
	int res;
	struct scsi_target *starget = scsi_alloc_target(parent, channel, id);
	struct scsi_target *starget;

	starget = scsi_alloc_target(parent, channel, id);
	if (!starget)
		return ERR_PTR(-ENOMEM);

+4 −1
Original line number Diff line number Diff line
@@ -106,6 +106,9 @@ static int scsi_scan(struct Scsi_Host *shost, const char *str)
		return -EINVAL;
	if (check_set(&lun, s3))
		return -EINVAL;
	if (shost->transportt->user_scan)
		res = shost->transportt->user_scan(shost, channel, id, lun);
	else
		res = scsi_scan_host_selected(shost, channel, id, lun, 1);
	return res;
}
+14 −8
Original line number Diff line number Diff line
@@ -1093,17 +1093,23 @@ static int fc_rport_match(struct attribute_container *cont,
/*
 * Must be called with shost->host_lock held
 */
static struct device *fc_target_parent(struct Scsi_Host *shost,
					int channel, uint id)
static int fc_user_scan(struct Scsi_Host *shost, uint channel,
		uint id, uint lun)
{
	struct fc_rport *rport;

	list_for_each_entry(rport, &fc_host_rports(shost), peers)
		if ((rport->channel == channel) &&
		    (rport->scsi_target_id == id))
			return &rport->dev;
	list_for_each_entry(rport, &fc_host_rports(shost), peers) {
		if (rport->scsi_target_id == -1)
			continue;

	return NULL;
		if ((channel == SCAN_WILD_CARD || channel == rport->channel) &&
		    (id == SCAN_WILD_CARD || id == rport->scsi_target_id)) {
			scsi_scan_target(&rport->dev, rport->channel,
					 rport->scsi_target_id, lun, 1);
		}
	}

	return 0;
}

struct scsi_transport_template *
@@ -1142,7 +1148,7 @@ fc_attach_transport(struct fc_function_template *ft)
	/* Transport uses the shost workq for scsi scanning */
	i->t.create_work_queue = 1;

	i->t.target_parent = fc_target_parent;
	i->t.user_scan = fc_user_scan;
	
	/*
	 * Setup SCSI Target Attributes.
Loading