include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / scsi / lpfc / lpfc_sli.c
index 9feeaff..049fb9a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/slab.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -4519,6 +4520,10 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
        /* Post receive buffers to the device */
        lpfc_sli4_rb_setup(phba);
 
+       /* Reset HBA FCF states after HBA reset */
+       phba->fcf.fcf_flag = 0;
+       phba->fcf.current_rec.flag = 0;
+
        /* Start the ELS watchdog timer */
        mod_timer(&vport->els_tmofunc,
                  jiffies + HZ * (phba->fc_ratov * 2));
@@ -11992,15 +11997,19 @@ lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *phba,
 }
 
 /**
- * lpfc_sli4_read_fcf_record - Read the driver's default FCF Record.
+ * lpfc_sli4_fcf_scan_read_fcf_rec - Read hba fcf record for fcf scan.
  * @phba: pointer to lpfc hba data structure.
  * @fcf_index: FCF table entry offset.
  *
- * This routine is invoked to read up to @fcf_num of FCF record from the
- * device starting with the given @fcf_index.
+ * This routine is invoked to scan the entire FCF table by reading FCF
+ * record and processing it one at a time starting from the @fcf_index
+ * for initial FCF discovery or fast FCF failover rediscovery.
+ *
+ * Return 0 if the mailbox command is submitted sucessfully, none 0
+ * otherwise.
  **/
 int
-lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
+lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
 {
        int rc = 0, error;
        LPFC_MBOXQ_t *mboxq;
@@ -12012,17 +12021,17 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
                                "2000 Failed to allocate mbox for "
                                "READ_FCF cmd\n");
                error = -ENOMEM;
-               goto fail_fcfscan;
+               goto fail_fcf_scan;
        }
        /* Construct the read FCF record mailbox command */
-       rc = lpfc_sli4_mbx_read_fcf_record(phba, mboxq, fcf_index);
+       rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index);
        if (rc) {
                error = -EINVAL;
-               goto fail_fcfscan;
+               goto fail_fcf_scan;
        }
        /* Issue the mailbox command asynchronously */
        mboxq->vport = phba->pport;
-       mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_record;
+       mboxq->mbox_cmpl = lpfc_mbx_cmpl_fcf_scan_read_fcf_rec;
        rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
        if (rc == MBX_NOT_FINISHED)
                error = -EIO;
@@ -12030,9 +12039,13 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
                spin_lock_irq(&phba->hbalock);
                phba->hba_flag |= FCF_DISC_INPROGRESS;
                spin_unlock_irq(&phba->hbalock);
+               /* Reset FCF round robin index bmask for new scan */
+               if (fcf_index == LPFC_FCOE_FCF_GET_FIRST)
+                       memset(phba->fcf.fcf_rr_bmask, 0,
+                              sizeof(*phba->fcf.fcf_rr_bmask));
                error = 0;
        }
-fail_fcfscan:
+fail_fcf_scan:
        if (error) {
                if (mboxq)
                        lpfc_sli4_mbox_cmd_free(phba, mboxq);
@@ -12045,6 +12058,181 @@ fail_fcfscan:
 }
 
 /**
+ * lpfc_sli4_fcf_rr_read_fcf_rec - Read hba fcf record for round robin fcf.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index: FCF table entry offset.
+ *
+ * This routine is invoked to read an FCF record indicated by @fcf_index
+ * and to use it for FLOGI round robin FCF failover.
+ *
+ * Return 0 if the mailbox command is submitted sucessfully, none 0
+ * otherwise.
+ **/
+int
+lpfc_sli4_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       int rc = 0, error;
+       LPFC_MBOXQ_t *mboxq;
+
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_INIT,
+                               "2763 Failed to allocate mbox for "
+                               "READ_FCF cmd\n");
+               error = -ENOMEM;
+               goto fail_fcf_read;
+       }
+       /* Construct the read FCF record mailbox command */
+       rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index);
+       if (rc) {
+               error = -EINVAL;
+               goto fail_fcf_read;
+       }
+       /* Issue the mailbox command asynchronously */
+       mboxq->vport = phba->pport;
+       mboxq->mbox_cmpl = lpfc_mbx_cmpl_fcf_rr_read_fcf_rec;
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED)
+               error = -EIO;
+       else
+               error = 0;
+
+fail_fcf_read:
+       if (error && mboxq)
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+       return error;
+}
+
+/**
+ * lpfc_sli4_read_fcf_rec - Read hba fcf record for update eligible fcf bmask.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index: FCF table entry offset.
+ *
+ * This routine is invoked to read an FCF record indicated by @fcf_index to
+ * determine whether it's eligible for FLOGI round robin failover list.
+ *
+ * Return 0 if the mailbox command is submitted sucessfully, none 0
+ * otherwise.
+ **/
+int
+lpfc_sli4_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       int rc = 0, error;
+       LPFC_MBOXQ_t *mboxq;
+
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_INIT,
+                               "2758 Failed to allocate mbox for "
+                               "READ_FCF cmd\n");
+                               error = -ENOMEM;
+                               goto fail_fcf_read;
+       }
+       /* Construct the read FCF record mailbox command */
+       rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index);
+       if (rc) {
+               error = -EINVAL;
+               goto fail_fcf_read;
+       }
+       /* Issue the mailbox command asynchronously */
+       mboxq->vport = phba->pport;
+       mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_rec;
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED)
+               error = -EIO;
+       else
+               error = 0;
+
+fail_fcf_read:
+       if (error && mboxq)
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+       return error;
+}
+
+/**
+ * lpfc_sli4_fcf_rr_next_index_get - Get next eligible fcf record index
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is to get the next eligible FCF record index in a round
+ * robin fashion. If the next eligible FCF record index equals to the
+ * initial round robin FCF record index, LPFC_FCOE_FCF_NEXT_NONE (0xFFFF)
+ * shall be returned, otherwise, the next eligible FCF record's index
+ * shall be returned.
+ **/
+uint16_t
+lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
+{
+       uint16_t next_fcf_index;
+
+       /* Search from the currently registered FCF index */
+       next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
+                                      LPFC_SLI4_FCF_TBL_INDX_MAX,
+                                      phba->fcf.current_rec.fcf_indx);
+       /* Wrap around condition on phba->fcf.fcf_rr_bmask */
+       if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
+               next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
+                                              LPFC_SLI4_FCF_TBL_INDX_MAX, 0);
+       /* Round robin failover stop condition */
+       if (next_fcf_index == phba->fcf.fcf_rr_init_indx)
+               return LPFC_FCOE_FCF_NEXT_NONE;
+
+       return next_fcf_index;
+}
+
+/**
+ * lpfc_sli4_fcf_rr_index_set - Set bmask with eligible fcf record index
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine sets the FCF record index in to the eligible bmask for
+ * round robin failover search. It checks to make sure that the index
+ * does not go beyond the range of the driver allocated bmask dimension
+ * before setting the bit.
+ *
+ * Returns 0 if the index bit successfully set, otherwise, it returns
+ * -EINVAL.
+ **/
+int
+lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+                               "2610 HBA FCF index reached driver's "
+                               "book keeping dimension: fcf_index:%d, "
+                               "driver_bmask_max:%d\n",
+                               fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX);
+               return -EINVAL;
+       }
+       /* Set the eligible FCF record index bmask */
+       set_bit(fcf_index, phba->fcf.fcf_rr_bmask);
+
+       return 0;
+}
+
+/**
+ * lpfc_sli4_fcf_rr_index_set - Clear bmask from eligible fcf record index
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine clears the FCF record index from the eligible bmask for
+ * round robin failover search. It checks to make sure that the index
+ * does not go beyond the range of the driver allocated bmask dimension
+ * before clearing the bit.
+ **/
+void
+lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+                               "2762 HBA FCF index goes beyond driver's "
+                               "book keeping dimension: fcf_index:%d, "
+                               "driver_bmask_max:%d\n",
+                               fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX);
+               return;
+       }
+       /* Clear the eligible FCF record index bmask */
+       clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
+}
+
+/**
  * lpfc_mbx_cmpl_redisc_fcf_table - completion routine for rediscover FCF table
  * @phba: pointer to lpfc hba data structure.
  *
@@ -12065,21 +12253,40 @@ lpfc_mbx_cmpl_redisc_fcf_table(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
        shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
                             &redisc_fcf->header.cfg_shdr.response);
        if (shdr_status || shdr_add_status) {
-               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
                                "2746 Requesting for FCF rediscovery failed "
                                "status x%x add_status x%x\n",
                                shdr_status, shdr_add_status);
-               /*
-                * Request failed, last resort to re-try current
-                * registered FCF entry
-                */
-               lpfc_retry_pport_discovery(phba);
-       } else
+               if (phba->fcf.fcf_flag & FCF_ACVL_DISC) {
+                       spin_lock_irq(&phba->hbalock);
+                       phba->fcf.fcf_flag &= ~FCF_ACVL_DISC;
+                       spin_unlock_irq(&phba->hbalock);
+                       /*
+                        * CVL event triggered FCF rediscover request failed,
+                        * last resort to re-try current registered FCF entry.
+                        */
+                       lpfc_retry_pport_discovery(phba);
+               } else {
+                       spin_lock_irq(&phba->hbalock);
+                       phba->fcf.fcf_flag &= ~FCF_DEAD_DISC;
+                       spin_unlock_irq(&phba->hbalock);
+                       /*
+                        * DEAD FCF event triggered FCF rediscover request
+                        * failed, last resort to fail over as a link down
+                        * to FCF registration.
+                        */
+                       lpfc_sli4_fcf_dead_failthrough(phba);
+               }
+       } else {
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                               "2775 Start FCF rediscovery quiescent period "
+                               "wait timer before scaning FCF table\n");
                /*
                 * Start FCF rediscovery wait timer for pending FCF
                 * before rescan FCF record table.
                 */
                lpfc_fcf_redisc_wait_start_timer(phba);
+       }
 
        mempool_free(mbox, phba->mbox_mem_pool);
 }
@@ -12098,6 +12305,9 @@ lpfc_sli4_redisc_fcf_table(struct lpfc_hba *phba)
        struct lpfc_mbx_redisc_fcf_tbl *redisc_fcf;
        int rc, length;
 
+       /* Cancel retry delay timers to all vports before FCF rediscover */
+       lpfc_cancel_all_vport_retry_delay_timer(phba);
+
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mbox) {
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
@@ -12129,6 +12339,31 @@ lpfc_sli4_redisc_fcf_table(struct lpfc_hba *phba)
 }
 
 /**
+ * lpfc_sli4_fcf_dead_failthrough - Failthrough routine to fcf dead event
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This function is the failover routine as a last resort to the FCF DEAD
+ * event when driver failed to perform fast FCF failover.
+ **/
+void
+lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *phba)
+{
+       uint32_t link_state;
+
+       /*
+        * Last resort as FCF DEAD event failover will treat this as
+        * a link down, but save the link state because we don't want
+        * it to be changed to Link Down unless it is already down.
+        */
+       link_state = phba->link_state;
+       lpfc_linkdown(phba);
+       phba->link_state = link_state;
+
+       /* Unregister FCF if no devices connected to it */
+       lpfc_unregister_unused_fcf(phba);
+}
+
+/**
  * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled.
  * @phba: pointer to lpfc hba data structure.
  *