]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/scsi/scsi_transport_fc.c
[SCSI] qla2xxx: Allocate enough space for the full PCI descriptor.
[mv-sheeva.git] / drivers / scsi / scsi_transport_fc.c
index 217651468115aafc7488cb2beb8b70db101a1e37..47057254850dae0cf3d7f4b86811474c953455bd 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  *  FiberChannel transport specific attributes exported to sysfs.
  *
  *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
@@ -22,6 +22,7 @@
  *  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>
@@ -37,6 +38,7 @@
 #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
@@ -377,7 +379,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
        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.
@@ -1198,12 +1200,9 @@ store_fc_vport_delete(struct class_device *cdev, const char *buf,
                           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,
@@ -1944,6 +1943,9 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel,
                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,
@@ -1996,7 +1998,7 @@ fc_attach_transport(struct fc_function_template *ft)
        i->t.eh_timed_out = fc_timed_out;
 
        i->t.user_scan = fc_user_scan;
-       
+
        /*
         * Setup SCSI Target Attributes.
         */
@@ -2215,23 +2217,12 @@ fc_remove_host(struct Scsi_Host *shost)
        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,
@@ -2308,7 +2299,7 @@ fc_rport_final_delete(struct work_struct *work)
        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)
@@ -2367,7 +2358,7 @@ fc_rport_final_delete(struct work_struct *work)
  * 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)
 {
@@ -2858,7 +2849,7 @@ EXPORT_SYMBOL(fc_remote_port_rolechg);
  * 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
@@ -3061,6 +3052,7 @@ fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
        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);
 
@@ -3207,8 +3199,30 @@ fc_vport_terminate(struct fc_vport *vport)
 }
 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");