be2net: support flashing new regions on Skyhawk-R
authorVasundhara Volam <vasundhara.volam@emulex.com>
Fri, 30 May 2014 13:36:25 +0000 (19:06 +0530)
committerDavid S. Miller <davem@davemloft.net>
Sat, 31 May 2014 00:27:33 +0000 (17:27 -0700)
Certain new flash regions have been added to Skyhawk-R FW image. The newer
FW images specify op_types for each region. A region is flashed only
when it's CRC doesn't match that of the region on the HW flash. While
upgrading to a new FW image the driver is expected to tolerate certain
errors.

This patch re-factors code under be_flash() to support the above scheme.
Signed-off-by: Vasundhara Volam <vasundhara.volam@emulex.com>
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_hw.h
drivers/net/ethernet/emulex/benet/be_main.c

index 216463b..f73185b 100644 (file)
@@ -133,6 +133,9 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
        compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
                                CQE_STATUS_COMPL_MASK;
 
+       extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
+                               CQE_STATUS_EXTD_MASK;
+
        resp_hdr = be_decode_resp_hdr(compl->tag0, compl->tag1);
 
        if (resp_hdr) {
@@ -172,16 +175,25 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
                        adapter->be_get_temp_freq = 0;
 
                if (compl_status == MCC_STATUS_NOT_SUPPORTED ||
-                       compl_status == MCC_STATUS_ILLEGAL_REQUEST)
-                       goto done;
+                   compl_status == MCC_STATUS_ILLEGAL_REQUEST)
+                       return compl_status;
+
+               /* Ignore CRC mismatch error during FW download with old FW */
+               if (opcode == OPCODE_COMMON_WRITE_FLASHROM &&
+                   compl_status == MCC_STATUS_FAILED &&
+                   extd_status == MCC_ADDL_STS_FLASH_IMAGE_CRC_MISMATCH)
+                       return compl_status;
+
+               /* Ignore illegal field error during FW download with old FW */
+               if (opcode == OPCODE_COMMON_WRITE_FLASHROM &&
+                   compl_status == MCC_STATUS_ILLEGAL_FIELD)
+                       return compl_status;
 
                if (compl_status == MCC_STATUS_UNAUTHORIZED_REQUEST) {
                        dev_warn(&adapter->pdev->dev,
                                 "VF is not privileged to issue opcode %d-%d\n",
                                 opcode, subsystem);
                } else {
-                       extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
-                                       CQE_STATUS_EXTD_MASK;
                        dev_err(&adapter->pdev->dev,
                                "opcode %d-%d failed:status %d-%d\n",
                                opcode, subsystem, compl_status, extd_status);
@@ -190,7 +202,6 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
                                return extd_status;
                }
        }
-done:
        return compl_status;
 }
 
@@ -2300,7 +2311,7 @@ err_unlock:
 }
 
 int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
-                        int offset)
+                         u16 optype, int offset)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_read_flash_crc *req;
@@ -2319,7 +2330,7 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
                               OPCODE_COMMON_READ_FLASHROM, sizeof(*req),
                               wrb, NULL);
 
-       req->params.op_type = cpu_to_le32(OPTYPE_REDBOOT);
+       req->params.op_type = cpu_to_le32(optype);
        req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT);
        req->params.offset = cpu_to_le32(offset);
        req->params.data_buf_size = cpu_to_le32(0x4);
index 9df9d3b..070f775 100644 (file)
@@ -61,6 +61,7 @@ enum {
 };
 
 #define MCC_ADDL_STS_INSUFFICIENT_RESOURCES    0x16
+#define MCC_ADDL_STS_FLASH_IMAGE_CRC_MISMATCH  0x4d
 
 #define CQE_STATUS_COMPL_MASK          0xFFFF
 #define CQE_STATUS_COMPL_SHIFT         0       /* bits 0 - 15 */
@@ -1186,7 +1187,8 @@ struct be_cmd_read_flash_crc {
        struct flashrom_params params;
        u8 crc[4];
        u8 rsvd[4];
-};
+} __packed;
+
 /**************** Lancer Firmware Flash ************/
 struct amap_lancer_write_obj_context {
        u8 write_length[24];
@@ -2088,7 +2090,7 @@ int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
                           u32 data_size, u32 data_offset, const char *obj_name,
                           u32 *data_read, u32 *eof, u8 *addn_status);
 int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
-                        int offset);
+                         u16 optype, int offset);
 int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
                            struct be_dma_mem *nonemb_cmd);
 int be_cmd_fw_init(struct be_adapter *adapter);
index 3bd1985..8840c64 100644 (file)
 #define OPTYPE_FCOE_FW_ACTIVE          10
 #define OPTYPE_FCOE_FW_BACKUP          11
 #define OPTYPE_NCSI_FW                 13
+#define OPTYPE_REDBOOT_DIR             18
+#define OPTYPE_REDBOOT_CONFIG          19
+#define OPTYPE_SH_PHY_FW               21
+#define OPTYPE_FLASHISM_JUMPVECTOR     22
+#define OPTYPE_UFI_DIR                 23
 #define OPTYPE_PHY_FW                  99
 #define TN_8022                                13
 
-#define ILLEGAL_IOCTL_REQ              2
 #define FLASHROM_OPER_PHY_FLASH                9
 #define FLASHROM_OPER_PHY_SAVE         10
 #define FLASHROM_OPER_FLASH            1
 #define IMAGE_FIRMWARE_BACKUP_FCoE     178
 #define IMAGE_FIRMWARE_BACKUP_COMP_FCoE 179
 #define IMAGE_FIRMWARE_PHY             192
+#define IMAGE_REDBOOT_DIR              208
+#define IMAGE_REDBOOT_CONFIG           209
+#define IMAGE_UFI_DIR                  210
 #define IMAGE_BOOT_CODE                        224
 
 /************* Rx Packet Type Encoding **************/
@@ -534,7 +541,8 @@ struct flash_section_entry {
        u32 image_size;
        u32 cksum;
        u32 entry_point;
-       u32 rsvd0;
+       u16 optype;
+       u16 rsvd0;
        u32 rsvd1;
        u8 ver_data[32];
 } __packed;
index d39a1c6..d2b4efa 100644 (file)
@@ -3630,34 +3630,7 @@ static void be_netpoll(struct net_device *netdev)
 }
 #endif
 
-#define FW_FILE_HDR_SIGN       "ServerEngines Corp. "
-static char flash_cookie[2][16] =      {"*** SE FLAS", "H DIRECTORY *** "};
-
-static bool be_flash_redboot(struct be_adapter *adapter,
-                            const u8 *p, u32 img_start, int image_size,
-                            int hdr_size)
-{
-       u32 crc_offset;
-       u8 flashed_crc[4];
-       int status;
-
-       crc_offset = hdr_size + img_start + image_size - 4;
-
-       p += crc_offset;
-
-       status = be_cmd_get_flash_crc(adapter, flashed_crc, (image_size - 4));
-       if (status) {
-               dev_err(&adapter->pdev->dev,
-                       "could not get crc from flash, not flashing redboot\n");
-               return false;
-       }
-
-       /*update redboot only if crc does not match*/
-       if (!memcmp(flashed_crc, p, 4))
-               return false;
-       else
-               return true;
-}
+static char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "};
 
 static bool phy_flashing_required(struct be_adapter *adapter)
 {
@@ -3704,12 +3677,35 @@ static struct flash_section_info *get_fsec_info(struct be_adapter *adapter,
        return NULL;
 }
 
+static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p,
+                             u32 img_offset, u32 img_size, int hdr_size,
+                             u16 img_optype, bool *crc_match)
+{
+       u32 crc_offset;
+       int status;
+       u8 crc[4];
+
+       status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_size - 4);
+       if (status)
+               return status;
+
+       crc_offset = hdr_size + img_offset + img_size - 4;
+
+       /* Skip flashing, if crc of flashed region matches */
+       if (!memcmp(crc, p + crc_offset, 4))
+               *crc_match = true;
+       else
+               *crc_match = false;
+
+       return status;
+}
+
 static int be_flash(struct be_adapter *adapter, const u8 *img,
                    struct be_dma_mem *flash_cmd, int optype, int img_size)
 {
-       u32 total_bytes = 0, flash_op, num_bytes = 0;
-       int status = 0;
        struct be_cmd_write_flashrom *req = flash_cmd->va;
+       u32 total_bytes, flash_op, num_bytes;
+       int status;
 
        total_bytes = img_size;
        while (total_bytes) {
@@ -3733,14 +3729,11 @@ static int be_flash(struct be_adapter *adapter, const u8 *img,
                img += num_bytes;
                status = be_cmd_write_flashrom(adapter, flash_cmd, optype,
                                               flash_op, num_bytes);
-               if (status) {
-                       if (status == ILLEGAL_IOCTL_REQ &&
-                           optype == OPTYPE_PHY_FW)
-                               break;
-                       dev_err(&adapter->pdev->dev,
-                               "cmd to write to flash rom failed.\n");
+               if (status == MCC_STATUS_ILLEGAL_REQUEST &&
+                   optype == OPTYPE_PHY_FW)
+                       break;
+               else if (status)
                        return status;
-               }
        }
        return 0;
 }
@@ -3750,12 +3743,13 @@ static int be_flash_BEx(struct be_adapter *adapter,
                        const struct firmware *fw,
                        struct be_dma_mem *flash_cmd, int num_of_images)
 {
-       int status = 0, i, filehdr_size = 0;
        int img_hdrs_size = (num_of_images * sizeof(struct image_hdr));
-       const u8 *p = fw->data;
-       const struct flash_comp *pflashcomp;
-       int num_comp, redboot;
+       struct device *dev = &adapter->pdev->dev;
        struct flash_section_info *fsec = NULL;
+       int status, i, filehdr_size, num_comp;
+       const struct flash_comp *pflashcomp;
+       bool crc_match;
+       const u8 *p;
 
        struct flash_comp gen3_flash_types[] = {
                { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, OPTYPE_ISCSI_ACTIVE,
@@ -3812,8 +3806,7 @@ static int be_flash_BEx(struct be_adapter *adapter,
        /* Get flash section info*/
        fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw);
        if (!fsec) {
-               dev_err(&adapter->pdev->dev,
-                       "Invalid Cookie. UFI corrupted ?\n");
+               dev_err(dev, "Invalid Cookie. FW image may be corrupted\n");
                return -1;
        }
        for (i = 0; i < num_comp; i++) {
@@ -3829,25 +3822,32 @@ static int be_flash_BEx(struct be_adapter *adapter,
                                continue;
 
                if (pflashcomp[i].optype == OPTYPE_REDBOOT) {
-                       redboot = be_flash_redboot(adapter, fw->data,
-                                                  pflashcomp[i].offset,
-                                                  pflashcomp[i].size,
-                                                  filehdr_size +
-                                                  img_hdrs_size);
-                       if (!redboot)
+                       status = be_check_flash_crc(adapter, fw->data,
+                                                   pflashcomp[i].offset,
+                                                   pflashcomp[i].size,
+                                                   filehdr_size +
+                                                   img_hdrs_size,
+                                                   OPTYPE_REDBOOT, &crc_match);
+                       if (status) {
+                               dev_err(dev,
+                                       "Could not get CRC for 0x%x region\n",
+                                       pflashcomp[i].optype);
+                               continue;
+                       }
+
+                       if (crc_match)
                                continue;
                }
 
-               p = fw->data;
-               p += filehdr_size + pflashcomp[i].offset + img_hdrs_size;
+               p = fw->data + filehdr_size + pflashcomp[i].offset +
+                       img_hdrs_size;
                if (p + pflashcomp[i].size > fw->data + fw->size)
                        return -1;
 
                status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype,
                                  pflashcomp[i].size);
                if (status) {
-                       dev_err(&adapter->pdev->dev,
-                               "Flashing section type %d failed.\n",
+                       dev_err(dev, "Flashing section type 0x%x failed\n",
                                pflashcomp[i].img_type);
                        return status;
                }
@@ -3855,74 +3855,134 @@ static int be_flash_BEx(struct be_adapter *adapter,
        return 0;
 }
 
+static u16 be_get_img_optype(struct flash_section_entry fsec_entry)
+{
+       u32 img_type = le32_to_cpu(fsec_entry.type);
+       u16 img_optype = le16_to_cpu(fsec_entry.optype);
+
+       if (img_optype != 0xFFFF)
+               return img_optype;
+
+       switch (img_type) {
+       case IMAGE_FIRMWARE_iSCSI:
+               img_optype = OPTYPE_ISCSI_ACTIVE;
+               break;
+       case IMAGE_BOOT_CODE:
+               img_optype = OPTYPE_REDBOOT;
+               break;
+       case IMAGE_OPTION_ROM_ISCSI:
+               img_optype = OPTYPE_BIOS;
+               break;
+       case IMAGE_OPTION_ROM_PXE:
+               img_optype = OPTYPE_PXE_BIOS;
+               break;
+       case IMAGE_OPTION_ROM_FCoE:
+               img_optype = OPTYPE_FCOE_BIOS;
+               break;
+       case IMAGE_FIRMWARE_BACKUP_iSCSI:
+               img_optype = OPTYPE_ISCSI_BACKUP;
+               break;
+       case IMAGE_NCSI:
+               img_optype = OPTYPE_NCSI_FW;
+               break;
+       case IMAGE_FLASHISM_JUMPVECTOR:
+               img_optype = OPTYPE_FLASHISM_JUMPVECTOR;
+               break;
+       case IMAGE_FIRMWARE_PHY:
+               img_optype = OPTYPE_SH_PHY_FW;
+               break;
+       case IMAGE_REDBOOT_DIR:
+               img_optype = OPTYPE_REDBOOT_DIR;
+               break;
+       case IMAGE_REDBOOT_CONFIG:
+               img_optype = OPTYPE_REDBOOT_CONFIG;
+               break;
+       case IMAGE_UFI_DIR:
+               img_optype = OPTYPE_UFI_DIR;
+               break;
+       default:
+               break;
+       }
+
+       return img_optype;
+}
+
 static int be_flash_skyhawk(struct be_adapter *adapter,
                            const struct firmware *fw,
                            struct be_dma_mem *flash_cmd, int num_of_images)
 {
-       int status = 0, i, filehdr_size = 0;
-       int img_offset, img_size, img_optype, redboot;
        int img_hdrs_size = num_of_images * sizeof(struct image_hdr);
-       const u8 *p = fw->data;
+       struct device *dev = &adapter->pdev->dev;
        struct flash_section_info *fsec = NULL;
+       u32 img_offset, img_size, img_type;
+       int status, i, filehdr_size;
+       bool crc_match, old_fw_img;
+       u16 img_optype;
+       const u8 *p;
 
        filehdr_size = sizeof(struct flash_file_hdr_g3);
        fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw);
        if (!fsec) {
-               dev_err(&adapter->pdev->dev,
-                       "Invalid Cookie. UFI corrupted ?\n");
+               dev_err(dev, "Invalid Cookie. FW image may be corrupted\n");
                return -1;
        }
 
        for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) {
                img_offset = le32_to_cpu(fsec->fsec_entry[i].offset);
                img_size   = le32_to_cpu(fsec->fsec_entry[i].pad_size);
+               img_type   = le32_to_cpu(fsec->fsec_entry[i].type);
+               img_optype = be_get_img_optype(fsec->fsec_entry[i]);
+               old_fw_img = fsec->fsec_entry[i].optype == 0xFFFF;
 
-               switch (le32_to_cpu(fsec->fsec_entry[i].type)) {
-               case IMAGE_FIRMWARE_iSCSI:
-                       img_optype = OPTYPE_ISCSI_ACTIVE;
-                       break;
-               case IMAGE_BOOT_CODE:
-                       img_optype = OPTYPE_REDBOOT;
-                       break;
-               case IMAGE_OPTION_ROM_ISCSI:
-                       img_optype = OPTYPE_BIOS;
-                       break;
-               case IMAGE_OPTION_ROM_PXE:
-                       img_optype = OPTYPE_PXE_BIOS;
-                       break;
-               case IMAGE_OPTION_ROM_FCoE:
-                       img_optype = OPTYPE_FCOE_BIOS;
-                       break;
-               case IMAGE_FIRMWARE_BACKUP_iSCSI:
-                       img_optype = OPTYPE_ISCSI_BACKUP;
-                       break;
-               case IMAGE_NCSI:
-                       img_optype = OPTYPE_NCSI_FW;
-                       break;
-               default:
+               if (img_optype == 0xFFFF)
                        continue;
+               /* Don't bother verifying CRC if an old FW image is being
+                * flashed
+                */
+               if (old_fw_img)
+                       goto flash;
+
+               status = be_check_flash_crc(adapter, fw->data, img_offset,
+                                           img_size, filehdr_size +
+                                           img_hdrs_size, img_optype,
+                                           &crc_match);
+               /* The current FW image on the card does not recognize the new
+                * FLASH op_type. The FW download is partially complete.
+                * Reboot the server now to enable FW image to recognize the
+                * new FLASH op_type. To complete the remaining process,
+                * download the same FW again after the reboot.
+                */
+               if (status == MCC_STATUS_ILLEGAL_REQUEST ||
+                   status == MCC_STATUS_ILLEGAL_FIELD) {
+                       dev_err(dev, "Flash incomplete. Reset the server\n");
+                       dev_err(dev, "Download FW image again after reset\n");
+                       return -EAGAIN;
+               } else if (status) {
+                       dev_err(dev, "Could not get CRC for 0x%x region\n",
+                               img_optype);
+                       return -EFAULT;
                }
 
-               if (img_optype == OPTYPE_REDBOOT) {
-                       redboot = be_flash_redboot(adapter, fw->data,
-                                                  img_offset, img_size,
-                                                  filehdr_size +
-                                                  img_hdrs_size);
-                       if (!redboot)
-                               continue;
-               }
+               if (crc_match)
+                       continue;
 
-               p = fw->data;
-               p += filehdr_size + img_offset + img_hdrs_size;
+flash:
+               p = fw->data + filehdr_size + img_offset + img_hdrs_size;
                if (p + img_size > fw->data + fw->size)
                        return -1;
 
                status = be_flash(adapter, p, flash_cmd, img_optype, img_size);
-               if (status) {
-                       dev_err(&adapter->pdev->dev,
-                               "Flashing section type %d failed.\n",
-                               fsec->fsec_entry[i].type);
-                       return status;
+               /* For old FW images ignore ILLEGAL_FIELD error or errors on
+                * UFI_DIR region
+                */
+               if (old_fw_img && (status == MCC_STATUS_ILLEGAL_FIELD ||
+                                  (img_optype == OPTYPE_UFI_DIR &&
+                                   status == MCC_STATUS_FAILED))) {
+                       continue;
+               } else if (status) {
+                       dev_err(dev, "Flashing section type 0x%x failed\n",
+                               img_type);
+                       return -EFAULT;
                }
        }
        return 0;