/kern_2.6.32/drivers/scsi/lpfc/lpfc_sli.c
http://omnia2droid.googlecode.com/ · C · 11727 lines · 7311 code · 1016 blank · 3400 comment · 1121 complexity · 2dbf256a4c0bdc2091ab8a5cb5e4b7e7 MD5 · raw file
Large files are truncated click here to view the full file
- /*******************************************************************
- * This file is part of the Emulex Linux Device Driver for *
- * Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2009 Emulex. All rights reserved. *
- * EMULEX and SLI are trademarks of Emulex. *
- * www.emulex.com *
- * Portions Copyright (C) 2004-2005 Christoph Hellwig *
- * *
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of version 2 of the GNU General *
- * Public License as published by the Free Software Foundation. *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID. See the GNU General Public License for *
- * more details, a copy of which can be found in the file COPYING *
- * included with this package. *
- *******************************************************************/
- #include <linux/blkdev.h>
- #include <linux/pci.h>
- #include <linux/interrupt.h>
- #include <linux/delay.h>
- #include <scsi/scsi.h>
- #include <scsi/scsi_cmnd.h>
- #include <scsi/scsi_device.h>
- #include <scsi/scsi_host.h>
- #include <scsi/scsi_transport_fc.h>
- #include <scsi/fc/fc_fs.h>
- #include "lpfc_hw4.h"
- #include "lpfc_hw.h"
- #include "lpfc_sli.h"
- #include "lpfc_sli4.h"
- #include "lpfc_nl.h"
- #include "lpfc_disc.h"
- #include "lpfc_scsi.h"
- #include "lpfc.h"
- #include "lpfc_crtn.h"
- #include "lpfc_logmsg.h"
- #include "lpfc_compat.h"
- #include "lpfc_debugfs.h"
- #include "lpfc_vport.h"
- /* There are only four IOCB completion types. */
- typedef enum _lpfc_iocb_type {
- LPFC_UNKNOWN_IOCB,
- LPFC_UNSOL_IOCB,
- LPFC_SOL_IOCB,
- LPFC_ABORT_IOCB
- } lpfc_iocb_type;
- /* Provide function prototypes local to this module. */
- static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *,
- uint32_t);
- static int lpfc_sli4_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *,
- uint8_t *, uint32_t *);
- static IOCB_t *
- lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
- {
- return &iocbq->iocb;
- }
- /**
- * lpfc_sli4_wq_put - Put a Work Queue Entry on an Work Queue
- * @q: The Work Queue to operate on.
- * @wqe: The work Queue Entry to put on the Work queue.
- *
- * This routine will copy the contents of @wqe to the next available entry on
- * the @q. This function will then ring the Work Queue Doorbell to signal the
- * HBA to start processing the Work Queue Entry. This function returns 0 if
- * successful. If no entries are available on @q then this function will return
- * -ENOMEM.
- * The caller is expected to hold the hbalock when calling this routine.
- **/
- static uint32_t
- lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
- {
- union lpfc_wqe *temp_wqe = q->qe[q->host_index].wqe;
- struct lpfc_register doorbell;
- uint32_t host_index;
- /* If the host has not yet processed the next entry then we are done */
- if (((q->host_index + 1) % q->entry_count) == q->hba_index)
- return -ENOMEM;
- /* set consumption flag every once in a while */
- if (!((q->host_index + 1) % LPFC_RELEASE_NOTIFICATION_INTERVAL))
- bf_set(lpfc_wqe_gen_wqec, &wqe->generic, 1);
- lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
- /* Update the host index before invoking device */
- host_index = q->host_index;
- q->host_index = ((q->host_index + 1) % q->entry_count);
- /* Ring Doorbell */
- doorbell.word0 = 0;
- bf_set(lpfc_wq_doorbell_num_posted, &doorbell, 1);
- bf_set(lpfc_wq_doorbell_index, &doorbell, host_index);
- bf_set(lpfc_wq_doorbell_id, &doorbell, q->queue_id);
- writel(doorbell.word0, q->phba->sli4_hba.WQDBregaddr);
- readl(q->phba->sli4_hba.WQDBregaddr); /* Flush */
- return 0;
- }
- /**
- * lpfc_sli4_wq_release - Updates internal hba index for WQ
- * @q: The Work Queue to operate on.
- * @index: The index to advance the hba index to.
- *
- * This routine will update the HBA index of a queue to reflect consumption of
- * Work Queue Entries by the HBA. When the HBA indicates that it has consumed
- * an entry the host calls this function to update the queue's internal
- * pointers. This routine returns the number of entries that were consumed by
- * the HBA.
- **/
- static uint32_t
- lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index)
- {
- uint32_t released = 0;
- if (q->hba_index == index)
- return 0;
- do {
- q->hba_index = ((q->hba_index + 1) % q->entry_count);
- released++;
- } while (q->hba_index != index);
- return released;
- }
- /**
- * lpfc_sli4_mq_put - Put a Mailbox Queue Entry on an Mailbox Queue
- * @q: The Mailbox Queue to operate on.
- * @wqe: The Mailbox Queue Entry to put on the Work queue.
- *
- * This routine will copy the contents of @mqe to the next available entry on
- * the @q. This function will then ring the Work Queue Doorbell to signal the
- * HBA to start processing the Work Queue Entry. This function returns 0 if
- * successful. If no entries are available on @q then this function will return
- * -ENOMEM.
- * The caller is expected to hold the hbalock when calling this routine.
- **/
- static uint32_t
- lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe)
- {
- struct lpfc_mqe *temp_mqe = q->qe[q->host_index].mqe;
- struct lpfc_register doorbell;
- uint32_t host_index;
- /* If the host has not yet processed the next entry then we are done */
- if (((q->host_index + 1) % q->entry_count) == q->hba_index)
- return -ENOMEM;
- lpfc_sli_pcimem_bcopy(mqe, temp_mqe, q->entry_size);
- /* Save off the mailbox pointer for completion */
- q->phba->mbox = (MAILBOX_t *)temp_mqe;
- /* Update the host index before invoking device */
- host_index = q->host_index;
- q->host_index = ((q->host_index + 1) % q->entry_count);
- /* Ring Doorbell */
- doorbell.word0 = 0;
- bf_set(lpfc_mq_doorbell_num_posted, &doorbell, 1);
- bf_set(lpfc_mq_doorbell_id, &doorbell, q->queue_id);
- writel(doorbell.word0, q->phba->sli4_hba.MQDBregaddr);
- readl(q->phba->sli4_hba.MQDBregaddr); /* Flush */
- return 0;
- }
- /**
- * lpfc_sli4_mq_release - Updates internal hba index for MQ
- * @q: The Mailbox Queue to operate on.
- *
- * This routine will update the HBA index of a queue to reflect consumption of
- * a Mailbox Queue Entry by the HBA. When the HBA indicates that it has consumed
- * an entry the host calls this function to update the queue's internal
- * pointers. This routine returns the number of entries that were consumed by
- * the HBA.
- **/
- static uint32_t
- lpfc_sli4_mq_release(struct lpfc_queue *q)
- {
- /* Clear the mailbox pointer for completion */
- q->phba->mbox = NULL;
- q->hba_index = ((q->hba_index + 1) % q->entry_count);
- return 1;
- }
- /**
- * lpfc_sli4_eq_get - Gets the next valid EQE from a EQ
- * @q: The Event Queue to get the first valid EQE from
- *
- * This routine will get the first valid Event Queue Entry from @q, update
- * the queue's internal hba index, and return the EQE. If no valid EQEs are in
- * the Queue (no more work to do), or the Queue is full of EQEs that have been
- * processed, but not popped back to the HBA then this routine will return NULL.
- **/
- static struct lpfc_eqe *
- lpfc_sli4_eq_get(struct lpfc_queue *q)
- {
- struct lpfc_eqe *eqe = q->qe[q->hba_index].eqe;
- /* If the next EQE is not valid then we are done */
- if (!bf_get(lpfc_eqe_valid, eqe))
- return NULL;
- /* If the host has not yet processed the next entry then we are done */
- if (((q->hba_index + 1) % q->entry_count) == q->host_index)
- return NULL;
- q->hba_index = ((q->hba_index + 1) % q->entry_count);
- return eqe;
- }
- /**
- * lpfc_sli4_eq_release - Indicates the host has finished processing an EQ
- * @q: The Event Queue that the host has completed processing for.
- * @arm: Indicates whether the host wants to arms this CQ.
- *
- * This routine will mark all Event Queue Entries on @q, from the last
- * known completed entry to the last entry that was processed, as completed
- * by clearing the valid bit for each completion queue entry. Then it will
- * notify the HBA, by ringing the doorbell, that the EQEs have been processed.
- * The internal host index in the @q will be updated by this routine to indicate
- * that the host has finished processing the entries. The @arm parameter
- * indicates that the queue should be rearmed when ringing the doorbell.
- *
- * This function will return the number of EQEs that were popped.
- **/
- uint32_t
- lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
- {
- uint32_t released = 0;
- struct lpfc_eqe *temp_eqe;
- struct lpfc_register doorbell;
- /* while there are valid entries */
- while (q->hba_index != q->host_index) {
- temp_eqe = q->qe[q->host_index].eqe;
- bf_set(lpfc_eqe_valid, temp_eqe, 0);
- released++;
- q->host_index = ((q->host_index + 1) % q->entry_count);
- }
- if (unlikely(released == 0 && !arm))
- return 0;
- /* ring doorbell for number popped */
- doorbell.word0 = 0;
- if (arm) {
- bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1);
- bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1);
- }
- bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released);
- bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT);
- bf_set(lpfc_eqcq_doorbell_eqid, &doorbell, q->queue_id);
- writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
- return released;
- }
- /**
- * lpfc_sli4_cq_get - Gets the next valid CQE from a CQ
- * @q: The Completion Queue to get the first valid CQE from
- *
- * This routine will get the first valid Completion Queue Entry from @q, update
- * the queue's internal hba index, and return the CQE. If no valid CQEs are in
- * the Queue (no more work to do), or the Queue is full of CQEs that have been
- * processed, but not popped back to the HBA then this routine will return NULL.
- **/
- static struct lpfc_cqe *
- lpfc_sli4_cq_get(struct lpfc_queue *q)
- {
- struct lpfc_cqe *cqe;
- /* If the next CQE is not valid then we are done */
- if (!bf_get(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
- return NULL;
- /* If the host has not yet processed the next entry then we are done */
- if (((q->hba_index + 1) % q->entry_count) == q->host_index)
- return NULL;
- cqe = q->qe[q->hba_index].cqe;
- q->hba_index = ((q->hba_index + 1) % q->entry_count);
- return cqe;
- }
- /**
- * lpfc_sli4_cq_release - Indicates the host has finished processing a CQ
- * @q: The Completion Queue that the host has completed processing for.
- * @arm: Indicates whether the host wants to arms this CQ.
- *
- * This routine will mark all Completion queue entries on @q, from the last
- * known completed entry to the last entry that was processed, as completed
- * by clearing the valid bit for each completion queue entry. Then it will
- * notify the HBA, by ringing the doorbell, that the CQEs have been processed.
- * The internal host index in the @q will be updated by this routine to indicate
- * that the host has finished processing the entries. The @arm parameter
- * indicates that the queue should be rearmed when ringing the doorbell.
- *
- * This function will return the number of CQEs that were released.
- **/
- uint32_t
- lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
- {
- uint32_t released = 0;
- struct lpfc_cqe *temp_qe;
- struct lpfc_register doorbell;
- /* while there are valid entries */
- while (q->hba_index != q->host_index) {
- temp_qe = q->qe[q->host_index].cqe;
- bf_set(lpfc_cqe_valid, temp_qe, 0);
- released++;
- q->host_index = ((q->host_index + 1) % q->entry_count);
- }
- if (unlikely(released == 0 && !arm))
- return 0;
- /* ring doorbell for number popped */
- doorbell.word0 = 0;
- if (arm)
- bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1);
- bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released);
- bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_COMPLETION);
- bf_set(lpfc_eqcq_doorbell_cqid, &doorbell, q->queue_id);
- writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
- return released;
- }
- /**
- * lpfc_sli4_rq_put - Put a Receive Buffer Queue Entry on a Receive Queue
- * @q: The Header Receive Queue to operate on.
- * @wqe: The Receive Queue Entry to put on the Receive queue.
- *
- * This routine will copy the contents of @wqe to the next available entry on
- * the @q. This function will then ring the Receive Queue Doorbell to signal the
- * HBA to start processing the Receive Queue Entry. This function returns the
- * index that the rqe was copied to if successful. If no entries are available
- * on @q then this function will return -ENOMEM.
- * The caller is expected to hold the hbalock when calling this routine.
- **/
- static int
- lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq,
- struct lpfc_rqe *hrqe, struct lpfc_rqe *drqe)
- {
- struct lpfc_rqe *temp_hrqe = hq->qe[hq->host_index].rqe;
- struct lpfc_rqe *temp_drqe = dq->qe[dq->host_index].rqe;
- struct lpfc_register doorbell;
- int put_index = hq->host_index;
- if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ)
- return -EINVAL;
- if (hq->host_index != dq->host_index)
- return -EINVAL;
- /* If the host has not yet processed the next entry then we are done */
- if (((hq->host_index + 1) % hq->entry_count) == hq->hba_index)
- return -EBUSY;
- lpfc_sli_pcimem_bcopy(hrqe, temp_hrqe, hq->entry_size);
- lpfc_sli_pcimem_bcopy(drqe, temp_drqe, dq->entry_size);
- /* Update the host index to point to the next slot */
- hq->host_index = ((hq->host_index + 1) % hq->entry_count);
- dq->host_index = ((dq->host_index + 1) % dq->entry_count);
- /* Ring The Header Receive Queue Doorbell */
- if (!(hq->host_index % LPFC_RQ_POST_BATCH)) {
- doorbell.word0 = 0;
- bf_set(lpfc_rq_doorbell_num_posted, &doorbell,
- LPFC_RQ_POST_BATCH);
- bf_set(lpfc_rq_doorbell_id, &doorbell, hq->queue_id);
- writel(doorbell.word0, hq->phba->sli4_hba.RQDBregaddr);
- }
- return put_index;
- }
- /**
- * lpfc_sli4_rq_release - Updates internal hba index for RQ
- * @q: The Header Receive Queue to operate on.
- *
- * This routine will update the HBA index of a queue to reflect consumption of
- * one Receive Queue Entry by the HBA. When the HBA indicates that it has
- * consumed an entry the host calls this function to update the queue's
- * internal pointers. This routine returns the number of entries that were
- * consumed by the HBA.
- **/
- static uint32_t
- lpfc_sli4_rq_release(struct lpfc_queue *hq, struct lpfc_queue *dq)
- {
- if ((hq->type != LPFC_HRQ) || (dq->type != LPFC_DRQ))
- return 0;
- hq->hba_index = ((hq->hba_index + 1) % hq->entry_count);
- dq->hba_index = ((dq->hba_index + 1) % dq->entry_count);
- return 1;
- }
- /**
- * 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)
- {
- return (IOCB_t *) (((char *) pring->cmdringaddr) +
- 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)
- {
- return (IOCB_t *) (((char *) pring->rspringaddr) +
- 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)
- {
- struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
- struct lpfc_iocbq * iocbq = NULL;
- list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
- return iocbq;
- }
- /**
- * __lpfc_clear_active_sglq - Remove the active sglq for this XRI.
- * @phba: Pointer to HBA context object.
- * @xritag: XRI value.
- *
- * This function clears the sglq pointer from the array of acive
- * sglq's. The xritag that is passed in is used to index into the
- * array. Before the xritag can be used it needs to be adjusted
- * by subtracting the xribase.
- *
- * Returns sglq ponter = success, NULL = Failure.
- **/
- static struct lpfc_sglq *
- __lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
- {
- uint16_t adj_xri;
- struct lpfc_sglq *sglq;
- adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
- if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri)
- return NULL;
- sglq = phba->sli4_hba.lpfc_sglq_active_list[adj_xri];
- phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = NULL;
- return sglq;
- }
- /**
- * __lpfc_get_active_sglq - Get the active sglq for this XRI.
- * @phba: Pointer to HBA context object.
- * @xritag: XRI value.
- *
- * This function returns the sglq pointer from the array of acive
- * sglq's. The xritag that is passed in is used to index into the
- * array. Before the xritag can be used it needs to be adjusted
- * by subtracting the xribase.
- *
- * Returns sglq ponter = success, NULL = Failure.
- **/
- static struct lpfc_sglq *
- __lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
- {
- uint16_t adj_xri;
- struct lpfc_sglq *sglq;
- adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
- if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri)
- return NULL;
- sglq = phba->sli4_hba.lpfc_sglq_active_list[adj_xri];
- return sglq;
- }
- /**
- * __lpfc_sli_get_sglq - Allocates an iocb object from sgl pool
- * @phba: Pointer to HBA context object.
- *
- * This function is called with hbalock held. This function
- * Gets a new driver sglq object from the sglq list. If the
- * list is not empty then it is successful, it returns pointer to the newly
- * allocated sglq object else it returns NULL.
- **/
- static struct lpfc_sglq *
- __lpfc_sli_get_sglq(struct lpfc_hba *phba)
- {
- struct list_head *lpfc_sgl_list = &phba->sli4_hba.lpfc_sgl_list;
- struct lpfc_sglq *sglq = NULL;
- uint16_t adj_xri;
- list_remove_head(lpfc_sgl_list, sglq, struct lpfc_sglq, list);
- adj_xri = sglq->sli4_xritag - phba->sli4_hba.max_cfg_param.xri_base;
- phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq;
- return sglq;
- }
- /**
- * 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)
- {
- struct lpfc_iocbq * iocbq = NULL;
- unsigned long iflags;
- spin_lock_irqsave(&phba->hbalock, iflags);
- iocbq = __lpfc_sli_get_iocbq(phba);
- spin_unlock_irqrestore(&phba->hbalock, iflags);
- return iocbq;
- }
- /**
- * __lpfc_sli_release_iocbq_s4 - 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.
- * The sqlq structure that holds the xritag and phys and virtual
- * mappings for the scatter gather list is retrieved from the
- * active array of sglq. The get of the sglq pointer also clears
- * the entry in the array. If the status of the IO indiactes that
- * this IO was aborted then the sglq entry it put on the
- * lpfc_abts_els_sgl_list until the CQ_ABORTED_XRI is received. If the
- * IO has good status or fails for any other reason then the sglq
- * entry is added to the free list (lpfc_sgl_list).
- **/
- static void
- __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
- {
- struct lpfc_sglq *sglq;
- size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
- unsigned long iflag;
- if (iocbq->sli4_xritag == NO_XRI)
- sglq = NULL;
- else
- sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag);
- if (sglq) {
- if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED
- || ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
- && (iocbq->iocb.un.ulpWord[4]
- == IOERR_SLI_ABORTED))) {
- spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock,
- iflag);
- list_add(&sglq->list,
- &phba->sli4_hba.lpfc_abts_els_sgl_list);
- spin_unlock_irqrestore(
- &phba->sli4_hba.abts_sgl_list_lock, iflag);
- } else
- list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
- }
- /*
- * Clean all volatile data fields, preserve iotag and node struct.
- */
- memset((char *)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
- iocbq->sli4_xritag = NO_XRI;
- list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
- }
- /**
- * __lpfc_sli_release_iocbq_s3 - 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_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
- {
- size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
- /*
- * Clean all volatile data fields, preserve iotag and node struct.
- */
- memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
- iocbq->sli4_xritag = NO_XRI;
- 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 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)
- {
- phba->__lpfc_sli_release_iocbq(phba, 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 no lock held to release the iocb to
- * iocb pool.
- **/
- void
- lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
- {
- unsigned long iflags;
- /*
- * Clean all volatile data fields, preserve iotag and node struct.
- */
- spin_lock_irqsave(&phba->hbalock, iflags);
- __lpfc_sli_release_iocbq(phba, iocbq);
- spin_unlock_irqrestore(&phba->hbalock, iflags);
- }
- /**
- * lpfc_sli_cancel_iocbs - Cancel all iocbs from a list.
- * @phba: Pointer to HBA context object.
- * @iocblist: List of IOCBs.
- * @ulpstatus: ULP status in IOCB command field.
- * @ulpWord4: ULP word-4 in IOCB command field.
- *
- * This function is called with a list of IOCBs to cancel. It cancels the IOCB
- * on the list by invoking the complete callback function associated with the
- * IOCB with the provided @ulpstatus and @ulpword4 set to the IOCB commond
- * fields.
- **/
- void
- lpfc_sli_cancel_iocbs(struct lpfc_hba *phba, struct list_head *iocblist,
- uint32_t ulpstatus, uint32_t ulpWord4)
- {
- struct lpfc_iocbq *piocb;
- while (!list_empty(iocblist)) {
- list_remove_head(iocblist, piocb, struct lpfc_iocbq, list);
- if (!piocb->iocb_cmpl)
- lpfc_sli_release_iocbq(phba, piocb);
- else {
- piocb->iocb.ulpStatus = ulpstatus;
- piocb->iocb.un.ulpWord[4] = ulpWord4;
- (piocb->iocb_cmpl) (phba, piocb, piocb);
- }
- }
- return;
- }
- /**
- * 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)
- {
- lpfc_iocb_type type = LPFC_UNKNOWN_IOCB;
- if (iocb_cmnd > CMD_MAX_IOCB_CMD)
- return 0;
- switch (iocb_cmnd) {
- case CMD_XMIT_SEQUENCE_CR:
- case CMD_XMIT_SEQUENCE_CX:
- case CMD_XMIT_BCAST_CN:
- case CMD_XMIT_BCAST_CX:
- case CMD_ELS_REQUEST_CR:
- case CMD_ELS_REQUEST_CX:
- case CMD_CREATE_XRI_CR:
- case CMD_CREATE_XRI_CX:
- case CMD_GET_RPI_CN:
- case CMD_XMIT_ELS_RSP_CX:
- case CMD_GET_RPI_CR:
- case CMD_FCP_IWRITE_CR:
- case CMD_FCP_IWRITE_CX:
- case CMD_FCP_IREAD_CR:
- case CMD_FCP_IREAD_CX:
- case CMD_FCP_ICMND_CR:
- case CMD_FCP_ICMND_CX:
- case CMD_FCP_TSEND_CX:
- case CMD_FCP_TRSP_CX:
- case CMD_FCP_TRECEIVE_CX:
- case CMD_FCP_AUTO_TRSP_CX:
- case CMD_ADAPTER_MSG:
- case CMD_ADAPTER_DUMP:
- case CMD_XMIT_SEQUENCE64_CR:
- case CMD_XMIT_SEQUENCE64_CX:
- case CMD_XMIT_BCAST64_CN:
- case CMD_XMIT_BCAST64_CX:
- case CMD_ELS_REQUEST64_CR:
- case CMD_ELS_REQUEST64_CX:
- case CMD_FCP_IWRITE64_CR:
- case CMD_FCP_IWRITE64_CX:
- case CMD_FCP_IREAD64_CR:
- case CMD_FCP_IREAD64_CX:
- case CMD_FCP_ICMND64_CR:
- case CMD_FCP_ICMND64_CX:
- case CMD_FCP_TSEND64_CX:
- case CMD_FCP_TRSP64_CX:
- case CMD_FCP_TRECEIVE64_CX:
- case CMD_GEN_REQUEST64_CR:
- case CMD_GEN_REQUEST64_CX:
- case CMD_XMIT_ELS_RSP64_CX:
- case DSSCMD_IWRITE64_CR:
- case DSSCMD_IWRITE64_CX:
- case DSSCMD_IREAD64_CR:
- case DSSCMD_IREAD64_CX:
- case DSSCMD_INVALIDATE_DEK:
- case DSSCMD_SET_KEK:
- case DSSCMD_GET_KEK_ID:
- case DSSCMD_GEN_XFER:
- type = LPFC_SOL_IOCB;
- break;
- case CMD_ABORT_XRI_CN:
- case CMD_ABORT_XRI_CX:
- case CMD_CLOSE_XRI_CN:
- case CMD_CLOSE_XRI_CX:
- case CMD_XRI_ABORTED_CX:
- case CMD_ABORT_MXRI64_CN:
- type = LPFC_ABORT_IOCB;
- break;
- case CMD_RCV_SEQUENCE_CX:
- case CMD_RCV_ELS_REQ_CX:
- case CMD_RCV_SEQUENCE64_CX:
- case CMD_RCV_ELS_REQ64_CX:
- case CMD_ASYNC_STATUS:
- case CMD_IOCB_RCV_SEQ64_CX:
- case CMD_IOCB_RCV_ELS64_CX:
- case CMD_IOCB_RCV_CONT64_CX:
- case CMD_IOCB_RET_XRI64_CX:
- type = LPFC_UNSOL_IOCB;
- break;
- case CMD_IOCB_XMIT_MSEQ64_CR:
- case CMD_IOCB_XMIT_MSEQ64_CX:
- case CMD_IOCB_RCV_SEQ_LIST64_CX:
- case CMD_IOCB_RCV_ELS_LIST64_CX:
- case CMD_IOCB_CLOSE_EXTENDED_CN:
- case CMD_IOCB_ABORT_EXTENDED_CN:
- case CMD_IOCB_RET_HBQE64_CN:
- case CMD_IOCB_FCP_IBIDIR64_CR:
- case CMD_IOCB_FCP_IBIDIR64_CX:
- case CMD_IOCB_FCP_ITASKMGT64_CX:
- case CMD_IOCB_LOGENTRY_CN:
- case CMD_IOCB_LOGENTRY_ASYNC_CN:
- printk("%s - Unhandled SLI-3 Command x%x\n",
- __func__, iocb_cmnd);
- type = LPFC_UNKNOWN_IOCB;
- break;
- default:
- type = LPFC_UNKNOWN_IOCB;
- break;
- }
- 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)
- {
- struct lpfc_sli *psli = &phba->sli;
- LPFC_MBOXQ_t *pmb;
- MAILBOX_t *pmbox;
- int i, rc, ret = 0;
- pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!pmb)
- return -ENOMEM;
- pmbox = &pmb->u.mb;
- phba->link_state = LPFC_INIT_MBX_CMDS;
- for (i = 0; i < psli->num_rings; i++) {
- lpfc_config_ring(phba, i, pmb);
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
- if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0446 Adapter failed to init (%d), "
- "mbxCmd x%x CFG_RING, mbxStatus x%x, "
- "ring %d\n",
- rc, pmbox->mbxCommand,
- pmbox->mbxStatus, i);
- phba->link_state = LPFC_HBA_ERROR;
- ret = -ENXIO;
- break;
- }
- }
- mempool_free(pmb, phba->mbox_mem_pool);
- 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)
- {
- list_add_tail(&piocb->list, &pring->txcmplq);
- pring->txcmplq_cnt++;
- if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
- (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
- (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
- if (!piocb->vport)
- BUG();
- else
- mod_timer(&piocb->vport->els_tmofunc,
- jiffies + HZ * (phba->fc_ratov << 1));
- }
- 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)
- {
- struct lpfc_iocbq *cmd_iocb;
- list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list);
- if (cmd_iocb != NULL)
- pring->txq_cnt--;
- 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->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;
- if (unlikely(pring->local_getidx == pring->next_cmdidx)) {
- pring->local_getidx = le32_to_cpu(pgp->cmdGetInx);
- if (unlikely(pring->local_getidx >= max_cmd_idx)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0315 Ring %d issue: portCmdGet %d "
- "is bigger than cmd ring %d\n",
- pring->ringno,
- pring->local_getidx, max_cmd_idx);
- phba->link_state = LPFC_HBA_ERROR;
- /*
- * All error attention handlers are posted to
- * worker thread
- */
- phba->work_ha |= HA_ERATT;
- phba->work_hs = HS_FFER3;
- lpfc_worker_wake_up(phba);
- return NULL;
- }
- if (pring->local_getidx == pring->next_cmdidx)
- return NULL;
- }
- 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)
- {
- struct lpfc_iocbq **new_arr;
- struct lpfc_iocbq **old_arr;
- size_t new_len;
- struct lpfc_sli *psli = &phba->sli;
- uint16_t iotag;
- spin_lock_irq(&phba->hbalock);
- iotag = psli->last_iotag;
- if(++iotag < psli->iocbq_lookup_len) {
- psli->last_iotag = iotag;
- psli->iocbq_lookup[iotag] = iocbq;
- spin_unlock_irq(&phba->hbalock);
- iocbq->iotag = iotag;
- return iotag;
- } else if (psli->iocbq_lookup_len < (0xffff
- - LPFC_IOCBQ_LOOKUP_INCREMENT)) {
- new_len = psli->iocbq_lookup_len + LPFC_IOCBQ_LOOKUP_INCREMENT;
- spin_unlock_irq(&phba->hbalock);
- new_arr = kzalloc(new_len * sizeof (struct lpfc_iocbq *),
- GFP_KERNEL);
- if (new_arr) {
- spin_lock_irq(&phba->hbalock);
- old_arr = psli->iocbq_lookup;
- if (new_len <= psli->iocbq_lookup_len) {
- /* highly unprobable case */
- kfree(new_arr);
- iotag = psli->last_iotag;
- if(++iotag < psli->iocbq_lookup_len) {
- psli->last_iotag = iotag;
- psli->iocbq_lookup[iotag] = iocbq;
- spin_unlock_irq(&phba->hbalock);
- iocbq->iotag = iotag;
- return iotag;
- }
- spin_unlock_irq(&phba->hbalock);
- return 0;
- }
- if (psli->iocbq_lookup)
- memcpy(new_arr, old_arr,
- ((psli->last_iotag + 1) *
- sizeof (struct lpfc_iocbq *)));
- psli->iocbq_lookup = new_arr;
- psli->iocbq_lookup_len = new_len;
- psli->last_iotag = iotag;
- psli->iocbq_lookup[iotag] = iocbq;
- spin_unlock_irq(&phba->hbalock);
- iocbq->iotag = iotag;
- kfree(old_arr);
- return iotag;
- }
- } else
- spin_unlock_irq(&phba->hbalock);
- lpfc_printf_log(phba, KERN_ERR,LOG_SLI,
- "0318 Failed to allocate IOTAG.last IOTAG is %d\n",
- psli->last_iotag);
- 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)
- {
- /*
- * Set up an iotag
- */
- nextiocb->iocb.ulpIoTag = (nextiocb->iocb_cmpl) ? nextiocb->iotag : 0;
- if (pring->ringno == LPFC_ELS_RING) {
- lpfc_debugfs_slow_ring_trc(phba,
- "IOCB cmd ring: wd4:x%08x wd6:x%08x wd7:x%08x",
- *(((uint32_t *) &nextiocb->iocb) + 4),
- *(((uint32_t *) &nextiocb->iocb) + 6),
- *(((uint32_t *) &nextiocb->iocb) + 7));
- }
- /*
- * Issue iocb command to adapter
- */
- lpfc_sli_pcimem_bcopy(&nextiocb->iocb, iocb, phba->iocb_cmd_size);
- wmb();
- pring->stats.iocb_cmd++;
- /*
- * If there is no completion routine to call, we can release the
- * IOCB buffer back right now. For IOCBs, like QUE_RING_BUF,
- * that have no rsp ring completion, iocb_cmpl MUST be NULL.
- */
- if (nextiocb->iocb_cmpl)
- lpfc_sli_ringtxcmpl_put(phba, pring, nextiocb);
- else
- __lpfc_sli_release_iocbq(phba, nextiocb);
- /*
- * Let the HBA know what IOCB slot will be the next one the
- * driver will put a command into.
- */
- pring->cmdidx = pring->next_cmdidx;
- 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)
- {
- int ringno = pring->ringno;
- pring->flag |= LPFC_CALL_RING_AVAILABLE;
- wmb();
- /*
- * Set ring 'ringno' to SET R0CE_REQ in Chip Att register.
- * The HBA will tell us when an IOCB entry is available.
- */
- writel((CA_R0ATT|CA_R0CE_REQ) << (ringno*4), phba->CAregaddr);
- readl(phba->CAregaddr); /* flush */
- 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)
- {
- int ringno = pring->ringno;
- /*
- * Tell the HBA that there is work to do in this ring.
- */
- 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)
- {
- IOCB_t *iocb;
- struct lpfc_iocbq *nextiocb;
- /*
- * Check to see if:
- * (a) there is anything on the txq to send
- * (b) link is up
- * (c) link attention events can be processed (fcp ring only)
- * (d) IOCB processing is not blocked by the outstanding mbox command.
- */
- if (pring->txq_cnt &&
- lpfc_is_link_up(phba) &&
- (pring->ringno != phba->sli.fcp_ring ||
- phba->sli.sli_flag & LPFC_PROCESS_LA)) {
- while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
- (nextiocb = lpfc_sli_ringtx_get(phba, pring)))
- lpfc_sli_submit_iocb(phba, pring, iocb, nextiocb);
- if (iocb)
- lpfc_sli_update_ring(phba, pring);
- else
- lpfc_sli_update_full_ring(phba, 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)
- {
- struct hbq_s *hbqp = &phba->hbqs[hbqno];
- if (hbqp->next_hbqPutIdx == hbqp->hbqPutIdx &&
- ++hbqp->next_hbqPutIdx >= hbqp->entry_count)
- hbqp->next_hbqPutIdx = 0;
- if (unlikely(hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)) {
- uint32_t raw_index = phba->hbq_get[hbqno];
- uint32_t getidx = le32_to_cpu(raw_index);
- hbqp->local_hbqGetIdx = getidx;
- if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) {
- lpfc_printf_log(phba, KERN_ERR,
- LOG_SLI | LOG_VPORT,
- "1802 HBQ %d: local_hbqGetIdx "
- "%u is > than hbqp->entry_count %u\n",
- hbqno, hbqp->local_hbqGetIdx,
- hbqp->entry_count);
- phba->link_state = LPFC_HBA_ERROR;
- return NULL;
- }
- if (hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)
- return NULL;
- }
- return (struct lpfc_hbq_entry *) phba->hbqs[hbqno].hbq_virt +
- 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)
- {
- struct lpfc_dmabuf *dmabuf, *next_dmabuf;
- struct hbq_dmabuf *hbq_buf;
- unsigned long flags;
- int i, hbq_count;
- uint32_t hbqno;
- hbq_count = lpfc_sli_hbq_count();
- /* Return all memory used by all HBQs */
- spin_lock_irqsave(&phba->hbalock, flags);
- for (i = 0; i < hbq_count; ++i) {
- list_for_each_entry_safe(dmabuf, next_dmabuf,
- &phba->hbqs[i].hbq_buffer_list, list) {
- hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
- list_del(&hbq_buf->dbuf.list);
- (phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf);
- }
- phba->hbqs[i].buffer_count = 0;
- }
- /* Return all HBQ buffer that are in-fly */
- list_for_each_entry_safe(dmabuf, next_dmabuf, &phba->rb_pend_list,
- list) {
- hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
- list_del(&hbq_buf->dbuf.list);
- if (hbq_buf->tag == -1) {
- (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
- (phba, hbq_buf);
- } else {
- hbqno = hbq_buf->tag >> 16;
- if (hbqno >= LPFC_MAX_HBQS)
- (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
- (phba, hbq_buf);
- else
- (phba->hbqs[hbqno].hbq_free_buffer)(phba,
- hbq_buf);
- }
- }
- /* Mark the HBQs not in use */
- phba->hbq_in_use = 0;
- 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 int
- lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
- struct hbq_dmabuf *hbq_buf)
- {
- return phba->lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf);
- }
- /**
- * lpfc_sli_hbq_to_firmware_s3 - Post the hbq buffer to SLI3 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 and place it on the hbq_buffer_list. The function will return zero if
- * it successfully post the buffer else it will return an error.
- **/
- static int
- lpfc_sli_hbq_to_firmware_s3(struct lpfc_hba *phba, uint32_t hbqno,
- struct hbq_dmabuf *hbq_buf)
- {
- struct lpfc_hbq_entry *hbqe;
- dma_addr_t physaddr = hbq_buf->dbuf.phys;
- /* Get next HBQ entry slot to use */
- hbqe = lpfc_sli_next_hbq_slot(phba, hbqno);
- if (hbqe) {
- struct hbq_s *hbqp = &phba->hbqs[hbqno];
- hbqe->bde.addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
- hbqe->bde.addrLow = le32_to_cpu(putPaddrLow(physaddr));
- hbqe->bde.tus.f.bdeSize = hbq_buf->size;
- hbqe->bde.tus.f.bdeFlags = 0;
- hbqe->bde.tus.w = le32_to_cpu(hbqe->bde.tus.w);
- hbqe->buffer_tag = le32_to_cpu(hbq_buf->tag);
- /* Sync SLIM */
- hbqp->hbqPutIdx = hbqp->next_hbqPutIdx;
- writel(hbqp->hbqPutIdx, phba->hbq_put + hbqno);
- /* flush */
- readl(phba->hbq_put + hbqno);
- list_add_tail(&hbq_buf->dbuf.list, &hbqp->hbq_buffer_list);
- return 0;
- } else
- return -ENOMEM;
- }
- /**
- * lpfc_sli_hbq_to_firmware_s4 - Post the hbq buffer to SLI4 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 an RQE to the SLI4
- * firmware. If able to post the RQE to the RQ it will queue the hbq entry to
- * the hbq_buffer_list and return zero, otherwise it will return an error.
- **/
- static int
- lpfc_sli_hbq_to_firmware_s4(struct lpfc_hba *phba, uint32_t hbqno,
- struct hbq_dmabuf *hbq_buf)
- {
- int rc;
- struct lpfc_rqe hrqe;
- struct lpfc_rqe drqe;
- hrqe.address_lo = putPaddrLow(hbq_buf->hbuf.phys);
- hrqe.address_hi = putPaddrHigh(hbq_buf->hbuf.phys);
- drqe.address_lo = putPaddrLow(hbq_buf->dbuf.phys);
- drqe.address_hi = putPaddrHigh(hbq_buf->dbuf.phys);
- rc = lpfc_sli4_rq_put(phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq,
- &hrqe, &drqe);
- if (rc < 0)
- return rc;
- hbq_buf->tag = rc;
- list_add_tail(&hbq_buf->dbuf.list, &phba->hbqs[hbqno].hbq_buffer_list);
- return 0;
- }
- /* HBQ for ELS and CT traffic. */
- static struct lpfc_hbq_init lpfc_els_hbq = {
- .rn = 1,
- .entry_count = 200,
- .mask_count = 0,
- .profile = 0,
- .ring_mask = (1 << LPFC_ELS_RING),
- .buffer_count = 0,
- .init_count = 40,
- .add_count = 40,
- };
- /* HBQ for the extra ring if needed */
- static struct lpfc_hbq_init lpfc_extra_hbq = {
- .rn = 1,
- .entry_count = 200,
- .mask_count = 0,
- .profile = 0,
- .ring_mask = (1 << LPFC_EXTRA_RING),
- .buffer_count = 0,
- .init_count = 0,
- .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, posted = 0;
- unsigned long flags;
- struct hbq_dmabuf *hbq_buffer;
- LIST_HEAD(hbq_buf_list);
- if (!phba->hbqs[hbqno].hbq_alloc_buffer)
- return 0;
- 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 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++;
- posted++;
- } else
- (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
- }
- spin_unlock_irqrestore(&phba->hbalock, flags);
- return posted;
- err:
- spin_unlock_irqrestore(&phba->hbalock, flags);
- 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)
- {
- return(lpfc_sli_hbqbuf_fill_hbqs(phba, 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)
- {
- return(lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
- lpfc_hbq_defs[qno]->init_count));
- }
- /**
- * lpfc_sli_hbqbuf_get - Remove the first hbq off of an hbq list
- * @phba: Pointer to HBA context object.
- * @hbqno: HBQ number.
- *
- * This function removes the first hbq buffer on an hbq list and returns a
- * pointer to that buffer. If it finds no buffers on the list it returns NULL.
- **/
- static struct hbq_dmabuf *
- lpfc_sli_hbqbuf_get(struct list_head *rb_list)
- {
- struct lpfc_dmabuf *d_buf;
- list_remove_head(rb_list, d_buf, struct lpfc_dmabuf, list);
- if (!d_buf)
- return NULL;
- return container_of(d_buf, struct hbq_dmabuf, dbuf);
- }
- /**
- * 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)
- {
- struct lpfc_dmabuf *d_buf;
- struct hbq_dmabuf *hbq_buf;
- uint32_t hbqno;
- hbqno = tag >> 16;
- if (hbqno >= LPFC_MAX_HBQS)
- return NULL;
- spin_lock_irq(&phba->hbalock);
- list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
- hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
- if (hbq_buf->tag == tag) {
- spin_unlock_irq(&phba->hbalock);
- return hbq_buf;
- }
- }
- spin_unlock_irq(&phba->hbalock);
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
- "1803 Bad hbq tag. Data: x%x x%x\n",
- tag, phba->hbqs[tag >> 16].buffer_count);
- 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)
- {
- uint32_t hbqno;
- if (hbq_buffer) {
- hbqno = hbq_buffer->tag >> 16;
- if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
- (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
- }
- }…