diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_init.c')
| -rw-r--r-- | drivers/scsi/qla4xxx/ql4_init.c | 169 |
1 files changed, 152 insertions, 17 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 90614f38b55..6f12f859b11 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -1,6 +1,6 @@ /* * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2013 QLogic Corporation * * See LICENSE.qla4xxx for copyright and licensing details. */ @@ -86,6 +86,7 @@ static void qla4xxx_init_response_q_entries(struct scsi_qla_host *ha) int qla4xxx_init_rings(struct scsi_qla_host *ha) { unsigned long flags = 0; + int i; /* Initialize request queue. */ spin_lock_irqsave(&ha->hardware_lock, flags); @@ -101,11 +102,18 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha) if (is_qla8022(ha)) { writel(0, - (unsigned long __iomem *)&ha->qla4_8xxx_reg->req_q_out); + (unsigned long __iomem *)&ha->qla4_82xx_reg->req_q_out); + writel(0, + (unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_in); + writel(0, + (unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_out); + } else if (is_qla8032(ha) || is_qla8042(ha)) { + writel(0, + (unsigned long __iomem *)&ha->qla4_83xx_reg->req_q_in); writel(0, - (unsigned long __iomem *)&ha->qla4_8xxx_reg->rsp_q_in); + (unsigned long __iomem *)&ha->qla4_83xx_reg->rsp_q_in); writel(0, - (unsigned long __iomem *)&ha->qla4_8xxx_reg->rsp_q_out); + (unsigned long __iomem *)&ha->qla4_83xx_reg->rsp_q_out); } else { /* * Initialize DMA Shadow registers. The firmware is really @@ -125,6 +133,10 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha) qla4xxx_init_response_q_entries(ha); + /* Initialize mailbox active array */ + for (i = 0; i < MAX_MRB; i++) + ha->active_mrb_array[i] = NULL; + spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_SUCCESS; @@ -183,12 +195,10 @@ exit_get_sys_info_no_free: * @ha: pointer to host adapter structure. * **/ -static int qla4xxx_init_local_data(struct scsi_qla_host *ha) +static void qla4xxx_init_local_data(struct scsi_qla_host *ha) { /* Initialize aen queue */ ha->aen_q_count = MAX_AEN_ENTRIES; - - return qla4xxx_get_firmware_status(ha); } static uint8_t @@ -272,6 +282,120 @@ qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha) return ipv4_wait|ipv6_wait; } +static int qla4_80xx_is_minidump_dma_capable(struct scsi_qla_host *ha, + struct qla4_8xxx_minidump_template_hdr *md_hdr) +{ + int offset = (is_qla8022(ha)) ? QLA8022_TEMPLATE_CAP_OFFSET : + QLA83XX_TEMPLATE_CAP_OFFSET; + int rval = 1; + uint32_t *cap_offset; + + cap_offset = (uint32_t *)((char *)md_hdr + offset); + + if (!(le32_to_cpu(*cap_offset) & BIT_0)) { + ql4_printk(KERN_INFO, ha, "PEX DMA Not supported %d\n", + *cap_offset); + rval = 0; + } + + return rval; +} + +/** + * qla4xxx_alloc_fw_dump - Allocate memory for minidump data. + * @ha: pointer to host adapter structure. + **/ +void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha) +{ + int status; + uint32_t capture_debug_level; + int hdr_entry_bit, k; + void *md_tmp; + dma_addr_t md_tmp_dma; + struct qla4_8xxx_minidump_template_hdr *md_hdr; + int dma_capable; + + if (ha->fw_dump) { + ql4_printk(KERN_WARNING, ha, + "Firmware dump previously allocated.\n"); + return; + } + + status = qla4xxx_req_template_size(ha); + if (status != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, + "scsi%ld: Failed to get template size\n", + ha->host_no); + return; + } + + clear_bit(AF_82XX_FW_DUMPED, &ha->flags); + + /* Allocate memory for saving the template */ + md_tmp = dma_alloc_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size, + &md_tmp_dma, GFP_KERNEL); + + /* Request template */ + status = qla4xxx_get_minidump_template(ha, md_tmp_dma); + if (status != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, + "scsi%ld: Failed to get minidump template\n", + ha->host_no); + goto alloc_cleanup; + } + + md_hdr = (struct qla4_8xxx_minidump_template_hdr *)md_tmp; + + dma_capable = qla4_80xx_is_minidump_dma_capable(ha, md_hdr); + + capture_debug_level = md_hdr->capture_debug_level; + + /* Get capture mask based on module loadtime setting. */ + if ((ql4xmdcapmask >= 0x3 && ql4xmdcapmask <= 0x7F) || + (ql4xmdcapmask == 0xFF && dma_capable)) { + ha->fw_dump_capture_mask = ql4xmdcapmask; + } else { + if (ql4xmdcapmask == 0xFF) + ql4_printk(KERN_INFO, ha, "Falling back to default capture mask, as PEX DMA is not supported\n"); + ha->fw_dump_capture_mask = capture_debug_level; + } + + md_hdr->driver_capture_mask = ha->fw_dump_capture_mask; + + DEBUG2(ql4_printk(KERN_INFO, ha, "Minimum num of entries = %d\n", + md_hdr->num_of_entries)); + DEBUG2(ql4_printk(KERN_INFO, ha, "Dump template size = %d\n", + ha->fw_dump_tmplt_size)); + DEBUG2(ql4_printk(KERN_INFO, ha, "Selected Capture mask =0x%x\n", + ha->fw_dump_capture_mask)); + + /* Calculate fw_dump_size */ + for (hdr_entry_bit = 0x2, k = 1; (hdr_entry_bit & 0xFF); + hdr_entry_bit <<= 1, k++) { + if (hdr_entry_bit & ha->fw_dump_capture_mask) + ha->fw_dump_size += md_hdr->capture_size_array[k]; + } + + /* Total firmware dump size including command header */ + ha->fw_dump_size += ha->fw_dump_tmplt_size; + ha->fw_dump = vmalloc(ha->fw_dump_size); + if (!ha->fw_dump) + goto alloc_cleanup; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Minidump Tempalate Size = 0x%x KB\n", + ha->fw_dump_tmplt_size)); + DEBUG2(ql4_printk(KERN_INFO, ha, + "Total Minidump size = 0x%x KB\n", ha->fw_dump_size)); + + memcpy(ha->fw_dump, md_tmp, ha->fw_dump_tmplt_size); + ha->fw_dump_tmplt_hdr = ha->fw_dump; + +alloc_cleanup: + dma_free_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size, + md_tmp, md_tmp_dma); +} + static int qla4xxx_fw_ready(struct scsi_qla_host *ha) { uint32_t timeout_count; @@ -431,7 +555,7 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) /* For 82xx, stop firmware before initializing because if BIOS * has previously initialized firmware, then driver's initialize * firmware will fail. */ - if (is_qla8022(ha)) + if (is_qla80XX(ha)) qla4_8xxx_stop_firmware(ha); ql4_printk(KERN_INFO, ha, "Initializing firmware..\n"); @@ -440,9 +564,13 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) "control block\n", ha->host_no, __func__)); return status; } + if (!qla4xxx_fw_ready(ha)) return status; + if (is_qla80XX(ha) && !test_bit(AF_INIT_DONE, &ha->flags)) + qla4xxx_alloc_fw_dump(ha); + return qla4xxx_get_firmware_status(ha); } @@ -762,6 +890,8 @@ int qla4xxx_start_firmware(struct scsi_qla_host *ha) if (status == QLA_SUCCESS) { if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags)) qla4xxx_get_crash_record(ha); + + qla4xxx_init_rings(ha); } else { DEBUG(printk("scsi%ld: %s: Firmware has NOT started\n", ha->host_no, __func__)); @@ -831,14 +961,23 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset) if (ha->isp_ops->start_firmware(ha) == QLA_ERROR) goto exit_init_hba; + /* + * For ISP83XX, mailbox and IOCB interrupts are enabled separately. + * Mailbox interrupts must be enabled prior to issuing any mailbox + * command in order to prevent the possibility of losing interrupts + * while switching from polling to interrupt mode. IOCB interrupts are + * enabled via isp_ops->enable_intrs. + */ + if (is_qla8032(ha) || is_qla8042(ha)) + qla4_83xx_enable_mbox_intrs(ha); + if (qla4xxx_about_firmware(ha) == QLA_ERROR) goto exit_init_hba; if (ha->isp_ops->get_sys_info(ha) == QLA_ERROR) goto exit_init_hba; - if (qla4xxx_init_local_data(ha) == QLA_ERROR) - goto exit_init_hba; + qla4xxx_init_local_data(ha); status = qla4xxx_init_firmware(ha); if (status == QLA_ERROR) @@ -848,13 +987,8 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset) qla4xxx_build_ddb_list(ha, is_reset); set_bit(AF_ONLINE, &ha->flags); -exit_init_hba: - if (is_qla8022(ha) && (status == QLA_ERROR)) { - /* Since interrupts are registered in start_firmware for - * 82xx, release them here if initialize_adapter fails */ - qla4xxx_free_irqs(ha); - } +exit_init_hba: DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no, status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); return status; @@ -879,8 +1013,8 @@ int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, switch (state) { case DDB_DS_SESSION_ACTIVE: case DDB_DS_DISCOVERY: - ddb_entry->unblock_sess(ddb_entry->sess); qla4xxx_update_session_conn_param(ha, ddb_entry); + ddb_entry->unblock_sess(ddb_entry->sess); status = QLA_SUCCESS; break; case DDB_DS_SESSION_FAILED: @@ -892,6 +1026,7 @@ int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, } break; case DDB_DS_SESSION_ACTIVE: + case DDB_DS_DISCOVERY: switch (state) { case DDB_DS_SESSION_FAILED: /* |
