aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/lpfc/lpfc_ct.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_ct.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c168
1 files changed, 110 insertions, 58 deletions
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 463b74902ac..da61d8dc044 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2010 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2013 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -48,14 +48,14 @@
#include "lpfc_vport.h"
#include "lpfc_debugfs.h"
-#define HBA_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver
- * incapable of reporting */
-#define HBA_PORTSPEED_1GBIT 1 /* 1 GBit/sec */
-#define HBA_PORTSPEED_2GBIT 2 /* 2 GBit/sec */
-#define HBA_PORTSPEED_4GBIT 8 /* 4 GBit/sec */
-#define HBA_PORTSPEED_8GBIT 16 /* 8 GBit/sec */
-#define HBA_PORTSPEED_10GBIT 4 /* 10 GBit/sec */
-#define HBA_PORTSPEED_NOT_NEGOTIATED 5 /* Speed not established */
+/* FDMI Port Speed definitions */
+#define HBA_PORTSPEED_1GBIT 0x0001 /* 1 GBit/sec */
+#define HBA_PORTSPEED_2GBIT 0x0002 /* 2 GBit/sec */
+#define HBA_PORTSPEED_4GBIT 0x0008 /* 4 GBit/sec */
+#define HBA_PORTSPEED_10GBIT 0x0004 /* 10 GBit/sec */
+#define HBA_PORTSPEED_8GBIT 0x0010 /* 8 GBit/sec */
+#define HBA_PORTSPEED_16GBIT 0x0020 /* 16 GBit/sec */
+#define HBA_PORTSPEED_UNKNOWN 0x0800 /* Unknown */
#define FOURBYTES 4
@@ -104,7 +104,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
} else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
+ ((icmd->un.ulpWord[4] & IOERR_PARAM_MASK) ==
+ IOERR_RCV_BUFFER_WAITING)) {
/* Not enough posted buffers; Try posting more buffers */
phba->fc_stat.NoRcvBuf++;
if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
@@ -163,37 +164,24 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
/**
- * lpfc_sli4_ct_abort_unsol_event - Default handle for sli4 unsol abort
+ * lpfc_ct_handle_unsol_abort - ct upper level protocol abort handler
* @phba: Pointer to HBA context object.
- * @pring: Pointer to the driver internal I/O ring.
- * @piocbq: Pointer to the IOCBQ.
+ * @dmabuf: pointer to a dmabuf that describes the FC sequence
*
- * This function serves as the default handler for the sli4 unsolicited
- * abort event. It shall be invoked when there is no application interface
- * registered unsolicited abort handler. This handler does nothing but
- * just simply releases the dma buffer used by the unsol abort event.
+ * This function serves as the upper level protocol abort handler for CT
+ * protocol.
+ *
+ * Return 1 if abort has been handled, 0 otherwise.
**/
-void
-lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba,
- struct lpfc_sli_ring *pring,
- struct lpfc_iocbq *piocbq)
+int
+lpfc_ct_handle_unsol_abort(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf)
{
- IOCB_t *icmd = &piocbq->iocb;
- struct lpfc_dmabuf *bdeBuf;
- uint32_t size;
+ int handled;
- /* Forward abort event to any process registered to receive ct event */
- if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0)
- return;
+ /* CT upper level goes through BSG */
+ handled = lpfc_bsg_ct_unsol_abort(phba, dmabuf);
- /* If there is no BDE associated with IOCB, there is nothing to do */
- if (icmd->ulpBdeCount == 0)
- return;
- bdeBuf = piocbq->context2;
- piocbq->context2 = NULL;
- size = icmd->un.cont64[0].tus.f.bdeSize;
- lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
- lpfc_in_buf_free(phba, bdeBuf);
+ return handled;
}
static void
@@ -292,7 +280,7 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3;
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
kfree(buf_ptr);
- ctiocb->context1 = NULL;
+ ctiocb->context3 = NULL;
}
lpfc_sli_release_iocbq(phba, ctiocb);
return 0;
@@ -352,6 +340,8 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
icmd->ulpLe = 1;
icmd->ulpClass = CLASS3;
icmd->ulpContext = ndlp->nlp_rpi;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
/* For GEN_REQUEST64_CR, use the RPI */
@@ -631,7 +621,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* Check for retry */
if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
- irsp->un.ulpWord[4] != IOERR_NO_RESOURCES)
+ (irsp->un.ulpWord[4] & IOERR_PARAM_MASK) !=
+ IOERR_NO_RESOURCES)
vport->fc_ns_retry++;
/* CT command is being retried */
@@ -781,7 +772,9 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (cmdiocb->retry < LPFC_MAX_NS_RETRY) {
retry = 1;
if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
- switch (irsp->un.ulpWord[4]) {
+ switch ((irsp->un.ulpWord[4] &
+ IOERR_PARAM_MASK)) {
+
case IOERR_NO_RESOURCES:
/* We don't increment the retry
* count for this case.
@@ -902,12 +895,14 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (irsp->ulpStatus) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
- "0268 NS cmd %x Error (%d %d)\n",
+ "0268 NS cmd x%x Error (x%x x%x)\n",
cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]);
if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)))
+ (((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) ==
+ IOERR_SLI_DOWN) ||
+ ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) ==
+ IOERR_SLI_ABORTED)))
goto out;
retry = cmdiocb->retry;
@@ -1074,7 +1069,7 @@ int
lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
size_t size)
{
- char fwrev[16];
+ char fwrev[FW_REV_STR_SIZE];
int n;
lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
@@ -1593,8 +1588,10 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
ae->un.SupportSpeed = 0;
+ if (phba->lmt & LMT_16Gb)
+ ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT;
if (phba->lmt & LMT_10Gb)
- ae->un.SupportSpeed = HBA_PORTSPEED_10GBIT;
+ ae->un.SupportSpeed |= HBA_PORTSPEED_10GBIT;
if (phba->lmt & LMT_8Gb)
ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT;
if (phba->lmt & LMT_4Gb)
@@ -1612,24 +1609,26 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
ae->ad.bits.AttrType = be16_to_cpu(PORT_SPEED);
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
switch(phba->fc_linkspeed) {
- case LA_1GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
+ case LPFC_LINK_SPEED_1GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
break;
- case LA_2GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
+ case LPFC_LINK_SPEED_2GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
break;
- case LA_4GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
+ case LPFC_LINK_SPEED_4GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
break;
- case LA_8GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
+ case LPFC_LINK_SPEED_8GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
break;
- case LA_10GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
+ case LPFC_LINK_SPEED_10GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
break;
- default:
- ae->un.PortSpeed =
- HBA_PORTSPEED_UNKNOWN;
+ case LPFC_LINK_SPEED_16GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_16GBIT;
+ break;
+ default:
+ ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN;
break;
}
pab->ab.EntryCnt++;
@@ -1734,6 +1733,55 @@ fdmi_cmd_exit:
return 1;
}
+/**
+ * lpfc_delayed_disc_tmo - Timeout handler for delayed discovery timer.
+ * @ptr - Context object of the timer.
+ *
+ * This function set the WORKER_DELAYED_DISC_TMO flag and wake up
+ * the worker thread.
+ **/
+void
+lpfc_delayed_disc_tmo(unsigned long ptr)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t tmo_posted;
+ unsigned long iflag;
+
+ spin_lock_irqsave(&vport->work_port_lock, iflag);
+ tmo_posted = vport->work_port_events & WORKER_DELAYED_DISC_TMO;
+ if (!tmo_posted)
+ vport->work_port_events |= WORKER_DELAYED_DISC_TMO;
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+
+ if (!tmo_posted)
+ lpfc_worker_wake_up(phba);
+ return;
+}
+
+/**
+ * lpfc_delayed_disc_timeout_handler - Function called by worker thread to
+ * handle delayed discovery.
+ * @vport: pointer to a host virtual N_Port data structure.
+ *
+ * This function start nport discovery of the vport.
+ **/
+void
+lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ spin_lock_irq(shost->host_lock);
+ if (!(vport->fc_flag & FC_DISC_DELAYED)) {
+ spin_unlock_irq(shost->host_lock);
+ return;
+ }
+ vport->fc_flag &= ~FC_DISC_DELAYED;
+ spin_unlock_irq(shost->host_lock);
+
+ lpfc_do_scr_ns_plogi(vport->phba, vport);
+}
+
void
lpfc_fdmi_tmo(unsigned long ptr)
{
@@ -1763,7 +1811,8 @@ lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
if (init_utsname()->nodename[0] != '\0')
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
else
- mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
+ mod_timer(&vport->fc_fdmitmo, jiffies +
+ msecs_to_jiffies(1000 * 60));
}
return;
}
@@ -1779,7 +1828,7 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
uint8_t *fwname;
if (phba->sli_rev == LPFC_SLI_REV4)
- sprintf(fwrevision, "%s", vp->rev.opFwName);
+ snprintf(fwrevision, FW_REV_STR_SIZE, "%s", vp->rev.opFwName);
else if (vp->rev.rBit) {
if (psli->sli_flag & LPFC_SLI_ACTIVE)
rev = vp->rev.sli2FwRev;
@@ -1801,6 +1850,9 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
case 2:
c = 'B';
break;
+ case 3:
+ c = 'X';
+ break;
default:
c = 0;
break;