162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver 462306a36Sopenharmony_ci * Copyright (c) 2003-2014 QLogic Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "qla_def.h" 762306a36Sopenharmony_ci#include <linux/delay.h> 862306a36Sopenharmony_ci#include <linux/ktime.h> 962306a36Sopenharmony_ci#include <linux/pci.h> 1062306a36Sopenharmony_ci#include <linux/ratelimit.h> 1162306a36Sopenharmony_ci#include <linux/vmalloc.h> 1262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 1362306a36Sopenharmony_ci#include <linux/utsname.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* QLAFX00 specific Mailbox implementation functions */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* 1962306a36Sopenharmony_ci * qlafx00_mailbox_command 2062306a36Sopenharmony_ci * Issue mailbox command and waits for completion. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Input: 2362306a36Sopenharmony_ci * ha = adapter block pointer. 2462306a36Sopenharmony_ci * mcp = driver internal mbx struct pointer. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Output: 2762306a36Sopenharmony_ci * mb[MAX_MAILBOX_REGISTER_COUNT] = returned mailbox data. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Returns: 3062306a36Sopenharmony_ci * 0 : QLA_SUCCESS = cmd performed success 3162306a36Sopenharmony_ci * 1 : QLA_FUNCTION_FAILED (error encountered) 3262306a36Sopenharmony_ci * 6 : QLA_FUNCTION_TIMEOUT (timeout condition encountered) 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * Context: 3562306a36Sopenharmony_ci * Kernel context. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistatic int 3862306a36Sopenharmony_ciqlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci int rval; 4262306a36Sopenharmony_ci unsigned long flags = 0; 4362306a36Sopenharmony_ci device_reg_t *reg; 4462306a36Sopenharmony_ci uint8_t abort_active; 4562306a36Sopenharmony_ci uint8_t io_lock_on; 4662306a36Sopenharmony_ci uint16_t command = 0; 4762306a36Sopenharmony_ci uint32_t *iptr; 4862306a36Sopenharmony_ci __le32 __iomem *optr; 4962306a36Sopenharmony_ci uint32_t cnt; 5062306a36Sopenharmony_ci uint32_t mboxes; 5162306a36Sopenharmony_ci unsigned long wait_time; 5262306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 5362306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (ha->pdev->error_state == pci_channel_io_perm_failure) { 5662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x115c, 5762306a36Sopenharmony_ci "PCI channel failed permanently, exiting.\n"); 5862306a36Sopenharmony_ci return QLA_FUNCTION_TIMEOUT; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (vha->device_flags & DFLG_DEV_FAILED) { 6262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x115f, 6362306a36Sopenharmony_ci "Device in failed state, exiting.\n"); 6462306a36Sopenharmony_ci return QLA_FUNCTION_TIMEOUT; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci reg = ha->iobase; 6862306a36Sopenharmony_ci io_lock_on = base_vha->flags.init_done; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci rval = QLA_SUCCESS; 7162306a36Sopenharmony_ci abort_active = test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (ha->flags.pci_channel_io_perm_failure) { 7462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x1175, 7562306a36Sopenharmony_ci "Perm failure on EEH timeout MBX, exiting.\n"); 7662306a36Sopenharmony_ci return QLA_FUNCTION_TIMEOUT; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (ha->flags.isp82xx_fw_hung) { 8062306a36Sopenharmony_ci /* Setting Link-Down error */ 8162306a36Sopenharmony_ci mcp->mb[0] = MBS_LINK_DOWN_ERROR; 8262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x1176, 8362306a36Sopenharmony_ci "FW hung = %d.\n", ha->flags.isp82xx_fw_hung); 8462306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 8562306a36Sopenharmony_ci goto premature_exit; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* 8962306a36Sopenharmony_ci * Wait for active mailbox commands to finish by waiting at most tov 9062306a36Sopenharmony_ci * seconds. This is to serialize actual issuing of mailbox cmds during 9162306a36Sopenharmony_ci * non ISP abort time. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, mcp->tov * HZ)) { 9462306a36Sopenharmony_ci /* Timeout occurred. Return error. */ 9562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x1177, 9662306a36Sopenharmony_ci "Cmd access timeout, cmd=0x%x, Exiting.\n", 9762306a36Sopenharmony_ci mcp->mb[0]); 9862306a36Sopenharmony_ci return QLA_FUNCTION_TIMEOUT; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ha->flags.mbox_busy = 1; 10262306a36Sopenharmony_ci /* Save mailbox command for debug */ 10362306a36Sopenharmony_ci ha->mcp32 = mcp; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x1178, 10662306a36Sopenharmony_ci "Prepare to issue mbox cmd=0x%x.\n", mcp->mb[0]); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Load mailbox registers. */ 11162306a36Sopenharmony_ci optr = ®->ispfx00.mailbox0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci iptr = mcp->mb; 11462306a36Sopenharmony_ci command = mcp->mb[0]; 11562306a36Sopenharmony_ci mboxes = mcp->out_mb; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci for (cnt = 0; cnt < ha->mbx_count; cnt++) { 11862306a36Sopenharmony_ci if (mboxes & BIT_0) 11962306a36Sopenharmony_ci wrt_reg_dword(optr, *iptr); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci mboxes >>= 1; 12262306a36Sopenharmony_ci optr++; 12362306a36Sopenharmony_ci iptr++; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* Issue set host interrupt command to send cmd out. */ 12762306a36Sopenharmony_ci ha->flags.mbox_int = 0; 12862306a36Sopenharmony_ci clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1172, 13162306a36Sopenharmony_ci (uint8_t *)mcp->mb, 16); 13262306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1173, 13362306a36Sopenharmony_ci ((uint8_t *)mcp->mb + 0x10), 16); 13462306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1174, 13562306a36Sopenharmony_ci ((uint8_t *)mcp->mb + 0x20), 8); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Unlock mbx registers and wait for interrupt */ 13862306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x1179, 13962306a36Sopenharmony_ci "Going to unlock irq & waiting for interrupts. " 14062306a36Sopenharmony_ci "jiffies=%lx.\n", jiffies); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Wait for mbx cmd completion until timeout */ 14362306a36Sopenharmony_ci if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) { 14462306a36Sopenharmony_ci set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code); 14762306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci WARN_ON_ONCE(wait_for_completion_timeout(&ha->mbx_intr_comp, 15062306a36Sopenharmony_ci mcp->tov * HZ) != 0); 15162306a36Sopenharmony_ci } else { 15262306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x112c, 15362306a36Sopenharmony_ci "Cmd=%x Polling Mode.\n", command); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code); 15662306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */ 15962306a36Sopenharmony_ci while (!ha->flags.mbox_int) { 16062306a36Sopenharmony_ci if (time_after(jiffies, wait_time)) 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* Check for pending interrupts. */ 16462306a36Sopenharmony_ci qla2x00_poll(ha->rsp_q_map[0]); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (!ha->flags.mbox_int && 16762306a36Sopenharmony_ci !(IS_QLA2200(ha) && 16862306a36Sopenharmony_ci command == MBC_LOAD_RISC_RAM_EXTENDED)) 16962306a36Sopenharmony_ci usleep_range(10000, 11000); 17062306a36Sopenharmony_ci } /* while */ 17162306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x112d, 17262306a36Sopenharmony_ci "Waited %d sec.\n", 17362306a36Sopenharmony_ci (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ)); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* Check whether we timed out */ 17762306a36Sopenharmony_ci if (ha->flags.mbox_int) { 17862306a36Sopenharmony_ci uint32_t *iptr2; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x112e, 18162306a36Sopenharmony_ci "Cmd=%x completed.\n", command); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* Got interrupt. Clear the flag. */ 18462306a36Sopenharmony_ci ha->flags.mbox_int = 0; 18562306a36Sopenharmony_ci clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (ha->mailbox_out32[0] != MBS_COMMAND_COMPLETE) 18862306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* Load return mailbox registers. */ 19162306a36Sopenharmony_ci iptr2 = mcp->mb; 19262306a36Sopenharmony_ci iptr = (uint32_t *)&ha->mailbox_out32[0]; 19362306a36Sopenharmony_ci mboxes = mcp->in_mb; 19462306a36Sopenharmony_ci for (cnt = 0; cnt < ha->mbx_count; cnt++) { 19562306a36Sopenharmony_ci if (mboxes & BIT_0) 19662306a36Sopenharmony_ci *iptr2 = *iptr; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci mboxes >>= 1; 19962306a36Sopenharmony_ci iptr2++; 20062306a36Sopenharmony_ci iptr++; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci } else { 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci rval = QLA_FUNCTION_TIMEOUT; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci ha->flags.mbox_busy = 0; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Clean up */ 21062306a36Sopenharmony_ci ha->mcp32 = NULL; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) { 21362306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x113a, 21462306a36Sopenharmony_ci "checking for additional resp interrupt.\n"); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* polling mode for non isp_abort commands. */ 21762306a36Sopenharmony_ci qla2x00_poll(ha->rsp_q_map[0]); 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (rval == QLA_FUNCTION_TIMEOUT && 22162306a36Sopenharmony_ci mcp->mb[0] != MBC_GEN_SYSTEM_ERROR) { 22262306a36Sopenharmony_ci if (!io_lock_on || (mcp->flags & IOCTL_CMD) || 22362306a36Sopenharmony_ci ha->flags.eeh_busy) { 22462306a36Sopenharmony_ci /* not in dpc. schedule it for dpc to take over. */ 22562306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x115d, 22662306a36Sopenharmony_ci "Timeout, schedule isp_abort_needed.\n"); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && 22962306a36Sopenharmony_ci !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && 23062306a36Sopenharmony_ci !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0x115e, 23362306a36Sopenharmony_ci "Mailbox cmd timeout occurred, cmd=0x%x, " 23462306a36Sopenharmony_ci "mb[0]=0x%x, eeh_busy=0x%x. Scheduling ISP " 23562306a36Sopenharmony_ci "abort.\n", command, mcp->mb[0], 23662306a36Sopenharmony_ci ha->flags.eeh_busy); 23762306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 23862306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci } else if (!abort_active) { 24162306a36Sopenharmony_ci /* call abort directly since we are in the DPC thread */ 24262306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x1160, 24362306a36Sopenharmony_ci "Timeout, calling abort_isp.\n"); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && 24662306a36Sopenharmony_ci !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && 24762306a36Sopenharmony_ci !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0x1161, 25062306a36Sopenharmony_ci "Mailbox cmd timeout occurred, cmd=0x%x, " 25162306a36Sopenharmony_ci "mb[0]=0x%x. Scheduling ISP abort ", 25262306a36Sopenharmony_ci command, mcp->mb[0]); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); 25562306a36Sopenharmony_ci clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 25662306a36Sopenharmony_ci if (ha->isp_ops->abort_isp(vha)) { 25762306a36Sopenharmony_ci /* Failed. retry later. */ 25862306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 25962306a36Sopenharmony_ci &vha->dpc_flags); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); 26262306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x1162, 26362306a36Sopenharmony_ci "Finished abort_isp.\n"); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cipremature_exit: 26962306a36Sopenharmony_ci /* Allow next mbx cmd to come in. */ 27062306a36Sopenharmony_ci complete(&ha->mbx_cmd_comp); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (rval) { 27362306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x1163, 27462306a36Sopenharmony_ci "**** Failed=%x mbx[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x, cmd=%x ****.\n", 27562306a36Sopenharmony_ci rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], 27662306a36Sopenharmony_ci command); 27762306a36Sopenharmony_ci } else { 27862306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, base_vha, 0x1164, "Done %s.\n", __func__); 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return rval; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/* 28562306a36Sopenharmony_ci * qlafx00_driver_shutdown 28662306a36Sopenharmony_ci * Indicate a driver shutdown to firmware. 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci * Input: 28962306a36Sopenharmony_ci * ha = adapter block pointer. 29062306a36Sopenharmony_ci * 29162306a36Sopenharmony_ci * Returns: 29262306a36Sopenharmony_ci * local function return status code. 29362306a36Sopenharmony_ci * 29462306a36Sopenharmony_ci * Context: 29562306a36Sopenharmony_ci * Kernel context. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ciint 29862306a36Sopenharmony_ciqlafx00_driver_shutdown(scsi_qla_host_t *vha, int tmo) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci int rval; 30162306a36Sopenharmony_ci struct mbx_cmd_32 mc; 30262306a36Sopenharmony_ci struct mbx_cmd_32 *mcp = &mc; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1166, 30562306a36Sopenharmony_ci "Entered %s.\n", __func__); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci mcp->mb[0] = MBC_MR_DRV_SHUTDOWN; 30862306a36Sopenharmony_ci mcp->out_mb = MBX_0; 30962306a36Sopenharmony_ci mcp->in_mb = MBX_0; 31062306a36Sopenharmony_ci if (tmo) 31162306a36Sopenharmony_ci mcp->tov = tmo; 31262306a36Sopenharmony_ci else 31362306a36Sopenharmony_ci mcp->tov = MBX_TOV_SECONDS; 31462306a36Sopenharmony_ci mcp->flags = 0; 31562306a36Sopenharmony_ci rval = qlafx00_mailbox_command(vha, mcp); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 31862306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x1167, 31962306a36Sopenharmony_ci "Failed=%x.\n", rval); 32062306a36Sopenharmony_ci } else { 32162306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1168, 32262306a36Sopenharmony_ci "Done %s.\n", __func__); 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return rval; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/* 32962306a36Sopenharmony_ci * qlafx00_get_firmware_state 33062306a36Sopenharmony_ci * Get adapter firmware state. 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci * Input: 33362306a36Sopenharmony_ci * ha = adapter block pointer. 33462306a36Sopenharmony_ci * TARGET_QUEUE_LOCK must be released. 33562306a36Sopenharmony_ci * ADAPTER_STATE_LOCK must be released. 33662306a36Sopenharmony_ci * 33762306a36Sopenharmony_ci * Returns: 33862306a36Sopenharmony_ci * qla7xxx local function return status code. 33962306a36Sopenharmony_ci * 34062306a36Sopenharmony_ci * Context: 34162306a36Sopenharmony_ci * Kernel context. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_cistatic int 34462306a36Sopenharmony_ciqlafx00_get_firmware_state(scsi_qla_host_t *vha, uint32_t *states) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci int rval; 34762306a36Sopenharmony_ci struct mbx_cmd_32 mc; 34862306a36Sopenharmony_ci struct mbx_cmd_32 *mcp = &mc; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1169, 35162306a36Sopenharmony_ci "Entered %s.\n", __func__); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci mcp->mb[0] = MBC_GET_FIRMWARE_STATE; 35462306a36Sopenharmony_ci mcp->out_mb = MBX_0; 35562306a36Sopenharmony_ci mcp->in_mb = MBX_1|MBX_0; 35662306a36Sopenharmony_ci mcp->tov = MBX_TOV_SECONDS; 35762306a36Sopenharmony_ci mcp->flags = 0; 35862306a36Sopenharmony_ci rval = qlafx00_mailbox_command(vha, mcp); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* Return firmware states. */ 36162306a36Sopenharmony_ci states[0] = mcp->mb[1]; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 36462306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x116a, 36562306a36Sopenharmony_ci "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); 36662306a36Sopenharmony_ci } else { 36762306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116b, 36862306a36Sopenharmony_ci "Done %s.\n", __func__); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci return rval; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/* 37462306a36Sopenharmony_ci * qlafx00_init_firmware 37562306a36Sopenharmony_ci * Initialize adapter firmware. 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * Input: 37862306a36Sopenharmony_ci * ha = adapter block pointer. 37962306a36Sopenharmony_ci * dptr = Initialization control block pointer. 38062306a36Sopenharmony_ci * size = size of initialization control block. 38162306a36Sopenharmony_ci * TARGET_QUEUE_LOCK must be released. 38262306a36Sopenharmony_ci * ADAPTER_STATE_LOCK must be released. 38362306a36Sopenharmony_ci * 38462306a36Sopenharmony_ci * Returns: 38562306a36Sopenharmony_ci * qlafx00 local function return status code. 38662306a36Sopenharmony_ci * 38762306a36Sopenharmony_ci * Context: 38862306a36Sopenharmony_ci * Kernel context. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ciint 39162306a36Sopenharmony_ciqlafx00_init_firmware(scsi_qla_host_t *vha, uint16_t size) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci int rval; 39462306a36Sopenharmony_ci struct mbx_cmd_32 mc; 39562306a36Sopenharmony_ci struct mbx_cmd_32 *mcp = &mc; 39662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116c, 39962306a36Sopenharmony_ci "Entered %s.\n", __func__); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci mcp->mb[1] = 0; 40462306a36Sopenharmony_ci mcp->mb[2] = MSD(ha->init_cb_dma); 40562306a36Sopenharmony_ci mcp->mb[3] = LSD(ha->init_cb_dma); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; 40862306a36Sopenharmony_ci mcp->in_mb = MBX_0; 40962306a36Sopenharmony_ci mcp->buf_size = size; 41062306a36Sopenharmony_ci mcp->flags = MBX_DMA_OUT; 41162306a36Sopenharmony_ci mcp->tov = MBX_TOV_SECONDS; 41262306a36Sopenharmony_ci rval = qlafx00_mailbox_command(vha, mcp); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 41562306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x116d, 41662306a36Sopenharmony_ci "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); 41762306a36Sopenharmony_ci } else { 41862306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116e, 41962306a36Sopenharmony_ci "Done %s.\n", __func__); 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci return rval; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci/* 42562306a36Sopenharmony_ci * qlafx00_mbx_reg_test 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_cistatic int 42862306a36Sopenharmony_ciqlafx00_mbx_reg_test(scsi_qla_host_t *vha) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci int rval; 43162306a36Sopenharmony_ci struct mbx_cmd_32 mc; 43262306a36Sopenharmony_ci struct mbx_cmd_32 *mcp = &mc; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116f, 43562306a36Sopenharmony_ci "Entered %s.\n", __func__); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST; 43962306a36Sopenharmony_ci mcp->mb[1] = 0xAAAA; 44062306a36Sopenharmony_ci mcp->mb[2] = 0x5555; 44162306a36Sopenharmony_ci mcp->mb[3] = 0xAA55; 44262306a36Sopenharmony_ci mcp->mb[4] = 0x55AA; 44362306a36Sopenharmony_ci mcp->mb[5] = 0xA5A5; 44462306a36Sopenharmony_ci mcp->mb[6] = 0x5A5A; 44562306a36Sopenharmony_ci mcp->mb[7] = 0x2525; 44662306a36Sopenharmony_ci mcp->mb[8] = 0xBBBB; 44762306a36Sopenharmony_ci mcp->mb[9] = 0x6666; 44862306a36Sopenharmony_ci mcp->mb[10] = 0xBB66; 44962306a36Sopenharmony_ci mcp->mb[11] = 0x66BB; 45062306a36Sopenharmony_ci mcp->mb[12] = 0xB6B6; 45162306a36Sopenharmony_ci mcp->mb[13] = 0x6B6B; 45262306a36Sopenharmony_ci mcp->mb[14] = 0x3636; 45362306a36Sopenharmony_ci mcp->mb[15] = 0xCCCC; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci mcp->out_mb = MBX_15|MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8| 45762306a36Sopenharmony_ci MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; 45862306a36Sopenharmony_ci mcp->in_mb = MBX_15|MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8| 45962306a36Sopenharmony_ci MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; 46062306a36Sopenharmony_ci mcp->buf_size = 0; 46162306a36Sopenharmony_ci mcp->flags = MBX_DMA_OUT; 46262306a36Sopenharmony_ci mcp->tov = MBX_TOV_SECONDS; 46362306a36Sopenharmony_ci rval = qlafx00_mailbox_command(vha, mcp); 46462306a36Sopenharmony_ci if (rval == QLA_SUCCESS) { 46562306a36Sopenharmony_ci if (mcp->mb[17] != 0xAAAA || mcp->mb[18] != 0x5555 || 46662306a36Sopenharmony_ci mcp->mb[19] != 0xAA55 || mcp->mb[20] != 0x55AA) 46762306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 46862306a36Sopenharmony_ci if (mcp->mb[21] != 0xA5A5 || mcp->mb[22] != 0x5A5A || 46962306a36Sopenharmony_ci mcp->mb[23] != 0x2525 || mcp->mb[24] != 0xBBBB) 47062306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 47162306a36Sopenharmony_ci if (mcp->mb[25] != 0x6666 || mcp->mb[26] != 0xBB66 || 47262306a36Sopenharmony_ci mcp->mb[27] != 0x66BB || mcp->mb[28] != 0xB6B6) 47362306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 47462306a36Sopenharmony_ci if (mcp->mb[29] != 0x6B6B || mcp->mb[30] != 0x3636 || 47562306a36Sopenharmony_ci mcp->mb[31] != 0xCCCC) 47662306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 48062306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x1170, 48162306a36Sopenharmony_ci "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); 48262306a36Sopenharmony_ci } else { 48362306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1171, 48462306a36Sopenharmony_ci "Done %s.\n", __func__); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci return rval; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci/** 49062306a36Sopenharmony_ci * qlafx00_pci_config() - Setup ISPFx00 PCI configuration registers. 49162306a36Sopenharmony_ci * @vha: HA context 49262306a36Sopenharmony_ci * 49362306a36Sopenharmony_ci * Returns 0 on success. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ciint 49662306a36Sopenharmony_ciqlafx00_pci_config(scsi_qla_host_t *vha) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci uint16_t w; 49962306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci pci_set_master(ha->pdev); 50262306a36Sopenharmony_ci pci_try_set_mwi(ha->pdev); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci pci_read_config_word(ha->pdev, PCI_COMMAND, &w); 50562306a36Sopenharmony_ci w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); 50662306a36Sopenharmony_ci w &= ~PCI_COMMAND_INTX_DISABLE; 50762306a36Sopenharmony_ci pci_write_config_word(ha->pdev, PCI_COMMAND, w); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* PCIe -- adjust Maximum Read Request Size (2048). */ 51062306a36Sopenharmony_ci if (pci_is_pcie(ha->pdev)) 51162306a36Sopenharmony_ci pcie_set_readrq(ha->pdev, 2048); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci ha->chip_revision = ha->pdev->revision; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci return QLA_SUCCESS; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci/** 51962306a36Sopenharmony_ci * qlafx00_soc_cpu_reset() - Perform warm reset of iSA(CPUs being reset on SOC). 52062306a36Sopenharmony_ci * @vha: HA context 52162306a36Sopenharmony_ci * 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_cistatic inline void 52462306a36Sopenharmony_ciqlafx00_soc_cpu_reset(scsi_qla_host_t *vha) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci unsigned long flags = 0; 52762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 52862306a36Sopenharmony_ci int i, core; 52962306a36Sopenharmony_ci uint32_t cnt; 53062306a36Sopenharmony_ci uint32_t reg_val; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0x80004, 0); 53562306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0x82004, 0); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* stop the XOR DMA engines */ 53862306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0x60920, 0x02); 53962306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0x60924, 0x02); 54062306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0xf0920, 0x02); 54162306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0xf0924, 0x02); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* stop the IDMA engines */ 54462306a36Sopenharmony_ci reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x60840); 54562306a36Sopenharmony_ci reg_val &= ~(1<<12); 54662306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0x60840, reg_val); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x60844); 54962306a36Sopenharmony_ci reg_val &= ~(1<<12); 55062306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0x60844, reg_val); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x60848); 55362306a36Sopenharmony_ci reg_val &= ~(1<<12); 55462306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0x60848, reg_val); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x6084C); 55762306a36Sopenharmony_ci reg_val &= ~(1<<12); 55862306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0x6084C, reg_val); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci for (i = 0; i < 100000; i++) { 56162306a36Sopenharmony_ci if ((QLAFX00_GET_HBA_SOC_REG(ha, 0xd0000) & 0x10000000) == 0 && 56262306a36Sopenharmony_ci (QLAFX00_GET_HBA_SOC_REG(ha, 0x10600) & 0x1) == 0) 56362306a36Sopenharmony_ci break; 56462306a36Sopenharmony_ci udelay(100); 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* Set all 4 cores in reset */ 56862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 56962306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 57062306a36Sopenharmony_ci (SOC_SW_RST_CONTROL_REG_CORE0 + 8*i), (0xF01)); 57162306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 57262306a36Sopenharmony_ci (SOC_SW_RST_CONTROL_REG_CORE0 + 4 + 8*i), (0x01010101)); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Reset all units in Fabric */ 57662306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_RST_CONTROL_REG, (0x011f0101)); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* */ 57962306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0x10610, 1); 58062306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 0x10600, 0); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* Set all 4 core Memory Power Down Registers */ 58362306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 58462306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 58562306a36Sopenharmony_ci (SOC_PWR_MANAGEMENT_PWR_DOWN_REG + 4*i), (0x0)); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* Reset all interrupt control registers */ 58962306a36Sopenharmony_ci for (i = 0; i < 115; i++) { 59062306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 59162306a36Sopenharmony_ci (SOC_INTERRUPT_SOURCE_I_CONTROL_REG + 4*i), (0x0)); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* Reset Timers control registers. per core */ 59562306a36Sopenharmony_ci for (core = 0; core < 4; core++) 59662306a36Sopenharmony_ci for (i = 0; i < 8; i++) 59762306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 59862306a36Sopenharmony_ci (SOC_CORE_TIMER_REG + 0x100*core + 4*i), (0x0)); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* Reset per core IRQ ack register */ 60162306a36Sopenharmony_ci for (core = 0; core < 4; core++) 60262306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, 60362306a36Sopenharmony_ci (SOC_IRQ_ACK_REG + 0x100*core), (0x3FF)); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* Set Fabric control and config to defaults */ 60662306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_CONTROL_REG, (0x2)); 60762306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_CONFIG_REG, (0x3)); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* Kick in Fabric units */ 61062306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_RST_CONTROL_REG, (0x0)); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* Kick in Core0 to start boot process */ 61362306a36Sopenharmony_ci QLAFX00_SET_HBA_SOC_REG(ha, SOC_SW_RST_CONTROL_REG_CORE0, (0xF00)); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* Wait 10secs for soft-reset to complete. */ 61862306a36Sopenharmony_ci for (cnt = 10; cnt; cnt--) { 61962306a36Sopenharmony_ci msleep(1000); 62062306a36Sopenharmony_ci barrier(); 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci/** 62562306a36Sopenharmony_ci * qlafx00_soft_reset() - Soft Reset ISPFx00. 62662306a36Sopenharmony_ci * @vha: HA context 62762306a36Sopenharmony_ci * 62862306a36Sopenharmony_ci * Returns 0 on success. 62962306a36Sopenharmony_ci */ 63062306a36Sopenharmony_ciint 63162306a36Sopenharmony_ciqlafx00_soft_reset(scsi_qla_host_t *vha) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 63462306a36Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev) && 63762306a36Sopenharmony_ci ha->flags.pci_channel_io_perm_failure)) 63862306a36Sopenharmony_ci return rval; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ha->isp_ops->disable_intrs(ha); 64162306a36Sopenharmony_ci qlafx00_soc_cpu_reset(vha); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return QLA_SUCCESS; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci/** 64762306a36Sopenharmony_ci * qlafx00_chip_diag() - Test ISPFx00 for proper operation. 64862306a36Sopenharmony_ci * @vha: HA context 64962306a36Sopenharmony_ci * 65062306a36Sopenharmony_ci * Returns 0 on success. 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ciint 65362306a36Sopenharmony_ciqlafx00_chip_diag(scsi_qla_host_t *vha) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci int rval = 0; 65662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 65762306a36Sopenharmony_ci struct req_que *req = ha->req_q_map[0]; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci rval = qlafx00_mbx_reg_test(vha); 66262306a36Sopenharmony_ci if (rval) { 66362306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x1165, 66462306a36Sopenharmony_ci "Failed mailbox send register test\n"); 66562306a36Sopenharmony_ci } else { 66662306a36Sopenharmony_ci /* Flag a successful rval */ 66762306a36Sopenharmony_ci rval = QLA_SUCCESS; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci return rval; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_civoid 67362306a36Sopenharmony_ciqlafx00_config_rings(struct scsi_qla_host *vha) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 67662306a36Sopenharmony_ci struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci wrt_reg_dword(®->req_q_in, 0); 67962306a36Sopenharmony_ci wrt_reg_dword(®->req_q_out, 0); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci wrt_reg_dword(®->rsp_q_in, 0); 68262306a36Sopenharmony_ci wrt_reg_dword(®->rsp_q_out, 0); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* PCI posting */ 68562306a36Sopenharmony_ci rd_reg_dword(®->rsp_q_out); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cichar * 68962306a36Sopenharmony_ciqlafx00_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (pci_is_pcie(ha->pdev)) 69462306a36Sopenharmony_ci strscpy(str, "PCIe iSA", str_len); 69562306a36Sopenharmony_ci return str; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cichar * 69962306a36Sopenharmony_ciqlafx00_fw_version_str(struct scsi_qla_host *vha, char *str, size_t size) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci snprintf(str, size, "%s", ha->mr.fw_version); 70462306a36Sopenharmony_ci return str; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_civoid 70862306a36Sopenharmony_ciqlafx00_enable_intrs(struct qla_hw_data *ha) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci unsigned long flags = 0; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 71362306a36Sopenharmony_ci ha->interrupts_on = 1; 71462306a36Sopenharmony_ci QLAFX00_ENABLE_ICNTRL_REG(ha); 71562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_civoid 71962306a36Sopenharmony_ciqlafx00_disable_intrs(struct qla_hw_data *ha) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci unsigned long flags = 0; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 72462306a36Sopenharmony_ci ha->interrupts_on = 0; 72562306a36Sopenharmony_ci QLAFX00_DISABLE_ICNTRL_REG(ha); 72662306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ciint 73062306a36Sopenharmony_ciqlafx00_abort_target(fc_port_t *fcport, uint64_t l, int tag) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag); 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ciint 73662306a36Sopenharmony_ciqlafx00_lun_reset(fc_port_t *fcport, uint64_t l, int tag) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ciint 74262306a36Sopenharmony_ciqlafx00_iospace_config(struct qla_hw_data *ha) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci if (pci_request_selected_regions(ha->pdev, ha->bars, 74562306a36Sopenharmony_ci QLA2XXX_DRIVER_NAME)) { 74662306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x014e, 74762306a36Sopenharmony_ci "Failed to reserve PIO/MMIO regions (%s), aborting.\n", 74862306a36Sopenharmony_ci pci_name(ha->pdev)); 74962306a36Sopenharmony_ci goto iospace_error_exit; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* Use MMIO operations for all accesses. */ 75362306a36Sopenharmony_ci if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) { 75462306a36Sopenharmony_ci ql_log_pci(ql_log_warn, ha->pdev, 0x014f, 75562306a36Sopenharmony_ci "Invalid pci I/O region size (%s).\n", 75662306a36Sopenharmony_ci pci_name(ha->pdev)); 75762306a36Sopenharmony_ci goto iospace_error_exit; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci if (pci_resource_len(ha->pdev, 0) < BAR0_LEN_FX00) { 76062306a36Sopenharmony_ci ql_log_pci(ql_log_warn, ha->pdev, 0x0127, 76162306a36Sopenharmony_ci "Invalid PCI mem BAR0 region size (%s), aborting\n", 76262306a36Sopenharmony_ci pci_name(ha->pdev)); 76362306a36Sopenharmony_ci goto iospace_error_exit; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci ha->cregbase = 76762306a36Sopenharmony_ci ioremap(pci_resource_start(ha->pdev, 0), BAR0_LEN_FX00); 76862306a36Sopenharmony_ci if (!ha->cregbase) { 76962306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0128, 77062306a36Sopenharmony_ci "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev)); 77162306a36Sopenharmony_ci goto iospace_error_exit; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (!(pci_resource_flags(ha->pdev, 2) & IORESOURCE_MEM)) { 77562306a36Sopenharmony_ci ql_log_pci(ql_log_warn, ha->pdev, 0x0129, 77662306a36Sopenharmony_ci "region #2 not an MMIO resource (%s), aborting\n", 77762306a36Sopenharmony_ci pci_name(ha->pdev)); 77862306a36Sopenharmony_ci goto iospace_error_exit; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci if (pci_resource_len(ha->pdev, 2) < BAR2_LEN_FX00) { 78162306a36Sopenharmony_ci ql_log_pci(ql_log_warn, ha->pdev, 0x012a, 78262306a36Sopenharmony_ci "Invalid PCI mem BAR2 region size (%s), aborting\n", 78362306a36Sopenharmony_ci pci_name(ha->pdev)); 78462306a36Sopenharmony_ci goto iospace_error_exit; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci ha->iobase = 78862306a36Sopenharmony_ci ioremap(pci_resource_start(ha->pdev, 2), BAR2_LEN_FX00); 78962306a36Sopenharmony_ci if (!ha->iobase) { 79062306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x012b, 79162306a36Sopenharmony_ci "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev)); 79262306a36Sopenharmony_ci goto iospace_error_exit; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci /* Determine queue resources */ 79662306a36Sopenharmony_ci ha->max_req_queues = ha->max_rsp_queues = 1; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci ql_log_pci(ql_log_info, ha->pdev, 0x012c, 79962306a36Sopenharmony_ci "Bars 0x%x, iobase0 0x%p, iobase2 0x%p\n", 80062306a36Sopenharmony_ci ha->bars, ha->cregbase, ha->iobase); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return 0; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ciiospace_error_exit: 80562306a36Sopenharmony_ci return -ENOMEM; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic void 80962306a36Sopenharmony_ciqlafx00_save_queue_ptrs(struct scsi_qla_host *vha) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 81262306a36Sopenharmony_ci struct req_que *req = ha->req_q_map[0]; 81362306a36Sopenharmony_ci struct rsp_que *rsp = ha->rsp_q_map[0]; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci req->length_fx00 = req->length; 81662306a36Sopenharmony_ci req->ring_fx00 = req->ring; 81762306a36Sopenharmony_ci req->dma_fx00 = req->dma; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci rsp->length_fx00 = rsp->length; 82062306a36Sopenharmony_ci rsp->ring_fx00 = rsp->ring; 82162306a36Sopenharmony_ci rsp->dma_fx00 = rsp->dma; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x012d, 82462306a36Sopenharmony_ci "req: %p, ring_fx00: %p, length_fx00: 0x%x," 82562306a36Sopenharmony_ci "req->dma_fx00: 0x%llx\n", req, req->ring_fx00, 82662306a36Sopenharmony_ci req->length_fx00, (u64)req->dma_fx00); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x012e, 82962306a36Sopenharmony_ci "rsp: %p, ring_fx00: %p, length_fx00: 0x%x," 83062306a36Sopenharmony_ci "rsp->dma_fx00: 0x%llx\n", rsp, rsp->ring_fx00, 83162306a36Sopenharmony_ci rsp->length_fx00, (u64)rsp->dma_fx00); 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic int 83562306a36Sopenharmony_ciqlafx00_config_queues(struct scsi_qla_host *vha) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 83862306a36Sopenharmony_ci struct req_que *req = ha->req_q_map[0]; 83962306a36Sopenharmony_ci struct rsp_que *rsp = ha->rsp_q_map[0]; 84062306a36Sopenharmony_ci dma_addr_t bar2_hdl = pci_resource_start(ha->pdev, 2); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci req->length = ha->req_que_len; 84362306a36Sopenharmony_ci req->ring = (void __force *)ha->iobase + ha->req_que_off; 84462306a36Sopenharmony_ci req->dma = bar2_hdl + ha->req_que_off; 84562306a36Sopenharmony_ci if ((!req->ring) || (req->length == 0)) { 84662306a36Sopenharmony_ci ql_log_pci(ql_log_info, ha->pdev, 0x012f, 84762306a36Sopenharmony_ci "Unable to allocate memory for req_ring\n"); 84862306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0130, 85262306a36Sopenharmony_ci "req: %p req_ring pointer %p req len 0x%x " 85362306a36Sopenharmony_ci "req off 0x%x\n, req->dma: 0x%llx", 85462306a36Sopenharmony_ci req, req->ring, req->length, 85562306a36Sopenharmony_ci ha->req_que_off, (u64)req->dma); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci rsp->length = ha->rsp_que_len; 85862306a36Sopenharmony_ci rsp->ring = (void __force *)ha->iobase + ha->rsp_que_off; 85962306a36Sopenharmony_ci rsp->dma = bar2_hdl + ha->rsp_que_off; 86062306a36Sopenharmony_ci if ((!rsp->ring) || (rsp->length == 0)) { 86162306a36Sopenharmony_ci ql_log_pci(ql_log_info, ha->pdev, 0x0131, 86262306a36Sopenharmony_ci "Unable to allocate memory for rsp_ring\n"); 86362306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0132, 86762306a36Sopenharmony_ci "rsp: %p rsp_ring pointer %p rsp len 0x%x " 86862306a36Sopenharmony_ci "rsp off 0x%x, rsp->dma: 0x%llx\n", 86962306a36Sopenharmony_ci rsp, rsp->ring, rsp->length, 87062306a36Sopenharmony_ci ha->rsp_que_off, (u64)rsp->dma); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return QLA_SUCCESS; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic int 87662306a36Sopenharmony_ciqlafx00_init_fw_ready(scsi_qla_host_t *vha) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci int rval = 0; 87962306a36Sopenharmony_ci unsigned long wtime; 88062306a36Sopenharmony_ci uint16_t wait_time; /* Wait time */ 88162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 88262306a36Sopenharmony_ci struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00; 88362306a36Sopenharmony_ci uint32_t aenmbx, aenmbx7 = 0; 88462306a36Sopenharmony_ci uint32_t pseudo_aen; 88562306a36Sopenharmony_ci uint32_t state[5]; 88662306a36Sopenharmony_ci bool done = false; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* 30 seconds wait - Adjust if required */ 88962306a36Sopenharmony_ci wait_time = 30; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci pseudo_aen = rd_reg_dword(®->pseudoaen); 89262306a36Sopenharmony_ci if (pseudo_aen == 1) { 89362306a36Sopenharmony_ci aenmbx7 = rd_reg_dword(®->initval7); 89462306a36Sopenharmony_ci ha->mbx_intr_code = MSW(aenmbx7); 89562306a36Sopenharmony_ci ha->rqstq_intr_code = LSW(aenmbx7); 89662306a36Sopenharmony_ci rval = qlafx00_driver_shutdown(vha, 10); 89762306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 89862306a36Sopenharmony_ci qlafx00_soft_reset(vha); 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* wait time before firmware ready */ 90262306a36Sopenharmony_ci wtime = jiffies + (wait_time * HZ); 90362306a36Sopenharmony_ci do { 90462306a36Sopenharmony_ci aenmbx = rd_reg_dword(®->aenmailbox0); 90562306a36Sopenharmony_ci barrier(); 90662306a36Sopenharmony_ci ql_dbg(ql_dbg_mbx, vha, 0x0133, 90762306a36Sopenharmony_ci "aenmbx: 0x%x\n", aenmbx); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci switch (aenmbx) { 91062306a36Sopenharmony_ci case MBA_FW_NOT_STARTED: 91162306a36Sopenharmony_ci case MBA_FW_STARTING: 91262306a36Sopenharmony_ci break; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci case MBA_SYSTEM_ERR: 91562306a36Sopenharmony_ci case MBA_REQ_TRANSFER_ERR: 91662306a36Sopenharmony_ci case MBA_RSP_TRANSFER_ERR: 91762306a36Sopenharmony_ci case MBA_FW_INIT_FAILURE: 91862306a36Sopenharmony_ci qlafx00_soft_reset(vha); 91962306a36Sopenharmony_ci break; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci case MBA_FW_RESTART_CMPLT: 92262306a36Sopenharmony_ci /* Set the mbx and rqstq intr code */ 92362306a36Sopenharmony_ci aenmbx7 = rd_reg_dword(®->aenmailbox7); 92462306a36Sopenharmony_ci ha->mbx_intr_code = MSW(aenmbx7); 92562306a36Sopenharmony_ci ha->rqstq_intr_code = LSW(aenmbx7); 92662306a36Sopenharmony_ci ha->req_que_off = rd_reg_dword(®->aenmailbox1); 92762306a36Sopenharmony_ci ha->rsp_que_off = rd_reg_dword(®->aenmailbox3); 92862306a36Sopenharmony_ci ha->req_que_len = rd_reg_dword(®->aenmailbox5); 92962306a36Sopenharmony_ci ha->rsp_que_len = rd_reg_dword(®->aenmailbox6); 93062306a36Sopenharmony_ci wrt_reg_dword(®->aenmailbox0, 0); 93162306a36Sopenharmony_ci rd_reg_dword_relaxed(®->aenmailbox0); 93262306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0134, 93362306a36Sopenharmony_ci "f/w returned mbx_intr_code: 0x%x, " 93462306a36Sopenharmony_ci "rqstq_intr_code: 0x%x\n", 93562306a36Sopenharmony_ci ha->mbx_intr_code, ha->rqstq_intr_code); 93662306a36Sopenharmony_ci QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS); 93762306a36Sopenharmony_ci rval = QLA_SUCCESS; 93862306a36Sopenharmony_ci done = true; 93962306a36Sopenharmony_ci break; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci default: 94262306a36Sopenharmony_ci if ((aenmbx & 0xFF00) == MBA_FW_INIT_INPROGRESS) 94362306a36Sopenharmony_ci break; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* If fw is apparently not ready. In order to continue, 94662306a36Sopenharmony_ci * we might need to issue Mbox cmd, but the problem is 94762306a36Sopenharmony_ci * that the DoorBell vector values that come with the 94862306a36Sopenharmony_ci * 8060 AEN are most likely gone by now (and thus no 94962306a36Sopenharmony_ci * bell would be rung on the fw side when mbox cmd is 95062306a36Sopenharmony_ci * issued). We have to therefore grab the 8060 AEN 95162306a36Sopenharmony_ci * shadow regs (filled in by FW when the last 8060 95262306a36Sopenharmony_ci * AEN was being posted). 95362306a36Sopenharmony_ci * Do the following to determine what is needed in 95462306a36Sopenharmony_ci * order to get the FW ready: 95562306a36Sopenharmony_ci * 1. reload the 8060 AEN values from the shadow regs 95662306a36Sopenharmony_ci * 2. clear int status to get rid of possible pending 95762306a36Sopenharmony_ci * interrupts 95862306a36Sopenharmony_ci * 3. issue Get FW State Mbox cmd to determine fw state 95962306a36Sopenharmony_ci * Set the mbx and rqstq intr code from Shadow Regs 96062306a36Sopenharmony_ci */ 96162306a36Sopenharmony_ci aenmbx7 = rd_reg_dword(®->initval7); 96262306a36Sopenharmony_ci ha->mbx_intr_code = MSW(aenmbx7); 96362306a36Sopenharmony_ci ha->rqstq_intr_code = LSW(aenmbx7); 96462306a36Sopenharmony_ci ha->req_que_off = rd_reg_dword(®->initval1); 96562306a36Sopenharmony_ci ha->rsp_que_off = rd_reg_dword(®->initval3); 96662306a36Sopenharmony_ci ha->req_que_len = rd_reg_dword(®->initval5); 96762306a36Sopenharmony_ci ha->rsp_que_len = rd_reg_dword(®->initval6); 96862306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0135, 96962306a36Sopenharmony_ci "f/w returned mbx_intr_code: 0x%x, " 97062306a36Sopenharmony_ci "rqstq_intr_code: 0x%x\n", 97162306a36Sopenharmony_ci ha->mbx_intr_code, ha->rqstq_intr_code); 97262306a36Sopenharmony_ci QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci /* Get the FW state */ 97562306a36Sopenharmony_ci rval = qlafx00_get_firmware_state(vha, state); 97662306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 97762306a36Sopenharmony_ci /* Retry if timer has not expired */ 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (state[0] == FSTATE_FX00_CONFIG_WAIT) { 98262306a36Sopenharmony_ci /* Firmware is waiting to be 98362306a36Sopenharmony_ci * initialized by driver 98462306a36Sopenharmony_ci */ 98562306a36Sopenharmony_ci rval = QLA_SUCCESS; 98662306a36Sopenharmony_ci done = true; 98762306a36Sopenharmony_ci break; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* Issue driver shutdown and wait until f/w recovers. 99162306a36Sopenharmony_ci * Driver should continue to poll until 8060 AEN is 99262306a36Sopenharmony_ci * received indicating firmware recovery. 99362306a36Sopenharmony_ci */ 99462306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0136, 99562306a36Sopenharmony_ci "Sending Driver shutdown fw_state 0x%x\n", 99662306a36Sopenharmony_ci state[0]); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci rval = qlafx00_driver_shutdown(vha, 10); 99962306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 100062306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 100162306a36Sopenharmony_ci break; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci msleep(500); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci wtime = jiffies + (wait_time * HZ); 100662306a36Sopenharmony_ci break; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (!done) { 101062306a36Sopenharmony_ci if (time_after_eq(jiffies, wtime)) { 101162306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0137, 101262306a36Sopenharmony_ci "Init f/w failed: aen[7]: 0x%x\n", 101362306a36Sopenharmony_ci rd_reg_dword(®->aenmailbox7)); 101462306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 101562306a36Sopenharmony_ci done = true; 101662306a36Sopenharmony_ci break; 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci /* Delay for a while */ 101962306a36Sopenharmony_ci msleep(500); 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci } while (!done); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (rval) 102462306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0138, 102562306a36Sopenharmony_ci "%s **** FAILED ****.\n", __func__); 102662306a36Sopenharmony_ci else 102762306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0139, 102862306a36Sopenharmony_ci "%s **** SUCCESS ****.\n", __func__); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci return rval; 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci/* 103462306a36Sopenharmony_ci * qlafx00_fw_ready() - Waits for firmware ready. 103562306a36Sopenharmony_ci * @ha: HA context 103662306a36Sopenharmony_ci * 103762306a36Sopenharmony_ci * Returns 0 on success. 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_ciint 104062306a36Sopenharmony_ciqlafx00_fw_ready(scsi_qla_host_t *vha) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci int rval; 104362306a36Sopenharmony_ci unsigned long wtime; 104462306a36Sopenharmony_ci uint16_t wait_time; /* Wait time if loop is coming ready */ 104562306a36Sopenharmony_ci uint32_t state[5]; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci rval = QLA_SUCCESS; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci wait_time = 10; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* wait time before firmware ready */ 105262306a36Sopenharmony_ci wtime = jiffies + (wait_time * HZ); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci /* Wait for ISP to finish init */ 105562306a36Sopenharmony_ci if (!vha->flags.init_done) 105662306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x013a, 105762306a36Sopenharmony_ci "Waiting for init to complete...\n"); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci do { 106062306a36Sopenharmony_ci rval = qlafx00_get_firmware_state(vha, state); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (rval == QLA_SUCCESS) { 106362306a36Sopenharmony_ci if (state[0] == FSTATE_FX00_INITIALIZED) { 106462306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x013b, 106562306a36Sopenharmony_ci "fw_state=%x\n", state[0]); 106662306a36Sopenharmony_ci rval = QLA_SUCCESS; 106762306a36Sopenharmony_ci break; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (time_after_eq(jiffies, wtime)) 107362306a36Sopenharmony_ci break; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* Delay for a while */ 107662306a36Sopenharmony_ci msleep(500); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x013c, 107962306a36Sopenharmony_ci "fw_state=%x curr time=%lx.\n", state[0], jiffies); 108062306a36Sopenharmony_ci } while (1); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (rval) 108462306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x013d, 108562306a36Sopenharmony_ci "Firmware ready **** FAILED ****.\n"); 108662306a36Sopenharmony_ci else 108762306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x013e, 108862306a36Sopenharmony_ci "Firmware ready **** SUCCESS ****.\n"); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci return rval; 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic int 109462306a36Sopenharmony_ciqlafx00_find_all_targets(scsi_qla_host_t *vha, 109562306a36Sopenharmony_ci struct list_head *new_fcports) 109662306a36Sopenharmony_ci{ 109762306a36Sopenharmony_ci int rval; 109862306a36Sopenharmony_ci uint16_t tgt_id; 109962306a36Sopenharmony_ci fc_port_t *fcport, *new_fcport; 110062306a36Sopenharmony_ci int found; 110162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci rval = QLA_SUCCESS; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (!test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags)) 110662306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if ((atomic_read(&vha->loop_down_timer) || 110962306a36Sopenharmony_ci STATE_TRANSITION(vha))) { 111062306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, 0); 111162306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 111262306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x2088, 111662306a36Sopenharmony_ci "Listing Target bit map...\n"); 111762306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_init, vha, 0x2089, 111862306a36Sopenharmony_ci ha->gid_list, 32); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci /* Allocate temporary rmtport for any new rmtports discovered. */ 112162306a36Sopenharmony_ci new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); 112262306a36Sopenharmony_ci if (new_fcport == NULL) 112362306a36Sopenharmony_ci return QLA_MEMORY_ALLOC_FAILED; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci for_each_set_bit(tgt_id, (void *)ha->gid_list, 112662306a36Sopenharmony_ci QLAFX00_TGT_NODE_LIST_SIZE) { 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* Send get target node info */ 112962306a36Sopenharmony_ci new_fcport->tgt_id = tgt_id; 113062306a36Sopenharmony_ci rval = qlafx00_fx_disc(vha, new_fcport, 113162306a36Sopenharmony_ci FXDISC_GET_TGT_NODE_INFO); 113262306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 113362306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x208a, 113462306a36Sopenharmony_ci "Target info scan failed -- assuming zero-entry " 113562306a36Sopenharmony_ci "result...\n"); 113662306a36Sopenharmony_ci continue; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci /* Locate matching device in database. */ 114062306a36Sopenharmony_ci found = 0; 114162306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 114262306a36Sopenharmony_ci if (memcmp(new_fcport->port_name, 114362306a36Sopenharmony_ci fcport->port_name, WWN_SIZE)) 114462306a36Sopenharmony_ci continue; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci found++; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci /* 114962306a36Sopenharmony_ci * If tgt_id is same and state FCS_ONLINE, nothing 115062306a36Sopenharmony_ci * changed. 115162306a36Sopenharmony_ci */ 115262306a36Sopenharmony_ci if (fcport->tgt_id == new_fcport->tgt_id && 115362306a36Sopenharmony_ci atomic_read(&fcport->state) == FCS_ONLINE) 115462306a36Sopenharmony_ci break; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* 115762306a36Sopenharmony_ci * Tgt ID changed or device was marked to be updated. 115862306a36Sopenharmony_ci */ 115962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x208b, 116062306a36Sopenharmony_ci "TGT-ID Change(%s): Present tgt id: " 116162306a36Sopenharmony_ci "0x%x state: 0x%x " 116262306a36Sopenharmony_ci "wwnn = %llx wwpn = %llx.\n", 116362306a36Sopenharmony_ci __func__, fcport->tgt_id, 116462306a36Sopenharmony_ci atomic_read(&fcport->state), 116562306a36Sopenharmony_ci (unsigned long long)wwn_to_u64(fcport->node_name), 116662306a36Sopenharmony_ci (unsigned long long)wwn_to_u64(fcport->port_name)); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x208c, 116962306a36Sopenharmony_ci "TGT-ID Announce(%s): Discovered tgt " 117062306a36Sopenharmony_ci "id 0x%x wwnn = %llx " 117162306a36Sopenharmony_ci "wwpn = %llx.\n", __func__, new_fcport->tgt_id, 117262306a36Sopenharmony_ci (unsigned long long) 117362306a36Sopenharmony_ci wwn_to_u64(new_fcport->node_name), 117462306a36Sopenharmony_ci (unsigned long long) 117562306a36Sopenharmony_ci wwn_to_u64(new_fcport->port_name)); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (atomic_read(&fcport->state) != FCS_ONLINE) { 117862306a36Sopenharmony_ci fcport->old_tgt_id = fcport->tgt_id; 117962306a36Sopenharmony_ci fcport->tgt_id = new_fcport->tgt_id; 118062306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x208d, 118162306a36Sopenharmony_ci "TGT-ID: New fcport Added: %p\n", fcport); 118262306a36Sopenharmony_ci qla2x00_update_fcport(vha, fcport); 118362306a36Sopenharmony_ci } else { 118462306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x208e, 118562306a36Sopenharmony_ci " Existing TGT-ID %x did not get " 118662306a36Sopenharmony_ci " offline event from firmware.\n", 118762306a36Sopenharmony_ci fcport->old_tgt_id); 118862306a36Sopenharmony_ci qla2x00_mark_device_lost(vha, fcport, 0); 118962306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 119062306a36Sopenharmony_ci qla2x00_free_fcport(new_fcport); 119162306a36Sopenharmony_ci return rval; 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci break; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (found) 119762306a36Sopenharmony_ci continue; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci /* If device was not in our fcports list, then add it. */ 120062306a36Sopenharmony_ci list_add_tail(&new_fcport->list, new_fcports); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* Allocate a new replacement fcport. */ 120362306a36Sopenharmony_ci new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); 120462306a36Sopenharmony_ci if (new_fcport == NULL) 120562306a36Sopenharmony_ci return QLA_MEMORY_ALLOC_FAILED; 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci qla2x00_free_fcport(new_fcport); 120962306a36Sopenharmony_ci return rval; 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci/* 121362306a36Sopenharmony_ci * qlafx00_configure_all_targets 121462306a36Sopenharmony_ci * Setup target devices with node ID's. 121562306a36Sopenharmony_ci * 121662306a36Sopenharmony_ci * Input: 121762306a36Sopenharmony_ci * ha = adapter block pointer. 121862306a36Sopenharmony_ci * 121962306a36Sopenharmony_ci * Returns: 122062306a36Sopenharmony_ci * 0 = success. 122162306a36Sopenharmony_ci * BIT_0 = error 122262306a36Sopenharmony_ci */ 122362306a36Sopenharmony_cistatic int 122462306a36Sopenharmony_ciqlafx00_configure_all_targets(scsi_qla_host_t *vha) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci int rval; 122762306a36Sopenharmony_ci fc_port_t *fcport, *rmptemp; 122862306a36Sopenharmony_ci LIST_HEAD(new_fcports); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci rval = qlafx00_fx_disc(vha, &vha->hw->mr.fcport, 123162306a36Sopenharmony_ci FXDISC_GET_TGT_NODE_LIST); 123262306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 123362306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 123462306a36Sopenharmony_ci return rval; 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci rval = qlafx00_find_all_targets(vha, &new_fcports); 123862306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 123962306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 124062306a36Sopenharmony_ci return rval; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* 124462306a36Sopenharmony_ci * Delete all previous devices marked lost. 124562306a36Sopenharmony_ci */ 124662306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 124762306a36Sopenharmony_ci if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) 124862306a36Sopenharmony_ci break; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) { 125162306a36Sopenharmony_ci if (fcport->port_type != FCT_INITIATOR) 125262306a36Sopenharmony_ci qla2x00_mark_device_lost(vha, fcport, 0); 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci /* 125762306a36Sopenharmony_ci * Add the new devices to our devices list. 125862306a36Sopenharmony_ci */ 125962306a36Sopenharmony_ci list_for_each_entry_safe(fcport, rmptemp, &new_fcports, list) { 126062306a36Sopenharmony_ci if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) 126162306a36Sopenharmony_ci break; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci qla2x00_update_fcport(vha, fcport); 126462306a36Sopenharmony_ci list_move_tail(&fcport->list, &vha->vp_fcports); 126562306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x208f, 126662306a36Sopenharmony_ci "Attach new target id 0x%x wwnn = %llx " 126762306a36Sopenharmony_ci "wwpn = %llx.\n", 126862306a36Sopenharmony_ci fcport->tgt_id, 126962306a36Sopenharmony_ci (unsigned long long)wwn_to_u64(fcport->node_name), 127062306a36Sopenharmony_ci (unsigned long long)wwn_to_u64(fcport->port_name)); 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci /* Free all new device structures not processed. */ 127462306a36Sopenharmony_ci list_for_each_entry_safe(fcport, rmptemp, &new_fcports, list) { 127562306a36Sopenharmony_ci list_del(&fcport->list); 127662306a36Sopenharmony_ci qla2x00_free_fcport(fcport); 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci return rval; 128062306a36Sopenharmony_ci} 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci/* 128362306a36Sopenharmony_ci * qlafx00_configure_devices 128462306a36Sopenharmony_ci * Updates Fibre Channel Device Database with what is actually on loop. 128562306a36Sopenharmony_ci * 128662306a36Sopenharmony_ci * Input: 128762306a36Sopenharmony_ci * ha = adapter block pointer. 128862306a36Sopenharmony_ci * 128962306a36Sopenharmony_ci * Returns: 129062306a36Sopenharmony_ci * 0 = success. 129162306a36Sopenharmony_ci * 1 = error. 129262306a36Sopenharmony_ci * 2 = database was full and device was not configured. 129362306a36Sopenharmony_ci */ 129462306a36Sopenharmony_ciint 129562306a36Sopenharmony_ciqlafx00_configure_devices(scsi_qla_host_t *vha) 129662306a36Sopenharmony_ci{ 129762306a36Sopenharmony_ci int rval; 129862306a36Sopenharmony_ci unsigned long flags; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci rval = QLA_SUCCESS; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci flags = vha->dpc_flags; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2090, 130562306a36Sopenharmony_ci "Configure devices -- dpc flags =0x%lx\n", flags); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci rval = qlafx00_configure_all_targets(vha); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci if (rval == QLA_SUCCESS) { 131062306a36Sopenharmony_ci if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { 131162306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 131262306a36Sopenharmony_ci } else { 131362306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_READY); 131462306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x2091, 131562306a36Sopenharmony_ci "Device Ready\n"); 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (rval) { 132062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2092, 132162306a36Sopenharmony_ci "%s *** FAILED ***.\n", __func__); 132262306a36Sopenharmony_ci } else { 132362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2093, 132462306a36Sopenharmony_ci "%s: exiting normally.\n", __func__); 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci return rval; 132762306a36Sopenharmony_ci} 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_cistatic void 133062306a36Sopenharmony_ciqlafx00_abort_isp_cleanup(scsi_qla_host_t *vha, bool critemp) 133162306a36Sopenharmony_ci{ 133262306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 133362306a36Sopenharmony_ci fc_port_t *fcport; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci vha->flags.online = 0; 133662306a36Sopenharmony_ci ha->mr.fw_hbt_en = 0; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci if (!critemp) { 133962306a36Sopenharmony_ci ha->flags.chip_reset_done = 0; 134062306a36Sopenharmony_ci clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 134162306a36Sopenharmony_ci vha->qla_stats.total_isp_aborts++; 134262306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x013f, 134362306a36Sopenharmony_ci "Performing ISP error recovery - ha = %p.\n", ha); 134462306a36Sopenharmony_ci ha->isp_ops->reset_chip(vha); 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci if (atomic_read(&vha->loop_state) != LOOP_DOWN) { 134862306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DOWN); 134962306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, 135062306a36Sopenharmony_ci QLAFX00_LOOP_DOWN_TIME); 135162306a36Sopenharmony_ci } else { 135262306a36Sopenharmony_ci if (!atomic_read(&vha->loop_down_timer)) 135362306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, 135462306a36Sopenharmony_ci QLAFX00_LOOP_DOWN_TIME); 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* Clear all async request states across all VPs. */ 135862306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 135962306a36Sopenharmony_ci fcport->flags = 0; 136062306a36Sopenharmony_ci if (atomic_read(&fcport->state) == FCS_ONLINE) 136162306a36Sopenharmony_ci qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci if (!ha->flags.eeh_busy) { 136562306a36Sopenharmony_ci if (critemp) { 136662306a36Sopenharmony_ci qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); 136762306a36Sopenharmony_ci } else { 136862306a36Sopenharmony_ci /* Requeue all commands in outstanding command list. */ 136962306a36Sopenharmony_ci qla2x00_abort_all_cmds(vha, DID_RESET << 16); 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci qla2x00_free_irqs(vha); 137462306a36Sopenharmony_ci if (critemp) 137562306a36Sopenharmony_ci set_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags); 137662306a36Sopenharmony_ci else 137762306a36Sopenharmony_ci set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci /* Clear the Interrupts */ 138062306a36Sopenharmony_ci QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x0140, 138362306a36Sopenharmony_ci "%s Done done - ha=%p.\n", __func__, ha); 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci/** 138762306a36Sopenharmony_ci * qlafx00_init_response_q_entries() - Initializes response queue entries. 138862306a36Sopenharmony_ci * @rsp: response queue 138962306a36Sopenharmony_ci * 139062306a36Sopenharmony_ci * Beginning of request ring has initialization control block already built 139162306a36Sopenharmony_ci * by nvram config routine. 139262306a36Sopenharmony_ci * 139362306a36Sopenharmony_ci * Returns 0 on success. 139462306a36Sopenharmony_ci */ 139562306a36Sopenharmony_civoid 139662306a36Sopenharmony_ciqlafx00_init_response_q_entries(struct rsp_que *rsp) 139762306a36Sopenharmony_ci{ 139862306a36Sopenharmony_ci uint16_t cnt; 139962306a36Sopenharmony_ci response_t *pkt; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci rsp->ring_ptr = rsp->ring; 140262306a36Sopenharmony_ci rsp->ring_index = 0; 140362306a36Sopenharmony_ci rsp->status_srb = NULL; 140462306a36Sopenharmony_ci pkt = rsp->ring_ptr; 140562306a36Sopenharmony_ci for (cnt = 0; cnt < rsp->length; cnt++) { 140662306a36Sopenharmony_ci pkt->signature = RESPONSE_PROCESSED; 140762306a36Sopenharmony_ci wrt_reg_dword((void __force __iomem *)&pkt->signature, 140862306a36Sopenharmony_ci RESPONSE_PROCESSED); 140962306a36Sopenharmony_ci pkt++; 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ciint 141462306a36Sopenharmony_ciqlafx00_rescan_isp(scsi_qla_host_t *vha) 141562306a36Sopenharmony_ci{ 141662306a36Sopenharmony_ci uint32_t status = QLA_FUNCTION_FAILED; 141762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 141862306a36Sopenharmony_ci struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00; 141962306a36Sopenharmony_ci uint32_t aenmbx7; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci qla2x00_request_irqs(ha, ha->rsp_q_map[0]); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci aenmbx7 = rd_reg_dword(®->aenmailbox7); 142462306a36Sopenharmony_ci ha->mbx_intr_code = MSW(aenmbx7); 142562306a36Sopenharmony_ci ha->rqstq_intr_code = LSW(aenmbx7); 142662306a36Sopenharmony_ci ha->req_que_off = rd_reg_dword(®->aenmailbox1); 142762306a36Sopenharmony_ci ha->rsp_que_off = rd_reg_dword(®->aenmailbox3); 142862306a36Sopenharmony_ci ha->req_que_len = rd_reg_dword(®->aenmailbox5); 142962306a36Sopenharmony_ci ha->rsp_que_len = rd_reg_dword(®->aenmailbox6); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2094, 143262306a36Sopenharmony_ci "fw returned mbx_intr_code: 0x%x, rqstq_intr_code: 0x%x " 143362306a36Sopenharmony_ci " Req que offset 0x%x Rsp que offset 0x%x\n", 143462306a36Sopenharmony_ci ha->mbx_intr_code, ha->rqstq_intr_code, 143562306a36Sopenharmony_ci ha->req_que_off, ha->rsp_que_len); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* Clear the Interrupts */ 143862306a36Sopenharmony_ci QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci status = qla2x00_init_rings(vha); 144162306a36Sopenharmony_ci if (!status) { 144262306a36Sopenharmony_ci vha->flags.online = 1; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci /* if no cable then assume it's good */ 144562306a36Sopenharmony_ci if ((vha->device_flags & DFLG_NO_CABLE)) 144662306a36Sopenharmony_ci status = 0; 144762306a36Sopenharmony_ci /* Register system information */ 144862306a36Sopenharmony_ci if (qlafx00_fx_disc(vha, 144962306a36Sopenharmony_ci &vha->hw->mr.fcport, FXDISC_REG_HOST_INFO)) 145062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2095, 145162306a36Sopenharmony_ci "failed to register host info\n"); 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci scsi_unblock_requests(vha->host); 145462306a36Sopenharmony_ci return status; 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_civoid 145862306a36Sopenharmony_ciqlafx00_timer_routine(scsi_qla_host_t *vha) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 146162306a36Sopenharmony_ci uint32_t fw_heart_beat; 146262306a36Sopenharmony_ci uint32_t aenmbx0; 146362306a36Sopenharmony_ci struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00; 146462306a36Sopenharmony_ci uint32_t tempc; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci /* Check firmware health */ 146762306a36Sopenharmony_ci if (ha->mr.fw_hbt_cnt) 146862306a36Sopenharmony_ci ha->mr.fw_hbt_cnt--; 146962306a36Sopenharmony_ci else { 147062306a36Sopenharmony_ci if ((!ha->flags.mr_reset_hdlr_active) && 147162306a36Sopenharmony_ci (!test_bit(UNLOADING, &vha->dpc_flags)) && 147262306a36Sopenharmony_ci (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) && 147362306a36Sopenharmony_ci (ha->mr.fw_hbt_en)) { 147462306a36Sopenharmony_ci fw_heart_beat = rd_reg_dword(®->fwheartbeat); 147562306a36Sopenharmony_ci if (fw_heart_beat != ha->mr.old_fw_hbt_cnt) { 147662306a36Sopenharmony_ci ha->mr.old_fw_hbt_cnt = fw_heart_beat; 147762306a36Sopenharmony_ci ha->mr.fw_hbt_miss_cnt = 0; 147862306a36Sopenharmony_ci } else { 147962306a36Sopenharmony_ci ha->mr.fw_hbt_miss_cnt++; 148062306a36Sopenharmony_ci if (ha->mr.fw_hbt_miss_cnt == 148162306a36Sopenharmony_ci QLAFX00_HEARTBEAT_MISS_CNT) { 148262306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 148362306a36Sopenharmony_ci &vha->dpc_flags); 148462306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 148562306a36Sopenharmony_ci ha->mr.fw_hbt_miss_cnt = 0; 148662306a36Sopenharmony_ci } 148762306a36Sopenharmony_ci } 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci if (test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags)) { 149362306a36Sopenharmony_ci /* Reset recovery to be performed in timer routine */ 149462306a36Sopenharmony_ci aenmbx0 = rd_reg_dword(®->aenmailbox0); 149562306a36Sopenharmony_ci if (ha->mr.fw_reset_timer_exp) { 149662306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 149762306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 149862306a36Sopenharmony_ci ha->mr.fw_reset_timer_exp = 0; 149962306a36Sopenharmony_ci } else if (aenmbx0 == MBA_FW_RESTART_CMPLT) { 150062306a36Sopenharmony_ci /* Wake up DPC to rescan the targets */ 150162306a36Sopenharmony_ci set_bit(FX00_TARGET_SCAN, &vha->dpc_flags); 150262306a36Sopenharmony_ci clear_bit(FX00_RESET_RECOVERY, &vha->dpc_flags); 150362306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 150462306a36Sopenharmony_ci ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL; 150562306a36Sopenharmony_ci } else if ((aenmbx0 == MBA_FW_STARTING) && 150662306a36Sopenharmony_ci (!ha->mr.fw_hbt_en)) { 150762306a36Sopenharmony_ci ha->mr.fw_hbt_en = 1; 150862306a36Sopenharmony_ci } else if (!ha->mr.fw_reset_timer_tick) { 150962306a36Sopenharmony_ci if (aenmbx0 == ha->mr.old_aenmbx0_state) 151062306a36Sopenharmony_ci ha->mr.fw_reset_timer_exp = 1; 151162306a36Sopenharmony_ci ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL; 151262306a36Sopenharmony_ci } else if (aenmbx0 == 0xFFFFFFFF) { 151362306a36Sopenharmony_ci uint32_t data0, data1; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci data0 = QLAFX00_RD_REG(ha, 151662306a36Sopenharmony_ci QLAFX00_BAR1_BASE_ADDR_REG); 151762306a36Sopenharmony_ci data1 = QLAFX00_RD_REG(ha, 151862306a36Sopenharmony_ci QLAFX00_PEX0_WIN0_BASE_ADDR_REG); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci data0 &= 0xffff0000; 152162306a36Sopenharmony_ci data1 &= 0x0000ffff; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci QLAFX00_WR_REG(ha, 152462306a36Sopenharmony_ci QLAFX00_PEX0_WIN0_BASE_ADDR_REG, 152562306a36Sopenharmony_ci (data0 | data1)); 152662306a36Sopenharmony_ci } else if ((aenmbx0 & 0xFF00) == MBA_FW_POLL_STATE) { 152762306a36Sopenharmony_ci ha->mr.fw_reset_timer_tick = 152862306a36Sopenharmony_ci QLAFX00_MAX_RESET_INTERVAL; 152962306a36Sopenharmony_ci } else if (aenmbx0 == MBA_FW_RESET_FCT) { 153062306a36Sopenharmony_ci ha->mr.fw_reset_timer_tick = 153162306a36Sopenharmony_ci QLAFX00_MAX_RESET_INTERVAL; 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci if (ha->mr.old_aenmbx0_state != aenmbx0) { 153462306a36Sopenharmony_ci ha->mr.old_aenmbx0_state = aenmbx0; 153562306a36Sopenharmony_ci ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL; 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci ha->mr.fw_reset_timer_tick--; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci if (test_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags)) { 154062306a36Sopenharmony_ci /* 154162306a36Sopenharmony_ci * Critical temperature recovery to be 154262306a36Sopenharmony_ci * performed in timer routine 154362306a36Sopenharmony_ci */ 154462306a36Sopenharmony_ci if (ha->mr.fw_critemp_timer_tick == 0) { 154562306a36Sopenharmony_ci tempc = QLAFX00_GET_TEMPERATURE(ha); 154662306a36Sopenharmony_ci ql_dbg(ql_dbg_timer, vha, 0x6012, 154762306a36Sopenharmony_ci "ISPFx00(%s): Critical temp timer, " 154862306a36Sopenharmony_ci "current SOC temperature: %d\n", 154962306a36Sopenharmony_ci __func__, tempc); 155062306a36Sopenharmony_ci if (tempc < ha->mr.critical_temperature) { 155162306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 155262306a36Sopenharmony_ci clear_bit(FX00_CRITEMP_RECOVERY, 155362306a36Sopenharmony_ci &vha->dpc_flags); 155462306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci ha->mr.fw_critemp_timer_tick = 155762306a36Sopenharmony_ci QLAFX00_CRITEMP_INTERVAL; 155862306a36Sopenharmony_ci } else { 155962306a36Sopenharmony_ci ha->mr.fw_critemp_timer_tick--; 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci if (ha->mr.host_info_resend) { 156362306a36Sopenharmony_ci /* 156462306a36Sopenharmony_ci * Incomplete host info might be sent to firmware 156562306a36Sopenharmony_ci * durinng system boot - info should be resend 156662306a36Sopenharmony_ci */ 156762306a36Sopenharmony_ci if (ha->mr.hinfo_resend_timer_tick == 0) { 156862306a36Sopenharmony_ci ha->mr.host_info_resend = false; 156962306a36Sopenharmony_ci set_bit(FX00_HOST_INFO_RESEND, &vha->dpc_flags); 157062306a36Sopenharmony_ci ha->mr.hinfo_resend_timer_tick = 157162306a36Sopenharmony_ci QLAFX00_HINFO_RESEND_INTERVAL; 157262306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 157362306a36Sopenharmony_ci } else { 157462306a36Sopenharmony_ci ha->mr.hinfo_resend_timer_tick--; 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci/* 158162306a36Sopenharmony_ci * qlfx00a_reset_initialize 158262306a36Sopenharmony_ci * Re-initialize after a iSA device reset. 158362306a36Sopenharmony_ci * 158462306a36Sopenharmony_ci * Input: 158562306a36Sopenharmony_ci * ha = adapter block pointer. 158662306a36Sopenharmony_ci * 158762306a36Sopenharmony_ci * Returns: 158862306a36Sopenharmony_ci * 0 = success 158962306a36Sopenharmony_ci */ 159062306a36Sopenharmony_ciint 159162306a36Sopenharmony_ciqlafx00_reset_initialize(scsi_qla_host_t *vha) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (vha->device_flags & DFLG_DEV_FAILED) { 159662306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0142, 159762306a36Sopenharmony_ci "Device in failed state\n"); 159862306a36Sopenharmony_ci return QLA_SUCCESS; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci ha->flags.mr_reset_hdlr_active = 1; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci if (vha->flags.online) { 160462306a36Sopenharmony_ci scsi_block_requests(vha->host); 160562306a36Sopenharmony_ci qlafx00_abort_isp_cleanup(vha, false); 160662306a36Sopenharmony_ci } 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x0143, 160962306a36Sopenharmony_ci "(%s): succeeded.\n", __func__); 161062306a36Sopenharmony_ci ha->flags.mr_reset_hdlr_active = 0; 161162306a36Sopenharmony_ci return QLA_SUCCESS; 161262306a36Sopenharmony_ci} 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci/* 161562306a36Sopenharmony_ci * qlafx00_abort_isp 161662306a36Sopenharmony_ci * Resets ISP and aborts all outstanding commands. 161762306a36Sopenharmony_ci * 161862306a36Sopenharmony_ci * Input: 161962306a36Sopenharmony_ci * ha = adapter block pointer. 162062306a36Sopenharmony_ci * 162162306a36Sopenharmony_ci * Returns: 162262306a36Sopenharmony_ci * 0 = success 162362306a36Sopenharmony_ci */ 162462306a36Sopenharmony_ciint 162562306a36Sopenharmony_ciqlafx00_abort_isp(scsi_qla_host_t *vha) 162662306a36Sopenharmony_ci{ 162762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci if (vha->flags.online) { 163062306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev) && 163162306a36Sopenharmony_ci ha->flags.pci_channel_io_perm_failure)) { 163262306a36Sopenharmony_ci clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); 163362306a36Sopenharmony_ci return QLA_SUCCESS; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci scsi_block_requests(vha->host); 163762306a36Sopenharmony_ci qlafx00_abort_isp_cleanup(vha, false); 163862306a36Sopenharmony_ci } else { 163962306a36Sopenharmony_ci scsi_block_requests(vha->host); 164062306a36Sopenharmony_ci clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 164162306a36Sopenharmony_ci vha->qla_stats.total_isp_aborts++; 164262306a36Sopenharmony_ci ha->isp_ops->reset_chip(vha); 164362306a36Sopenharmony_ci set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags); 164462306a36Sopenharmony_ci /* Clear the Interrupts */ 164562306a36Sopenharmony_ci QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS); 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x0145, 164962306a36Sopenharmony_ci "(%s): succeeded.\n", __func__); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci return QLA_SUCCESS; 165262306a36Sopenharmony_ci} 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_cistatic inline fc_port_t* 165562306a36Sopenharmony_ciqlafx00_get_fcport(struct scsi_qla_host *vha, int tgt_id) 165662306a36Sopenharmony_ci{ 165762306a36Sopenharmony_ci fc_port_t *fcport; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci /* Check for matching device in remote port list. */ 166062306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 166162306a36Sopenharmony_ci if (fcport->tgt_id == tgt_id) { 166262306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5072, 166362306a36Sopenharmony_ci "Matching fcport(%p) found with TGT-ID: 0x%x " 166462306a36Sopenharmony_ci "and Remote TGT_ID: 0x%x\n", 166562306a36Sopenharmony_ci fcport, fcport->tgt_id, tgt_id); 166662306a36Sopenharmony_ci return fcport; 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci return NULL; 167062306a36Sopenharmony_ci} 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_cistatic void 167362306a36Sopenharmony_ciqlafx00_tgt_detach(struct scsi_qla_host *vha, int tgt_id) 167462306a36Sopenharmony_ci{ 167562306a36Sopenharmony_ci fc_port_t *fcport; 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x5073, 167862306a36Sopenharmony_ci "Detach TGT-ID: 0x%x\n", tgt_id); 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci fcport = qlafx00_get_fcport(vha, tgt_id); 168162306a36Sopenharmony_ci if (!fcport) 168262306a36Sopenharmony_ci return; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci qla2x00_mark_device_lost(vha, fcport, 0); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci return; 168762306a36Sopenharmony_ci} 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_civoid 169062306a36Sopenharmony_ciqlafx00_process_aen(struct scsi_qla_host *vha, struct qla_work_evt *evt) 169162306a36Sopenharmony_ci{ 169262306a36Sopenharmony_ci uint32_t aen_code, aen_data; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci aen_code = FCH_EVT_VENDOR_UNIQUE; 169562306a36Sopenharmony_ci aen_data = evt->u.aenfx.evtcode; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci switch (evt->u.aenfx.evtcode) { 169862306a36Sopenharmony_ci case QLAFX00_MBA_PORT_UPDATE: /* Port database update */ 169962306a36Sopenharmony_ci if (evt->u.aenfx.mbx[1] == 0) { 170062306a36Sopenharmony_ci if (evt->u.aenfx.mbx[2] == 1) { 170162306a36Sopenharmony_ci if (!vha->flags.fw_tgt_reported) 170262306a36Sopenharmony_ci vha->flags.fw_tgt_reported = 1; 170362306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, 0); 170462306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_UP); 170562306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 170662306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 170762306a36Sopenharmony_ci } else if (evt->u.aenfx.mbx[2] == 2) { 170862306a36Sopenharmony_ci qlafx00_tgt_detach(vha, evt->u.aenfx.mbx[3]); 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci } else if (evt->u.aenfx.mbx[1] == 0xffff) { 171162306a36Sopenharmony_ci if (evt->u.aenfx.mbx[2] == 1) { 171262306a36Sopenharmony_ci if (!vha->flags.fw_tgt_reported) 171362306a36Sopenharmony_ci vha->flags.fw_tgt_reported = 1; 171462306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 171562306a36Sopenharmony_ci } else if (evt->u.aenfx.mbx[2] == 2) { 171662306a36Sopenharmony_ci vha->device_flags |= DFLG_NO_CABLE; 171762306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci break; 172162306a36Sopenharmony_ci case QLAFX00_MBA_LINK_UP: 172262306a36Sopenharmony_ci aen_code = FCH_EVT_LINKUP; 172362306a36Sopenharmony_ci aen_data = 0; 172462306a36Sopenharmony_ci break; 172562306a36Sopenharmony_ci case QLAFX00_MBA_LINK_DOWN: 172662306a36Sopenharmony_ci aen_code = FCH_EVT_LINKDOWN; 172762306a36Sopenharmony_ci aen_data = 0; 172862306a36Sopenharmony_ci break; 172962306a36Sopenharmony_ci case QLAFX00_MBA_TEMP_CRIT: /* Critical temperature event */ 173062306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x5082, 173162306a36Sopenharmony_ci "Process critical temperature event " 173262306a36Sopenharmony_ci "aenmb[0]: %x\n", 173362306a36Sopenharmony_ci evt->u.aenfx.evtcode); 173462306a36Sopenharmony_ci scsi_block_requests(vha->host); 173562306a36Sopenharmony_ci qlafx00_abort_isp_cleanup(vha, true); 173662306a36Sopenharmony_ci scsi_unblock_requests(vha->host); 173762306a36Sopenharmony_ci break; 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci fc_host_post_event(vha->host, fc_get_event_number(), 174162306a36Sopenharmony_ci aen_code, aen_data); 174262306a36Sopenharmony_ci} 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_cistatic void 174562306a36Sopenharmony_ciqlafx00_update_host_attr(scsi_qla_host_t *vha, struct port_info_data *pinfo) 174662306a36Sopenharmony_ci{ 174762306a36Sopenharmony_ci u64 port_name = 0, node_name = 0; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci port_name = (unsigned long long)wwn_to_u64(pinfo->port_name); 175062306a36Sopenharmony_ci node_name = (unsigned long long)wwn_to_u64(pinfo->node_name); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci fc_host_node_name(vha->host) = node_name; 175362306a36Sopenharmony_ci fc_host_port_name(vha->host) = port_name; 175462306a36Sopenharmony_ci if (!pinfo->port_type) 175562306a36Sopenharmony_ci vha->hw->current_topology = ISP_CFG_F; 175662306a36Sopenharmony_ci if (pinfo->link_status == QLAFX00_LINK_STATUS_UP) 175762306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_READY); 175862306a36Sopenharmony_ci else if (pinfo->link_status == QLAFX00_LINK_STATUS_DOWN) 175962306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DOWN); 176062306a36Sopenharmony_ci vha->hw->link_data_rate = (uint16_t)pinfo->link_config; 176162306a36Sopenharmony_ci} 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_cistatic void 176462306a36Sopenharmony_ciqla2x00_fxdisc_iocb_timeout(void *data) 176562306a36Sopenharmony_ci{ 176662306a36Sopenharmony_ci srb_t *sp = data; 176762306a36Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci complete(&lio->u.fxiocb.fxiocb_comp); 177062306a36Sopenharmony_ci} 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_cistatic void qla2x00_fxdisc_sp_done(srb_t *sp, int res) 177362306a36Sopenharmony_ci{ 177462306a36Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci complete(&lio->u.fxiocb.fxiocb_comp); 177762306a36Sopenharmony_ci} 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ciint 178062306a36Sopenharmony_ciqlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type) 178162306a36Sopenharmony_ci{ 178262306a36Sopenharmony_ci srb_t *sp; 178362306a36Sopenharmony_ci struct srb_iocb *fdisc; 178462306a36Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 178562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 178662306a36Sopenharmony_ci struct host_system_info *phost_info; 178762306a36Sopenharmony_ci struct register_host_info *preg_hsi; 178862306a36Sopenharmony_ci struct new_utsname *p_sysid = NULL; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci /* ref: INIT */ 179162306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 179262306a36Sopenharmony_ci if (!sp) 179362306a36Sopenharmony_ci goto done; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci sp->type = SRB_FXIOCB_DCMD; 179662306a36Sopenharmony_ci sp->name = "fxdisc"; 179762306a36Sopenharmony_ci qla2x00_init_async_sp(sp, FXDISC_TIMEOUT, 179862306a36Sopenharmony_ci qla2x00_fxdisc_sp_done); 179962306a36Sopenharmony_ci sp->u.iocb_cmd.timeout = qla2x00_fxdisc_iocb_timeout; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci fdisc = &sp->u.iocb_cmd; 180262306a36Sopenharmony_ci switch (fx_type) { 180362306a36Sopenharmony_ci case FXDISC_GET_CONFIG_INFO: 180462306a36Sopenharmony_ci fdisc->u.fxiocb.flags = 180562306a36Sopenharmony_ci SRB_FXDISC_RESP_DMA_VALID; 180662306a36Sopenharmony_ci fdisc->u.fxiocb.rsp_len = sizeof(struct config_info_data); 180762306a36Sopenharmony_ci break; 180862306a36Sopenharmony_ci case FXDISC_GET_PORT_INFO: 180962306a36Sopenharmony_ci fdisc->u.fxiocb.flags = 181062306a36Sopenharmony_ci SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID; 181162306a36Sopenharmony_ci fdisc->u.fxiocb.rsp_len = QLAFX00_PORT_DATA_INFO; 181262306a36Sopenharmony_ci fdisc->u.fxiocb.req_data = cpu_to_le32(fcport->port_id); 181362306a36Sopenharmony_ci break; 181462306a36Sopenharmony_ci case FXDISC_GET_TGT_NODE_INFO: 181562306a36Sopenharmony_ci fdisc->u.fxiocb.flags = 181662306a36Sopenharmony_ci SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID; 181762306a36Sopenharmony_ci fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_INFO; 181862306a36Sopenharmony_ci fdisc->u.fxiocb.req_data = cpu_to_le32(fcport->tgt_id); 181962306a36Sopenharmony_ci break; 182062306a36Sopenharmony_ci case FXDISC_GET_TGT_NODE_LIST: 182162306a36Sopenharmony_ci fdisc->u.fxiocb.flags = 182262306a36Sopenharmony_ci SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID; 182362306a36Sopenharmony_ci fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_LIST_SIZE; 182462306a36Sopenharmony_ci break; 182562306a36Sopenharmony_ci case FXDISC_REG_HOST_INFO: 182662306a36Sopenharmony_ci fdisc->u.fxiocb.flags = SRB_FXDISC_REQ_DMA_VALID; 182762306a36Sopenharmony_ci fdisc->u.fxiocb.req_len = sizeof(struct register_host_info); 182862306a36Sopenharmony_ci p_sysid = utsname(); 182962306a36Sopenharmony_ci if (!p_sysid) { 183062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x303c, 183162306a36Sopenharmony_ci "Not able to get the system information\n"); 183262306a36Sopenharmony_ci goto done_free_sp; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci break; 183562306a36Sopenharmony_ci case FXDISC_ABORT_IOCTL: 183662306a36Sopenharmony_ci default: 183762306a36Sopenharmony_ci break; 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci if (fdisc->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) { 184162306a36Sopenharmony_ci fdisc->u.fxiocb.req_addr = dma_alloc_coherent(&ha->pdev->dev, 184262306a36Sopenharmony_ci fdisc->u.fxiocb.req_len, 184362306a36Sopenharmony_ci &fdisc->u.fxiocb.req_dma_handle, GFP_KERNEL); 184462306a36Sopenharmony_ci if (!fdisc->u.fxiocb.req_addr) 184562306a36Sopenharmony_ci goto done_free_sp; 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci if (fx_type == FXDISC_REG_HOST_INFO) { 184862306a36Sopenharmony_ci preg_hsi = (struct register_host_info *) 184962306a36Sopenharmony_ci fdisc->u.fxiocb.req_addr; 185062306a36Sopenharmony_ci phost_info = &preg_hsi->hsi; 185162306a36Sopenharmony_ci memset(preg_hsi, 0, sizeof(struct register_host_info)); 185262306a36Sopenharmony_ci phost_info->os_type = OS_TYPE_LINUX; 185362306a36Sopenharmony_ci strscpy(phost_info->sysname, p_sysid->sysname, 185462306a36Sopenharmony_ci sizeof(phost_info->sysname)); 185562306a36Sopenharmony_ci strscpy(phost_info->nodename, p_sysid->nodename, 185662306a36Sopenharmony_ci sizeof(phost_info->nodename)); 185762306a36Sopenharmony_ci if (!strcmp(phost_info->nodename, "(none)")) 185862306a36Sopenharmony_ci ha->mr.host_info_resend = true; 185962306a36Sopenharmony_ci strscpy(phost_info->release, p_sysid->release, 186062306a36Sopenharmony_ci sizeof(phost_info->release)); 186162306a36Sopenharmony_ci strscpy(phost_info->version, p_sysid->version, 186262306a36Sopenharmony_ci sizeof(phost_info->version)); 186362306a36Sopenharmony_ci strscpy(phost_info->machine, p_sysid->machine, 186462306a36Sopenharmony_ci sizeof(phost_info->machine)); 186562306a36Sopenharmony_ci strscpy(phost_info->domainname, p_sysid->domainname, 186662306a36Sopenharmony_ci sizeof(phost_info->domainname)); 186762306a36Sopenharmony_ci strscpy(phost_info->hostdriver, QLA2XXX_VERSION, 186862306a36Sopenharmony_ci sizeof(phost_info->hostdriver)); 186962306a36Sopenharmony_ci preg_hsi->utc = (uint64_t)ktime_get_real_seconds(); 187062306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0149, 187162306a36Sopenharmony_ci "ISP%04X: Host registration with firmware\n", 187262306a36Sopenharmony_ci ha->pdev->device); 187362306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x014a, 187462306a36Sopenharmony_ci "os_type = '%d', sysname = '%s', nodname = '%s'\n", 187562306a36Sopenharmony_ci phost_info->os_type, 187662306a36Sopenharmony_ci phost_info->sysname, 187762306a36Sopenharmony_ci phost_info->nodename); 187862306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x014b, 187962306a36Sopenharmony_ci "release = '%s', version = '%s'\n", 188062306a36Sopenharmony_ci phost_info->release, 188162306a36Sopenharmony_ci phost_info->version); 188262306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x014c, 188362306a36Sopenharmony_ci "machine = '%s' " 188462306a36Sopenharmony_ci "domainname = '%s', hostdriver = '%s'\n", 188562306a36Sopenharmony_ci phost_info->machine, 188662306a36Sopenharmony_ci phost_info->domainname, 188762306a36Sopenharmony_ci phost_info->hostdriver); 188862306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_disc, vha, 0x014d, 188962306a36Sopenharmony_ci phost_info, sizeof(*phost_info)); 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci } 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci if (fdisc->u.fxiocb.flags & SRB_FXDISC_RESP_DMA_VALID) { 189462306a36Sopenharmony_ci fdisc->u.fxiocb.rsp_addr = dma_alloc_coherent(&ha->pdev->dev, 189562306a36Sopenharmony_ci fdisc->u.fxiocb.rsp_len, 189662306a36Sopenharmony_ci &fdisc->u.fxiocb.rsp_dma_handle, GFP_KERNEL); 189762306a36Sopenharmony_ci if (!fdisc->u.fxiocb.rsp_addr) 189862306a36Sopenharmony_ci goto done_unmap_req; 189962306a36Sopenharmony_ci } 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci fdisc->u.fxiocb.req_func_type = cpu_to_le16(fx_type); 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 190462306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 190562306a36Sopenharmony_ci goto done_unmap_dma; 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci wait_for_completion(&fdisc->u.fxiocb.fxiocb_comp); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci if (fx_type == FXDISC_GET_CONFIG_INFO) { 191062306a36Sopenharmony_ci struct config_info_data *pinfo = 191162306a36Sopenharmony_ci (struct config_info_data *) fdisc->u.fxiocb.rsp_addr; 191262306a36Sopenharmony_ci strscpy(vha->hw->model_number, pinfo->model_num, 191362306a36Sopenharmony_ci ARRAY_SIZE(vha->hw->model_number)); 191462306a36Sopenharmony_ci strscpy(vha->hw->model_desc, pinfo->model_description, 191562306a36Sopenharmony_ci ARRAY_SIZE(vha->hw->model_desc)); 191662306a36Sopenharmony_ci memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name, 191762306a36Sopenharmony_ci sizeof(vha->hw->mr.symbolic_name)); 191862306a36Sopenharmony_ci memcpy(&vha->hw->mr.serial_num, pinfo->serial_num, 191962306a36Sopenharmony_ci sizeof(vha->hw->mr.serial_num)); 192062306a36Sopenharmony_ci memcpy(&vha->hw->mr.hw_version, pinfo->hw_version, 192162306a36Sopenharmony_ci sizeof(vha->hw->mr.hw_version)); 192262306a36Sopenharmony_ci memcpy(&vha->hw->mr.fw_version, pinfo->fw_version, 192362306a36Sopenharmony_ci sizeof(vha->hw->mr.fw_version)); 192462306a36Sopenharmony_ci strim(vha->hw->mr.fw_version); 192562306a36Sopenharmony_ci memcpy(&vha->hw->mr.uboot_version, pinfo->uboot_version, 192662306a36Sopenharmony_ci sizeof(vha->hw->mr.uboot_version)); 192762306a36Sopenharmony_ci memcpy(&vha->hw->mr.fru_serial_num, pinfo->fru_serial_num, 192862306a36Sopenharmony_ci sizeof(vha->hw->mr.fru_serial_num)); 192962306a36Sopenharmony_ci vha->hw->mr.critical_temperature = 193062306a36Sopenharmony_ci (pinfo->nominal_temp_value) ? 193162306a36Sopenharmony_ci pinfo->nominal_temp_value : QLAFX00_CRITEMP_THRSHLD; 193262306a36Sopenharmony_ci ha->mr.extended_io_enabled = (pinfo->enabled_capabilities & 193362306a36Sopenharmony_ci QLAFX00_EXTENDED_IO_EN_MASK) != 0; 193462306a36Sopenharmony_ci } else if (fx_type == FXDISC_GET_PORT_INFO) { 193562306a36Sopenharmony_ci struct port_info_data *pinfo = 193662306a36Sopenharmony_ci (struct port_info_data *) fdisc->u.fxiocb.rsp_addr; 193762306a36Sopenharmony_ci memcpy(vha->node_name, pinfo->node_name, WWN_SIZE); 193862306a36Sopenharmony_ci memcpy(vha->port_name, pinfo->port_name, WWN_SIZE); 193962306a36Sopenharmony_ci vha->d_id.b.domain = pinfo->port_id[0]; 194062306a36Sopenharmony_ci vha->d_id.b.area = pinfo->port_id[1]; 194162306a36Sopenharmony_ci vha->d_id.b.al_pa = pinfo->port_id[2]; 194262306a36Sopenharmony_ci qlafx00_update_host_attr(vha, pinfo); 194362306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0141, 194462306a36Sopenharmony_ci pinfo, 16); 194562306a36Sopenharmony_ci } else if (fx_type == FXDISC_GET_TGT_NODE_INFO) { 194662306a36Sopenharmony_ci struct qlafx00_tgt_node_info *pinfo = 194762306a36Sopenharmony_ci (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr; 194862306a36Sopenharmony_ci memcpy(fcport->node_name, pinfo->tgt_node_wwnn, WWN_SIZE); 194962306a36Sopenharmony_ci memcpy(fcport->port_name, pinfo->tgt_node_wwpn, WWN_SIZE); 195062306a36Sopenharmony_ci fcport->port_type = FCT_TARGET; 195162306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0144, 195262306a36Sopenharmony_ci pinfo, 16); 195362306a36Sopenharmony_ci } else if (fx_type == FXDISC_GET_TGT_NODE_LIST) { 195462306a36Sopenharmony_ci struct qlafx00_tgt_node_info *pinfo = 195562306a36Sopenharmony_ci (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr; 195662306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0146, 195762306a36Sopenharmony_ci pinfo, 16); 195862306a36Sopenharmony_ci memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE); 195962306a36Sopenharmony_ci } else if (fx_type == FXDISC_ABORT_IOCTL) 196062306a36Sopenharmony_ci fdisc->u.fxiocb.result = 196162306a36Sopenharmony_ci (fdisc->u.fxiocb.result == 196262306a36Sopenharmony_ci cpu_to_le32(QLAFX00_IOCTL_ICOB_ABORT_SUCCESS)) ? 196362306a36Sopenharmony_ci cpu_to_le32(QLA_SUCCESS) : cpu_to_le32(QLA_FUNCTION_FAILED); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci rval = le32_to_cpu(fdisc->u.fxiocb.result); 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_cidone_unmap_dma: 196862306a36Sopenharmony_ci if (fdisc->u.fxiocb.rsp_addr) 196962306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.rsp_len, 197062306a36Sopenharmony_ci fdisc->u.fxiocb.rsp_addr, fdisc->u.fxiocb.rsp_dma_handle); 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_cidone_unmap_req: 197362306a36Sopenharmony_ci if (fdisc->u.fxiocb.req_addr) 197462306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.req_len, 197562306a36Sopenharmony_ci fdisc->u.fxiocb.req_addr, fdisc->u.fxiocb.req_dma_handle); 197662306a36Sopenharmony_cidone_free_sp: 197762306a36Sopenharmony_ci /* ref: INIT */ 197862306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 197962306a36Sopenharmony_cidone: 198062306a36Sopenharmony_ci return rval; 198162306a36Sopenharmony_ci} 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci/* 198462306a36Sopenharmony_ci * qlafx00_initialize_adapter 198562306a36Sopenharmony_ci * Initialize board. 198662306a36Sopenharmony_ci * 198762306a36Sopenharmony_ci * Input: 198862306a36Sopenharmony_ci * ha = adapter block pointer. 198962306a36Sopenharmony_ci * 199062306a36Sopenharmony_ci * Returns: 199162306a36Sopenharmony_ci * 0 = success 199262306a36Sopenharmony_ci */ 199362306a36Sopenharmony_ciint 199462306a36Sopenharmony_ciqlafx00_initialize_adapter(scsi_qla_host_t *vha) 199562306a36Sopenharmony_ci{ 199662306a36Sopenharmony_ci int rval; 199762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 199862306a36Sopenharmony_ci uint32_t tempc; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci /* Clear adapter flags. */ 200162306a36Sopenharmony_ci vha->flags.online = 0; 200262306a36Sopenharmony_ci ha->flags.chip_reset_done = 0; 200362306a36Sopenharmony_ci vha->flags.reset_active = 0; 200462306a36Sopenharmony_ci ha->flags.pci_channel_io_perm_failure = 0; 200562306a36Sopenharmony_ci ha->flags.eeh_busy = 0; 200662306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); 200762306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DOWN); 200862306a36Sopenharmony_ci vha->device_flags = DFLG_NO_CABLE; 200962306a36Sopenharmony_ci vha->dpc_flags = 0; 201062306a36Sopenharmony_ci vha->flags.management_server_logged_in = 0; 201162306a36Sopenharmony_ci ha->isp_abort_cnt = 0; 201262306a36Sopenharmony_ci ha->beacon_blink_led = 0; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci set_bit(0, ha->req_qid_map); 201562306a36Sopenharmony_ci set_bit(0, ha->rsp_qid_map); 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0147, 201862306a36Sopenharmony_ci "Configuring PCI space...\n"); 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci rval = ha->isp_ops->pci_config(vha); 202162306a36Sopenharmony_ci if (rval) { 202262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0148, 202362306a36Sopenharmony_ci "Unable to configure PCI space.\n"); 202462306a36Sopenharmony_ci return rval; 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci rval = qlafx00_init_fw_ready(vha); 202862306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 202962306a36Sopenharmony_ci return rval; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci qlafx00_save_queue_ptrs(vha); 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci rval = qlafx00_config_queues(vha); 203462306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 203562306a36Sopenharmony_ci return rval; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci /* 203862306a36Sopenharmony_ci * Allocate the array of outstanding commands 203962306a36Sopenharmony_ci * now that we know the firmware resources. 204062306a36Sopenharmony_ci */ 204162306a36Sopenharmony_ci rval = qla2x00_alloc_outstanding_cmds(ha, vha->req); 204262306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 204362306a36Sopenharmony_ci return rval; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci rval = qla2x00_init_rings(vha); 204662306a36Sopenharmony_ci ha->flags.chip_reset_done = 1; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci tempc = QLAFX00_GET_TEMPERATURE(ha); 204962306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0152, 205062306a36Sopenharmony_ci "ISPFx00(%s): Critical temp timer, current SOC temperature: 0x%x\n", 205162306a36Sopenharmony_ci __func__, tempc); 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci return rval; 205462306a36Sopenharmony_ci} 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ciuint32_t 205762306a36Sopenharmony_ciqlafx00_fw_state_show(struct device *dev, struct device_attribute *attr, 205862306a36Sopenharmony_ci char *buf) 205962306a36Sopenharmony_ci{ 206062306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); 206162306a36Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 206262306a36Sopenharmony_ci uint32_t state[1]; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci if (qla2x00_reset_active(vha)) 206562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70ce, 206662306a36Sopenharmony_ci "ISP reset active.\n"); 206762306a36Sopenharmony_ci else if (!vha->hw->flags.eeh_busy) { 206862306a36Sopenharmony_ci rval = qlafx00_get_firmware_state(vha, state); 206962306a36Sopenharmony_ci } 207062306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 207162306a36Sopenharmony_ci memset(state, -1, sizeof(state)); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci return state[0]; 207462306a36Sopenharmony_ci} 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_civoid 207762306a36Sopenharmony_ciqlafx00_get_host_speed(struct Scsi_Host *shost) 207862306a36Sopenharmony_ci{ 207962306a36Sopenharmony_ci struct qla_hw_data *ha = ((struct scsi_qla_host *) 208062306a36Sopenharmony_ci (shost_priv(shost)))->hw; 208162306a36Sopenharmony_ci u32 speed = FC_PORTSPEED_UNKNOWN; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci switch (ha->link_data_rate) { 208462306a36Sopenharmony_ci case QLAFX00_PORT_SPEED_2G: 208562306a36Sopenharmony_ci speed = FC_PORTSPEED_2GBIT; 208662306a36Sopenharmony_ci break; 208762306a36Sopenharmony_ci case QLAFX00_PORT_SPEED_4G: 208862306a36Sopenharmony_ci speed = FC_PORTSPEED_4GBIT; 208962306a36Sopenharmony_ci break; 209062306a36Sopenharmony_ci case QLAFX00_PORT_SPEED_8G: 209162306a36Sopenharmony_ci speed = FC_PORTSPEED_8GBIT; 209262306a36Sopenharmony_ci break; 209362306a36Sopenharmony_ci case QLAFX00_PORT_SPEED_10G: 209462306a36Sopenharmony_ci speed = FC_PORTSPEED_10GBIT; 209562306a36Sopenharmony_ci break; 209662306a36Sopenharmony_ci } 209762306a36Sopenharmony_ci fc_host_speed(shost) = speed; 209862306a36Sopenharmony_ci} 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci/** QLAFX00 specific ISR implementation functions */ 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_cistatic inline void 210362306a36Sopenharmony_ciqlafx00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len, 210462306a36Sopenharmony_ci uint32_t sense_len, struct rsp_que *rsp, int res) 210562306a36Sopenharmony_ci{ 210662306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 210762306a36Sopenharmony_ci struct scsi_cmnd *cp = GET_CMD_SP(sp); 210862306a36Sopenharmony_ci uint32_t track_sense_len; 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci SET_FW_SENSE_LEN(sp, sense_len); 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci if (sense_len >= SCSI_SENSE_BUFFERSIZE) 211362306a36Sopenharmony_ci sense_len = SCSI_SENSE_BUFFERSIZE; 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci SET_CMD_SENSE_LEN(sp, sense_len); 211662306a36Sopenharmony_ci SET_CMD_SENSE_PTR(sp, cp->sense_buffer); 211762306a36Sopenharmony_ci track_sense_len = sense_len; 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci if (sense_len > par_sense_len) 212062306a36Sopenharmony_ci sense_len = par_sense_len; 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci memcpy(cp->sense_buffer, sense_data, sense_len); 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci SET_FW_SENSE_LEN(sp, GET_FW_SENSE_LEN(sp) - sense_len); 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len); 212762306a36Sopenharmony_ci track_sense_len -= sense_len; 212862306a36Sopenharmony_ci SET_CMD_SENSE_LEN(sp, track_sense_len); 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x304d, 213162306a36Sopenharmony_ci "sense_len=0x%x par_sense_len=0x%x track_sense_len=0x%x.\n", 213262306a36Sopenharmony_ci sense_len, par_sense_len, track_sense_len); 213362306a36Sopenharmony_ci if (GET_FW_SENSE_LEN(sp) > 0) { 213462306a36Sopenharmony_ci rsp->status_srb = sp; 213562306a36Sopenharmony_ci cp->result = res; 213662306a36Sopenharmony_ci } 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci if (sense_len) { 213962306a36Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3039, 214062306a36Sopenharmony_ci "Check condition Sense data, nexus%ld:%d:%llu cmd=%p.\n", 214162306a36Sopenharmony_ci sp->vha->host_no, cp->device->id, cp->device->lun, 214262306a36Sopenharmony_ci cp); 214362306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3049, 214462306a36Sopenharmony_ci cp->sense_buffer, sense_len); 214562306a36Sopenharmony_ci } 214662306a36Sopenharmony_ci} 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_cistatic void 214962306a36Sopenharmony_ciqlafx00_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, 215062306a36Sopenharmony_ci struct tsk_mgmt_entry_fx00 *pkt, srb_t *sp, 215162306a36Sopenharmony_ci __le16 sstatus, __le16 cpstatus) 215262306a36Sopenharmony_ci{ 215362306a36Sopenharmony_ci struct srb_iocb *tmf; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci tmf = &sp->u.iocb_cmd; 215662306a36Sopenharmony_ci if (cpstatus != cpu_to_le16((uint16_t)CS_COMPLETE) || 215762306a36Sopenharmony_ci (sstatus & cpu_to_le16((uint16_t)SS_RESPONSE_INFO_LEN_VALID))) 215862306a36Sopenharmony_ci cpstatus = cpu_to_le16((uint16_t)CS_INCOMPLETE); 215962306a36Sopenharmony_ci tmf->u.tmf.comp_status = cpstatus; 216062306a36Sopenharmony_ci sp->done(sp, 0); 216162306a36Sopenharmony_ci} 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_cistatic void 216462306a36Sopenharmony_ciqlafx00_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, 216562306a36Sopenharmony_ci struct abort_iocb_entry_fx00 *pkt) 216662306a36Sopenharmony_ci{ 216762306a36Sopenharmony_ci const char func[] = "ABT_IOCB"; 216862306a36Sopenharmony_ci srb_t *sp; 216962306a36Sopenharmony_ci struct srb_iocb *abt; 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); 217262306a36Sopenharmony_ci if (!sp) 217362306a36Sopenharmony_ci return; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci abt = &sp->u.iocb_cmd; 217662306a36Sopenharmony_ci abt->u.abt.comp_status = pkt->tgt_id_sts; 217762306a36Sopenharmony_ci sp->done(sp, 0); 217862306a36Sopenharmony_ci} 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_cistatic void 218162306a36Sopenharmony_ciqlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req, 218262306a36Sopenharmony_ci struct ioctl_iocb_entry_fx00 *pkt) 218362306a36Sopenharmony_ci{ 218462306a36Sopenharmony_ci const char func[] = "IOSB_IOCB"; 218562306a36Sopenharmony_ci srb_t *sp; 218662306a36Sopenharmony_ci struct bsg_job *bsg_job; 218762306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply; 218862306a36Sopenharmony_ci struct srb_iocb *iocb_job; 218962306a36Sopenharmony_ci int res = 0; 219062306a36Sopenharmony_ci struct qla_mt_iocb_rsp_fx00 fstatus; 219162306a36Sopenharmony_ci uint8_t *fw_sts_ptr; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); 219462306a36Sopenharmony_ci if (!sp) 219562306a36Sopenharmony_ci return; 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci if (sp->type == SRB_FXIOCB_DCMD) { 219862306a36Sopenharmony_ci iocb_job = &sp->u.iocb_cmd; 219962306a36Sopenharmony_ci iocb_job->u.fxiocb.seq_number = pkt->seq_no; 220062306a36Sopenharmony_ci iocb_job->u.fxiocb.fw_flags = pkt->fw_iotcl_flags; 220162306a36Sopenharmony_ci iocb_job->u.fxiocb.result = pkt->status; 220262306a36Sopenharmony_ci if (iocb_job->u.fxiocb.flags & SRB_FXDISC_RSP_DWRD_VALID) 220362306a36Sopenharmony_ci iocb_job->u.fxiocb.req_data = 220462306a36Sopenharmony_ci pkt->dataword_r; 220562306a36Sopenharmony_ci } else { 220662306a36Sopenharmony_ci bsg_job = sp->u.bsg_job; 220762306a36Sopenharmony_ci bsg_reply = bsg_job->reply; 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci memset(&fstatus, 0, sizeof(struct qla_mt_iocb_rsp_fx00)); 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci fstatus.reserved_1 = pkt->reserved_0; 221262306a36Sopenharmony_ci fstatus.func_type = pkt->comp_func_num; 221362306a36Sopenharmony_ci fstatus.ioctl_flags = pkt->fw_iotcl_flags; 221462306a36Sopenharmony_ci fstatus.ioctl_data = pkt->dataword_r; 221562306a36Sopenharmony_ci fstatus.adapid = pkt->adapid; 221662306a36Sopenharmony_ci fstatus.reserved_2 = pkt->dataword_r_extra; 221762306a36Sopenharmony_ci fstatus.res_count = pkt->residuallen; 221862306a36Sopenharmony_ci fstatus.status = pkt->status; 221962306a36Sopenharmony_ci fstatus.seq_number = pkt->seq_no; 222062306a36Sopenharmony_ci memcpy(fstatus.reserved_3, 222162306a36Sopenharmony_ci pkt->reserved_2, 20 * sizeof(uint8_t)); 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci fw_sts_ptr = bsg_job->reply + sizeof(struct fc_bsg_reply); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci memcpy(fw_sts_ptr, &fstatus, sizeof(fstatus)); 222662306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply) + 222762306a36Sopenharmony_ci sizeof(struct qla_mt_iocb_rsp_fx00) + sizeof(uint8_t); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, 223062306a36Sopenharmony_ci sp->vha, 0x5080, pkt, sizeof(*pkt)); 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, 223362306a36Sopenharmony_ci sp->vha, 0x5074, 223462306a36Sopenharmony_ci fw_sts_ptr, sizeof(fstatus)); 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci res = bsg_reply->result = DID_OK << 16; 223762306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 223862306a36Sopenharmony_ci bsg_job->reply_payload.payload_len; 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci sp->done(sp, res); 224162306a36Sopenharmony_ci} 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci/** 224462306a36Sopenharmony_ci * qlafx00_status_entry() - Process a Status IOCB entry. 224562306a36Sopenharmony_ci * @vha: SCSI driver HA context 224662306a36Sopenharmony_ci * @rsp: response queue 224762306a36Sopenharmony_ci * @pkt: Entry pointer 224862306a36Sopenharmony_ci */ 224962306a36Sopenharmony_cistatic void 225062306a36Sopenharmony_ciqlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) 225162306a36Sopenharmony_ci{ 225262306a36Sopenharmony_ci srb_t *sp; 225362306a36Sopenharmony_ci fc_port_t *fcport; 225462306a36Sopenharmony_ci struct scsi_cmnd *cp; 225562306a36Sopenharmony_ci struct sts_entry_fx00 *sts; 225662306a36Sopenharmony_ci __le16 comp_status; 225762306a36Sopenharmony_ci __le16 scsi_status; 225862306a36Sopenharmony_ci __le16 lscsi_status; 225962306a36Sopenharmony_ci int32_t resid; 226062306a36Sopenharmony_ci uint32_t sense_len, par_sense_len, rsp_info_len, resid_len, 226162306a36Sopenharmony_ci fw_resid_len; 226262306a36Sopenharmony_ci uint8_t *rsp_info = NULL, *sense_data = NULL; 226362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 226462306a36Sopenharmony_ci uint32_t hindex, handle; 226562306a36Sopenharmony_ci uint16_t que; 226662306a36Sopenharmony_ci struct req_que *req; 226762306a36Sopenharmony_ci int logit = 1; 226862306a36Sopenharmony_ci int res = 0; 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci sts = (struct sts_entry_fx00 *) pkt; 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci comp_status = sts->comp_status; 227362306a36Sopenharmony_ci scsi_status = sts->scsi_status & cpu_to_le16((uint16_t)SS_MASK); 227462306a36Sopenharmony_ci hindex = sts->handle; 227562306a36Sopenharmony_ci handle = LSW(hindex); 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci que = MSW(hindex); 227862306a36Sopenharmony_ci req = ha->req_q_map[que]; 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci /* Validate handle. */ 228162306a36Sopenharmony_ci if (handle < req->num_outstanding_cmds) 228262306a36Sopenharmony_ci sp = req->outstanding_cmds[handle]; 228362306a36Sopenharmony_ci else 228462306a36Sopenharmony_ci sp = NULL; 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci if (sp == NULL) { 228762306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3034, 228862306a36Sopenharmony_ci "Invalid status handle (0x%x).\n", handle); 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 229162306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 229262306a36Sopenharmony_ci return; 229362306a36Sopenharmony_ci } 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci if (sp->type == SRB_TM_CMD) { 229662306a36Sopenharmony_ci req->outstanding_cmds[handle] = NULL; 229762306a36Sopenharmony_ci qlafx00_tm_iocb_entry(vha, req, pkt, sp, 229862306a36Sopenharmony_ci scsi_status, comp_status); 229962306a36Sopenharmony_ci return; 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci /* Fast path completion. */ 230362306a36Sopenharmony_ci if (comp_status == CS_COMPLETE && scsi_status == 0) { 230462306a36Sopenharmony_ci qla2x00_process_completed_request(vha, req, handle); 230562306a36Sopenharmony_ci return; 230662306a36Sopenharmony_ci } 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci req->outstanding_cmds[handle] = NULL; 230962306a36Sopenharmony_ci cp = GET_CMD_SP(sp); 231062306a36Sopenharmony_ci if (cp == NULL) { 231162306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3048, 231262306a36Sopenharmony_ci "Command already returned (0x%x/%p).\n", 231362306a36Sopenharmony_ci handle, sp); 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci return; 231662306a36Sopenharmony_ci } 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci lscsi_status = scsi_status & cpu_to_le16((uint16_t)STATUS_MASK); 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci fcport = sp->fcport; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci sense_len = par_sense_len = rsp_info_len = resid_len = 232362306a36Sopenharmony_ci fw_resid_len = 0; 232462306a36Sopenharmony_ci if (scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID)) 232562306a36Sopenharmony_ci sense_len = sts->sense_len; 232662306a36Sopenharmony_ci if (scsi_status & cpu_to_le16(((uint16_t)SS_RESIDUAL_UNDER 232762306a36Sopenharmony_ci | (uint16_t)SS_RESIDUAL_OVER))) 232862306a36Sopenharmony_ci resid_len = le32_to_cpu(sts->residual_len); 232962306a36Sopenharmony_ci if (comp_status == cpu_to_le16((uint16_t)CS_DATA_UNDERRUN)) 233062306a36Sopenharmony_ci fw_resid_len = le32_to_cpu(sts->residual_len); 233162306a36Sopenharmony_ci rsp_info = sense_data = sts->data; 233262306a36Sopenharmony_ci par_sense_len = sizeof(sts->data); 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci /* Check for overrun. */ 233562306a36Sopenharmony_ci if (comp_status == CS_COMPLETE && 233662306a36Sopenharmony_ci scsi_status & cpu_to_le16((uint16_t)SS_RESIDUAL_OVER)) 233762306a36Sopenharmony_ci comp_status = cpu_to_le16((uint16_t)CS_DATA_OVERRUN); 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci /* 234062306a36Sopenharmony_ci * Based on Host and scsi status generate status code for Linux 234162306a36Sopenharmony_ci */ 234262306a36Sopenharmony_ci switch (le16_to_cpu(comp_status)) { 234362306a36Sopenharmony_ci case CS_COMPLETE: 234462306a36Sopenharmony_ci case CS_QUEUE_FULL: 234562306a36Sopenharmony_ci if (scsi_status == 0) { 234662306a36Sopenharmony_ci res = DID_OK << 16; 234762306a36Sopenharmony_ci break; 234862306a36Sopenharmony_ci } 234962306a36Sopenharmony_ci if (scsi_status & cpu_to_le16(((uint16_t)SS_RESIDUAL_UNDER 235062306a36Sopenharmony_ci | (uint16_t)SS_RESIDUAL_OVER))) { 235162306a36Sopenharmony_ci resid = resid_len; 235262306a36Sopenharmony_ci scsi_set_resid(cp, resid); 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci if (!lscsi_status && 235562306a36Sopenharmony_ci ((unsigned)(scsi_bufflen(cp) - resid) < 235662306a36Sopenharmony_ci cp->underflow)) { 235762306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3050, 235862306a36Sopenharmony_ci "Mid-layer underflow " 235962306a36Sopenharmony_ci "detected (0x%x of 0x%x bytes).\n", 236062306a36Sopenharmony_ci resid, scsi_bufflen(cp)); 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci res = DID_ERROR << 16; 236362306a36Sopenharmony_ci break; 236462306a36Sopenharmony_ci } 236562306a36Sopenharmony_ci } 236662306a36Sopenharmony_ci res = DID_OK << 16 | le16_to_cpu(lscsi_status); 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci if (lscsi_status == 236962306a36Sopenharmony_ci cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL)) { 237062306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3051, 237162306a36Sopenharmony_ci "QUEUE FULL detected.\n"); 237262306a36Sopenharmony_ci break; 237362306a36Sopenharmony_ci } 237462306a36Sopenharmony_ci logit = 0; 237562306a36Sopenharmony_ci if (lscsi_status != cpu_to_le16((uint16_t)SS_CHECK_CONDITION)) 237662306a36Sopenharmony_ci break; 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 237962306a36Sopenharmony_ci if (!(scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID))) 238062306a36Sopenharmony_ci break; 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci qlafx00_handle_sense(sp, sense_data, par_sense_len, sense_len, 238362306a36Sopenharmony_ci rsp, res); 238462306a36Sopenharmony_ci break; 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci case CS_DATA_UNDERRUN: 238762306a36Sopenharmony_ci /* Use F/W calculated residual length. */ 238862306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha)) 238962306a36Sopenharmony_ci resid = fw_resid_len; 239062306a36Sopenharmony_ci else 239162306a36Sopenharmony_ci resid = resid_len; 239262306a36Sopenharmony_ci scsi_set_resid(cp, resid); 239362306a36Sopenharmony_ci if (scsi_status & cpu_to_le16((uint16_t)SS_RESIDUAL_UNDER)) { 239462306a36Sopenharmony_ci if ((IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha)) 239562306a36Sopenharmony_ci && fw_resid_len != resid_len) { 239662306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3052, 239762306a36Sopenharmony_ci "Dropped frame(s) detected " 239862306a36Sopenharmony_ci "(0x%x of 0x%x bytes).\n", 239962306a36Sopenharmony_ci resid, scsi_bufflen(cp)); 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci res = DID_ERROR << 16 | 240262306a36Sopenharmony_ci le16_to_cpu(lscsi_status); 240362306a36Sopenharmony_ci goto check_scsi_status; 240462306a36Sopenharmony_ci } 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci if (!lscsi_status && 240762306a36Sopenharmony_ci ((unsigned)(scsi_bufflen(cp) - resid) < 240862306a36Sopenharmony_ci cp->underflow)) { 240962306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3053, 241062306a36Sopenharmony_ci "Mid-layer underflow " 241162306a36Sopenharmony_ci "detected (0x%x of 0x%x bytes, " 241262306a36Sopenharmony_ci "cp->underflow: 0x%x).\n", 241362306a36Sopenharmony_ci resid, scsi_bufflen(cp), cp->underflow); 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci res = DID_ERROR << 16; 241662306a36Sopenharmony_ci break; 241762306a36Sopenharmony_ci } 241862306a36Sopenharmony_ci } else if (lscsi_status != 241962306a36Sopenharmony_ci cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL) && 242062306a36Sopenharmony_ci lscsi_status != cpu_to_le16((uint16_t)SAM_STAT_BUSY)) { 242162306a36Sopenharmony_ci /* 242262306a36Sopenharmony_ci * scsi status of task set and busy are considered 242362306a36Sopenharmony_ci * to be task not completed. 242462306a36Sopenharmony_ci */ 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3054, 242762306a36Sopenharmony_ci "Dropped frame(s) detected (0x%x " 242862306a36Sopenharmony_ci "of 0x%x bytes).\n", resid, 242962306a36Sopenharmony_ci scsi_bufflen(cp)); 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci res = DID_ERROR << 16 | le16_to_cpu(lscsi_status); 243262306a36Sopenharmony_ci goto check_scsi_status; 243362306a36Sopenharmony_ci } else { 243462306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3055, 243562306a36Sopenharmony_ci "scsi_status: 0x%x, lscsi_status: 0x%x\n", 243662306a36Sopenharmony_ci scsi_status, lscsi_status); 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci res = DID_OK << 16 | le16_to_cpu(lscsi_status); 244062306a36Sopenharmony_ci logit = 0; 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_cicheck_scsi_status: 244362306a36Sopenharmony_ci /* 244462306a36Sopenharmony_ci * Check to see if SCSI Status is non zero. If so report SCSI 244562306a36Sopenharmony_ci * Status. 244662306a36Sopenharmony_ci */ 244762306a36Sopenharmony_ci if (lscsi_status != 0) { 244862306a36Sopenharmony_ci if (lscsi_status == 244962306a36Sopenharmony_ci cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL)) { 245062306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3056, 245162306a36Sopenharmony_ci "QUEUE FULL detected.\n"); 245262306a36Sopenharmony_ci logit = 1; 245362306a36Sopenharmony_ci break; 245462306a36Sopenharmony_ci } 245562306a36Sopenharmony_ci if (lscsi_status != 245662306a36Sopenharmony_ci cpu_to_le16((uint16_t)SS_CHECK_CONDITION)) 245762306a36Sopenharmony_ci break; 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 246062306a36Sopenharmony_ci if (!(scsi_status & 246162306a36Sopenharmony_ci cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID))) 246262306a36Sopenharmony_ci break; 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci qlafx00_handle_sense(sp, sense_data, par_sense_len, 246562306a36Sopenharmony_ci sense_len, rsp, res); 246662306a36Sopenharmony_ci } 246762306a36Sopenharmony_ci break; 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci case CS_PORT_LOGGED_OUT: 247062306a36Sopenharmony_ci case CS_PORT_CONFIG_CHG: 247162306a36Sopenharmony_ci case CS_PORT_BUSY: 247262306a36Sopenharmony_ci case CS_INCOMPLETE: 247362306a36Sopenharmony_ci case CS_PORT_UNAVAILABLE: 247462306a36Sopenharmony_ci case CS_TIMEOUT: 247562306a36Sopenharmony_ci case CS_RESET: 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci /* 247862306a36Sopenharmony_ci * We are going to have the fc class block the rport 247962306a36Sopenharmony_ci * while we try to recover so instruct the mid layer 248062306a36Sopenharmony_ci * to requeue until the class decides how to handle this. 248162306a36Sopenharmony_ci */ 248262306a36Sopenharmony_ci res = DID_TRANSPORT_DISRUPTED << 16; 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3057, 248562306a36Sopenharmony_ci "Port down status: port-state=0x%x.\n", 248662306a36Sopenharmony_ci atomic_read(&fcport->state)); 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci if (atomic_read(&fcport->state) == FCS_ONLINE) 248962306a36Sopenharmony_ci qla2x00_mark_device_lost(fcport->vha, fcport, 1); 249062306a36Sopenharmony_ci break; 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci case CS_ABORTED: 249362306a36Sopenharmony_ci res = DID_RESET << 16; 249462306a36Sopenharmony_ci break; 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci default: 249762306a36Sopenharmony_ci res = DID_ERROR << 16; 249862306a36Sopenharmony_ci break; 249962306a36Sopenharmony_ci } 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci if (logit) 250262306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3058, 250362306a36Sopenharmony_ci "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu " 250462306a36Sopenharmony_ci "tgt_id: 0x%x lscsi_status: 0x%x cdb=%10phN len=0x%x " 250562306a36Sopenharmony_ci "rsp_info=%p resid=0x%x fw_resid=0x%x sense_len=0x%x, " 250662306a36Sopenharmony_ci "par_sense_len=0x%x, rsp_info_len=0x%x\n", 250762306a36Sopenharmony_ci comp_status, scsi_status, res, vha->host_no, 250862306a36Sopenharmony_ci cp->device->id, cp->device->lun, fcport->tgt_id, 250962306a36Sopenharmony_ci lscsi_status, cp->cmnd, scsi_bufflen(cp), 251062306a36Sopenharmony_ci rsp_info, resid_len, fw_resid_len, sense_len, 251162306a36Sopenharmony_ci par_sense_len, rsp_info_len); 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci if (rsp->status_srb == NULL) 251462306a36Sopenharmony_ci sp->done(sp, res); 251562306a36Sopenharmony_ci else 251662306a36Sopenharmony_ci WARN_ON_ONCE(true); 251762306a36Sopenharmony_ci} 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci/** 252062306a36Sopenharmony_ci * qlafx00_status_cont_entry() - Process a Status Continuations entry. 252162306a36Sopenharmony_ci * @rsp: response queue 252262306a36Sopenharmony_ci * @pkt: Entry pointer 252362306a36Sopenharmony_ci * 252462306a36Sopenharmony_ci * Extended sense data. 252562306a36Sopenharmony_ci */ 252662306a36Sopenharmony_cistatic void 252762306a36Sopenharmony_ciqlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) 252862306a36Sopenharmony_ci{ 252962306a36Sopenharmony_ci uint8_t sense_sz = 0; 253062306a36Sopenharmony_ci struct qla_hw_data *ha = rsp->hw; 253162306a36Sopenharmony_ci struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev); 253262306a36Sopenharmony_ci srb_t *sp = rsp->status_srb; 253362306a36Sopenharmony_ci struct scsi_cmnd *cp; 253462306a36Sopenharmony_ci uint32_t sense_len; 253562306a36Sopenharmony_ci uint8_t *sense_ptr; 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci if (!sp) { 253862306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3037, 253962306a36Sopenharmony_ci "no SP, sp = %p\n", sp); 254062306a36Sopenharmony_ci return; 254162306a36Sopenharmony_ci } 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci if (!GET_FW_SENSE_LEN(sp)) { 254462306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x304b, 254562306a36Sopenharmony_ci "no fw sense data, sp = %p\n", sp); 254662306a36Sopenharmony_ci return; 254762306a36Sopenharmony_ci } 254862306a36Sopenharmony_ci cp = GET_CMD_SP(sp); 254962306a36Sopenharmony_ci if (cp == NULL) { 255062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x303b, 255162306a36Sopenharmony_ci "cmd is NULL: already returned to OS (sp=%p).\n", sp); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci rsp->status_srb = NULL; 255462306a36Sopenharmony_ci return; 255562306a36Sopenharmony_ci } 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci if (!GET_CMD_SENSE_LEN(sp)) { 255862306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x304c, 255962306a36Sopenharmony_ci "no sense data, sp = %p\n", sp); 256062306a36Sopenharmony_ci } else { 256162306a36Sopenharmony_ci sense_len = GET_CMD_SENSE_LEN(sp); 256262306a36Sopenharmony_ci sense_ptr = GET_CMD_SENSE_PTR(sp); 256362306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x304f, 256462306a36Sopenharmony_ci "sp=%p sense_len=0x%x sense_ptr=%p.\n", 256562306a36Sopenharmony_ci sp, sense_len, sense_ptr); 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci if (sense_len > sizeof(pkt->data)) 256862306a36Sopenharmony_ci sense_sz = sizeof(pkt->data); 256962306a36Sopenharmony_ci else 257062306a36Sopenharmony_ci sense_sz = sense_len; 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci /* Move sense data. */ 257362306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304e, 257462306a36Sopenharmony_ci pkt, sizeof(*pkt)); 257562306a36Sopenharmony_ci memcpy(sense_ptr, pkt->data, sense_sz); 257662306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304a, 257762306a36Sopenharmony_ci sense_ptr, sense_sz); 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci sense_len -= sense_sz; 258062306a36Sopenharmony_ci sense_ptr += sense_sz; 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci SET_CMD_SENSE_PTR(sp, sense_ptr); 258362306a36Sopenharmony_ci SET_CMD_SENSE_LEN(sp, sense_len); 258462306a36Sopenharmony_ci } 258562306a36Sopenharmony_ci sense_len = GET_FW_SENSE_LEN(sp); 258662306a36Sopenharmony_ci sense_len = (sense_len > sizeof(pkt->data)) ? 258762306a36Sopenharmony_ci (sense_len - sizeof(pkt->data)) : 0; 258862306a36Sopenharmony_ci SET_FW_SENSE_LEN(sp, sense_len); 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci /* Place command on done queue. */ 259162306a36Sopenharmony_ci if (sense_len == 0) { 259262306a36Sopenharmony_ci rsp->status_srb = NULL; 259362306a36Sopenharmony_ci sp->done(sp, cp->result); 259462306a36Sopenharmony_ci } else { 259562306a36Sopenharmony_ci WARN_ON_ONCE(true); 259662306a36Sopenharmony_ci } 259762306a36Sopenharmony_ci} 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci/** 260062306a36Sopenharmony_ci * qlafx00_multistatus_entry() - Process Multi response queue entries. 260162306a36Sopenharmony_ci * @vha: SCSI driver HA context 260262306a36Sopenharmony_ci * @rsp: response queue 260362306a36Sopenharmony_ci * @pkt: received packet 260462306a36Sopenharmony_ci */ 260562306a36Sopenharmony_cistatic void 260662306a36Sopenharmony_ciqlafx00_multistatus_entry(struct scsi_qla_host *vha, 260762306a36Sopenharmony_ci struct rsp_que *rsp, void *pkt) 260862306a36Sopenharmony_ci{ 260962306a36Sopenharmony_ci srb_t *sp; 261062306a36Sopenharmony_ci struct multi_sts_entry_fx00 *stsmfx; 261162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 261262306a36Sopenharmony_ci uint32_t handle, hindex, handle_count, i; 261362306a36Sopenharmony_ci uint16_t que; 261462306a36Sopenharmony_ci struct req_que *req; 261562306a36Sopenharmony_ci __le32 *handle_ptr; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci stsmfx = (struct multi_sts_entry_fx00 *) pkt; 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci handle_count = stsmfx->handle_count; 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci if (handle_count > MAX_HANDLE_COUNT) { 262262306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3035, 262362306a36Sopenharmony_ci "Invalid handle count (0x%x).\n", handle_count); 262462306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 262562306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 262662306a36Sopenharmony_ci return; 262762306a36Sopenharmony_ci } 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci handle_ptr = &stsmfx->handles[0]; 263062306a36Sopenharmony_ci 263162306a36Sopenharmony_ci for (i = 0; i < handle_count; i++) { 263262306a36Sopenharmony_ci hindex = le32_to_cpu(*handle_ptr); 263362306a36Sopenharmony_ci handle = LSW(hindex); 263462306a36Sopenharmony_ci que = MSW(hindex); 263562306a36Sopenharmony_ci req = ha->req_q_map[que]; 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_ci /* Validate handle. */ 263862306a36Sopenharmony_ci if (handle < req->num_outstanding_cmds) 263962306a36Sopenharmony_ci sp = req->outstanding_cmds[handle]; 264062306a36Sopenharmony_ci else 264162306a36Sopenharmony_ci sp = NULL; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci if (sp == NULL) { 264462306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3044, 264562306a36Sopenharmony_ci "Invalid status handle (0x%x).\n", handle); 264662306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 264762306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 264862306a36Sopenharmony_ci return; 264962306a36Sopenharmony_ci } 265062306a36Sopenharmony_ci qla2x00_process_completed_request(vha, req, handle); 265162306a36Sopenharmony_ci handle_ptr++; 265262306a36Sopenharmony_ci } 265362306a36Sopenharmony_ci} 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci/** 265662306a36Sopenharmony_ci * qlafx00_error_entry() - Process an error entry. 265762306a36Sopenharmony_ci * @vha: SCSI driver HA context 265862306a36Sopenharmony_ci * @rsp: response queue 265962306a36Sopenharmony_ci * @pkt: Entry pointer 266062306a36Sopenharmony_ci */ 266162306a36Sopenharmony_cistatic void 266262306a36Sopenharmony_ciqlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, 266362306a36Sopenharmony_ci struct sts_entry_fx00 *pkt) 266462306a36Sopenharmony_ci{ 266562306a36Sopenharmony_ci srb_t *sp; 266662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 266762306a36Sopenharmony_ci const char func[] = "ERROR-IOCB"; 266862306a36Sopenharmony_ci uint16_t que = 0; 266962306a36Sopenharmony_ci struct req_que *req = NULL; 267062306a36Sopenharmony_ci int res = DID_ERROR << 16; 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci req = ha->req_q_map[que]; 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); 267562306a36Sopenharmony_ci if (sp) { 267662306a36Sopenharmony_ci sp->done(sp, res); 267762306a36Sopenharmony_ci return; 267862306a36Sopenharmony_ci } 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 268162306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 268262306a36Sopenharmony_ci} 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci/** 268562306a36Sopenharmony_ci * qlafx00_process_response_queue() - Process response queue entries. 268662306a36Sopenharmony_ci * @vha: SCSI driver HA context 268762306a36Sopenharmony_ci * @rsp: response queue 268862306a36Sopenharmony_ci */ 268962306a36Sopenharmony_cistatic void 269062306a36Sopenharmony_ciqlafx00_process_response_queue(struct scsi_qla_host *vha, 269162306a36Sopenharmony_ci struct rsp_que *rsp) 269262306a36Sopenharmony_ci{ 269362306a36Sopenharmony_ci struct sts_entry_fx00 *pkt; 269462306a36Sopenharmony_ci response_t *lptr; 269562306a36Sopenharmony_ci uint16_t lreq_q_in = 0; 269662306a36Sopenharmony_ci uint16_t lreq_q_out = 0; 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci lreq_q_in = rd_reg_dword(rsp->rsp_q_in); 269962306a36Sopenharmony_ci lreq_q_out = rsp->ring_index; 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci while (lreq_q_in != lreq_q_out) { 270262306a36Sopenharmony_ci lptr = rsp->ring_ptr; 270362306a36Sopenharmony_ci memcpy_fromio(rsp->rsp_pkt, (void __iomem *)lptr, 270462306a36Sopenharmony_ci sizeof(rsp->rsp_pkt)); 270562306a36Sopenharmony_ci pkt = (struct sts_entry_fx00 *)rsp->rsp_pkt; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci rsp->ring_index++; 270862306a36Sopenharmony_ci lreq_q_out++; 270962306a36Sopenharmony_ci if (rsp->ring_index == rsp->length) { 271062306a36Sopenharmony_ci lreq_q_out = 0; 271162306a36Sopenharmony_ci rsp->ring_index = 0; 271262306a36Sopenharmony_ci rsp->ring_ptr = rsp->ring; 271362306a36Sopenharmony_ci } else { 271462306a36Sopenharmony_ci rsp->ring_ptr++; 271562306a36Sopenharmony_ci } 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci if (pkt->entry_status != 0 && 271862306a36Sopenharmony_ci pkt->entry_type != IOCTL_IOSB_TYPE_FX00) { 271962306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x507f, 272062306a36Sopenharmony_ci "type of error status in response: 0x%x\n", 272162306a36Sopenharmony_ci pkt->entry_status); 272262306a36Sopenharmony_ci qlafx00_error_entry(vha, rsp, 272362306a36Sopenharmony_ci (struct sts_entry_fx00 *)pkt); 272462306a36Sopenharmony_ci continue; 272562306a36Sopenharmony_ci } 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci switch (pkt->entry_type) { 272862306a36Sopenharmony_ci case STATUS_TYPE_FX00: 272962306a36Sopenharmony_ci qlafx00_status_entry(vha, rsp, pkt); 273062306a36Sopenharmony_ci break; 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci case STATUS_CONT_TYPE_FX00: 273362306a36Sopenharmony_ci qlafx00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); 273462306a36Sopenharmony_ci break; 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci case MULTI_STATUS_TYPE_FX00: 273762306a36Sopenharmony_ci qlafx00_multistatus_entry(vha, rsp, pkt); 273862306a36Sopenharmony_ci break; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci case ABORT_IOCB_TYPE_FX00: 274162306a36Sopenharmony_ci qlafx00_abort_iocb_entry(vha, rsp->req, 274262306a36Sopenharmony_ci (struct abort_iocb_entry_fx00 *)pkt); 274362306a36Sopenharmony_ci break; 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci case IOCTL_IOSB_TYPE_FX00: 274662306a36Sopenharmony_ci qlafx00_ioctl_iosb_entry(vha, rsp->req, 274762306a36Sopenharmony_ci (struct ioctl_iocb_entry_fx00 *)pkt); 274862306a36Sopenharmony_ci break; 274962306a36Sopenharmony_ci default: 275062306a36Sopenharmony_ci /* Type Not Supported. */ 275162306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5081, 275262306a36Sopenharmony_ci "Received unknown response pkt type %x " 275362306a36Sopenharmony_ci "entry status=%x.\n", 275462306a36Sopenharmony_ci pkt->entry_type, pkt->entry_status); 275562306a36Sopenharmony_ci break; 275662306a36Sopenharmony_ci } 275762306a36Sopenharmony_ci } 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci /* Adjust ring index */ 276062306a36Sopenharmony_ci wrt_reg_dword(rsp->rsp_q_out, rsp->ring_index); 276162306a36Sopenharmony_ci} 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci/** 276462306a36Sopenharmony_ci * qlafx00_async_event() - Process aynchronous events. 276562306a36Sopenharmony_ci * @vha: SCSI driver HA context 276662306a36Sopenharmony_ci */ 276762306a36Sopenharmony_cistatic void 276862306a36Sopenharmony_ciqlafx00_async_event(scsi_qla_host_t *vha) 276962306a36Sopenharmony_ci{ 277062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 277162306a36Sopenharmony_ci struct device_reg_fx00 __iomem *reg; 277262306a36Sopenharmony_ci int data_size = 1; 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci reg = &ha->iobase->ispfx00; 277562306a36Sopenharmony_ci /* Setup to process RIO completion. */ 277662306a36Sopenharmony_ci switch (ha->aenmb[0]) { 277762306a36Sopenharmony_ci case QLAFX00_MBA_SYSTEM_ERR: /* System Error */ 277862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5079, 277962306a36Sopenharmony_ci "ISP System Error - mbx1=%x\n", ha->aenmb[0]); 278062306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 278162306a36Sopenharmony_ci break; 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci case QLAFX00_MBA_SHUTDOWN_RQSTD: /* Shutdown requested */ 278462306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5076, 278562306a36Sopenharmony_ci "Asynchronous FW shutdown requested.\n"); 278662306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 278762306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 278862306a36Sopenharmony_ci break; 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci case QLAFX00_MBA_PORT_UPDATE: /* Port database update */ 279162306a36Sopenharmony_ci ha->aenmb[1] = rd_reg_dword(®->aenmailbox1); 279262306a36Sopenharmony_ci ha->aenmb[2] = rd_reg_dword(®->aenmailbox2); 279362306a36Sopenharmony_ci ha->aenmb[3] = rd_reg_dword(®->aenmailbox3); 279462306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5077, 279562306a36Sopenharmony_ci "Asynchronous port Update received " 279662306a36Sopenharmony_ci "aenmb[0]: %x, aenmb[1]: %x, aenmb[2]: %x, aenmb[3]: %x\n", 279762306a36Sopenharmony_ci ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3]); 279862306a36Sopenharmony_ci data_size = 4; 279962306a36Sopenharmony_ci break; 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ci case QLAFX00_MBA_TEMP_OVER: /* Over temperature event */ 280262306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x5085, 280362306a36Sopenharmony_ci "Asynchronous over temperature event received " 280462306a36Sopenharmony_ci "aenmb[0]: %x\n", 280562306a36Sopenharmony_ci ha->aenmb[0]); 280662306a36Sopenharmony_ci break; 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci case QLAFX00_MBA_TEMP_NORM: /* Normal temperature event */ 280962306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x5086, 281062306a36Sopenharmony_ci "Asynchronous normal temperature event received " 281162306a36Sopenharmony_ci "aenmb[0]: %x\n", 281262306a36Sopenharmony_ci ha->aenmb[0]); 281362306a36Sopenharmony_ci break; 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci case QLAFX00_MBA_TEMP_CRIT: /* Critical temperature event */ 281662306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x5083, 281762306a36Sopenharmony_ci "Asynchronous critical temperature event received " 281862306a36Sopenharmony_ci "aenmb[0]: %x\n", 281962306a36Sopenharmony_ci ha->aenmb[0]); 282062306a36Sopenharmony_ci break; 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_ci default: 282362306a36Sopenharmony_ci ha->aenmb[1] = rd_reg_dword(®->aenmailbox1); 282462306a36Sopenharmony_ci ha->aenmb[2] = rd_reg_dword(®->aenmailbox2); 282562306a36Sopenharmony_ci ha->aenmb[3] = rd_reg_dword(®->aenmailbox3); 282662306a36Sopenharmony_ci ha->aenmb[4] = rd_reg_dword(®->aenmailbox4); 282762306a36Sopenharmony_ci ha->aenmb[5] = rd_reg_dword(®->aenmailbox5); 282862306a36Sopenharmony_ci ha->aenmb[6] = rd_reg_dword(®->aenmailbox6); 282962306a36Sopenharmony_ci ha->aenmb[7] = rd_reg_dword(®->aenmailbox7); 283062306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5078, 283162306a36Sopenharmony_ci "AEN:%04x %04x %04x %04x :%04x %04x %04x %04x\n", 283262306a36Sopenharmony_ci ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3], 283362306a36Sopenharmony_ci ha->aenmb[4], ha->aenmb[5], ha->aenmb[6], ha->aenmb[7]); 283462306a36Sopenharmony_ci break; 283562306a36Sopenharmony_ci } 283662306a36Sopenharmony_ci qlafx00_post_aenfx_work(vha, ha->aenmb[0], 283762306a36Sopenharmony_ci (uint32_t *)ha->aenmb, data_size); 283862306a36Sopenharmony_ci} 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci/** 284162306a36Sopenharmony_ci * qlafx00_mbx_completion() - Process mailbox command completions. 284262306a36Sopenharmony_ci * @vha: SCSI driver HA context 284362306a36Sopenharmony_ci * @mb0: value to be written into mailbox register 0 284462306a36Sopenharmony_ci */ 284562306a36Sopenharmony_cistatic void 284662306a36Sopenharmony_ciqlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0) 284762306a36Sopenharmony_ci{ 284862306a36Sopenharmony_ci uint16_t cnt; 284962306a36Sopenharmony_ci __le32 __iomem *wptr; 285062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 285162306a36Sopenharmony_ci struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00; 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci if (!ha->mcp32) 285462306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x507e, "MBX pointer ERROR.\n"); 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci /* Load return mailbox registers. */ 285762306a36Sopenharmony_ci ha->flags.mbox_int = 1; 285862306a36Sopenharmony_ci ha->mailbox_out32[0] = mb0; 285962306a36Sopenharmony_ci wptr = ®->mailbox17; 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci for (cnt = 1; cnt < ha->mbx_count; cnt++) { 286262306a36Sopenharmony_ci ha->mailbox_out32[cnt] = rd_reg_dword(wptr); 286362306a36Sopenharmony_ci wptr++; 286462306a36Sopenharmony_ci } 286562306a36Sopenharmony_ci} 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_ci/** 286862306a36Sopenharmony_ci * qlafx00_intr_handler() - Process interrupts for the ISPFX00. 286962306a36Sopenharmony_ci * @irq: interrupt number 287062306a36Sopenharmony_ci * @dev_id: SCSI driver HA context 287162306a36Sopenharmony_ci * 287262306a36Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt. 287362306a36Sopenharmony_ci * 287462306a36Sopenharmony_ci * Returns handled flag. 287562306a36Sopenharmony_ci */ 287662306a36Sopenharmony_ciirqreturn_t 287762306a36Sopenharmony_ciqlafx00_intr_handler(int irq, void *dev_id) 287862306a36Sopenharmony_ci{ 287962306a36Sopenharmony_ci scsi_qla_host_t *vha; 288062306a36Sopenharmony_ci struct qla_hw_data *ha; 288162306a36Sopenharmony_ci struct device_reg_fx00 __iomem *reg; 288262306a36Sopenharmony_ci int status; 288362306a36Sopenharmony_ci unsigned long iter; 288462306a36Sopenharmony_ci uint32_t stat; 288562306a36Sopenharmony_ci uint32_t mb[8]; 288662306a36Sopenharmony_ci struct rsp_que *rsp; 288762306a36Sopenharmony_ci unsigned long flags; 288862306a36Sopenharmony_ci uint32_t clr_intr = 0; 288962306a36Sopenharmony_ci uint32_t intr_stat = 0; 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci rsp = (struct rsp_que *) dev_id; 289262306a36Sopenharmony_ci if (!rsp) { 289362306a36Sopenharmony_ci ql_log(ql_log_info, NULL, 0x507d, 289462306a36Sopenharmony_ci "%s: NULL response queue pointer.\n", __func__); 289562306a36Sopenharmony_ci return IRQ_NONE; 289662306a36Sopenharmony_ci } 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci ha = rsp->hw; 289962306a36Sopenharmony_ci reg = &ha->iobase->ispfx00; 290062306a36Sopenharmony_ci status = 0; 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 290362306a36Sopenharmony_ci return IRQ_HANDLED; 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 290662306a36Sopenharmony_ci vha = pci_get_drvdata(ha->pdev); 290762306a36Sopenharmony_ci for (iter = 50; iter--; clr_intr = 0) { 290862306a36Sopenharmony_ci stat = QLAFX00_RD_INTR_REG(ha); 290962306a36Sopenharmony_ci if (qla2x00_check_reg32_for_disconnect(vha, stat)) 291062306a36Sopenharmony_ci break; 291162306a36Sopenharmony_ci intr_stat = stat & QLAFX00_HST_INT_STS_BITS; 291262306a36Sopenharmony_ci if (!intr_stat) 291362306a36Sopenharmony_ci break; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci if (stat & QLAFX00_INTR_MB_CMPLT) { 291662306a36Sopenharmony_ci mb[0] = rd_reg_dword(®->mailbox16); 291762306a36Sopenharmony_ci qlafx00_mbx_completion(vha, mb[0]); 291862306a36Sopenharmony_ci status |= MBX_INTERRUPT; 291962306a36Sopenharmony_ci clr_intr |= QLAFX00_INTR_MB_CMPLT; 292062306a36Sopenharmony_ci } 292162306a36Sopenharmony_ci if (intr_stat & QLAFX00_INTR_ASYNC_CMPLT) { 292262306a36Sopenharmony_ci ha->aenmb[0] = rd_reg_dword(®->aenmailbox0); 292362306a36Sopenharmony_ci qlafx00_async_event(vha); 292462306a36Sopenharmony_ci clr_intr |= QLAFX00_INTR_ASYNC_CMPLT; 292562306a36Sopenharmony_ci } 292662306a36Sopenharmony_ci if (intr_stat & QLAFX00_INTR_RSP_CMPLT) { 292762306a36Sopenharmony_ci qlafx00_process_response_queue(vha, rsp); 292862306a36Sopenharmony_ci clr_intr |= QLAFX00_INTR_RSP_CMPLT; 292962306a36Sopenharmony_ci } 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci QLAFX00_CLR_INTR_REG(ha, clr_intr); 293262306a36Sopenharmony_ci QLAFX00_RD_INTR_REG(ha); 293362306a36Sopenharmony_ci } 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_ci qla2x00_handle_mbx_completion(ha, status); 293662306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci return IRQ_HANDLED; 293962306a36Sopenharmony_ci} 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci/** QLAFX00 specific IOCB implementation functions */ 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_cistatic inline cont_a64_entry_t * 294462306a36Sopenharmony_ciqlafx00_prep_cont_type1_iocb(struct req_que *req, 294562306a36Sopenharmony_ci cont_a64_entry_t *lcont_pkt) 294662306a36Sopenharmony_ci{ 294762306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt; 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_ci /* Adjust ring index. */ 295062306a36Sopenharmony_ci req->ring_index++; 295162306a36Sopenharmony_ci if (req->ring_index == req->length) { 295262306a36Sopenharmony_ci req->ring_index = 0; 295362306a36Sopenharmony_ci req->ring_ptr = req->ring; 295462306a36Sopenharmony_ci } else { 295562306a36Sopenharmony_ci req->ring_ptr++; 295662306a36Sopenharmony_ci } 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci cont_pkt = (cont_a64_entry_t *)req->ring_ptr; 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_ci /* Load packet defaults. */ 296162306a36Sopenharmony_ci lcont_pkt->entry_type = CONTINUE_A64_TYPE_FX00; 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci return cont_pkt; 296462306a36Sopenharmony_ci} 296562306a36Sopenharmony_ci 296662306a36Sopenharmony_cistatic inline void 296762306a36Sopenharmony_ciqlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt, 296862306a36Sopenharmony_ci uint16_t tot_dsds, struct cmd_type_7_fx00 *lcmd_pkt) 296962306a36Sopenharmony_ci{ 297062306a36Sopenharmony_ci uint16_t avail_dsds; 297162306a36Sopenharmony_ci struct dsd64 *cur_dsd; 297262306a36Sopenharmony_ci scsi_qla_host_t *vha; 297362306a36Sopenharmony_ci struct scsi_cmnd *cmd; 297462306a36Sopenharmony_ci struct scatterlist *sg; 297562306a36Sopenharmony_ci int i, cont; 297662306a36Sopenharmony_ci struct req_que *req; 297762306a36Sopenharmony_ci cont_a64_entry_t lcont_pkt; 297862306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt; 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci vha = sp->vha; 298162306a36Sopenharmony_ci req = vha->req; 298262306a36Sopenharmony_ci 298362306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 298462306a36Sopenharmony_ci cont = 0; 298562306a36Sopenharmony_ci cont_pkt = NULL; 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci /* Update entry type to indicate Command Type 3 IOCB */ 298862306a36Sopenharmony_ci lcmd_pkt->entry_type = FX00_COMMAND_TYPE_7; 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci /* No data transfer */ 299162306a36Sopenharmony_ci if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { 299262306a36Sopenharmony_ci lcmd_pkt->byte_count = cpu_to_le32(0); 299362306a36Sopenharmony_ci return; 299462306a36Sopenharmony_ci } 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci /* Set transfer direction */ 299762306a36Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) { 299862306a36Sopenharmony_ci lcmd_pkt->cntrl_flags = TMF_WRITE_DATA; 299962306a36Sopenharmony_ci vha->qla_stats.output_bytes += scsi_bufflen(cmd); 300062306a36Sopenharmony_ci } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 300162306a36Sopenharmony_ci lcmd_pkt->cntrl_flags = TMF_READ_DATA; 300262306a36Sopenharmony_ci vha->qla_stats.input_bytes += scsi_bufflen(cmd); 300362306a36Sopenharmony_ci } 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci /* One DSD is available in the Command Type 3 IOCB */ 300662306a36Sopenharmony_ci avail_dsds = 1; 300762306a36Sopenharmony_ci cur_dsd = &lcmd_pkt->dsd; 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci /* Load data segments */ 301062306a36Sopenharmony_ci scsi_for_each_sg(cmd, sg, tot_dsds, i) { 301162306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 301262306a36Sopenharmony_ci if (avail_dsds == 0) { 301362306a36Sopenharmony_ci /* 301462306a36Sopenharmony_ci * Five DSDs are available in the Continuation 301562306a36Sopenharmony_ci * Type 1 IOCB. 301662306a36Sopenharmony_ci */ 301762306a36Sopenharmony_ci memset(&lcont_pkt, 0, REQUEST_ENTRY_SIZE); 301862306a36Sopenharmony_ci cont_pkt = 301962306a36Sopenharmony_ci qlafx00_prep_cont_type1_iocb(req, &lcont_pkt); 302062306a36Sopenharmony_ci cur_dsd = lcont_pkt.dsd; 302162306a36Sopenharmony_ci avail_dsds = 5; 302262306a36Sopenharmony_ci cont = 1; 302362306a36Sopenharmony_ci } 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 302662306a36Sopenharmony_ci avail_dsds--; 302762306a36Sopenharmony_ci if (avail_dsds == 0 && cont == 1) { 302862306a36Sopenharmony_ci cont = 0; 302962306a36Sopenharmony_ci memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt, 303062306a36Sopenharmony_ci sizeof(lcont_pkt)); 303162306a36Sopenharmony_ci } 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_ci } 303462306a36Sopenharmony_ci if (avail_dsds != 0 && cont == 1) { 303562306a36Sopenharmony_ci memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt, 303662306a36Sopenharmony_ci sizeof(lcont_pkt)); 303762306a36Sopenharmony_ci } 303862306a36Sopenharmony_ci} 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci/** 304162306a36Sopenharmony_ci * qlafx00_start_scsi() - Send a SCSI command to the ISP 304262306a36Sopenharmony_ci * @sp: command to send to the ISP 304362306a36Sopenharmony_ci * 304462306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 304562306a36Sopenharmony_ci */ 304662306a36Sopenharmony_ciint 304762306a36Sopenharmony_ciqlafx00_start_scsi(srb_t *sp) 304862306a36Sopenharmony_ci{ 304962306a36Sopenharmony_ci int nseg; 305062306a36Sopenharmony_ci unsigned long flags; 305162306a36Sopenharmony_ci uint32_t handle; 305262306a36Sopenharmony_ci uint16_t cnt; 305362306a36Sopenharmony_ci uint16_t req_cnt; 305462306a36Sopenharmony_ci uint16_t tot_dsds; 305562306a36Sopenharmony_ci struct req_que *req = NULL; 305662306a36Sopenharmony_ci struct rsp_que *rsp = NULL; 305762306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 305862306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 305962306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 306062306a36Sopenharmony_ci struct cmd_type_7_fx00 *cmd_pkt; 306162306a36Sopenharmony_ci struct cmd_type_7_fx00 lcmd_pkt; 306262306a36Sopenharmony_ci struct scsi_lun llun; 306362306a36Sopenharmony_ci 306462306a36Sopenharmony_ci /* Setup device pointers. */ 306562306a36Sopenharmony_ci rsp = ha->rsp_q_map[0]; 306662306a36Sopenharmony_ci req = vha->req; 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 306962306a36Sopenharmony_ci tot_dsds = 0; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci /* Acquire ring specific lock */ 307262306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 307562306a36Sopenharmony_ci if (handle == 0) 307662306a36Sopenharmony_ci goto queuing_error; 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 307962306a36Sopenharmony_ci if (scsi_sg_count(cmd)) { 308062306a36Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 308162306a36Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 308262306a36Sopenharmony_ci if (unlikely(!nseg)) 308362306a36Sopenharmony_ci goto queuing_error; 308462306a36Sopenharmony_ci } else 308562306a36Sopenharmony_ci nseg = 0; 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci tot_dsds = nseg; 308862306a36Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 308962306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 309062306a36Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci if (req->ring_index < cnt) 309362306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 309462306a36Sopenharmony_ci else 309562306a36Sopenharmony_ci req->cnt = req->length - 309662306a36Sopenharmony_ci (req->ring_index - cnt); 309762306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 309862306a36Sopenharmony_ci goto queuing_error; 309962306a36Sopenharmony_ci } 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci /* Build command packet. */ 310262306a36Sopenharmony_ci req->current_outstanding_cmd = handle; 310362306a36Sopenharmony_ci req->outstanding_cmds[handle] = sp; 310462306a36Sopenharmony_ci sp->handle = handle; 310562306a36Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 310662306a36Sopenharmony_ci req->cnt -= req_cnt; 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_ci cmd_pkt = (struct cmd_type_7_fx00 *)req->ring_ptr; 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci memset(&lcmd_pkt, 0, REQUEST_ENTRY_SIZE); 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci lcmd_pkt.handle = make_handle(req->id, sp->handle); 311362306a36Sopenharmony_ci lcmd_pkt.reserved_0 = 0; 311462306a36Sopenharmony_ci lcmd_pkt.port_path_ctrl = 0; 311562306a36Sopenharmony_ci lcmd_pkt.reserved_1 = 0; 311662306a36Sopenharmony_ci lcmd_pkt.dseg_count = cpu_to_le16(tot_dsds); 311762306a36Sopenharmony_ci lcmd_pkt.tgt_idx = cpu_to_le16(sp->fcport->tgt_id); 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &llun); 312062306a36Sopenharmony_ci host_to_adap((uint8_t *)&llun, (uint8_t *)&lcmd_pkt.lun, 312162306a36Sopenharmony_ci sizeof(lcmd_pkt.lun)); 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci /* Load SCSI command packet. */ 312462306a36Sopenharmony_ci host_to_adap(cmd->cmnd, lcmd_pkt.fcp_cdb, sizeof(lcmd_pkt.fcp_cdb)); 312562306a36Sopenharmony_ci lcmd_pkt.byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci /* Build IOCB segments */ 312862306a36Sopenharmony_ci qlafx00_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, &lcmd_pkt); 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci /* Set total data segment count. */ 313162306a36Sopenharmony_ci lcmd_pkt.entry_count = (uint8_t)req_cnt; 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ci /* Specify response queue number where completion should happen */ 313462306a36Sopenharmony_ci lcmd_pkt.entry_status = (uint8_t) rsp->id; 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e, 313762306a36Sopenharmony_ci cmd->cmnd, cmd->cmd_len); 313862306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3032, 313962306a36Sopenharmony_ci &lcmd_pkt, sizeof(lcmd_pkt)); 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ci memcpy_toio((void __iomem *)cmd_pkt, &lcmd_pkt, REQUEST_ENTRY_SIZE); 314262306a36Sopenharmony_ci wmb(); 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_ci /* Adjust ring index. */ 314562306a36Sopenharmony_ci req->ring_index++; 314662306a36Sopenharmony_ci if (req->ring_index == req->length) { 314762306a36Sopenharmony_ci req->ring_index = 0; 314862306a36Sopenharmony_ci req->ring_ptr = req->ring; 314962306a36Sopenharmony_ci } else 315062306a36Sopenharmony_ci req->ring_ptr++; 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_ci /* Set chip new ring index. */ 315562306a36Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 315662306a36Sopenharmony_ci QLAFX00_SET_HST_INTR(ha, ha->rqstq_intr_code); 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 315962306a36Sopenharmony_ci return QLA_SUCCESS; 316062306a36Sopenharmony_ci 316162306a36Sopenharmony_ciqueuing_error: 316262306a36Sopenharmony_ci if (tot_dsds) 316362306a36Sopenharmony_ci scsi_dma_unmap(cmd); 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 316862306a36Sopenharmony_ci} 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_civoid 317162306a36Sopenharmony_ciqlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb) 317262306a36Sopenharmony_ci{ 317362306a36Sopenharmony_ci struct srb_iocb *fxio = &sp->u.iocb_cmd; 317462306a36Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 317562306a36Sopenharmony_ci struct req_que *req = vha->req; 317662306a36Sopenharmony_ci struct tsk_mgmt_entry_fx00 tm_iocb; 317762306a36Sopenharmony_ci struct scsi_lun llun; 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci memset(&tm_iocb, 0, sizeof(struct tsk_mgmt_entry_fx00)); 318062306a36Sopenharmony_ci tm_iocb.entry_type = TSK_MGMT_IOCB_TYPE_FX00; 318162306a36Sopenharmony_ci tm_iocb.entry_count = 1; 318262306a36Sopenharmony_ci tm_iocb.handle = make_handle(req->id, sp->handle); 318362306a36Sopenharmony_ci tm_iocb.reserved_0 = 0; 318462306a36Sopenharmony_ci tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id); 318562306a36Sopenharmony_ci tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags); 318662306a36Sopenharmony_ci if (tm_iocb.control_flags == cpu_to_le32((uint32_t)TCF_LUN_RESET)) { 318762306a36Sopenharmony_ci int_to_scsilun(fxio->u.tmf.lun, &llun); 318862306a36Sopenharmony_ci host_to_adap((uint8_t *)&llun, (uint8_t *)&tm_iocb.lun, 318962306a36Sopenharmony_ci sizeof(struct scsi_lun)); 319062306a36Sopenharmony_ci } 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci memcpy(ptm_iocb, &tm_iocb, 319362306a36Sopenharmony_ci sizeof(struct tsk_mgmt_entry_fx00)); 319462306a36Sopenharmony_ci wmb(); 319562306a36Sopenharmony_ci} 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_civoid 319862306a36Sopenharmony_ciqlafx00_abort_iocb(srb_t *sp, struct abort_iocb_entry_fx00 *pabt_iocb) 319962306a36Sopenharmony_ci{ 320062306a36Sopenharmony_ci struct srb_iocb *fxio = &sp->u.iocb_cmd; 320162306a36Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 320262306a36Sopenharmony_ci struct req_que *req = vha->req; 320362306a36Sopenharmony_ci struct abort_iocb_entry_fx00 abt_iocb; 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci memset(&abt_iocb, 0, sizeof(struct abort_iocb_entry_fx00)); 320662306a36Sopenharmony_ci abt_iocb.entry_type = ABORT_IOCB_TYPE_FX00; 320762306a36Sopenharmony_ci abt_iocb.entry_count = 1; 320862306a36Sopenharmony_ci abt_iocb.handle = make_handle(req->id, sp->handle); 320962306a36Sopenharmony_ci abt_iocb.abort_handle = make_handle(req->id, fxio->u.abt.cmd_hndl); 321062306a36Sopenharmony_ci abt_iocb.tgt_id_sts = cpu_to_le16(sp->fcport->tgt_id); 321162306a36Sopenharmony_ci abt_iocb.req_que_no = cpu_to_le16(req->id); 321262306a36Sopenharmony_ci 321362306a36Sopenharmony_ci memcpy(pabt_iocb, &abt_iocb, 321462306a36Sopenharmony_ci sizeof(struct abort_iocb_entry_fx00)); 321562306a36Sopenharmony_ci wmb(); 321662306a36Sopenharmony_ci} 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_civoid 321962306a36Sopenharmony_ciqlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb) 322062306a36Sopenharmony_ci{ 322162306a36Sopenharmony_ci struct srb_iocb *fxio = &sp->u.iocb_cmd; 322262306a36Sopenharmony_ci struct qla_mt_iocb_rqst_fx00 *piocb_rqst; 322362306a36Sopenharmony_ci struct bsg_job *bsg_job; 322462306a36Sopenharmony_ci struct fc_bsg_request *bsg_request; 322562306a36Sopenharmony_ci struct fxdisc_entry_fx00 fx_iocb; 322662306a36Sopenharmony_ci uint8_t entry_cnt = 1; 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci memset(&fx_iocb, 0, sizeof(struct fxdisc_entry_fx00)); 322962306a36Sopenharmony_ci fx_iocb.entry_type = FX00_IOCB_TYPE; 323062306a36Sopenharmony_ci fx_iocb.handle = sp->handle; 323162306a36Sopenharmony_ci fx_iocb.entry_count = entry_cnt; 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci if (sp->type == SRB_FXIOCB_DCMD) { 323462306a36Sopenharmony_ci fx_iocb.func_num = 323562306a36Sopenharmony_ci sp->u.iocb_cmd.u.fxiocb.req_func_type; 323662306a36Sopenharmony_ci fx_iocb.adapid = fxio->u.fxiocb.adapter_id; 323762306a36Sopenharmony_ci fx_iocb.adapid_hi = fxio->u.fxiocb.adapter_id_hi; 323862306a36Sopenharmony_ci fx_iocb.reserved_0 = fxio->u.fxiocb.reserved_0; 323962306a36Sopenharmony_ci fx_iocb.reserved_1 = fxio->u.fxiocb.reserved_1; 324062306a36Sopenharmony_ci fx_iocb.dataword_extra = fxio->u.fxiocb.req_data_extra; 324162306a36Sopenharmony_ci 324262306a36Sopenharmony_ci if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) { 324362306a36Sopenharmony_ci fx_iocb.req_dsdcnt = cpu_to_le16(1); 324462306a36Sopenharmony_ci fx_iocb.req_xfrcnt = 324562306a36Sopenharmony_ci cpu_to_le16(fxio->u.fxiocb.req_len); 324662306a36Sopenharmony_ci put_unaligned_le64(fxio->u.fxiocb.req_dma_handle, 324762306a36Sopenharmony_ci &fx_iocb.dseg_rq[0].address); 324862306a36Sopenharmony_ci fx_iocb.dseg_rq[0].length = 324962306a36Sopenharmony_ci cpu_to_le32(fxio->u.fxiocb.req_len); 325062306a36Sopenharmony_ci } 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci if (fxio->u.fxiocb.flags & SRB_FXDISC_RESP_DMA_VALID) { 325362306a36Sopenharmony_ci fx_iocb.rsp_dsdcnt = cpu_to_le16(1); 325462306a36Sopenharmony_ci fx_iocb.rsp_xfrcnt = 325562306a36Sopenharmony_ci cpu_to_le16(fxio->u.fxiocb.rsp_len); 325662306a36Sopenharmony_ci put_unaligned_le64(fxio->u.fxiocb.rsp_dma_handle, 325762306a36Sopenharmony_ci &fx_iocb.dseg_rsp[0].address); 325862306a36Sopenharmony_ci fx_iocb.dseg_rsp[0].length = 325962306a36Sopenharmony_ci cpu_to_le32(fxio->u.fxiocb.rsp_len); 326062306a36Sopenharmony_ci } 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DWRD_VALID) { 326362306a36Sopenharmony_ci fx_iocb.dataword = fxio->u.fxiocb.req_data; 326462306a36Sopenharmony_ci } 326562306a36Sopenharmony_ci fx_iocb.flags = fxio->u.fxiocb.flags; 326662306a36Sopenharmony_ci } else { 326762306a36Sopenharmony_ci struct scatterlist *sg; 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_ci bsg_job = sp->u.bsg_job; 327062306a36Sopenharmony_ci bsg_request = bsg_job->request; 327162306a36Sopenharmony_ci piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *) 327262306a36Sopenharmony_ci &bsg_request->rqst_data.h_vendor.vendor_cmd[1]; 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci fx_iocb.func_num = piocb_rqst->func_type; 327562306a36Sopenharmony_ci fx_iocb.adapid = piocb_rqst->adapid; 327662306a36Sopenharmony_ci fx_iocb.adapid_hi = piocb_rqst->adapid_hi; 327762306a36Sopenharmony_ci fx_iocb.reserved_0 = piocb_rqst->reserved_0; 327862306a36Sopenharmony_ci fx_iocb.reserved_1 = piocb_rqst->reserved_1; 327962306a36Sopenharmony_ci fx_iocb.dataword_extra = piocb_rqst->dataword_extra; 328062306a36Sopenharmony_ci fx_iocb.dataword = piocb_rqst->dataword; 328162306a36Sopenharmony_ci fx_iocb.req_xfrcnt = piocb_rqst->req_len; 328262306a36Sopenharmony_ci fx_iocb.rsp_xfrcnt = piocb_rqst->rsp_len; 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) { 328562306a36Sopenharmony_ci int avail_dsds, tot_dsds; 328662306a36Sopenharmony_ci cont_a64_entry_t lcont_pkt; 328762306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt = NULL; 328862306a36Sopenharmony_ci struct dsd64 *cur_dsd; 328962306a36Sopenharmony_ci int index = 0, cont = 0; 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci fx_iocb.req_dsdcnt = 329262306a36Sopenharmony_ci cpu_to_le16(bsg_job->request_payload.sg_cnt); 329362306a36Sopenharmony_ci tot_dsds = 329462306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt; 329562306a36Sopenharmony_ci cur_dsd = &fx_iocb.dseg_rq[0]; 329662306a36Sopenharmony_ci avail_dsds = 1; 329762306a36Sopenharmony_ci for_each_sg(bsg_job->request_payload.sg_list, sg, 329862306a36Sopenharmony_ci tot_dsds, index) { 329962306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 330062306a36Sopenharmony_ci if (avail_dsds == 0) { 330162306a36Sopenharmony_ci /* 330262306a36Sopenharmony_ci * Five DSDs are available in the Cont. 330362306a36Sopenharmony_ci * Type 1 IOCB. 330462306a36Sopenharmony_ci */ 330562306a36Sopenharmony_ci memset(&lcont_pkt, 0, 330662306a36Sopenharmony_ci REQUEST_ENTRY_SIZE); 330762306a36Sopenharmony_ci cont_pkt = 330862306a36Sopenharmony_ci qlafx00_prep_cont_type1_iocb( 330962306a36Sopenharmony_ci sp->vha->req, &lcont_pkt); 331062306a36Sopenharmony_ci cur_dsd = lcont_pkt.dsd; 331162306a36Sopenharmony_ci avail_dsds = 5; 331262306a36Sopenharmony_ci cont = 1; 331362306a36Sopenharmony_ci entry_cnt++; 331462306a36Sopenharmony_ci } 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 331762306a36Sopenharmony_ci avail_dsds--; 331862306a36Sopenharmony_ci 331962306a36Sopenharmony_ci if (avail_dsds == 0 && cont == 1) { 332062306a36Sopenharmony_ci cont = 0; 332162306a36Sopenharmony_ci memcpy_toio( 332262306a36Sopenharmony_ci (void __iomem *)cont_pkt, 332362306a36Sopenharmony_ci &lcont_pkt, REQUEST_ENTRY_SIZE); 332462306a36Sopenharmony_ci ql_dump_buffer( 332562306a36Sopenharmony_ci ql_dbg_user + ql_dbg_verbose, 332662306a36Sopenharmony_ci sp->vha, 0x3042, 332762306a36Sopenharmony_ci (uint8_t *)&lcont_pkt, 332862306a36Sopenharmony_ci REQUEST_ENTRY_SIZE); 332962306a36Sopenharmony_ci } 333062306a36Sopenharmony_ci } 333162306a36Sopenharmony_ci if (avail_dsds != 0 && cont == 1) { 333262306a36Sopenharmony_ci memcpy_toio((void __iomem *)cont_pkt, 333362306a36Sopenharmony_ci &lcont_pkt, REQUEST_ENTRY_SIZE); 333462306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, 333562306a36Sopenharmony_ci sp->vha, 0x3043, 333662306a36Sopenharmony_ci (uint8_t *)&lcont_pkt, REQUEST_ENTRY_SIZE); 333762306a36Sopenharmony_ci } 333862306a36Sopenharmony_ci } 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_ci if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) { 334162306a36Sopenharmony_ci int avail_dsds, tot_dsds; 334262306a36Sopenharmony_ci cont_a64_entry_t lcont_pkt; 334362306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt = NULL; 334462306a36Sopenharmony_ci struct dsd64 *cur_dsd; 334562306a36Sopenharmony_ci int index = 0, cont = 0; 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci fx_iocb.rsp_dsdcnt = 334862306a36Sopenharmony_ci cpu_to_le16(bsg_job->reply_payload.sg_cnt); 334962306a36Sopenharmony_ci tot_dsds = bsg_job->reply_payload.sg_cnt; 335062306a36Sopenharmony_ci cur_dsd = &fx_iocb.dseg_rsp[0]; 335162306a36Sopenharmony_ci avail_dsds = 1; 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci for_each_sg(bsg_job->reply_payload.sg_list, sg, 335462306a36Sopenharmony_ci tot_dsds, index) { 335562306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 335662306a36Sopenharmony_ci if (avail_dsds == 0) { 335762306a36Sopenharmony_ci /* 335862306a36Sopenharmony_ci * Five DSDs are available in the Cont. 335962306a36Sopenharmony_ci * Type 1 IOCB. 336062306a36Sopenharmony_ci */ 336162306a36Sopenharmony_ci memset(&lcont_pkt, 0, 336262306a36Sopenharmony_ci REQUEST_ENTRY_SIZE); 336362306a36Sopenharmony_ci cont_pkt = 336462306a36Sopenharmony_ci qlafx00_prep_cont_type1_iocb( 336562306a36Sopenharmony_ci sp->vha->req, &lcont_pkt); 336662306a36Sopenharmony_ci cur_dsd = lcont_pkt.dsd; 336762306a36Sopenharmony_ci avail_dsds = 5; 336862306a36Sopenharmony_ci cont = 1; 336962306a36Sopenharmony_ci entry_cnt++; 337062306a36Sopenharmony_ci } 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 337362306a36Sopenharmony_ci avail_dsds--; 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci if (avail_dsds == 0 && cont == 1) { 337662306a36Sopenharmony_ci cont = 0; 337762306a36Sopenharmony_ci memcpy_toio((void __iomem *)cont_pkt, 337862306a36Sopenharmony_ci &lcont_pkt, 337962306a36Sopenharmony_ci REQUEST_ENTRY_SIZE); 338062306a36Sopenharmony_ci ql_dump_buffer( 338162306a36Sopenharmony_ci ql_dbg_user + ql_dbg_verbose, 338262306a36Sopenharmony_ci sp->vha, 0x3045, 338362306a36Sopenharmony_ci (uint8_t *)&lcont_pkt, 338462306a36Sopenharmony_ci REQUEST_ENTRY_SIZE); 338562306a36Sopenharmony_ci } 338662306a36Sopenharmony_ci } 338762306a36Sopenharmony_ci if (avail_dsds != 0 && cont == 1) { 338862306a36Sopenharmony_ci memcpy_toio((void __iomem *)cont_pkt, 338962306a36Sopenharmony_ci &lcont_pkt, REQUEST_ENTRY_SIZE); 339062306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, 339162306a36Sopenharmony_ci sp->vha, 0x3046, 339262306a36Sopenharmony_ci (uint8_t *)&lcont_pkt, REQUEST_ENTRY_SIZE); 339362306a36Sopenharmony_ci } 339462306a36Sopenharmony_ci } 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci if (piocb_rqst->flags & SRB_FXDISC_REQ_DWRD_VALID) 339762306a36Sopenharmony_ci fx_iocb.dataword = piocb_rqst->dataword; 339862306a36Sopenharmony_ci fx_iocb.flags = piocb_rqst->flags; 339962306a36Sopenharmony_ci fx_iocb.entry_count = entry_cnt; 340062306a36Sopenharmony_ci } 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, 340362306a36Sopenharmony_ci sp->vha, 0x3047, &fx_iocb, sizeof(fx_iocb)); 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci memcpy_toio((void __iomem *)pfxiocb, &fx_iocb, sizeof(fx_iocb)); 340662306a36Sopenharmony_ci wmb(); 340762306a36Sopenharmony_ci} 3408