]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/lpfc/lpfc_sli.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[linux-2.6-omap-h63xx.git] / drivers / scsi / lpfc / lpfc_sli.c
index f40aa7b905f716e335b4d30b33e1859ed478b214..8ab5babdeebcded91401e0617c82ab2d5931b08e 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
 #include "lpfc.h"
@@ -66,10 +67,16 @@ typedef enum _lpfc_iocb_type {
        LPFC_ABORT_IOCB
 } lpfc_iocb_type;
 
-               /* SLI-2/SLI-3 provide different sized iocbs.  Given a pointer
-                * to the start of the ring, and the slot number of the
-                * desired iocb entry, calc a pointer to that entry.
-                */
+/**
+ * lpfc_cmd_iocb: Get next command iocb entry in the ring.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function returns pointer to next command iocb entry
+ * in the command ring. The caller must hold hbalock to prevent
+ * other threads consume the next command iocb.
+ * SLI-2/SLI-3 provide different sized iocbs.
+ **/
 static inline IOCB_t *
 lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
@@ -77,6 +84,16 @@ lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
                           pring->cmdidx * phba->iocb_cmd_size);
 }
 
+/**
+ * lpfc_resp_iocb: Get next response iocb entry in the ring.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function returns pointer to next response iocb entry
+ * in the response ring. The caller must hold hbalock to make sure
+ * that no other thread consume the next response iocb.
+ * SLI-2/SLI-3 provide different sized iocbs.
+ **/
 static inline IOCB_t *
 lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
@@ -84,6 +101,15 @@ lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
                           pring->rspidx * phba->iocb_rsp_size);
 }
 
+/**
+ * __lpfc_sli_get_iocbq: Allocates an iocb object from iocb pool.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called with hbalock held. This function
+ * allocates a new driver iocb object from the iocb pool. If the
+ * allocation is successful, it returns pointer to the newly
+ * allocated iocb object else it returns NULL.
+ **/
 static struct lpfc_iocbq *
 __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
 {
@@ -94,6 +120,15 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
        return iocbq;
 }
 
+/**
+ * lpfc_sli_get_iocbq: Allocates an iocb object from iocb pool.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called with no lock held. This function
+ * allocates a new driver iocb object from the iocb pool. If the
+ * allocation is successful, it returns pointer to the newly
+ * allocated iocb object else it returns NULL.
+ **/
 struct lpfc_iocbq *
 lpfc_sli_get_iocbq(struct lpfc_hba *phba)
 {
@@ -106,6 +141,16 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba)
        return iocbq;
 }
 
+/**
+ * __lpfc_sli_release_iocbq: Release iocb to the iocb pool.
+ * @phba: Pointer to HBA context object.
+ * @iocbq: Pointer to driver iocb object.
+ *
+ * This function is called with hbalock held to release driver
+ * iocb object to the iocb pool. The iotag in the iocb object
+ * does not change for each use of the iocb object. This function
+ * clears all other fields of the iocb object when it is freed.
+ **/
 static void
 __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
 {
@@ -118,6 +163,14 @@ __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
        list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
 }
 
+/**
+ * lpfc_sli_release_iocbq: Release iocb to the iocb pool.
+ * @phba: Pointer to HBA context object.
+ * @iocbq: Pointer to driver iocb object.
+ *
+ * This function is called with no lock held to release the iocb to
+ * iocb pool.
+ **/
 void
 lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
 {
@@ -131,10 +184,21 @@ lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
        spin_unlock_irqrestore(&phba->hbalock, iflags);
 }
 
-/*
- * Translate the iocb command to an iocb command type used to decide the final
- * disposition of each completed IOCB.
- */
+/**
+ * lpfc_sli_iocb_cmd_type: Get the iocb type.
+ * @iocb_cmnd : iocb command code.
+ *
+ * This function is called by ring event handler function to get the iocb type.
+ * This function translates the iocb command to an iocb command type used to
+ * decide the final disposition of each completed IOCB.
+ * The function returns
+ * LPFC_UNKNOWN_IOCB if it is an unsupported iocb
+ * LPFC_SOL_IOCB     if it is a solicited iocb completion
+ * LPFC_ABORT_IOCB   if it is an abort iocb
+ * LPFC_UNSOL_IOCB   if it is an unsolicited iocb
+ *
+ * The caller is not required to hold any lock.
+ **/
 static lpfc_iocb_type
 lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
 {
@@ -219,7 +283,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
        case CMD_IOCB_LOGENTRY_CN:
        case CMD_IOCB_LOGENTRY_ASYNC_CN:
                printk("%s - Unhandled SLI-3 Command x%x\n",
-                               __FUNCTION__, iocb_cmnd);
+                               __func__, iocb_cmnd);
                type = LPFC_UNKNOWN_IOCB;
                break;
        default:
@@ -230,6 +294,17 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
        return type;
 }
 
+/**
+ * lpfc_sli_ring_map: Issue config_ring mbox for all rings.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called from SLI initialization code
+ * to configure every ring of the HBA's SLI interface. The
+ * caller is not required to hold any lock. This function issues
+ * a config_ring mailbox command for each ring.
+ * This function returns zero if successful else returns a negative
+ * error code.
+ **/
 static int
 lpfc_sli_ring_map(struct lpfc_hba *phba)
 {
@@ -262,6 +337,18 @@ lpfc_sli_ring_map(struct lpfc_hba *phba)
        return ret;
 }
 
+/**
+ * lpfc_sli_ringtxcmpl_put: Adds new iocb to the txcmplq.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @piocb: Pointer to the driver iocb object.
+ *
+ * This function is called with hbalock held. The function adds the
+ * new iocb to txcmplq of the given ring. This function always returns
+ * 0. If this function is called for ELS ring, this function checks if
+ * there is a vport associated with the ELS command. This function also
+ * starts els_tmofunc timer if this is an ELS command.
+ **/
 static int
 lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        struct lpfc_iocbq *piocb)
@@ -282,6 +369,16 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return 0;
 }
 
+/**
+ * lpfc_sli_ringtx_get: Get first element of the txq.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function is called with hbalock held to get next
+ * iocb in txq of the given ring. If there is any iocb in
+ * the txq, the function returns first iocb in the list after
+ * removing the iocb from the list, else it returns NULL.
+ **/
 static struct lpfc_iocbq *
 lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
@@ -293,14 +390,25 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        return cmd_iocb;
 }
 
+/**
+ * lpfc_sli_next_iocb_slot: Get next iocb slot in the ring.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function is called with hbalock held and the caller must post the
+ * iocb without releasing the lock. If the caller releases the lock,
+ * iocb slot returned by the function is not guaranteed to be available.
+ * The function returns pointer to the next available iocb slot if there
+ * is available slot in the ring, else it returns NULL.
+ * If the get index of the ring is ahead of the put index, the function
+ * will post an error attention event to the worker thread to take the
+ * HBA to offline state.
+ **/
 static IOCB_t *
 lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
-       struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
-               &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
-               &phba->slim2p->mbx.us.s2.port[pring->ringno];
+       struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
        uint32_t  max_cmd_idx = pring->numCiocb;
-
        if ((pring->next_cmdidx == pring->cmdidx) &&
           (++pring->next_cmdidx >= max_cmd_idx))
                pring->next_cmdidx = 0;
@@ -336,6 +444,18 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        return lpfc_cmd_iocb(phba, pring);
 }
 
+/**
+ * lpfc_sli_next_iotag: Get an iotag for the iocb.
+ * @phba: Pointer to HBA context object.
+ * @iocbq: Pointer to driver iocb object.
+ *
+ * This function gets an iotag for the iocb. If there is no unused iotag and
+ * the iocbq_lookup_len < 0xffff, this function allocates a bigger iotag_lookup
+ * array and assigns a new iotag.
+ * The function returns the allocated iotag if successful, else returns zero.
+ * Zero is not a valid iotag.
+ * The caller is not required to hold any lock.
+ **/
 uint16_t
 lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
 {
@@ -399,6 +519,20 @@ lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
        return 0;
 }
 
+/**
+ * lpfc_sli_submit_iocb: Submit an iocb to the firmware.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @iocb: Pointer to iocb slot in the ring.
+ * @nextiocb: Pointer to driver iocb object which need to be
+ *            posted to firmware.
+ *
+ * This function is called with hbalock held to post a new iocb to
+ * the firmware. This function copies the new iocb to ring iocb slot and
+ * updates the ring pointers. It adds the new iocb to txcmplq if there is
+ * a completion call back for this iocb else the function will free the
+ * iocb object.
+ **/
 static void
 lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                IOCB_t *iocb, struct lpfc_iocbq *nextiocb)
@@ -441,6 +575,18 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        writel(pring->cmdidx, &phba->host_gp[pring->ringno].cmdPutInx);
 }
 
+/**
+ * lpfc_sli_update_full_ring: Update the chip attention register.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * The caller is not required to hold any lock for calling this function.
+ * This function updates the chip attention bits for the ring to inform firmware
+ * that there are pending work to be done for this ring and requests an
+ * interrupt when there is space available in the ring. This function is
+ * called when the driver is unable to post more iocbs to the ring due
+ * to unavailability of space in the ring.
+ **/
 static void
 lpfc_sli_update_full_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
@@ -460,6 +606,15 @@ lpfc_sli_update_full_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        pring->stats.iocb_cmd_full++;
 }
 
+/**
+ * lpfc_sli_update_ring: Update chip attention register.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function updates the chip attention register bit for the
+ * given ring to inform HBA that there is more work to be done
+ * in this ring. The caller is not required to hold any lock.
+ **/
 static void
 lpfc_sli_update_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
@@ -468,11 +623,22 @@ lpfc_sli_update_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        /*
         * Tell the HBA that there is work to do in this ring.
         */
-       wmb();
-       writel(CA_R0ATT << (ringno * 4), phba->CAregaddr);
-       readl(phba->CAregaddr); /* flush */
+       if (!(phba->sli3_options & LPFC_SLI3_CRP_ENABLED)) {
+               wmb();
+               writel(CA_R0ATT << (ringno * 4), phba->CAregaddr);
+               readl(phba->CAregaddr); /* flush */
+       }
 }
 
+/**
+ * lpfc_sli_resume_iocb: Process iocbs in the txq.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function is called with hbalock held to post pending iocbs
+ * in the txq to the firmware. This function is called when driver
+ * detects space available in the ring.
+ **/
 static void
 lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
@@ -504,6 +670,16 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        return;
 }
 
+/**
+ * lpfc_sli_next_hbq_slot: Get next hbq entry for the HBQ.
+ * @phba: Pointer to HBA context object.
+ * @hbqno: HBQ number.
+ *
+ * This function is called with hbalock held to get the next
+ * available slot for the given HBQ. If there is free slot
+ * available for the HBQ it will return pointer to the next available
+ * HBQ entry else it will return NULL.
+ **/
 static struct lpfc_hbq_entry *
 lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
 {
@@ -539,6 +715,15 @@ lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
                        hbqp->hbqPutIdx;
 }
 
+/**
+ * lpfc_sli_hbqbuf_free_all: Free all the hbq buffers.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called with no lock held to free all the
+ * hbq buffers while uninitializing the SLI interface. It also
+ * frees the HBQ buffers returned by the firmware but not yet
+ * processed by the upper layers.
+ **/
 void
 lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
 {
@@ -584,6 +769,18 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
        spin_unlock_irqrestore(&phba->hbalock, flags);
 }
 
+/**
+ * lpfc_sli_hbq_to_firmware: Post the hbq buffer to firmware.
+ * @phba: Pointer to HBA context object.
+ * @hbqno: HBQ number.
+ * @hbq_buf: Pointer to HBQ buffer.
+ *
+ * This function is called with the hbalock held to post a
+ * hbq buffer to the firmware. If the function finds an empty
+ * slot in the HBQ, it will post the buffer. The function will return
+ * pointer to the hbq entry if it successfully post the buffer
+ * else it will return NULL.
+ **/
 static struct lpfc_hbq_entry *
 lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
                         struct hbq_dmabuf *hbq_buf)
@@ -612,6 +809,7 @@ lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
        return hbqe;
 }
 
+/* HBQ for ELS and CT traffic. */
 static struct lpfc_hbq_init lpfc_els_hbq = {
        .rn = 1,
        .entry_count = 200,
@@ -623,6 +821,7 @@ static struct lpfc_hbq_init lpfc_els_hbq = {
        .add_count = 5,
 };
 
+/* HBQ for the extra ring if needed */
 static struct lpfc_hbq_init lpfc_extra_hbq = {
        .rn = 1,
        .entry_count = 200,
@@ -634,51 +833,81 @@ static struct lpfc_hbq_init lpfc_extra_hbq = {
        .add_count = 5,
 };
 
+/* Array of HBQs */
 struct lpfc_hbq_init *lpfc_hbq_defs[] = {
        &lpfc_els_hbq,
        &lpfc_extra_hbq,
 };
 
+/**
+ * lpfc_sli_hbqbuf_fill_hbqs: Post more hbq buffers to HBQ.
+ * @phba: Pointer to HBA context object.
+ * @hbqno: HBQ number.
+ * @count: Number of HBQ buffers to be posted.
+ *
+ * This function is called with no lock held to post more hbq buffers to the
+ * given HBQ. The function returns the number of HBQ buffers successfully
+ * posted.
+ **/
 static int
 lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
 {
-       uint32_t i, start, end;
+       uint32_t i, posted = 0;
        unsigned long flags;
        struct hbq_dmabuf *hbq_buffer;
-
+       LIST_HEAD(hbq_buf_list);
        if (!phba->hbqs[hbqno].hbq_alloc_buffer)
                return 0;
 
-       start = phba->hbqs[hbqno].buffer_count;
-       end = count + start;
-       if (end > lpfc_hbq_defs[hbqno]->entry_count)
-               end = lpfc_hbq_defs[hbqno]->entry_count;
-
+       if ((phba->hbqs[hbqno].buffer_count + count) >
+           lpfc_hbq_defs[hbqno]->entry_count)
+               count = lpfc_hbq_defs[hbqno]->entry_count -
+                                       phba->hbqs[hbqno].buffer_count;
+       if (!count)
+               return 0;
+       /* Allocate HBQ entries */
+       for (i = 0; i < count; i++) {
+               hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
+               if (!hbq_buffer)
+                       break;
+               list_add_tail(&hbq_buffer->dbuf.list, &hbq_buf_list);
+       }
        /* Check whether HBQ is still in use */
        spin_lock_irqsave(&phba->hbalock, flags);
        if (!phba->hbq_in_use)
-               goto out;
-
-       /* Populate HBQ entries */
-       for (i = start; i < end; i++) {
-               hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
-               if (!hbq_buffer)
-                       goto err;
-               hbq_buffer->tag = (i | (hbqno << 16));
-               if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
+               goto err;
+       while (!list_empty(&hbq_buf_list)) {
+               list_remove_head(&hbq_buf_list, hbq_buffer, struct hbq_dmabuf,
+                                dbuf.list);
+               hbq_buffer->tag = (phba->hbqs[hbqno].buffer_count |
+                                     (hbqno << 16));
+               if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
                        phba->hbqs[hbqno].buffer_count++;
-               else
+                       posted++;
+               } else
                        (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
        }
-
- out:
        spin_unlock_irqrestore(&phba->hbalock, flags);
-       return 0;
- err:
+       return posted;
+err:
        spin_unlock_irqrestore(&phba->hbalock, flags);
-       return 1;
+       while (!list_empty(&hbq_buf_list)) {
+               list_remove_head(&hbq_buf_list, hbq_buffer, struct hbq_dmabuf,
+                                dbuf.list);
+               (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
+       }
+       return 0;
 }
 
+/**
+ * lpfc_sli_hbqbuf_add_hbqs: Post more HBQ buffers to firmware.
+ * @phba: Pointer to HBA context object.
+ * @qno: HBQ number.
+ *
+ * This function posts more buffers to the HBQ. This function
+ * is called with no lock held. The function returns the number of HBQ entries
+ * successfully allocated.
+ **/
 int
 lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno)
 {
@@ -686,6 +915,15 @@ lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno)
                                         lpfc_hbq_defs[qno]->add_count));
 }
 
+/**
+ * lpfc_sli_hbqbuf_init_hbqs: Post initial buffers to the HBQ.
+ * @phba: Pointer to HBA context object.
+ * @qno:  HBQ queue number.
+ *
+ * This function is called from SLI initialization code path with
+ * no lock held to post initial HBQ buffers to firmware. The
+ * function returns the number of HBQ entries successfully allocated.
+ **/
 static int
 lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno)
 {
@@ -693,6 +931,16 @@ lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno)
                                         lpfc_hbq_defs[qno]->init_count));
 }
 
+/**
+ * lpfc_sli_hbqbuf_find: Find the hbq buffer associated with a tag.
+ * @phba: Pointer to HBA context object.
+ * @tag: Tag of the hbq buffer.
+ *
+ * This function is called with hbalock held. This function searches
+ * for the hbq buffer associated with the given tag in the hbq buffer
+ * list. If it finds the hbq buffer, it returns the hbq_buffer other wise
+ * it returns NULL.
+ **/
 static struct hbq_dmabuf *
 lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
 {
@@ -716,6 +964,15 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
        return NULL;
 }
 
+/**
+ * lpfc_sli_free_hbq: Give back the hbq buffer to firmware.
+ * @phba: Pointer to HBA context object.
+ * @hbq_buffer: Pointer to HBQ buffer.
+ *
+ * This function is called with hbalock. This function gives back
+ * the hbq buffer to firmware. If the HBQ does not have space to
+ * post the buffer, it will free the buffer.
+ **/
 void
 lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *hbq_buffer)
 {
@@ -729,6 +986,15 @@ lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *hbq_buffer)
        }
 }
 
+/**
+ * lpfc_sli_chk_mbx_command: Check if the mailbox is a legitimate mailbox.
+ * @mbxCommand: mailbox command code.
+ *
+ * This function is called by the mailbox event handler function to verify
+ * that the completed mailbox command is a legitimate mailbox command. If the
+ * completed mailbox is not known to the function, it will return MBX_SHUTDOWN
+ * and the mailbox event handler will take the HBA offline.
+ **/
 static int
 lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
 {
@@ -785,6 +1051,8 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
        case MBX_REG_VPI:
        case MBX_UNREG_VPI:
        case MBX_HEARTBEAT:
+       case MBX_PORT_CAPABILITIES:
+       case MBX_PORT_IOV_CONTROL:
                ret = mbxCommand;
                break;
        default:
@@ -793,6 +1061,19 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
        }
        return ret;
 }
+
+/**
+ * lpfc_sli_wake_mbox_wait: Completion handler for mbox issued from
+ *          lpfc_sli_issue_mbox_wait.
+ * @phba: Pointer to HBA context object.
+ * @pmboxq: Pointer to mailbox command.
+ *
+ * This is completion handler function for mailbox commands issued from
+ * lpfc_sli_issue_mbox_wait function. This function is called by the
+ * mailbox event handler function with no lock held. This function
+ * will wake up thread waiting on the wait queue pointed by context1
+ * of the mailbox.
+ **/
 static void
 lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
 {
@@ -812,6 +1093,17 @@ lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
        return;
 }
 
+
+/**
+ * lpfc_sli_def_mbox_cmpl: Default mailbox completion handler.
+ * @phba: Pointer to HBA context object.
+ * @pmb: Pointer to mailbox object.
+ *
+ * This function is the default mailbox completion handler. It
+ * frees the memory resources associated with the completed mailbox
+ * command. If the completed command is a REG_LOGIN mailbox command,
+ * this function will issue a UREG_LOGIN to re-claim the RPI.
+ **/
 void
 lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
@@ -846,6 +1138,19 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        return;
 }
 
+/**
+ * lpfc_sli_handle_mb_event: Handle mailbox completions from firmware.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called with no lock held. This function processes all
+ * the completed mailbox commands and gives it to upper layers. The interrupt
+ * service routine processes mailbox completion interrupt and adds completed
+ * mailbox commands to the mboxq_cmpl queue and signals the worker thread.
+ * Worker thread call lpfc_sli_handle_mb_event, which will return the
+ * completed mailbox commands in mboxq_cmpl queue to the upper layers. This
+ * function returns the mailbox commands to the upper layer by calling the
+ * completion handler function of each mailbox.
+ **/
 int
 lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
 {
@@ -953,6 +1258,18 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
        return 0;
 }
 
+/**
+ * lpfc_sli_replace_hbqbuff: Replace the HBQ buffer with a new buffer.
+ * @phba: Pointer to HBA context object.
+ * @tag: Tag for the HBQ buffer.
+ *
+ * This function is called from unsolicited event handler code path to get the
+ * HBQ buffer associated with an unsolicited iocb. This function is called with
+ * no lock held. It returns the buffer associated with the given tag and posts
+ * another buffer to the firmware. Note that the new buffer must be allocated
+ * before taking the hbalock and that the hba lock must be held until it is
+ * finished with the hbq entry swap.
+ **/
 static struct lpfc_dmabuf *
 lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
 {
@@ -962,22 +1279,28 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
        dma_addr_t phys;        /* mapped address */
        unsigned long flags;
 
+       hbqno = tag >> 16;
+       new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
        /* Check whether HBQ is still in use */
        spin_lock_irqsave(&phba->hbalock, flags);
        if (!phba->hbq_in_use) {
+               if (new_hbq_entry)
+                       (phba->hbqs[hbqno].hbq_free_buffer)(phba,
+                                                           new_hbq_entry);
                spin_unlock_irqrestore(&phba->hbalock, flags);
                return NULL;
        }
 
        hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
        if (hbq_entry == NULL) {
+               if (new_hbq_entry)
+                       (phba->hbqs[hbqno].hbq_free_buffer)(phba,
+                                                           new_hbq_entry);
                spin_unlock_irqrestore(&phba->hbalock, flags);
                return NULL;
        }
        list_del(&hbq_entry->dbuf.list);
 
-       hbqno = tag >> 16;
-       new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
        if (new_hbq_entry == NULL) {
                list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list);
                spin_unlock_irqrestore(&phba->hbalock, flags);
@@ -997,6 +1320,18 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
        return &new_hbq_entry->dbuf;
 }
 
+/**
+ * lpfc_sli_get_buff: Get the buffer associated with the buffer tag.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @tag: buffer tag.
+ *
+ * This function is called with no lock held. When QUE_BUFTAG_BIT bit
+ * is set in the tag the buffer is posted for a particular exchange,
+ * the function will return the buffer without replacing the buffer.
+ * If the buffer is for unsolicited ELS or CT traffic, this function
+ * returns the buffer and also posts another buffer to the firmware.
+ **/
 static struct lpfc_dmabuf *
 lpfc_sli_get_buff(struct lpfc_hba *phba,
                        struct lpfc_sli_ring *pring,
@@ -1008,6 +1343,21 @@ lpfc_sli_get_buff(struct lpfc_hba *phba,
                return lpfc_sli_replace_hbqbuff(phba, tag);
 }
 
+
+/**
+ * lpfc_sli_process_unsol_iocb: Unsolicited iocb handler.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @saveq: Pointer to the unsolicited iocb.
+ *
+ * This function is called with no lock held by the ring event handler
+ * when there is an unsolicited iocb posted to the response ring by the
+ * firmware. This function gets the buffer associated with the iocbs
+ * and calls the event handler for the ring. This function handles both
+ * qring buffers and hbq buffers.
+ * When the function returns 1 the caller can free the iocb object otherwise
+ * upper layer functions will free the iocb objects.
+ **/
 static int
 lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                            struct lpfc_iocbq *saveq)
@@ -1192,6 +1542,18 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return 1;
 }
 
+/**
+ * lpfc_sli_iocbq_lookup: Find command iocb for the given response iocb.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @prspiocb: Pointer to response iocb object.
+ *
+ * This function looks up the iocb_lookup table to get the command iocb
+ * corresponding to the given response iocb using the iotag of the
+ * response iocb. This function is called with the hbalock held.
+ * This function returns the command iocb object if it finds the command
+ * iocb else returns NULL.
+ **/
 static struct lpfc_iocbq *
 lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
                      struct lpfc_sli_ring *pring,
@@ -1217,6 +1579,23 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
        return NULL;
 }
 
+/**
+ * lpfc_sli_process_sol_iocb: process solicited iocb completion.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @saveq: Pointer to the response iocb to be processed.
+ *
+ * This function is called by the ring event handler for non-fcp
+ * rings when there is a new response iocb in the response ring.
+ * The caller is not required to hold any locks. This function
+ * gets the command iocb associated with the response iocb and
+ * calls the completion handler for the command iocb. If there
+ * is no completion handler, the function will free the resources
+ * associated with command iocb. If the response iocb is for
+ * an already aborted command iocb, the status of the completion
+ * is changed to IOSTAT_LOCAL_REJECT/IOERR_SLI_ABORTED.
+ * This function always returns 1.
+ **/
 static int
 lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                          struct lpfc_iocbq *saveq)
@@ -1232,6 +1611,17 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        if (cmdiocbp) {
                if (cmdiocbp->iocb_cmpl) {
+                       /*
+                        * If an ELS command failed send an event to mgmt
+                        * application.
+                        */
+                       if (saveq->iocb.ulpStatus &&
+                            (pring->ringno == LPFC_ELS_RING) &&
+                            (cmdiocbp->iocb.ulpCommand ==
+                               CMD_ELS_REQUEST64_CR))
+                               lpfc_send_els_failure_event(phba,
+                                       cmdiocbp, saveq);
+
                        /*
                         * Post all ELS completions to the worker thread.
                         * All other are passed to the completion callback.
@@ -1282,12 +1672,20 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return rc;
 }
 
+/**
+ * lpfc_sli_rsp_pointers_error: Response ring pointer error handler.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function is called from the iocb ring event handlers when
+ * put pointer is ahead of the get pointer for a ring. This function signal
+ * an error attention condition to the worker thread and the worker
+ * thread will transition the HBA to offline state.
+ **/
 static void
 lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
-       struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
-               &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
-               &phba->slim2p->mbx.us.s2.port[pring->ringno];
+       struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
        /*
         * Ring <ringno> handler: portRspPut <portRspPut> is bigger then
         * rsp ring <portRspMax>
@@ -1312,6 +1710,51 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        return;
 }
 
+/**
+ * lpfc_poll_eratt: Error attention polling timer timeout handler.
+ * @ptr: Pointer to address of HBA context object.
+ *
+ * This function is invoked by the Error Attention polling timer when the
+ * timer times out. It will check the SLI Error Attention register for
+ * possible attention events. If so, it will post an Error Attention event
+ * and wake up worker thread to process it. Otherwise, it will set up the
+ * Error Attention polling timer for the next poll.
+ **/
+void lpfc_poll_eratt(unsigned long ptr)
+{
+       struct lpfc_hba *phba;
+       uint32_t eratt = 0;
+
+       phba = (struct lpfc_hba *)ptr;
+
+       /* Check chip HA register for error event */
+       eratt = lpfc_sli_check_eratt(phba);
+
+       if (eratt)
+               /* Tell the worker thread there is work to do */
+               lpfc_worker_wake_up(phba);
+       else
+               /* Restart the timer for next eratt poll */
+               mod_timer(&phba->eratt_poll, jiffies +
+                                       HZ * LPFC_ERATT_POLL_INTERVAL);
+       return;
+}
+
+/**
+ * lpfc_sli_poll_fcp_ring: Handle FCP ring completion in polling mode.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called from lpfc_queuecommand, lpfc_poll_timeout,
+ * lpfc_abort_handler and lpfc_slave_configure when FCP_RING_POLLING
+ * is enabled.
+ *
+ * The caller does not hold any lock.
+ * The function processes each response iocb in the response ring until it
+ * finds an iocb with LE bit set and chains all the iocbs upto the iocb with
+ * LE bit set. The function will call the completion handler of the command iocb
+ * if the response iocb indicates a completion for a command iocb or it is
+ * an abort completion.
+ **/
 void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
 {
        struct lpfc_sli      *psli  = &phba->sli;
@@ -1320,7 +1763,7 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
        IOCB_t *entry = NULL;
        struct lpfc_iocbq *cmdiocbq = NULL;
        struct lpfc_iocbq rspiocbq;
-       struct lpfc_pgp *pgp;
+       struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
        uint32_t status;
        uint32_t portRspPut, portRspMax;
        int type;
@@ -1330,11 +1773,6 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
 
        pring->stats.iocb_event++;
 
-       pgp = (phba->sli_rev == 3) ?
-               &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
-               &phba->slim2p->mbx.us.s2.port[pring->ringno];
-
-
        /*
         * The next available response entry should never exceed the maximum
         * entries.  If it does, treat it as an adapter hardware error.
@@ -1372,8 +1810,8 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
                                        irsp->un.ulpWord[3],
                                        irsp->un.ulpWord[4],
                                        irsp->un.ulpWord[5],
-                                       *(((uint32_t *) irsp) + 6),
-                                       *(((uint32_t *) irsp) + 7));
+                                       *(uint32_t *)&irsp->un1,
+                                       *((uint32_t *)&irsp->un1 + 1));
                }
 
                switch (type) {
@@ -1465,17 +1903,28 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
        return;
 }
 
-/*
+/**
+ * lpfc_sli_handle_fast_ring_event: Handle ring events on FCP ring.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @mask: Host attention register mask for this ring.
+ *
+ * This function is called from the interrupt context when there is a ring
+ * event for the fcp ring. The caller does not hold any lock.
+ * The function processes each response iocb in the response ring until it
+ * finds an iocb with LE bit set and chains all the iocbs upto the iocb with
+ * LE bit set. The function will call the completion handler of the command iocb
+ * if the response iocb indicates a completion for a command iocb or it is
+ * an abort completion. The function will call lpfc_sli_process_unsol_iocb
+ * function if this is an unsolicited iocb.
  * This routine presumes LPFC_FCP_RING handling and doesn't bother
- * to check it explicitly.
- */
+ * to check it explicitly. This function always returns 1.
+ **/
 static int
 lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
                                struct lpfc_sli_ring *pring, uint32_t mask)
 {
-       struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
-               &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
-               &phba->slim2p->mbx.us.s2.port[pring->ringno];
+       struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
        IOCB_t *irsp = NULL;
        IOCB_t *entry = NULL;
        struct lpfc_iocbq *cmdiocbq = NULL;
@@ -1548,8 +1997,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
                                        irsp->un.ulpWord[3],
                                        irsp->un.ulpWord[4],
                                        irsp->un.ulpWord[5],
-                                       *(((uint32_t *) irsp) + 6),
-                                       *(((uint32_t *) irsp) + 7));
+                                       *(uint32_t *)&irsp->un1,
+                                       *((uint32_t *)&irsp->un1 + 1));
                }
 
                switch (type) {
@@ -1646,13 +2095,28 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
        return rc;
 }
 
+/**
+ * lpfc_sli_handle_slow_ring_event: Handle ring events for non-FCP rings.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @mask: Host attention register mask for this ring.
+ *
+ * This function is called from the worker thread when there is a ring
+ * event for non-fcp rings. The caller does not hold any lock .
+ * The function processes each response iocb in the response ring until it
+ * finds an iocb with LE bit set and chains all the iocbs upto the iocb with
+ * LE bit set. The function will call lpfc_sli_process_sol_iocb function if the
+ * response iocb indicates a completion of a command iocb. The function
+ * will call lpfc_sli_process_unsol_iocb function if this is an unsolicited
+ * iocb. The function frees the resources or calls the completion handler if
+ * this iocb is an abort completion. The function returns 0 when the allocated
+ * iocbs are not freed, otherwise returns 1.
+ **/
 int
 lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
                                struct lpfc_sli_ring *pring, uint32_t mask)
 {
-       struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
-               &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
-               &phba->slim2p->mbx.us.s2.port[pring->ringno];
+       struct lpfc_pgp *pgp;
        IOCB_t *entry;
        IOCB_t *irsp = NULL;
        struct lpfc_iocbq *rspiocbp = NULL;
@@ -1666,6 +2130,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
        int rc = 1;
        unsigned long iflag;
 
+       pgp = &phba->port_gp[pring->ringno];
        spin_lock_irqsave(&phba->hbalock, iflag);
        pring->stats.iocb_event++;
 
@@ -1715,7 +2180,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
                rspiocbp = __lpfc_sli_get_iocbq(phba);
                if (rspiocbp == NULL) {
                        printk(KERN_ERR "%s: out of buffers! Failing "
-                              "completion.\n", __FUNCTION__);
+                              "completion.\n", __func__);
                        break;
                }
 
@@ -1904,6 +2369,16 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
        return rc;
 }
 
+/**
+ * lpfc_sli_abort_iocb_ring: Abort all iocbs in the ring.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function aborts all iocbs in the given ring and frees all the iocb
+ * objects in txq. This function issues an abort iocb for all the iocb commands
+ * in txcmplq. The iocbs in the txcmplq is not guaranteed to complete before
+ * the return of this function. The caller is not required to hold any locks.
+ **/
 void
 lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
@@ -1943,6 +2418,83 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        }
 }
 
+/**
+ * lpfc_sli_flush_fcp_rings: flush all iocbs in the fcp ring.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function flushes all iocbs in the fcp ring and frees all the iocb
+ * objects in txq and txcmplq. This function will not issue abort iocbs
+ * for all the iocb commands in txcmplq, they will just be returned with
+ * IOERR_SLI_DOWN. This function is invoked with EEH when device's PCI
+ * slot has been permanently disabled.
+ **/
+void
+lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
+{
+       LIST_HEAD(txq);
+       LIST_HEAD(txcmplq);
+       struct lpfc_iocbq *iocb;
+       IOCB_t *cmd = NULL;
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_sli_ring  *pring;
+
+       /* Currently, only one fcp ring */
+       pring = &psli->ring[psli->fcp_ring];
+
+       spin_lock_irq(&phba->hbalock);
+       /* Retrieve everything on txq */
+       list_splice_init(&pring->txq, &txq);
+       pring->txq_cnt = 0;
+
+       /* Retrieve everything on the txcmplq */
+       list_splice_init(&pring->txcmplq, &txcmplq);
+       pring->txcmplq_cnt = 0;
+       spin_unlock_irq(&phba->hbalock);
+
+       /* Flush the txq */
+       while (!list_empty(&txq)) {
+               iocb = list_get_first(&txq, struct lpfc_iocbq, list);
+               cmd = &iocb->iocb;
+               list_del_init(&iocb->list);
+
+               if (!iocb->iocb_cmpl)
+                       lpfc_sli_release_iocbq(phba, iocb);
+               else {
+                       cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       cmd->un.ulpWord[4] = IOERR_SLI_DOWN;
+                       (iocb->iocb_cmpl) (phba, iocb, iocb);
+               }
+       }
+
+       /* Flush the txcmpq */
+       while (!list_empty(&txcmplq)) {
+               iocb = list_get_first(&txcmplq, struct lpfc_iocbq, list);
+               cmd = &iocb->iocb;
+               list_del_init(&iocb->list);
+
+               if (!iocb->iocb_cmpl)
+                       lpfc_sli_release_iocbq(phba, iocb);
+               else {
+                       cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       cmd->un.ulpWord[4] = IOERR_SLI_DOWN;
+                       (iocb->iocb_cmpl) (phba, iocb, iocb);
+               }
+       }
+}
+
+/**
+ * lpfc_sli_brdready: Check for host status bits.
+ * @phba: Pointer to HBA context object.
+ * @mask: Bit mask to be checked.
+ *
+ * This function reads the host status register and compares
+ * with the provided bit mask to check if HBA completed
+ * the restart. This function will wait in a loop for the
+ * HBA to complete restart. If the HBA does not restart within
+ * 15 iterations, the function will reset the HBA again. The
+ * function returns 1 when HBA fail to restart otherwise returns
+ * zero.
+ **/
 int
 lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask)
 {
@@ -1990,6 +2542,13 @@ lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask)
 
 #define BARRIER_TEST_PATTERN (0xdeadbeef)
 
+/**
+ * lpfc_reset_barrier: Make HBA ready for HBA reset.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called before resetting an HBA. This
+ * function requests HBA to quiesce DMAs before a reset.
+ **/
 void lpfc_reset_barrier(struct lpfc_hba *phba)
 {
        uint32_t __iomem *resp_buf;
@@ -2063,6 +2622,17 @@ restore_hc:
        readl(phba->HCregaddr); /* flush */
 }
 
+/**
+ * lpfc_sli_brdkill: Issue a kill_board mailbox command.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function issues a kill_board mailbox command and waits for
+ * the error attention interrupt. This function is called for stopping
+ * the firmware processing. The caller is not required to hold any
+ * locks. This function calls lpfc_hba_down_post function to free
+ * any pending commands after the kill. The function will return 1 when it
+ * fails to kill the board else will return 0.
+ **/
 int
 lpfc_sli_brdkill(struct lpfc_hba *phba)
 {
@@ -2139,6 +2709,17 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
        return ha_copy & HA_ERATT ? 0 : 1;
 }
 
+/**
+ * lpfc_sli_brdreset: Reset the HBA.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function resets the HBA by writing HC_INITFF to the control
+ * register. After the HBA resets, this function resets all the iocb ring
+ * indices. This function disables PCI layer parity checking during
+ * the reset.
+ * This function returns 0 always.
+ * The caller is not required to hold any locks.
+ **/
 int
 lpfc_sli_brdreset(struct lpfc_hba *phba)
 {
@@ -2191,6 +2772,19 @@ lpfc_sli_brdreset(struct lpfc_hba *phba)
        return 0;
 }
 
+/**
+ * lpfc_sli_brdrestart: Restart the HBA.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called in the SLI initialization code path to
+ * restart the HBA. The caller is not required to hold any lock.
+ * This function writes MBX_RESTART mailbox command to the SLIM and
+ * resets the HBA. At the end of the function, it calls lpfc_hba_down_post
+ * function to free any pending commands. The function enables
+ * POST only during the first initialization. The function returns zero.
+ * The function does not guarantee completion of MBX_RESTART mailbox
+ * command before the return of this function.
+ **/
 int
 lpfc_sli_brdrestart(struct lpfc_hba *phba)
 {
@@ -2251,6 +2845,16 @@ lpfc_sli_brdrestart(struct lpfc_hba *phba)
        return 0;
 }
 
+/**
+ * lpfc_sli_chipset_init: Wait for the restart of the HBA after a restart.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called after a HBA restart to wait for successful
+ * restart of the HBA. Successful restart of the HBA is indicated by
+ * HS_FFRDY and HS_MBRDY bits. If the HBA fails to restart even after 15
+ * iteration, the function will restart the HBA again. The function returns
+ * zero if HBA successfully restarted else returns negative error code.
+ **/
 static int
 lpfc_sli_chipset_init(struct lpfc_hba *phba)
 {
@@ -2336,12 +2940,25 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
        return 0;
 }
 
+/**
+ * lpfc_sli_hbq_count: Get the number of HBQs to be configured.
+ *
+ * This function calculates and returns the number of HBQs required to be
+ * configured.
+ **/
 int
 lpfc_sli_hbq_count(void)
 {
        return ARRAY_SIZE(lpfc_hbq_defs);
 }
 
+/**
+ * lpfc_sli_hbq_entry_count: Calculate total number of hbq entries.
+ *
+ * This function adds the number of hbq entries in every HBQ to get
+ * the total number of hbq entries required for the HBA and returns
+ * the total count.
+ **/
 static int
 lpfc_sli_hbq_entry_count(void)
 {
@@ -2354,12 +2971,27 @@ lpfc_sli_hbq_entry_count(void)
        return count;
 }
 
+/**
+ * lpfc_sli_hbq_size: Calculate memory required for all hbq entries.
+ *
+ * This function calculates amount of memory required for all hbq entries
+ * to be configured and returns the total memory required.
+ **/
 int
 lpfc_sli_hbq_size(void)
 {
        return lpfc_sli_hbq_entry_count() * sizeof(struct lpfc_hbq_entry);
 }
 
+/**
+ * lpfc_sli_hbq_setup: configure and initialize HBQs.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called during the SLI initialization to configure
+ * all the HBQs and post buffers to the HBQ. The caller is not
+ * required to hold any locks. This function will return zero if successful
+ * else it will return negative error code.
+ **/
 static int
 lpfc_sli_hbq_setup(struct lpfc_hba *phba)
 {
@@ -2415,15 +3047,26 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba)
        mempool_free(pmb, phba->mbox_mem_pool);
 
        /* Initially populate or replenish the HBQs */
-       for (hbqno = 0; hbqno < hbq_count; ++hbqno) {
-               if (lpfc_sli_hbqbuf_init_hbqs(phba, hbqno))
-                       return -ENOMEM;
-       }
+       for (hbqno = 0; hbqno < hbq_count; ++hbqno)
+               lpfc_sli_hbqbuf_init_hbqs(phba, hbqno);
        return 0;
 }
 
-static int
-lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode)
+/**
+ * lpfc_sli_config_port: Issue config port mailbox command.
+ * @phba: Pointer to HBA context object.
+ * @sli_mode: sli mode - 2/3
+ *
+ * This function is called by the sli intialization code path
+ * to issue config_port mailbox command. This function restarts the
+ * HBA firmware and issues a config_port mailbox command to configure
+ * the SLI interface in the sli mode specified by sli_mode
+ * variable. The caller is not required to hold any locks.
+ * The function returns 0 if successful, else returns negative error
+ * code.
+ **/
+int
+lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
 {
        LPFC_MBOXQ_t *pmb;
        uint32_t resetcount = 0, rc = 0, done = 0;
@@ -2460,13 +3103,15 @@ lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode)
                if (rc == -ERESTART) {
                        phba->link_state = LPFC_LINK_UNKNOWN;
                        continue;
-               } else if (rc) {
+               } else if (rc)
                        break;
-               }
-
                phba->link_state = LPFC_INIT_MBX_CMDS;
                lpfc_config_port(phba, pmb);
                rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+               phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED |
+                                       LPFC_SLI3_HBQ_ENABLED |
+                                       LPFC_SLI3_CRP_ENABLED |
+                                       LPFC_SLI3_INB_ENABLED);
                if (rc != MBX_SUCCESS) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "0442 Adapter failed to init, mbxCmd x%x "
@@ -2476,30 +3121,64 @@ lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode)
                        phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
                        spin_unlock_irq(&phba->hbalock);
                        rc = -ENXIO;
-               } else {
+               } else
                        done = 1;
-                       phba->max_vpi = (phba->max_vpi &&
-                                        pmb->mb.un.varCfgPort.gmv) != 0
-                               ? pmb->mb.un.varCfgPort.max_vpi
-                               : 0;
-               }
        }
-
        if (!done) {
                rc = -EINVAL;
                goto do_prep_failed;
        }
-
-       if ((pmb->mb.un.varCfgPort.sli_mode == 3) &&
-               (!pmb->mb.un.varCfgPort.cMA)) {
-               rc = -ENXIO;
+       if (pmb->mb.un.varCfgPort.sli_mode == 3) {
+               if (!pmb->mb.un.varCfgPort.cMA) {
+                       rc = -ENXIO;
+                       goto do_prep_failed;
+               }
+               if (phba->max_vpi && pmb->mb.un.varCfgPort.gmv) {
+                       phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
+                       phba->max_vpi = pmb->mb.un.varCfgPort.max_vpi;
+               } else
+                       phba->max_vpi = 0;
+               if (pmb->mb.un.varCfgPort.gerbm)
+                       phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
+               if (pmb->mb.un.varCfgPort.gcrp)
+                       phba->sli3_options |= LPFC_SLI3_CRP_ENABLED;
+               if (pmb->mb.un.varCfgPort.ginb) {
+                       phba->sli3_options |= LPFC_SLI3_INB_ENABLED;
+                       phba->port_gp = phba->mbox->us.s3_inb_pgp.port;
+                       phba->inb_ha_copy = &phba->mbox->us.s3_inb_pgp.ha_copy;
+                       phba->inb_counter = &phba->mbox->us.s3_inb_pgp.counter;
+                       phba->inb_last_counter =
+                                       phba->mbox->us.s3_inb_pgp.counter;
+               } else {
+                       phba->port_gp = phba->mbox->us.s3_pgp.port;
+                       phba->inb_ha_copy = NULL;
+                       phba->inb_counter = NULL;
+               }
+       } else {
+               phba->port_gp = phba->mbox->us.s2.port;
+               phba->inb_ha_copy = NULL;
+               phba->inb_counter = NULL;
+               phba->max_vpi = 0;
        }
-
 do_prep_failed:
        mempool_free(pmb, phba->mbox_mem_pool);
        return rc;
 }
 
+
+/**
+ * lpfc_sli_hba_setup: SLI intialization function.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is the main SLI intialization function. This function
+ * is called by the HBA intialization code, HBA reset code and HBA
+ * error attention handler code. Caller is not required to hold any
+ * locks. This function issues config_port mailbox command to configure
+ * the SLI, setup iocb rings and HBQ rings. In the end the function
+ * calls the config_port_post function to issue init_link mailbox
+ * command and to start the discovery. The function will return zero
+ * if successful, else it will return negative error code.
+ **/
 int
 lpfc_sli_hba_setup(struct lpfc_hba *phba)
 {
@@ -2528,22 +3207,20 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
                break;
        }
 
-       rc = lpfc_do_config_port(phba, mode);
+       rc = lpfc_sli_config_port(phba, mode);
+
        if (rc && lpfc_sli_mode == 3)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
                                "1820 Unable to select SLI-3.  "
                                "Not supported by adapter.\n");
        if (rc && mode != 2)
-               rc = lpfc_do_config_port(phba, 2);
+               rc = lpfc_sli_config_port(phba, 2);
        if (rc)
                goto lpfc_sli_hba_setup_error;
 
        if (phba->sli_rev == 3) {
                phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE;
                phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE;
-               phba->sli3_options |= LPFC_SLI3_ENABLED;
-               phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
-
        } else {
                phba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE;
                phba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE;
@@ -2558,8 +3235,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
        if (rc)
                goto lpfc_sli_hba_setup_error;
 
-                               /* Init HBQs */
-
+       /* Init HBQs */
        if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
                rc = lpfc_sli_hbq_setup(phba);
                if (rc)
@@ -2581,19 +3257,19 @@ lpfc_sli_hba_setup_error:
        return rc;
 }
 
-/*! lpfc_mbox_timeout
- *
- * \pre
- * \post
- * \param hba Pointer to per struct lpfc_hba structure
- * \param l1  Pointer to the driver's mailbox queue.
- * \return
- *   void
- *
- * \b Description:
+
+/**
+ * lpfc_mbox_timeout: Timeout call back function for mbox timer.
+ * @ptr: context object - pointer to hba structure.
  *
- * This routine handles mailbox timeout events at timer interrupt context.
- */
+ * This is the callback function for mailbox timer. The mailbox
+ * timer is armed when a new mailbox command is issued and the timer
+ * is deleted when the mailbox complete. The function is called by
+ * the kernel timer code when a mailbox does not complete within
+ * expected time. This function wakes up the worker thread to
+ * process the mailbox timeout and returns. All the processing is
+ * done by the worker thread function lpfc_mbox_timeout_handler.
+ **/
 void
 lpfc_mbox_timeout(unsigned long ptr)
 {
@@ -2612,6 +3288,15 @@ lpfc_mbox_timeout(unsigned long ptr)
        return;
 }
 
+
+/**
+ * lpfc_mbox_timeout_handler: Worker thread function to handle mailbox timeout.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called from worker thread when a mailbox command times out.
+ * The caller is not required to hold any locks. This function will reset the
+ * HBA and recover all the pending commands.
+ **/
 void
 lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
 {
@@ -2666,6 +3351,32 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
        return;
 }
 
+/**
+ * lpfc_sli_issue_mbox: Issue a mailbox command to firmware.
+ * @phba: Pointer to HBA context object.
+ * @pmbox: Pointer to mailbox object.
+ * @flag: Flag indicating how the mailbox need to be processed.
+ *
+ * This function is called by discovery code and HBA management code
+ * to submit a mailbox command to firmware. This function gets the
+ * hbalock to protect the data structures.
+ * The mailbox command can be submitted in polling mode, in which case
+ * this function will wait in a polling loop for the completion of the
+ * mailbox.
+ * If the mailbox is submitted in no_wait mode (not polling) the
+ * function will submit the command and returns immediately without waiting
+ * for the mailbox completion. The no_wait is supported only when HBA
+ * is in SLI2/SLI3 mode - interrupts are enabled.
+ * The SLI interface allows only one mailbox pending at a time. If the
+ * mailbox is issued in polling mode and there is already a mailbox
+ * pending, then the function will return an error. If the mailbox is issued
+ * in NO_WAIT mode and there is a mailbox pending already, the function
+ * will return MBX_BUSY after queuing the mailbox into mailbox queue.
+ * The sli layer owns the mailbox object until the completion of mailbox
+ * command if this function return MBX_BUSY or MBX_SUCCESS. For all other
+ * return codes the caller owns the mailbox command after the return of
+ * the function.
+ **/
 int
 lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 {
@@ -2676,7 +3387,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
        int i;
        unsigned long timeout;
        unsigned long drvr_flag = 0;
-       volatile uint32_t word0, ldata;
+       uint32_t word0, ldata;
        void __iomem *to_slim;
        int processing_queue = 0;
 
@@ -2836,12 +3547,11 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 
        if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
                /* First copy command data to host SLIM area */
-               lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE);
+               lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
        } else {
                if (mb->mbxCommand == MBX_CONFIG_PORT) {
                        /* copy command data into host mbox for cmpl */
-                       lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx,
-                                             MAILBOX_CMD_SIZE);
+                       lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
                }
 
                /* First copy mbox command data to HBA SLIM, skip past first
@@ -2851,7 +3561,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                            MAILBOX_CMD_SIZE - sizeof (uint32_t));
 
                /* Next copy over first word, with mbxOwner set */
-               ldata = *((volatile uint32_t *)mb);
+               ldata = *((uint32_t *)mb);
                to_slim = phba->MBslimaddr;
                writel(ldata, to_slim);
                readl(to_slim); /* flush */
@@ -2883,7 +3593,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 
                if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
                        /* First read mbox status word */
-                       word0 = *((volatile uint32_t *)&phba->slim2p->mbx);
+                       word0 = *((uint32_t *)phba->mbox);
                        word0 = le32_to_cpu(word0);
                } else {
                        /* First read mbox status word */
@@ -2922,12 +3632,11 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 
                        if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
                                /* First copy command data */
-                               word0 = *((volatile uint32_t *)
-                                               &phba->slim2p->mbx);
+                               word0 = *((uint32_t *)phba->mbox);
                                word0 = le32_to_cpu(word0);
                                if (mb->mbxCommand == MBX_CONFIG_PORT) {
                                        MAILBOX_t *slimmb;
-                                       volatile uint32_t slimword0;
+                                       uint32_t slimword0;
                                        /* Check real SLIM for any errors */
                                        slimword0 = readl(phba->MBslimaddr);
                                        slimmb = (MAILBOX_t *) & slimword0;
@@ -2948,8 +3657,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 
                if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
                        /* copy results back to user */
-                       lpfc_sli_pcimem_bcopy(&phba->slim2p->mbx, mb,
-                                             MAILBOX_CMD_SIZE);
+                       lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE);
                } else {
                        /* First copy command data */
                        lpfc_memcpy_from_slim(mb, phba->MBslimaddr,
@@ -2980,9 +3688,16 @@ out_not_finished:
        return MBX_NOT_FINISHED;
 }
 
-/*
- * Caller needs to hold lock.
- */
+/**
+ * __lpfc_sli_ringtx_put: Add an iocb to the txq.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @piocb: Pointer to address of newly added command iocb.
+ *
+ * This function is called with hbalock held to add a command
+ * iocb to the txq when SLI layer cannot submit the command iocb
+ * to the ring.
+ **/
 static void
 __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                    struct lpfc_iocbq *piocb)
@@ -2992,6 +3707,23 @@ __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        pring->txq_cnt++;
 }
 
+/**
+ * lpfc_sli_next_iocb: Get the next iocb in the txq.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @piocb: Pointer to address of newly added command iocb.
+ *
+ * This function is called with hbalock held before a new
+ * iocb is submitted to the firmware. This function checks
+ * txq to flush the iocbs in txq to Firmware before
+ * submitting new iocbs to the Firmware.
+ * If there are iocbs in the txq which need to be submitted
+ * to firmware, lpfc_sli_next_iocb returns the first element
+ * of the txq after dequeuing it from txq.
+ * If there is no iocb in the txq then the function will return
+ * *piocb and *piocb is set to NULL. Caller needs to check
+ * *piocb to find if there are more commands in the txq.
+ **/
 static struct lpfc_iocbq *
 lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                   struct lpfc_iocbq **piocb)
@@ -3007,9 +3739,30 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return nextiocb;
 }
 
-/*
- * Lockless version of lpfc_sli_issue_iocb.
- */
+/**
+ * __lpfc_sli_issue_iocb: Lockless version of lpfc_sli_issue_iocb.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @piocb: Pointer to command iocb.
+ * @flag: Flag indicating if this command can be put into txq.
+ *
+ * __lpfc_sli_issue_iocb is used by other functions in the driver
+ * to issue an iocb command to the HBA. If the PCI slot is recovering
+ * from error state or if HBA is resetting or if LPFC_STOP_IOCB_EVENT
+ * flag is turned on, the function returns IOCB_ERROR.
+ * When the link is down, this function allows only iocbs for
+ * posting buffers.
+ * This function finds next available slot in the command ring and
+ * posts the command to the available slot and writes the port
+ * attention register to request HBA start processing new iocb.
+ * If there is no slot available in the ring and
+ * flag & SLI_IOCB_RET_IOCB is set, the new iocb is added to the
+ * txq, otherwise the function returns IOCB_BUSY.
+ *
+ * This function is called with hbalock held.
+ * The function will return success after it successfully submit the
+ * iocb to firmware or after adding to the txq.
+ **/
 static int
 __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                    struct lpfc_iocbq *piocb, uint32_t flag)
@@ -3052,6 +3805,16 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                 * can be issued if the link is not up.
                 */
                switch (piocb->iocb.ulpCommand) {
+               case CMD_GEN_REQUEST64_CR:
+               case CMD_GEN_REQUEST64_CX:
+                       if (!(phba->sli.sli_flag & LPFC_MENLO_MAINT) ||
+                               (piocb->iocb.un.genreq64.w5.hcsw.Rctl !=
+                                       FC_FCP_CMND) ||
+                               (piocb->iocb.un.genreq64.w5.hcsw.Type !=
+                                       MENLO_TRANSPORT_TYPE))
+
+                               goto iocb_busy;
+                       break;
                case CMD_QUE_RING_BUF_CN:
                case CMD_QUE_RING_BUF64_CN:
                        /*
@@ -3106,6 +3869,19 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 }
 
 
+/**
+ * lpfc_sli_issue_iocb: Wrapper function for __lpfc_sli_issue_iocb.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @piocb: Pointer to command iocb.
+ * @flag: Flag indicating if this command can be put into txq.
+ *
+ * lpfc_sli_issue_iocb is a wrapper around __lpfc_sli_issue_iocb
+ * function. This function gets the hbalock and calls
+ * __lpfc_sli_issue_iocb function and will return the error returned
+ * by __lpfc_sli_issue_iocb function. This wrapper is used by
+ * functions which do not hold hbalock.
+ **/
 int
 lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                    struct lpfc_iocbq *piocb, uint32_t flag)
@@ -3120,6 +3896,17 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return rc;
 }
 
+/**
+ * lpfc_extra_ring_setup: Extra ring setup function.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called while driver attaches with the
+ * HBA to setup the extra ring. The extra ring is used
+ * only when driver needs to support target mode functionality
+ * or IP over FC functionalities.
+ *
+ * This function is called with no lock held.
+ **/
 static int
 lpfc_extra_ring_setup( struct lpfc_hba *phba)
 {
@@ -3155,6 +3942,19 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
        return 0;
 }
 
+/**
+ * lpfc_sli_async_event_handler: ASYNC iocb handler function.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @iocbq: Pointer to iocb object.
+ *
+ * This function is called by the slow ring event handler
+ * function when there is an ASYNC event iocb in the ring.
+ * This function is called with no lock held.
+ * Currently this function handles only temperature related
+ * ASYNC events. The function decodes the temperature sensor
+ * event message and posts events for the management applications.
+ **/
 static void
 lpfc_sli_async_event_handler(struct lpfc_hba * phba,
        struct lpfc_sli_ring * pring, struct lpfc_iocbq * iocbq)
@@ -3210,6 +4010,17 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba,
 }
 
 
+/**
+ * lpfc_sli_setup: SLI ring setup function.
+ * @phba: Pointer to HBA context object.
+ *
+ * lpfc_sli_setup sets up rings of the SLI interface with
+ * number of iocbs per ring and iotags. This function is
+ * called while driver attach to the HBA and before the
+ * interrupts are enabled. So there is no need for locking.
+ *
+ * This function always returns 0.
+ **/
 int
 lpfc_sli_setup(struct lpfc_hba *phba)
 {
@@ -3321,6 +4132,17 @@ lpfc_sli_setup(struct lpfc_hba *phba)
        return 0;
 }
 
+/**
+ * lpfc_sli_queue_setup: Queue initialization function.
+ * @phba: Pointer to HBA context object.
+ *
+ * lpfc_sli_queue_setup sets up mailbox queues and iocb queues for each
+ * ring. This function also initializes ring indices of each ring.
+ * This function is called during the initialization of the SLI
+ * interface of an HBA.
+ * This function is called with no lock held and always returns
+ * 1.
+ **/
 int
 lpfc_sli_queue_setup(struct lpfc_hba *phba)
 {
@@ -3349,6 +4171,23 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)
        return 1;
 }
 
+/**
+ * lpfc_sli_host_down: Vport cleanup function.
+ * @vport: Pointer to virtual port object.
+ *
+ * lpfc_sli_host_down is called to clean up the resources
+ * associated with a vport before destroying virtual
+ * port data structures.
+ * This function does following operations:
+ * - Free discovery resources associated with this virtual
+ *   port.
+ * - Free iocbs associated with this virtual port in
+ *   the txq.
+ * - Send abort for all iocb commands associated with this
+ *   vport in txcmplq.
+ *
+ * This function is called with no lock held and always returns 1.
+ **/
 int
 lpfc_sli_host_down(struct lpfc_vport *vport)
 {
@@ -3411,6 +4250,21 @@ lpfc_sli_host_down(struct lpfc_vport *vport)
        return 1;
 }
 
+/**
+ * lpfc_sli_hba_down: Resource cleanup function for the HBA.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function cleans up all iocb, buffers, mailbox commands
+ * while shutting down the HBA. This function is called with no
+ * lock held and always returns 1.
+ * This function does the following to cleanup driver resources:
+ * - Free discovery resources for each virtual port
+ * - Cleanup any pending fabric iocbs
+ * - Iterate through the iocb txq and free each entry
+ *   in the list.
+ * - Free up any buffer posted to the HBA
+ * - Free mailbox commands in the mailbox queue.
+ **/
 int
 lpfc_sli_hba_down(struct lpfc_hba *phba)
 {
@@ -3501,6 +4355,18 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
        return 1;
 }
 
+/**
+ * lpfc_sli_pcimem_bcopy: SLI memory copy function.
+ * @srcp: Source memory pointer.
+ * @destp: Destination memory pointer.
+ * @cnt: Number of words required to be copied.
+ *
+ * This function is used for copying data between driver memory
+ * and the SLI memory. This function also changes the endianness
+ * of each word if native endianness is different from SLI
+ * endianness. This function can be called with or without
+ * lock.
+ **/
 void
 lpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
 {
@@ -3518,6 +4384,17 @@ lpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
        }
 }
 
+
+/**
+ * lpfc_sli_ringpostbuf_put: Function to add a buffer to postbufq.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @mp: Pointer to driver buffer object.
+ *
+ * This function is called with no lock held.
+ * It always return zero after adding the buffer to the postbufq
+ * buffer list.
+ **/
 int
 lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                         struct lpfc_dmabuf *mp)
@@ -3531,6 +4408,18 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return 0;
 }
 
+/**
+ * lpfc_sli_get_buffer_tag: Tag allocation function for a buffer posted
+ *          using CMD_QUE_XRI64_CX iocb.
+ * @phba: Pointer to HBA context object.
+ *
+ * When HBQ is enabled, buffers are searched based on tags. This function
+ * allocates a tag for buffer posted using CMD_QUE_XRI64_CX iocb. The
+ * tag is bit wise or-ed with QUE_BUFTAG_BIT to make sure that the tag
+ * does not conflict with tags of buffer posted for unsolicited events.
+ * The function returns the allocated tag. The function is called with
+ * no locks held.
+ **/
 uint32_t
 lpfc_sli_get_buffer_tag(struct lpfc_hba *phba)
 {
@@ -3545,6 +4434,22 @@ lpfc_sli_get_buffer_tag(struct lpfc_hba *phba)
        return phba->buffer_tag_count;
 }
 
+/**
+ * lpfc_sli_ring_taggedbuf_get: Search HBQ buffer associated with
+ *              posted using CMD_QUE_XRI64_CX iocb.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @tag: Buffer tag.
+ *
+ * Buffers posted using CMD_QUE_XRI64_CX iocb are in pring->postbufq
+ * list. After HBA DMA data to these buffers, CMD_IOCB_RET_XRI64_CX
+ * iocb is posted to the response ring with the tag of the buffer.
+ * This function searches the pring->postbufq list using the tag
+ * to find buffer associated with CMD_IOCB_RET_XRI64_CX
+ * iocb. If the buffer is found then lpfc_dmabuf object of the
+ * buffer is returned to the caller else NULL is returned.
+ * This function is called with no lock held.
+ **/
 struct lpfc_dmabuf *
 lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        uint32_t tag)
@@ -3565,7 +4470,7 @@ lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        spin_unlock_irq(&phba->hbalock);
        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                       "0410 Cannot find virtual addr for buffer tag on "
+                       "0402 Cannot find virtual addr for buffer tag on "
                        "ring %d Data x%lx x%p x%p x%x\n",
                        pring->ringno, (unsigned long) tag,
                        slp->next, slp->prev, pring->postbufq_cnt);
@@ -3573,6 +4478,23 @@ lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return NULL;
 }
 
+/**
+ * lpfc_sli_ringpostbuf_get: SLI2 buffer search function for
+ *      unsolicited ct and els events.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @phys: DMA address of the buffer.
+ *
+ * This function searches the buffer list using the dma_address
+ * of unsolicited event to find the driver's lpfc_dmabuf object
+ * corresponding to the dma_address. The function returns the
+ * lpfc_dmabuf object if a buffer is found else it returns NULL.
+ * This function is called by the ct and els unsolicited event
+ * handlers to get the buffer associated with the unsolicited
+ * event.
+ *
+ * This function is called with no lock held.
+ **/
 struct lpfc_dmabuf *
 lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                         dma_addr_t phys)
@@ -3600,6 +4522,17 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return NULL;
 }
 
+/**
+ * lpfc_sli_abort_els_cmpl: Completion handler for the els abort iocbs.
+ * @phba: Pointer to HBA context object.
+ * @cmdiocb: Pointer to driver command iocb object.
+ * @rspiocb: Pointer to driver response iocb object.
+ *
+ * This function is the completion handler for the abort iocbs for
+ * ELS commands. This function is called from the ELS ring event
+ * handler with no lock held. This function frees memory resources
+ * associated with the abort iocb.
+ **/
 static void
 lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        struct lpfc_iocbq *rspiocb)
@@ -3665,6 +4598,17 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        return;
 }
 
+/**
+ * lpfc_ignore_els_cmpl: Completion handler for aborted ELS command.
+ * @phba: Pointer to HBA context object.
+ * @cmdiocb: Pointer to driver command iocb object.
+ * @rspiocb: Pointer to driver response iocb object.
+ *
+ * The function is called from SLI ring event handler with no
+ * lock held. This function is the completion handler for ELS commands
+ * which are aborted. The function frees memory resources used for
+ * the aborted ELS commands.
+ **/
 static void
 lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                     struct lpfc_iocbq *rspiocb)
@@ -3673,7 +4617,7 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
        /* ELS cmd tag <ulpIoTag> completes */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "0133 Ignoring ELS cmd tag x%x completion Data: "
+                       "0139 Ignoring ELS cmd tag x%x completion Data: "
                        "x%x x%x x%x\n",
                        irsp->ulpIoTag, irsp->ulpStatus,
                        irsp->un.ulpWord[4], irsp->ulpTimeout);
@@ -3684,6 +4628,17 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        return;
 }
 
+/**
+ * lpfc_sli_issue_abort_iotag: Abort function for a command iocb.
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @cmdiocb: Pointer to driver command iocb object.
+ *
+ * This function issues an abort iocb for the provided command
+ * iocb. This function is called with hbalock held.
+ * The function returns 0 when it fails due to memory allocation
+ * failure or when the command iocb is an abort request.
+ **/
 int
 lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                           struct lpfc_iocbq *cmdiocb)
@@ -3748,6 +4703,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                         iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
        retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
 
+       if (retval)
+               __lpfc_sli_release_iocbq(phba, abtsiocbp);
 abort_iotag_exit:
        /*
         * Caller to this routine should check for IOCB_ERROR
@@ -3757,6 +4714,29 @@ abort_iotag_exit:
        return retval;
 }
 
+/**
+ * lpfc_sli_validate_fcp_iocb: Filtering function, used to find commands
+ *                    associated with a vport/SCSI target/lun.
+ * @iocbq: Pointer to driver iocb object.
+ * @vport: Pointer to driver virtual port object.
+ * @tgt_id: SCSI ID of the target.
+ * @lun_id: LUN ID of the scsi device.
+ * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST
+ *
+ * This function acts as iocb filter for functions which abort or count
+ * all FCP iocbs pending on a lun/SCSI target/SCSI host. It will return
+ * 0 if the filtering criteria is met for the given iocb and will return
+ * 1 if the filtering criteria is not met.
+ * If ctx_cmd == LPFC_CTX_LUN, the function returns 0 only if the
+ * given iocb is for the SCSI device specified by vport, tgt_id and
+ * lun_id parameter.
+ * If ctx_cmd == LPFC_CTX_TGT,  the function returns 0 only if the
+ * given iocb is for the SCSI target specified by vport and tgt_id
+ * parameters.
+ * If ctx_cmd == LPFC_CTX_HOST, the function returns 0 only if the
+ * given iocb is for the SCSI host associated with the given vport.
+ * This function is called with no locks held.
+ **/
 static int
 lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport,
                           uint16_t tgt_id, uint64_t lun_id,
@@ -3793,13 +4773,32 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport,
                break;
        default:
                printk(KERN_ERR "%s: Unknown context cmd type, value %d\n",
-                       __FUNCTION__, ctx_cmd);
+                       __func__, ctx_cmd);
                break;
        }
 
        return rc;
 }
 
+/**
+ * lpfc_sli_sum_iocb: Function to count the number of FCP iocbs pending.
+ * @vport: Pointer to virtual port.
+ * @tgt_id: SCSI ID of the target.
+ * @lun_id: LUN ID of the scsi device.
+ * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST.
+ *
+ * This function returns number of FCP commands pending for the vport.
+ * When ctx_cmd == LPFC_CTX_LUN, the function returns number of FCP
+ * commands pending on the vport associated with SCSI device specified
+ * by tgt_id and lun_id parameters.
+ * When ctx_cmd == LPFC_CTX_TGT, the function returns number of FCP
+ * commands pending on the vport associated with SCSI target specified
+ * by tgt_id parameter.
+ * When ctx_cmd == LPFC_CTX_HOST, the function returns number of FCP
+ * commands pending on the vport.
+ * This function returns the number of iocbs which satisfy the filter.
+ * This function is called without any lock held.
+ **/
 int
 lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id,
                  lpfc_ctx_cmd ctx_cmd)
@@ -3819,6 +4818,17 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id,
        return sum;
 }
 
+/**
+ * lpfc_sli_abort_fcp_cmpl: Completion handler function for an aborted
+ *       FCP iocb.
+ * @phba: Pointer to HBA context object
+ * @cmdiocb: Pointer to command iocb object.
+ * @rspiocb: Pointer to response iocb object.
+ *
+ * This function is called when an aborted FCP iocb completes. This
+ * function is called by the ring event handler with no lock held.
+ * This function frees the iocb.
+ **/
 void
 lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        struct lpfc_iocbq *rspiocb)
@@ -3827,6 +4837,28 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        return;
 }
 
+/**
+ * lpfc_sli_abort_iocb: This function issue abort for all SCSI commands
+ *          pending on a SCSI host(vport)/target/lun.
+ * @vport: Pointer to virtual port.
+ * @pring: Pointer to driver SLI ring object.
+ * @tgt_id: SCSI ID of the target.
+ * @lun_id: LUN ID of the scsi device.
+ * @abort_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST.
+ *
+ * This function sends an abort command for every SCSI command
+ * associated with the given virtual port pending on the ring
+ * filtered by lpfc_sli_validate_fcp_iocb function.
+ * When abort_cmd == LPFC_CTX_LUN, the function sends abort only to the
+ * FCP iocbs associated with lun specified by tgt_id and lun_id
+ * parameters
+ * When abort_cmd == LPFC_CTX_TGT, the function sends abort only to the
+ * FCP iocbs associated with SCSI target specified by tgt_id parameter.
+ * When abort_cmd == LPFC_CTX_HOST, the function sends abort to all
+ * FCP iocbs associated with virtual port.
+ * This function returns number of iocbs it failed to abort.
+ * This function is called with no locks held.
+ **/
 int
 lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
                    uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd abort_cmd)
@@ -3878,6 +4910,24 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
        return errcnt;
 }
 
+/**
+ * lpfc_sli_wake_iocb_wait: iocb completion handler for iocb issued using
+ *                          lpfc_sli_issue_iocb_wait.
+ * @phba: Pointer to HBA context object.
+ * @cmdiocbq: Pointer to command iocb.
+ * @rspiocbq: Pointer to response iocb.
+ *
+ * This function is the completion handler for iocbs issued using
+ * lpfc_sli_issue_iocb_wait function. This function is called by the
+ * ring event handler function without any lock held. This function
+ * can be called from both worker thread context and interrupt
+ * context. This function also can be called from other thread which
+ * cleans up the SLI layer objects.
+ * This function copy the contents of the response iocb to the
+ * response iocb memory object provided by the caller of
+ * lpfc_sli_issue_iocb_wait and then wakes up the thread which
+ * sleeps for the iocb completion.
+ **/
 static void
 lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
                        struct lpfc_iocbq *cmdiocbq,
@@ -3899,13 +4949,36 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
        return;
 }
 
-/*
- * Issue the caller's iocb and wait for its completion, but no longer than the
- * caller's timeout.  Note that iocb_flags is cleared before the
- * lpfc_sli_issue_call since the wake routine sets a unique value and by
- * definition this is a wait function.
- */
-
+/**
+ * lpfc_sli_issue_iocb_wait: Synchronous function to issue iocb commands.
+ * @phba: Pointer to HBA context object..
+ * @pring: Pointer to sli ring.
+ * @piocb: Pointer to command iocb.
+ * @prspiocbq: Pointer to response iocb.
+ * @timeout: Timeout in number of seconds.
+ *
+ * This function issues the iocb to firmware and waits for the
+ * iocb to complete. If the iocb command is not
+ * completed within timeout seconds, it returns IOCB_TIMEDOUT.
+ * Caller should not free the iocb resources if this function
+ * returns IOCB_TIMEDOUT.
+ * The function waits for the iocb completion using an
+ * non-interruptible wait.
+ * This function will sleep while waiting for iocb completion.
+ * So, this function should not be called from any context which
+ * does not allow sleeping. Due to the same reason, this function
+ * cannot be called with interrupt disabled.
+ * This function assumes that the iocb completions occur while
+ * this function sleep. So, this function cannot be called from
+ * the thread which process iocb completion for this ring.
+ * This function clears the iocb_flag of the iocb object before
+ * issuing the iocb and the iocb completion handler sets this
+ * flag and wakes this thread when the iocb completes.
+ * The contents of the response iocb will be copied to prspiocbq
+ * by the completion handler when the command completes.
+ * This function returns IOCB_SUCCESS when success.
+ * This function is called with no lock held.
+ **/
 int
 lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
                         struct lpfc_sli_ring *pring,
@@ -3963,7 +5036,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
                }
        } else {
                lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                               ":0332 IOCB wait issue failed, Data x%x\n",
+                               "0332 IOCB wait issue failed, Data x%x\n",
                                retval);
                retval = IOCB_ERROR;
        }
@@ -3983,6 +5056,32 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
        return retval;
 }
 
+/**
+ * lpfc_sli_issue_mbox_wait: Synchronous function to issue mailbox.
+ * @phba: Pointer to HBA context object.
+ * @pmboxq: Pointer to driver mailbox object.
+ * @timeout: Timeout in number of seconds.
+ *
+ * This function issues the mailbox to firmware and waits for the
+ * mailbox command to complete. If the mailbox command is not
+ * completed within timeout seconds, it returns MBX_TIMEOUT.
+ * The function waits for the mailbox completion using an
+ * interruptible wait. If the thread is woken up due to a
+ * signal, MBX_TIMEOUT error is returned to the caller. Caller
+ * should not free the mailbox resources, if this function returns
+ * MBX_TIMEOUT.
+ * This function will sleep while waiting for mailbox completion.
+ * So, this function should not be called from any context which
+ * does not allow sleeping. Due to the same reason, this function
+ * cannot be called with interrupt disabled.
+ * This function assumes that the mailbox completion occurs while
+ * this function sleep. So, this function cannot be called from
+ * the worker thread which processes mailbox completion.
+ * This function is called in the context of HBA management
+ * applications.
+ * This function returns MBX_SUCCESS when successful.
+ * This function is called with no lock held.
+ **/
 int
 lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
                         uint32_t timeout)
@@ -4027,6 +5126,18 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
        return retval;
 }
 
+/**
+ * lpfc_sli_flush_mbox_queue: mailbox queue cleanup function.
+ * @phba: Pointer to HBA context.
+ *
+ * This function is called to cleanup any pending mailbox
+ * objects in the driver queue before bringing the HBA offline.
+ * This function is called while resetting the HBA.
+ * The function is called without any lock held. The function
+ * takes hbalock to update SLI data structure.
+ * This function returns 1 when there is an active mailbox
+ * command pending else returns 0.
+ **/
 int
 lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
 {
@@ -4058,8 +5169,74 @@ lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
        return (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) ? 1 : 0;
 }
 
+/**
+ * lpfc_sli_check_eratt: check error attention events
+ * @phba: Pointer to HBA context.
+ *
+ * This function is called form timer soft interrupt context to check HBA's
+ * error attention register bit for error attention events.
+ *
+ * This fucntion returns 1 when there is Error Attention in the Host Attention
+ * Register and returns 0 otherwise.
+ **/
+int
+lpfc_sli_check_eratt(struct lpfc_hba *phba)
+{
+       uint32_t ha_copy;
+
+       /* If somebody is waiting to handle an eratt, don't process it
+        * here. The brdkill function will do this.
+        */
+       if (phba->link_flag & LS_IGNORE_ERATT)
+               return 0;
+
+       /* Check if interrupt handler handles this ERATT */
+       spin_lock_irq(&phba->hbalock);
+       if (phba->hba_flag & HBA_ERATT_HANDLED) {
+               /* Interrupt handler has handled ERATT */
+               spin_unlock_irq(&phba->hbalock);
+               return 0;
+       }
+
+       /* Read chip Host Attention (HA) register */
+       ha_copy = readl(phba->HAregaddr);
+       if (ha_copy & HA_ERATT) {
+               /* Read host status register to retrieve error event */
+               lpfc_sli_read_hs(phba);
+               /* Set the driver HA work bitmap */
+               phba->work_ha |= HA_ERATT;
+               /* Indicate polling handles this ERATT */
+               phba->hba_flag |= HBA_ERATT_HANDLED;
+               spin_unlock_irq(&phba->hbalock);
+               return 1;
+       }
+       spin_unlock_irq(&phba->hbalock);
+       return 0;
+}
+
+/**
+ * lpfc_sp_intr_handler: The slow-path interrupt handler of lpfc driver.
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is directly called from the PCI layer as an interrupt
+ * service routine when the device is enabled with MSI-X multi-message
+ * interrupt mode and there are slow-path events in the HBA. However,
+ * when the device is enabled with either MSI or Pin-IRQ interrupt mode,
+ * this function is called as part of the device-level interrupt handler.
+ * When the PCI slot is in error recovery or the HBA is undergoing
+ * initialization, the interrupt handler will not process the interrupt.
+ * The link attention and ELS ring attention events are handled by the
+ * worker thread. The interrupt handler signals the worker thread and
+ * and returns for these events. This function is called without any
+ * lock held. It gets the hbalock to access and update SLI data
+ * structures.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled else it
+ * returns IRQ_NONE.
+ **/
 irqreturn_t
-lpfc_intr_handler(int irq, void *dev_id)
+lpfc_sp_intr_handler(int irq, void *dev_id)
 {
        struct lpfc_hba  *phba;
        uint32_t ha_copy;
@@ -4078,48 +5255,52 @@ lpfc_intr_handler(int irq, void *dev_id)
         * Get the driver's phba structure from the dev_id and
         * assume the HBA is not interrupting.
         */
-       phba = (struct lpfc_hba *) dev_id;
+       phba = (struct lpfc_hba *)dev_id;
 
        if (unlikely(!phba))
                return IRQ_NONE;
 
-       /* If the pci channel is offline, ignore all the interrupts. */
-       if (unlikely(pci_channel_offline(phba->pcidev)))
-               return IRQ_NONE;
-
-       phba->sli.slistat.sli_intr++;
-
        /*
-        * Call the HBA to see if it is interrupting.  If not, don't claim
-        * the interrupt
-        */
-
-       /* Ignore all interrupts during initialization. */
-       if (unlikely(phba->link_state < LPFC_LINK_DOWN))
-               return IRQ_NONE;
-
-       /*
-        * Read host attention register to determine interrupt source
-        * Clear Attention Sources, except Error Attention (to
-        * preserve status) and Link Attention
-        */
-       spin_lock(&phba->hbalock);
-       ha_copy = readl(phba->HAregaddr);
-       /* If somebody is waiting to handle an eratt don't process it
-        * here.  The brdkill function will do this.
+        * Stuff needs to be attented to when this function is invoked as an
+        * individual interrupt handler in MSI-X multi-message interrupt mode
         */
-       if (phba->link_flag & LS_IGNORE_ERATT)
-               ha_copy &= ~HA_ERATT;
-       writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
-       readl(phba->HAregaddr); /* flush */
-       spin_unlock(&phba->hbalock);
-
-       if (unlikely(!ha_copy))
-               return IRQ_NONE;
+       if (phba->intr_type == MSIX) {
+               /* If the pci channel is offline, ignore all the interrupts */
+               if (unlikely(pci_channel_offline(phba->pcidev)))
+                       return IRQ_NONE;
+               /* Update device-level interrupt statistics */
+               phba->sli.slistat.sli_intr++;
+               /* Ignore all interrupts during initialization. */
+               if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+                       return IRQ_NONE;
+               /* Need to read HA REG for slow-path events */
+               spin_lock(&phba->hbalock);
+               ha_copy = readl(phba->HAregaddr);
+               /* If somebody is waiting to handle an eratt don't process it
+                * here. The brdkill function will do this.
+                */
+               if (phba->link_flag & LS_IGNORE_ERATT)
+                       ha_copy &= ~HA_ERATT;
+               /* Check the need for handling ERATT in interrupt handler */
+               if (ha_copy & HA_ERATT) {
+                       if (phba->hba_flag & HBA_ERATT_HANDLED)
+                               /* ERATT polling has handled ERATT */
+                               ha_copy &= ~HA_ERATT;
+                       else
+                               /* Indicate interrupt handler handles ERATT */
+                               phba->hba_flag |= HBA_ERATT_HANDLED;
+               }
+               /* Clear up only attention source related to slow-path */
+               writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)),
+                       phba->HAregaddr);
+               readl(phba->HAregaddr); /* flush */
+               spin_unlock(&phba->hbalock);
+       } else
+               ha_copy = phba->ha_copy;
 
        work_ha_copy = ha_copy & phba->work_ha_mask;
 
-       if (unlikely(work_ha_copy)) {
+       if (work_ha_copy) {
                if (work_ha_copy & HA_LATT) {
                        if (phba->sli.sli_flag & LPFC_PROCESS_LA) {
                                /*
@@ -4138,7 +5319,7 @@ lpfc_intr_handler(int irq, void *dev_id)
                                work_ha_copy &= ~HA_LATT;
                }
 
-               if (work_ha_copy & ~(HA_ERATT|HA_MBATT|HA_LATT)) {
+               if (work_ha_copy & ~(HA_ERATT | HA_MBATT | HA_LATT)) {
                        /*
                         * Turn off Slow Rings interrupts, LPFC_ELS_RING is
                         * the only slow ring.
@@ -4179,31 +5360,13 @@ lpfc_intr_handler(int irq, void *dev_id)
                                spin_unlock(&phba->hbalock);
                        }
                }
-
-               if (work_ha_copy & HA_ERATT) {
-                       /*
-                        * There was a link/board error.  Read the
-                        * status register to retrieve the error event
-                        * and process it.
-                        */
-                       phba->sli.slistat.err_attn_event++;
-                       /* Save status info */
-                       phba->work_hs = readl(phba->HSregaddr);
-                       phba->work_status[0] = readl(phba->MBslimaddr + 0xa8);
-                       phba->work_status[1] = readl(phba->MBslimaddr + 0xac);
-
-                       /* Clear Chip error bit */
-                       writel(HA_ERATT, phba->HAregaddr);
-                       readl(phba->HAregaddr); /* flush */
-                       phba->pport->stopped = 1;
-               }
-
                spin_lock(&phba->hbalock);
-               if ((work_ha_copy & HA_MBATT) &&
-                   (phba->sli.mbox_active)) {
+               if (work_ha_copy & HA_ERATT)
+                       lpfc_sli_read_hs(phba);
+               if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) {
                        pmb = phba->sli.mbox_active;
                        pmbox = &pmb->mb;
-                       mbox = &phba->slim2p->mbx;
+                       mbox = phba->mbox;
                        vport = pmb->vport;
 
                        /* First check out the status word */
@@ -4270,7 +5433,7 @@ lpfc_intr_handler(int irq, void *dev_id)
                                                        lpfc_printf_log(phba,
                                                        KERN_ERR,
                                                        LOG_MBOX | LOG_SLI,
-                                                       "0306 rc should have"
+                                                       "0350 rc should have"
                                                        "been MBX_BUSY");
                                                goto send_current_mbox;
                                        }
@@ -4283,6 +5446,7 @@ lpfc_intr_handler(int irq, void *dev_id)
                        }
                } else
                        spin_unlock(&phba->hbalock);
+
                if ((work_ha_copy & HA_MBATT) &&
                    (phba->sli.mbox_active == NULL)) {
 send_current_mbox:
@@ -4302,15 +5466,74 @@ send_current_mbox:
                spin_unlock(&phba->hbalock);
                lpfc_worker_wake_up(phba);
        }
+       return IRQ_HANDLED;
 
-       ha_copy &= ~(phba->work_ha_mask);
+} /* lpfc_sp_intr_handler */
+
+/**
+ * lpfc_fp_intr_handler: The fast-path interrupt handler of lpfc driver.
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is directly called from the PCI layer as an interrupt
+ * service routine when the device is enabled with MSI-X multi-message
+ * interrupt mode and there is a fast-path FCP IOCB ring event in the
+ * HBA. However, when the device is enabled with either MSI or Pin-IRQ
+ * interrupt mode, this function is called as part of the device-level
+ * interrupt handler. When the PCI slot is in error recovery or the HBA
+ * is undergoing initialization, the interrupt handler will not process
+ * the interrupt. The SCSI FCP fast-path ring event are handled in the
+ * intrrupt context. This function is called without any lock held. It
+ * gets the hbalock to access and update SLI data structures.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled else it
+ * returns IRQ_NONE.
+ **/
+irqreturn_t
+lpfc_fp_intr_handler(int irq, void *dev_id)
+{
+       struct lpfc_hba  *phba;
+       uint32_t ha_copy;
+       unsigned long status;
+
+       /* Get the driver's phba structure from the dev_id and
+        * assume the HBA is not interrupting.
+        */
+       phba = (struct lpfc_hba *) dev_id;
+
+       if (unlikely(!phba))
+               return IRQ_NONE;
+
+       /*
+        * Stuff needs to be attented to when this function is invoked as an
+        * individual interrupt handler in MSI-X multi-message interrupt mode
+        */
+       if (phba->intr_type == MSIX) {
+               /* If pci channel is offline, ignore all the interrupts */
+               if (unlikely(pci_channel_offline(phba->pcidev)))
+                       return IRQ_NONE;
+               /* Update device-level interrupt statistics */
+               phba->sli.slistat.sli_intr++;
+               /* Ignore all interrupts during initialization. */
+               if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+                       return IRQ_NONE;
+               /* Need to read HA REG for FCP ring and other ring events */
+               ha_copy = readl(phba->HAregaddr);
+               /* Clear up only attention source related to fast-path */
+               spin_lock(&phba->hbalock);
+               writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)),
+                       phba->HAregaddr);
+               readl(phba->HAregaddr); /* flush */
+               spin_unlock(&phba->hbalock);
+       } else
+               ha_copy = phba->ha_copy;
 
        /*
-        * Process all events on FCP ring.  Take the optimized path for
-        * FCP IO.  Any other IO is slow path and is handled by
-        * the worker thread.
+        * Process all events on FCP ring. Take the optimized path for FCP IO.
         */
-       status = (ha_copy & (HA_RXMASK  << (4*LPFC_FCP_RING)));
+       ha_copy &= ~(phba->work_ha_mask);
+
+       status = (ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING)));
        status >>= (4*LPFC_FCP_RING);
        if (status & HA_RXMASK)
                lpfc_sli_handle_fast_ring_event(phba,
@@ -4319,11 +5542,10 @@ send_current_mbox:
 
        if (phba->cfg_multi_ring_support == 2) {
                /*
-                * Process all events on extra ring.  Take the optimized path
-                * for extra ring IO.  Any other IO is slow path and is handled
-                * by the worker thread.
+                * Process all events on extra ring. Take the optimized path
+                * for extra ring IO.
                 */
-               status = (ha_copy & (HA_RXMASK  << (4*LPFC_EXTRA_RING)));
+               status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING)));
                status >>= (4*LPFC_EXTRA_RING);
                if (status & HA_RXMASK) {
                        lpfc_sli_handle_fast_ring_event(phba,
@@ -4332,5 +5554,106 @@ send_current_mbox:
                }
        }
        return IRQ_HANDLED;
+}  /* lpfc_fp_intr_handler */
+
+/**
+ * lpfc_intr_handler: The device-level interrupt handler of lpfc driver.
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is the device-level interrupt handler called from the PCI
+ * layer when either MSI or Pin-IRQ interrupt mode is enabled and there is
+ * an event in the HBA which requires driver attention. This function
+ * invokes the slow-path interrupt attention handling function and fast-path
+ * interrupt attention handling function in turn to process the relevant
+ * HBA attention events. This function is called without any lock held. It
+ * gets the hbalock to access and update SLI data structures.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled, else it
+ * returns IRQ_NONE.
+ **/
+irqreturn_t
+lpfc_intr_handler(int irq, void *dev_id)
+{
+       struct lpfc_hba  *phba;
+       irqreturn_t sp_irq_rc, fp_irq_rc;
+       unsigned long status1, status2;
+
+       /*
+        * Get the driver's phba structure from the dev_id and
+        * assume the HBA is not interrupting.
+        */
+       phba = (struct lpfc_hba *) dev_id;
+
+       if (unlikely(!phba))
+               return IRQ_NONE;
+
+       /* If the pci channel is offline, ignore all the interrupts. */
+       if (unlikely(pci_channel_offline(phba->pcidev)))
+               return IRQ_NONE;
+
+       /* Update device level interrupt statistics */
+       phba->sli.slistat.sli_intr++;
+
+       /* Ignore all interrupts during initialization. */
+       if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+               return IRQ_NONE;
+
+       spin_lock(&phba->hbalock);
+       phba->ha_copy = readl(phba->HAregaddr);
+       if (unlikely(!phba->ha_copy)) {
+               spin_unlock(&phba->hbalock);
+               return IRQ_NONE;
+       } else if (phba->ha_copy & HA_ERATT) {
+               if (phba->hba_flag & HBA_ERATT_HANDLED)
+                       /* ERATT polling has handled ERATT */
+                       phba->ha_copy &= ~HA_ERATT;
+               else
+                       /* Indicate interrupt handler handles ERATT */
+                       phba->hba_flag |= HBA_ERATT_HANDLED;
+       }
+
+       /* Clear attention sources except link and error attentions */
+       writel((phba->ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
+       readl(phba->HAregaddr); /* flush */
+       spin_unlock(&phba->hbalock);
+
+       /*
+        * Invokes slow-path host attention interrupt handling as appropriate.
+        */
+
+       /* status of events with mailbox and link attention */
+       status1 = phba->ha_copy & (HA_MBATT | HA_LATT | HA_ERATT);
+
+       /* status of events with ELS ring */
+       status2 = (phba->ha_copy & (HA_RXMASK  << (4*LPFC_ELS_RING)));
+       status2 >>= (4*LPFC_ELS_RING);
+
+       if (status1 || (status2 & HA_RXMASK))
+               sp_irq_rc = lpfc_sp_intr_handler(irq, dev_id);
+       else
+               sp_irq_rc = IRQ_NONE;
+
+       /*
+        * Invoke fast-path host attention interrupt handling as appropriate.
+        */
+
+       /* status of events with FCP ring */
+       status1 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING)));
+       status1 >>= (4*LPFC_FCP_RING);
+
+       /* status of events with extra ring */
+       if (phba->cfg_multi_ring_support == 2) {
+               status2 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING)));
+               status2 >>= (4*LPFC_EXTRA_RING);
+       } else
+               status2 = 0;
+
+       if ((status1 & HA_RXMASK) || (status2 & HA_RXMASK))
+               fp_irq_rc = lpfc_fp_intr_handler(irq, dev_id);
+       else
+               fp_irq_rc = IRQ_NONE;
 
-} /* lpfc_intr_handler */
+       /* Return device-level interrupt handling status */
+       return (sp_irq_rc == IRQ_HANDLED) ? sp_irq_rc : fp_irq_rc;
+}  /* lpfc_intr_handler */