diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_os.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 494 |
1 files changed, 331 insertions, 163 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 9da426628b97..ad2da9cd7000 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1,6 +1,6 @@ /* * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2012 QLogic Corporation * * See LICENSE.qla4xxx for copyright and licensing details. */ @@ -18,6 +18,7 @@ #include "ql4_glbl.h" #include "ql4_dbg.h" #include "ql4_inline.h" +#include "ql4_83xx.h" /* * Driver version @@ -160,7 +161,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); static int qla4xxx_slave_alloc(struct scsi_device *device); static int qla4xxx_slave_configure(struct scsi_device *device); static void qla4xxx_slave_destroy(struct scsi_device *sdev); -static umode_t ql4_attr_is_visible(int param_type, int param); +static umode_t qla4_attr_is_visible(int param_type, int param); static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason); @@ -203,7 +204,7 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST | CAP_DATADGST | CAP_LOGIN_OFFLOAD | CAP_MULTI_R2T, - .attr_is_visible = ql4_attr_is_visible, + .attr_is_visible = qla4_attr_is_visible, .create_session = qla4xxx_session_create, .destroy_session = qla4xxx_session_destroy, .start_conn = qla4xxx_conn_start, @@ -315,7 +316,7 @@ exit_send_ping: return rval; } -static umode_t ql4_attr_is_visible(int param_type, int param) +static umode_t qla4_attr_is_visible(int param_type, int param) { switch (param_type) { case ISCSI_HOST_PARAM: @@ -1366,7 +1367,7 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, conn = cls_conn->dd_data; qla_conn = conn->dd_data; - dst_addr = &qla_conn->qla_ep->dst_addr; + dst_addr = (struct sockaddr *)&qla_conn->qla_ep->dst_addr; switch (param) { case ISCSI_PARAM_CONN_PORT: @@ -2315,8 +2316,17 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) if (ha->nx_pcibase) iounmap( (struct device_reg_82xx __iomem *)ha->nx_pcibase); - } else if (ha->reg) + } else if (is_qla8032(ha)) { + if (ha->nx_pcibase) + iounmap( + (struct device_reg_83xx __iomem *)ha->nx_pcibase); + } else if (ha->reg) { iounmap(ha->reg); + } + + if (ha->reset_tmplt.buff) + vfree(ha->reset_tmplt.buff); + pci_release_regions(ha->pdev); } @@ -2420,7 +2430,7 @@ static int qla4_8xxx_check_temp(struct scsi_qla_host *ha) uint32_t temp, temp_state, temp_val; int status = QLA_SUCCESS; - temp = qla4_8xxx_rd_32(ha, CRB_TEMP_STATE); + temp = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_TEMP_STATE); temp_state = qla82xx_get_temp_state(temp); temp_val = qla82xx_get_temp_val(temp); @@ -2456,7 +2466,8 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) uint32_t fw_heartbeat_counter; int status = QLA_SUCCESS; - fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); + fw_heartbeat_counter = qla4_8xxx_rd_direct(ha, + QLA8XXX_PEG_ALIVE_COUNTER); /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */ if (fw_heartbeat_counter == 0xffffffff) { DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen " @@ -2470,28 +2481,7 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) /* FW not alive after 2 seconds */ if (ha->seconds_since_last_heartbeat == 2) { ha->seconds_since_last_heartbeat = 0; - - ql4_printk(KERN_INFO, ha, - "scsi(%ld): %s, Dumping hw/fw registers:\n " - " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:" - " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:" - " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:" - " 0x%x,\n PEG_NET_4_PC: 0x%x\n", - ha->host_no, __func__, - qla4_8xxx_rd_32(ha, - QLA82XX_PEG_HALT_STATUS1), - qla4_8xxx_rd_32(ha, - QLA82XX_PEG_HALT_STATUS2), - qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + - 0x3c), - qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + - 0x3c), - qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + - 0x3c), - qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + - 0x3c), - qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + - 0x3c)); + qla4_8xxx_dump_peg_reg(ha); status = QLA_ERROR; } } else @@ -2501,6 +2491,48 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) return status; } +static void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha) +{ + uint32_t halt_status; + int halt_status_unrecoverable = 0; + + halt_status = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1); + + if (is_qla8022(ha)) { + ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n", + __func__); + qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0 | + CRB_NIU_XG_PAUSE_CTL_P1); + + if (QLA82XX_FWERROR_CODE(halt_status) == 0x67) + ql4_printk(KERN_ERR, ha, "%s: Firmware aborted with error code 0x00006700. Device is being reset\n", + __func__); + if (halt_status & HALT_STATUS_UNRECOVERABLE) + halt_status_unrecoverable = 1; + } else if (is_qla8032(ha)) { + if (halt_status & QLA83XX_HALT_STATUS_FW_RESET) + ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n", + __func__); + else if (halt_status & QLA83XX_HALT_STATUS_UNRECOVERABLE) + halt_status_unrecoverable = 1; + } + + /* + * Since we cannot change dev_state in interrupt context, + * set appropriate DPC flag then wakeup DPC + */ + if (halt_status_unrecoverable) { + set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); + } else { + ql4_printk(KERN_INFO, ha, "%s: detect abort needed!\n", + __func__); + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } + qla4xxx_mailbox_premature_completion(ha); + qla4xxx_wake_dpc(ha); +} + /** * qla4_8xxx_watchdog - Poll dev state * @ha: Pointer to host adapter structure. @@ -2509,31 +2541,33 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) **/ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) { - uint32_t dev_state, halt_status; + uint32_t dev_state; /* don't poll if reset is going on */ if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || test_bit(DPC_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) { - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE); if (qla4_8xxx_check_temp(ha)) { - ql4_printk(KERN_INFO, ha, "disabling pause" - " transmit on port 0 & 1.\n"); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, - CRB_NIU_XG_PAUSE_CTL_P0 | - CRB_NIU_XG_PAUSE_CTL_P1); + if (is_qla8022(ha)) { + ql4_printk(KERN_INFO, ha, "disabling pause transmit on port 0 & 1.\n"); + qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0 | + CRB_NIU_XG_PAUSE_CTL_P1); + } set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); qla4xxx_wake_dpc(ha); - } else if (dev_state == QLA82XX_DEV_NEED_RESET && - !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { - if (!ql4xdontresethba) { + } else if (dev_state == QLA8XXX_DEV_NEED_RESET && + !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { + if (is_qla8032(ha) || + (is_qla8022(ha) && !ql4xdontresethba)) { ql4_printk(KERN_INFO, ha, "%s: HW State: " "NEED RESET!\n", __func__); set_bit(DPC_RESET_HA, &ha->dpc_flags); qla4xxx_wake_dpc(ha); } - } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && + } else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT && !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n", __func__); @@ -2541,36 +2575,8 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) qla4xxx_wake_dpc(ha); } else { /* Check firmware health */ - if (qla4_8xxx_check_fw_alive(ha)) { - ql4_printk(KERN_INFO, ha, "disabling pause" - " transmit on port 0 & 1.\n"); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, - CRB_NIU_XG_PAUSE_CTL_P0 | - CRB_NIU_XG_PAUSE_CTL_P1); - halt_status = qla4_8xxx_rd_32(ha, - QLA82XX_PEG_HALT_STATUS1); - - if (QLA82XX_FWERROR_CODE(halt_status) == 0x67) - ql4_printk(KERN_ERR, ha, "%s:" - " Firmware aborted with" - " error code 0x00006700." - " Device is being reset\n", - __func__); - - /* Since we cannot change dev_state in interrupt - * context, set appropriate DPC flag then wakeup - * DPC */ - if (halt_status & HALT_STATUS_UNRECOVERABLE) - set_bit(DPC_HA_UNRECOVERABLE, - &ha->dpc_flags); - else { - ql4_printk(KERN_INFO, ha, "%s: detect " - "abort needed!\n", __func__); - set_bit(DPC_RESET_HA, &ha->dpc_flags); - } - qla4xxx_mailbox_premature_completion(ha); - qla4xxx_wake_dpc(ha); - } + if (qla4_8xxx_check_fw_alive(ha)) + qla4_8xxx_process_fw_error(ha); } } } @@ -2652,11 +2658,10 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) if (!pci_channel_offline(ha->pdev)) pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); - if (is_qla8022(ha)) { + if (is_qla80XX(ha)) qla4_8xxx_watchdog(ha); - } - if (!is_qla8022(ha)) { + if (is_qla40XX(ha)) { /* Check for heartbeat interval. */ if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && ha->heartbeat_interval != 0) { @@ -2941,6 +2946,14 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); + if (is_qla8032(ha) && + !test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { + ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n", + __func__); + /* disable pause frame for ISP83xx */ + qla4_83xx_disable_pause(ha); + } + iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) @@ -2953,9 +2966,9 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) goto recover_ha_init_adapter; } - /* For the ISP-82xx adapter, issue a stop_firmware if invoked + /* For the ISP-8xxx adapter, issue a stop_firmware if invoked * from eh_host_reset or ioctl module */ - if (is_qla8022(ha) && !reset_chip && + if (is_qla80XX(ha) && !reset_chip && test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { DEBUG2(ql4_printk(KERN_INFO, ha, @@ -2978,13 +2991,13 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) } /* Issue full chip reset if recovering from a catastrophic error, - * or if stop_firmware fails for ISP-82xx. + * or if stop_firmware fails for ISP-8xxx. * This is the default case for ISP-4xxx */ - if (!is_qla8022(ha) || reset_chip) { - if (!is_qla8022(ha)) + if (is_qla40XX(ha) || reset_chip) { + if (is_qla40XX(ha)) goto chip_reset; - /* Check if 82XX firmware is alive or not + /* Check if 8XXX firmware is alive or not * We may have arrived here from NEED_RESET * detection only */ if (test_bit(AF_FW_RECOVERY, &ha->flags)) @@ -3000,10 +3013,10 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ); } - +chip_reset: if (!test_bit(AF_FW_RECOVERY, &ha->flags)) qla4xxx_cmd_wait(ha); -chip_reset: + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); qla4xxx_abort_active_cmds(ha, DID_RESET << 16); DEBUG2(ql4_printk(KERN_INFO, ha, @@ -3021,7 +3034,7 @@ recover_ha_init_adapter: /* For ISP-4xxx, force function 1 to always initialize * before function 3 to prevent both funcions from * stepping on top of the other */ - if (!is_qla8022(ha) && (ha->mac_index == 3)) + if (is_qla40XX(ha) && (ha->mac_index == 3)) ssleep(6); /* NOTE: AF_ONLINE flag set upon successful completion of @@ -3039,11 +3052,12 @@ recover_ha_init_adapter: * Since we don't want to block the DPC for too long * with multiple resets in the same thread, * utilize DPC to retry */ - if (is_qla8022(ha)) { - qla4_8xxx_idc_lock(ha); - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - qla4_8xxx_idc_unlock(ha); - if (dev_state == QLA82XX_DEV_FAILED) { + if (is_qla80XX(ha)) { + ha->isp_ops->idc_lock(ha); + dev_state = qla4_8xxx_rd_direct(ha, + QLA8XXX_CRB_DEV_STATE); + ha->isp_ops->idc_unlock(ha); + if (dev_state == QLA8XXX_DEV_FAILED) { ql4_printk(KERN_INFO, ha, "%s: don't retry " "recover adapter. H/W is in Failed " "state\n", __func__); @@ -3168,6 +3182,7 @@ int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session) struct iscsi_session *sess; struct ddb_entry *ddb_entry; struct scsi_qla_host *ha; + int status = QLA_SUCCESS; sess = cls_session->dd_data; ddb_entry = sess->dd_data; @@ -3175,11 +3190,20 @@ int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session) ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" " unblock user space session\n", ha->host_no, __func__, ddb_entry->fw_ddb_index); - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); - return QLA_SUCCESS; + if (!iscsi_is_session_online(cls_session)) { + iscsi_conn_start(ddb_entry->conn); + iscsi_conn_login_event(ddb_entry->conn, + ISCSI_CONN_STATE_LOGGED_IN); + } else { + ql4_printk(KERN_INFO, ha, + "scsi%ld: %s: ddb[%d] session [%d] already logged in\n", + ha->host_no, __func__, ddb_entry->fw_ddb_index, + cls_session->sid); + status = QLA_ERROR; + } + + return status; } static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) @@ -3373,15 +3397,26 @@ static void qla4xxx_do_dpc(struct work_struct *work) /* post events to application */ qla4xxx_do_work(ha); - if (is_qla8022(ha)) { + if (is_qla80XX(ha)) { if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { - qla4_8xxx_idc_lock(ha); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - qla4_8xxx_idc_unlock(ha); + if (is_qla8032(ha)) { + ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n", + __func__); + /* disable pause frame for ISP83xx */ + qla4_83xx_disable_pause(ha); + } + + ha->isp_ops->idc_lock(ha); + qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, + QLA8XXX_DEV_FAILED); + ha->isp_ops->idc_unlock(ha); ql4_printk(KERN_INFO, ha, "HW State: FAILED\n"); qla4_8xxx_device_state_handler(ha); } + + if (test_and_clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags)) + qla4_83xx_post_idc_ack(ha); + if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { qla4_8xxx_need_qsnt_handler(ha); } @@ -3391,7 +3426,8 @@ static void qla4xxx_do_dpc(struct work_struct *work) (test_bit(DPC_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) { - if (ql4xdontresethba) { + if ((is_qla8022(ha) && ql4xdontresethba) || + (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) { DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", ha->host_no, __func__)); clear_bit(DPC_RESET_HA, &ha->dpc_flags); @@ -3477,6 +3513,18 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) ha->isp_ops->disable_intrs(ha); } + if (is_qla40XX(ha)) { + writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), + &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + } else if (is_qla8022(ha)) { + writel(0, &ha->qla4_82xx_reg->host_int); + readl(&ha->qla4_82xx_reg->host_int); + } else if (is_qla8032(ha)) { + writel(0, &ha->qla4_83xx_reg->risc_intr); + readl(&ha->qla4_83xx_reg->risc_intr); + } + /* Remove timer thread, if present */ if (ha->timer_active) qla4xxx_stop_timer(ha); @@ -3492,10 +3540,10 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) /* Put firmware in known state */ ha->isp_ops->reset_firmware(ha); - if (is_qla8022(ha)) { - qla4_8xxx_idc_lock(ha); + if (is_qla80XX(ha)) { + ha->isp_ops->idc_lock(ha); qla4_8xxx_clear_drv_active(ha); - qla4_8xxx_idc_unlock(ha); + ha->isp_ops->idc_unlock(ha); } /* Detach interrupts */ @@ -3542,16 +3590,20 @@ int qla4_8xxx_iospace_config(struct scsi_qla_host *ha) /* Mapping of IO base pointer, door bell read and write pointer */ /* mapping of IO base pointer */ - ha->qla4_8xxx_reg = - (struct device_reg_82xx __iomem *)((uint8_t *)ha->nx_pcibase + - 0xbc000 + (ha->pdev->devfn << 11)); + if (is_qla8022(ha)) { + ha->qla4_82xx_reg = (struct device_reg_82xx __iomem *) + ((uint8_t *)ha->nx_pcibase + 0xbc000 + + (ha->pdev->devfn << 11)); + ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : + QLA82XX_CAM_RAM_DB2); + } else if (is_qla8032(ha)) { + ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *) + ((uint8_t *)ha->nx_pcibase); + } db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ db_len = pci_resource_len(pdev, 4); - ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : - QLA82XX_CAM_RAM_DB2); - return 0; iospace_error_exit: return -ENOMEM; @@ -3639,23 +3691,64 @@ static struct isp_operations qla4xxx_isp_ops = { .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out, .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in, .get_sys_info = qla4xxx_get_sys_info, + .queue_mailbox_command = qla4xxx_queue_mbox_cmd, + .process_mailbox_interrupt = qla4xxx_process_mbox_intr, }; -static struct isp_operations qla4_8xxx_isp_ops = { +static struct isp_operations qla4_82xx_isp_ops = { .iospace_config = qla4_8xxx_iospace_config, .pci_config = qla4_8xxx_pci_config, - .disable_intrs = qla4_8xxx_disable_intrs, - .enable_intrs = qla4_8xxx_enable_intrs, + .disable_intrs = qla4_82xx_disable_intrs, + .enable_intrs = qla4_82xx_enable_intrs, .start_firmware = qla4_8xxx_load_risc, - .intr_handler = qla4_8xxx_intr_handler, - .interrupt_service_routine = qla4_8xxx_interrupt_service_routine, - .reset_chip = qla4_8xxx_isp_reset, + .restart_firmware = qla4_82xx_try_start_fw, + .intr_handler = qla4_82xx_intr_handler, + .interrupt_service_routine = qla4_82xx_interrupt_service_routine, + .need_reset = qla4_8xxx_need_reset, + .reset_chip = qla4_82xx_isp_reset, .reset_firmware = qla4_8xxx_stop_firmware, - .queue_iocb = qla4_8xxx_queue_iocb, - .complete_iocb = qla4_8xxx_complete_iocb, - .rd_shdw_req_q_out = qla4_8xxx_rd_shdw_req_q_out, - .rd_shdw_rsp_q_in = qla4_8xxx_rd_shdw_rsp_q_in, + .queue_iocb = qla4_82xx_queue_iocb, + .complete_iocb = qla4_82xx_complete_iocb, + .rd_shdw_req_q_out = qla4_82xx_rd_shdw_req_q_out, + .rd_shdw_rsp_q_in = qla4_82xx_rd_shdw_rsp_q_in, .get_sys_info = qla4_8xxx_get_sys_info, + .rd_reg_direct = qla4_82xx_rd_32, + .wr_reg_direct = qla4_82xx_wr_32, + .rd_reg_indirect = qla4_82xx_md_rd_32, + .wr_reg_indirect = qla4_82xx_md_wr_32, + .idc_lock = qla4_82xx_idc_lock, + .idc_unlock = qla4_82xx_idc_unlock, + .rom_lock_recovery = qla4_82xx_rom_lock_recovery, + .queue_mailbox_command = qla4_82xx_queue_mbox_cmd, + .process_mailbox_interrupt = qla4_82xx_process_mbox_intr, +}; + +static struct isp_operations qla4_83xx_isp_ops = { + .iospace_config = qla4_8xxx_iospace_config, + .pci_config = qla4_8xxx_pci_config, + .disable_intrs = qla4_83xx_disable_intrs, + .enable_intrs = qla4_83xx_enable_intrs, + .start_firmware = qla4_8xxx_load_risc, + .restart_firmware = qla4_83xx_start_firmware, + .intr_handler = qla4_83xx_intr_handler, + .interrupt_service_routine = qla4_83xx_interrupt_service_routine, + .need_reset = qla4_8xxx_need_reset, + .reset_chip = qla4_83xx_isp_reset, + .reset_firmware = qla4_8xxx_stop_firmware, + .queue_iocb = qla4_83xx_queue_iocb, + .complete_iocb = qla4_83xx_complete_iocb, + .rd_shdw_req_q_out = qla4_83xx_rd_shdw_req_q_out, + .rd_shdw_rsp_q_in = qla4_83xx_rd_shdw_rsp_q_in, + .get_sys_info = qla4_8xxx_get_sys_info, + .rd_reg_direct = qla4_83xx_rd_reg, + .wr_reg_direct = qla4_83xx_wr_reg, + .rd_reg_indirect = qla4_83xx_rd_reg_indirect, + .wr_reg_indirect = qla4_83xx_wr_reg_indirect, + .idc_lock = qla4_83xx_drv_lock, + .idc_unlock = qla4_83xx_drv_unlock, + .rom_lock_recovery = qla4_83xx_rom_lock_recovery, + .queue_mailbox_command = qla4_83xx_queue_mbox_cmd, + .process_mailbox_interrupt = qla4_83xx_process_mbox_intr, }; uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) @@ -3663,9 +3756,14 @@ uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out); } -uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) +uint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha) { - return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out)); + return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out)); +} + +uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha) +{ + return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->req_q_out)); } uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) @@ -3673,9 +3771,14 @@ uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); } -uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) +uint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) { - return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in)); + return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in)); +} + +uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) +{ + return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->rsp_q_in)); } static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) @@ -5050,30 +5153,36 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ha->pdev = pdev; ha->host = host; ha->host_no = host->host_no; + ha->func_num = PCI_FUNC(ha->pdev->devfn); pci_enable_pcie_error_reporting(pdev); /* Setup Runtime configurable options */ if (is_qla8022(ha)) { - ha->isp_ops = &qla4_8xxx_isp_ops; - rwlock_init(&ha->hw_lock); + ha->isp_ops = &qla4_82xx_isp_ops; + ha->reg_tbl = (uint32_t *) qla4_82xx_reg_tbl; ha->qdr_sn_window = -1; ha->ddr_mn_window = -1; ha->curr_window = 255; - ha->func_num = PCI_FUNC(ha->pdev->devfn); nx_legacy_intr = &legacy_intr[ha->func_num]; ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; ha->nx_legacy_intr.tgt_status_reg = nx_legacy_intr->tgt_status_reg; ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; + } else if (is_qla8032(ha)) { + ha->isp_ops = &qla4_83xx_isp_ops; + ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl; } else { ha->isp_ops = &qla4xxx_isp_ops; } - /* Set EEH reset type to fundamental if required by hba */ - if (is_qla8022(ha)) + if (is_qla80XX(ha)) { + rwlock_init(&ha->hw_lock); + ha->pf_bit = ha->func_num << 16; + /* Set EEH reset type to fundamental if required by hba */ pdev->needs_freset = 1; + } /* Configure PCI I/O space. */ ret = ha->isp_ops->iospace_config(ha); @@ -5094,6 +5203,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, init_completion(&ha->disable_acb_comp); spin_lock_init(&ha->hardware_lock); + spin_lock_init(&ha->work_lock); /* Initialize work list */ INIT_LIST_HEAD(&ha->work_list); @@ -5128,8 +5238,20 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, if (ret) goto probe_failed; - if (is_qla8022(ha)) - (void) qla4_8xxx_get_flash_info(ha); + if (is_qla80XX(ha)) + qla4_8xxx_get_flash_info(ha); + + if (is_qla8032(ha)) { + qla4_83xx_read_reset_template(ha); + /* + * NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0. + * If DONRESET_BIT0 is set, drivers should not set dev_state + * to NEED_RESET. But if NEED_RESET is set, drivers should + * should honor the reset. + */ + if (ql4xdontresethba == 1) + qla4_83xx_set_idc_dontreset(ha); + } /* * Initialize the Host adapter request/response queues and @@ -5137,14 +5259,20 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, * NOTE: interrupts enabled upon successful completion */ status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); + + /* Dont retry adapter initialization if IRQ allocation failed */ + if (!test_bit(AF_IRQ_ATTACHED, &ha->flags)) + goto skip_retry_init; + while ((!test_bit(AF_ONLINE, &ha->flags)) && init_retry_count++ < MAX_INIT_RETRIES) { - if (is_qla8022(ha)) { - qla4_8xxx_idc_lock(ha); - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - qla4_8xxx_idc_unlock(ha); - if (dev_state == QLA82XX_DEV_FAILED) { + if (is_qla80XX(ha)) { + ha->isp_ops->idc_lock(ha); + dev_state = qla4_8xxx_rd_direct(ha, + QLA82XX_CRB_DEV_STATE); + ha->isp_ops->idc_unlock(ha); + if (dev_state == QLA8XXX_DEV_FAILED) { ql4_printk(KERN_WARNING, ha, "%s: don't retry " "initialize adapter. H/W is in failed state\n", __func__); @@ -5160,16 +5288,18 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); } +skip_retry_init: if (!test_bit(AF_ONLINE, &ha->flags)) { ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); - if (is_qla8022(ha) && ql4xdontresethba) { + if ((is_qla8022(ha) && ql4xdontresethba) || + (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) { /* Put the device in failed state. */ DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n")); - qla4_8xxx_idc_lock(ha); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - qla4_8xxx_idc_unlock(ha); + ha->isp_ops->idc_lock(ha); + qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, + QLA8XXX_DEV_FAILED); + ha->isp_ops->idc_unlock(ha); } ret = -ENODEV; goto remove_host; @@ -5195,12 +5325,13 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, goto remove_host; } - /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc + /* + * For ISP-8XXX, request_irqs is called in qla4_8xxx_load_risc * (which is called indirectly by qla4xxx_initialize_adapter), * so that irqs will be registered after crbinit but before * mbx_intr_enable. */ - if (!is_qla8022(ha)) { + if (is_qla40XX(ha)) { ret = qla4xxx_request_irqs(ha); if (ret) { ql4_printk(KERN_WARNING, ha, "Failed to reserve " @@ -5226,6 +5357,10 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); + /* Set the driver version */ + if (is_qla80XX(ha)) + qla4_8xxx_set_param(ha, SET_DRVR_VERSION); + if (qla4xxx_setup_boot_info(ha)) ql4_printk(KERN_ERR, ha, "%s: No iSCSI boot target configured\n", __func__); @@ -5333,9 +5468,16 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) { struct scsi_qla_host *ha; + /* + * If the PCI device is disabled then it means probe_adapter had + * failed and resources already cleaned up on probe_adapter exit. + */ + if (!pci_is_enabled(pdev)) + return; + ha = pci_get_drvdata(pdev); - if (!is_qla8022(ha)) + if (is_qla40XX(ha)) qla4xxx_prevent_other_port_reinit(ha); /* destroy iface from sysfs */ @@ -5755,7 +5897,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) ha = to_qla_host(cmd->device->host); - if (ql4xdontresethba) { + if (is_qla8032(ha) && ql4xdontresethba) + qla4_83xx_set_idc_dontreset(ha); + + /* + * For ISP8324, if IDC_CTRL DONTRESET_BIT0 is set by other + * protocol drivers, we should not set device_state to + * NEED_RESET + */ + if (ql4xdontresethba || + (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) { DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", ha->host_no, __func__)); @@ -5779,7 +5930,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) } if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { - if (is_qla8022(ha)) + if (is_qla80XX(ha)) set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); else set_bit(DPC_RESET_HA, &ha->dpc_flags); @@ -5874,7 +6025,7 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type) break; case SCSI_FIRMWARE_RESET: if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { - if (is_qla8022(ha)) + if (is_qla80XX(ha)) /* set firmware context reset */ set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); @@ -6013,32 +6164,43 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) "0x%x is the owner\n", ha->host_no, __func__, ha->pdev->devfn); - qla4_8xxx_idc_lock(ha); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_COLD); - - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, - QLA82XX_IDC_VERSION); + ha->isp_ops->idc_lock(ha); + qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, + QLA8XXX_DEV_COLD); + ha->isp_ops->idc_unlock(ha); + + rval = qla4_8xxx_update_idc_reg(ha); + if (rval == QLA_ERROR) { + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: FAILED\n", + ha->host_no, __func__); + ha->isp_ops->idc_lock(ha); + qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, + QLA8XXX_DEV_FAILED); + ha->isp_ops->idc_unlock(ha); + goto exit_error_recovery; + } - qla4_8xxx_idc_unlock(ha); clear_bit(AF_FW_RECOVERY, &ha->flags); rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); - qla4_8xxx_idc_lock(ha); if (rval != QLA_SUCCESS) { ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " "FAILED\n", ha->host_no, __func__); + ha->isp_ops->idc_lock(ha); qla4_8xxx_clear_drv_active(ha); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); + qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, + QLA8XXX_DEV_FAILED); + ha->isp_ops->idc_unlock(ha); } else { ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " "READY\n", ha->host_no, __func__); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_READY); + ha->isp_ops->idc_lock(ha); + qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, + QLA8XXX_DEV_READY); /* Clear driver state register */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); + qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, 0); qla4_8xxx_set_drv_active(ha); + ha->isp_ops->idc_unlock(ha); ret = qla4xxx_request_irqs(ha); if (ret) { ql4_printk(KERN_WARNING, ha, "Failed to " @@ -6050,13 +6212,12 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) rval = QLA_SUCCESS; } } - qla4_8xxx_idc_unlock(ha); } else { ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not " "the reset owner\n", ha->host_no, __func__, ha->pdev->devfn); - if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == - QLA82XX_DEV_READY)) { + if ((qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE) == + QLA8XXX_DEV_READY)) { clear_bit(AF_FW_RECOVERY, &ha->flags); rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); if (rval == QLA_SUCCESS) { @@ -6071,11 +6232,12 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) rval = QLA_SUCCESS; } } - qla4_8xxx_idc_lock(ha); + ha->isp_ops->idc_lock(ha); qla4_8xxx_set_drv_active(ha); - qla4_8xxx_idc_unlock(ha); + ha->isp_ops->idc_unlock(ha); } } +exit_error_recovery: clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); return rval; } @@ -6114,7 +6276,7 @@ qla4xxx_pci_slot_reset(struct pci_dev *pdev) ha->isp_ops->disable_intrs(ha); - if (is_qla8022(ha)) { + if (is_qla80XX(ha)) { if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { ret = PCI_ERS_RESULT_RECOVERED; goto exit_slot_reset; @@ -6180,6 +6342,12 @@ static struct pci_device_id qla4xxx_pci_tbl[] = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP8324, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, {0, 0}, }; MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); |