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 "qla_gbl.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kthread.h> 1062306a36Sopenharmony_ci#include <linux/vmalloc.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/bsg-lib.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic void qla2xxx_free_fcport_work(struct work_struct *work) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci struct fc_port *fcport = container_of(work, typeof(*fcport), 1762306a36Sopenharmony_ci free_work); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci qla2x00_free_fcport(fcport); 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* BSG support for ELS/CT pass through */ 2362306a36Sopenharmony_civoid qla2x00_bsg_job_done(srb_t *sp, int res) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct bsg_job *bsg_job = sp->u.bsg_job; 2662306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci ql_dbg(ql_dbg_user, sp->vha, 0x7009, 2962306a36Sopenharmony_ci "%s: sp hdl %x, result=%x bsg ptr %p\n", 3062306a36Sopenharmony_ci __func__, sp->handle, res, bsg_job); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci /* ref: INIT */ 3362306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci bsg_reply->result = res; 3662306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 3762306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid qla2x00_bsg_sp_free(srb_t *sp) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct qla_hw_data *ha = sp->vha->hw; 4362306a36Sopenharmony_ci struct bsg_job *bsg_job = sp->u.bsg_job; 4462306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 4562306a36Sopenharmony_ci struct qla_mt_iocb_rqst_fx00 *piocb_rqst; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (sp->type == SRB_FXIOCB_BCMD) { 4862306a36Sopenharmony_ci piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *) 4962306a36Sopenharmony_ci &bsg_request->rqst_data.h_vendor.vendor_cmd[1]; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) 5262306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, 5362306a36Sopenharmony_ci bsg_job->request_payload.sg_list, 5462306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) 5762306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, 5862306a36Sopenharmony_ci bsg_job->reply_payload.sg_list, 5962306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 6062306a36Sopenharmony_ci } else { 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (sp->remap.remapped) { 6362306a36Sopenharmony_ci dma_pool_free(ha->purex_dma_pool, sp->remap.rsp.buf, 6462306a36Sopenharmony_ci sp->remap.rsp.dma); 6562306a36Sopenharmony_ci dma_pool_free(ha->purex_dma_pool, sp->remap.req.buf, 6662306a36Sopenharmony_ci sp->remap.req.dma); 6762306a36Sopenharmony_ci } else { 6862306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, 6962306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, 7262306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (sp->type == SRB_CT_CMD || 7762306a36Sopenharmony_ci sp->type == SRB_FXIOCB_BCMD || 7862306a36Sopenharmony_ci sp->type == SRB_ELS_CMD_HST) { 7962306a36Sopenharmony_ci INIT_WORK(&sp->fcport->free_work, qla2xxx_free_fcport_work); 8062306a36Sopenharmony_ci queue_work(ha->wq, &sp->fcport->free_work); 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci qla2x00_rel_sp(sp); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciint 8762306a36Sopenharmony_ciqla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *vha, 8862306a36Sopenharmony_ci struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci int i, ret, num_valid; 9162306a36Sopenharmony_ci uint8_t *bcode; 9262306a36Sopenharmony_ci struct qla_fcp_prio_entry *pri_entry; 9362306a36Sopenharmony_ci uint32_t *bcode_val_ptr, bcode_val; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci ret = 1; 9662306a36Sopenharmony_ci num_valid = 0; 9762306a36Sopenharmony_ci bcode = (uint8_t *)pri_cfg; 9862306a36Sopenharmony_ci bcode_val_ptr = (uint32_t *)pri_cfg; 9962306a36Sopenharmony_ci bcode_val = (uint32_t)(*bcode_val_ptr); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (bcode_val == 0xFFFFFFFF) { 10262306a36Sopenharmony_ci /* No FCP Priority config data in flash */ 10362306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7051, 10462306a36Sopenharmony_ci "No FCP Priority config data.\n"); 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (memcmp(bcode, "HQOS", 4)) { 10962306a36Sopenharmony_ci /* Invalid FCP priority data header*/ 11062306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7052, 11162306a36Sopenharmony_ci "Invalid FCP Priority data header. bcode=0x%x.\n", 11262306a36Sopenharmony_ci bcode_val); 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci if (flag != 1) 11662306a36Sopenharmony_ci return ret; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci pri_entry = &pri_cfg->entry[0]; 11962306a36Sopenharmony_ci for (i = 0; i < pri_cfg->num_entries; i++) { 12062306a36Sopenharmony_ci if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID) 12162306a36Sopenharmony_ci num_valid++; 12262306a36Sopenharmony_ci pri_entry++; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (num_valid == 0) { 12662306a36Sopenharmony_ci /* No valid FCP priority data entries */ 12762306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7053, 12862306a36Sopenharmony_ci "No valid FCP Priority data entries.\n"); 12962306a36Sopenharmony_ci ret = 0; 13062306a36Sopenharmony_ci } else { 13162306a36Sopenharmony_ci /* FCP priority data is valid */ 13262306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7054, 13362306a36Sopenharmony_ci "Valid FCP priority data. num entries = %d.\n", 13462306a36Sopenharmony_ci num_valid); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return ret; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic int 14162306a36Sopenharmony_ciqla24xx_proc_fcp_prio_cfg_cmd(struct bsg_job *bsg_job) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 14462306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 14562306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 14662306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 14762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 14862306a36Sopenharmony_ci int ret = 0; 14962306a36Sopenharmony_ci uint32_t len; 15062306a36Sopenharmony_ci uint32_t oper; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_P3P_TYPE(ha))) { 15362306a36Sopenharmony_ci ret = -EINVAL; 15462306a36Sopenharmony_ci goto exit_fcp_prio_cfg; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Get the sub command */ 15862306a36Sopenharmony_ci oper = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Only set config is allowed if config memory is not allocated */ 16162306a36Sopenharmony_ci if (!ha->fcp_prio_cfg && (oper != QLFC_FCP_PRIO_SET_CONFIG)) { 16262306a36Sopenharmony_ci ret = -EINVAL; 16362306a36Sopenharmony_ci goto exit_fcp_prio_cfg; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci switch (oper) { 16662306a36Sopenharmony_ci case QLFC_FCP_PRIO_DISABLE: 16762306a36Sopenharmony_ci if (ha->flags.fcp_prio_enabled) { 16862306a36Sopenharmony_ci ha->flags.fcp_prio_enabled = 0; 16962306a36Sopenharmony_ci ha->fcp_prio_cfg->attributes &= 17062306a36Sopenharmony_ci ~FCP_PRIO_ATTR_ENABLE; 17162306a36Sopenharmony_ci qla24xx_update_all_fcp_prio(vha); 17262306a36Sopenharmony_ci bsg_reply->result = DID_OK; 17362306a36Sopenharmony_ci } else { 17462306a36Sopenharmony_ci ret = -EINVAL; 17562306a36Sopenharmony_ci bsg_reply->result = (DID_ERROR << 16); 17662306a36Sopenharmony_ci goto exit_fcp_prio_cfg; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci case QLFC_FCP_PRIO_ENABLE: 18162306a36Sopenharmony_ci if (!ha->flags.fcp_prio_enabled) { 18262306a36Sopenharmony_ci if (ha->fcp_prio_cfg) { 18362306a36Sopenharmony_ci ha->flags.fcp_prio_enabled = 1; 18462306a36Sopenharmony_ci ha->fcp_prio_cfg->attributes |= 18562306a36Sopenharmony_ci FCP_PRIO_ATTR_ENABLE; 18662306a36Sopenharmony_ci qla24xx_update_all_fcp_prio(vha); 18762306a36Sopenharmony_ci bsg_reply->result = DID_OK; 18862306a36Sopenharmony_ci } else { 18962306a36Sopenharmony_ci ret = -EINVAL; 19062306a36Sopenharmony_ci bsg_reply->result = (DID_ERROR << 16); 19162306a36Sopenharmony_ci goto exit_fcp_prio_cfg; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci case QLFC_FCP_PRIO_GET_CONFIG: 19762306a36Sopenharmony_ci len = bsg_job->reply_payload.payload_len; 19862306a36Sopenharmony_ci if (!len || len > FCP_PRIO_CFG_SIZE) { 19962306a36Sopenharmony_ci ret = -EINVAL; 20062306a36Sopenharmony_ci bsg_reply->result = (DID_ERROR << 16); 20162306a36Sopenharmony_ci goto exit_fcp_prio_cfg; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci bsg_reply->result = DID_OK; 20562306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 20662306a36Sopenharmony_ci sg_copy_from_buffer( 20762306a36Sopenharmony_ci bsg_job->reply_payload.sg_list, 20862306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, ha->fcp_prio_cfg, 20962306a36Sopenharmony_ci len); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci case QLFC_FCP_PRIO_SET_CONFIG: 21462306a36Sopenharmony_ci len = bsg_job->request_payload.payload_len; 21562306a36Sopenharmony_ci if (!len || len > FCP_PRIO_CFG_SIZE) { 21662306a36Sopenharmony_ci bsg_reply->result = (DID_ERROR << 16); 21762306a36Sopenharmony_ci ret = -EINVAL; 21862306a36Sopenharmony_ci goto exit_fcp_prio_cfg; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (!ha->fcp_prio_cfg) { 22262306a36Sopenharmony_ci ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE); 22362306a36Sopenharmony_ci if (!ha->fcp_prio_cfg) { 22462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7050, 22562306a36Sopenharmony_ci "Unable to allocate memory for fcp prio " 22662306a36Sopenharmony_ci "config data (%x).\n", FCP_PRIO_CFG_SIZE); 22762306a36Sopenharmony_ci bsg_reply->result = (DID_ERROR << 16); 22862306a36Sopenharmony_ci ret = -ENOMEM; 22962306a36Sopenharmony_ci goto exit_fcp_prio_cfg; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE); 23462306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 23562306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, ha->fcp_prio_cfg, 23662306a36Sopenharmony_ci FCP_PRIO_CFG_SIZE); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* validate fcp priority data */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 1)) { 24162306a36Sopenharmony_ci bsg_reply->result = (DID_ERROR << 16); 24262306a36Sopenharmony_ci ret = -EINVAL; 24362306a36Sopenharmony_ci /* If buffer was invalidatic int 24462306a36Sopenharmony_ci * fcp_prio_cfg is of no use 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci vfree(ha->fcp_prio_cfg); 24762306a36Sopenharmony_ci ha->fcp_prio_cfg = NULL; 24862306a36Sopenharmony_ci goto exit_fcp_prio_cfg; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ha->flags.fcp_prio_enabled = 0; 25262306a36Sopenharmony_ci if (ha->fcp_prio_cfg->attributes & FCP_PRIO_ATTR_ENABLE) 25362306a36Sopenharmony_ci ha->flags.fcp_prio_enabled = 1; 25462306a36Sopenharmony_ci qla24xx_update_all_fcp_prio(vha); 25562306a36Sopenharmony_ci bsg_reply->result = DID_OK; 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci default: 25862306a36Sopenharmony_ci ret = -EINVAL; 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ciexit_fcp_prio_cfg: 26262306a36Sopenharmony_ci if (!ret) 26362306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 26462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 26562306a36Sopenharmony_ci return ret; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int 26962306a36Sopenharmony_ciqla2x00_process_els(struct bsg_job *bsg_job) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 27262306a36Sopenharmony_ci struct fc_rport *rport; 27362306a36Sopenharmony_ci fc_port_t *fcport = NULL; 27462306a36Sopenharmony_ci struct Scsi_Host *host; 27562306a36Sopenharmony_ci scsi_qla_host_t *vha; 27662306a36Sopenharmony_ci struct qla_hw_data *ha; 27762306a36Sopenharmony_ci srb_t *sp; 27862306a36Sopenharmony_ci const char *type; 27962306a36Sopenharmony_ci int req_sg_cnt, rsp_sg_cnt; 28062306a36Sopenharmony_ci int rval = (DID_ERROR << 16); 28162306a36Sopenharmony_ci uint32_t els_cmd = 0; 28262306a36Sopenharmony_ci int qla_port_allocated = 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (bsg_request->msgcode == FC_BSG_RPT_ELS) { 28562306a36Sopenharmony_ci rport = fc_bsg_to_rport(bsg_job); 28662306a36Sopenharmony_ci if (!rport) { 28762306a36Sopenharmony_ci rval = -ENOMEM; 28862306a36Sopenharmony_ci goto done; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci fcport = *(fc_port_t **) rport->dd_data; 29162306a36Sopenharmony_ci host = rport_to_shost(rport); 29262306a36Sopenharmony_ci vha = shost_priv(host); 29362306a36Sopenharmony_ci ha = vha->hw; 29462306a36Sopenharmony_ci type = "FC_BSG_RPT_ELS"; 29562306a36Sopenharmony_ci } else { 29662306a36Sopenharmony_ci host = fc_bsg_to_shost(bsg_job); 29762306a36Sopenharmony_ci vha = shost_priv(host); 29862306a36Sopenharmony_ci ha = vha->hw; 29962306a36Sopenharmony_ci type = "FC_BSG_HST_ELS_NOLOGIN"; 30062306a36Sopenharmony_ci els_cmd = bsg_request->rqst_data.h_els.command_code; 30162306a36Sopenharmony_ci if (els_cmd == ELS_AUTH_ELS) 30262306a36Sopenharmony_ci return qla_edif_process_els(vha, bsg_job); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!vha->flags.online) { 30662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n"); 30762306a36Sopenharmony_ci rval = -EIO; 30862306a36Sopenharmony_ci goto done; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* pass through is supported only for ISP 4Gb or higher */ 31262306a36Sopenharmony_ci if (!IS_FWI2_CAPABLE(ha)) { 31362306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7001, 31462306a36Sopenharmony_ci "ELS passthru not supported for ISP23xx based adapters.\n"); 31562306a36Sopenharmony_ci rval = -EPERM; 31662306a36Sopenharmony_ci goto done; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Multiple SG's are not supported for ELS requests */ 32062306a36Sopenharmony_ci if (bsg_job->request_payload.sg_cnt > 1 || 32162306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt > 1) { 32262306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7002, 32362306a36Sopenharmony_ci "Multiple SG's are not supported for ELS requests, " 32462306a36Sopenharmony_ci "request_sg_cnt=%x reply_sg_cnt=%x.\n", 32562306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, 32662306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt); 32762306a36Sopenharmony_ci rval = -EPERM; 32862306a36Sopenharmony_ci goto done; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* ELS request for rport */ 33262306a36Sopenharmony_ci if (bsg_request->msgcode == FC_BSG_RPT_ELS) { 33362306a36Sopenharmony_ci /* make sure the rport is logged in, 33462306a36Sopenharmony_ci * if not perform fabric login 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci if (atomic_read(&fcport->state) != FCS_ONLINE) { 33762306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7003, 33862306a36Sopenharmony_ci "Port %06X is not online for ELS passthru.\n", 33962306a36Sopenharmony_ci fcport->d_id.b24); 34062306a36Sopenharmony_ci rval = -EIO; 34162306a36Sopenharmony_ci goto done; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci /* Allocate a dummy fcport structure, since functions 34562306a36Sopenharmony_ci * preparing the IOCB and mailbox command retrieves port 34662306a36Sopenharmony_ci * specific information from fcport structure. For Host based 34762306a36Sopenharmony_ci * ELS commands there will be no fcport structure allocated 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_ci fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); 35062306a36Sopenharmony_ci if (!fcport) { 35162306a36Sopenharmony_ci rval = -ENOMEM; 35262306a36Sopenharmony_ci goto done; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci qla_port_allocated = 1; 35662306a36Sopenharmony_ci /* Initialize all required fields of fcport */ 35762306a36Sopenharmony_ci fcport->vha = vha; 35862306a36Sopenharmony_ci fcport->d_id.b.al_pa = 35962306a36Sopenharmony_ci bsg_request->rqst_data.h_els.port_id[0]; 36062306a36Sopenharmony_ci fcport->d_id.b.area = 36162306a36Sopenharmony_ci bsg_request->rqst_data.h_els.port_id[1]; 36262306a36Sopenharmony_ci fcport->d_id.b.domain = 36362306a36Sopenharmony_ci bsg_request->rqst_data.h_els.port_id[2]; 36462306a36Sopenharmony_ci fcport->loop_id = 36562306a36Sopenharmony_ci (fcport->d_id.b.al_pa == 0xFD) ? 36662306a36Sopenharmony_ci NPH_FABRIC_CONTROLLER : NPH_F_PORT; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci req_sg_cnt = 37062306a36Sopenharmony_ci dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, 37162306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 37262306a36Sopenharmony_ci if (!req_sg_cnt) { 37362306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, 37462306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 37562306a36Sopenharmony_ci rval = -ENOMEM; 37662306a36Sopenharmony_ci goto done_free_fcport; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, 38062306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 38162306a36Sopenharmony_ci if (!rsp_sg_cnt) { 38262306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, 38362306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 38462306a36Sopenharmony_ci rval = -ENOMEM; 38562306a36Sopenharmony_ci goto done_free_fcport; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || 38962306a36Sopenharmony_ci (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { 39062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7008, 39162306a36Sopenharmony_ci "dma mapping resulted in different sg counts, " 39262306a36Sopenharmony_ci "request_sg_cnt: %x dma_request_sg_cnt:%x reply_sg_cnt:%x " 39362306a36Sopenharmony_ci "dma_reply_sg_cnt:%x.\n", bsg_job->request_payload.sg_cnt, 39462306a36Sopenharmony_ci req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt); 39562306a36Sopenharmony_ci rval = -EAGAIN; 39662306a36Sopenharmony_ci goto done_unmap_sg; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Alloc SRB structure */ 40062306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 40162306a36Sopenharmony_ci if (!sp) { 40262306a36Sopenharmony_ci rval = -ENOMEM; 40362306a36Sopenharmony_ci goto done_unmap_sg; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci sp->type = 40762306a36Sopenharmony_ci (bsg_request->msgcode == FC_BSG_RPT_ELS ? 40862306a36Sopenharmony_ci SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); 40962306a36Sopenharmony_ci sp->name = 41062306a36Sopenharmony_ci (bsg_request->msgcode == FC_BSG_RPT_ELS ? 41162306a36Sopenharmony_ci "bsg_els_rpt" : "bsg_els_hst"); 41262306a36Sopenharmony_ci sp->u.bsg_job = bsg_job; 41362306a36Sopenharmony_ci sp->free = qla2x00_bsg_sp_free; 41462306a36Sopenharmony_ci sp->done = qla2x00_bsg_job_done; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x700a, 41762306a36Sopenharmony_ci "bsg rqst type: %s els type: %x - loop-id=%x " 41862306a36Sopenharmony_ci "portid=%-2x%02x%02x.\n", type, 41962306a36Sopenharmony_ci bsg_request->rqst_data.h_els.command_code, fcport->loop_id, 42062306a36Sopenharmony_ci fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 42362306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 42462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x700e, 42562306a36Sopenharmony_ci "qla2x00_start_sp failed = %d\n", rval); 42662306a36Sopenharmony_ci qla2x00_rel_sp(sp); 42762306a36Sopenharmony_ci rval = -EIO; 42862306a36Sopenharmony_ci goto done_unmap_sg; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci return rval; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cidone_unmap_sg: 43362306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, 43462306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 43562306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, 43662306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 43762306a36Sopenharmony_ci goto done_free_fcport; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cidone_free_fcport: 44062306a36Sopenharmony_ci if (qla_port_allocated) 44162306a36Sopenharmony_ci qla2x00_free_fcport(fcport); 44262306a36Sopenharmony_cidone: 44362306a36Sopenharmony_ci return rval; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic inline uint16_t 44762306a36Sopenharmony_ciqla24xx_calc_ct_iocbs(uint16_t dsds) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci uint16_t iocbs; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci iocbs = 1; 45262306a36Sopenharmony_ci if (dsds > 2) { 45362306a36Sopenharmony_ci iocbs += (dsds - 2) / 5; 45462306a36Sopenharmony_ci if ((dsds - 2) % 5) 45562306a36Sopenharmony_ci iocbs++; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci return iocbs; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic int 46162306a36Sopenharmony_ciqla2x00_process_ct(struct bsg_job *bsg_job) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci srb_t *sp; 46462306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 46562306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 46662306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 46762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 46862306a36Sopenharmony_ci int rval = (DID_ERROR << 16); 46962306a36Sopenharmony_ci int req_sg_cnt, rsp_sg_cnt; 47062306a36Sopenharmony_ci uint16_t loop_id; 47162306a36Sopenharmony_ci struct fc_port *fcport; 47262306a36Sopenharmony_ci char *type = "FC_BSG_HST_CT"; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci req_sg_cnt = 47562306a36Sopenharmony_ci dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, 47662306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 47762306a36Sopenharmony_ci if (!req_sg_cnt) { 47862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x700f, 47962306a36Sopenharmony_ci "dma_map_sg return %d for request\n", req_sg_cnt); 48062306a36Sopenharmony_ci rval = -ENOMEM; 48162306a36Sopenharmony_ci goto done; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, 48562306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 48662306a36Sopenharmony_ci if (!rsp_sg_cnt) { 48762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7010, 48862306a36Sopenharmony_ci "dma_map_sg return %d for reply\n", rsp_sg_cnt); 48962306a36Sopenharmony_ci rval = -ENOMEM; 49062306a36Sopenharmony_ci goto done; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || 49462306a36Sopenharmony_ci (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { 49562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7011, 49662306a36Sopenharmony_ci "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x " 49762306a36Sopenharmony_ci "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt, 49862306a36Sopenharmony_ci req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt); 49962306a36Sopenharmony_ci rval = -EAGAIN; 50062306a36Sopenharmony_ci goto done_unmap_sg; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (!vha->flags.online) { 50462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7012, 50562306a36Sopenharmony_ci "Host is not online.\n"); 50662306a36Sopenharmony_ci rval = -EIO; 50762306a36Sopenharmony_ci goto done_unmap_sg; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci loop_id = 51162306a36Sopenharmony_ci (bsg_request->rqst_data.h_ct.preamble_word1 & 0xFF000000) 51262306a36Sopenharmony_ci >> 24; 51362306a36Sopenharmony_ci switch (loop_id) { 51462306a36Sopenharmony_ci case 0xFC: 51562306a36Sopenharmony_ci loop_id = NPH_SNS; 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci case 0xFA: 51862306a36Sopenharmony_ci loop_id = vha->mgmt_svr_loop_id; 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci default: 52162306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7013, 52262306a36Sopenharmony_ci "Unknown loop id: %x.\n", loop_id); 52362306a36Sopenharmony_ci rval = -EINVAL; 52462306a36Sopenharmony_ci goto done_unmap_sg; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* Allocate a dummy fcport structure, since functions preparing the 52862306a36Sopenharmony_ci * IOCB and mailbox command retrieves port specific information 52962306a36Sopenharmony_ci * from fcport structure. For Host based ELS commands there will be 53062306a36Sopenharmony_ci * no fcport structure allocated 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_ci fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); 53362306a36Sopenharmony_ci if (!fcport) { 53462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7014, 53562306a36Sopenharmony_ci "Failed to allocate fcport.\n"); 53662306a36Sopenharmony_ci rval = -ENOMEM; 53762306a36Sopenharmony_ci goto done_unmap_sg; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* Initialize all required fields of fcport */ 54162306a36Sopenharmony_ci fcport->vha = vha; 54262306a36Sopenharmony_ci fcport->d_id.b.al_pa = bsg_request->rqst_data.h_ct.port_id[0]; 54362306a36Sopenharmony_ci fcport->d_id.b.area = bsg_request->rqst_data.h_ct.port_id[1]; 54462306a36Sopenharmony_ci fcport->d_id.b.domain = bsg_request->rqst_data.h_ct.port_id[2]; 54562306a36Sopenharmony_ci fcport->loop_id = loop_id; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Alloc SRB structure */ 54862306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 54962306a36Sopenharmony_ci if (!sp) { 55062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7015, 55162306a36Sopenharmony_ci "qla2x00_get_sp failed.\n"); 55262306a36Sopenharmony_ci rval = -ENOMEM; 55362306a36Sopenharmony_ci goto done_free_fcport; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci sp->type = SRB_CT_CMD; 55762306a36Sopenharmony_ci sp->name = "bsg_ct"; 55862306a36Sopenharmony_ci sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt); 55962306a36Sopenharmony_ci sp->u.bsg_job = bsg_job; 56062306a36Sopenharmony_ci sp->free = qla2x00_bsg_sp_free; 56162306a36Sopenharmony_ci sp->done = qla2x00_bsg_job_done; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7016, 56462306a36Sopenharmony_ci "bsg rqst type: %s else type: %x - " 56562306a36Sopenharmony_ci "loop-id=%x portid=%02x%02x%02x.\n", type, 56662306a36Sopenharmony_ci (bsg_request->rqst_data.h_ct.preamble_word2 >> 16), 56762306a36Sopenharmony_ci fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, 56862306a36Sopenharmony_ci fcport->d_id.b.al_pa); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 57162306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 57262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7017, 57362306a36Sopenharmony_ci "qla2x00_start_sp failed=%d.\n", rval); 57462306a36Sopenharmony_ci qla2x00_rel_sp(sp); 57562306a36Sopenharmony_ci rval = -EIO; 57662306a36Sopenharmony_ci goto done_free_fcport; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci return rval; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cidone_free_fcport: 58162306a36Sopenharmony_ci qla2x00_free_fcport(fcport); 58262306a36Sopenharmony_cidone_unmap_sg: 58362306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, 58462306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 58562306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, 58662306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 58762306a36Sopenharmony_cidone: 58862306a36Sopenharmony_ci return rval; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci/* Disable loopback mode */ 59262306a36Sopenharmony_cistatic inline int 59362306a36Sopenharmony_ciqla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config, 59462306a36Sopenharmony_ci int wait, int wait2) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci int ret = 0; 59762306a36Sopenharmony_ci int rval = 0; 59862306a36Sopenharmony_ci uint16_t new_config[4]; 59962306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha)) 60262306a36Sopenharmony_ci goto done_reset_internal; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci memset(new_config, 0 , sizeof(new_config)); 60562306a36Sopenharmony_ci if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == 60662306a36Sopenharmony_ci ENABLE_INTERNAL_LOOPBACK || 60762306a36Sopenharmony_ci (config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == 60862306a36Sopenharmony_ci ENABLE_EXTERNAL_LOOPBACK) { 60962306a36Sopenharmony_ci new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK; 61062306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70bf, "new_config[0]=%02x\n", 61162306a36Sopenharmony_ci (new_config[0] & INTERNAL_LOOPBACK_MASK)); 61262306a36Sopenharmony_ci memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci ha->notify_dcbx_comp = wait; 61562306a36Sopenharmony_ci ha->notify_lb_portup_comp = wait2; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci ret = qla81xx_set_port_config(vha, new_config); 61862306a36Sopenharmony_ci if (ret != QLA_SUCCESS) { 61962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7025, 62062306a36Sopenharmony_ci "Set port config failed.\n"); 62162306a36Sopenharmony_ci ha->notify_dcbx_comp = 0; 62262306a36Sopenharmony_ci ha->notify_lb_portup_comp = 0; 62362306a36Sopenharmony_ci rval = -EINVAL; 62462306a36Sopenharmony_ci goto done_reset_internal; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* Wait for DCBX complete event */ 62862306a36Sopenharmony_ci if (wait && !wait_for_completion_timeout(&ha->dcbx_comp, 62962306a36Sopenharmony_ci (DCBX_COMP_TIMEOUT * HZ))) { 63062306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7026, 63162306a36Sopenharmony_ci "DCBX completion not received.\n"); 63262306a36Sopenharmony_ci ha->notify_dcbx_comp = 0; 63362306a36Sopenharmony_ci ha->notify_lb_portup_comp = 0; 63462306a36Sopenharmony_ci rval = -EINVAL; 63562306a36Sopenharmony_ci goto done_reset_internal; 63662306a36Sopenharmony_ci } else 63762306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7027, 63862306a36Sopenharmony_ci "DCBX completion received.\n"); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (wait2 && 64162306a36Sopenharmony_ci !wait_for_completion_timeout(&ha->lb_portup_comp, 64262306a36Sopenharmony_ci (LB_PORTUP_COMP_TIMEOUT * HZ))) { 64362306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70c5, 64462306a36Sopenharmony_ci "Port up completion not received.\n"); 64562306a36Sopenharmony_ci ha->notify_lb_portup_comp = 0; 64662306a36Sopenharmony_ci rval = -EINVAL; 64762306a36Sopenharmony_ci goto done_reset_internal; 64862306a36Sopenharmony_ci } else 64962306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70c6, 65062306a36Sopenharmony_ci "Port up completion received.\n"); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci ha->notify_dcbx_comp = 0; 65362306a36Sopenharmony_ci ha->notify_lb_portup_comp = 0; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_cidone_reset_internal: 65662306a36Sopenharmony_ci return rval; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/* 66062306a36Sopenharmony_ci * Set the port configuration to enable the internal or external loopback 66162306a36Sopenharmony_ci * depending on the loopback mode. 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_cistatic inline int 66462306a36Sopenharmony_ciqla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config, 66562306a36Sopenharmony_ci uint16_t *new_config, uint16_t mode) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci int ret = 0; 66862306a36Sopenharmony_ci int rval = 0; 66962306a36Sopenharmony_ci unsigned long rem_tmo = 0, current_tmo = 0; 67062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha)) 67362306a36Sopenharmony_ci goto done_set_internal; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci if (mode == INTERNAL_LOOPBACK) 67662306a36Sopenharmony_ci new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1); 67762306a36Sopenharmony_ci else if (mode == EXTERNAL_LOOPBACK) 67862306a36Sopenharmony_ci new_config[0] = config[0] | (ENABLE_EXTERNAL_LOOPBACK << 1); 67962306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70be, 68062306a36Sopenharmony_ci "new_config[0]=%02x\n", (new_config[0] & INTERNAL_LOOPBACK_MASK)); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci ha->notify_dcbx_comp = 1; 68562306a36Sopenharmony_ci ret = qla81xx_set_port_config(vha, new_config); 68662306a36Sopenharmony_ci if (ret != QLA_SUCCESS) { 68762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7021, 68862306a36Sopenharmony_ci "set port config failed.\n"); 68962306a36Sopenharmony_ci ha->notify_dcbx_comp = 0; 69062306a36Sopenharmony_ci rval = -EINVAL; 69162306a36Sopenharmony_ci goto done_set_internal; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* Wait for DCBX complete event */ 69562306a36Sopenharmony_ci current_tmo = DCBX_COMP_TIMEOUT * HZ; 69662306a36Sopenharmony_ci while (1) { 69762306a36Sopenharmony_ci rem_tmo = wait_for_completion_timeout(&ha->dcbx_comp, 69862306a36Sopenharmony_ci current_tmo); 69962306a36Sopenharmony_ci if (!ha->idc_extend_tmo || rem_tmo) { 70062306a36Sopenharmony_ci ha->idc_extend_tmo = 0; 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci current_tmo = ha->idc_extend_tmo * HZ; 70462306a36Sopenharmony_ci ha->idc_extend_tmo = 0; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (!rem_tmo) { 70862306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7022, 70962306a36Sopenharmony_ci "DCBX completion not received.\n"); 71062306a36Sopenharmony_ci ret = qla81xx_reset_loopback_mode(vha, new_config, 0, 0); 71162306a36Sopenharmony_ci /* 71262306a36Sopenharmony_ci * If the reset of the loopback mode doesn't work take a FCoE 71362306a36Sopenharmony_ci * dump and reset the chip. 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_ci if (ret) { 71662306a36Sopenharmony_ci qla2xxx_dump_fw(vha); 71762306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci rval = -EINVAL; 72062306a36Sopenharmony_ci } else { 72162306a36Sopenharmony_ci if (ha->flags.idc_compl_status) { 72262306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70c3, 72362306a36Sopenharmony_ci "Bad status in IDC Completion AEN\n"); 72462306a36Sopenharmony_ci rval = -EINVAL; 72562306a36Sopenharmony_ci ha->flags.idc_compl_status = 0; 72662306a36Sopenharmony_ci } else 72762306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7023, 72862306a36Sopenharmony_ci "DCBX completion received.\n"); 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci ha->notify_dcbx_comp = 0; 73262306a36Sopenharmony_ci ha->idc_extend_tmo = 0; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cidone_set_internal: 73562306a36Sopenharmony_ci return rval; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic int 73962306a36Sopenharmony_ciqla2x00_process_loopback(struct bsg_job *bsg_job) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 74262306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 74362306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 74462306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 74562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 74662306a36Sopenharmony_ci int rval; 74762306a36Sopenharmony_ci uint8_t command_sent; 74862306a36Sopenharmony_ci char *type; 74962306a36Sopenharmony_ci struct msg_echo_lb elreq; 75062306a36Sopenharmony_ci uint16_t response[MAILBOX_REGISTER_COUNT]; 75162306a36Sopenharmony_ci uint16_t config[4], new_config[4]; 75262306a36Sopenharmony_ci uint8_t *fw_sts_ptr; 75362306a36Sopenharmony_ci void *req_data = NULL; 75462306a36Sopenharmony_ci dma_addr_t req_data_dma; 75562306a36Sopenharmony_ci uint32_t req_data_len; 75662306a36Sopenharmony_ci uint8_t *rsp_data = NULL; 75762306a36Sopenharmony_ci dma_addr_t rsp_data_dma; 75862306a36Sopenharmony_ci uint32_t rsp_data_len; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (!vha->flags.online) { 76162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7019, "Host is not online.\n"); 76262306a36Sopenharmony_ci return -EIO; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci memset(&elreq, 0, sizeof(elreq)); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev, 76862306a36Sopenharmony_ci bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, 76962306a36Sopenharmony_ci DMA_TO_DEVICE); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (!elreq.req_sg_cnt) { 77262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x701a, 77362306a36Sopenharmony_ci "dma_map_sg returned %d for request.\n", elreq.req_sg_cnt); 77462306a36Sopenharmony_ci return -ENOMEM; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci elreq.rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, 77862306a36Sopenharmony_ci bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt, 77962306a36Sopenharmony_ci DMA_FROM_DEVICE); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (!elreq.rsp_sg_cnt) { 78262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x701b, 78362306a36Sopenharmony_ci "dma_map_sg returned %d for reply.\n", elreq.rsp_sg_cnt); 78462306a36Sopenharmony_ci rval = -ENOMEM; 78562306a36Sopenharmony_ci goto done_unmap_req_sg; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if ((elreq.req_sg_cnt != bsg_job->request_payload.sg_cnt) || 78962306a36Sopenharmony_ci (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { 79062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x701c, 79162306a36Sopenharmony_ci "dma mapping resulted in different sg counts, " 79262306a36Sopenharmony_ci "request_sg_cnt: %x dma_request_sg_cnt: %x " 79362306a36Sopenharmony_ci "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n", 79462306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt, 79562306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt); 79662306a36Sopenharmony_ci rval = -EAGAIN; 79762306a36Sopenharmony_ci goto done_unmap_sg; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; 80062306a36Sopenharmony_ci req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len, 80162306a36Sopenharmony_ci &req_data_dma, GFP_KERNEL); 80262306a36Sopenharmony_ci if (!req_data) { 80362306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x701d, 80462306a36Sopenharmony_ci "dma alloc failed for req_data.\n"); 80562306a36Sopenharmony_ci rval = -ENOMEM; 80662306a36Sopenharmony_ci goto done_unmap_sg; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len, 81062306a36Sopenharmony_ci &rsp_data_dma, GFP_KERNEL); 81162306a36Sopenharmony_ci if (!rsp_data) { 81262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7004, 81362306a36Sopenharmony_ci "dma alloc failed for rsp_data.\n"); 81462306a36Sopenharmony_ci rval = -ENOMEM; 81562306a36Sopenharmony_ci goto done_free_dma_req; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* Copy the request buffer in req_data now */ 81962306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 82062306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, req_data, req_data_len); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci elreq.send_dma = req_data_dma; 82362306a36Sopenharmony_ci elreq.rcv_dma = rsp_data_dma; 82462306a36Sopenharmony_ci elreq.transfer_size = req_data_len; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci elreq.options = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; 82762306a36Sopenharmony_ci elreq.iteration_count = 82862306a36Sopenharmony_ci bsg_request->rqst_data.h_vendor.vendor_cmd[2]; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (atomic_read(&vha->loop_state) == LOOP_READY && 83162306a36Sopenharmony_ci ((ha->current_topology == ISP_CFG_F && (elreq.options & 7) >= 2) || 83262306a36Sopenharmony_ci ((IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) && 83362306a36Sopenharmony_ci get_unaligned_le32(req_data) == ELS_OPCODE_BYTE && 83462306a36Sopenharmony_ci req_data_len == MAX_ELS_FRAME_PAYLOAD && 83562306a36Sopenharmony_ci elreq.options == EXTERNAL_LOOPBACK))) { 83662306a36Sopenharmony_ci type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; 83762306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x701e, 83862306a36Sopenharmony_ci "BSG request type: %s.\n", type); 83962306a36Sopenharmony_ci command_sent = INT_DEF_LB_ECHO_CMD; 84062306a36Sopenharmony_ci rval = qla2x00_echo_test(vha, &elreq, response); 84162306a36Sopenharmony_ci } else { 84262306a36Sopenharmony_ci if (IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) { 84362306a36Sopenharmony_ci memset(config, 0, sizeof(config)); 84462306a36Sopenharmony_ci memset(new_config, 0, sizeof(new_config)); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (qla81xx_get_port_config(vha, config)) { 84762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x701f, 84862306a36Sopenharmony_ci "Get port config failed.\n"); 84962306a36Sopenharmony_ci rval = -EPERM; 85062306a36Sopenharmony_ci goto done_free_dma_rsp; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if ((config[0] & INTERNAL_LOOPBACK_MASK) != 0) { 85462306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70c4, 85562306a36Sopenharmony_ci "Loopback operation already in " 85662306a36Sopenharmony_ci "progress.\n"); 85762306a36Sopenharmony_ci rval = -EAGAIN; 85862306a36Sopenharmony_ci goto done_free_dma_rsp; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70c0, 86262306a36Sopenharmony_ci "elreq.options=%04x\n", elreq.options); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (elreq.options == EXTERNAL_LOOPBACK) 86562306a36Sopenharmony_ci if (IS_QLA8031(ha) || IS_QLA8044(ha)) 86662306a36Sopenharmony_ci rval = qla81xx_set_loopback_mode(vha, 86762306a36Sopenharmony_ci config, new_config, elreq.options); 86862306a36Sopenharmony_ci else 86962306a36Sopenharmony_ci rval = qla81xx_reset_loopback_mode(vha, 87062306a36Sopenharmony_ci config, 1, 0); 87162306a36Sopenharmony_ci else 87262306a36Sopenharmony_ci rval = qla81xx_set_loopback_mode(vha, config, 87362306a36Sopenharmony_ci new_config, elreq.options); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (rval) { 87662306a36Sopenharmony_ci rval = -EPERM; 87762306a36Sopenharmony_ci goto done_free_dma_rsp; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci type = "FC_BSG_HST_VENDOR_LOOPBACK"; 88162306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7028, 88262306a36Sopenharmony_ci "BSG request type: %s.\n", type); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci command_sent = INT_DEF_LB_LOOPBACK_CMD; 88562306a36Sopenharmony_ci rval = qla2x00_loopback_test(vha, &elreq, response); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (response[0] == MBS_COMMAND_ERROR && 88862306a36Sopenharmony_ci response[1] == MBS_LB_RESET) { 88962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7029, 89062306a36Sopenharmony_ci "MBX command error, Aborting ISP.\n"); 89162306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 89262306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 89362306a36Sopenharmony_ci qla2x00_wait_for_chip_reset(vha); 89462306a36Sopenharmony_ci /* Also reset the MPI */ 89562306a36Sopenharmony_ci if (IS_QLA81XX(ha)) { 89662306a36Sopenharmony_ci if (qla81xx_restart_mpi_firmware(vha) != 89762306a36Sopenharmony_ci QLA_SUCCESS) { 89862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x702a, 89962306a36Sopenharmony_ci "MPI reset failed.\n"); 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci rval = -EIO; 90462306a36Sopenharmony_ci goto done_free_dma_rsp; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (new_config[0]) { 90862306a36Sopenharmony_ci int ret; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* Revert back to original port config 91162306a36Sopenharmony_ci * Also clear internal loopback 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_ci ret = qla81xx_reset_loopback_mode(vha, 91462306a36Sopenharmony_ci new_config, 0, 1); 91562306a36Sopenharmony_ci if (ret) { 91662306a36Sopenharmony_ci /* 91762306a36Sopenharmony_ci * If the reset of the loopback mode 91862306a36Sopenharmony_ci * doesn't work take FCoE dump and then 91962306a36Sopenharmony_ci * reset the chip. 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_ci qla2xxx_dump_fw(vha); 92262306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 92362306a36Sopenharmony_ci &vha->dpc_flags); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci } else { 92962306a36Sopenharmony_ci type = "FC_BSG_HST_VENDOR_LOOPBACK"; 93062306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x702b, 93162306a36Sopenharmony_ci "BSG request type: %s.\n", type); 93262306a36Sopenharmony_ci command_sent = INT_DEF_LB_LOOPBACK_CMD; 93362306a36Sopenharmony_ci rval = qla2x00_loopback_test(vha, &elreq, response); 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (rval) { 93862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x702c, 93962306a36Sopenharmony_ci "Vendor request %s failed.\n", type); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci rval = 0; 94262306a36Sopenharmony_ci bsg_reply->result = (DID_ERROR << 16); 94362306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 94462306a36Sopenharmony_ci } else { 94562306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x702d, 94662306a36Sopenharmony_ci "Vendor request %s completed.\n", type); 94762306a36Sopenharmony_ci bsg_reply->result = (DID_OK << 16); 94862306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 94962306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, rsp_data, 95062306a36Sopenharmony_ci rsp_data_len); 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply) + 95462306a36Sopenharmony_ci sizeof(response) + sizeof(uint8_t); 95562306a36Sopenharmony_ci fw_sts_ptr = bsg_job->reply + sizeof(struct fc_bsg_reply); 95662306a36Sopenharmony_ci memcpy(bsg_job->reply + sizeof(struct fc_bsg_reply), response, 95762306a36Sopenharmony_ci sizeof(response)); 95862306a36Sopenharmony_ci fw_sts_ptr += sizeof(response); 95962306a36Sopenharmony_ci *fw_sts_ptr = command_sent; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cidone_free_dma_rsp: 96262306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, rsp_data_len, 96362306a36Sopenharmony_ci rsp_data, rsp_data_dma); 96462306a36Sopenharmony_cidone_free_dma_req: 96562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, req_data_len, 96662306a36Sopenharmony_ci req_data, req_data_dma); 96762306a36Sopenharmony_cidone_unmap_sg: 96862306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, 96962306a36Sopenharmony_ci bsg_job->reply_payload.sg_list, 97062306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 97162306a36Sopenharmony_cidone_unmap_req_sg: 97262306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, 97362306a36Sopenharmony_ci bsg_job->request_payload.sg_list, 97462306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 97562306a36Sopenharmony_ci if (!rval) 97662306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 97762306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 97862306a36Sopenharmony_ci return rval; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistatic int 98262306a36Sopenharmony_ciqla84xx_reset(struct bsg_job *bsg_job) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 98562306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 98662306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 98762306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 98862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 98962306a36Sopenharmony_ci int rval = 0; 99062306a36Sopenharmony_ci uint32_t flag; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (!IS_QLA84XX(ha)) { 99362306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x702f, "Not 84xx, exiting.\n"); 99462306a36Sopenharmony_ci return -EINVAL; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci if (rval) { 100262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7030, 100362306a36Sopenharmony_ci "Vendor request 84xx reset failed.\n"); 100462306a36Sopenharmony_ci rval = (DID_ERROR << 16); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci } else { 100762306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7031, 100862306a36Sopenharmony_ci "Vendor request 84xx reset completed.\n"); 100962306a36Sopenharmony_ci bsg_reply->result = DID_OK; 101062306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 101162306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci return rval; 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic int 101862306a36Sopenharmony_ciqla84xx_updatefw(struct bsg_job *bsg_job) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 102162306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 102262306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 102362306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 102462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 102562306a36Sopenharmony_ci struct verify_chip_entry_84xx *mn = NULL; 102662306a36Sopenharmony_ci dma_addr_t mn_dma, fw_dma; 102762306a36Sopenharmony_ci void *fw_buf = NULL; 102862306a36Sopenharmony_ci int rval = 0; 102962306a36Sopenharmony_ci uint32_t sg_cnt; 103062306a36Sopenharmony_ci uint32_t data_len; 103162306a36Sopenharmony_ci uint16_t options; 103262306a36Sopenharmony_ci uint32_t flag; 103362306a36Sopenharmony_ci uint32_t fw_ver; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (!IS_QLA84XX(ha)) { 103662306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7032, 103762306a36Sopenharmony_ci "Not 84xx, exiting.\n"); 103862306a36Sopenharmony_ci return -EINVAL; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, 104262306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 104362306a36Sopenharmony_ci if (!sg_cnt) { 104462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7033, 104562306a36Sopenharmony_ci "dma_map_sg returned %d for request.\n", sg_cnt); 104662306a36Sopenharmony_ci return -ENOMEM; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (sg_cnt != bsg_job->request_payload.sg_cnt) { 105062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7034, 105162306a36Sopenharmony_ci "DMA mapping resulted in different sg counts, " 105262306a36Sopenharmony_ci "request_sg_cnt: %x dma_request_sg_cnt: %x.\n", 105362306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, sg_cnt); 105462306a36Sopenharmony_ci rval = -EAGAIN; 105562306a36Sopenharmony_ci goto done_unmap_sg; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci data_len = bsg_job->request_payload.payload_len; 105962306a36Sopenharmony_ci fw_buf = dma_alloc_coherent(&ha->pdev->dev, data_len, 106062306a36Sopenharmony_ci &fw_dma, GFP_KERNEL); 106162306a36Sopenharmony_ci if (!fw_buf) { 106262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7035, 106362306a36Sopenharmony_ci "DMA alloc failed for fw_buf.\n"); 106462306a36Sopenharmony_ci rval = -ENOMEM; 106562306a36Sopenharmony_ci goto done_unmap_sg; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 106962306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, fw_buf, data_len); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci mn = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); 107262306a36Sopenharmony_ci if (!mn) { 107362306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7036, 107462306a36Sopenharmony_ci "DMA alloc failed for fw buffer.\n"); 107562306a36Sopenharmony_ci rval = -ENOMEM; 107662306a36Sopenharmony_ci goto done_free_fw_buf; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; 108062306a36Sopenharmony_ci fw_ver = get_unaligned_le32((uint32_t *)fw_buf + 2); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci mn->entry_type = VERIFY_CHIP_IOCB_TYPE; 108362306a36Sopenharmony_ci mn->entry_count = 1; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci options = VCO_FORCE_UPDATE | VCO_END_OF_DATA; 108662306a36Sopenharmony_ci if (flag == A84_ISSUE_UPDATE_DIAGFW_CMD) 108762306a36Sopenharmony_ci options |= VCO_DIAG_FW; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci mn->options = cpu_to_le16(options); 109062306a36Sopenharmony_ci mn->fw_ver = cpu_to_le32(fw_ver); 109162306a36Sopenharmony_ci mn->fw_size = cpu_to_le32(data_len); 109262306a36Sopenharmony_ci mn->fw_seq_size = cpu_to_le32(data_len); 109362306a36Sopenharmony_ci put_unaligned_le64(fw_dma, &mn->dsd.address); 109462306a36Sopenharmony_ci mn->dsd.length = cpu_to_le32(data_len); 109562306a36Sopenharmony_ci mn->data_seg_cnt = cpu_to_le16(1); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (rval) { 110062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7037, 110162306a36Sopenharmony_ci "Vendor request 84xx updatefw failed.\n"); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci rval = (DID_ERROR << 16); 110462306a36Sopenharmony_ci } else { 110562306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7038, 110662306a36Sopenharmony_ci "Vendor request 84xx updatefw completed.\n"); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 110962306a36Sopenharmony_ci bsg_reply->result = DID_OK; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, mn, mn_dma); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cidone_free_fw_buf: 111562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, data_len, fw_buf, fw_dma); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cidone_unmap_sg: 111862306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, 111962306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (!rval) 112262306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 112362306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 112462306a36Sopenharmony_ci return rval; 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cistatic int 112862306a36Sopenharmony_ciqla84xx_mgmt_cmd(struct bsg_job *bsg_job) 112962306a36Sopenharmony_ci{ 113062306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 113162306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 113262306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 113362306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 113462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 113562306a36Sopenharmony_ci struct access_chip_84xx *mn = NULL; 113662306a36Sopenharmony_ci dma_addr_t mn_dma, mgmt_dma; 113762306a36Sopenharmony_ci void *mgmt_b = NULL; 113862306a36Sopenharmony_ci int rval = 0; 113962306a36Sopenharmony_ci struct qla_bsg_a84_mgmt *ql84_mgmt; 114062306a36Sopenharmony_ci uint32_t sg_cnt; 114162306a36Sopenharmony_ci uint32_t data_len = 0; 114262306a36Sopenharmony_ci uint32_t dma_direction = DMA_NONE; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (!IS_QLA84XX(ha)) { 114562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x703a, 114662306a36Sopenharmony_ci "Not 84xx, exiting.\n"); 114762306a36Sopenharmony_ci return -EINVAL; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci mn = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); 115162306a36Sopenharmony_ci if (!mn) { 115262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x703c, 115362306a36Sopenharmony_ci "DMA alloc failed for fw buffer.\n"); 115462306a36Sopenharmony_ci return -ENOMEM; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci mn->entry_type = ACCESS_CHIP_IOCB_TYPE; 115862306a36Sopenharmony_ci mn->entry_count = 1; 115962306a36Sopenharmony_ci ql84_mgmt = (void *)bsg_request + sizeof(struct fc_bsg_request); 116062306a36Sopenharmony_ci switch (ql84_mgmt->mgmt.cmd) { 116162306a36Sopenharmony_ci case QLA84_MGMT_READ_MEM: 116262306a36Sopenharmony_ci case QLA84_MGMT_GET_INFO: 116362306a36Sopenharmony_ci sg_cnt = dma_map_sg(&ha->pdev->dev, 116462306a36Sopenharmony_ci bsg_job->reply_payload.sg_list, 116562306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 116662306a36Sopenharmony_ci if (!sg_cnt) { 116762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x703d, 116862306a36Sopenharmony_ci "dma_map_sg returned %d for reply.\n", sg_cnt); 116962306a36Sopenharmony_ci rval = -ENOMEM; 117062306a36Sopenharmony_ci goto exit_mgmt; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci dma_direction = DMA_FROM_DEVICE; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (sg_cnt != bsg_job->reply_payload.sg_cnt) { 117662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x703e, 117762306a36Sopenharmony_ci "DMA mapping resulted in different sg counts, " 117862306a36Sopenharmony_ci "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n", 117962306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, sg_cnt); 118062306a36Sopenharmony_ci rval = -EAGAIN; 118162306a36Sopenharmony_ci goto done_unmap_sg; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci data_len = bsg_job->reply_payload.payload_len; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len, 118762306a36Sopenharmony_ci &mgmt_dma, GFP_KERNEL); 118862306a36Sopenharmony_ci if (!mgmt_b) { 118962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x703f, 119062306a36Sopenharmony_ci "DMA alloc failed for mgmt_b.\n"); 119162306a36Sopenharmony_ci rval = -ENOMEM; 119262306a36Sopenharmony_ci goto done_unmap_sg; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) { 119662306a36Sopenharmony_ci mn->options = cpu_to_le16(ACO_DUMP_MEMORY); 119762306a36Sopenharmony_ci mn->parameter1 = 119862306a36Sopenharmony_ci cpu_to_le32( 119962306a36Sopenharmony_ci ql84_mgmt->mgmt.mgmtp.u.mem.start_addr); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci } else if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO) { 120262306a36Sopenharmony_ci mn->options = cpu_to_le16(ACO_REQUEST_INFO); 120362306a36Sopenharmony_ci mn->parameter1 = 120462306a36Sopenharmony_ci cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.info.type); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci mn->parameter2 = 120762306a36Sopenharmony_ci cpu_to_le32( 120862306a36Sopenharmony_ci ql84_mgmt->mgmt.mgmtp.u.info.context); 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci break; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci case QLA84_MGMT_WRITE_MEM: 121362306a36Sopenharmony_ci sg_cnt = dma_map_sg(&ha->pdev->dev, 121462306a36Sopenharmony_ci bsg_job->request_payload.sg_list, 121562306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci if (!sg_cnt) { 121862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7040, 121962306a36Sopenharmony_ci "dma_map_sg returned %d.\n", sg_cnt); 122062306a36Sopenharmony_ci rval = -ENOMEM; 122162306a36Sopenharmony_ci goto exit_mgmt; 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci dma_direction = DMA_TO_DEVICE; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (sg_cnt != bsg_job->request_payload.sg_cnt) { 122762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7041, 122862306a36Sopenharmony_ci "DMA mapping resulted in different sg counts, " 122962306a36Sopenharmony_ci "request_sg_cnt: %x dma_request_sg_cnt: %x.\n", 123062306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, sg_cnt); 123162306a36Sopenharmony_ci rval = -EAGAIN; 123262306a36Sopenharmony_ci goto done_unmap_sg; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci data_len = bsg_job->request_payload.payload_len; 123662306a36Sopenharmony_ci mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len, 123762306a36Sopenharmony_ci &mgmt_dma, GFP_KERNEL); 123862306a36Sopenharmony_ci if (!mgmt_b) { 123962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7042, 124062306a36Sopenharmony_ci "DMA alloc failed for mgmt_b.\n"); 124162306a36Sopenharmony_ci rval = -ENOMEM; 124262306a36Sopenharmony_ci goto done_unmap_sg; 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 124662306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, mgmt_b, data_len); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci mn->options = cpu_to_le16(ACO_LOAD_MEMORY); 124962306a36Sopenharmony_ci mn->parameter1 = 125062306a36Sopenharmony_ci cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.mem.start_addr); 125162306a36Sopenharmony_ci break; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci case QLA84_MGMT_CHNG_CONFIG: 125462306a36Sopenharmony_ci mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); 125562306a36Sopenharmony_ci mn->parameter1 = 125662306a36Sopenharmony_ci cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.id); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci mn->parameter2 = 125962306a36Sopenharmony_ci cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param0); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci mn->parameter3 = 126262306a36Sopenharmony_ci cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param1); 126362306a36Sopenharmony_ci break; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci default: 126662306a36Sopenharmony_ci rval = -EIO; 126762306a36Sopenharmony_ci goto exit_mgmt; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci if (ql84_mgmt->mgmt.cmd != QLA84_MGMT_CHNG_CONFIG) { 127162306a36Sopenharmony_ci mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->mgmt.len); 127262306a36Sopenharmony_ci mn->dseg_count = cpu_to_le16(1); 127362306a36Sopenharmony_ci put_unaligned_le64(mgmt_dma, &mn->dsd.address); 127462306a36Sopenharmony_ci mn->dsd.length = cpu_to_le32(ql84_mgmt->mgmt.len); 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci if (rval) { 128062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7043, 128162306a36Sopenharmony_ci "Vendor request 84xx mgmt failed.\n"); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci rval = (DID_ERROR << 16); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci } else { 128662306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7044, 128762306a36Sopenharmony_ci "Vendor request 84xx mgmt completed.\n"); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 129062306a36Sopenharmony_ci bsg_reply->result = DID_OK; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if ((ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) || 129362306a36Sopenharmony_ci (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO)) { 129462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 129562306a36Sopenharmony_ci bsg_job->reply_payload.payload_len; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 129862306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, mgmt_b, 129962306a36Sopenharmony_ci data_len); 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_cidone_unmap_sg: 130462306a36Sopenharmony_ci if (mgmt_b) 130562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, data_len, mgmt_b, mgmt_dma); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (dma_direction == DMA_TO_DEVICE) 130862306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, 130962306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 131062306a36Sopenharmony_ci else if (dma_direction == DMA_FROM_DEVICE) 131162306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, 131262306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ciexit_mgmt: 131562306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, mn, mn_dma); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci if (!rval) 131862306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 131962306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 132062306a36Sopenharmony_ci return rval; 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_cistatic int 132462306a36Sopenharmony_ciqla24xx_iidma(struct bsg_job *bsg_job) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 132762306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 132862306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 132962306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 133062306a36Sopenharmony_ci int rval = 0; 133162306a36Sopenharmony_ci struct qla_port_param *port_param = NULL; 133262306a36Sopenharmony_ci fc_port_t *fcport = NULL; 133362306a36Sopenharmony_ci int found = 0; 133462306a36Sopenharmony_ci uint16_t mb[MAILBOX_REGISTER_COUNT]; 133562306a36Sopenharmony_ci uint8_t *rsp_ptr = NULL; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (!IS_IIDMA_CAPABLE(vha->hw)) { 133862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x7046, "iiDMA not supported.\n"); 133962306a36Sopenharmony_ci return -EINVAL; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci port_param = (void *)bsg_request + sizeof(struct fc_bsg_request); 134362306a36Sopenharmony_ci if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) { 134462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7048, 134562306a36Sopenharmony_ci "Invalid destination type.\n"); 134662306a36Sopenharmony_ci return -EINVAL; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 135062306a36Sopenharmony_ci if (fcport->port_type != FCT_TARGET) 135162306a36Sopenharmony_ci continue; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn, 135462306a36Sopenharmony_ci fcport->port_name, sizeof(fcport->port_name))) 135562306a36Sopenharmony_ci continue; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci found = 1; 135862306a36Sopenharmony_ci break; 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci if (!found) { 136262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7049, 136362306a36Sopenharmony_ci "Failed to find port.\n"); 136462306a36Sopenharmony_ci return -EINVAL; 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if (atomic_read(&fcport->state) != FCS_ONLINE) { 136862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x704a, 136962306a36Sopenharmony_ci "Port is not online.\n"); 137062306a36Sopenharmony_ci return -EINVAL; 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (fcport->flags & FCF_LOGIN_NEEDED) { 137462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x704b, 137562306a36Sopenharmony_ci "Remote port not logged in flags = 0x%x.\n", fcport->flags); 137662306a36Sopenharmony_ci return -EINVAL; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci if (port_param->mode) 138062306a36Sopenharmony_ci rval = qla2x00_set_idma_speed(vha, fcport->loop_id, 138162306a36Sopenharmony_ci port_param->speed, mb); 138262306a36Sopenharmony_ci else 138362306a36Sopenharmony_ci rval = qla2x00_get_idma_speed(vha, fcport->loop_id, 138462306a36Sopenharmony_ci &port_param->speed, mb); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (rval) { 138762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x704c, 138862306a36Sopenharmony_ci "iiDMA cmd failed for %8phN -- " 138962306a36Sopenharmony_ci "%04x %x %04x %04x.\n", fcport->port_name, 139062306a36Sopenharmony_ci rval, fcport->fp_speed, mb[0], mb[1]); 139162306a36Sopenharmony_ci rval = (DID_ERROR << 16); 139262306a36Sopenharmony_ci } else { 139362306a36Sopenharmony_ci if (!port_param->mode) { 139462306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply) + 139562306a36Sopenharmony_ci sizeof(struct qla_port_param); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci rsp_ptr = ((uint8_t *)bsg_reply) + 139862306a36Sopenharmony_ci sizeof(struct fc_bsg_reply); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci memcpy(rsp_ptr, port_param, 140162306a36Sopenharmony_ci sizeof(struct qla_port_param)); 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci bsg_reply->result = DID_OK; 140562306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 140662306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci return rval; 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_cistatic int 141362306a36Sopenharmony_ciqla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha, 141462306a36Sopenharmony_ci uint8_t is_update) 141562306a36Sopenharmony_ci{ 141662306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 141762306a36Sopenharmony_ci uint32_t start = 0; 141862306a36Sopenharmony_ci int valid = 0; 141962306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 142262306a36Sopenharmony_ci return -EINVAL; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci start = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; 142562306a36Sopenharmony_ci if (start > ha->optrom_size) { 142662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7055, 142762306a36Sopenharmony_ci "start %d > optrom_size %d.\n", start, ha->optrom_size); 142862306a36Sopenharmony_ci return -EINVAL; 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci if (ha->optrom_state != QLA_SWAITING) { 143262306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x7056, 143362306a36Sopenharmony_ci "optrom_state %d.\n", ha->optrom_state); 143462306a36Sopenharmony_ci return -EBUSY; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci ha->optrom_region_start = start; 143862306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7057, "is_update=%d.\n", is_update); 143962306a36Sopenharmony_ci if (is_update) { 144062306a36Sopenharmony_ci if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0) 144162306a36Sopenharmony_ci valid = 1; 144262306a36Sopenharmony_ci else if (start == (ha->flt_region_boot * 4) || 144362306a36Sopenharmony_ci start == (ha->flt_region_fw * 4)) 144462306a36Sopenharmony_ci valid = 1; 144562306a36Sopenharmony_ci else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || 144662306a36Sopenharmony_ci IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || 144762306a36Sopenharmony_ci IS_QLA28XX(ha)) 144862306a36Sopenharmony_ci valid = 1; 144962306a36Sopenharmony_ci if (!valid) { 145062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7058, 145162306a36Sopenharmony_ci "Invalid start region 0x%x/0x%x.\n", start, 145262306a36Sopenharmony_ci bsg_job->request_payload.payload_len); 145362306a36Sopenharmony_ci return -EINVAL; 145462306a36Sopenharmony_ci } 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci ha->optrom_region_size = start + 145762306a36Sopenharmony_ci bsg_job->request_payload.payload_len > ha->optrom_size ? 145862306a36Sopenharmony_ci ha->optrom_size - start : 145962306a36Sopenharmony_ci bsg_job->request_payload.payload_len; 146062306a36Sopenharmony_ci ha->optrom_state = QLA_SWRITING; 146162306a36Sopenharmony_ci } else { 146262306a36Sopenharmony_ci ha->optrom_region_size = start + 146362306a36Sopenharmony_ci bsg_job->reply_payload.payload_len > ha->optrom_size ? 146462306a36Sopenharmony_ci ha->optrom_size - start : 146562306a36Sopenharmony_ci bsg_job->reply_payload.payload_len; 146662306a36Sopenharmony_ci ha->optrom_state = QLA_SREADING; 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci ha->optrom_buffer = vzalloc(ha->optrom_region_size); 147062306a36Sopenharmony_ci if (!ha->optrom_buffer) { 147162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7059, 147262306a36Sopenharmony_ci "Read: Unable to allocate memory for optrom retrieval " 147362306a36Sopenharmony_ci "(%x)\n", ha->optrom_region_size); 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci ha->optrom_state = QLA_SWAITING; 147662306a36Sopenharmony_ci return -ENOMEM; 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci return 0; 148062306a36Sopenharmony_ci} 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_cistatic int 148362306a36Sopenharmony_ciqla2x00_read_optrom(struct bsg_job *bsg_job) 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 148662306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 148762306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 148862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 148962306a36Sopenharmony_ci int rval = 0; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci if (ha->flags.nic_core_reset_hdlr_active) 149262306a36Sopenharmony_ci return -EBUSY; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci mutex_lock(&ha->optrom_mutex); 149562306a36Sopenharmony_ci rval = qla2x00_optrom_setup(bsg_job, vha, 0); 149662306a36Sopenharmony_ci if (rval) { 149762306a36Sopenharmony_ci mutex_unlock(&ha->optrom_mutex); 149862306a36Sopenharmony_ci return rval; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci ha->isp_ops->read_optrom(vha, ha->optrom_buffer, 150262306a36Sopenharmony_ci ha->optrom_region_start, ha->optrom_region_size); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 150562306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, ha->optrom_buffer, 150662306a36Sopenharmony_ci ha->optrom_region_size); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = ha->optrom_region_size; 150962306a36Sopenharmony_ci bsg_reply->result = DID_OK; 151062306a36Sopenharmony_ci vfree(ha->optrom_buffer); 151162306a36Sopenharmony_ci ha->optrom_buffer = NULL; 151262306a36Sopenharmony_ci ha->optrom_state = QLA_SWAITING; 151362306a36Sopenharmony_ci mutex_unlock(&ha->optrom_mutex); 151462306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 151562306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 151662306a36Sopenharmony_ci return rval; 151762306a36Sopenharmony_ci} 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_cistatic int 152062306a36Sopenharmony_ciqla2x00_update_optrom(struct bsg_job *bsg_job) 152162306a36Sopenharmony_ci{ 152262306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 152362306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 152462306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 152562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 152662306a36Sopenharmony_ci int rval = 0; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci mutex_lock(&ha->optrom_mutex); 152962306a36Sopenharmony_ci rval = qla2x00_optrom_setup(bsg_job, vha, 1); 153062306a36Sopenharmony_ci if (rval) { 153162306a36Sopenharmony_ci mutex_unlock(&ha->optrom_mutex); 153262306a36Sopenharmony_ci return rval; 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci /* Set the isp82xx_no_md_cap not to capture minidump */ 153662306a36Sopenharmony_ci ha->flags.isp82xx_no_md_cap = 1; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 153962306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, ha->optrom_buffer, 154062306a36Sopenharmony_ci ha->optrom_region_size); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci rval = ha->isp_ops->write_optrom(vha, ha->optrom_buffer, 154362306a36Sopenharmony_ci ha->optrom_region_start, ha->optrom_region_size); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (rval) { 154662306a36Sopenharmony_ci bsg_reply->result = -EINVAL; 154762306a36Sopenharmony_ci rval = -EINVAL; 154862306a36Sopenharmony_ci } else { 154962306a36Sopenharmony_ci bsg_reply->result = DID_OK; 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci vfree(ha->optrom_buffer); 155262306a36Sopenharmony_ci ha->optrom_buffer = NULL; 155362306a36Sopenharmony_ci ha->optrom_state = QLA_SWAITING; 155462306a36Sopenharmony_ci mutex_unlock(&ha->optrom_mutex); 155562306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 155662306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 155762306a36Sopenharmony_ci return rval; 155862306a36Sopenharmony_ci} 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_cistatic int 156162306a36Sopenharmony_ciqla2x00_update_fru_versions(struct bsg_job *bsg_job) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 156462306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 156562306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 156662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 156762306a36Sopenharmony_ci int rval = 0; 156862306a36Sopenharmony_ci uint8_t bsg[DMA_POOL_SIZE]; 156962306a36Sopenharmony_ci struct qla_image_version_list *list = (void *)bsg; 157062306a36Sopenharmony_ci struct qla_image_version *image; 157162306a36Sopenharmony_ci uint32_t count; 157262306a36Sopenharmony_ci dma_addr_t sfp_dma; 157362306a36Sopenharmony_ci void *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci if (!sfp) { 157662306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 157762306a36Sopenharmony_ci EXT_STATUS_NO_MEMORY; 157862306a36Sopenharmony_ci goto done; 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 158262306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, list, sizeof(bsg)); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci image = list->version; 158562306a36Sopenharmony_ci count = list->count; 158662306a36Sopenharmony_ci while (count--) { 158762306a36Sopenharmony_ci memcpy(sfp, &image->field_info, sizeof(image->field_info)); 158862306a36Sopenharmony_ci rval = qla2x00_write_sfp(vha, sfp_dma, sfp, 158962306a36Sopenharmony_ci image->field_address.device, image->field_address.offset, 159062306a36Sopenharmony_ci sizeof(image->field_info), image->field_address.option); 159162306a36Sopenharmony_ci if (rval) { 159262306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 159362306a36Sopenharmony_ci EXT_STATUS_MAILBOX; 159462306a36Sopenharmony_ci goto dealloc; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci image++; 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cidealloc: 160262306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, sfp, sfp_dma); 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_cidone: 160562306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 160662306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 160762306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 160862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci return 0; 161162306a36Sopenharmony_ci} 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_cistatic int 161462306a36Sopenharmony_ciqla2x00_read_fru_status(struct bsg_job *bsg_job) 161562306a36Sopenharmony_ci{ 161662306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 161762306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 161862306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 161962306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 162062306a36Sopenharmony_ci int rval = 0; 162162306a36Sopenharmony_ci uint8_t bsg[DMA_POOL_SIZE]; 162262306a36Sopenharmony_ci struct qla_status_reg *sr = (void *)bsg; 162362306a36Sopenharmony_ci dma_addr_t sfp_dma; 162462306a36Sopenharmony_ci uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci if (!sfp) { 162762306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 162862306a36Sopenharmony_ci EXT_STATUS_NO_MEMORY; 162962306a36Sopenharmony_ci goto done; 163062306a36Sopenharmony_ci } 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 163362306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, sr, sizeof(*sr)); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 163662306a36Sopenharmony_ci sr->field_address.device, sr->field_address.offset, 163762306a36Sopenharmony_ci sizeof(sr->status_reg), sr->field_address.option); 163862306a36Sopenharmony_ci sr->status_reg = *sfp; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci if (rval) { 164162306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 164262306a36Sopenharmony_ci EXT_STATUS_MAILBOX; 164362306a36Sopenharmony_ci goto dealloc; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 164762306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, sr, sizeof(*sr)); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_cidealloc: 165262306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, sfp, sfp_dma); 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_cidone: 165562306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 165662306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sizeof(*sr); 165762306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 165862306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 165962306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci return 0; 166262306a36Sopenharmony_ci} 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_cistatic int 166562306a36Sopenharmony_ciqla2x00_write_fru_status(struct bsg_job *bsg_job) 166662306a36Sopenharmony_ci{ 166762306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 166862306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 166962306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 167062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 167162306a36Sopenharmony_ci int rval = 0; 167262306a36Sopenharmony_ci uint8_t bsg[DMA_POOL_SIZE]; 167362306a36Sopenharmony_ci struct qla_status_reg *sr = (void *)bsg; 167462306a36Sopenharmony_ci dma_addr_t sfp_dma; 167562306a36Sopenharmony_ci uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci if (!sfp) { 167862306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 167962306a36Sopenharmony_ci EXT_STATUS_NO_MEMORY; 168062306a36Sopenharmony_ci goto done; 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 168462306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, sr, sizeof(*sr)); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci *sfp = sr->status_reg; 168762306a36Sopenharmony_ci rval = qla2x00_write_sfp(vha, sfp_dma, sfp, 168862306a36Sopenharmony_ci sr->field_address.device, sr->field_address.offset, 168962306a36Sopenharmony_ci sizeof(sr->status_reg), sr->field_address.option); 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci if (rval) { 169262306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 169362306a36Sopenharmony_ci EXT_STATUS_MAILBOX; 169462306a36Sopenharmony_ci goto dealloc; 169562306a36Sopenharmony_ci } 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_cidealloc: 170062306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, sfp, sfp_dma); 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_cidone: 170362306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 170462306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 170562306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 170662306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci return 0; 170962306a36Sopenharmony_ci} 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_cistatic int 171262306a36Sopenharmony_ciqla2x00_write_i2c(struct bsg_job *bsg_job) 171362306a36Sopenharmony_ci{ 171462306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 171562306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 171662306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 171762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 171862306a36Sopenharmony_ci int rval = 0; 171962306a36Sopenharmony_ci uint8_t bsg[DMA_POOL_SIZE]; 172062306a36Sopenharmony_ci struct qla_i2c_access *i2c = (void *)bsg; 172162306a36Sopenharmony_ci dma_addr_t sfp_dma; 172262306a36Sopenharmony_ci uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci if (!sfp) { 172562306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 172662306a36Sopenharmony_ci EXT_STATUS_NO_MEMORY; 172762306a36Sopenharmony_ci goto done; 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 173162306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c)); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci memcpy(sfp, i2c->buffer, i2c->length); 173462306a36Sopenharmony_ci rval = qla2x00_write_sfp(vha, sfp_dma, sfp, 173562306a36Sopenharmony_ci i2c->device, i2c->offset, i2c->length, i2c->option); 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci if (rval) { 173862306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 173962306a36Sopenharmony_ci EXT_STATUS_MAILBOX; 174062306a36Sopenharmony_ci goto dealloc; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_cidealloc: 174662306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, sfp, sfp_dma); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_cidone: 174962306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 175062306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 175162306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 175262306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci return 0; 175562306a36Sopenharmony_ci} 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_cistatic int 175862306a36Sopenharmony_ciqla2x00_read_i2c(struct bsg_job *bsg_job) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 176162306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 176262306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 176362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 176462306a36Sopenharmony_ci int rval = 0; 176562306a36Sopenharmony_ci uint8_t bsg[DMA_POOL_SIZE]; 176662306a36Sopenharmony_ci struct qla_i2c_access *i2c = (void *)bsg; 176762306a36Sopenharmony_ci dma_addr_t sfp_dma; 176862306a36Sopenharmony_ci uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (!sfp) { 177162306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 177262306a36Sopenharmony_ci EXT_STATUS_NO_MEMORY; 177362306a36Sopenharmony_ci goto done; 177462306a36Sopenharmony_ci } 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 177762306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c)); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 178062306a36Sopenharmony_ci i2c->device, i2c->offset, i2c->length, i2c->option); 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci if (rval) { 178362306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 178462306a36Sopenharmony_ci EXT_STATUS_MAILBOX; 178562306a36Sopenharmony_ci goto dealloc; 178662306a36Sopenharmony_ci } 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci memcpy(i2c->buffer, sfp, i2c->length); 178962306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 179062306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, i2c, sizeof(*i2c)); 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_cidealloc: 179562306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, sfp, sfp_dma); 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_cidone: 179862306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 179962306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sizeof(*i2c); 180062306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 180162306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 180262306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci return 0; 180562306a36Sopenharmony_ci} 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_cistatic int 180862306a36Sopenharmony_ciqla24xx_process_bidir_cmd(struct bsg_job *bsg_job) 180962306a36Sopenharmony_ci{ 181062306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 181162306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 181262306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 181362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 181462306a36Sopenharmony_ci uint32_t rval = EXT_STATUS_OK; 181562306a36Sopenharmony_ci uint16_t req_sg_cnt = 0; 181662306a36Sopenharmony_ci uint16_t rsp_sg_cnt = 0; 181762306a36Sopenharmony_ci uint16_t nextlid = 0; 181862306a36Sopenharmony_ci uint32_t tot_dsds; 181962306a36Sopenharmony_ci srb_t *sp = NULL; 182062306a36Sopenharmony_ci uint32_t req_data_len; 182162306a36Sopenharmony_ci uint32_t rsp_data_len; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci /* Check the type of the adapter */ 182462306a36Sopenharmony_ci if (!IS_BIDI_CAPABLE(ha)) { 182562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70a0, 182662306a36Sopenharmony_ci "This adapter is not supported\n"); 182762306a36Sopenharmony_ci rval = EXT_STATUS_NOT_SUPPORTED; 182862306a36Sopenharmony_ci goto done; 182962306a36Sopenharmony_ci } 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || 183262306a36Sopenharmony_ci test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || 183362306a36Sopenharmony_ci test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { 183462306a36Sopenharmony_ci rval = EXT_STATUS_BUSY; 183562306a36Sopenharmony_ci goto done; 183662306a36Sopenharmony_ci } 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci /* Check if host is online */ 183962306a36Sopenharmony_ci if (!vha->flags.online) { 184062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70a1, 184162306a36Sopenharmony_ci "Host is not online\n"); 184262306a36Sopenharmony_ci rval = EXT_STATUS_DEVICE_OFFLINE; 184362306a36Sopenharmony_ci goto done; 184462306a36Sopenharmony_ci } 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci /* Check if cable is plugged in or not */ 184762306a36Sopenharmony_ci if (vha->device_flags & DFLG_NO_CABLE) { 184862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70a2, 184962306a36Sopenharmony_ci "Cable is unplugged...\n"); 185062306a36Sopenharmony_ci rval = EXT_STATUS_INVALID_CFG; 185162306a36Sopenharmony_ci goto done; 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci /* Check if the switch is connected or not */ 185562306a36Sopenharmony_ci if (ha->current_topology != ISP_CFG_F) { 185662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70a3, 185762306a36Sopenharmony_ci "Host is not connected to the switch\n"); 185862306a36Sopenharmony_ci rval = EXT_STATUS_INVALID_CFG; 185962306a36Sopenharmony_ci goto done; 186062306a36Sopenharmony_ci } 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci /* Check if operating mode is P2P */ 186362306a36Sopenharmony_ci if (ha->operating_mode != P2P) { 186462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70a4, 186562306a36Sopenharmony_ci "Host operating mode is not P2p\n"); 186662306a36Sopenharmony_ci rval = EXT_STATUS_INVALID_CFG; 186762306a36Sopenharmony_ci goto done; 186862306a36Sopenharmony_ci } 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci mutex_lock(&ha->selflogin_lock); 187162306a36Sopenharmony_ci if (vha->self_login_loop_id == 0) { 187262306a36Sopenharmony_ci /* Initialize all required fields of fcport */ 187362306a36Sopenharmony_ci vha->bidir_fcport.vha = vha; 187462306a36Sopenharmony_ci vha->bidir_fcport.d_id.b.al_pa = vha->d_id.b.al_pa; 187562306a36Sopenharmony_ci vha->bidir_fcport.d_id.b.area = vha->d_id.b.area; 187662306a36Sopenharmony_ci vha->bidir_fcport.d_id.b.domain = vha->d_id.b.domain; 187762306a36Sopenharmony_ci vha->bidir_fcport.loop_id = vha->loop_id; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci if (qla2x00_fabric_login(vha, &(vha->bidir_fcport), &nextlid)) { 188062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70a7, 188162306a36Sopenharmony_ci "Failed to login port %06X for bidirectional IOCB\n", 188262306a36Sopenharmony_ci vha->bidir_fcport.d_id.b24); 188362306a36Sopenharmony_ci mutex_unlock(&ha->selflogin_lock); 188462306a36Sopenharmony_ci rval = EXT_STATUS_MAILBOX; 188562306a36Sopenharmony_ci goto done; 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci vha->self_login_loop_id = nextlid - 1; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci } 189062306a36Sopenharmony_ci /* Assign the self login loop id to fcport */ 189162306a36Sopenharmony_ci mutex_unlock(&ha->selflogin_lock); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci vha->bidir_fcport.loop_id = vha->self_login_loop_id; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci req_sg_cnt = dma_map_sg(&ha->pdev->dev, 189662306a36Sopenharmony_ci bsg_job->request_payload.sg_list, 189762306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, 189862306a36Sopenharmony_ci DMA_TO_DEVICE); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci if (!req_sg_cnt) { 190162306a36Sopenharmony_ci rval = EXT_STATUS_NO_MEMORY; 190262306a36Sopenharmony_ci goto done; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, 190662306a36Sopenharmony_ci bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt, 190762306a36Sopenharmony_ci DMA_FROM_DEVICE); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci if (!rsp_sg_cnt) { 191062306a36Sopenharmony_ci rval = EXT_STATUS_NO_MEMORY; 191162306a36Sopenharmony_ci goto done_unmap_req_sg; 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || 191562306a36Sopenharmony_ci (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { 191662306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70a9, 191762306a36Sopenharmony_ci "Dma mapping resulted in different sg counts " 191862306a36Sopenharmony_ci "[request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt: " 191962306a36Sopenharmony_ci "%x dma_reply_sg_cnt: %x]\n", 192062306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, req_sg_cnt, 192162306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, rsp_sg_cnt); 192262306a36Sopenharmony_ci rval = EXT_STATUS_NO_MEMORY; 192362306a36Sopenharmony_ci goto done_unmap_sg; 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci req_data_len = bsg_job->request_payload.payload_len; 192762306a36Sopenharmony_ci rsp_data_len = bsg_job->reply_payload.payload_len; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci if (req_data_len != rsp_data_len) { 193062306a36Sopenharmony_ci rval = EXT_STATUS_BUSY; 193162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70aa, 193262306a36Sopenharmony_ci "req_data_len != rsp_data_len\n"); 193362306a36Sopenharmony_ci goto done_unmap_sg; 193462306a36Sopenharmony_ci } 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci /* Alloc SRB structure */ 193762306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, &(vha->bidir_fcport), GFP_KERNEL); 193862306a36Sopenharmony_ci if (!sp) { 193962306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70ac, 194062306a36Sopenharmony_ci "Alloc SRB structure failed\n"); 194162306a36Sopenharmony_ci rval = EXT_STATUS_NO_MEMORY; 194262306a36Sopenharmony_ci goto done_unmap_sg; 194362306a36Sopenharmony_ci } 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci /*Populate srb->ctx with bidir ctx*/ 194662306a36Sopenharmony_ci sp->u.bsg_job = bsg_job; 194762306a36Sopenharmony_ci sp->free = qla2x00_bsg_sp_free; 194862306a36Sopenharmony_ci sp->type = SRB_BIDI_CMD; 194962306a36Sopenharmony_ci sp->done = qla2x00_bsg_job_done; 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci /* Add the read and write sg count */ 195262306a36Sopenharmony_ci tot_dsds = rsp_sg_cnt + req_sg_cnt; 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci rval = qla2x00_start_bidir(sp, vha, tot_dsds); 195562306a36Sopenharmony_ci if (rval != EXT_STATUS_OK) 195662306a36Sopenharmony_ci goto done_free_srb; 195762306a36Sopenharmony_ci /* the bsg request will be completed in the interrupt handler */ 195862306a36Sopenharmony_ci return rval; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_cidone_free_srb: 196162306a36Sopenharmony_ci mempool_free(sp, ha->srb_mempool); 196262306a36Sopenharmony_cidone_unmap_sg: 196362306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, 196462306a36Sopenharmony_ci bsg_job->reply_payload.sg_list, 196562306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 196662306a36Sopenharmony_cidone_unmap_req_sg: 196762306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, 196862306a36Sopenharmony_ci bsg_job->request_payload.sg_list, 196962306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 197062306a36Sopenharmony_cidone: 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci /* Return an error vendor specific response 197362306a36Sopenharmony_ci * and complete the bsg request 197462306a36Sopenharmony_ci */ 197562306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval; 197662306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 197762306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 197862306a36Sopenharmony_ci bsg_reply->result = (DID_OK) << 16; 197962306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 198062306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 198162306a36Sopenharmony_ci /* Always return success, vendor rsp carries correct status */ 198262306a36Sopenharmony_ci return 0; 198362306a36Sopenharmony_ci} 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_cistatic int 198662306a36Sopenharmony_ciqlafx00_mgmt_cmd(struct bsg_job *bsg_job) 198762306a36Sopenharmony_ci{ 198862306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 198962306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 199062306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 199162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 199262306a36Sopenharmony_ci int rval = (DID_ERROR << 16); 199362306a36Sopenharmony_ci struct qla_mt_iocb_rqst_fx00 *piocb_rqst; 199462306a36Sopenharmony_ci srb_t *sp; 199562306a36Sopenharmony_ci int req_sg_cnt = 0, rsp_sg_cnt = 0; 199662306a36Sopenharmony_ci struct fc_port *fcport; 199762306a36Sopenharmony_ci char *type = "FC_BSG_HST_FX_MGMT"; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci /* Copy the IOCB specific information */ 200062306a36Sopenharmony_ci piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *) 200162306a36Sopenharmony_ci &bsg_request->rqst_data.h_vendor.vendor_cmd[1]; 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci /* Dump the vendor information */ 200462306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_user + ql_dbg_verbose , vha, 0x70cf, 200562306a36Sopenharmony_ci piocb_rqst, sizeof(*piocb_rqst)); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci if (!vha->flags.online) { 200862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70d0, 200962306a36Sopenharmony_ci "Host is not online.\n"); 201062306a36Sopenharmony_ci rval = -EIO; 201162306a36Sopenharmony_ci goto done; 201262306a36Sopenharmony_ci } 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) { 201562306a36Sopenharmony_ci req_sg_cnt = dma_map_sg(&ha->pdev->dev, 201662306a36Sopenharmony_ci bsg_job->request_payload.sg_list, 201762306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 201862306a36Sopenharmony_ci if (!req_sg_cnt) { 201962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70c7, 202062306a36Sopenharmony_ci "dma_map_sg return %d for request\n", req_sg_cnt); 202162306a36Sopenharmony_ci rval = -ENOMEM; 202262306a36Sopenharmony_ci goto done; 202362306a36Sopenharmony_ci } 202462306a36Sopenharmony_ci } 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) { 202762306a36Sopenharmony_ci rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, 202862306a36Sopenharmony_ci bsg_job->reply_payload.sg_list, 202962306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 203062306a36Sopenharmony_ci if (!rsp_sg_cnt) { 203162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70c8, 203262306a36Sopenharmony_ci "dma_map_sg return %d for reply\n", rsp_sg_cnt); 203362306a36Sopenharmony_ci rval = -ENOMEM; 203462306a36Sopenharmony_ci goto done_unmap_req_sg; 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70c9, 203962306a36Sopenharmony_ci "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x " 204062306a36Sopenharmony_ci "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt, 204162306a36Sopenharmony_ci req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt); 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci /* Allocate a dummy fcport structure, since functions preparing the 204462306a36Sopenharmony_ci * IOCB and mailbox command retrieves port specific information 204562306a36Sopenharmony_ci * from fcport structure. For Host based ELS commands there will be 204662306a36Sopenharmony_ci * no fcport structure allocated 204762306a36Sopenharmony_ci */ 204862306a36Sopenharmony_ci fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); 204962306a36Sopenharmony_ci if (!fcport) { 205062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70ca, 205162306a36Sopenharmony_ci "Failed to allocate fcport.\n"); 205262306a36Sopenharmony_ci rval = -ENOMEM; 205362306a36Sopenharmony_ci goto done_unmap_rsp_sg; 205462306a36Sopenharmony_ci } 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci /* Alloc SRB structure */ 205762306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 205862306a36Sopenharmony_ci if (!sp) { 205962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70cb, 206062306a36Sopenharmony_ci "qla2x00_get_sp failed.\n"); 206162306a36Sopenharmony_ci rval = -ENOMEM; 206262306a36Sopenharmony_ci goto done_free_fcport; 206362306a36Sopenharmony_ci } 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci /* Initialize all required fields of fcport */ 206662306a36Sopenharmony_ci fcport->vha = vha; 206762306a36Sopenharmony_ci fcport->loop_id = le32_to_cpu(piocb_rqst->dataword); 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci sp->type = SRB_FXIOCB_BCMD; 207062306a36Sopenharmony_ci sp->name = "bsg_fx_mgmt"; 207162306a36Sopenharmony_ci sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt); 207262306a36Sopenharmony_ci sp->u.bsg_job = bsg_job; 207362306a36Sopenharmony_ci sp->free = qla2x00_bsg_sp_free; 207462306a36Sopenharmony_ci sp->done = qla2x00_bsg_job_done; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70cc, 207762306a36Sopenharmony_ci "bsg rqst type: %s fx_mgmt_type: %x id=%x\n", 207862306a36Sopenharmony_ci type, piocb_rqst->func_type, fcport->loop_id); 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 208162306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 208262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70cd, 208362306a36Sopenharmony_ci "qla2x00_start_sp failed=%d.\n", rval); 208462306a36Sopenharmony_ci mempool_free(sp, ha->srb_mempool); 208562306a36Sopenharmony_ci rval = -EIO; 208662306a36Sopenharmony_ci goto done_free_fcport; 208762306a36Sopenharmony_ci } 208862306a36Sopenharmony_ci return rval; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_cidone_free_fcport: 209162306a36Sopenharmony_ci qla2x00_free_fcport(fcport); 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_cidone_unmap_rsp_sg: 209462306a36Sopenharmony_ci if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) 209562306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, 209662306a36Sopenharmony_ci bsg_job->reply_payload.sg_list, 209762306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 209862306a36Sopenharmony_cidone_unmap_req_sg: 209962306a36Sopenharmony_ci if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) 210062306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, 210162306a36Sopenharmony_ci bsg_job->request_payload.sg_list, 210262306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_cidone: 210562306a36Sopenharmony_ci return rval; 210662306a36Sopenharmony_ci} 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_cistatic int 210962306a36Sopenharmony_ciqla26xx_serdes_op(struct bsg_job *bsg_job) 211062306a36Sopenharmony_ci{ 211162306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 211262306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 211362306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 211462306a36Sopenharmony_ci int rval = 0; 211562306a36Sopenharmony_ci struct qla_serdes_reg sr; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci memset(&sr, 0, sizeof(sr)); 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 212062306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, &sr, sizeof(sr)); 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci switch (sr.cmd) { 212362306a36Sopenharmony_ci case INT_SC_SERDES_WRITE_REG: 212462306a36Sopenharmony_ci rval = qla2x00_write_serdes_word(vha, sr.addr, sr.val); 212562306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 212662306a36Sopenharmony_ci break; 212762306a36Sopenharmony_ci case INT_SC_SERDES_READ_REG: 212862306a36Sopenharmony_ci rval = qla2x00_read_serdes_word(vha, sr.addr, &sr.val); 212962306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 213062306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, &sr, sizeof(sr)); 213162306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sizeof(sr); 213262306a36Sopenharmony_ci break; 213362306a36Sopenharmony_ci default: 213462306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x708c, 213562306a36Sopenharmony_ci "Unknown serdes cmd %x.\n", sr.cmd); 213662306a36Sopenharmony_ci rval = -EINVAL; 213762306a36Sopenharmony_ci break; 213862306a36Sopenharmony_ci } 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 214162306a36Sopenharmony_ci rval ? EXT_STATUS_MAILBOX : 0; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 214462306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 214562306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 214662306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 214762306a36Sopenharmony_ci return 0; 214862306a36Sopenharmony_ci} 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_cistatic int 215162306a36Sopenharmony_ciqla8044_serdes_op(struct bsg_job *bsg_job) 215262306a36Sopenharmony_ci{ 215362306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 215462306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 215562306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 215662306a36Sopenharmony_ci int rval = 0; 215762306a36Sopenharmony_ci struct qla_serdes_reg_ex sr; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci memset(&sr, 0, sizeof(sr)); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 216262306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, &sr, sizeof(sr)); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci switch (sr.cmd) { 216562306a36Sopenharmony_ci case INT_SC_SERDES_WRITE_REG: 216662306a36Sopenharmony_ci rval = qla8044_write_serdes_word(vha, sr.addr, sr.val); 216762306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 216862306a36Sopenharmony_ci break; 216962306a36Sopenharmony_ci case INT_SC_SERDES_READ_REG: 217062306a36Sopenharmony_ci rval = qla8044_read_serdes_word(vha, sr.addr, &sr.val); 217162306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 217262306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, &sr, sizeof(sr)); 217362306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sizeof(sr); 217462306a36Sopenharmony_ci break; 217562306a36Sopenharmony_ci default: 217662306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x7020, 217762306a36Sopenharmony_ci "Unknown serdes cmd %x.\n", sr.cmd); 217862306a36Sopenharmony_ci rval = -EINVAL; 217962306a36Sopenharmony_ci break; 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 218362306a36Sopenharmony_ci rval ? EXT_STATUS_MAILBOX : 0; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 218662306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 218762306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 218862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 218962306a36Sopenharmony_ci return 0; 219062306a36Sopenharmony_ci} 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_cistatic int 219362306a36Sopenharmony_ciqla27xx_get_flash_upd_cap(struct bsg_job *bsg_job) 219462306a36Sopenharmony_ci{ 219562306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 219662306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 219762306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 219862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 219962306a36Sopenharmony_ci struct qla_flash_update_caps cap; 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha)) 220262306a36Sopenharmony_ci return -EPERM; 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci memset(&cap, 0, sizeof(cap)); 220562306a36Sopenharmony_ci cap.capabilities = (uint64_t)ha->fw_attributes_ext[1] << 48 | 220662306a36Sopenharmony_ci (uint64_t)ha->fw_attributes_ext[0] << 32 | 220762306a36Sopenharmony_ci (uint64_t)ha->fw_attributes_h << 16 | 220862306a36Sopenharmony_ci (uint64_t)ha->fw_attributes; 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 221162306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, &cap, sizeof(cap)); 221262306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sizeof(cap); 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 221562306a36Sopenharmony_ci EXT_STATUS_OK; 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 221862306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 221962306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 222062306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 222162306a36Sopenharmony_ci return 0; 222262306a36Sopenharmony_ci} 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_cistatic int 222562306a36Sopenharmony_ciqla27xx_set_flash_upd_cap(struct bsg_job *bsg_job) 222662306a36Sopenharmony_ci{ 222762306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 222862306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 222962306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 223062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 223162306a36Sopenharmony_ci uint64_t online_fw_attr = 0; 223262306a36Sopenharmony_ci struct qla_flash_update_caps cap; 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) 223562306a36Sopenharmony_ci return -EPERM; 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci memset(&cap, 0, sizeof(cap)); 223862306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 223962306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, &cap, sizeof(cap)); 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci online_fw_attr = (uint64_t)ha->fw_attributes_ext[1] << 48 | 224262306a36Sopenharmony_ci (uint64_t)ha->fw_attributes_ext[0] << 32 | 224362306a36Sopenharmony_ci (uint64_t)ha->fw_attributes_h << 16 | 224462306a36Sopenharmony_ci (uint64_t)ha->fw_attributes; 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci if (online_fw_attr != cap.capabilities) { 224762306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 224862306a36Sopenharmony_ci EXT_STATUS_INVALID_PARAM; 224962306a36Sopenharmony_ci return -EINVAL; 225062306a36Sopenharmony_ci } 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci if (cap.outage_duration < MAX_LOOP_TIMEOUT) { 225362306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 225462306a36Sopenharmony_ci EXT_STATUS_INVALID_PARAM; 225562306a36Sopenharmony_ci return -EINVAL; 225662306a36Sopenharmony_ci } 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 226162306a36Sopenharmony_ci EXT_STATUS_OK; 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 226462306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 226562306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 226662306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 226762306a36Sopenharmony_ci return 0; 226862306a36Sopenharmony_ci} 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_cistatic int 227162306a36Sopenharmony_ciqla27xx_get_bbcr_data(struct bsg_job *bsg_job) 227262306a36Sopenharmony_ci{ 227362306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 227462306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 227562306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 227662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 227762306a36Sopenharmony_ci struct qla_bbcr_data bbcr; 227862306a36Sopenharmony_ci uint16_t loop_id, topo, sw_cap; 227962306a36Sopenharmony_ci uint8_t domain, area, al_pa, state; 228062306a36Sopenharmony_ci int rval; 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) 228362306a36Sopenharmony_ci return -EPERM; 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci memset(&bbcr, 0, sizeof(bbcr)); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci if (vha->flags.bbcr_enable) 228862306a36Sopenharmony_ci bbcr.status = QLA_BBCR_STATUS_ENABLED; 228962306a36Sopenharmony_ci else 229062306a36Sopenharmony_ci bbcr.status = QLA_BBCR_STATUS_DISABLED; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci if (bbcr.status == QLA_BBCR_STATUS_ENABLED) { 229362306a36Sopenharmony_ci rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa, 229462306a36Sopenharmony_ci &area, &domain, &topo, &sw_cap); 229562306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 229662306a36Sopenharmony_ci bbcr.status = QLA_BBCR_STATUS_UNKNOWN; 229762306a36Sopenharmony_ci bbcr.state = QLA_BBCR_STATE_OFFLINE; 229862306a36Sopenharmony_ci bbcr.mbx1 = loop_id; 229962306a36Sopenharmony_ci goto done; 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci state = (vha->bbcr >> 12) & 0x1; 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci if (state) { 230562306a36Sopenharmony_ci bbcr.state = QLA_BBCR_STATE_OFFLINE; 230662306a36Sopenharmony_ci bbcr.offline_reason_code = QLA_BBCR_REASON_LOGIN_REJECT; 230762306a36Sopenharmony_ci } else { 230862306a36Sopenharmony_ci bbcr.state = QLA_BBCR_STATE_ONLINE; 230962306a36Sopenharmony_ci bbcr.negotiated_bbscn = (vha->bbcr >> 8) & 0xf; 231062306a36Sopenharmony_ci } 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci bbcr.configured_bbscn = vha->bbcr & 0xf; 231362306a36Sopenharmony_ci } 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_cidone: 231662306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 231762306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, &bbcr, sizeof(bbcr)); 231862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sizeof(bbcr); 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 232362306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 232462306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 232562306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 232662306a36Sopenharmony_ci return 0; 232762306a36Sopenharmony_ci} 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_cistatic int 233062306a36Sopenharmony_ciqla2x00_get_priv_stats(struct bsg_job *bsg_job) 233162306a36Sopenharmony_ci{ 233262306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 233362306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 233462306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 233562306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 233662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 233762306a36Sopenharmony_ci struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); 233862306a36Sopenharmony_ci struct link_statistics *stats = NULL; 233962306a36Sopenharmony_ci dma_addr_t stats_dma; 234062306a36Sopenharmony_ci int rval; 234162306a36Sopenharmony_ci uint32_t *cmd = bsg_request->rqst_data.h_vendor.vendor_cmd; 234262306a36Sopenharmony_ci uint options = cmd[0] == QL_VND_GET_PRIV_STATS_EX ? cmd[1] : 0; 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci if (test_bit(UNLOADING, &vha->dpc_flags)) 234562306a36Sopenharmony_ci return -ENODEV; 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 234862306a36Sopenharmony_ci return -ENODEV; 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci if (qla2x00_reset_active(vha)) 235162306a36Sopenharmony_ci return -EBUSY; 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci if (!IS_FWI2_CAPABLE(ha)) 235462306a36Sopenharmony_ci return -EPERM; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci stats = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stats), &stats_dma, 235762306a36Sopenharmony_ci GFP_KERNEL); 235862306a36Sopenharmony_ci if (!stats) { 235962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70e2, 236062306a36Sopenharmony_ci "Failed to allocate memory for stats.\n"); 236162306a36Sopenharmony_ci return -ENOMEM; 236262306a36Sopenharmony_ci } 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, options); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci if (rval == QLA_SUCCESS) { 236762306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e5, 236862306a36Sopenharmony_ci stats, sizeof(*stats)); 236962306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 237062306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, stats, sizeof(*stats)); 237162306a36Sopenharmony_ci } 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sizeof(*stats); 237462306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 237562306a36Sopenharmony_ci rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci bsg_job->reply_len = sizeof(*bsg_reply); 237862306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 237962306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 238062306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*stats), 238362306a36Sopenharmony_ci stats, stats_dma); 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci return 0; 238662306a36Sopenharmony_ci} 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_cistatic int 238962306a36Sopenharmony_ciqla2x00_do_dport_diagnostics(struct bsg_job *bsg_job) 239062306a36Sopenharmony_ci{ 239162306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 239262306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 239362306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 239462306a36Sopenharmony_ci int rval; 239562306a36Sopenharmony_ci struct qla_dport_diag *dd; 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) && 239862306a36Sopenharmony_ci !IS_QLA28XX(vha->hw)) 239962306a36Sopenharmony_ci return -EPERM; 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci dd = kmalloc(sizeof(*dd), GFP_KERNEL); 240262306a36Sopenharmony_ci if (!dd) { 240362306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70db, 240462306a36Sopenharmony_ci "Failed to allocate memory for dport.\n"); 240562306a36Sopenharmony_ci return -ENOMEM; 240662306a36Sopenharmony_ci } 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 240962306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, dd, sizeof(*dd)); 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci rval = qla26xx_dport_diagnostics( 241262306a36Sopenharmony_ci vha, dd->buf, sizeof(dd->buf), dd->options); 241362306a36Sopenharmony_ci if (rval == QLA_SUCCESS) { 241462306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 241562306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, dd, sizeof(*dd)); 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sizeof(*dd); 241962306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 242062306a36Sopenharmony_ci rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK; 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci bsg_job->reply_len = sizeof(*bsg_reply); 242362306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 242462306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 242562306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci kfree(dd); 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci return 0; 243062306a36Sopenharmony_ci} 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_cistatic int 243362306a36Sopenharmony_ciqla2x00_do_dport_diagnostics_v2(struct bsg_job *bsg_job) 243462306a36Sopenharmony_ci{ 243562306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 243662306a36Sopenharmony_ci struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); 243762306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 243862306a36Sopenharmony_ci int rval; 243962306a36Sopenharmony_ci struct qla_dport_diag_v2 *dd; 244062306a36Sopenharmony_ci mbx_cmd_t mc; 244162306a36Sopenharmony_ci mbx_cmd_t *mcp = &mc; 244262306a36Sopenharmony_ci uint16_t options; 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci if (!IS_DPORT_CAPABLE(vha->hw)) 244562306a36Sopenharmony_ci return -EPERM; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci dd = kzalloc(sizeof(*dd), GFP_KERNEL); 244862306a36Sopenharmony_ci if (!dd) 244962306a36Sopenharmony_ci return -ENOMEM; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 245262306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, dd, sizeof(*dd)); 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci options = dd->options; 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci /* Check dport Test in progress */ 245762306a36Sopenharmony_ci if (options == QLA_GET_DPORT_RESULT_V2 && 245862306a36Sopenharmony_ci vha->dport_status & DPORT_DIAG_IN_PROGRESS) { 245962306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 246062306a36Sopenharmony_ci EXT_STATUS_DPORT_DIAG_IN_PROCESS; 246162306a36Sopenharmony_ci goto dportcomplete; 246262306a36Sopenharmony_ci } 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci /* Check chip reset in progress and start/restart requests arrive */ 246562306a36Sopenharmony_ci if (vha->dport_status & DPORT_DIAG_CHIP_RESET_IN_PROGRESS && 246662306a36Sopenharmony_ci (options == QLA_START_DPORT_TEST_V2 || 246762306a36Sopenharmony_ci options == QLA_RESTART_DPORT_TEST_V2)) { 246862306a36Sopenharmony_ci vha->dport_status &= ~DPORT_DIAG_CHIP_RESET_IN_PROGRESS; 246962306a36Sopenharmony_ci } 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci /* Check chip reset in progress and get result request arrive */ 247262306a36Sopenharmony_ci if (vha->dport_status & DPORT_DIAG_CHIP_RESET_IN_PROGRESS && 247362306a36Sopenharmony_ci options == QLA_GET_DPORT_RESULT_V2) { 247462306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 247562306a36Sopenharmony_ci EXT_STATUS_DPORT_DIAG_NOT_RUNNING; 247662306a36Sopenharmony_ci goto dportcomplete; 247762306a36Sopenharmony_ci } 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci rval = qla26xx_dport_diagnostics_v2(vha, dd, mcp); 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci if (rval == QLA_SUCCESS) { 248262306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 248362306a36Sopenharmony_ci EXT_STATUS_OK; 248462306a36Sopenharmony_ci if (options == QLA_START_DPORT_TEST_V2 || 248562306a36Sopenharmony_ci options == QLA_RESTART_DPORT_TEST_V2) { 248662306a36Sopenharmony_ci dd->mbx1 = mcp->mb[0]; 248762306a36Sopenharmony_ci dd->mbx2 = mcp->mb[1]; 248862306a36Sopenharmony_ci vha->dport_status |= DPORT_DIAG_IN_PROGRESS; 248962306a36Sopenharmony_ci } else if (options == QLA_GET_DPORT_RESULT_V2) { 249062306a36Sopenharmony_ci dd->mbx1 = le16_to_cpu(vha->dport_data[1]); 249162306a36Sopenharmony_ci dd->mbx2 = le16_to_cpu(vha->dport_data[2]); 249262306a36Sopenharmony_ci } 249362306a36Sopenharmony_ci } else { 249462306a36Sopenharmony_ci dd->mbx1 = mcp->mb[0]; 249562306a36Sopenharmony_ci dd->mbx2 = mcp->mb[1]; 249662306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 249762306a36Sopenharmony_ci EXT_STATUS_DPORT_DIAG_ERR; 249862306a36Sopenharmony_ci } 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_cidportcomplete: 250162306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 250262306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, dd, sizeof(*dd)); 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sizeof(*dd); 250562306a36Sopenharmony_ci bsg_job->reply_len = sizeof(*bsg_reply); 250662306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 250762306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 250862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci kfree(dd); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci return 0; 251362306a36Sopenharmony_ci} 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_cistatic int 251662306a36Sopenharmony_ciqla2x00_get_flash_image_status(struct bsg_job *bsg_job) 251762306a36Sopenharmony_ci{ 251862306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); 251962306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 252062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 252162306a36Sopenharmony_ci struct qla_active_regions regions = { }; 252262306a36Sopenharmony_ci struct active_regions active_regions = { }; 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci qla27xx_get_active_image(vha, &active_regions); 252562306a36Sopenharmony_ci regions.global_image = active_regions.global; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci if (IS_QLA27XX(ha)) 252862306a36Sopenharmony_ci regions.nvme_params = QLA27XX_PRIMARY_IMAGE; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci if (IS_QLA28XX(ha)) { 253162306a36Sopenharmony_ci qla28xx_get_aux_images(vha, &active_regions); 253262306a36Sopenharmony_ci regions.board_config = active_regions.aux.board_config; 253362306a36Sopenharmony_ci regions.vpd_nvram = active_regions.aux.vpd_nvram; 253462306a36Sopenharmony_ci regions.npiv_config_0_1 = active_regions.aux.npiv_config_0_1; 253562306a36Sopenharmony_ci regions.npiv_config_2_3 = active_regions.aux.npiv_config_2_3; 253662306a36Sopenharmony_ci regions.nvme_params = active_regions.aux.nvme_params; 253762306a36Sopenharmony_ci } 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70e1, 254062306a36Sopenharmony_ci "%s(%lu): FW=%u BCFG=%u VPDNVR=%u NPIV01=%u NPIV02=%u NVME_PARAMS=%u\n", 254162306a36Sopenharmony_ci __func__, vha->host_no, regions.global_image, 254262306a36Sopenharmony_ci regions.board_config, regions.vpd_nvram, 254362306a36Sopenharmony_ci regions.npiv_config_0_1, regions.npiv_config_2_3, regions.nvme_params); 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 254662306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, ®ions, sizeof(regions)); 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; 254962306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sizeof(regions); 255062306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 255162306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 255262306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 255362306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci return 0; 255662306a36Sopenharmony_ci} 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_cistatic int 255962306a36Sopenharmony_ciqla2x00_manage_host_stats(struct bsg_job *bsg_job) 256062306a36Sopenharmony_ci{ 256162306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); 256262306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 256362306a36Sopenharmony_ci struct ql_vnd_mng_host_stats_param *req_data; 256462306a36Sopenharmony_ci struct ql_vnd_mng_host_stats_resp rsp_data; 256562306a36Sopenharmony_ci u32 req_data_len; 256662306a36Sopenharmony_ci int ret = 0; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci if (!vha->flags.online) { 256962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "Host is not online.\n"); 257062306a36Sopenharmony_ci return -EIO; 257162306a36Sopenharmony_ci } 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci req_data_len = bsg_job->request_payload.payload_len; 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci if (req_data_len != sizeof(struct ql_vnd_mng_host_stats_param)) { 257662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n"); 257762306a36Sopenharmony_ci return -EIO; 257862306a36Sopenharmony_ci } 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci req_data = kzalloc(sizeof(*req_data), GFP_KERNEL); 258162306a36Sopenharmony_ci if (!req_data) { 258262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n"); 258362306a36Sopenharmony_ci return -ENOMEM; 258462306a36Sopenharmony_ci } 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci /* Copy the request buffer in req_data */ 258762306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 258862306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, req_data, 258962306a36Sopenharmony_ci req_data_len); 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci switch (req_data->action) { 259262306a36Sopenharmony_ci case QLA_STOP: 259362306a36Sopenharmony_ci ret = qla2xxx_stop_stats(vha->host, req_data->stat_type); 259462306a36Sopenharmony_ci break; 259562306a36Sopenharmony_ci case QLA_START: 259662306a36Sopenharmony_ci ret = qla2xxx_start_stats(vha->host, req_data->stat_type); 259762306a36Sopenharmony_ci break; 259862306a36Sopenharmony_ci case QLA_CLEAR: 259962306a36Sopenharmony_ci ret = qla2xxx_reset_stats(vha->host, req_data->stat_type); 260062306a36Sopenharmony_ci break; 260162306a36Sopenharmony_ci default: 260262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "Invalid action.\n"); 260362306a36Sopenharmony_ci ret = -EIO; 260462306a36Sopenharmony_ci break; 260562306a36Sopenharmony_ci } 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci kfree(req_data); 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci /* Prepare response */ 261062306a36Sopenharmony_ci rsp_data.status = ret; 261162306a36Sopenharmony_ci bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_stats_resp); 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; 261462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 261562306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 261662306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, 261762306a36Sopenharmony_ci &rsp_data, 261862306a36Sopenharmony_ci sizeof(struct ql_vnd_mng_host_stats_resp)); 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci bsg_reply->result = DID_OK; 262162306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 262262306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci return ret; 262562306a36Sopenharmony_ci} 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_cistatic int 262862306a36Sopenharmony_ciqla2x00_get_host_stats(struct bsg_job *bsg_job) 262962306a36Sopenharmony_ci{ 263062306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); 263162306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 263262306a36Sopenharmony_ci struct ql_vnd_stats_param *req_data; 263362306a36Sopenharmony_ci struct ql_vnd_host_stats_resp rsp_data; 263462306a36Sopenharmony_ci u32 req_data_len; 263562306a36Sopenharmony_ci int ret = 0; 263662306a36Sopenharmony_ci u64 ini_entry_count = 0; 263762306a36Sopenharmony_ci u64 entry_count = 0; 263862306a36Sopenharmony_ci u64 tgt_num = 0; 263962306a36Sopenharmony_ci u64 tmp_stat_type = 0; 264062306a36Sopenharmony_ci u64 response_len = 0; 264162306a36Sopenharmony_ci void *data; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci req_data_len = bsg_job->request_payload.payload_len; 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci if (req_data_len != sizeof(struct ql_vnd_stats_param)) { 264662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n"); 264762306a36Sopenharmony_ci return -EIO; 264862306a36Sopenharmony_ci } 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci req_data = kzalloc(sizeof(*req_data), GFP_KERNEL); 265162306a36Sopenharmony_ci if (!req_data) { 265262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n"); 265362306a36Sopenharmony_ci return -ENOMEM; 265462306a36Sopenharmony_ci } 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci /* Copy the request buffer in req_data */ 265762306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 265862306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, req_data, req_data_len); 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci /* Copy stat type to work on it */ 266162306a36Sopenharmony_ci tmp_stat_type = req_data->stat_type; 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci if (tmp_stat_type & QLA2XX_TGT_SHT_LNK_DOWN) { 266462306a36Sopenharmony_ci /* Num of tgts connected to this host */ 266562306a36Sopenharmony_ci tgt_num = qla2x00_get_num_tgts(vha); 266662306a36Sopenharmony_ci /* unset BIT_17 */ 266762306a36Sopenharmony_ci tmp_stat_type &= ~(1 << 17); 266862306a36Sopenharmony_ci } 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci /* Total ini stats */ 267162306a36Sopenharmony_ci ini_entry_count = qla2x00_count_set_bits(tmp_stat_type); 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci /* Total number of entries */ 267462306a36Sopenharmony_ci entry_count = ini_entry_count + tgt_num; 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci response_len = sizeof(struct ql_vnd_host_stats_resp) + 267762306a36Sopenharmony_ci (sizeof(struct ql_vnd_stat_entry) * entry_count); 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci if (response_len > bsg_job->reply_payload.payload_len) { 268062306a36Sopenharmony_ci rsp_data.status = EXT_STATUS_BUFFER_TOO_SMALL; 268162306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_BUFFER_TOO_SMALL; 268262306a36Sopenharmony_ci bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_stats_resp); 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 268562306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 268662306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, &rsp_data, 268762306a36Sopenharmony_ci sizeof(struct ql_vnd_mng_host_stats_resp)); 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci bsg_reply->result = DID_OK; 269062306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 269162306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 269262306a36Sopenharmony_ci goto host_stat_out; 269362306a36Sopenharmony_ci } 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci data = kzalloc(response_len, GFP_KERNEL); 269662306a36Sopenharmony_ci if (!data) { 269762306a36Sopenharmony_ci ret = -ENOMEM; 269862306a36Sopenharmony_ci goto host_stat_out; 269962306a36Sopenharmony_ci } 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci ret = qla2xxx_get_ini_stats(fc_bsg_to_shost(bsg_job), req_data->stat_type, 270262306a36Sopenharmony_ci data, response_len); 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci rsp_data.status = EXT_STATUS_OK; 270562306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 270862306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, 270962306a36Sopenharmony_ci data, response_len); 271062306a36Sopenharmony_ci bsg_reply->result = DID_OK; 271162306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 271262306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci kfree(data); 271562306a36Sopenharmony_cihost_stat_out: 271662306a36Sopenharmony_ci kfree(req_data); 271762306a36Sopenharmony_ci return ret; 271862306a36Sopenharmony_ci} 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_cistatic struct fc_rport * 272162306a36Sopenharmony_ciqla2xxx_find_rport(scsi_qla_host_t *vha, uint32_t tgt_num) 272262306a36Sopenharmony_ci{ 272362306a36Sopenharmony_ci fc_port_t *fcport = NULL; 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 272662306a36Sopenharmony_ci if (fcport->rport->number == tgt_num) 272762306a36Sopenharmony_ci return fcport->rport; 272862306a36Sopenharmony_ci } 272962306a36Sopenharmony_ci return NULL; 273062306a36Sopenharmony_ci} 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_cistatic int 273362306a36Sopenharmony_ciqla2x00_get_tgt_stats(struct bsg_job *bsg_job) 273462306a36Sopenharmony_ci{ 273562306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); 273662306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 273762306a36Sopenharmony_ci struct ql_vnd_tgt_stats_param *req_data; 273862306a36Sopenharmony_ci u32 req_data_len; 273962306a36Sopenharmony_ci int ret = 0; 274062306a36Sopenharmony_ci u64 response_len = 0; 274162306a36Sopenharmony_ci struct ql_vnd_tgt_stats_resp *data = NULL; 274262306a36Sopenharmony_ci struct fc_rport *rport = NULL; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci if (!vha->flags.online) { 274562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "Host is not online.\n"); 274662306a36Sopenharmony_ci return -EIO; 274762306a36Sopenharmony_ci } 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci req_data_len = bsg_job->request_payload.payload_len; 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci if (req_data_len != sizeof(struct ql_vnd_stat_entry)) { 275262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n"); 275362306a36Sopenharmony_ci return -EIO; 275462306a36Sopenharmony_ci } 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_ci req_data = kzalloc(sizeof(*req_data), GFP_KERNEL); 275762306a36Sopenharmony_ci if (!req_data) { 275862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n"); 275962306a36Sopenharmony_ci return -ENOMEM; 276062306a36Sopenharmony_ci } 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci /* Copy the request buffer in req_data */ 276362306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 276462306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, 276562306a36Sopenharmony_ci req_data, req_data_len); 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci response_len = sizeof(struct ql_vnd_tgt_stats_resp) + 276862306a36Sopenharmony_ci sizeof(struct ql_vnd_stat_entry); 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci /* structure + size for one entry */ 277162306a36Sopenharmony_ci data = kzalloc(response_len, GFP_KERNEL); 277262306a36Sopenharmony_ci if (!data) { 277362306a36Sopenharmony_ci kfree(req_data); 277462306a36Sopenharmony_ci return -ENOMEM; 277562306a36Sopenharmony_ci } 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci if (response_len > bsg_job->reply_payload.payload_len) { 277862306a36Sopenharmony_ci data->status = EXT_STATUS_BUFFER_TOO_SMALL; 277962306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_BUFFER_TOO_SMALL; 278062306a36Sopenharmony_ci bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_stats_resp); 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 278362306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 278462306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, data, 278562306a36Sopenharmony_ci sizeof(struct ql_vnd_tgt_stats_resp)); 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci bsg_reply->result = DID_OK; 278862306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 278962306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 279062306a36Sopenharmony_ci goto tgt_stat_out; 279162306a36Sopenharmony_ci } 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci rport = qla2xxx_find_rport(vha, req_data->tgt_id); 279462306a36Sopenharmony_ci if (!rport) { 279562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "target %d not found.\n", req_data->tgt_id); 279662306a36Sopenharmony_ci ret = EXT_STATUS_INVALID_PARAM; 279762306a36Sopenharmony_ci data->status = EXT_STATUS_INVALID_PARAM; 279862306a36Sopenharmony_ci goto reply; 279962306a36Sopenharmony_ci } 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ci ret = qla2xxx_get_tgt_stats(fc_bsg_to_shost(bsg_job), req_data->stat_type, 280262306a36Sopenharmony_ci rport, (void *)data, response_len); 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; 280562306a36Sopenharmony_cireply: 280662306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 280762306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 280862306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, data, 280962306a36Sopenharmony_ci response_len); 281062306a36Sopenharmony_ci bsg_reply->result = DID_OK; 281162306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 281262306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_citgt_stat_out: 281562306a36Sopenharmony_ci kfree(data); 281662306a36Sopenharmony_ci kfree(req_data); 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci return ret; 281962306a36Sopenharmony_ci} 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_cistatic int 282262306a36Sopenharmony_ciqla2x00_manage_host_port(struct bsg_job *bsg_job) 282362306a36Sopenharmony_ci{ 282462306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); 282562306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 282662306a36Sopenharmony_ci struct ql_vnd_mng_host_port_param *req_data; 282762306a36Sopenharmony_ci struct ql_vnd_mng_host_port_resp rsp_data; 282862306a36Sopenharmony_ci u32 req_data_len; 282962306a36Sopenharmony_ci int ret = 0; 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci req_data_len = bsg_job->request_payload.payload_len; 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ci if (req_data_len != sizeof(struct ql_vnd_mng_host_port_param)) { 283462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n"); 283562306a36Sopenharmony_ci return -EIO; 283662306a36Sopenharmony_ci } 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci req_data = kzalloc(sizeof(*req_data), GFP_KERNEL); 283962306a36Sopenharmony_ci if (!req_data) { 284062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n"); 284162306a36Sopenharmony_ci return -ENOMEM; 284262306a36Sopenharmony_ci } 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci /* Copy the request buffer in req_data */ 284562306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 284662306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, req_data, req_data_len); 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci switch (req_data->action) { 284962306a36Sopenharmony_ci case QLA_ENABLE: 285062306a36Sopenharmony_ci ret = qla2xxx_enable_port(vha->host); 285162306a36Sopenharmony_ci break; 285262306a36Sopenharmony_ci case QLA_DISABLE: 285362306a36Sopenharmony_ci ret = qla2xxx_disable_port(vha->host); 285462306a36Sopenharmony_ci break; 285562306a36Sopenharmony_ci default: 285662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0000, "Invalid action.\n"); 285762306a36Sopenharmony_ci ret = -EIO; 285862306a36Sopenharmony_ci break; 285962306a36Sopenharmony_ci } 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci kfree(req_data); 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci /* Prepare response */ 286462306a36Sopenharmony_ci rsp_data.status = ret; 286562306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; 286662306a36Sopenharmony_ci bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_port_resp); 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 286962306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 287062306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, &rsp_data, 287162306a36Sopenharmony_ci sizeof(struct ql_vnd_mng_host_port_resp)); 287262306a36Sopenharmony_ci bsg_reply->result = DID_OK; 287362306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 287462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci return ret; 287762306a36Sopenharmony_ci} 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_cistatic int 288062306a36Sopenharmony_ciqla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_job) 288162306a36Sopenharmony_ci{ 288262306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci ql_dbg(ql_dbg_edif, vha, 0x911b, "%s FC_BSG_HST_VENDOR cmd[0]=0x%x\n", 288562306a36Sopenharmony_ci __func__, bsg_request->rqst_data.h_vendor.vendor_cmd[0]); 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci switch (bsg_request->rqst_data.h_vendor.vendor_cmd[0]) { 288862306a36Sopenharmony_ci case QL_VND_LOOPBACK: 288962306a36Sopenharmony_ci return qla2x00_process_loopback(bsg_job); 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci case QL_VND_A84_RESET: 289262306a36Sopenharmony_ci return qla84xx_reset(bsg_job); 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci case QL_VND_A84_UPDATE_FW: 289562306a36Sopenharmony_ci return qla84xx_updatefw(bsg_job); 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci case QL_VND_A84_MGMT_CMD: 289862306a36Sopenharmony_ci return qla84xx_mgmt_cmd(bsg_job); 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci case QL_VND_IIDMA: 290162306a36Sopenharmony_ci return qla24xx_iidma(bsg_job); 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci case QL_VND_FCP_PRIO_CFG_CMD: 290462306a36Sopenharmony_ci return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job); 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci case QL_VND_READ_FLASH: 290762306a36Sopenharmony_ci return qla2x00_read_optrom(bsg_job); 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ci case QL_VND_UPDATE_FLASH: 291062306a36Sopenharmony_ci return qla2x00_update_optrom(bsg_job); 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci case QL_VND_SET_FRU_VERSION: 291362306a36Sopenharmony_ci return qla2x00_update_fru_versions(bsg_job); 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci case QL_VND_READ_FRU_STATUS: 291662306a36Sopenharmony_ci return qla2x00_read_fru_status(bsg_job); 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci case QL_VND_WRITE_FRU_STATUS: 291962306a36Sopenharmony_ci return qla2x00_write_fru_status(bsg_job); 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_ci case QL_VND_WRITE_I2C: 292262306a36Sopenharmony_ci return qla2x00_write_i2c(bsg_job); 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci case QL_VND_READ_I2C: 292562306a36Sopenharmony_ci return qla2x00_read_i2c(bsg_job); 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci case QL_VND_DIAG_IO_CMD: 292862306a36Sopenharmony_ci return qla24xx_process_bidir_cmd(bsg_job); 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci case QL_VND_FX00_MGMT_CMD: 293162306a36Sopenharmony_ci return qlafx00_mgmt_cmd(bsg_job); 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci case QL_VND_SERDES_OP: 293462306a36Sopenharmony_ci return qla26xx_serdes_op(bsg_job); 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci case QL_VND_SERDES_OP_EX: 293762306a36Sopenharmony_ci return qla8044_serdes_op(bsg_job); 293862306a36Sopenharmony_ci 293962306a36Sopenharmony_ci case QL_VND_GET_FLASH_UPDATE_CAPS: 294062306a36Sopenharmony_ci return qla27xx_get_flash_upd_cap(bsg_job); 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci case QL_VND_SET_FLASH_UPDATE_CAPS: 294362306a36Sopenharmony_ci return qla27xx_set_flash_upd_cap(bsg_job); 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci case QL_VND_GET_BBCR_DATA: 294662306a36Sopenharmony_ci return qla27xx_get_bbcr_data(bsg_job); 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci case QL_VND_GET_PRIV_STATS: 294962306a36Sopenharmony_ci case QL_VND_GET_PRIV_STATS_EX: 295062306a36Sopenharmony_ci return qla2x00_get_priv_stats(bsg_job); 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci case QL_VND_DPORT_DIAGNOSTICS: 295362306a36Sopenharmony_ci return qla2x00_do_dport_diagnostics(bsg_job); 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci case QL_VND_DPORT_DIAGNOSTICS_V2: 295662306a36Sopenharmony_ci return qla2x00_do_dport_diagnostics_v2(bsg_job); 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci case QL_VND_EDIF_MGMT: 295962306a36Sopenharmony_ci return qla_edif_app_mgmt(bsg_job); 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_ci case QL_VND_SS_GET_FLASH_IMAGE_STATUS: 296262306a36Sopenharmony_ci return qla2x00_get_flash_image_status(bsg_job); 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci case QL_VND_MANAGE_HOST_STATS: 296562306a36Sopenharmony_ci return qla2x00_manage_host_stats(bsg_job); 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci case QL_VND_GET_HOST_STATS: 296862306a36Sopenharmony_ci return qla2x00_get_host_stats(bsg_job); 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci case QL_VND_GET_TGT_STATS: 297162306a36Sopenharmony_ci return qla2x00_get_tgt_stats(bsg_job); 297262306a36Sopenharmony_ci 297362306a36Sopenharmony_ci case QL_VND_MANAGE_HOST_PORT: 297462306a36Sopenharmony_ci return qla2x00_manage_host_port(bsg_job); 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci case QL_VND_MBX_PASSTHRU: 297762306a36Sopenharmony_ci return qla2x00_mailbox_passthru(bsg_job); 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci default: 298062306a36Sopenharmony_ci return -ENOSYS; 298162306a36Sopenharmony_ci } 298262306a36Sopenharmony_ci} 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ciint 298562306a36Sopenharmony_ciqla24xx_bsg_request(struct bsg_job *bsg_job) 298662306a36Sopenharmony_ci{ 298762306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 298862306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 298962306a36Sopenharmony_ci int ret = -EINVAL; 299062306a36Sopenharmony_ci struct fc_rport *rport; 299162306a36Sopenharmony_ci struct Scsi_Host *host; 299262306a36Sopenharmony_ci scsi_qla_host_t *vha; 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ci /* In case no data transferred. */ 299562306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci if (bsg_request->msgcode == FC_BSG_RPT_ELS) { 299862306a36Sopenharmony_ci rport = fc_bsg_to_rport(bsg_job); 299962306a36Sopenharmony_ci if (!rport) 300062306a36Sopenharmony_ci return ret; 300162306a36Sopenharmony_ci host = rport_to_shost(rport); 300262306a36Sopenharmony_ci vha = shost_priv(host); 300362306a36Sopenharmony_ci } else { 300462306a36Sopenharmony_ci host = fc_bsg_to_shost(bsg_job); 300562306a36Sopenharmony_ci vha = shost_priv(host); 300662306a36Sopenharmony_ci } 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci /* Disable port will bring down the chip, allow enable command */ 300962306a36Sopenharmony_ci if (bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_MANAGE_HOST_PORT || 301062306a36Sopenharmony_ci bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_GET_HOST_STATS) 301162306a36Sopenharmony_ci goto skip_chip_chk; 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci if (vha->hw->flags.port_isolated) { 301462306a36Sopenharmony_ci bsg_reply->result = DID_ERROR; 301562306a36Sopenharmony_ci /* operation not permitted */ 301662306a36Sopenharmony_ci return -EPERM; 301762306a36Sopenharmony_ci } 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_ci if (qla2x00_chip_is_down(vha)) { 302062306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x709f, 302162306a36Sopenharmony_ci "BSG: ISP abort active/needed -- cmd=%d.\n", 302262306a36Sopenharmony_ci bsg_request->msgcode); 302362306a36Sopenharmony_ci SET_DID_STATUS(bsg_reply->result, DID_ERROR); 302462306a36Sopenharmony_ci return -EBUSY; 302562306a36Sopenharmony_ci } 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci if (test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags)) { 302862306a36Sopenharmony_ci SET_DID_STATUS(bsg_reply->result, DID_ERROR); 302962306a36Sopenharmony_ci return -EIO; 303062306a36Sopenharmony_ci } 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ciskip_chip_chk: 303362306a36Sopenharmony_ci ql_dbg(ql_dbg_user + ql_dbg_verbose, vha, 0x7000, 303462306a36Sopenharmony_ci "Entered %s msgcode=0x%x. bsg ptr %px\n", 303562306a36Sopenharmony_ci __func__, bsg_request->msgcode, bsg_job); 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci switch (bsg_request->msgcode) { 303862306a36Sopenharmony_ci case FC_BSG_RPT_ELS: 303962306a36Sopenharmony_ci case FC_BSG_HST_ELS_NOLOGIN: 304062306a36Sopenharmony_ci ret = qla2x00_process_els(bsg_job); 304162306a36Sopenharmony_ci break; 304262306a36Sopenharmony_ci case FC_BSG_HST_CT: 304362306a36Sopenharmony_ci ret = qla2x00_process_ct(bsg_job); 304462306a36Sopenharmony_ci break; 304562306a36Sopenharmony_ci case FC_BSG_HST_VENDOR: 304662306a36Sopenharmony_ci ret = qla2x00_process_vendor_specific(vha, bsg_job); 304762306a36Sopenharmony_ci break; 304862306a36Sopenharmony_ci case FC_BSG_HST_ADD_RPORT: 304962306a36Sopenharmony_ci case FC_BSG_HST_DEL_RPORT: 305062306a36Sopenharmony_ci case FC_BSG_RPT_CT: 305162306a36Sopenharmony_ci default: 305262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x705a, "Unsupported BSG request.\n"); 305362306a36Sopenharmony_ci break; 305462306a36Sopenharmony_ci } 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci ql_dbg(ql_dbg_user + ql_dbg_verbose, vha, 0x7000, 305762306a36Sopenharmony_ci "%s done with return %x\n", __func__, ret); 305862306a36Sopenharmony_ci 305962306a36Sopenharmony_ci return ret; 306062306a36Sopenharmony_ci} 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ciint 306362306a36Sopenharmony_ciqla24xx_bsg_timeout(struct bsg_job *bsg_job) 306462306a36Sopenharmony_ci{ 306562306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 306662306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); 306762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 306862306a36Sopenharmony_ci srb_t *sp; 306962306a36Sopenharmony_ci int cnt, que; 307062306a36Sopenharmony_ci unsigned long flags; 307162306a36Sopenharmony_ci struct req_que *req; 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x708b, "%s CMD timeout. bsg ptr %p.\n", 307462306a36Sopenharmony_ci __func__, bsg_job); 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci if (qla2x00_isp_reg_stat(ha)) { 307762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x9007, 307862306a36Sopenharmony_ci "PCI/Register disconnect.\n"); 307962306a36Sopenharmony_ci qla_pci_set_eeh_busy(vha); 308062306a36Sopenharmony_ci } 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci /* find the bsg job from the active list of commands */ 308362306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 308462306a36Sopenharmony_ci for (que = 0; que < ha->max_req_queues; que++) { 308562306a36Sopenharmony_ci req = ha->req_q_map[que]; 308662306a36Sopenharmony_ci if (!req) 308762306a36Sopenharmony_ci continue; 308862306a36Sopenharmony_ci 308962306a36Sopenharmony_ci for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { 309062306a36Sopenharmony_ci sp = req->outstanding_cmds[cnt]; 309162306a36Sopenharmony_ci if (sp && 309262306a36Sopenharmony_ci (sp->type == SRB_CT_CMD || 309362306a36Sopenharmony_ci sp->type == SRB_ELS_CMD_HST || 309462306a36Sopenharmony_ci sp->type == SRB_ELS_CMD_HST_NOLOGIN || 309562306a36Sopenharmony_ci sp->type == SRB_FXIOCB_BCMD) && 309662306a36Sopenharmony_ci sp->u.bsg_job == bsg_job) { 309762306a36Sopenharmony_ci req->outstanding_cmds[cnt] = NULL; 309862306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_ci if (!ha->flags.eeh_busy && ha->isp_ops->abort_command(sp)) { 310162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x7089, 310262306a36Sopenharmony_ci "mbx abort_command failed.\n"); 310362306a36Sopenharmony_ci bsg_reply->result = -EIO; 310462306a36Sopenharmony_ci } else { 310562306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x708a, 310662306a36Sopenharmony_ci "mbx abort_command success.\n"); 310762306a36Sopenharmony_ci bsg_reply->result = 0; 310862306a36Sopenharmony_ci } 310962306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 311062306a36Sopenharmony_ci goto done; 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci } 311362306a36Sopenharmony_ci } 311462306a36Sopenharmony_ci } 311562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 311662306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x708b, "SRB not found to abort.\n"); 311762306a36Sopenharmony_ci bsg_reply->result = -ENXIO; 311862306a36Sopenharmony_ci return 0; 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_cidone: 312162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 312262306a36Sopenharmony_ci /* ref: INIT */ 312362306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 312462306a36Sopenharmony_ci return 0; 312562306a36Sopenharmony_ci} 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ciint qla2x00_mailbox_passthru(struct bsg_job *bsg_job) 312862306a36Sopenharmony_ci{ 312962306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply = bsg_job->reply; 313062306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); 313162306a36Sopenharmony_ci int ret = -EINVAL; 313262306a36Sopenharmony_ci int ptsize = sizeof(struct qla_mbx_passthru); 313362306a36Sopenharmony_ci struct qla_mbx_passthru *req_data = NULL; 313462306a36Sopenharmony_ci uint32_t req_data_len; 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci req_data_len = bsg_job->request_payload.payload_len; 313762306a36Sopenharmony_ci if (req_data_len != ptsize) { 313862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xf0a3, "req_data_len invalid.\n"); 313962306a36Sopenharmony_ci return -EIO; 314062306a36Sopenharmony_ci } 314162306a36Sopenharmony_ci req_data = kzalloc(ptsize, GFP_KERNEL); 314262306a36Sopenharmony_ci if (!req_data) { 314362306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xf0a4, 314462306a36Sopenharmony_ci "req_data memory allocation failure.\n"); 314562306a36Sopenharmony_ci return -ENOMEM; 314662306a36Sopenharmony_ci } 314762306a36Sopenharmony_ci 314862306a36Sopenharmony_ci /* Copy the request buffer in req_data */ 314962306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 315062306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, req_data, ptsize); 315162306a36Sopenharmony_ci ret = qla_mailbox_passthru(vha, req_data->mbx_in, req_data->mbx_out); 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci /* Copy the req_data in request buffer */ 315462306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 315562306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, req_data, ptsize); 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = ptsize; 315862306a36Sopenharmony_ci if (ret == QLA_SUCCESS) 315962306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; 316062306a36Sopenharmony_ci else 316162306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_ERR; 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci bsg_job->reply_len = sizeof(*bsg_job->reply); 316462306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 316562306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci kfree(req_data); 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_ci return ret; 317062306a36Sopenharmony_ci} 3171