]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/scsi/libfc/fc_elsct.c
Merge branch 'devel' of git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa...
[mv-sheeva.git] / drivers / scsi / libfc / fc_elsct.c
index 5cfa68732e9d7dd8a0da7aaa9e8aad1c4aa7e2a1..53748724f2c52e55b8aa93ebf8bd9cfc554a7015 100644 (file)
 #include <scsi/libfc.h>
 #include <scsi/fc_encode.h>
 
-/*
- * fc_elsct_send - sends ELS/CT frame
+/**
+ * fc_elsct_send() - Send an ELS or CT frame
+ * @lport:     The local port to send the frame on
+ * @did:       The destination ID for the frame
+ * @fp:                The frame to be sent
+ * @op:                The operational code
+ * @resp:      The callback routine when the response is received
+ * @arg:       The argument to pass to the response callback routine
+ * @timer_msec: The timeout period for the frame (in msecs)
  */
-static struct fc_seq *fc_elsct_send(struct fc_lport *lport,
-                                   u32 did,
-                                   struct fc_frame *fp,
-                                   unsigned int op,
-                                   void (*resp)(struct fc_seq *,
-                                                struct fc_frame *fp,
-                                                void *arg),
-                                   void *arg, u32 timer_msec)
+struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did,
+                            struct fc_frame *fp, unsigned int op,
+                            void (*resp)(struct fc_seq *,
+                                         struct fc_frame *,
+                                         void *),
+                            void *arg, u32 timer_msec)
 {
        enum fc_rctl r_ctl;
        enum fc_fh_type fh_type;
@@ -53,15 +58,22 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport,
                did = FC_FID_DIR_SERV;
        }
 
-       if (rc)
+       if (rc) {
+               fc_frame_free(fp);
                return NULL;
+       }
 
        fc_fill_fc_hdr(fp, r_ctl, did, fc_host_port_id(lport->host), fh_type,
                       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
        return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec);
 }
+EXPORT_SYMBOL(fc_elsct_send);
 
+/**
+ * fc_elsct_init() - Initialize the ELS/CT layer
+ * @lport: The local port to initialize the ELS/CT layer for
+ */
 int fc_elsct_init(struct fc_lport *lport)
 {
        if (!lport->tt.elsct_send)
@@ -72,12 +84,15 @@ int fc_elsct_init(struct fc_lport *lport)
 EXPORT_SYMBOL(fc_elsct_init);
 
 /**
- * fc_els_resp_type() - return string describing ELS response for debug.
- * @fp: frame pointer with possible error code.
+ * fc_els_resp_type() - Return a string describing the ELS response
+ * @fp: The frame pointer or possible error code
  */
 const char *fc_els_resp_type(struct fc_frame *fp)
 {
        const char *msg;
+       struct fc_frame_header *fh;
+       struct fc_ct_hdr *ct;
+
        if (IS_ERR(fp)) {
                switch (-PTR_ERR(fp)) {
                case FC_NO_ERR:
@@ -94,15 +109,41 @@ const char *fc_els_resp_type(struct fc_frame *fp)
                        break;
                }
        } else {
-               switch (fc_frame_payload_op(fp)) {
-               case ELS_LS_ACC:
-                       msg = "accept";
+               fh = fc_frame_header_get(fp);
+               switch (fh->fh_type) {
+               case FC_TYPE_ELS:
+                       switch (fc_frame_payload_op(fp)) {
+                       case ELS_LS_ACC:
+                               msg = "accept";
+                               break;
+                       case ELS_LS_RJT:
+                               msg = "reject";
+                               break;
+                       default:
+                               msg = "response unknown ELS";
+                               break;
+                       }
                        break;
-               case ELS_LS_RJT:
-                       msg = "reject";
+               case FC_TYPE_CT:
+                       ct = fc_frame_payload_get(fp, sizeof(*ct));
+                       if (ct) {
+                               switch (ntohs(ct->ct_cmd)) {
+                               case FC_FS_ACC:
+                                       msg = "CT accept";
+                                       break;
+                               case FC_FS_RJT:
+                                       msg = "CT reject";
+                                       break;
+                               default:
+                                       msg = "response unknown CT";
+                                       break;
+                               }
+                       } else {
+                               msg = "short CT response";
+                       }
                        break;
                default:
-                       msg = "response unknown ELS";
+                       msg = "response not ELS or CT";
                        break;
                }
        }