Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[safe/jmp/linux-2.6] / drivers / scsi / lpfc / lpfc_ct.c
index 92441ce..26dae8b 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -34,6 +34,7 @@
 
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
 #include "lpfc.h"
@@ -63,7 +64,7 @@ lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
 {
        if (!mp) {
                lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                               "0146 Ignoring unsolicted CT No HBQ "
+                               "0146 Ignoring unsolicited CT No HBQ "
                                "status = x%x\n",
                                piocbq->iocb.ulpStatus);
        }
@@ -101,7 +102,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                /* Not enough posted buffers; Try posting more buffers */
                phba->fc_stat.NoRcvBuf++;
                if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
-                       lpfc_post_buffer(phba, pring, 2, 1);
+                       lpfc_post_buffer(phba, pring, 2);
                return;
        }
 
@@ -134,25 +135,24 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                }
                list_del(&head);
        } else {
-               struct lpfc_iocbq  *next;
-
-               list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
+               INIT_LIST_HEAD(&head);
+               list_add_tail(&head, &piocbq->list);
+               list_for_each_entry(iocbq, &head, list) {
                        icmd = &iocbq->iocb;
                        if (icmd->ulpBdeCount == 0)
-                               lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0);
+                               lpfc_ct_unsol_buffer(phba, iocbq, NULL, 0);
                        for (i = 0; i < icmd->ulpBdeCount; i++) {
                                paddr = getPaddr(icmd->un.cont64[i].addrHigh,
                                                 icmd->un.cont64[i].addrLow);
                                mp = lpfc_sli_ringpostbuf_get(phba, pring,
                                                              paddr);
                                size = icmd->un.cont64[i].tus.f.bdeSize;
-                               lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
+                               lpfc_ct_unsol_buffer(phba, iocbq, mp, size);
                                lpfc_in_buf_free(phba, mp);
                        }
-                       list_del(&iocbq->list);
-                       lpfc_sli_release_iocbq(phba, iocbq);
-                       lpfc_post_buffer(phba, pring, i, 1);
+                       lpfc_post_buffer(phba, pring, i);
                }
+               list_del(&head);
        }
 }
 
@@ -212,7 +212,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
                else
                        list_add_tail(&mp->list, &mlist->list);
 
-               bpl->tus.f.bdeFlags = BUFF_USE_RCV;
+               bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
                /* build buffer ptr list for IOCB */
                bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
                bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
@@ -283,7 +283,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
        icmd->un.genreq64.bdl.ulpIoTag32 = 0;
        icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
        icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
-       icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
+       icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
        icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64));
 
        if (usr_flg)
@@ -294,7 +294,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
        /* Save for completion so we can release these resources */
        geniocb->context1 = (uint8_t *) inp;
        geniocb->context2 = (uint8_t *) outp;
-       geniocb->context_un.ndlp = ndlp;
+       geniocb->context_un.ndlp = lpfc_nlp_get(ndlp);
 
        /* Fill in payload, bp points to frame payload */
        icmd->ulpCommand = CMD_GEN_REQUEST64_CR;
@@ -438,7 +438,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
                                    (!(vport->ct_flags & FC_CT_RFF_ID)) ||
                                    (!vport->cfg_restrict_login)) {
                                        ndlp = lpfc_setup_disc_node(vport, Did);
-                                       if (ndlp) {
+                                       if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
                                                lpfc_debugfs_disc_trc(vport,
                                                LPFC_DISC_TRC_CT,
                                                "Parse GID_FTrsp: "
@@ -489,8 +489,10 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
                                                 */
                                                ndlp = lpfc_findnode_did(vport,
                                                        Did);
-                                               if (ndlp && (ndlp->nlp_type &
-                                                       NLP_FCP_TARGET))
+                                               if (ndlp &&
+                                                   NLP_CHK_NODE_ACT(ndlp)
+                                                   && (ndlp->nlp_type &
+                                                    NLP_FCP_TARGET))
                                                        lpfc_setup_disc_node
                                                                (vport, Did);
                                                else if (lpfc_ns_cmd(vport,
@@ -541,7 +543,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        struct lpfc_dmabuf *outp;
        struct lpfc_sli_ct_request *CTrsp;
        struct lpfc_nodelist *ndlp;
-       int rc, retry;
+       int rc;
 
        /* First save ndlp, before we overwrite it */
        ndlp = cmdiocb->context_un.ndlp;
@@ -561,45 +563,29 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        if (vport->load_flag & FC_UNLOADING)
                goto out;
 
-       if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
+       if (lpfc_els_chk_latt(vport)) {
                lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
                                 "0216 Link event during NS query\n");
                lpfc_vport_set_state(vport, FC_VPORT_FAILED);
                goto out;
        }
-
+       if (lpfc_error_lost_link(irsp)) {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "0226 NS query failed due to link event\n");
+               goto out;
+       }
        if (irsp->ulpStatus) {
                /* Check for retry */
                if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
-                       retry = 1;
-                       if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
-                               switch (irsp->un.ulpWord[4]) {
-                               case IOERR_NO_RESOURCES:
-                                       /* We don't increment the retry
-                                        * count for this case.
-                                        */
-                                       break;
-                               case IOERR_LINK_DOWN:
-                               case IOERR_SLI_ABORTED:
-                               case IOERR_SLI_DOWN:
-                                       retry = 0;
-                                       break;
-                               default:
-                                       vport->fc_ns_retry++;
-                               }
-                       }
-                       else
+                       if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
+                           irsp->un.ulpWord[4] != IOERR_NO_RESOURCES)
                                vport->fc_ns_retry++;
 
-                       if (retry) {
-                               /* CT command is being retried */
-                               rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
+                       /* CT command is being retried */
+                       rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
                                         vport->fc_ns_retry, 0);
-                               if (rc == 0) {
-                                       /* success */
-                                       goto out;
-                               }
-                       }
+                       if (rc == 0)
+                               goto out;
                }
                lpfc_vport_set_state(vport, FC_VPORT_FAILED);
                lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -773,12 +759,12 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                 "0267 NameServer GFF Rsp "
                                 "x%x Error (%d %d) Data: x%x x%x\n",
                                 did, irsp->ulpStatus, irsp->un.ulpWord[4],
-                                vport->fc_flag, vport->fc_rscn_id_cnt)
+                                vport->fc_flag, vport->fc_rscn_id_cnt);
        }
 
        /* This is a target port, unregistered port, or the GFF_ID failed */
        ndlp = lpfc_setup_disc_node(vport, did);
-       if (ndlp) {
+       if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
                lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
                                 "0242 Process x%x GFF "
                                 "NameServer Rsp Data: x%x x%x x%x\n",
@@ -875,7 +861,7 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
                retry++;
                lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
-                                "0216 Retrying NS cmd %x\n", cmdcode);
+                                "0250 Retrying NS cmd %x\n", cmdcode);
                rc = lpfc_ns_cmd(vport, cmdcode, retry, 0);
                if (rc == 0)
                        goto out;
@@ -1004,7 +990,7 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        return;
 }
 
-static int
+int
 lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
        size_t size)
 {
@@ -1064,7 +1050,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
        int rc = 0;
 
        ndlp = lpfc_findnode_did(vport, NameServer_DID);
-       if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) {
+       if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)
+           || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) {
                rc=1;
                goto ns_cmd_exit;
        }
@@ -1213,8 +1200,9 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
                cmpl = lpfc_cmpl_ct_cmd_rff_id;
                break;
        }
-       lpfc_nlp_get(ndlp);
-
+       /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
+        * to hold ndlp reference for the corresponding callback function.
+        */
        if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
                /* On success, The cmpl function will free the buffers */
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
@@ -1222,9 +1210,13 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
                        cmdcode, ndlp->nlp_DID, 0);
                return 0;
        }
-
        rc=6;
+
+       /* Decrement ndlp reference count to release ndlp reference held
+        * for the failed command's callback function.
+        */
        lpfc_nlp_put(ndlp);
+
        lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
 ns_cmd_free_bmp:
        kfree(bmp);
@@ -1271,6 +1263,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        }
 
        ndlp = lpfc_findnode_did(vport, FDMI_DID);
+       if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+               goto fail_out;
+
        if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
                /* FDMI rsp failed */
                lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
@@ -1294,6 +1289,8 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
                break;
        }
+
+fail_out:
        lpfc_ct_free_iocb(phba, cmdiocb);
        return;
 }
@@ -1650,12 +1647,18 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
        bpl->tus.w = le32_to_cpu(bpl->tus.w);
 
        cmpl = lpfc_cmpl_ct_cmd_fdmi;
-       lpfc_nlp_get(ndlp);
 
+       /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
+        * to hold ndlp reference for the corresponding callback function.
+        */
        if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0))
                return 0;
 
+       /* Decrement ndlp reference count to release ndlp reference held
+        * for the failed command's callback function.
+        */
        lpfc_nlp_put(ndlp);
+
        lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
 fdmi_cmd_free_bmp:
        kfree(bmp);
@@ -1676,20 +1679,18 @@ lpfc_fdmi_tmo(unsigned long ptr)
 {
        struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
        struct lpfc_hba   *phba = vport->phba;
+       uint32_t tmo_posted;
        unsigned long iflag;
 
        spin_lock_irqsave(&vport->work_port_lock, iflag);
-       if (!(vport->work_port_events & WORKER_FDMI_TMO)) {
+       tmo_posted = vport->work_port_events & WORKER_FDMI_TMO;
+       if (!tmo_posted)
                vport->work_port_events |= WORKER_FDMI_TMO;
-               spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+       spin_unlock_irqrestore(&vport->work_port_lock, iflag);
 
-               spin_lock_irqsave(&phba->hbalock, iflag);
-               if (phba->work_wait)
-                       lpfc_worker_wake_up(phba);
-               spin_unlock_irqrestore(&phba->hbalock, iflag);
-       }
-       else
-               spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+       if (!tmo_posted)
+               lpfc_worker_wake_up(phba);
+       return;
 }
 
 void
@@ -1698,7 +1699,7 @@ lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
        struct lpfc_nodelist *ndlp;
 
        ndlp = lpfc_findnode_did(vport, FDMI_DID);
-       if (ndlp) {
+       if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
                if (init_utsname()->nodename[0] != '\0')
                        lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
                else