summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2007-10-27 17:38:00 (GMT)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-12 00:22:33 (GMT)
commit76bb24efdc5de8eead0ccc07ec7e3b59a4ca0f15 (patch)
tree989311bb1be4a8331407bb6d3d67e5bd95e8a7a6
parenta8adb83208020c913f010cb4e26d09e25300db8e (diff)
downloadlinux-76bb24efdc5de8eead0ccc07ec7e3b59a4ca0f15.tar.xz
[SCSI] lpfc 8.2.3 : Internal loopback fixes
Internal loopback fixes: - Use HBQs rather than Q_RING_BUFF - Correct HBQs continuation entries - Update CT handler to SLI3 iocbs Signed-off-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/scsi/lpfc/lpfc.h7
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h31
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c123
4 files changed, 153 insertions, 13 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 636a930..46ccdff 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -68,6 +68,7 @@ struct lpfc_dmabuf {
struct list_head list;
void *virt; /* virtual address ptr */
dma_addr_t phys; /* mapped address */
+ uint32_t buffer_tag; /* used for tagged queue ring */
};
struct lpfc_dma_pool {
@@ -582,6 +583,12 @@ struct lpfc_hba {
unsigned long last_completion_time;
struct timer_list hb_tmofunc;
uint8_t hb_outstanding;
+ /*
+ * Following bit will be set for all buffer tags which are not
+ * associated with any HBQ.
+ */
+#define QUE_BUFTAG_BIT (1<<31)
+ uint32_t buffer_tag_count;
};
static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 338b5dd..87bea17 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -211,6 +211,11 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
struct lpfc_sli_ring *,
dma_addr_t);
+
+uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *);
+struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *,
+ struct lpfc_sli_ring *, uint32_t );
+
int lpfc_sli_hbq_count(void);
int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 8635b92..b61e45a 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1373,6 +1373,7 @@ typedef struct { /* FireFly BIU registers */
#define CMD_FCP_TRECEIVE64_CX 0xA1
#define CMD_FCP_TRSP64_CX 0xA3
+#define CMD_QUE_XRI64_CX 0xB3
#define CMD_IOCB_RCV_SEQ64_CX 0xB5
#define CMD_IOCB_RCV_ELS64_CX 0xB7
#define CMD_IOCB_RCV_CONT64_CX 0xBB
@@ -3039,7 +3040,26 @@ struct rcv_sli3 {
struct ulp_bde64 bde2;
};
+/* Structure used for a single HBQ entry */
+struct lpfc_hbq_entry {
+ struct ulp_bde64 bde;
+ uint32_t buffer_tag;
+};
+/* IOCB Command template for QUE_XRI64_CX (0xB3) command */
+typedef struct {
+ struct lpfc_hbq_entry buff;
+ uint32_t rsvd;
+ uint32_t rsvd1;
+} QUE_XRI64_CX_FIELDS;
+
+struct que_xri64cx_ext_fields {
+ uint32_t iotag64_low;
+ uint32_t iotag64_high;
+ uint32_t ebde_count;
+ uint32_t rsvd;
+ struct lpfc_hbq_entry buff[5];
+};
typedef struct _IOCB { /* IOCB structure */
union {
@@ -3064,6 +3084,7 @@ typedef struct _IOCB { /* IOCB structure */
FCPI_FIELDS64 fcpi64; /* FCP 64 bit Initiator template */
FCPT_FIELDS64 fcpt64; /* FCP 64 bit target template */
ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */
+ QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */
uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */
} un;
@@ -3121,6 +3142,10 @@ typedef struct _IOCB { /* IOCB structure */
union {
struct rcv_sli3 rcvsli3; /* words 8 - 15 */
+
+ /* words 8-31 used for que_xri_cx iocb */
+ struct que_xri64cx_ext_fields que_xri64cx_ext_words;
+
uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */
} unsli3;
@@ -3160,12 +3185,6 @@ typedef struct _IOCB { /* IOCB structure */
} IOCB_t;
-/* Structure used for a single HBQ entry */
-struct lpfc_hbq_entry {
- struct ulp_bde64 bde;
- uint32_t buffer_tag;
-};
-
#define SLI1_SLIM_SIZE (4 * 1024)
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index c3743d6..9bc85d5 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -931,6 +931,16 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
return &new_hbq_entry->dbuf;
}
+static struct lpfc_dmabuf *
+lpfc_sli_get_buff(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring,
+ uint32_t tag)
+{
+ if (tag & QUE_BUFTAG_BIT)
+ return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
+ else
+ return lpfc_sli_replace_hbqbuff(phba, tag);
+}
static int
lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
@@ -940,6 +950,7 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
WORD5 * w5p;
uint32_t Rctl, Type;
uint32_t match, i;
+ struct lpfc_iocbq *iocbq;
match = 0;
irsp = &(saveq->iocb);
@@ -984,12 +995,69 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
- if (irsp->ulpBdeCount != 0)
- saveq->context2 = lpfc_sli_replace_hbqbuff(phba,
+ struct lpfc_hbq_entry *hbqe_1, *hbqe_2;
+ hbqe_1 = (struct lpfc_hbq_entry *) &saveq->iocb.un.ulpWord[0];
+ hbqe_2 = (struct lpfc_hbq_entry *) &saveq->iocb.
+ unsli3.sli3Words[4];
+
+ if (irsp->ulpBdeCount != 0) {
+ saveq->context2 = lpfc_sli_get_buff(phba, pring,
irsp->un.ulpWord[3]);
- if (irsp->ulpBdeCount == 2)
- saveq->context3 = lpfc_sli_replace_hbqbuff(phba,
+ if (!saveq->context2)
+ lpfc_printf_log(phba,
+ KERN_ERR,
+ LOG_SLI,
+ "0341 Ring %d Cannot find buffer for "
+ "an unsolicited iocb. tag 0x%x\n",
+ pring->ringno,
+ irsp->un.ulpWord[3]);
+
+ }
+ if (irsp->ulpBdeCount == 2) {
+ saveq->context3 = lpfc_sli_get_buff(phba, pring,
irsp->unsli3.sli3Words[7]);
+ if (!saveq->context3)
+ lpfc_printf_log(phba,
+ KERN_ERR,
+ LOG_SLI,
+ "0342 Ring %d Cannot find buffer for an"
+ " unsolicited iocb. tag 0x%x\n",
+ pring->ringno,
+ irsp->unsli3.sli3Words[7]);
+ }
+ list_for_each_entry(iocbq, &saveq->list, list) {
+ hbqe_1 = (struct lpfc_hbq_entry *) &iocbq->iocb.
+ un.ulpWord[0];
+ hbqe_2 = (struct lpfc_hbq_entry *) &iocbq->iocb.
+ unsli3.sli3Words[4];
+ irsp = &(iocbq->iocb);
+
+ if (irsp->ulpBdeCount != 0) {
+ iocbq->context2 = lpfc_sli_get_buff(phba, pring,
+ irsp->un.ulpWord[3]);
+ if (!saveq->context2)
+ lpfc_printf_log(phba,
+ KERN_ERR,
+ LOG_SLI,
+ "0343 Ring %d Cannot find "
+ "buffer for an unsolicited iocb"
+ ". tag 0x%x\n", pring->ringno,
+ irsp->un.ulpWord[3]);
+ }
+ if (irsp->ulpBdeCount == 2) {
+ iocbq->context3 = lpfc_sli_get_buff(phba, pring,
+ irsp->unsli3.sli3Words[7]);
+ if (!saveq->context3)
+ lpfc_printf_log(phba,
+ KERN_ERR,
+ LOG_SLI,
+ "0344 Ring %d Cannot find "
+ "buffer for an unsolicited "
+ "iocb. tag 0x%x\n",
+ pring->ringno,
+ irsp->unsli3.sli3Words[7]);
+ }
+ }
}
/* unSolicited Responses */
@@ -2480,7 +2548,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
lpfc_sli_abort_iocb_ring(phba, pring);
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "0316 Resetting board due to mailbox timeout\n");
+ "0345 Resetting board due to mailbox timeout\n");
/*
* lpfc_offline calls lpfc_sli_hba_down which will clean up
* on oustanding mailbox commands.
@@ -2975,7 +3043,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba,
lpfc_printf_log(phba,
KERN_ERR,
LOG_SLI,
- "0327 Ring %d handler: unexpected ASYNC_STATUS"
+ "0346 Ring %d handler: unexpected ASYNC_STATUS"
" evt_code 0x%x\n",
pring->ringno,
icmd->un.asyncstat.evt_code);
@@ -2988,7 +3056,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba,
lpfc_printf_log(phba,
KERN_WARNING,
LOG_TEMP,
- "0339 Adapter is very hot, please take "
+ "0347 Adapter is very hot, please take "
"corrective action. temperature : %d Celsius\n",
temp);
}
@@ -3314,6 +3382,47 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
return 0;
}
+uint32_t
+lpfc_sli_get_buffer_tag(struct lpfc_hba *phba)
+{
+ spin_lock_irq(&phba->hbalock);
+ phba->buffer_tag_count++;
+ /*
+ * Always set the QUE_BUFTAG_BIT to distiguish between
+ * a tag assigned by HBQ.
+ */
+ phba->buffer_tag_count |= QUE_BUFTAG_BIT;
+ spin_unlock_irq(&phba->hbalock);
+ return phba->buffer_tag_count;
+}
+
+struct lpfc_dmabuf *
+lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ uint32_t tag)
+{
+ struct lpfc_dmabuf *mp, *next_mp;
+ struct list_head *slp = &pring->postbufq;
+
+ /* Search postbufq, from the begining, looking for a match on tag */
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
+ if (mp->buffer_tag == tag) {
+ list_del_init(&mp->list);
+ pring->postbufq_cnt--;
+ spin_unlock_irq(&phba->hbalock);
+ return mp;
+ }
+ }
+
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0410 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);
+
+ return NULL;
+}
struct lpfc_dmabuf *
lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,