scsi: qla2xxx: Add support for multiple fwdump templates/segments
authorJoe Carnuccio <joe.carnuccio@cavium.com>
Tue, 12 Mar 2019 18:08:17 +0000 (11:08 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 19 Mar 2019 16:22:54 +0000 (12:22 -0400)
This patch adds multipe firmware dump template and segments support for
ISP27XX/28XX.

Signed-off-by: Joe Carnuccio <joe.carnuccio@cavium.com>
Signed-off-by: Himanshu Madhani <hmadhani@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla2xxx/qla_tmpl.c

index 9547d96..4c294bc 100644 (file)
@@ -84,8 +84,7 @@ qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *vha,
                return 0;
        }
 
-       if (bcode[0] != 'H' || bcode[1] != 'Q' || bcode[2] != 'O' ||
-                       bcode[3] != 'S') {
+       if (memcmp(bcode, "HQOS", 4)) {
                /* Invalid FCP priority data header*/
                ql_dbg(ql_dbg_user, vha, 0x7052,
                    "Invalid FCP Priority data header. bcode=0x%x.\n",
index 533e498..cf2f597 100644 (file)
@@ -4030,9 +4030,11 @@ struct qla_hw_data {
        uint8_t         pep_version[3];
 
        /* Firmware dump template */
-       void            *fw_dump_template;
-       uint32_t        fw_dump_template_len;
-       /* Firmware dump information. */
+       struct fwdt {
+               void *template;
+               ulong length;
+               ulong dump_size;
+       } fwdt[2];
        struct qla2xxx_fw_dump *fw_dump;
        uint32_t        fw_dump_len;
        bool            fw_dumped;
@@ -4075,7 +4077,6 @@ struct qla_hw_data {
        uint16_t        product_id[4];
 
        uint8_t         model_number[16+1];
-#define BINZERO                "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
        char            model_desc[80];
        uint8_t         adapter_id[16+1];
 
index e300a70..a222997 100644 (file)
@@ -611,7 +611,7 @@ extern void qla82xx_fw_dump(scsi_qla_host_t *, int);
 extern void qla8044_fw_dump(scsi_qla_host_t *, int);
 
 extern void qla27xx_fwdump(scsi_qla_host_t *, int);
-extern ulong qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *);
+extern ulong qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *, void *);
 extern int qla27xx_fwdt_template_valid(void *);
 extern ulong qla27xx_fwdt_template_size(void *);
 
index 17509ab..24fc0a5 100644 (file)
@@ -3089,12 +3089,15 @@ eft_err:
 void
 qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
 {
+       int rval;
        uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
            eft_size, fce_size, mq_size;
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = ha->req_q_map[0];
        struct rsp_que *rsp = ha->rsp_q_map[0];
        struct qla2xxx_fw_dump *fw_dump;
+       dma_addr_t tc_dma;
+       void *tc;
 
        dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
        req_q_size = rsp_q_size = 0;
@@ -3139,20 +3142,51 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
 
                fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
 try_eft:
+               if (ha->eft)
+                       dma_free_coherent(&ha->pdev->dev,
+                           EFT_SIZE, ha->eft, ha->eft_dma);
+
+               /* Allocate memory for Extended Trace Buffer. */
+               tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
+                                        GFP_KERNEL);
+               if (!tc) {
+                       ql_log(ql_log_warn, vha, 0x00c1,
+                           "Unable to allocate (%d KB) for EFT.\n",
+                           EFT_SIZE / 1024);
+                       goto allocate;
+               }
+
+               rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS);
+               if (rval) {
+                       ql_log(ql_log_warn, vha, 0x00c2,
+                           "Unable to initialize EFT (%d).\n", rval);
+                       dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
+                           tc_dma);
+               }
                ql_dbg(ql_dbg_init, vha, 0x00c3,
                    "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024);
                eft_size = EFT_SIZE;
        }
 
        if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
-               if (!ha->fw_dump_template) {
-                       ql_log(ql_log_warn, vha, 0x00ba,
-                           "Failed missing fwdump template\n");
-                       return;
+               struct fwdt *fwdt = ha->fwdt;
+               uint j;
+
+               for (j = 0; j < 2; j++, fwdt++) {
+                       if (!fwdt->template) {
+                               ql_log(ql_log_warn, vha, 0x00ba,
+                                   "-> fwdt%u no template\n", j);
+                               continue;
+                       }
+                       ql_dbg(ql_dbg_init, vha, 0x00fa,
+                           "-> fwdt%u calculating fwdump size...\n", j);
+                       fwdt->dump_size = qla27xx_fwdt_calculate_dump_size(
+                           vha, fwdt->template);
+                       ql_dbg(ql_dbg_init, vha, 0x00fa,
+                           "-> fwdt%u calculated fwdump size = %#lx bytes\n",
+                           j, fwdt->dump_size);
+                       dump_size += fwdt->dump_size;
                }
-               dump_size = qla27xx_fwdt_calculate_dump_size(vha);
-               ql_dbg(ql_dbg_init, vha, 0x00fa,
-                   "-> allocating fwdump (%x bytes)...\n", dump_size);
                goto allocate;
        }
 
@@ -4270,11 +4304,14 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
 {
        char *st, *en;
        uint16_t index;
+       uint64_t zero[2] = { 0 };
        struct qla_hw_data *ha = vha->hw;
        int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
            !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha);
 
-       if (memcmp(model, BINZERO, len) != 0) {
+       if (len > sizeof(zero))
+               len = sizeof(zero);
+       if (memcmp(model, &zero, len) != 0) {
                strncpy(ha->model_number, model, len);
                st = en = ha->model_number;
                en += len - 1;
@@ -4378,8 +4415,8 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
            nv, ha->nvram_size);
 
        /* Bad NVRAM data, set defaults parameters. */
-       if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
-           nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
+       if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) ||
+           nv->nvram_version < 1) {
                /* Reset NVRAM data. */
                ql_log(ql_log_warn, vha, 0x0064,
                    "Inconsistent NVRAM "
@@ -6986,9 +7023,8 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
            nv, ha->nvram_size);
 
        /* Bad NVRAM data, set defaults parameters. */
-       if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
-           || nv->id[3] != ' ' ||
-           nv->nvram_version < cpu_to_le16(ICB_VERSION)) {
+       if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) ||
+           le16_to_cpu(nv->nvram_version) < ICB_VERSION) {
                /* Reset NVRAM data. */
                ql_log(ql_log_warn, vha, 0x006b,
                    "Inconsistent NVRAM detected: checksum=0x%x id=%c "
@@ -7304,14 +7340,16 @@ static int
 qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
     uint32_t faddr)
 {
-       int     rval = QLA_SUCCESS;
-       int     segments, fragment;
-       uint32_t *dcode, dlen;
-       uint32_t risc_addr;
-       uint32_t risc_size;
-       uint32_t i;
+       int rval;
+       uint templates, segments, fragment;
+       ulong i;
+       uint j;
+       ulong dlen;
+       uint32_t *dcode;
+       uint32_t risc_addr, risc_size, risc_attr = 0;
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = ha->req_q_map[0];
+       struct fwdt *fwdt = ha->fwdt;
 
        ql_dbg(ql_dbg_init, vha, 0x008b,
            "FW: Loading firmware from flash (%x).\n", faddr);
@@ -7329,34 +7367,36 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
                return QLA_FUNCTION_FAILED;
        }
 
-       while (segments && rval == QLA_SUCCESS) {
-               /* Read segment's load information. */
-               qla24xx_read_flash_data(vha, dcode, faddr, 4);
-
+       dcode = (void *)req->ring;
+       *srisc_addr = 0;
+       segments = FA_RISC_CODE_SEGMENTS;
+       for (j = 0; j < segments; j++) {
+               ql_dbg(ql_dbg_init, vha, 0x008d,
+                   "-> Loading segment %u...\n", j);
+               qla24xx_read_flash_data(vha, dcode, faddr, 10);
                risc_addr = be32_to_cpu(dcode[2]);
-               *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
                risc_size = be32_to_cpu(dcode[3]);
+               if (!*srisc_addr) {
+                       *srisc_addr = risc_addr;
+                       risc_attr = be32_to_cpu(dcode[9]);
+               }
 
-               fragment = 0;
-               while (risc_size > 0 && rval == QLA_SUCCESS) {
-                       dlen = (uint32_t)(ha->fw_transfer_size >> 2);
+               dlen = ha->fw_transfer_size >> 2;
+               for (fragment = 0; risc_size; fragment++) {
                        if (dlen > risc_size)
                                dlen = risc_size;
 
                        ql_dbg(ql_dbg_init, vha, 0x008e,
-                           "Loading risc segment@ risc addr %x "
-                           "number of dwords 0x%x offset 0x%x.\n",
-                           risc_addr, dlen, faddr);
-
+                           "-> Loading fragment %u: %#x <- %#x (%#lx dwords)...\n",
+                           fragment, risc_addr, faddr, dlen);
                        qla24xx_read_flash_data(vha, dcode, faddr, dlen);
                        for (i = 0; i < dlen; i++)
                                dcode[i] = swab32(dcode[i]);
 
-                       rval = qla2x00_load_ram(vha, req->dma, risc_addr,
-                           dlen);
+                       rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen);
                        if (rval) {
                                ql_log(ql_log_fatal, vha, 0x008f,
-                                   "Failed to load segment %d of firmware.\n",
+                                   "-> Failed load firmware fragment %u.\n",
                                    fragment);
                                return QLA_FUNCTION_FAILED;
                        }
@@ -7364,72 +7404,83 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
                        faddr += dlen;
                        risc_addr += dlen;
                        risc_size -= dlen;
-                       fragment++;
                }
-
-               /* Next segment. */
-               segments--;
        }
 
        if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
-               return rval;
+               return QLA_SUCCESS;
 
-       if (ha->fw_dump_template)
-               vfree(ha->fw_dump_template);
-       ha->fw_dump_template = NULL;
-       ha->fw_dump_template_len = 0;
-
-       ql_dbg(ql_dbg_init, vha, 0x0161,
-           "Loading fwdump template from %x\n", faddr);
-       qla24xx_read_flash_data(vha, dcode, faddr, 7);
-       risc_size = be32_to_cpu(dcode[2]);
-       ql_dbg(ql_dbg_init, vha, 0x0162,
-           "-> array size %x dwords\n", risc_size);
-       if (risc_size == 0 || risc_size == ~0)
-               goto failed;
+       templates = (risc_attr & BIT_9) ? 2 : 1;
+       ql_dbg(ql_dbg_init, vha, 0x0160, "-> templates = %u\n", templates);
+       for (j = 0; j < templates; j++, fwdt++) {
+               if (fwdt->template)
+                       vfree(fwdt->template);
+               fwdt->template = NULL;
+               fwdt->length = 0;
+
+               qla24xx_read_flash_data(vha, dcode, faddr, 7);
+               risc_size = be32_to_cpu(dcode[2]);
+               ql_dbg(ql_dbg_init, vha, 0x0161,
+                   "-> fwdt%u template array at %#x (%#x dwords)\n",
+                   j, faddr, risc_size);
+               if (!risc_size || !~risc_size) {
+                       ql_dbg(ql_dbg_init, vha, 0x0162,
+                           "-> fwdt%u failed to read array\n", j);
+                       goto failed;
+               }
 
-       dlen = (risc_size - 8) * sizeof(*dcode);
-       ql_dbg(ql_dbg_init, vha, 0x0163,
-           "-> template allocating %x bytes...\n", dlen);
-       ha->fw_dump_template = vmalloc(dlen);
-       if (!ha->fw_dump_template) {
-               ql_log(ql_log_warn, vha, 0x0164,
-                   "Failed fwdump template allocate %x bytes.\n", risc_size);
-               goto failed;
-       }
+               /* skip header and ignore checksum */
+               faddr += 7;
+               risc_size -= 8;
+
+               ql_dbg(ql_dbg_init, vha, 0x0163,
+                   "-> fwdt%u template allocate template %#x words...\n",
+                   j, risc_size);
+               fwdt->template = vmalloc(risc_size * sizeof(*dcode));
+               if (!fwdt->template) {
+                       ql_log(ql_log_warn, vha, 0x0164,
+                           "-> fwdt%u failed allocate template.\n", j);
+                       goto failed;
+               }
 
-       faddr += 7;
-       risc_size -= 8;
-       dcode = ha->fw_dump_template;
-       qla24xx_read_flash_data(vha, dcode, faddr, risc_size);
-       for (i = 0; i < risc_size; i++)
-               dcode[i] = le32_to_cpu(dcode[i]);
+               dcode = fwdt->template;
+               qla24xx_read_flash_data(vha, dcode, faddr, risc_size);
+               for (i = 0; i < risc_size; i++)
+                       dcode[i] = le32_to_cpu(dcode[i]);
 
-       if (!qla27xx_fwdt_template_valid(dcode)) {
-               ql_log(ql_log_warn, vha, 0x0165,
-                   "Failed fwdump template validate\n");
-               goto failed;
-       }
+               if (!qla27xx_fwdt_template_valid(dcode)) {
+                       ql_log(ql_log_warn, vha, 0x0165,
+                           "-> fwdt%u failed template validate\n", j);
+                       goto failed;
+               }
 
-       dlen = qla27xx_fwdt_template_size(dcode);
-       ql_dbg(ql_dbg_init, vha, 0x0166,
-           "-> template size %x bytes\n", dlen);
-       if (dlen > risc_size * sizeof(*dcode)) {
-               ql_log(ql_log_warn, vha, 0x0167,
-                   "Failed fwdump template exceeds array by %zx bytes\n",
-                   (size_t)(dlen - risc_size * sizeof(*dcode)));
-               goto failed;
+               dlen = qla27xx_fwdt_template_size(dcode);
+               ql_dbg(ql_dbg_init, vha, 0x0166,
+                   "-> fwdt%u template size %#lx bytes (%#lx words)\n",
+                   j, dlen, dlen / sizeof(*dcode));
+               if (dlen > risc_size * sizeof(*dcode)) {
+                       ql_log(ql_log_warn, vha, 0x0167,
+                           "-> fwdt%u template exceeds array (%-lu bytes)\n",
+                           j, dlen - risc_size * sizeof(*dcode));
+                       goto failed;
+               }
+
+               fwdt->length = dlen;
+               ql_dbg(ql_dbg_init, vha, 0x0168,
+                   "-> fwdt%u loaded template ok\n", j);
+
+               faddr += risc_size + 1;
        }
-       ha->fw_dump_template_len = dlen;
-       return rval;
+
+       return QLA_SUCCESS;
 
 failed:
-       ql_log(ql_log_warn, vha, 0x016d, "Failed fwdump template\n");
-       if (ha->fw_dump_template)
-               vfree(ha->fw_dump_template);
-       ha->fw_dump_template = NULL;
-       ha->fw_dump_template_len = 0;
-       return rval;
+       if (fwdt->template)
+               vfree(fwdt->template);
+       fwdt->template = NULL;
+       fwdt->length = 0;
+
+       return QLA_SUCCESS;
 }
 
 #define QLA_FW_URL "http://ldriver.qlogic.com/firmware/"
@@ -7537,31 +7588,31 @@ static int
 qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 {
        int     rval;
-       int     segments, fragment;
-       uint32_t *dcode, dlen;
-       uint32_t risc_addr;
-       uint32_t risc_size;
-       uint32_t i;
+       uint templates, segments, fragment;
+       uint32_t *dcode;
+       ulong dlen;
+       uint32_t risc_addr, risc_size, risc_attr = 0;
+       ulong i;
+       uint j;
        struct fw_blob *blob;
        uint32_t *fwcode;
-       uint32_t fwclen;
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = ha->req_q_map[0];
+       struct fwdt *fwdt = ha->fwdt;
+
+       ql_dbg(ql_dbg_init, vha, 0x0090,
+           "-> FW: Loading via request-firmware.\n");
 
-       /* Load firmware blob. */
        blob = qla2x00_request_firmware(vha);
        if (!blob) {
-               ql_log(ql_log_warn, vha, 0x0090,
-                   "Firmware image unavailable.\n");
-               ql_log(ql_log_warn, vha, 0x0091,
-                   "Firmware images can be retrieved from: "
-                   QLA_FW_URL ".\n");
+               ql_log(ql_log_warn, vha, 0x0092,
+                   "-> Firmware file not found.\n");
 
                return QLA_FUNCTION_FAILED;
        }
 
        fwcode = (void *)blob->fw->data;
-       dcode = fwcode;
+       dcode = fwcode + 4;
        if (qla24xx_risc_firmware_invalid(dcode)) {
                ql_log(ql_log_fatal, vha, 0x0093,
                    "Unable to verify integrity of firmware image (%zd).\n",
@@ -7583,38 +7634,39 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                return QLA_FUNCTION_FAILED;
        }
 
-       while (segments && rval == QLA_SUCCESS) {
+       dcode = (void *)req->ring;
+       *srisc_addr = 0;
+       segments = FA_RISC_CODE_SEGMENTS;
+       for (j = 0; j < segments; j++) {
+               ql_dbg(ql_dbg_init, vha, 0x0096,
+                   "-> Loading segment %u...\n", j);
                risc_addr = be32_to_cpu(fwcode[2]);
-               *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
                risc_size = be32_to_cpu(fwcode[3]);
 
-               /* Validate firmware image size. */
-               fwclen += risc_size * sizeof(uint32_t);
-               if (blob->fw->size < fwclen) {
-                       ql_log(ql_log_fatal, vha, 0x0096,
-                           "Unable to verify integrity of firmware image "
-                           "(%zd).\n", blob->fw->size);
-                       return QLA_FUNCTION_FAILED;
+               if (!*srisc_addr) {
+                       *srisc_addr = risc_addr;
+                       risc_attr = be32_to_cpu(fwcode[9]);
                }
 
-               fragment = 0;
-               while (risc_size > 0 && rval == QLA_SUCCESS) {
+               dlen = ha->fw_transfer_size >> 2;
+               for (fragment = 0; risc_size; fragment++) {
                        dlen = (uint32_t)(ha->fw_transfer_size >> 2);
                        if (dlen > risc_size)
                                dlen = risc_size;
 
                        ql_dbg(ql_dbg_init, vha, 0x0097,
-                           "Loading risc segment@ risc addr %x "
-                           "number of dwords 0x%x.\n", risc_addr, dlen);
+                           "-> Loading fragment %u: %#x <- %#x (%#lx words)...\n",
+                           fragment, risc_addr,
+                           (uint32_t)(fwcode - (typeof(fwcode))blob->fw->data),
+                           dlen);
 
                        for (i = 0; i < dlen; i++)
                                dcode[i] = swab32(fwcode[i]);
 
-                       rval = qla2x00_load_ram(vha, req->dma, risc_addr,
-                           dlen);
+                       rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen);
                        if (rval) {
                                ql_log(ql_log_fatal, vha, 0x0098,
-                                   "Failed to load segment %d of firmware.\n",
+                                   "-> Failed load firmware fragment %u.\n",
                                    fragment);
                                return QLA_FUNCTION_FAILED;
                        }
@@ -7622,71 +7674,82 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                        fwcode += dlen;
                        risc_addr += dlen;
                        risc_size -= dlen;
-                       fragment++;
                }
-
-               /* Next segment. */
-               segments--;
        }
 
        if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
-               return rval;
+               return QLA_SUCCESS;
 
-       if (ha->fw_dump_template)
-               vfree(ha->fw_dump_template);
-       ha->fw_dump_template = NULL;
-       ha->fw_dump_template_len = 0;
-
-       ql_dbg(ql_dbg_init, vha, 0x171,
-           "Loading fwdump template from %x\n",
-           (uint32_t)((void *)fwcode - (void *)blob->fw->data));
-       risc_size = be32_to_cpu(fwcode[2]);
-       ql_dbg(ql_dbg_init, vha, 0x172,
-           "-> array size %x dwords\n", risc_size);
-       if (risc_size == 0 || risc_size == ~0)
-               goto failed;
+       templates = (risc_attr & BIT_9) ? 2 : 1;
+       ql_dbg(ql_dbg_init, vha, 0x0170, "-> templates = %u\n", templates);
+       for (j = 0; j < templates; j++, fwdt++) {
+               if (fwdt->template)
+                       vfree(fwdt->template);
+               fwdt->template = NULL;
+               fwdt->length = 0;
+
+               risc_size = be32_to_cpu(fwcode[2]);
+               ql_dbg(ql_dbg_init, vha, 0x0171,
+                   "-> fwdt%u template array at %#x (%#x dwords)\n",
+                   j, (uint32_t)((void *)fwcode - (void *)blob->fw->data),
+                   risc_size);
+               if (!risc_size || !~risc_size) {
+                       ql_dbg(ql_dbg_init, vha, 0x0172,
+                           "-> fwdt%u failed to read array\n", j);
+                       goto failed;
+               }
 
-       dlen = (risc_size - 8) * sizeof(*fwcode);
-       ql_dbg(ql_dbg_init, vha, 0x0173,
-           "-> template allocating %x bytes...\n", dlen);
-       ha->fw_dump_template = vmalloc(dlen);
-       if (!ha->fw_dump_template) {
-               ql_log(ql_log_warn, vha, 0x0174,
-                   "Failed fwdump template allocate %x bytes.\n", risc_size);
-               goto failed;
-       }
+               /* skip header and ignore checksum */
+               fwcode += 7;
+               risc_size -= 8;
+
+               ql_dbg(ql_dbg_init, vha, 0x0173,
+                   "-> fwdt%u template allocate template %#x words...\n",
+                   j, risc_size);
+               fwdt->template = vmalloc(risc_size * sizeof(*dcode));
+               if (!fwdt->template) {
+                       ql_log(ql_log_warn, vha, 0x0174,
+                           "-> fwdt%u failed allocate template.\n", j);
+                       goto failed;
+               }
 
-       fwcode += 7;
-       risc_size -= 8;
-       dcode = ha->fw_dump_template;
-       for (i = 0; i < risc_size; i++)
-               dcode[i] = le32_to_cpu(fwcode[i]);
+               dcode = fwdt->template;
+               for (i = 0; i < risc_size; i++)
+                       dcode[i] = le32_to_cpu(fwcode[i]);
 
-       if (!qla27xx_fwdt_template_valid(dcode)) {
-               ql_log(ql_log_warn, vha, 0x0175,
-                   "Failed fwdump template validate\n");
-               goto failed;
-       }
+               if (!qla27xx_fwdt_template_valid(dcode)) {
+                       ql_log(ql_log_warn, vha, 0x0175,
+                           "-> fwdt%u failed template validate\n", j);
+                       goto failed;
+               }
 
-       dlen = qla27xx_fwdt_template_size(dcode);
-       ql_dbg(ql_dbg_init, vha, 0x0176,
-           "-> template size %x bytes\n", dlen);
-       if (dlen > risc_size * sizeof(*fwcode)) {
-               ql_log(ql_log_warn, vha, 0x0177,
-                   "Failed fwdump template exceeds array by %zx bytes\n",
-                   (size_t)(dlen - risc_size * sizeof(*fwcode)));
-               goto failed;
+               dlen = qla27xx_fwdt_template_size(dcode);
+               ql_dbg(ql_dbg_init, vha, 0x0176,
+                   "-> fwdt%u template size %#lx bytes (%#lx words)\n",
+                   j, dlen, dlen / sizeof(*dcode));
+               if (dlen > risc_size * sizeof(*dcode)) {
+                       ql_log(ql_log_warn, vha, 0x0177,
+                           "-> fwdt%u template exceeds array (%-lu bytes)\n",
+                           j, dlen - risc_size * sizeof(*dcode));
+                       goto failed;
+               }
+
+               fwdt->length = dlen;
+               ql_dbg(ql_dbg_init, vha, 0x0178,
+                   "-> fwdt%u loaded template ok\n", j);
+
+               fwcode += risc_size + 1;
        }
-       ha->fw_dump_template_len = dlen;
-       return rval;
+
+       return QLA_SUCCESS;
 
 failed:
-       ql_log(ql_log_warn, vha, 0x017d, "Failed fwdump template\n");
-       if (ha->fw_dump_template)
-               vfree(ha->fw_dump_template);
-       ha->fw_dump_template = NULL;
-       ha->fw_dump_template_len = 0;
-       return rval;
+       if (fwdt->template)
+               vfree(fwdt->template);
+       fwdt->template = NULL;
+       fwdt->length = 0;
+
+       return QLA_SUCCESS;
 }
 
 int
@@ -7953,9 +8016,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
            nv, ha->nvram_size);
 
        /* Bad NVRAM data, set defaults parameters. */
-       if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
-           || nv->id[3] != ' ' ||
-           nv->nvram_version < cpu_to_le16(ICB_VERSION)) {
+       if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) ||
+           le16_to_cpu(nv->nvram_version) < ICB_VERSION) {
                /* Reset NVRAM data. */
                ql_log(ql_log_info, vha, 0x0073,
                    "Inconsistent NVRAM detected: checksum=0x%x id=%c "
index 58df603..012125e 100644 (file)
@@ -4647,6 +4647,9 @@ qla2x00_free_exchoffld_buffer(struct qla_hw_data *ha)
 static void
 qla2x00_free_fw_dump(struct qla_hw_data *ha)
 {
+       struct fwdt *fwdt = ha->fwdt;
+       uint j;
+
        if (ha->fce)
                dma_free_coherent(&ha->pdev->dev,
                    FCE_SIZE, ha->fce, ha->fce_dma);
@@ -4657,8 +4660,6 @@ qla2x00_free_fw_dump(struct qla_hw_data *ha)
 
        if (ha->fw_dump)
                vfree(ha->fw_dump);
-       if (ha->fw_dump_template)
-               vfree(ha->fw_dump_template);
 
        ha->fce = NULL;
        ha->fce_dma = 0;
@@ -4669,8 +4670,13 @@ qla2x00_free_fw_dump(struct qla_hw_data *ha)
        ha->fw_dump_reading = 0;
        ha->fw_dump = NULL;
        ha->fw_dump_len = 0;
-       ha->fw_dump_template = NULL;
-       ha->fw_dump_template_len = 0;
+
+       for (j = 0; j < 2; j++, fwdt++) {
+               if (fwdt->template)
+                       vfree(fwdt->template);
+               fwdt->template = NULL;
+               fwdt->length = 0;
+       }
 }
 
 /*
index 0e3de06..9c3abe2 100644 (file)
@@ -2633,6 +2633,8 @@ qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
                goto slow_read;
 
 try_fast:
+       if (offset & 0xff)
+               goto slow_read;
        optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
            &optrom_dma, GFP_KERNEL);
        if (!optrom) {
index c6a09d3..da1eb56 100644 (file)
@@ -38,7 +38,6 @@ qla27xx_insert32(uint32_t value, void *buf, ulong *len)
 static inline void
 qla27xx_insertbuf(void *mem, ulong size, void *buf, ulong *len)
 {
-
        if (buf && mem && size) {
                buf += *len;
                memcpy(buf, mem, size);
@@ -855,23 +854,11 @@ qla27xx_walk_template(struct scsi_qla_host *vha,
 
        if (count)
                ql_dbg(ql_dbg_misc, vha, 0xd018,
-                   "%s: entry residual count (%lx)\n", __func__, count);
+                   "%s: entry count residual=+%lu\n", __func__, count);
 
        if (ent)
                ql_dbg(ql_dbg_misc, vha, 0xd019,
-                   "%s: missing end entry (%lx)\n", __func__, count);
-
-       if (buf && *len != vha->hw->fw_dump_len)
-               ql_dbg(ql_dbg_misc, vha, 0xd01b,
-                   "%s: length=%#lx residual=%+ld\n",
-                   __func__, *len, vha->hw->fw_dump_len - *len);
-
-       if (buf) {
-               ql_log(ql_log_warn, vha, 0xd015,
-                   "Firmware dump saved to temp buffer (%lu/%p)\n",
-                   vha->host_no, vha->hw->fw_dump);
-               qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
-       }
+                   "%s: missing end entry\n", __func__);
 }
 
 static void
@@ -894,8 +881,8 @@ qla27xx_driver_info(struct qla27xx_fwdt_template *tmp)
 }
 
 static void
-qla27xx_firmware_info(struct qla27xx_fwdt_template *tmp,
-       struct scsi_qla_host *vha)
+qla27xx_firmware_info(struct scsi_qla_host *vha,
+    struct qla27xx_fwdt_template *tmp)
 {
        tmp->firmware_version[0] = vha->hw->fw_major_version;
        tmp->firmware_version[1] = vha->hw->fw_minor_version;
@@ -912,7 +899,7 @@ ql27xx_edit_template(struct scsi_qla_host *vha,
 {
        qla27xx_time_stamp(tmp);
        qla27xx_driver_info(tmp);
-       qla27xx_firmware_info(tmp, vha);
+       qla27xx_firmware_info(vha, tmp);
 }
 
 static inline uint32_t
@@ -943,26 +930,26 @@ qla27xx_verify_template_header(struct qla27xx_fwdt_template *tmp)
        return le32_to_cpu(tmp->template_type) == TEMPLATE_TYPE_FWDUMP;
 }
 
-static void
-qla27xx_execute_fwdt_template(struct scsi_qla_host *vha)
+static ulong
+qla27xx_execute_fwdt_template(struct scsi_qla_host *vha,
+    struct qla27xx_fwdt_template *tmp, void *buf)
 {
-       struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
-       ulong len;
+       ulong len = 0;
 
        if (qla27xx_fwdt_template_valid(tmp)) {
                len = tmp->template_size;
-               tmp = memcpy(vha->hw->fw_dump, tmp, len);
+               tmp = memcpy(buf, tmp, len);
                ql27xx_edit_template(vha, tmp);
-               qla27xx_walk_template(vha, tmp, tmp, &len);
-               vha->hw->fw_dump_len = len;
-               vha->hw->fw_dumped = 1;
+               qla27xx_walk_template(vha, tmp, buf, &len);
        }
+
+       return len;
 }
 
 ulong
-qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha)
+qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha, void *p)
 {
-       struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
+       struct qla27xx_fwdt_template *tmp = p;
        ulong len = 0;
 
        if (qla27xx_fwdt_template_valid(tmp)) {
@@ -1012,17 +999,41 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&vha->hw->hardware_lock, flags);
 #endif
 
-       if (!vha->hw->fw_dump)
-               ql_log(ql_log_warn, vha, 0xd01e, "fwdump buffer missing.\n");
-       else if (!vha->hw->fw_dump_template)
-               ql_log(ql_log_warn, vha, 0xd01f, "fwdump template missing.\n");
-       else if (vha->hw->fw_dumped)
-               ql_log(ql_log_warn, vha, 0xd300,
-                   "Firmware has been previously dumped (%p),"
-                   " -- ignoring request\n", vha->hw->fw_dump);
-       else {
-               QLA_FW_STOPPED(vha->hw);
-               qla27xx_execute_fwdt_template(vha);
+       if (!vha->hw->fw_dump) {
+               ql_log(ql_log_warn, vha, 0xd01e, "-> fwdump no buffer\n");
+       } else if (vha->hw->fw_dumped) {
+               ql_log(ql_log_warn, vha, 0xd01f,
+                   "-> Firmware already dumped (%p) -- ignoring request\n",
+                   vha->hw->fw_dump);
+       } else {
+               struct fwdt *fwdt = vha->hw->fwdt;
+               uint j;
+               ulong len;
+               void *buf = vha->hw->fw_dump;
+
+               for (j = 0; j < 2; j++, fwdt++, buf += len) {
+                       ql_log(ql_log_warn, vha, 0xd011,
+                           "-> fwdt%u running...\n", j);
+                       if (!fwdt->template) {
+                               ql_log(ql_log_warn, vha, 0xd012,
+                                   "-> fwdt%u no template\n", j);
+                               break;
+                       }
+                       len = qla27xx_execute_fwdt_template(vha,
+                           fwdt->template, buf);
+                       if (len != fwdt->dump_size) {
+                               ql_log(ql_log_warn, vha, 0xd013,
+                                   "-> fwdt%u fwdump residual=%+ld\n",
+                                   j, fwdt->dump_size - len);
+                       }
+               }
+               vha->hw->fw_dump_len = buf - (void *)vha->hw->fw_dump;
+               vha->hw->fw_dumped = 1;
+
+               ql_log(ql_log_warn, vha, 0xd015,
+                   "-> Firmware dump saved to buffer (%lu/%p) <%lx>\n",
+                   vha->host_no, vha->hw->fw_dump, vha->hw->fw_dump_cap_flags);
+               qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
        }
 
 #ifndef __CHECKER__