--- zzzz-none-000/linux-3.10.107/drivers/scsi/qla2xxx/qla_bsg.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/scsi/qla2xxx/qla_bsg.c 2021-02-04 17:41:59.000000000 +0000 @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2012 QLogic Corporation + * Copyright (c) 2003-2014 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -125,7 +125,7 @@ uint32_t len; uint32_t oper; - if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA82XX(ha))) { + if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_P3P_TYPE(ha))) { ret = -EINVAL; goto exit_fcp_prio_cfg; } @@ -269,6 +269,12 @@ type = "FC_BSG_HST_ELS_NOLOGIN"; } + if (!vha->flags.online) { + ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n"); + rval = -EIO; + goto done; + } + /* pass through is supported only for ISP 4Gb or higher */ if (!IS_FWI2_CAPABLE(ha)) { ql_dbg(ql_dbg_user, vha, 0x7001, @@ -326,12 +332,6 @@ NPH_FABRIC_CONTROLLER : NPH_F_PORT; } - if (!vha->flags.online) { - ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n"); - rval = -EIO; - goto done; - } - req_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); @@ -399,13 +399,13 @@ goto done_free_fcport; done_free_fcport: - if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN) + if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) kfree(fcport); done: return rval; } -inline uint16_t +static inline uint16_t qla24xx_calc_ct_iocbs(uint16_t dsds) { uint16_t iocbs; @@ -559,7 +559,7 @@ uint16_t new_config[4]; struct qla_hw_data *ha = vha->hw; - if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) + if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha)) goto done_reset_internal; memset(new_config, 0 , sizeof(new_config)); @@ -627,9 +627,10 @@ { int ret = 0; int rval = 0; + unsigned long rem_tmo = 0, current_tmo = 0; struct qla_hw_data *ha = vha->hw; - if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) + if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha)) goto done_set_internal; if (mode == INTERNAL_LOOPBACK) @@ -652,8 +653,19 @@ } /* Wait for DCBX complete event */ - if (!wait_for_completion_timeout(&ha->dcbx_comp, - (DCBX_COMP_TIMEOUT * HZ))) { + current_tmo = DCBX_COMP_TIMEOUT * HZ; + while (1) { + rem_tmo = wait_for_completion_timeout(&ha->dcbx_comp, + current_tmo); + if (!ha->idc_extend_tmo || rem_tmo) { + ha->idc_extend_tmo = 0; + break; + } + current_tmo = ha->idc_extend_tmo * HZ; + ha->idc_extend_tmo = 0; + } + + if (!rem_tmo) { ql_dbg(ql_dbg_user, vha, 0x7022, "DCBX completion not received.\n"); ret = qla81xx_reset_loopback_mode(vha, new_config, 0, 0); @@ -678,6 +690,7 @@ } ha->notify_dcbx_comp = 0; + ha->idc_extend_tmo = 0; done_set_internal: return rval; @@ -773,7 +786,7 @@ if (atomic_read(&vha->loop_state) == LOOP_READY && (ha->current_topology == ISP_CFG_F || - ((IS_QLA81XX(ha) || IS_QLA8031(ha)) && + ((IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) && le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE && req_data_len == MAX_ELS_FRAME_PAYLOAD)) && elreq.options == EXTERNAL_LOOPBACK) { @@ -783,7 +796,7 @@ command_sent = INT_DEF_LB_ECHO_CMD; rval = qla2x00_echo_test(vha, &elreq, response); } else { - if (IS_QLA81XX(ha) || IS_QLA8031(ha)) { + if (IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) { memset(config, 0, sizeof(config)); memset(new_config, 0, sizeof(new_config)); @@ -806,7 +819,7 @@ "elreq.options=%04x\n", elreq.options); if (elreq.options == EXTERNAL_LOOPBACK) - if (IS_QLA8031(ha)) + if (IS_QLA8031(ha) || IS_QLA8044(ha)) rval = qla81xx_set_loopback_mode(vha, config, new_config, elreq.options); else @@ -1084,14 +1097,6 @@ return -EINVAL; } - ql84_mgmt = (struct qla_bsg_a84_mgmt *)((char *)bsg_job->request + - sizeof(struct fc_bsg_request)); - if (!ql84_mgmt) { - ql_log(ql_log_warn, vha, 0x703b, - "MGMT header not provided, exiting.\n"); - return -EINVAL; - } - mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); if (!mn) { ql_log(ql_log_warn, vha, 0x703c, @@ -1102,7 +1107,7 @@ memset(mn, 0, sizeof(struct access_chip_84xx)); mn->entry_type = ACCESS_CHIP_IOCB_TYPE; mn->entry_count = 1; - + ql84_mgmt = (void *)bsg_job->request + sizeof(struct fc_bsg_request); switch (ql84_mgmt->mgmt.cmd) { case QLA84_MGMT_READ_MEM: case QLA84_MGMT_GET_INFO: @@ -1274,6 +1279,7 @@ int rval = 0; struct qla_port_param *port_param = NULL; fc_port_t *fcport = NULL; + int found = 0; uint16_t mb[MAILBOX_REGISTER_COUNT]; uint8_t *rsp_ptr = NULL; @@ -1282,14 +1288,7 @@ return -EINVAL; } - port_param = (struct qla_port_param *)((char *)bsg_job->request + - sizeof(struct fc_bsg_request)); - if (!port_param) { - ql_log(ql_log_warn, vha, 0x7047, - "port_param header not provided.\n"); - return -EINVAL; - } - + port_param = (void *)bsg_job->request + sizeof(struct fc_bsg_request); if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) { ql_log(ql_log_warn, vha, 0x7048, "Invalid destination type.\n"); @@ -1303,10 +1302,12 @@ if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn, fcport->port_name, sizeof(fcport->port_name))) continue; + + found = 1; break; } - if (!fcport) { + if (!found) { ql_log(ql_log_warn, vha, 0x7049, "Failed to find port.\n"); return -EINVAL; @@ -1333,12 +1334,9 @@ if (rval) { ql_log(ql_log_warn, vha, 0x704c, - "iIDMA cmd failed for %02x%02x%02x%02x%02x%02x%02x%02x -- " - "%04x %x %04x %04x.\n", fcport->port_name[0], - fcport->port_name[1], fcport->port_name[2], - fcport->port_name[3], fcport->port_name[4], - fcport->port_name[5], fcport->port_name[6], - fcport->port_name[7], rval, fcport->fp_speed, mb[0], mb[1]); + "iIDMA cmd failed for %8phN -- " + "%04x %x %04x %04x.\n", fcport->port_name, + rval, fcport->fp_speed, mb[0], mb[1]); rval = (DID_ERROR << 16); } else { if (!port_param->mode) { @@ -1392,7 +1390,7 @@ start == (ha->flt_region_fw * 4)) valid = 1; else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || - IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) + IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha)) valid = 1; if (!valid) { ql_log(ql_log_warn, vha, 0x7058, @@ -1439,9 +1437,12 @@ if (ha->flags.nic_core_reset_hdlr_active) return -EBUSY; + mutex_lock(&ha->optrom_mutex); rval = qla2x00_optrom_setup(bsg_job, vha, 0); - if (rval) + if (rval) { + mutex_unlock(&ha->optrom_mutex); return rval; + } ha->isp_ops->read_optrom(vha, ha->optrom_buffer, ha->optrom_region_start, ha->optrom_region_size); @@ -1455,6 +1456,7 @@ vfree(ha->optrom_buffer); ha->optrom_buffer = NULL; ha->optrom_state = QLA_SWAITING; + mutex_unlock(&ha->optrom_mutex); bsg_job->job_done(bsg_job); return rval; } @@ -1467,9 +1469,12 @@ struct qla_hw_data *ha = vha->hw; int rval = 0; + mutex_lock(&ha->optrom_mutex); rval = qla2x00_optrom_setup(bsg_job, vha, 1); - if (rval) + if (rval) { + mutex_unlock(&ha->optrom_mutex); return rval; + } /* Set the isp82xx_no_md_cap not to capture minidump */ ha->flags.isp82xx_no_md_cap = 1; @@ -1485,6 +1490,7 @@ vfree(ha->optrom_buffer); ha->optrom_buffer = NULL; ha->optrom_state = QLA_SWAITING; + mutex_unlock(&ha->optrom_mutex); bsg_job->job_done(bsg_job); return rval; } @@ -1727,7 +1733,6 @@ struct Scsi_Host *host = bsg_job->shost; scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; - uint16_t thread_id; uint32_t rval = EXT_STATUS_OK; uint16_t req_sg_cnt = 0; uint16_t rsp_sg_cnt = 0; @@ -1784,8 +1789,6 @@ goto done; } - thread_id = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; - mutex_lock(&ha->selflogin_lock); if (vha->self_login_loop_id == 0) { /* Initialize all required fields of fcport */ @@ -1897,7 +1900,7 @@ bsg_job->reply->reply_payload_rcv_len = 0; bsg_job->reply->result = (DID_OK) << 16; bsg_job->job_done(bsg_job); - /* Always retrun success, vendor rsp carries correct status */ + /* Always return success, vendor rsp carries correct status */ return 0; } @@ -2024,6 +2027,86 @@ } static int +qla26xx_serdes_op(struct fc_bsg_job *bsg_job) +{ + struct Scsi_Host *host = bsg_job->shost; + scsi_qla_host_t *vha = shost_priv(host); + int rval = 0; + struct qla_serdes_reg sr; + + memset(&sr, 0, sizeof(sr)); + + sg_copy_to_buffer(bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, &sr, sizeof(sr)); + + switch (sr.cmd) { + case INT_SC_SERDES_WRITE_REG: + rval = qla2x00_write_serdes_word(vha, sr.addr, sr.val); + bsg_job->reply->reply_payload_rcv_len = 0; + break; + case INT_SC_SERDES_READ_REG: + rval = qla2x00_read_serdes_word(vha, sr.addr, &sr.val); + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, &sr, sizeof(sr)); + bsg_job->reply->reply_payload_rcv_len = sizeof(sr); + break; + default: + ql_dbg(ql_dbg_user, vha, 0x708c, + "Unknown serdes cmd %x.\n", sr.cmd); + rval = -EINVAL; + break; + } + + bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = + rval ? EXT_STATUS_MAILBOX : 0; + + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + bsg_job->reply->result = DID_OK << 16; + bsg_job->job_done(bsg_job); + return 0; +} + +static int +qla8044_serdes_op(struct fc_bsg_job *bsg_job) +{ + struct Scsi_Host *host = bsg_job->shost; + scsi_qla_host_t *vha = shost_priv(host); + int rval = 0; + struct qla_serdes_reg_ex sr; + + memset(&sr, 0, sizeof(sr)); + + sg_copy_to_buffer(bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, &sr, sizeof(sr)); + + switch (sr.cmd) { + case INT_SC_SERDES_WRITE_REG: + rval = qla8044_write_serdes_word(vha, sr.addr, sr.val); + bsg_job->reply->reply_payload_rcv_len = 0; + break; + case INT_SC_SERDES_READ_REG: + rval = qla8044_read_serdes_word(vha, sr.addr, &sr.val); + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, &sr, sizeof(sr)); + bsg_job->reply->reply_payload_rcv_len = sizeof(sr); + break; + default: + ql_dbg(ql_dbg_user, vha, 0x70cf, + "Unknown serdes cmd %x.\n", sr.cmd); + rval = -EINVAL; + break; + } + + bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = + rval ? EXT_STATUS_MAILBOX : 0; + + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + bsg_job->reply->result = DID_OK << 16; + bsg_job->job_done(bsg_job); + return 0; +} + +static int qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) { switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { @@ -2071,6 +2154,13 @@ case QL_VND_FX00_MGMT_CMD: return qlafx00_mgmt_cmd(bsg_job); + + case QL_VND_SERDES_OP: + return qla26xx_serdes_op(bsg_job); + + case QL_VND_SERDES_OP_EX: + return qla8044_serdes_op(bsg_job); + default: return -ENOSYS; } @@ -2081,7 +2171,6 @@ { int ret = -EINVAL; struct fc_rport *rport; - fc_port_t *fcport = NULL; struct Scsi_Host *host; scsi_qla_host_t *vha; @@ -2090,7 +2179,6 @@ if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { rport = bsg_job->rport; - fcport = *(fc_port_t **) rport->dd_data; host = rport_to_shost(rport); vha = shost_priv(host); } else { @@ -2153,6 +2241,7 @@ (sp->type == SRB_ELS_CMD_HST) || (sp->type == SRB_FXIOCB_BCMD)) && (sp->u.bsg_job == bsg_job)) { + req->outstanding_cmds[cnt] = NULL; spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ha->isp_ops->abort_command(sp)) { ql_log(ql_log_warn, vha, 0x7089, @@ -2180,8 +2269,6 @@ done: spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (bsg_job->request->msgcode == FC_BSG_HST_CT) - kfree(sp->fcport); - qla2x00_rel_sp(vha, sp); + sp->free(vha, sp); return 0; }