Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds
[powerpc.git] / drivers / scsi / scsi_transport_fc.c
index 2176514..7a7cfe5 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>
 #include <net/netlink.h>
 #include <scsi/scsi_netlink_fc.h>
 #include "scsi_priv.h"
+#include "scsi_transport_fc_internal.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 +380,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.
@@ -471,7 +474,7 @@ static DECLARE_TRANSPORT_CLASS(fc_vport_class,
  */
 static unsigned int fc_dev_loss_tmo = 60;              /* seconds */
 
-module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR);
+module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(dev_loss_tmo,
                 "Maximum number of seconds that the FC transport should"
                 " insulate the loss of a remote port. Once this value is"
@@ -1198,12 +1201,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 +1944,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,
@@ -1954,6 +1957,19 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel,
        return 0;
 }
 
+static int fc_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
+                               int result)
+{
+       struct fc_internal *i = to_fc_internal(shost->transportt);
+       return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
+}
+
+static int fc_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
+{
+       struct fc_internal *i = to_fc_internal(shost->transportt);
+       return i->f->it_nexus_response(shost, nexus, result);
+}
+
 struct scsi_transport_template *
 fc_attach_transport(struct fc_function_template *ft)
 {
@@ -1996,7 +2012,11 @@ fc_attach_transport(struct fc_function_template *ft)
        i->t.eh_timed_out = fc_timed_out;
 
        i->t.user_scan = fc_user_scan;
-       
+
+       /* target-mode drivers' functions */
+       i->t.tsk_mgmt_response = fc_tsk_mgmt_response;
+       i->t.it_nexus_response = fc_it_nexus_response;
+
        /*
         * Setup SCSI Target Attributes.
         */
@@ -2215,23 +2235,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 +2317,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 +2376,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)
 {
@@ -2765,6 +2774,10 @@ fc_remote_port_delete(struct fc_rport  *rport)
 
        spin_unlock_irqrestore(shost->host_lock, flags);
 
+       if (rport->roles & FC_PORT_ROLE_FCP_INITIATOR &&
+           shost->active_mode & MODE_TARGET)
+               fc_tgt_it_nexus_destroy(shost, (unsigned long)rport);
+
        scsi_target_block(&rport->dev);
 
        /* see if we need to kill io faster than waiting for device loss */
@@ -2805,6 +2818,7 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
        struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
        unsigned long flags;
        int create = 0;
+       int ret;
 
        spin_lock_irqsave(shost->host_lock, flags);
        if (roles & FC_PORT_ROLE_FCP_TARGET) {
@@ -2813,6 +2827,12 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
                        create = 1;
                } else if (!(rport->roles & FC_PORT_ROLE_FCP_TARGET))
                        create = 1;
+       } else if (shost->active_mode & MODE_TARGET) {
+               ret = fc_tgt_it_nexus_create(shost, (unsigned long)rport,
+                                            (char *)&rport->node_name);
+               if (ret)
+                       printk(KERN_ERR "FC Remore Port tgt nexus failed %d\n",
+                              ret);
        }
 
        rport->roles = roles;
@@ -2858,7 +2878,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
@@ -2997,10 +3017,12 @@ fc_scsi_scan_rport(struct work_struct *work)
        struct fc_rport *rport =
                container_of(work, struct fc_rport, scan_work);
        struct Scsi_Host *shost = rport_to_shost(rport);
+       struct fc_internal *i = to_fc_internal(shost->transportt);
        unsigned long flags;
 
        if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
-           (rport->roles & FC_PORT_ROLE_FCP_TARGET)) {
+           (rport->roles & FC_PORT_ROLE_FCP_TARGET) &&
+           !(i->f->disable_target_scan)) {
                scsi_scan_target(&rport->dev, rport->channel,
                        rport->scsi_target_id, SCAN_WILD_CARD, 1);
        }
@@ -3061,6 +3083,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 +3230,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");