From: Jitendra <jitendra.bhiv...@avagotech.com>

Log messages for misconfigured transceivers reported by FW.

Register async events that driver handles using MCC_CREATE_EXT ioctl.
Errors messages for faulted/uncertified/unqualified optics are logged.
Added FW config validation.

Signed-off-by: Jitendra <jitendra.bhiv...@avagotech.com>
---
 drivers/scsi/be2iscsi/be_cmds.c |  169 ++++++++++++++++++-----------
 drivers/scsi/be2iscsi/be_cmds.h |   47 +++++++-
 drivers/scsi/be2iscsi/be_main.c |   22 +---
 drivers/scsi/be2iscsi/be_main.h |   12 ++-
 drivers/scsi/be2iscsi/be_mgmt.c |  230 +++++++++++++++++++++++++++------------
 drivers/scsi/be2iscsi/be_mgmt.h |    2 +
 6 files changed, 327 insertions(+), 155 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index e4cc98f..58a9fda 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -267,26 +267,6 @@ void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int 
tag)
        spin_unlock(&ctrl->mcc_lock);
 }
 
-bool is_link_state_evt(u32 trailer)
-{
-       return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
-                 ASYNC_TRAILER_EVENT_CODE_MASK) ==
-                 ASYNC_EVENT_CODE_LINK_STATE);
-}
-
-static bool is_iscsi_evt(u32 trailer)
-{
-       return ((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
-                 ASYNC_TRAILER_EVENT_CODE_MASK) ==
-                 ASYNC_EVENT_CODE_ISCSI;
-}
-
-static int iscsi_evt_type(u32 trailer)
-{
-       return (trailer >> ASYNC_TRAILER_EVENT_TYPE_SHIFT) &
-                ASYNC_TRAILER_EVENT_TYPE_MASK;
-}
-
 static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
 {
        if (compl->flags != 0) {
@@ -343,7 +323,7 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
                        if (resp_hdr->response_length)
                                return 0;
                }
-               return -EBUSY;
+               return -EINVAL;
        }
        return 0;
 }
@@ -422,7 +402,7 @@ void beiscsi_fail_session(struct iscsi_cls_session 
*cls_session)
        iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
 }
 
-void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
+static void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
                struct be_async_event_link_state *evt)
 {
        if ((evt->port_link_status == ASYNC_EVENT_LINK_DOWN) ||
@@ -450,6 +430,103 @@ void beiscsi_async_link_state_process(struct beiscsi_hba 
*phba,
        }
 }
 
+static char *beiscsi_port_misconf_event_msg[] = {
+       "Physical Link is functional.",
+       "Optics faulted/incorrectly installed/not installed - Reseat optics, if 
issue not resolved, replace.",
+       "Optics of two types installed - Remove one optic or install matching 
pair of optics.",
+       "Incompatible optics - Replace with compatible optics for card to 
function.",
+       "Unqualified optics - Replace with Avago optics for Warranty and 
Technical Support.",
+       "Uncertified optics - Replace with Avago Certified optics to enable 
link operation."
+};
+#define BEISCSI_PORT_MISCONF_EVENT_MAX \
+       (sizeof(beiscsi_port_misconf_event_msg) / \
+        sizeof(beiscsi_port_misconf_event_msg[0]))
+
+static void beiscsi_process_async_sli(struct beiscsi_hba *phba,
+                                     struct be_mcc_compl *compl)
+{
+       struct be_async_event_sli *async_sli;
+       u8 evt_type, state, old_state, le;
+       char *sev = KERN_WARNING;
+       char *msg = NULL;
+
+       evt_type = compl->flags >> ASYNC_TRAILER_EVENT_TYPE_SHIFT;
+       evt_type &= ASYNC_TRAILER_EVENT_TYPE_MASK;
+
+       /* processing only MISCONFIGURED physical port event */
+       if (evt_type != ASYNC_SLI_EVENT_TYPE_MISCONFIGURED)
+               return;
+
+       async_sli = (struct be_async_event_sli *)compl;
+       state = async_sli->event_data1 >>
+                (phba->fw_config.phys_port * 8) & 0xff;
+       le = async_sli->event_data2 >>
+                (phba->fw_config.phys_port * 8) & 0xff;
+
+       old_state = phba->optic_state;
+       phba->optic_state = state;
+
+       if (state >= BEISCSI_PORT_MISCONF_EVENT_MAX) {
+               /* fw is reporting a state we don't know, log and return */
+               __beiscsi_log(phba, KERN_ERR,
+                           "BC_%d : Port %c: Unrecognized optic state 0x%x\n",
+                           phba->port_name, async_sli->event_data1);
+               return;
+       }
+
+       if (ASYNC_SLI_LINK_EFFECT_VALID(le)) {
+               /* log link effect for unqualified-4, uncertified-5 optics */
+               if (state > 3)
+                       msg = (ASYNC_SLI_LINK_EFFECT_STATE(le)) ?
+                               " Link is non-operational." :
+                               " Link is operational.";
+               /* 1 - info */
+               if (ASYNC_SLI_LINK_EFFECT_SEV(le) == 1)
+                       sev = KERN_INFO;
+               /* 2 - error */
+               if (ASYNC_SLI_LINK_EFFECT_SEV(le) == 2)
+                       sev = KERN_ERR;
+       }
+
+       if (old_state != phba->optic_state)
+               __beiscsi_log(phba, sev, "BC_%d : Port %c: %s%s\n",
+                             phba->port_name,
+                             beiscsi_port_misconf_event_msg[state],
+                             !msg ? "" : msg);
+}
+
+void beiscsi_process_async_event(struct beiscsi_hba *phba,
+                               struct be_mcc_compl *compl)
+{
+       char *sev = KERN_INFO;
+       u8 evt_code;
+
+       /* interpret flags as an async trailer */
+       evt_code = compl->flags >> ASYNC_TRAILER_EVENT_CODE_SHIFT;
+       evt_code &= ASYNC_TRAILER_EVENT_CODE_MASK;
+       switch (evt_code) {
+       case ASYNC_EVENT_CODE_LINK_STATE:
+               beiscsi_async_link_state_process(phba,
+                               (struct be_async_event_link_state *)compl);
+               break;
+       case ASYNC_EVENT_CODE_ISCSI:
+               phba->state |= BE_ADAPTER_CHECK_BOOT;
+               phba->get_boot = BE_GET_BOOT_RETRIES;
+               sev = KERN_ERR;
+               break;
+       case ASYNC_EVENT_CODE_SLI:
+               beiscsi_process_async_sli(phba, compl);
+               break;
+       default:
+               /* event not registered */
+               sev = KERN_ERR;
+       }
+
+       beiscsi_log(phba, sev, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+                   "BC_%d : ASYNC Event: status 0x%08x flags 0x%08x\n",
+                   compl->status, compl->flags);
+}
+
 int beiscsi_process_mcc(struct beiscsi_hba *phba)
 {
        struct be_mcc_compl *compl;
@@ -459,45 +536,10 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba)
        spin_lock_bh(&phba->ctrl.mcc_cq_lock);
        while ((compl = be_mcc_compl_get(phba))) {
                if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
-                       /* Interpret flags as an async trailer */
-                       if (is_link_state_evt(compl->flags))
-                               /* Interpret compl as a async link evt */
-                               beiscsi_async_link_state_process(phba,
-                                  (struct be_async_event_link_state *) compl);
-                       else if (is_iscsi_evt(compl->flags)) {
-                               switch (iscsi_evt_type(compl->flags)) {
-                               case ASYNC_EVENT_NEW_ISCSI_TGT_DISC:
-                               case ASYNC_EVENT_NEW_ISCSI_CONN:
-                               case ASYNC_EVENT_NEW_TCP_CONN:
-                                       phba->state |= BE_ADAPTER_CHECK_BOOT;
-                                       phba->get_boot = BE_GET_BOOT_RETRIES;
-                                       beiscsi_log(phba, KERN_ERR,
-                                                   BEISCSI_LOG_CONFIG |
-                                                   BEISCSI_LOG_MBOX,
-                                                   "BC_%d : Async iscsi Event,"
-                                                   " flags handled = 0x%08x\n",
-                                                   compl->flags);
-                                       break;
-                               default:
-                                       phba->state |= BE_ADAPTER_CHECK_BOOT;
-                                       phba->get_boot = BE_GET_BOOT_RETRIES;
-                                       beiscsi_log(phba, KERN_ERR,
-                                                   BEISCSI_LOG_CONFIG |
-                                                   BEISCSI_LOG_MBOX,
-                                                   "BC_%d : Unsupported Async"
-                                                   " Event, flags = 0x%08x\n",
-                                                   compl->flags);
-                               }
-                       } else
-                               beiscsi_log(phba, KERN_ERR,
-                                           BEISCSI_LOG_CONFIG |
-                                           BEISCSI_LOG_MBOX,
-                                           "BC_%d : Unsupported Async Event, 
flags"
-                                           " = 0x%08x\n", compl->flags);
-
+                       beiscsi_process_async_event(phba, compl);
                } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
-                               status = be_mcc_compl_process(ctrl, compl);
-                               atomic_dec(&phba->ctrl.mcc_obj.q.used);
+                       status = be_mcc_compl_process(ctrl, compl);
+                       atomic_dec(&phba->ctrl.mcc_obj.q.used);
                }
                be_mcc_compl_use(compl);
                num++;
@@ -1013,7 +1055,7 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
                        struct be_queue_info *cq)
 {
        struct be_mcc_wrb *wrb;
-       struct be_cmd_req_mcc_create *req;
+       struct be_cmd_req_mcc_create_ext *req;
        struct be_dma_mem *q_mem = &mccq->dma_mem;
        struct be_ctrl_info *ctrl;
        void *ctxt;
@@ -1029,9 +1071,12 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
        be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
 
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-                       OPCODE_COMMON_MCC_CREATE, sizeof(*req));
+                       OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req));
 
        req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+       req->async_evt_bitmap = 1 << ASYNC_EVENT_CODE_LINK_STATE;
+       req->async_evt_bitmap |= 1 << ASYNC_EVENT_CODE_ISCSI;
+       req->async_evt_bitmap |= 1 << ASYNC_EVENT_CODE_SLI;
 
        AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt,
                      PCI_FUNC(phba->pcidev->devfn));
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 5d165ee..6411f7b 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -119,13 +119,22 @@ struct be_mcc_compl {
 #define ASYNC_TRAILER_EVENT_CODE_MASK  0xFF
 #define ASYNC_EVENT_CODE_LINK_STATE    0x1
 #define ASYNC_EVENT_CODE_ISCSI         0x4
+#define ASYNC_EVENT_CODE_SLI           0x11
 
 #define ASYNC_TRAILER_EVENT_TYPE_SHIFT 16      /* bits 16 - 23 */
-#define ASYNC_TRAILER_EVENT_TYPE_MASK  0xF
+#define ASYNC_TRAILER_EVENT_TYPE_MASK  0xFF
+
+/* iSCSI events */
 #define ASYNC_EVENT_NEW_ISCSI_TGT_DISC 0x4
 #define ASYNC_EVENT_NEW_ISCSI_CONN     0x5
 #define ASYNC_EVENT_NEW_TCP_CONN       0x7
 
+/* SLI events */
+#define ASYNC_SLI_EVENT_TYPE_MISCONFIGURED     0x9
+#define ASYNC_SLI_LINK_EFFECT_VALID(le)                (le & 0x80)
+#define ASYNC_SLI_LINK_EFFECT_SEV(le)          ((le >> 1)  & 0x03)
+#define ASYNC_SLI_LINK_EFFECT_STATE(le)                (le & 0x01)
+
 struct be_async_event_trailer {
        u32 code;
 };
@@ -153,6 +162,16 @@ struct be_async_event_link_state {
        struct be_async_event_trailer trailer;
 } __packed;
 
+/**
+ * When async-trailer is SLI event, mcc_compl is interpreted as
+ */
+struct be_async_event_sli {
+       u32 event_data1;
+       u32 event_data2;
+       u32 reserved;
+       u32 trailer;
+} __packed;
+
 struct be_mcc_mailbox {
        struct be_mcc_wrb wrb;
        struct be_mcc_compl compl;
@@ -172,6 +191,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_CQ_CREATE                                12
 #define OPCODE_COMMON_EQ_CREATE                                13
 #define OPCODE_COMMON_MCC_CREATE                       21
+#define OPCODE_COMMON_MCC_CREATE_EXT                   90
 #define OPCODE_COMMON_ADD_TEMPLATE_HEADER_BUFFERS      24
 #define OPCODE_COMMON_REMOVE_TEMPLATE_HEADER_BUFFERS   25
 #define OPCODE_COMMON_GET_CNTL_ATTRIBUTES              32
@@ -183,6 +203,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_EQ_DESTROY                       55
 #define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG            58
 #define OPCODE_COMMON_FUNCTION_RESET                   61
+#define OPCODE_COMMON_GET_PORT_NAME                    77
 
 /**
  * LIST of opcodes that are common between Initiator and Target
@@ -587,10 +608,11 @@ struct amap_mcc_context {
        u8 rsvd2[32];
 } __packed;
 
-struct be_cmd_req_mcc_create {
+struct be_cmd_req_mcc_create_ext {
        struct be_cmd_req_hdr hdr;
        u16 num_pages;
        u16 rsvd0;
+       u32 async_evt_bitmap;
        u8 context[sizeof(struct amap_mcc_context) / 8];
        struct phys_addr pages[8];
 } __packed;
@@ -748,8 +770,8 @@ struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba);
 int be_mcc_notify_wait(struct beiscsi_hba *phba);
 void be_mcc_notify(struct beiscsi_hba *phba);
 unsigned int alloc_mcc_tag(struct beiscsi_hba *phba);
-void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
-               struct be_async_event_link_state *evt);
+void beiscsi_process_async_event(struct beiscsi_hba *phba,
+                               struct be_mcc_compl *compl);
 int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
                                    struct be_mcc_compl *compl);
 
@@ -777,8 +799,6 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct 
be_dma_mem *q_mem,
                       struct hwi_wrb_context *pwrb_context,
                       uint8_t ulp_num);
 
-bool is_link_state_evt(u32 trailer);
-
 /* Configuration Functions */
 int be_cmd_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag);
 
@@ -1137,6 +1157,21 @@ struct be_cmd_get_all_if_id_req {
        u32 if_hndl_list[1];
 } __packed;
 
+struct be_cmd_get_port_name {
+       union {
+               struct be_cmd_req_hdr req_hdr;
+               struct be_cmd_resp_hdr resp_hdr;
+       } h;
+       union {
+               struct {
+                       u32 reserved;
+               } req;
+               struct {
+                       u32 port_names;
+               } resp;
+       } p;
+} __packed;
+
 #define ISCSI_OPCODE_SCSI_DATA_OUT             5
 #define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY 5
 #define OPCODE_COMMON_MODIFY_EQ_DELAY          41
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 2f3e118..d036706 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -2048,21 +2048,7 @@ static void  beiscsi_process_mcc_isr(struct beiscsi_hba 
*phba)
                        num_processed = 0;
                }
                if (mcc_compl->flags & CQE_FLAGS_ASYNC_MASK) {
-                       /* Interpret flags as an async trailer */
-                       if (is_link_state_evt(mcc_compl->flags))
-                               /* Interpret compl as a async link evt */
-                               beiscsi_async_link_state_process(phba,
-                               (struct be_async_event_link_state *) mcc_compl);
-                       else {
-                               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_MBOX,
-                                           "BM_%d :  Unsupported Async Event, 
flags"
-                                           " = 0x%08x\n",
-                                           mcc_compl->flags);
-                               if (phba->state & BE_ADAPTER_LINK_UP) {
-                                       phba->state |= BE_ADAPTER_CHECK_BOOT;
-                                       phba->get_boot = BE_GET_BOOT_RETRIES;
-                               }
-                       }
+                       beiscsi_process_async_event(phba, mcc_compl);
                } else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) {
                        be_mcc_compl_process_isr(&phba->ctrl, mcc_compl);
                        atomic_dec(&phba->ctrl.mcc_obj.q.used);
@@ -3868,6 +3854,8 @@ static int hwi_init_port(struct beiscsi_hba *phba)
        phwi_context->min_eqd = 0;
        phwi_context->cur_eqd = 0;
        be_cmd_fw_initialize(&phba->ctrl);
+       /* set optic state to unknown */
+       phba->optic_state = 0xff;
 
        status = beiscsi_create_eqs(phba, phwi_context);
        if (status != 0) {
@@ -5545,6 +5533,7 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
        }
 
        beiscsi_get_params(phba);
+
        phba->shost->max_id = phba->params.cxns_per_ctrl;
        phba->shost->can_queue = phba->params.ios_per_ctrl;
        ret = hwi_init_controller(phba);
@@ -5681,6 +5670,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
                            "BM_%d : Error getting fw config\n");
                goto free_port;
        }
+       mgmt_get_port_name(&phba->ctrl, phba);
+       beiscsi_get_params(phba);
 
        if (enable_msix)
                find_num_cpus(phba);
@@ -5698,7 +5689,6 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
        }
 
        phba->shost->max_id = phba->params.cxns_per_ctrl;
-       beiscsi_get_params(phba);
        phba->shost->can_queue = phba->params.ios_per_ctrl;
        ret = beiscsi_init_port(phba);
        if (ret < 0) {
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index bd9d1e1..f89861b 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -397,7 +397,9 @@ struct beiscsi_hba {
                 * group together since they are used most frequently
                 * for cid to cri conversion
                 */
+#define BEISCSI_PHYS_PORT_MAX  4
                unsigned int phys_port;
+               /* valid values of phys_port id are 0, 1, 2, 3 */
                unsigned int eqid_count;
                unsigned int cqid_count;
                unsigned int iscsi_cid_start[BEISCSI_ULP_COUNT];
@@ -415,6 +417,7 @@ struct beiscsi_hba {
        } fw_config;
 
        unsigned int state;
+       u8 optic_state;
        int get_boot;
        bool fw_timeout;
        bool ue_detected;
@@ -422,6 +425,7 @@ struct beiscsi_hba {
 
        bool mac_addr_set;
        u8 mac_address[ETH_ALEN];
+       u8 port_name;
        char fw_ver_str[BEISCSI_VER_STRLEN];
        char wq_name[20];
        struct workqueue_struct *wq;    /* The actuak work queue */
@@ -1073,12 +1077,14 @@ struct hwi_context_memory {
 #define BEISCSI_LOG_CONFIG     0x0020  /* CONFIG Code Path */
 #define BEISCSI_LOG_ISCSI      0x0040  /* SCSI/iSCSI Protocol related Logs */
 
+#define __beiscsi_log(phba, level, fmt, arg...) \
+       shost_printk(level, phba->shost, fmt, __LINE__, ##arg)
+
 #define beiscsi_log(phba, level, mask, fmt, arg...) \
 do { \
        uint32_t log_value = phba->attr_log_enable; \
                if (((mask) & log_value) || (level[1] <= '3')) \
-                       shost_printk(level, phba->shost, \
-                                    fmt, __LINE__, ##arg); \
-} while (0)
+                       __beiscsi_log(phba, level, fmt, ##arg); \
+} while (0);
 
 #endif
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index a8a1670..15f7ad7 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -316,6 +316,48 @@ unsigned int mgmt_get_session_info(struct beiscsi_hba 
*phba,
 }
 
 /**
+ * mgmt_get_port_name()- Get port name for the function
+ * @ctrl: ptr to Ctrl Info
+ * @phba: ptr to the dev priv structure
+ *
+ * Get the alphanumeric character for port
+ *
+ **/
+int mgmt_get_port_name(struct be_ctrl_info *ctrl,
+                      struct beiscsi_hba *phba)
+{
+       int ret = 0;
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_get_port_name *ioctl;
+
+       mutex_lock(&ctrl->mbox_lock);
+       wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       memset(wrb, 0, sizeof(*wrb));
+       ioctl = embedded_payload(wrb);
+
+       be_wrb_hdr_prepare(wrb, sizeof(*ioctl), true, 0);
+       be_cmd_hdr_prepare(&ioctl->h.req_hdr, CMD_SUBSYSTEM_COMMON,
+                          OPCODE_COMMON_GET_PORT_NAME,
+                          EMBED_MBX_MAX_PAYLOAD_SIZE);
+       ret = be_mbox_notify(ctrl);
+       phba->port_name = 0;
+       if (!ret) {
+               phba->port_name = ioctl->p.resp.port_names >>
+                                 (phba->fw_config.phys_port * 8) & 0xff;
+       } else {
+               beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+                           "BG_%d : GET_PORT_NAME ret 0x%x status 0x%x\n",
+                           ret, ioctl->h.resp_hdr.status);
+       }
+
+       if (phba->port_name == 0)
+               phba->port_name = '?';
+
+       mutex_unlock(&ctrl->mbox_lock);
+       return ret;
+}
+
+/**
  * mgmt_get_fw_config()- Get the FW config for the function
  * @ctrl: ptr to Ctrl Info
  * @phba: ptr to the dev priv structure
@@ -331,90 +373,142 @@ int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
                                struct beiscsi_hba *phba)
 {
        struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
-       struct be_fw_cfg *req = embedded_payload(wrb);
-       int status = 0;
+       struct be_fw_cfg *pfw_cfg = embedded_payload(wrb);
+       uint32_t cid_count, icd_count;
+       int status = -EINVAL;
+       uint8_t ulp_num = 0;
 
        mutex_lock(&ctrl->mbox_lock);
        memset(wrb, 0, sizeof(*wrb));
+       be_wrb_hdr_prepare(wrb, sizeof(*pfw_cfg), true, 0);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+       be_cmd_hdr_prepare(&pfw_cfg->hdr, CMD_SUBSYSTEM_COMMON,
                           OPCODE_COMMON_QUERY_FIRMWARE_CONFIG,
                           EMBED_MBX_MAX_PAYLOAD_SIZE);
-       status = be_mbox_notify(ctrl);
-       if (!status) {
-               uint8_t ulp_num = 0;
-               struct be_fw_cfg *pfw_cfg;
-               pfw_cfg = req;
 
-               if (!is_chip_be2_be3r(phba)) {
-                       phba->fw_config.eqid_count = pfw_cfg->eqid_count;
-                       phba->fw_config.cqid_count = pfw_cfg->cqid_count;
+       if (be_mbox_notify(ctrl)) {
+               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+                           "BG_%d : Failed in mgmt_get_fw_config\n");
+               goto fail_init;
+       }
 
-                       beiscsi_log(phba, KERN_INFO,
-                                   BEISCSI_LOG_INIT,
-                                   "BG_%d : EQ_Count : %d CQ_Count : %d\n",
-                                   phba->fw_config.eqid_count,
+       /* FW response formats depend on port id */
+       phba->fw_config.phys_port = pfw_cfg->phys_port;
+       if (phba->fw_config.phys_port >= BEISCSI_PHYS_PORT_MAX) {
+               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+                           "BG_%d : invalid physical port id %d\n",
+                           phba->fw_config.phys_port);
+               goto fail_init;
+       }
+
+       /* populate and check FW config against min and max values */
+       if (!is_chip_be2_be3r(phba)) {
+               phba->fw_config.eqid_count = pfw_cfg->eqid_count;
+               phba->fw_config.cqid_count = pfw_cfg->cqid_count;
+               if (phba->fw_config.eqid_count == 0 ||
+                   phba->fw_config.eqid_count > 2048) {
+                       beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+                                   "BG_%d : invalid EQ count %d\n",
+                                   phba->fw_config.eqid_count);
+                       goto fail_init;
+               }
+               if (phba->fw_config.cqid_count == 0 ||
+                   phba->fw_config.cqid_count > 4096) {
+                       beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+                                   "BG_%d : invalid CQ count %d\n",
                                    phba->fw_config.cqid_count);
+                       goto fail_init;
                }
+               beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+                           "BG_%d : EQ_Count : %d CQ_Count : %d\n",
+                           phba->fw_config.eqid_count,
+                           phba->fw_config.cqid_count);
+       }
 
-               for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
-                       if (pfw_cfg->ulp[ulp_num].ulp_mode &
-                           BEISCSI_ULP_ISCSI_INI_MODE)
-                               set_bit(ulp_num,
-                               &phba->fw_config.ulp_supported);
-
-               phba->fw_config.phys_port = pfw_cfg->phys_port;
-               for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
-                       if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
-
-                               phba->fw_config.iscsi_cid_start[ulp_num] =
-                                       pfw_cfg->ulp[ulp_num].sq_base;
-                               phba->fw_config.iscsi_cid_count[ulp_num] =
-                                       pfw_cfg->ulp[ulp_num].sq_count;
-
-                               phba->fw_config.iscsi_icd_start[ulp_num] =
-                                       pfw_cfg->ulp[ulp_num].icd_base;
-                               phba->fw_config.iscsi_icd_count[ulp_num] =
-                                       pfw_cfg->ulp[ulp_num].icd_count;
-
-                               phba->fw_config.iscsi_chain_start[ulp_num] =
-                                       pfw_cfg->chain_icd[ulp_num].chain_base;
-                               phba->fw_config.iscsi_chain_count[ulp_num] =
-                                       pfw_cfg->chain_icd[ulp_num].chain_count;
-
-                               beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
-                                           "BG_%d : Function loaded on ULP : 
%d\n"
-                                           "\tiscsi_cid_count : %d\n"
-                                           "\tiscsi_cid_start : %d\n"
-                                           "\t iscsi_icd_count : %d\n"
-                                           "\t iscsi_icd_start : %d\n",
-                                           ulp_num,
-                                           phba->fw_config.
-                                           iscsi_cid_count[ulp_num],
-                                           phba->fw_config.
-                                           iscsi_cid_start[ulp_num],
-                                           phba->fw_config.
-                                           iscsi_icd_count[ulp_num],
-                                           phba->fw_config.
-                                           iscsi_icd_start[ulp_num]);
-                       }
+       /**
+        * Check on which all ULP iSCSI Protocol is loaded.
+        * Set the Bit for those ULP. This set flag is used
+        * at all places in the code to check on which ULP
+        * iSCSi Protocol is loaded
+        **/
+       for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
+               if (pfw_cfg->ulp[ulp_num].ulp_mode &
+                   BEISCSI_ULP_ISCSI_INI_MODE) {
+                       set_bit(ulp_num, &phba->fw_config.ulp_supported);
+
+                       /* Get the CID, ICD and Chain count for each ULP */
+                       phba->fw_config.iscsi_cid_start[ulp_num] =
+                               pfw_cfg->ulp[ulp_num].sq_base;
+                       phba->fw_config.iscsi_cid_count[ulp_num] =
+                               pfw_cfg->ulp[ulp_num].sq_count;
+
+                       phba->fw_config.iscsi_icd_start[ulp_num] =
+                               pfw_cfg->ulp[ulp_num].icd_base;
+                       phba->fw_config.iscsi_icd_count[ulp_num] =
+                               pfw_cfg->ulp[ulp_num].icd_count;
+
+                       phba->fw_config.iscsi_chain_start[ulp_num] =
+                               pfw_cfg->chain_icd[ulp_num].chain_base;
+                       phba->fw_config.iscsi_chain_count[ulp_num] =
+                               pfw_cfg->chain_icd[ulp_num].chain_count;
+
+                       beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+                                   "BG_%d : Function loaded on ULP : %d\n"
+                                   "\tiscsi_cid_count : %d\n"
+                                   "\tiscsi_cid_start : %d\n"
+                                   "\t iscsi_icd_count : %d\n"
+                                   "\t iscsi_icd_start : %d\n",
+                                   ulp_num,
+                                   phba->fw_config.
+                                   iscsi_cid_count[ulp_num],
+                                   phba->fw_config.
+                                   iscsi_cid_start[ulp_num],
+                                   phba->fw_config.
+                                   iscsi_icd_count[ulp_num],
+                                   phba->fw_config.
+                                   iscsi_icd_start[ulp_num]);
                }
+       }
 
-               phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode &
-                                                 BEISCSI_FUNC_DUA_MODE);
+       if (phba->fw_config.ulp_supported == 0) {
+               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+                           "BG_%d : iSCSI initiator mode not set: ULP0 %x ULP1 
%x\n",
+                           pfw_cfg->ulp[BEISCSI_ULP0].ulp_mode,
+                           pfw_cfg->ulp[BEISCSI_ULP1].ulp_mode);
+               goto fail_init;
+       }
 
-               beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
-                           "BG_%d : DUA Mode : 0x%x\n",
-                           phba->fw_config.dual_ulp_aware);
+       /**
+        * ICD is shared among ULPs. Use icd_count of any one loaded ULP
+        **/
+       for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
+               if (test_bit(ulp_num, &phba->fw_config.ulp_supported))
+                       break;
+       icd_count = phba->fw_config.iscsi_icd_count[ulp_num];
+       if (icd_count == 0 || icd_count > 65536) {
+               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+                           "BG_%d: invalid ICD count %d\n", icd_count);
+               goto fail_init;
+       }
 
-       } else {
+       cid_count = BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP0) +
+                   BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP1);
+       if (cid_count == 0 || cid_count > 4096) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                           "BG_%d : Failed in mgmt_get_fw_config\n");
-               status = -EINVAL;
+                           "BG_%d: invalid CID count %d\n", cid_count);
+               goto fail_init;
        }
 
+       phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode &
+                                         BEISCSI_FUNC_DUA_MODE);
+
+       beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+                   "BG_%d : DUA Mode : 0x%x\n",
+                   phba->fw_config.dual_ulp_aware);
+
+       /* all set, continue using this FW config */
+       status = 0;
+fail_init:
        mutex_unlock(&ctrl->mbox_lock);
        return status;
 }
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index c1dbb69..f3a48a0 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -268,6 +268,8 @@ struct beiscsi_endpoint {
 
 int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
                                 struct beiscsi_hba *phba);
+int mgmt_get_port_name(struct be_ctrl_info *ctrl,
+                      struct beiscsi_hba *phba);
 
 unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
                                         struct beiscsi_endpoint *beiscsi_ep,
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to