-/*
+/*
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
* Copyright (C) 2004-2007 James Smart, Emulex Corporation
* Rewrite for host, target, device, and remote port attributes,
* statistics, and service functions...
+ * Add vports, etc
*
*/
#include <linux/module.h>
#include "scsi_priv.h"
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
+static void fc_vport_sched_delete(struct work_struct *work);
/*
* This is a temporary carrier for creating a vport. It will eventually
struct Scsi_Host *shost = dev_to_shost(dev);
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
- /*
+ /*
* Set default values easily detected by the midlayer as
* failure cases. The scsi lldd is responsible for initializing
* all transport attributes to valid values per host.
size_t count)
{
struct fc_vport *vport = transport_class_to_vport(cdev);
- int stat;
-
- stat = fc_vport_terminate(vport);
- if (stat)
- return stat;
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ fc_queue_work(shost, &vport->vport_delete_work);
return count;
}
static FC_CLASS_DEVICE_ATTR(vport, vport_delete, S_IWUSR,
if (rport->scsi_target_id == -1)
continue;
+ if (rport->port_state != FC_PORTSTATE_ONLINE)
+ continue;
+
if ((channel == SCAN_WILD_CARD || channel == rport->channel) &&
(id == SCAN_WILD_CARD || id == rport->scsi_target_id)) {
scsi_scan_target(&rport->dev, rport->channel,
i->t.eh_timed_out = fc_timed_out;
i->t.user_scan = fc_user_scan;
-
+
/*
* Setup SCSI Target Attributes.
*/
struct workqueue_struct *work_q;
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
unsigned long flags;
- int stat;
spin_lock_irqsave(shost->host_lock, flags);
/* Remove any vports */
- list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers) {
- spin_unlock_irqrestore(shost->host_lock, flags);
- /* this must be called synchronously */
- stat = fc_vport_terminate(vport);
- spin_lock_irqsave(shost->host_lock, flags);
- if (stat)
- dev_printk(KERN_ERR, vport->dev.parent,
- "%s: %s could not be deleted created via "
- "shost%d channel %d\n", __FUNCTION__,
- vport->dev.bus_id, vport->shost->host_no,
- vport->channel);
- }
+ list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers)
+ fc_queue_work(shost, &vport->vport_delete_work);
/* Remove any remote ports */
list_for_each_entry_safe(rport, next_rport,
unsigned long flags;
/*
- * if a scan is pending, flush the SCSI Host work_q so that
+ * if a scan is pending, flush the SCSI Host work_q so that
* that we can reclaim the rport scan work element.
*/
if (rport->flags & FC_RPORT_SCAN_PENDING)
* Notes:
* This routine assumes no locks are held on entry.
**/
-struct fc_rport *
+static struct fc_rport *
fc_rport_create(struct Scsi_Host *shost, int channel,
struct fc_rport_identifiers *ids)
{
* fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
* which we blocked, and has now failed to return
* in the allotted time.
- *
+ *
* @work: rport target that failed to reappear in the allotted time.
**/
static void
vport->shost = shost;
vport->channel = channel;
vport->flags = FC_VPORT_CREATING;
+ INIT_WORK(&vport->vport_delete_work, fc_vport_sched_delete);
spin_lock_irqsave(shost->host_lock, flags);
}
EXPORT_SYMBOL(fc_vport_terminate);
+/**
+ * fc_vport_sched_delete - workq-based delete request for a vport
+ *
+ * @work: vport to be deleted.
+ **/
+static void
+fc_vport_sched_delete(struct work_struct *work)
+{
+ struct fc_vport *vport =
+ container_of(work, struct fc_vport, vport_delete_work);
+ int stat;
+
+ stat = fc_vport_terminate(vport);
+ if (stat)
+ dev_printk(KERN_ERR, vport->dev.parent,
+ "%s: %s could not be deleted created via "
+ "shost%d channel %d - error %d\n", __FUNCTION__,
+ vport->dev.bus_id, vport->shost->host_no,
+ vport->channel, stat);
+}
+
-MODULE_AUTHOR("Martin Hicks");
+/* Original Author: Martin Hicks */
+MODULE_AUTHOR("James Smart");
MODULE_DESCRIPTION("FC Transport Attributes");
MODULE_LICENSE("GPL");