Merge branch 'sh-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / scsi / libfc / fc_lport.c
index c5a10f9..906bbca 100644 (file)
@@ -52,7 +52,7 @@
  * while making the callback. To ensure that the rport is not free'd while
  * processing the callback the rport callbacks are serialized through a
  * single-threaded workqueue. An rport would never be free'd while in a
- * callback handler becuase no other rport work in this queue can be executed
+ * callback handler because no other rport work in this queue can be executed
  * at the same time.
  *
  * When discovery succeeds or fails a callback is made to the lport as
@@ -163,7 +163,7 @@ static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp)
  * fc_lport_rport_callback() - Event handler for rport events
  * @lport: The lport which is receiving the event
  * @rdata: private remote port data
- * @event: The event that occured
+ * @event: The event that occurred
  *
  * Locking Note: The rport lock should not be held when calling
  *              this function.
@@ -379,7 +379,7 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type)
 
 /**
  * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report.
- * @lport: Fibre Channel local port recieving the RLIR
+ * @lport: Fibre Channel local port receiving the RLIR
  * @fp:           The RLIR request frame
  *
  * Locking Note: The lport lock is expected to be held before calling
@@ -396,7 +396,7 @@ static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp)
 
 /**
  * fc_lport_recv_echo_req() - Handle received ECHO request
- * @lport: The local port recieving the ECHO
+ * @lport: The local port receiving the ECHO
  * @fp:           ECHO request frame
  *
  * Locking Note: The lport lock is expected to be held before calling
@@ -432,7 +432,7 @@ static void fc_lport_recv_echo_req(struct fc_lport *lport,
 
 /**
  * fc_lport_recv_rnid_req() - Handle received Request Node ID data request
- * @lport: The local port recieving the RNID
+ * @lport: The local port receiving the RNID
  * @fp:           The RNID request frame
  *
  * Locking Note: The lport lock is expected to be held before calling
@@ -491,7 +491,7 @@ static void fc_lport_recv_rnid_req(struct fc_lport *lport,
 
 /**
  * fc_lport_recv_logo_req() - Handle received fabric LOGO request
- * @lport: The local port recieving the LOGO
+ * @lport: The local port receiving the LOGO
  * @fp:           The LOGO request frame
  *
  * Locking Note: The lport lock is exected to be held before calling
@@ -633,6 +633,7 @@ int fc_lport_destroy(struct fc_lport *lport)
        lport->tt.fcp_abort_io(lport);
        lport->tt.disc_stop_final(lport);
        lport->tt.exch_mgr_reset(lport, 0, 0);
+       fc_fc4_del_lport(lport);
        return 0;
 }
 EXPORT_SYMBOL(fc_lport_destroy);
@@ -770,7 +771,7 @@ EXPORT_SYMBOL(fc_lport_set_local_id);
 
 /**
  * fc_lport_recv_flogi_req() - Receive a FLOGI request
- * @lport: The local port that recieved the request
+ * @lport: The local port that received the request
  * @rx_fp: The FLOGI frame
  *
  * A received FLOGI request indicates a point-to-point connection.
@@ -849,7 +850,7 @@ out:
 }
 
 /**
- * fc_lport_recv_req() - The generic lport request handler
+ * fc_lport_recv_els_req() - The generic lport ELS request handler
  * @lport: The local port that received the request
  * @fp:           The request frame
  *
@@ -857,11 +858,11 @@ out:
  * if an rport should handle the request.
  *
  * Locking Note: This function should not be called with the lport
- *              lock held becuase it will grab the lock.
+ *              lock held because it will grab the lock.
  */
-static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
+static void fc_lport_recv_els_req(struct fc_lport *lport,
+                                 struct fc_frame *fp)
 {
-       struct fc_frame_header *fh = fc_frame_header_get(fp);
        void (*recv)(struct fc_lport *, struct fc_frame *);
 
        mutex_lock(&lport->lp_mutex);
@@ -873,8 +874,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
         */
        if (!lport->link_up)
                fc_frame_free(fp);
-       else if (fh->fh_type == FC_TYPE_ELS &&
-                fh->fh_r_ctl == FC_RCTL_ELS_REQ) {
+       else {
                /*
                 * Check opcode.
                 */
@@ -903,14 +903,62 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
                }
 
                recv(lport, fp);
-       } else {
-               FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n",
-                            fr_eof(fp));
-               fc_frame_free(fp);
        }
        mutex_unlock(&lport->lp_mutex);
 }
 
+static int fc_lport_els_prli(struct fc_rport_priv *rdata, u32 spp_len,
+                            const struct fc_els_spp *spp_in,
+                            struct fc_els_spp *spp_out)
+{
+       return FC_SPP_RESP_INVL;
+}
+
+struct fc4_prov fc_lport_els_prov = {
+       .prli = fc_lport_els_prli,
+       .recv = fc_lport_recv_els_req,
+};
+
+/**
+ * fc_lport_recv_req() - The generic lport request handler
+ * @lport: The lport that received the request
+ * @fp: The frame the request is in
+ *
+ * Locking Note: This function should not be called with the lport
+ *              lock held because it may grab the lock.
+ */
+static void fc_lport_recv_req(struct fc_lport *lport,
+                             struct fc_frame *fp)
+{
+       struct fc_frame_header *fh = fc_frame_header_get(fp);
+       struct fc_seq *sp = fr_seq(fp);
+       struct fc4_prov *prov;
+
+       /*
+        * Use RCU read lock and module_lock to be sure module doesn't
+        * deregister and get unloaded while we're calling it.
+        * try_module_get() is inlined and accepts a NULL parameter.
+        * Only ELSes and FCP target ops should come through here.
+        * The locking is unfortunate, and a better scheme is being sought.
+        */
+
+       rcu_read_lock();
+       if (fh->fh_type >= FC_FC4_PROV_SIZE)
+               goto drop;
+       prov = rcu_dereference(fc_passive_prov[fh->fh_type]);
+       if (!prov || !try_module_get(prov->module))
+               goto drop;
+       rcu_read_unlock();
+       prov->recv(lport, fp);
+       module_put(prov->module);
+       return;
+drop:
+       rcu_read_unlock();
+       FC_LPORT_DBG(lport, "dropping unexpected frame type %x\n", fh->fh_type);
+       fc_frame_free(fp);
+       lport->tt.exch_done(sp);
+}
+
 /**
  * fc_lport_reset() - Reset a local port
  * @lport: The local port which should be reset
@@ -1542,6 +1590,7 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
  */
 int fc_lport_config(struct fc_lport *lport)
 {
+       INIT_LIST_HEAD(&lport->ema_list);
        INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout);
        mutex_init(&lport->lp_mutex);
 
@@ -1549,6 +1598,7 @@ int fc_lport_config(struct fc_lport *lport)
 
        fc_lport_add_fc4_type(lport, FC_TYPE_FCP);
        fc_lport_add_fc4_type(lport, FC_TYPE_CT);
+       fc_fc4_conf_lport_params(lport, FC_TYPE_FCP);
 
        return 0;
 }
@@ -1586,6 +1636,7 @@ int fc_lport_init(struct fc_lport *lport)
                fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_1GBIT;
        if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT)
                fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT;
+       fc_fc4_add_lport(lport);
 
        return 0;
 }