3189 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * QLogic Fibre Channel HBA Driver4 * Copyright (c) 2003-2014 QLogic Corporation5 */6#include "qla_def.h"7#include "qla_gbl.h"8 9#include <linux/kthread.h>10#include <linux/vmalloc.h>11#include <linux/delay.h>12#include <linux/bsg-lib.h>13 14static void qla2xxx_free_fcport_work(struct work_struct *work)15{16 struct fc_port *fcport = container_of(work, typeof(*fcport),17 free_work);18 19 qla2x00_free_fcport(fcport);20}21 22/* BSG support for ELS/CT pass through */23void qla2x00_bsg_job_done(srb_t *sp, int res)24{25 struct bsg_job *bsg_job = sp->u.bsg_job;26 struct fc_bsg_reply *bsg_reply = bsg_job->reply;27 28 ql_dbg(ql_dbg_user, sp->vha, 0x7009,29 "%s: sp hdl %x, result=%x bsg ptr %p\n",30 __func__, sp->handle, res, bsg_job);31 32 /* ref: INIT */33 kref_put(&sp->cmd_kref, qla2x00_sp_release);34 35 bsg_reply->result = res;36 bsg_job_done(bsg_job, bsg_reply->result,37 bsg_reply->reply_payload_rcv_len);38}39 40void qla2x00_bsg_sp_free(srb_t *sp)41{42 struct qla_hw_data *ha = sp->vha->hw;43 struct bsg_job *bsg_job = sp->u.bsg_job;44 struct fc_bsg_request *bsg_request = bsg_job->request;45 struct qla_mt_iocb_rqst_fx00 *piocb_rqst;46 47 if (sp->type == SRB_FXIOCB_BCMD) {48 piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)49 &bsg_request->rqst_data.h_vendor.vendor_cmd[1];50 51 if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID)52 dma_unmap_sg(&ha->pdev->dev,53 bsg_job->request_payload.sg_list,54 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);55 56 if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)57 dma_unmap_sg(&ha->pdev->dev,58 bsg_job->reply_payload.sg_list,59 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);60 } else {61 62 if (sp->remap.remapped) {63 dma_pool_free(ha->purex_dma_pool, sp->remap.rsp.buf,64 sp->remap.rsp.dma);65 dma_pool_free(ha->purex_dma_pool, sp->remap.req.buf,66 sp->remap.req.dma);67 } else {68 dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,69 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);70 71 dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,72 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);73 }74 }75 76 if (sp->type == SRB_CT_CMD ||77 sp->type == SRB_FXIOCB_BCMD ||78 sp->type == SRB_ELS_CMD_HST) {79 INIT_WORK(&sp->fcport->free_work, qla2xxx_free_fcport_work);80 queue_work(ha->wq, &sp->fcport->free_work);81 }82 83 qla2x00_rel_sp(sp);84}85 86int87qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *vha,88 struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)89{90 int i, ret, num_valid;91 uint8_t *bcode;92 struct qla_fcp_prio_entry *pri_entry;93 uint32_t *bcode_val_ptr, bcode_val;94 95 ret = 1;96 num_valid = 0;97 bcode = (uint8_t *)pri_cfg;98 bcode_val_ptr = (uint32_t *)pri_cfg;99 bcode_val = (uint32_t)(*bcode_val_ptr);100 101 if (bcode_val == 0xFFFFFFFF) {102 /* No FCP Priority config data in flash */103 ql_dbg(ql_dbg_user, vha, 0x7051,104 "No FCP Priority config data.\n");105 return 0;106 }107 108 if (memcmp(bcode, "HQOS", 4)) {109 /* Invalid FCP priority data header*/110 ql_dbg(ql_dbg_user, vha, 0x7052,111 "Invalid FCP Priority data header. bcode=0x%x.\n",112 bcode_val);113 return 0;114 }115 if (flag != 1)116 return ret;117 118 pri_entry = &pri_cfg->entry[0];119 for (i = 0; i < pri_cfg->num_entries; i++) {120 if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID)121 num_valid++;122 pri_entry++;123 }124 125 if (num_valid == 0) {126 /* No valid FCP priority data entries */127 ql_dbg(ql_dbg_user, vha, 0x7053,128 "No valid FCP Priority data entries.\n");129 ret = 0;130 } else {131 /* FCP priority data is valid */132 ql_dbg(ql_dbg_user, vha, 0x7054,133 "Valid FCP priority data. num entries = %d.\n",134 num_valid);135 }136 137 return ret;138}139 140static int141qla24xx_proc_fcp_prio_cfg_cmd(struct bsg_job *bsg_job)142{143 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);144 struct fc_bsg_request *bsg_request = bsg_job->request;145 struct fc_bsg_reply *bsg_reply = bsg_job->reply;146 scsi_qla_host_t *vha = shost_priv(host);147 struct qla_hw_data *ha = vha->hw;148 int ret = 0;149 uint32_t len;150 uint32_t oper;151 152 if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_P3P_TYPE(ha))) {153 ret = -EINVAL;154 goto exit_fcp_prio_cfg;155 }156 157 /* Get the sub command */158 oper = bsg_request->rqst_data.h_vendor.vendor_cmd[1];159 160 /* Only set config is allowed if config memory is not allocated */161 if (!ha->fcp_prio_cfg && (oper != QLFC_FCP_PRIO_SET_CONFIG)) {162 ret = -EINVAL;163 goto exit_fcp_prio_cfg;164 }165 switch (oper) {166 case QLFC_FCP_PRIO_DISABLE:167 if (ha->flags.fcp_prio_enabled) {168 ha->flags.fcp_prio_enabled = 0;169 ha->fcp_prio_cfg->attributes &=170 ~FCP_PRIO_ATTR_ENABLE;171 qla24xx_update_all_fcp_prio(vha);172 bsg_reply->result = DID_OK;173 } else {174 ret = -EINVAL;175 bsg_reply->result = (DID_ERROR << 16);176 goto exit_fcp_prio_cfg;177 }178 break;179 180 case QLFC_FCP_PRIO_ENABLE:181 if (!ha->flags.fcp_prio_enabled) {182 if (ha->fcp_prio_cfg) {183 ha->flags.fcp_prio_enabled = 1;184 ha->fcp_prio_cfg->attributes |=185 FCP_PRIO_ATTR_ENABLE;186 qla24xx_update_all_fcp_prio(vha);187 bsg_reply->result = DID_OK;188 } else {189 ret = -EINVAL;190 bsg_reply->result = (DID_ERROR << 16);191 goto exit_fcp_prio_cfg;192 }193 }194 break;195 196 case QLFC_FCP_PRIO_GET_CONFIG:197 len = bsg_job->reply_payload.payload_len;198 if (!len || len > FCP_PRIO_CFG_SIZE) {199 ret = -EINVAL;200 bsg_reply->result = (DID_ERROR << 16);201 goto exit_fcp_prio_cfg;202 }203 204 bsg_reply->result = DID_OK;205 bsg_reply->reply_payload_rcv_len =206 sg_copy_from_buffer(207 bsg_job->reply_payload.sg_list,208 bsg_job->reply_payload.sg_cnt, ha->fcp_prio_cfg,209 len);210 211 break;212 213 case QLFC_FCP_PRIO_SET_CONFIG:214 len = bsg_job->request_payload.payload_len;215 if (!len || len > FCP_PRIO_CFG_SIZE) {216 bsg_reply->result = (DID_ERROR << 16);217 ret = -EINVAL;218 goto exit_fcp_prio_cfg;219 }220 221 if (!ha->fcp_prio_cfg) {222 ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE);223 if (!ha->fcp_prio_cfg) {224 ql_log(ql_log_warn, vha, 0x7050,225 "Unable to allocate memory for fcp prio "226 "config data (%x).\n", FCP_PRIO_CFG_SIZE);227 bsg_reply->result = (DID_ERROR << 16);228 ret = -ENOMEM;229 goto exit_fcp_prio_cfg;230 }231 }232 233 memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE);234 sg_copy_to_buffer(bsg_job->request_payload.sg_list,235 bsg_job->request_payload.sg_cnt, ha->fcp_prio_cfg,236 FCP_PRIO_CFG_SIZE);237 238 /* validate fcp priority data */239 240 if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 1)) {241 bsg_reply->result = (DID_ERROR << 16);242 ret = -EINVAL;243 /* If buffer was invalidatic int244 * fcp_prio_cfg is of no use245 */246 vfree(ha->fcp_prio_cfg);247 ha->fcp_prio_cfg = NULL;248 goto exit_fcp_prio_cfg;249 }250 251 ha->flags.fcp_prio_enabled = 0;252 if (ha->fcp_prio_cfg->attributes & FCP_PRIO_ATTR_ENABLE)253 ha->flags.fcp_prio_enabled = 1;254 qla24xx_update_all_fcp_prio(vha);255 bsg_reply->result = DID_OK;256 break;257 default:258 ret = -EINVAL;259 break;260 }261exit_fcp_prio_cfg:262 if (!ret)263 bsg_job_done(bsg_job, bsg_reply->result,264 bsg_reply->reply_payload_rcv_len);265 return ret;266}267 268static int269qla2x00_process_els(struct bsg_job *bsg_job)270{271 struct fc_bsg_request *bsg_request = bsg_job->request;272 struct fc_rport *rport;273 fc_port_t *fcport = NULL;274 struct Scsi_Host *host;275 scsi_qla_host_t *vha;276 struct qla_hw_data *ha;277 srb_t *sp;278 const char *type;279 int req_sg_cnt, rsp_sg_cnt;280 int rval = (DID_ERROR << 16);281 uint32_t els_cmd = 0;282 int qla_port_allocated = 0;283 284 if (bsg_request->msgcode == FC_BSG_RPT_ELS) {285 rport = fc_bsg_to_rport(bsg_job);286 if (!rport) {287 rval = -ENOMEM;288 goto done;289 }290 fcport = *(fc_port_t **) rport->dd_data;291 host = rport_to_shost(rport);292 vha = shost_priv(host);293 ha = vha->hw;294 type = "FC_BSG_RPT_ELS";295 } else {296 host = fc_bsg_to_shost(bsg_job);297 vha = shost_priv(host);298 ha = vha->hw;299 type = "FC_BSG_HST_ELS_NOLOGIN";300 els_cmd = bsg_request->rqst_data.h_els.command_code;301 if (els_cmd == ELS_AUTH_ELS)302 return qla_edif_process_els(vha, bsg_job);303 }304 305 if (!vha->flags.online) {306 ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n");307 rval = -EIO;308 goto done;309 }310 311 /* pass through is supported only for ISP 4Gb or higher */312 if (!IS_FWI2_CAPABLE(ha)) {313 ql_dbg(ql_dbg_user, vha, 0x7001,314 "ELS passthru not supported for ISP23xx based adapters.\n");315 rval = -EPERM;316 goto done;317 }318 319 /* Multiple SG's are not supported for ELS requests */320 if (bsg_job->request_payload.sg_cnt > 1 ||321 bsg_job->reply_payload.sg_cnt > 1) {322 ql_dbg(ql_dbg_user, vha, 0x7002,323 "Multiple SG's are not supported for ELS requests, "324 "request_sg_cnt=%x reply_sg_cnt=%x.\n",325 bsg_job->request_payload.sg_cnt,326 bsg_job->reply_payload.sg_cnt);327 rval = -ENOBUFS;328 goto done;329 }330 331 /* ELS request for rport */332 if (bsg_request->msgcode == FC_BSG_RPT_ELS) {333 /* make sure the rport is logged in,334 * if not perform fabric login335 */336 if (atomic_read(&fcport->state) != FCS_ONLINE) {337 ql_dbg(ql_dbg_user, vha, 0x7003,338 "Port %06X is not online for ELS passthru.\n",339 fcport->d_id.b24);340 rval = -EIO;341 goto done;342 }343 } else {344 /* Allocate a dummy fcport structure, since functions345 * preparing the IOCB and mailbox command retrieves port346 * specific information from fcport structure. For Host based347 * ELS commands there will be no fcport structure allocated348 */349 fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);350 if (!fcport) {351 rval = -ENOMEM;352 goto done;353 }354 355 qla_port_allocated = 1;356 /* Initialize all required fields of fcport */357 fcport->vha = vha;358 fcport->d_id.b.al_pa =359 bsg_request->rqst_data.h_els.port_id[0];360 fcport->d_id.b.area =361 bsg_request->rqst_data.h_els.port_id[1];362 fcport->d_id.b.domain =363 bsg_request->rqst_data.h_els.port_id[2];364 fcport->loop_id =365 (fcport->d_id.b.al_pa == 0xFD) ?366 NPH_FABRIC_CONTROLLER : NPH_F_PORT;367 }368 369 req_sg_cnt =370 dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,371 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);372 if (!req_sg_cnt) {373 dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,374 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);375 rval = -ENOMEM;376 goto done_free_fcport;377 }378 379 rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,380 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);381 if (!rsp_sg_cnt) {382 dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,383 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);384 rval = -ENOMEM;385 goto done_free_fcport;386 }387 388 if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) ||389 (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {390 ql_log(ql_log_warn, vha, 0x7008,391 "dma mapping resulted in different sg counts, "392 "request_sg_cnt: %x dma_request_sg_cnt:%x reply_sg_cnt:%x "393 "dma_reply_sg_cnt:%x.\n", bsg_job->request_payload.sg_cnt,394 req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);395 rval = -EAGAIN;396 goto done_unmap_sg;397 }398 399 /* Alloc SRB structure */400 sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);401 if (!sp) {402 rval = -ENOMEM;403 goto done_unmap_sg;404 }405 406 sp->type =407 (bsg_request->msgcode == FC_BSG_RPT_ELS ?408 SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST);409 sp->name =410 (bsg_request->msgcode == FC_BSG_RPT_ELS ?411 "bsg_els_rpt" : "bsg_els_hst");412 sp->u.bsg_job = bsg_job;413 sp->free = qla2x00_bsg_sp_free;414 sp->done = qla2x00_bsg_job_done;415 416 ql_dbg(ql_dbg_user, vha, 0x700a,417 "bsg rqst type: %s els type: %x - loop-id=%x "418 "portid=%-2x%02x%02x.\n", type,419 bsg_request->rqst_data.h_els.command_code, fcport->loop_id,420 fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);421 422 rval = qla2x00_start_sp(sp);423 if (rval != QLA_SUCCESS) {424 ql_log(ql_log_warn, vha, 0x700e,425 "qla2x00_start_sp failed = %d\n", rval);426 qla2x00_rel_sp(sp);427 rval = -EIO;428 goto done_unmap_sg;429 }430 return rval;431 432done_unmap_sg:433 dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,434 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);435 dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,436 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);437 goto done_free_fcport;438 439done_free_fcport:440 if (qla_port_allocated)441 qla2x00_free_fcport(fcport);442done:443 return rval;444}445 446static inline uint16_t447qla24xx_calc_ct_iocbs(uint16_t dsds)448{449 uint16_t iocbs;450 451 iocbs = 1;452 if (dsds > 2) {453 iocbs += (dsds - 2) / 5;454 if ((dsds - 2) % 5)455 iocbs++;456 }457 return iocbs;458}459 460static int461qla2x00_process_ct(struct bsg_job *bsg_job)462{463 srb_t *sp;464 struct fc_bsg_request *bsg_request = bsg_job->request;465 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);466 scsi_qla_host_t *vha = shost_priv(host);467 struct qla_hw_data *ha = vha->hw;468 int rval = (DID_ERROR << 16);469 int req_sg_cnt, rsp_sg_cnt;470 uint16_t loop_id;471 struct fc_port *fcport;472 char *type = "FC_BSG_HST_CT";473 474 req_sg_cnt =475 dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,476 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);477 if (!req_sg_cnt) {478 ql_log(ql_log_warn, vha, 0x700f,479 "dma_map_sg return %d for request\n", req_sg_cnt);480 rval = -ENOMEM;481 goto done;482 }483 484 rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,485 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);486 if (!rsp_sg_cnt) {487 ql_log(ql_log_warn, vha, 0x7010,488 "dma_map_sg return %d for reply\n", rsp_sg_cnt);489 rval = -ENOMEM;490 goto done;491 }492 493 if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) ||494 (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {495 ql_log(ql_log_warn, vha, 0x7011,496 "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x "497 "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt,498 req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);499 rval = -EAGAIN;500 goto done_unmap_sg;501 }502 503 if (!vha->flags.online) {504 ql_log(ql_log_warn, vha, 0x7012,505 "Host is not online.\n");506 rval = -EIO;507 goto done_unmap_sg;508 }509 510 loop_id =511 (bsg_request->rqst_data.h_ct.preamble_word1 & 0xFF000000)512 >> 24;513 switch (loop_id) {514 case 0xFC:515 loop_id = NPH_SNS;516 break;517 case 0xFA:518 loop_id = vha->mgmt_svr_loop_id;519 break;520 default:521 ql_dbg(ql_dbg_user, vha, 0x7013,522 "Unknown loop id: %x.\n", loop_id);523 rval = -EINVAL;524 goto done_unmap_sg;525 }526 527 /* Allocate a dummy fcport structure, since functions preparing the528 * IOCB and mailbox command retrieves port specific information529 * from fcport structure. For Host based ELS commands there will be530 * no fcport structure allocated531 */532 fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);533 if (!fcport) {534 ql_log(ql_log_warn, vha, 0x7014,535 "Failed to allocate fcport.\n");536 rval = -ENOMEM;537 goto done_unmap_sg;538 }539 540 /* Initialize all required fields of fcport */541 fcport->vha = vha;542 fcport->d_id.b.al_pa = bsg_request->rqst_data.h_ct.port_id[0];543 fcport->d_id.b.area = bsg_request->rqst_data.h_ct.port_id[1];544 fcport->d_id.b.domain = bsg_request->rqst_data.h_ct.port_id[2];545 fcport->loop_id = loop_id;546 547 /* Alloc SRB structure */548 sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);549 if (!sp) {550 ql_log(ql_log_warn, vha, 0x7015,551 "qla2x00_get_sp failed.\n");552 rval = -ENOMEM;553 goto done_free_fcport;554 }555 556 sp->type = SRB_CT_CMD;557 sp->name = "bsg_ct";558 sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt);559 sp->u.bsg_job = bsg_job;560 sp->free = qla2x00_bsg_sp_free;561 sp->done = qla2x00_bsg_job_done;562 563 ql_dbg(ql_dbg_user, vha, 0x7016,564 "bsg rqst type: %s else type: %x - "565 "loop-id=%x portid=%02x%02x%02x.\n", type,566 (bsg_request->rqst_data.h_ct.preamble_word2 >> 16),567 fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,568 fcport->d_id.b.al_pa);569 570 rval = qla2x00_start_sp(sp);571 if (rval != QLA_SUCCESS) {572 ql_log(ql_log_warn, vha, 0x7017,573 "qla2x00_start_sp failed=%d.\n", rval);574 qla2x00_rel_sp(sp);575 rval = -EIO;576 goto done_free_fcport;577 }578 return rval;579 580done_free_fcport:581 qla2x00_free_fcport(fcport);582done_unmap_sg:583 dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,584 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);585 dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,586 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);587done:588 return rval;589}590 591/* Disable loopback mode */592static inline int593qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,594 int wait, int wait2)595{596 int ret = 0;597 int rval = 0;598 uint16_t new_config[4];599 struct qla_hw_data *ha = vha->hw;600 601 if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))602 goto done_reset_internal;603 604 memset(new_config, 0 , sizeof(new_config));605 if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==606 ENABLE_INTERNAL_LOOPBACK ||607 (config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==608 ENABLE_EXTERNAL_LOOPBACK) {609 new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK;610 ql_dbg(ql_dbg_user, vha, 0x70bf, "new_config[0]=%02x\n",611 (new_config[0] & INTERNAL_LOOPBACK_MASK));612 memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;613 614 ha->notify_dcbx_comp = wait;615 ha->notify_lb_portup_comp = wait2;616 617 ret = qla81xx_set_port_config(vha, new_config);618 if (ret != QLA_SUCCESS) {619 ql_log(ql_log_warn, vha, 0x7025,620 "Set port config failed.\n");621 ha->notify_dcbx_comp = 0;622 ha->notify_lb_portup_comp = 0;623 rval = -EINVAL;624 goto done_reset_internal;625 }626 627 /* Wait for DCBX complete event */628 if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,629 (DCBX_COMP_TIMEOUT * HZ))) {630 ql_dbg(ql_dbg_user, vha, 0x7026,631 "DCBX completion not received.\n");632 ha->notify_dcbx_comp = 0;633 ha->notify_lb_portup_comp = 0;634 rval = -EINVAL;635 goto done_reset_internal;636 } else637 ql_dbg(ql_dbg_user, vha, 0x7027,638 "DCBX completion received.\n");639 640 if (wait2 &&641 !wait_for_completion_timeout(&ha->lb_portup_comp,642 (LB_PORTUP_COMP_TIMEOUT * HZ))) {643 ql_dbg(ql_dbg_user, vha, 0x70c5,644 "Port up completion not received.\n");645 ha->notify_lb_portup_comp = 0;646 rval = -EINVAL;647 goto done_reset_internal;648 } else649 ql_dbg(ql_dbg_user, vha, 0x70c6,650 "Port up completion received.\n");651 652 ha->notify_dcbx_comp = 0;653 ha->notify_lb_portup_comp = 0;654 }655done_reset_internal:656 return rval;657}658 659/*660 * Set the port configuration to enable the internal or external loopback661 * depending on the loopback mode.662 */663static inline int664qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,665 uint16_t *new_config, uint16_t mode)666{667 int ret = 0;668 int rval = 0;669 unsigned long rem_tmo = 0, current_tmo = 0;670 struct qla_hw_data *ha = vha->hw;671 672 if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))673 goto done_set_internal;674 675 if (mode == INTERNAL_LOOPBACK)676 new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);677 else if (mode == EXTERNAL_LOOPBACK)678 new_config[0] = config[0] | (ENABLE_EXTERNAL_LOOPBACK << 1);679 ql_dbg(ql_dbg_user, vha, 0x70be,680 "new_config[0]=%02x\n", (new_config[0] & INTERNAL_LOOPBACK_MASK));681 682 memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3);683 684 ha->notify_dcbx_comp = 1;685 ret = qla81xx_set_port_config(vha, new_config);686 if (ret != QLA_SUCCESS) {687 ql_log(ql_log_warn, vha, 0x7021,688 "set port config failed.\n");689 ha->notify_dcbx_comp = 0;690 rval = -EINVAL;691 goto done_set_internal;692 }693 694 /* Wait for DCBX complete event */695 current_tmo = DCBX_COMP_TIMEOUT * HZ;696 while (1) {697 rem_tmo = wait_for_completion_timeout(&ha->dcbx_comp,698 current_tmo);699 if (!ha->idc_extend_tmo || rem_tmo) {700 ha->idc_extend_tmo = 0;701 break;702 }703 current_tmo = ha->idc_extend_tmo * HZ;704 ha->idc_extend_tmo = 0;705 }706 707 if (!rem_tmo) {708 ql_dbg(ql_dbg_user, vha, 0x7022,709 "DCBX completion not received.\n");710 ret = qla81xx_reset_loopback_mode(vha, new_config, 0, 0);711 /*712 * If the reset of the loopback mode doesn't work take a FCoE713 * dump and reset the chip.714 */715 if (ret) {716 qla2xxx_dump_fw(vha);717 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);718 }719 rval = -EINVAL;720 } else {721 if (ha->flags.idc_compl_status) {722 ql_dbg(ql_dbg_user, vha, 0x70c3,723 "Bad status in IDC Completion AEN\n");724 rval = -EINVAL;725 ha->flags.idc_compl_status = 0;726 } else727 ql_dbg(ql_dbg_user, vha, 0x7023,728 "DCBX completion received.\n");729 }730 731 ha->notify_dcbx_comp = 0;732 ha->idc_extend_tmo = 0;733 734done_set_internal:735 return rval;736}737 738static int739qla2x00_process_loopback(struct bsg_job *bsg_job)740{741 struct fc_bsg_request *bsg_request = bsg_job->request;742 struct fc_bsg_reply *bsg_reply = bsg_job->reply;743 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);744 scsi_qla_host_t *vha = shost_priv(host);745 struct qla_hw_data *ha = vha->hw;746 int rval;747 uint8_t command_sent;748 char *type;749 struct msg_echo_lb elreq;750 uint16_t response[MAILBOX_REGISTER_COUNT];751 uint16_t config[4], new_config[4];752 uint8_t *fw_sts_ptr;753 void *req_data = NULL;754 dma_addr_t req_data_dma;755 uint32_t req_data_len;756 uint8_t *rsp_data = NULL;757 dma_addr_t rsp_data_dma;758 uint32_t rsp_data_len;759 760 if (!vha->flags.online) {761 ql_log(ql_log_warn, vha, 0x7019, "Host is not online.\n");762 return -EIO;763 }764 765 memset(&elreq, 0, sizeof(elreq));766 767 elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev,768 bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt,769 DMA_TO_DEVICE);770 771 if (!elreq.req_sg_cnt) {772 ql_log(ql_log_warn, vha, 0x701a,773 "dma_map_sg returned %d for request.\n", elreq.req_sg_cnt);774 return -ENOMEM;775 }776 777 elreq.rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,778 bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt,779 DMA_FROM_DEVICE);780 781 if (!elreq.rsp_sg_cnt) {782 ql_log(ql_log_warn, vha, 0x701b,783 "dma_map_sg returned %d for reply.\n", elreq.rsp_sg_cnt);784 rval = -ENOMEM;785 goto done_unmap_req_sg;786 }787 788 if ((elreq.req_sg_cnt != bsg_job->request_payload.sg_cnt) ||789 (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {790 ql_log(ql_log_warn, vha, 0x701c,791 "dma mapping resulted in different sg counts, "792 "request_sg_cnt: %x dma_request_sg_cnt: %x "793 "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n",794 bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt,795 bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt);796 rval = -EAGAIN;797 goto done_unmap_sg;798 }799 req_data_len = rsp_data_len = bsg_job->request_payload.payload_len;800 req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len,801 &req_data_dma, GFP_KERNEL);802 if (!req_data) {803 ql_log(ql_log_warn, vha, 0x701d,804 "dma alloc failed for req_data.\n");805 rval = -ENOMEM;806 goto done_unmap_sg;807 }808 809 rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len,810 &rsp_data_dma, GFP_KERNEL);811 if (!rsp_data) {812 ql_log(ql_log_warn, vha, 0x7004,813 "dma alloc failed for rsp_data.\n");814 rval = -ENOMEM;815 goto done_free_dma_req;816 }817 818 /* Copy the request buffer in req_data now */819 sg_copy_to_buffer(bsg_job->request_payload.sg_list,820 bsg_job->request_payload.sg_cnt, req_data, req_data_len);821 822 elreq.send_dma = req_data_dma;823 elreq.rcv_dma = rsp_data_dma;824 elreq.transfer_size = req_data_len;825 826 elreq.options = bsg_request->rqst_data.h_vendor.vendor_cmd[1];827 elreq.iteration_count =828 bsg_request->rqst_data.h_vendor.vendor_cmd[2];829 830 if (atomic_read(&vha->loop_state) == LOOP_READY &&831 ((ha->current_topology == ISP_CFG_F && (elreq.options & 7) >= 2) ||832 ((IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) &&833 get_unaligned_le32(req_data) == ELS_OPCODE_BYTE &&834 req_data_len == MAX_ELS_FRAME_PAYLOAD &&835 elreq.options == EXTERNAL_LOOPBACK))) {836 type = "FC_BSG_HST_VENDOR_ECHO_DIAG";837 ql_dbg(ql_dbg_user, vha, 0x701e,838 "BSG request type: %s.\n", type);839 command_sent = INT_DEF_LB_ECHO_CMD;840 rval = qla2x00_echo_test(vha, &elreq, response);841 } else {842 if (IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) {843 memset(config, 0, sizeof(config));844 memset(new_config, 0, sizeof(new_config));845 846 if (qla81xx_get_port_config(vha, config)) {847 ql_log(ql_log_warn, vha, 0x701f,848 "Get port config failed.\n");849 rval = -EPERM;850 goto done_free_dma_rsp;851 }852 853 if ((config[0] & INTERNAL_LOOPBACK_MASK) != 0) {854 ql_dbg(ql_dbg_user, vha, 0x70c4,855 "Loopback operation already in "856 "progress.\n");857 rval = -EAGAIN;858 goto done_free_dma_rsp;859 }860 861 ql_dbg(ql_dbg_user, vha, 0x70c0,862 "elreq.options=%04x\n", elreq.options);863 864 if (elreq.options == EXTERNAL_LOOPBACK)865 if (IS_QLA8031(ha) || IS_QLA8044(ha))866 rval = qla81xx_set_loopback_mode(vha,867 config, new_config, elreq.options);868 else869 rval = qla81xx_reset_loopback_mode(vha,870 config, 1, 0);871 else872 rval = qla81xx_set_loopback_mode(vha, config,873 new_config, elreq.options);874 875 if (rval) {876 rval = -EPERM;877 goto done_free_dma_rsp;878 }879 880 type = "FC_BSG_HST_VENDOR_LOOPBACK";881 ql_dbg(ql_dbg_user, vha, 0x7028,882 "BSG request type: %s.\n", type);883 884 command_sent = INT_DEF_LB_LOOPBACK_CMD;885 rval = qla2x00_loopback_test(vha, &elreq, response);886 887 if (response[0] == MBS_COMMAND_ERROR &&888 response[1] == MBS_LB_RESET) {889 ql_log(ql_log_warn, vha, 0x7029,890 "MBX command error, Aborting ISP.\n");891 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);892 qla2xxx_wake_dpc(vha);893 qla2x00_wait_for_chip_reset(vha);894 /* Also reset the MPI */895 if (IS_QLA81XX(ha)) {896 if (qla81xx_restart_mpi_firmware(vha) !=897 QLA_SUCCESS) {898 ql_log(ql_log_warn, vha, 0x702a,899 "MPI reset failed.\n");900 }901 }902 903 rval = -EIO;904 goto done_free_dma_rsp;905 }906 907 if (new_config[0]) {908 int ret;909 910 /* Revert back to original port config911 * Also clear internal loopback912 */913 ret = qla81xx_reset_loopback_mode(vha,914 new_config, 0, 1);915 if (ret) {916 /*917 * If the reset of the loopback mode918 * doesn't work take FCoE dump and then919 * reset the chip.920 */921 qla2xxx_dump_fw(vha);922 set_bit(ISP_ABORT_NEEDED,923 &vha->dpc_flags);924 }925 926 }927 928 } else {929 type = "FC_BSG_HST_VENDOR_LOOPBACK";930 ql_dbg(ql_dbg_user, vha, 0x702b,931 "BSG request type: %s.\n", type);932 command_sent = INT_DEF_LB_LOOPBACK_CMD;933 rval = qla2x00_loopback_test(vha, &elreq, response);934 }935 }936 937 if (rval) {938 ql_log(ql_log_warn, vha, 0x702c,939 "Vendor request %s failed.\n", type);940 941 rval = 0;942 bsg_reply->result = (DID_ERROR << 16);943 bsg_reply->reply_payload_rcv_len = 0;944 } else {945 ql_dbg(ql_dbg_user, vha, 0x702d,946 "Vendor request %s completed.\n", type);947 bsg_reply->result = (DID_OK << 16);948 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,949 bsg_job->reply_payload.sg_cnt, rsp_data,950 rsp_data_len);951 }952 953 bsg_job->reply_len = sizeof(struct fc_bsg_reply) +954 sizeof(response) + sizeof(uint8_t);955 fw_sts_ptr = bsg_job->reply + sizeof(struct fc_bsg_reply);956 memcpy(bsg_job->reply + sizeof(struct fc_bsg_reply), response,957 sizeof(response));958 fw_sts_ptr += sizeof(response);959 *fw_sts_ptr = command_sent;960 961done_free_dma_rsp:962 dma_free_coherent(&ha->pdev->dev, rsp_data_len,963 rsp_data, rsp_data_dma);964done_free_dma_req:965 dma_free_coherent(&ha->pdev->dev, req_data_len,966 req_data, req_data_dma);967done_unmap_sg:968 dma_unmap_sg(&ha->pdev->dev,969 bsg_job->reply_payload.sg_list,970 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);971done_unmap_req_sg:972 dma_unmap_sg(&ha->pdev->dev,973 bsg_job->request_payload.sg_list,974 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);975 if (!rval)976 bsg_job_done(bsg_job, bsg_reply->result,977 bsg_reply->reply_payload_rcv_len);978 return rval;979}980 981static int982qla84xx_reset(struct bsg_job *bsg_job)983{984 struct fc_bsg_request *bsg_request = bsg_job->request;985 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);986 struct fc_bsg_reply *bsg_reply = bsg_job->reply;987 scsi_qla_host_t *vha = shost_priv(host);988 struct qla_hw_data *ha = vha->hw;989 int rval = 0;990 uint32_t flag;991 992 if (!IS_QLA84XX(ha)) {993 ql_dbg(ql_dbg_user, vha, 0x702f, "Not 84xx, exiting.\n");994 return -EINVAL;995 }996 997 flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1];998 999 rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW);1000 1001 if (rval) {1002 ql_log(ql_log_warn, vha, 0x7030,1003 "Vendor request 84xx reset failed.\n");1004 rval = (DID_ERROR << 16);1005 1006 } else {1007 ql_dbg(ql_dbg_user, vha, 0x7031,1008 "Vendor request 84xx reset completed.\n");1009 bsg_reply->result = DID_OK;1010 bsg_job_done(bsg_job, bsg_reply->result,1011 bsg_reply->reply_payload_rcv_len);1012 }1013 1014 return rval;1015}1016 1017static int1018qla84xx_updatefw(struct bsg_job *bsg_job)1019{1020 struct fc_bsg_request *bsg_request = bsg_job->request;1021 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1022 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1023 scsi_qla_host_t *vha = shost_priv(host);1024 struct qla_hw_data *ha = vha->hw;1025 struct verify_chip_entry_84xx *mn = NULL;1026 dma_addr_t mn_dma, fw_dma;1027 void *fw_buf = NULL;1028 int rval = 0;1029 uint32_t sg_cnt;1030 uint32_t data_len;1031 uint16_t options;1032 uint32_t flag;1033 uint32_t fw_ver;1034 1035 if (!IS_QLA84XX(ha)) {1036 ql_dbg(ql_dbg_user, vha, 0x7032,1037 "Not 84xx, exiting.\n");1038 return -EINVAL;1039 }1040 1041 sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,1042 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);1043 if (!sg_cnt) {1044 ql_log(ql_log_warn, vha, 0x7033,1045 "dma_map_sg returned %d for request.\n", sg_cnt);1046 return -ENOMEM;1047 }1048 1049 if (sg_cnt != bsg_job->request_payload.sg_cnt) {1050 ql_log(ql_log_warn, vha, 0x7034,1051 "DMA mapping resulted in different sg counts, "1052 "request_sg_cnt: %x dma_request_sg_cnt: %x.\n",1053 bsg_job->request_payload.sg_cnt, sg_cnt);1054 rval = -EAGAIN;1055 goto done_unmap_sg;1056 }1057 1058 data_len = bsg_job->request_payload.payload_len;1059 fw_buf = dma_alloc_coherent(&ha->pdev->dev, data_len,1060 &fw_dma, GFP_KERNEL);1061 if (!fw_buf) {1062 ql_log(ql_log_warn, vha, 0x7035,1063 "DMA alloc failed for fw_buf.\n");1064 rval = -ENOMEM;1065 goto done_unmap_sg;1066 }1067 1068 sg_copy_to_buffer(bsg_job->request_payload.sg_list,1069 bsg_job->request_payload.sg_cnt, fw_buf, data_len);1070 1071 mn = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);1072 if (!mn) {1073 ql_log(ql_log_warn, vha, 0x7036,1074 "DMA alloc failed for fw buffer.\n");1075 rval = -ENOMEM;1076 goto done_free_fw_buf;1077 }1078 1079 flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1];1080 fw_ver = get_unaligned_le32((uint32_t *)fw_buf + 2);1081 1082 mn->entry_type = VERIFY_CHIP_IOCB_TYPE;1083 mn->entry_count = 1;1084 1085 options = VCO_FORCE_UPDATE | VCO_END_OF_DATA;1086 if (flag == A84_ISSUE_UPDATE_DIAGFW_CMD)1087 options |= VCO_DIAG_FW;1088 1089 mn->options = cpu_to_le16(options);1090 mn->fw_ver = cpu_to_le32(fw_ver);1091 mn->fw_size = cpu_to_le32(data_len);1092 mn->fw_seq_size = cpu_to_le32(data_len);1093 put_unaligned_le64(fw_dma, &mn->dsd.address);1094 mn->dsd.length = cpu_to_le32(data_len);1095 mn->data_seg_cnt = cpu_to_le16(1);1096 1097 rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120);1098 1099 if (rval) {1100 ql_log(ql_log_warn, vha, 0x7037,1101 "Vendor request 84xx updatefw failed.\n");1102 1103 rval = (DID_ERROR << 16);1104 } else {1105 ql_dbg(ql_dbg_user, vha, 0x7038,1106 "Vendor request 84xx updatefw completed.\n");1107 1108 bsg_job->reply_len = sizeof(struct fc_bsg_reply);1109 bsg_reply->result = DID_OK;1110 }1111 1112 dma_pool_free(ha->s_dma_pool, mn, mn_dma);1113 1114done_free_fw_buf:1115 dma_free_coherent(&ha->pdev->dev, data_len, fw_buf, fw_dma);1116 1117done_unmap_sg:1118 dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,1119 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);1120 1121 if (!rval)1122 bsg_job_done(bsg_job, bsg_reply->result,1123 bsg_reply->reply_payload_rcv_len);1124 return rval;1125}1126 1127static int1128qla84xx_mgmt_cmd(struct bsg_job *bsg_job)1129{1130 struct fc_bsg_request *bsg_request = bsg_job->request;1131 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1132 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1133 scsi_qla_host_t *vha = shost_priv(host);1134 struct qla_hw_data *ha = vha->hw;1135 struct access_chip_84xx *mn = NULL;1136 dma_addr_t mn_dma, mgmt_dma;1137 void *mgmt_b = NULL;1138 int rval = 0;1139 struct qla_bsg_a84_mgmt *ql84_mgmt;1140 uint32_t sg_cnt;1141 uint32_t data_len = 0;1142 uint32_t dma_direction = DMA_NONE;1143 1144 if (!IS_QLA84XX(ha)) {1145 ql_log(ql_log_warn, vha, 0x703a,1146 "Not 84xx, exiting.\n");1147 return -EINVAL;1148 }1149 1150 mn = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);1151 if (!mn) {1152 ql_log(ql_log_warn, vha, 0x703c,1153 "DMA alloc failed for fw buffer.\n");1154 return -ENOMEM;1155 }1156 1157 mn->entry_type = ACCESS_CHIP_IOCB_TYPE;1158 mn->entry_count = 1;1159 ql84_mgmt = (void *)bsg_request + sizeof(struct fc_bsg_request);1160 switch (ql84_mgmt->mgmt.cmd) {1161 case QLA84_MGMT_READ_MEM:1162 case QLA84_MGMT_GET_INFO:1163 sg_cnt = dma_map_sg(&ha->pdev->dev,1164 bsg_job->reply_payload.sg_list,1165 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);1166 if (!sg_cnt) {1167 ql_log(ql_log_warn, vha, 0x703d,1168 "dma_map_sg returned %d for reply.\n", sg_cnt);1169 rval = -ENOMEM;1170 goto exit_mgmt;1171 }1172 1173 dma_direction = DMA_FROM_DEVICE;1174 1175 if (sg_cnt != bsg_job->reply_payload.sg_cnt) {1176 ql_log(ql_log_warn, vha, 0x703e,1177 "DMA mapping resulted in different sg counts, "1178 "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n",1179 bsg_job->reply_payload.sg_cnt, sg_cnt);1180 rval = -EAGAIN;1181 goto done_unmap_sg;1182 }1183 1184 data_len = bsg_job->reply_payload.payload_len;1185 1186 mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len,1187 &mgmt_dma, GFP_KERNEL);1188 if (!mgmt_b) {1189 ql_log(ql_log_warn, vha, 0x703f,1190 "DMA alloc failed for mgmt_b.\n");1191 rval = -ENOMEM;1192 goto done_unmap_sg;1193 }1194 1195 if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) {1196 mn->options = cpu_to_le16(ACO_DUMP_MEMORY);1197 mn->parameter1 =1198 cpu_to_le32(1199 ql84_mgmt->mgmt.mgmtp.u.mem.start_addr);1200 1201 } else if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO) {1202 mn->options = cpu_to_le16(ACO_REQUEST_INFO);1203 mn->parameter1 =1204 cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.info.type);1205 1206 mn->parameter2 =1207 cpu_to_le32(1208 ql84_mgmt->mgmt.mgmtp.u.info.context);1209 }1210 break;1211 1212 case QLA84_MGMT_WRITE_MEM:1213 sg_cnt = dma_map_sg(&ha->pdev->dev,1214 bsg_job->request_payload.sg_list,1215 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);1216 1217 if (!sg_cnt) {1218 ql_log(ql_log_warn, vha, 0x7040,1219 "dma_map_sg returned %d.\n", sg_cnt);1220 rval = -ENOMEM;1221 goto exit_mgmt;1222 }1223 1224 dma_direction = DMA_TO_DEVICE;1225 1226 if (sg_cnt != bsg_job->request_payload.sg_cnt) {1227 ql_log(ql_log_warn, vha, 0x7041,1228 "DMA mapping resulted in different sg counts, "1229 "request_sg_cnt: %x dma_request_sg_cnt: %x.\n",1230 bsg_job->request_payload.sg_cnt, sg_cnt);1231 rval = -EAGAIN;1232 goto done_unmap_sg;1233 }1234 1235 data_len = bsg_job->request_payload.payload_len;1236 mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len,1237 &mgmt_dma, GFP_KERNEL);1238 if (!mgmt_b) {1239 ql_log(ql_log_warn, vha, 0x7042,1240 "DMA alloc failed for mgmt_b.\n");1241 rval = -ENOMEM;1242 goto done_unmap_sg;1243 }1244 1245 sg_copy_to_buffer(bsg_job->request_payload.sg_list,1246 bsg_job->request_payload.sg_cnt, mgmt_b, data_len);1247 1248 mn->options = cpu_to_le16(ACO_LOAD_MEMORY);1249 mn->parameter1 =1250 cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.mem.start_addr);1251 break;1252 1253 case QLA84_MGMT_CHNG_CONFIG:1254 mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM);1255 mn->parameter1 =1256 cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.id);1257 1258 mn->parameter2 =1259 cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param0);1260 1261 mn->parameter3 =1262 cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param1);1263 break;1264 1265 default:1266 rval = -EIO;1267 goto exit_mgmt;1268 }1269 1270 if (ql84_mgmt->mgmt.cmd != QLA84_MGMT_CHNG_CONFIG) {1271 mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->mgmt.len);1272 mn->dseg_count = cpu_to_le16(1);1273 put_unaligned_le64(mgmt_dma, &mn->dsd.address);1274 mn->dsd.length = cpu_to_le32(ql84_mgmt->mgmt.len);1275 }1276 1277 rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0);1278 1279 if (rval) {1280 ql_log(ql_log_warn, vha, 0x7043,1281 "Vendor request 84xx mgmt failed.\n");1282 1283 rval = (DID_ERROR << 16);1284 1285 } else {1286 ql_dbg(ql_dbg_user, vha, 0x7044,1287 "Vendor request 84xx mgmt completed.\n");1288 1289 bsg_job->reply_len = sizeof(struct fc_bsg_reply);1290 bsg_reply->result = DID_OK;1291 1292 if ((ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) ||1293 (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO)) {1294 bsg_reply->reply_payload_rcv_len =1295 bsg_job->reply_payload.payload_len;1296 1297 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,1298 bsg_job->reply_payload.sg_cnt, mgmt_b,1299 data_len);1300 }1301 }1302 1303done_unmap_sg:1304 if (mgmt_b)1305 dma_free_coherent(&ha->pdev->dev, data_len, mgmt_b, mgmt_dma);1306 1307 if (dma_direction == DMA_TO_DEVICE)1308 dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,1309 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);1310 else if (dma_direction == DMA_FROM_DEVICE)1311 dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,1312 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);1313 1314exit_mgmt:1315 dma_pool_free(ha->s_dma_pool, mn, mn_dma);1316 1317 if (!rval)1318 bsg_job_done(bsg_job, bsg_reply->result,1319 bsg_reply->reply_payload_rcv_len);1320 return rval;1321}1322 1323static int1324qla24xx_iidma(struct bsg_job *bsg_job)1325{1326 struct fc_bsg_request *bsg_request = bsg_job->request;1327 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1328 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1329 scsi_qla_host_t *vha = shost_priv(host);1330 int rval = 0;1331 struct qla_port_param *port_param = NULL;1332 fc_port_t *fcport = NULL;1333 int found = 0;1334 uint16_t mb[MAILBOX_REGISTER_COUNT];1335 uint8_t *rsp_ptr = NULL;1336 1337 if (!IS_IIDMA_CAPABLE(vha->hw)) {1338 ql_log(ql_log_info, vha, 0x7046, "iiDMA not supported.\n");1339 return -EINVAL;1340 }1341 1342 port_param = (void *)bsg_request + sizeof(struct fc_bsg_request);1343 if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) {1344 ql_log(ql_log_warn, vha, 0x7048,1345 "Invalid destination type.\n");1346 return -EINVAL;1347 }1348 1349 list_for_each_entry(fcport, &vha->vp_fcports, list) {1350 if (fcport->port_type != FCT_TARGET)1351 continue;1352 1353 if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn,1354 fcport->port_name, sizeof(fcport->port_name)))1355 continue;1356 1357 found = 1;1358 break;1359 }1360 1361 if (!found) {1362 ql_log(ql_log_warn, vha, 0x7049,1363 "Failed to find port.\n");1364 return -EINVAL;1365 }1366 1367 if (atomic_read(&fcport->state) != FCS_ONLINE) {1368 ql_log(ql_log_warn, vha, 0x704a,1369 "Port is not online.\n");1370 return -EINVAL;1371 }1372 1373 if (fcport->flags & FCF_LOGIN_NEEDED) {1374 ql_log(ql_log_warn, vha, 0x704b,1375 "Remote port not logged in flags = 0x%x.\n", fcport->flags);1376 return -EINVAL;1377 }1378 1379 if (port_param->mode)1380 rval = qla2x00_set_idma_speed(vha, fcport->loop_id,1381 port_param->speed, mb);1382 else1383 rval = qla2x00_get_idma_speed(vha, fcport->loop_id,1384 &port_param->speed, mb);1385 1386 if (rval) {1387 ql_log(ql_log_warn, vha, 0x704c,1388 "iiDMA cmd failed for %8phN -- "1389 "%04x %x %04x %04x.\n", fcport->port_name,1390 rval, fcport->fp_speed, mb[0], mb[1]);1391 rval = (DID_ERROR << 16);1392 } else {1393 if (!port_param->mode) {1394 bsg_job->reply_len = sizeof(struct fc_bsg_reply) +1395 sizeof(struct qla_port_param);1396 1397 rsp_ptr = ((uint8_t *)bsg_reply) +1398 sizeof(struct fc_bsg_reply);1399 1400 memcpy(rsp_ptr, port_param,1401 sizeof(struct qla_port_param));1402 }1403 1404 bsg_reply->result = DID_OK;1405 bsg_job_done(bsg_job, bsg_reply->result,1406 bsg_reply->reply_payload_rcv_len);1407 }1408 1409 return rval;1410}1411 1412static int1413qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,1414 uint8_t is_update)1415{1416 struct fc_bsg_request *bsg_request = bsg_job->request;1417 uint32_t start = 0;1418 int valid = 0;1419 struct qla_hw_data *ha = vha->hw;1420 1421 if (unlikely(pci_channel_offline(ha->pdev)))1422 return -EINVAL;1423 1424 start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];1425 if (start > ha->optrom_size) {1426 ql_log(ql_log_warn, vha, 0x7055,1427 "start %d > optrom_size %d.\n", start, ha->optrom_size);1428 return -EINVAL;1429 }1430 1431 if (ha->optrom_state != QLA_SWAITING) {1432 ql_log(ql_log_info, vha, 0x7056,1433 "optrom_state %d.\n", ha->optrom_state);1434 return -EBUSY;1435 }1436 1437 ha->optrom_region_start = start;1438 ql_dbg(ql_dbg_user, vha, 0x7057, "is_update=%d.\n", is_update);1439 if (is_update) {1440 if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)1441 valid = 1;1442 else if (start == (ha->flt_region_boot * 4) ||1443 start == (ha->flt_region_fw * 4))1444 valid = 1;1445 else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||1446 IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||1447 IS_QLA28XX(ha))1448 valid = 1;1449 if (!valid) {1450 ql_log(ql_log_warn, vha, 0x7058,1451 "Invalid start region 0x%x/0x%x.\n", start,1452 bsg_job->request_payload.payload_len);1453 return -EINVAL;1454 }1455 1456 ha->optrom_region_size = start +1457 bsg_job->request_payload.payload_len > ha->optrom_size ?1458 ha->optrom_size - start :1459 bsg_job->request_payload.payload_len;1460 ha->optrom_state = QLA_SWRITING;1461 } else {1462 ha->optrom_region_size = start +1463 bsg_job->reply_payload.payload_len > ha->optrom_size ?1464 ha->optrom_size - start :1465 bsg_job->reply_payload.payload_len;1466 ha->optrom_state = QLA_SREADING;1467 }1468 1469 ha->optrom_buffer = vzalloc(ha->optrom_region_size);1470 if (!ha->optrom_buffer) {1471 ql_log(ql_log_warn, vha, 0x7059,1472 "Read: Unable to allocate memory for optrom retrieval "1473 "(%x)\n", ha->optrom_region_size);1474 1475 ha->optrom_state = QLA_SWAITING;1476 return -ENOMEM;1477 }1478 1479 return 0;1480}1481 1482static int1483qla2x00_read_optrom(struct bsg_job *bsg_job)1484{1485 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1486 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1487 scsi_qla_host_t *vha = shost_priv(host);1488 struct qla_hw_data *ha = vha->hw;1489 int rval = 0;1490 1491 if (ha->flags.nic_core_reset_hdlr_active)1492 return -EBUSY;1493 1494 mutex_lock(&ha->optrom_mutex);1495 rval = qla2x00_optrom_setup(bsg_job, vha, 0);1496 if (rval) {1497 mutex_unlock(&ha->optrom_mutex);1498 return rval;1499 }1500 1501 ha->isp_ops->read_optrom(vha, ha->optrom_buffer,1502 ha->optrom_region_start, ha->optrom_region_size);1503 1504 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,1505 bsg_job->reply_payload.sg_cnt, ha->optrom_buffer,1506 ha->optrom_region_size);1507 1508 bsg_reply->reply_payload_rcv_len = ha->optrom_region_size;1509 bsg_reply->result = DID_OK;1510 vfree(ha->optrom_buffer);1511 ha->optrom_buffer = NULL;1512 ha->optrom_state = QLA_SWAITING;1513 mutex_unlock(&ha->optrom_mutex);1514 bsg_job_done(bsg_job, bsg_reply->result,1515 bsg_reply->reply_payload_rcv_len);1516 return rval;1517}1518 1519static int1520qla2x00_update_optrom(struct bsg_job *bsg_job)1521{1522 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1523 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1524 scsi_qla_host_t *vha = shost_priv(host);1525 struct qla_hw_data *ha = vha->hw;1526 int rval = 0;1527 1528 mutex_lock(&ha->optrom_mutex);1529 rval = qla2x00_optrom_setup(bsg_job, vha, 1);1530 if (rval) {1531 mutex_unlock(&ha->optrom_mutex);1532 return rval;1533 }1534 1535 /* Set the isp82xx_no_md_cap not to capture minidump */1536 ha->flags.isp82xx_no_md_cap = 1;1537 1538 sg_copy_to_buffer(bsg_job->request_payload.sg_list,1539 bsg_job->request_payload.sg_cnt, ha->optrom_buffer,1540 ha->optrom_region_size);1541 1542 rval = ha->isp_ops->write_optrom(vha, ha->optrom_buffer,1543 ha->optrom_region_start, ha->optrom_region_size);1544 1545 if (rval) {1546 bsg_reply->result = -EINVAL;1547 rval = -EINVAL;1548 } else {1549 bsg_reply->result = DID_OK;1550 }1551 vfree(ha->optrom_buffer);1552 ha->optrom_buffer = NULL;1553 ha->optrom_state = QLA_SWAITING;1554 mutex_unlock(&ha->optrom_mutex);1555 bsg_job_done(bsg_job, bsg_reply->result,1556 bsg_reply->reply_payload_rcv_len);1557 return rval;1558}1559 1560static int1561qla2x00_update_fru_versions(struct bsg_job *bsg_job)1562{1563 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1564 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1565 scsi_qla_host_t *vha = shost_priv(host);1566 struct qla_hw_data *ha = vha->hw;1567 int rval = 0;1568 uint8_t bsg[DMA_POOL_SIZE];1569 struct qla_image_version_list *list = (void *)bsg;1570 struct qla_image_version *image;1571 uint32_t count;1572 dma_addr_t sfp_dma;1573 void *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);1574 1575 if (!sfp) {1576 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =1577 EXT_STATUS_NO_MEMORY;1578 goto done;1579 }1580 1581 sg_copy_to_buffer(bsg_job->request_payload.sg_list,1582 bsg_job->request_payload.sg_cnt, list, sizeof(bsg));1583 1584 image = list->version;1585 count = list->count;1586 while (count--) {1587 memcpy(sfp, &image->field_info, sizeof(image->field_info));1588 rval = qla2x00_write_sfp(vha, sfp_dma, sfp,1589 image->field_address.device, image->field_address.offset,1590 sizeof(image->field_info), image->field_address.option);1591 if (rval) {1592 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =1593 EXT_STATUS_MAILBOX;1594 goto dealloc;1595 }1596 image++;1597 }1598 1599 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0;1600 1601dealloc:1602 dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);1603 1604done:1605 bsg_job->reply_len = sizeof(struct fc_bsg_reply);1606 bsg_reply->result = DID_OK << 16;1607 bsg_job_done(bsg_job, bsg_reply->result,1608 bsg_reply->reply_payload_rcv_len);1609 1610 return 0;1611}1612 1613static int1614qla2x00_read_fru_status(struct bsg_job *bsg_job)1615{1616 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1617 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1618 scsi_qla_host_t *vha = shost_priv(host);1619 struct qla_hw_data *ha = vha->hw;1620 int rval = 0;1621 uint8_t bsg[DMA_POOL_SIZE];1622 struct qla_status_reg *sr = (void *)bsg;1623 dma_addr_t sfp_dma;1624 uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);1625 1626 if (!sfp) {1627 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =1628 EXT_STATUS_NO_MEMORY;1629 goto done;1630 }1631 1632 sg_copy_to_buffer(bsg_job->request_payload.sg_list,1633 bsg_job->request_payload.sg_cnt, sr, sizeof(*sr));1634 1635 rval = qla2x00_read_sfp(vha, sfp_dma, sfp,1636 sr->field_address.device, sr->field_address.offset,1637 sizeof(sr->status_reg), sr->field_address.option);1638 sr->status_reg = *sfp;1639 1640 if (rval) {1641 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =1642 EXT_STATUS_MAILBOX;1643 goto dealloc;1644 }1645 1646 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,1647 bsg_job->reply_payload.sg_cnt, sr, sizeof(*sr));1648 1649 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0;1650 1651dealloc:1652 dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);1653 1654done:1655 bsg_job->reply_len = sizeof(struct fc_bsg_reply);1656 bsg_reply->reply_payload_rcv_len = sizeof(*sr);1657 bsg_reply->result = DID_OK << 16;1658 bsg_job_done(bsg_job, bsg_reply->result,1659 bsg_reply->reply_payload_rcv_len);1660 1661 return 0;1662}1663 1664static int1665qla2x00_write_fru_status(struct bsg_job *bsg_job)1666{1667 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1668 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1669 scsi_qla_host_t *vha = shost_priv(host);1670 struct qla_hw_data *ha = vha->hw;1671 int rval = 0;1672 uint8_t bsg[DMA_POOL_SIZE];1673 struct qla_status_reg *sr = (void *)bsg;1674 dma_addr_t sfp_dma;1675 uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);1676 1677 if (!sfp) {1678 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =1679 EXT_STATUS_NO_MEMORY;1680 goto done;1681 }1682 1683 sg_copy_to_buffer(bsg_job->request_payload.sg_list,1684 bsg_job->request_payload.sg_cnt, sr, sizeof(*sr));1685 1686 *sfp = sr->status_reg;1687 rval = qla2x00_write_sfp(vha, sfp_dma, sfp,1688 sr->field_address.device, sr->field_address.offset,1689 sizeof(sr->status_reg), sr->field_address.option);1690 1691 if (rval) {1692 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =1693 EXT_STATUS_MAILBOX;1694 goto dealloc;1695 }1696 1697 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0;1698 1699dealloc:1700 dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);1701 1702done:1703 bsg_job->reply_len = sizeof(struct fc_bsg_reply);1704 bsg_reply->result = DID_OK << 16;1705 bsg_job_done(bsg_job, bsg_reply->result,1706 bsg_reply->reply_payload_rcv_len);1707 1708 return 0;1709}1710 1711static int1712qla2x00_write_i2c(struct bsg_job *bsg_job)1713{1714 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1715 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1716 scsi_qla_host_t *vha = shost_priv(host);1717 struct qla_hw_data *ha = vha->hw;1718 int rval = 0;1719 uint8_t bsg[DMA_POOL_SIZE];1720 struct qla_i2c_access *i2c = (void *)bsg;1721 dma_addr_t sfp_dma;1722 uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);1723 1724 if (!sfp) {1725 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =1726 EXT_STATUS_NO_MEMORY;1727 goto done;1728 }1729 1730 sg_copy_to_buffer(bsg_job->request_payload.sg_list,1731 bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c));1732 1733 memcpy(sfp, i2c->buffer, i2c->length);1734 rval = qla2x00_write_sfp(vha, sfp_dma, sfp,1735 i2c->device, i2c->offset, i2c->length, i2c->option);1736 1737 if (rval) {1738 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =1739 EXT_STATUS_MAILBOX;1740 goto dealloc;1741 }1742 1743 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0;1744 1745dealloc:1746 dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);1747 1748done:1749 bsg_job->reply_len = sizeof(struct fc_bsg_reply);1750 bsg_reply->result = DID_OK << 16;1751 bsg_job_done(bsg_job, bsg_reply->result,1752 bsg_reply->reply_payload_rcv_len);1753 1754 return 0;1755}1756 1757static int1758qla2x00_read_i2c(struct bsg_job *bsg_job)1759{1760 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1761 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1762 scsi_qla_host_t *vha = shost_priv(host);1763 struct qla_hw_data *ha = vha->hw;1764 int rval = 0;1765 uint8_t bsg[DMA_POOL_SIZE];1766 struct qla_i2c_access *i2c = (void *)bsg;1767 dma_addr_t sfp_dma;1768 uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);1769 1770 if (!sfp) {1771 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =1772 EXT_STATUS_NO_MEMORY;1773 goto done;1774 }1775 1776 sg_copy_to_buffer(bsg_job->request_payload.sg_list,1777 bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c));1778 1779 rval = qla2x00_read_sfp(vha, sfp_dma, sfp,1780 i2c->device, i2c->offset, i2c->length, i2c->option);1781 1782 if (rval) {1783 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =1784 EXT_STATUS_MAILBOX;1785 goto dealloc;1786 }1787 1788 memcpy(i2c->buffer, sfp, i2c->length);1789 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,1790 bsg_job->reply_payload.sg_cnt, i2c, sizeof(*i2c));1791 1792 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = 0;1793 1794dealloc:1795 dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);1796 1797done:1798 bsg_job->reply_len = sizeof(struct fc_bsg_reply);1799 bsg_reply->reply_payload_rcv_len = sizeof(*i2c);1800 bsg_reply->result = DID_OK << 16;1801 bsg_job_done(bsg_job, bsg_reply->result,1802 bsg_reply->reply_payload_rcv_len);1803 1804 return 0;1805}1806 1807static int1808qla24xx_process_bidir_cmd(struct bsg_job *bsg_job)1809{1810 struct fc_bsg_reply *bsg_reply = bsg_job->reply;1811 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1812 scsi_qla_host_t *vha = shost_priv(host);1813 struct qla_hw_data *ha = vha->hw;1814 uint32_t rval = EXT_STATUS_OK;1815 uint16_t req_sg_cnt = 0;1816 uint16_t rsp_sg_cnt = 0;1817 uint16_t nextlid = 0;1818 uint32_t tot_dsds;1819 srb_t *sp = NULL;1820 uint32_t req_data_len;1821 uint32_t rsp_data_len;1822 1823 /* Check the type of the adapter */1824 if (!IS_BIDI_CAPABLE(ha)) {1825 ql_log(ql_log_warn, vha, 0x70a0,1826 "This adapter is not supported\n");1827 rval = EXT_STATUS_NOT_SUPPORTED;1828 goto done;1829 }1830 1831 if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||1832 test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||1833 test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {1834 rval = EXT_STATUS_BUSY;1835 goto done;1836 }1837 1838 /* Check if host is online */1839 if (!vha->flags.online) {1840 ql_log(ql_log_warn, vha, 0x70a1,1841 "Host is not online\n");1842 rval = EXT_STATUS_DEVICE_OFFLINE;1843 goto done;1844 }1845 1846 /* Check if cable is plugged in or not */1847 if (vha->device_flags & DFLG_NO_CABLE) {1848 ql_log(ql_log_warn, vha, 0x70a2,1849 "Cable is unplugged...\n");1850 rval = EXT_STATUS_INVALID_CFG;1851 goto done;1852 }1853 1854 /* Check if the switch is connected or not */1855 if (ha->current_topology != ISP_CFG_F) {1856 ql_log(ql_log_warn, vha, 0x70a3,1857 "Host is not connected to the switch\n");1858 rval = EXT_STATUS_INVALID_CFG;1859 goto done;1860 }1861 1862 /* Check if operating mode is P2P */1863 if (ha->operating_mode != P2P) {1864 ql_log(ql_log_warn, vha, 0x70a4,1865 "Host operating mode is not P2p\n");1866 rval = EXT_STATUS_INVALID_CFG;1867 goto done;1868 }1869 1870 mutex_lock(&ha->selflogin_lock);1871 if (vha->self_login_loop_id == 0) {1872 /* Initialize all required fields of fcport */1873 vha->bidir_fcport.vha = vha;1874 vha->bidir_fcport.d_id.b.al_pa = vha->d_id.b.al_pa;1875 vha->bidir_fcport.d_id.b.area = vha->d_id.b.area;1876 vha->bidir_fcport.d_id.b.domain = vha->d_id.b.domain;1877 vha->bidir_fcport.loop_id = vha->loop_id;1878 1879 if (qla2x00_fabric_login(vha, &(vha->bidir_fcport), &nextlid)) {1880 ql_log(ql_log_warn, vha, 0x70a7,1881 "Failed to login port %06X for bidirectional IOCB\n",1882 vha->bidir_fcport.d_id.b24);1883 mutex_unlock(&ha->selflogin_lock);1884 rval = EXT_STATUS_MAILBOX;1885 goto done;1886 }1887 vha->self_login_loop_id = nextlid - 1;1888 1889 }1890 /* Assign the self login loop id to fcport */1891 mutex_unlock(&ha->selflogin_lock);1892 1893 vha->bidir_fcport.loop_id = vha->self_login_loop_id;1894 1895 req_sg_cnt = dma_map_sg(&ha->pdev->dev,1896 bsg_job->request_payload.sg_list,1897 bsg_job->request_payload.sg_cnt,1898 DMA_TO_DEVICE);1899 1900 if (!req_sg_cnt) {1901 rval = EXT_STATUS_NO_MEMORY;1902 goto done;1903 }1904 1905 rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,1906 bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt,1907 DMA_FROM_DEVICE);1908 1909 if (!rsp_sg_cnt) {1910 rval = EXT_STATUS_NO_MEMORY;1911 goto done_unmap_req_sg;1912 }1913 1914 if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) ||1915 (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {1916 ql_dbg(ql_dbg_user, vha, 0x70a9,1917 "Dma mapping resulted in different sg counts "1918 "[request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt: "1919 "%x dma_reply_sg_cnt: %x]\n",1920 bsg_job->request_payload.sg_cnt, req_sg_cnt,1921 bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);1922 rval = EXT_STATUS_NO_MEMORY;1923 goto done_unmap_sg;1924 }1925 1926 req_data_len = bsg_job->request_payload.payload_len;1927 rsp_data_len = bsg_job->reply_payload.payload_len;1928 1929 if (req_data_len != rsp_data_len) {1930 rval = EXT_STATUS_BUSY;1931 ql_log(ql_log_warn, vha, 0x70aa,1932 "req_data_len != rsp_data_len\n");1933 goto done_unmap_sg;1934 }1935 1936 /* Alloc SRB structure */1937 sp = qla2x00_get_sp(vha, &(vha->bidir_fcport), GFP_KERNEL);1938 if (!sp) {1939 ql_dbg(ql_dbg_user, vha, 0x70ac,1940 "Alloc SRB structure failed\n");1941 rval = EXT_STATUS_NO_MEMORY;1942 goto done_unmap_sg;1943 }1944 1945 /*Populate srb->ctx with bidir ctx*/1946 sp->u.bsg_job = bsg_job;1947 sp->free = qla2x00_bsg_sp_free;1948 sp->type = SRB_BIDI_CMD;1949 sp->done = qla2x00_bsg_job_done;1950 1951 /* Add the read and write sg count */1952 tot_dsds = rsp_sg_cnt + req_sg_cnt;1953 1954 rval = qla2x00_start_bidir(sp, vha, tot_dsds);1955 if (rval != EXT_STATUS_OK)1956 goto done_free_srb;1957 /* the bsg request will be completed in the interrupt handler */1958 return rval;1959 1960done_free_srb:1961 mempool_free(sp, ha->srb_mempool);1962done_unmap_sg:1963 dma_unmap_sg(&ha->pdev->dev,1964 bsg_job->reply_payload.sg_list,1965 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);1966done_unmap_req_sg:1967 dma_unmap_sg(&ha->pdev->dev,1968 bsg_job->request_payload.sg_list,1969 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);1970done:1971 1972 /* Return an error vendor specific response1973 * and complete the bsg request1974 */1975 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;1976 bsg_job->reply_len = sizeof(struct fc_bsg_reply);1977 bsg_reply->reply_payload_rcv_len = 0;1978 bsg_reply->result = (DID_OK) << 16;1979 bsg_job_done(bsg_job, bsg_reply->result,1980 bsg_reply->reply_payload_rcv_len);1981 /* Always return success, vendor rsp carries correct status */1982 return 0;1983}1984 1985static int1986qlafx00_mgmt_cmd(struct bsg_job *bsg_job)1987{1988 struct fc_bsg_request *bsg_request = bsg_job->request;1989 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);1990 scsi_qla_host_t *vha = shost_priv(host);1991 struct qla_hw_data *ha = vha->hw;1992 int rval = (DID_ERROR << 16);1993 struct qla_mt_iocb_rqst_fx00 *piocb_rqst;1994 srb_t *sp;1995 int req_sg_cnt = 0, rsp_sg_cnt = 0;1996 struct fc_port *fcport;1997 char *type = "FC_BSG_HST_FX_MGMT";1998 1999 /* Copy the IOCB specific information */2000 piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)2001 &bsg_request->rqst_data.h_vendor.vendor_cmd[1];2002 2003 /* Dump the vendor information */2004 ql_dump_buffer(ql_dbg_user + ql_dbg_verbose , vha, 0x70cf,2005 piocb_rqst, sizeof(*piocb_rqst));2006 2007 if (!vha->flags.online) {2008 ql_log(ql_log_warn, vha, 0x70d0,2009 "Host is not online.\n");2010 rval = -EIO;2011 goto done;2012 }2013 2014 if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) {2015 req_sg_cnt = dma_map_sg(&ha->pdev->dev,2016 bsg_job->request_payload.sg_list,2017 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);2018 if (!req_sg_cnt) {2019 ql_log(ql_log_warn, vha, 0x70c7,2020 "dma_map_sg return %d for request\n", req_sg_cnt);2021 rval = -ENOMEM;2022 goto done;2023 }2024 }2025 2026 if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) {2027 rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,2028 bsg_job->reply_payload.sg_list,2029 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);2030 if (!rsp_sg_cnt) {2031 ql_log(ql_log_warn, vha, 0x70c8,2032 "dma_map_sg return %d for reply\n", rsp_sg_cnt);2033 rval = -ENOMEM;2034 goto done_unmap_req_sg;2035 }2036 }2037 2038 ql_dbg(ql_dbg_user, vha, 0x70c9,2039 "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x "2040 "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt,2041 req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);2042 2043 /* Allocate a dummy fcport structure, since functions preparing the2044 * IOCB and mailbox command retrieves port specific information2045 * from fcport structure. For Host based ELS commands there will be2046 * no fcport structure allocated2047 */2048 fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);2049 if (!fcport) {2050 ql_log(ql_log_warn, vha, 0x70ca,2051 "Failed to allocate fcport.\n");2052 rval = -ENOMEM;2053 goto done_unmap_rsp_sg;2054 }2055 2056 /* Alloc SRB structure */2057 sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);2058 if (!sp) {2059 ql_log(ql_log_warn, vha, 0x70cb,2060 "qla2x00_get_sp failed.\n");2061 rval = -ENOMEM;2062 goto done_free_fcport;2063 }2064 2065 /* Initialize all required fields of fcport */2066 fcport->vha = vha;2067 fcport->loop_id = le32_to_cpu(piocb_rqst->dataword);2068 2069 sp->type = SRB_FXIOCB_BCMD;2070 sp->name = "bsg_fx_mgmt";2071 sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt);2072 sp->u.bsg_job = bsg_job;2073 sp->free = qla2x00_bsg_sp_free;2074 sp->done = qla2x00_bsg_job_done;2075 2076 ql_dbg(ql_dbg_user, vha, 0x70cc,2077 "bsg rqst type: %s fx_mgmt_type: %x id=%x\n",2078 type, piocb_rqst->func_type, fcport->loop_id);2079 2080 rval = qla2x00_start_sp(sp);2081 if (rval != QLA_SUCCESS) {2082 ql_log(ql_log_warn, vha, 0x70cd,2083 "qla2x00_start_sp failed=%d.\n", rval);2084 mempool_free(sp, ha->srb_mempool);2085 rval = -EIO;2086 goto done_free_fcport;2087 }2088 return rval;2089 2090done_free_fcport:2091 qla2x00_free_fcport(fcport);2092 2093done_unmap_rsp_sg:2094 if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)2095 dma_unmap_sg(&ha->pdev->dev,2096 bsg_job->reply_payload.sg_list,2097 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);2098done_unmap_req_sg:2099 if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID)2100 dma_unmap_sg(&ha->pdev->dev,2101 bsg_job->request_payload.sg_list,2102 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);2103 2104done:2105 return rval;2106}2107 2108static int2109qla26xx_serdes_op(struct bsg_job *bsg_job)2110{2111 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2112 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);2113 scsi_qla_host_t *vha = shost_priv(host);2114 int rval = 0;2115 struct qla_serdes_reg sr;2116 2117 memset(&sr, 0, sizeof(sr));2118 2119 sg_copy_to_buffer(bsg_job->request_payload.sg_list,2120 bsg_job->request_payload.sg_cnt, &sr, sizeof(sr));2121 2122 switch (sr.cmd) {2123 case INT_SC_SERDES_WRITE_REG:2124 rval = qla2x00_write_serdes_word(vha, sr.addr, sr.val);2125 bsg_reply->reply_payload_rcv_len = 0;2126 break;2127 case INT_SC_SERDES_READ_REG:2128 rval = qla2x00_read_serdes_word(vha, sr.addr, &sr.val);2129 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2130 bsg_job->reply_payload.sg_cnt, &sr, sizeof(sr));2131 bsg_reply->reply_payload_rcv_len = sizeof(sr);2132 break;2133 default:2134 ql_dbg(ql_dbg_user, vha, 0x708c,2135 "Unknown serdes cmd %x.\n", sr.cmd);2136 rval = -EINVAL;2137 break;2138 }2139 2140 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2141 rval ? EXT_STATUS_MAILBOX : 0;2142 2143 bsg_job->reply_len = sizeof(struct fc_bsg_reply);2144 bsg_reply->result = DID_OK << 16;2145 bsg_job_done(bsg_job, bsg_reply->result,2146 bsg_reply->reply_payload_rcv_len);2147 return 0;2148}2149 2150static int2151qla8044_serdes_op(struct bsg_job *bsg_job)2152{2153 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2154 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);2155 scsi_qla_host_t *vha = shost_priv(host);2156 int rval = 0;2157 struct qla_serdes_reg_ex sr;2158 2159 memset(&sr, 0, sizeof(sr));2160 2161 sg_copy_to_buffer(bsg_job->request_payload.sg_list,2162 bsg_job->request_payload.sg_cnt, &sr, sizeof(sr));2163 2164 switch (sr.cmd) {2165 case INT_SC_SERDES_WRITE_REG:2166 rval = qla8044_write_serdes_word(vha, sr.addr, sr.val);2167 bsg_reply->reply_payload_rcv_len = 0;2168 break;2169 case INT_SC_SERDES_READ_REG:2170 rval = qla8044_read_serdes_word(vha, sr.addr, &sr.val);2171 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2172 bsg_job->reply_payload.sg_cnt, &sr, sizeof(sr));2173 bsg_reply->reply_payload_rcv_len = sizeof(sr);2174 break;2175 default:2176 ql_dbg(ql_dbg_user, vha, 0x7020,2177 "Unknown serdes cmd %x.\n", sr.cmd);2178 rval = -EINVAL;2179 break;2180 }2181 2182 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2183 rval ? EXT_STATUS_MAILBOX : 0;2184 2185 bsg_job->reply_len = sizeof(struct fc_bsg_reply);2186 bsg_reply->result = DID_OK << 16;2187 bsg_job_done(bsg_job, bsg_reply->result,2188 bsg_reply->reply_payload_rcv_len);2189 return 0;2190}2191 2192static int2193qla27xx_get_flash_upd_cap(struct bsg_job *bsg_job)2194{2195 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2196 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);2197 scsi_qla_host_t *vha = shost_priv(host);2198 struct qla_hw_data *ha = vha->hw;2199 struct qla_flash_update_caps cap;2200 2201 if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha))2202 return -EPERM;2203 2204 memset(&cap, 0, sizeof(cap));2205 cap.capabilities = (uint64_t)ha->fw_attributes_ext[1] << 48 |2206 (uint64_t)ha->fw_attributes_ext[0] << 32 |2207 (uint64_t)ha->fw_attributes_h << 16 |2208 (uint64_t)ha->fw_attributes;2209 2210 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2211 bsg_job->reply_payload.sg_cnt, &cap, sizeof(cap));2212 bsg_reply->reply_payload_rcv_len = sizeof(cap);2213 2214 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2215 EXT_STATUS_OK;2216 2217 bsg_job->reply_len = sizeof(struct fc_bsg_reply);2218 bsg_reply->result = DID_OK << 16;2219 bsg_job_done(bsg_job, bsg_reply->result,2220 bsg_reply->reply_payload_rcv_len);2221 return 0;2222}2223 2224static int2225qla27xx_set_flash_upd_cap(struct bsg_job *bsg_job)2226{2227 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2228 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);2229 scsi_qla_host_t *vha = shost_priv(host);2230 struct qla_hw_data *ha = vha->hw;2231 uint64_t online_fw_attr = 0;2232 struct qla_flash_update_caps cap;2233 2234 if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))2235 return -EPERM;2236 2237 memset(&cap, 0, sizeof(cap));2238 sg_copy_to_buffer(bsg_job->request_payload.sg_list,2239 bsg_job->request_payload.sg_cnt, &cap, sizeof(cap));2240 2241 online_fw_attr = (uint64_t)ha->fw_attributes_ext[1] << 48 |2242 (uint64_t)ha->fw_attributes_ext[0] << 32 |2243 (uint64_t)ha->fw_attributes_h << 16 |2244 (uint64_t)ha->fw_attributes;2245 2246 if (online_fw_attr != cap.capabilities) {2247 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2248 EXT_STATUS_INVALID_PARAM;2249 return -EINVAL;2250 }2251 2252 if (cap.outage_duration < MAX_LOOP_TIMEOUT) {2253 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2254 EXT_STATUS_INVALID_PARAM;2255 return -EINVAL;2256 }2257 2258 bsg_reply->reply_payload_rcv_len = 0;2259 2260 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2261 EXT_STATUS_OK;2262 2263 bsg_job->reply_len = sizeof(struct fc_bsg_reply);2264 bsg_reply->result = DID_OK << 16;2265 bsg_job_done(bsg_job, bsg_reply->result,2266 bsg_reply->reply_payload_rcv_len);2267 return 0;2268}2269 2270static int2271qla27xx_get_bbcr_data(struct bsg_job *bsg_job)2272{2273 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2274 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);2275 scsi_qla_host_t *vha = shost_priv(host);2276 struct qla_hw_data *ha = vha->hw;2277 struct qla_bbcr_data bbcr;2278 uint16_t loop_id, topo, sw_cap;2279 uint8_t domain, area, al_pa, state;2280 int rval;2281 2282 if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))2283 return -EPERM;2284 2285 memset(&bbcr, 0, sizeof(bbcr));2286 2287 if (vha->flags.bbcr_enable)2288 bbcr.status = QLA_BBCR_STATUS_ENABLED;2289 else2290 bbcr.status = QLA_BBCR_STATUS_DISABLED;2291 2292 if (bbcr.status == QLA_BBCR_STATUS_ENABLED) {2293 rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa,2294 &area, &domain, &topo, &sw_cap);2295 if (rval != QLA_SUCCESS) {2296 bbcr.status = QLA_BBCR_STATUS_UNKNOWN;2297 bbcr.state = QLA_BBCR_STATE_OFFLINE;2298 bbcr.mbx1 = loop_id;2299 goto done;2300 }2301 2302 state = (vha->bbcr >> 12) & 0x1;2303 2304 if (state) {2305 bbcr.state = QLA_BBCR_STATE_OFFLINE;2306 bbcr.offline_reason_code = QLA_BBCR_REASON_LOGIN_REJECT;2307 } else {2308 bbcr.state = QLA_BBCR_STATE_ONLINE;2309 bbcr.negotiated_bbscn = (vha->bbcr >> 8) & 0xf;2310 }2311 2312 bbcr.configured_bbscn = vha->bbcr & 0xf;2313 }2314 2315done:2316 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2317 bsg_job->reply_payload.sg_cnt, &bbcr, sizeof(bbcr));2318 bsg_reply->reply_payload_rcv_len = sizeof(bbcr);2319 2320 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;2321 2322 bsg_job->reply_len = sizeof(struct fc_bsg_reply);2323 bsg_reply->result = DID_OK << 16;2324 bsg_job_done(bsg_job, bsg_reply->result,2325 bsg_reply->reply_payload_rcv_len);2326 return 0;2327}2328 2329static int2330qla2x00_get_priv_stats(struct bsg_job *bsg_job)2331{2332 struct fc_bsg_request *bsg_request = bsg_job->request;2333 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2334 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);2335 scsi_qla_host_t *vha = shost_priv(host);2336 struct qla_hw_data *ha = vha->hw;2337 struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);2338 struct link_statistics *stats = NULL;2339 dma_addr_t stats_dma;2340 int rval;2341 uint32_t *cmd = bsg_request->rqst_data.h_vendor.vendor_cmd;2342 uint options = cmd[0] == QL_VND_GET_PRIV_STATS_EX ? cmd[1] : 0;2343 2344 if (test_bit(UNLOADING, &vha->dpc_flags))2345 return -ENODEV;2346 2347 if (unlikely(pci_channel_offline(ha->pdev)))2348 return -ENODEV;2349 2350 if (qla2x00_reset_active(vha))2351 return -EBUSY;2352 2353 if (!IS_FWI2_CAPABLE(ha))2354 return -EPERM;2355 2356 stats = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stats), &stats_dma,2357 GFP_KERNEL);2358 if (!stats) {2359 ql_log(ql_log_warn, vha, 0x70e2,2360 "Failed to allocate memory for stats.\n");2361 return -ENOMEM;2362 }2363 2364 rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, options);2365 2366 if (rval == QLA_SUCCESS) {2367 ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e5,2368 stats, sizeof(*stats));2369 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2370 bsg_job->reply_payload.sg_cnt, stats, sizeof(*stats));2371 }2372 2373 bsg_reply->reply_payload_rcv_len = sizeof(*stats);2374 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2375 rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK;2376 2377 bsg_job->reply_len = sizeof(*bsg_reply);2378 bsg_reply->result = DID_OK << 16;2379 bsg_job_done(bsg_job, bsg_reply->result,2380 bsg_reply->reply_payload_rcv_len);2381 2382 dma_free_coherent(&ha->pdev->dev, sizeof(*stats),2383 stats, stats_dma);2384 2385 return 0;2386}2387 2388static int2389qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)2390{2391 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2392 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);2393 scsi_qla_host_t *vha = shost_priv(host);2394 int rval;2395 struct qla_dport_diag *dd;2396 2397 if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&2398 !IS_QLA28XX(vha->hw))2399 return -EPERM;2400 2401 dd = kmalloc(sizeof(*dd), GFP_KERNEL);2402 if (!dd) {2403 ql_log(ql_log_warn, vha, 0x70db,2404 "Failed to allocate memory for dport.\n");2405 return -ENOMEM;2406 }2407 2408 sg_copy_to_buffer(bsg_job->request_payload.sg_list,2409 bsg_job->request_payload.sg_cnt, dd, sizeof(*dd));2410 2411 rval = qla26xx_dport_diagnostics(2412 vha, dd->buf, sizeof(dd->buf), dd->options);2413 if (rval == QLA_SUCCESS) {2414 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2415 bsg_job->reply_payload.sg_cnt, dd, sizeof(*dd));2416 }2417 2418 bsg_reply->reply_payload_rcv_len = sizeof(*dd);2419 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2420 rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK;2421 2422 bsg_job->reply_len = sizeof(*bsg_reply);2423 bsg_reply->result = DID_OK << 16;2424 bsg_job_done(bsg_job, bsg_reply->result,2425 bsg_reply->reply_payload_rcv_len);2426 2427 kfree(dd);2428 2429 return 0;2430}2431 2432static int2433qla2x00_do_dport_diagnostics_v2(struct bsg_job *bsg_job)2434{2435 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2436 struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);2437 scsi_qla_host_t *vha = shost_priv(host);2438 int rval;2439 struct qla_dport_diag_v2 *dd;2440 mbx_cmd_t mc;2441 mbx_cmd_t *mcp = &mc;2442 uint16_t options;2443 2444 if (!IS_DPORT_CAPABLE(vha->hw))2445 return -EPERM;2446 2447 dd = kzalloc(sizeof(*dd), GFP_KERNEL);2448 if (!dd)2449 return -ENOMEM;2450 2451 sg_copy_to_buffer(bsg_job->request_payload.sg_list,2452 bsg_job->request_payload.sg_cnt, dd, sizeof(*dd));2453 2454 options = dd->options;2455 2456 /* Check dport Test in progress */2457 if (options == QLA_GET_DPORT_RESULT_V2 &&2458 vha->dport_status & DPORT_DIAG_IN_PROGRESS) {2459 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2460 EXT_STATUS_DPORT_DIAG_IN_PROCESS;2461 goto dportcomplete;2462 }2463 2464 /* Check chip reset in progress and start/restart requests arrive */2465 if (vha->dport_status & DPORT_DIAG_CHIP_RESET_IN_PROGRESS &&2466 (options == QLA_START_DPORT_TEST_V2 ||2467 options == QLA_RESTART_DPORT_TEST_V2)) {2468 vha->dport_status &= ~DPORT_DIAG_CHIP_RESET_IN_PROGRESS;2469 }2470 2471 /* Check chip reset in progress and get result request arrive */2472 if (vha->dport_status & DPORT_DIAG_CHIP_RESET_IN_PROGRESS &&2473 options == QLA_GET_DPORT_RESULT_V2) {2474 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2475 EXT_STATUS_DPORT_DIAG_NOT_RUNNING;2476 goto dportcomplete;2477 }2478 2479 rval = qla26xx_dport_diagnostics_v2(vha, dd, mcp);2480 2481 if (rval == QLA_SUCCESS) {2482 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2483 EXT_STATUS_OK;2484 if (options == QLA_START_DPORT_TEST_V2 ||2485 options == QLA_RESTART_DPORT_TEST_V2) {2486 dd->mbx1 = mcp->mb[0];2487 dd->mbx2 = mcp->mb[1];2488 vha->dport_status |= DPORT_DIAG_IN_PROGRESS;2489 } else if (options == QLA_GET_DPORT_RESULT_V2) {2490 dd->mbx1 = le16_to_cpu(vha->dport_data[1]);2491 dd->mbx2 = le16_to_cpu(vha->dport_data[2]);2492 }2493 } else {2494 dd->mbx1 = mcp->mb[0];2495 dd->mbx2 = mcp->mb[1];2496 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =2497 EXT_STATUS_DPORT_DIAG_ERR;2498 }2499 2500dportcomplete:2501 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2502 bsg_job->reply_payload.sg_cnt, dd, sizeof(*dd));2503 2504 bsg_reply->reply_payload_rcv_len = sizeof(*dd);2505 bsg_job->reply_len = sizeof(*bsg_reply);2506 bsg_reply->result = DID_OK << 16;2507 bsg_job_done(bsg_job, bsg_reply->result,2508 bsg_reply->reply_payload_rcv_len);2509 2510 kfree(dd);2511 2512 return 0;2513}2514 2515static int2516qla2x00_get_flash_image_status(struct bsg_job *bsg_job)2517{2518 scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));2519 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2520 struct qla_hw_data *ha = vha->hw;2521 struct qla_active_regions regions = { };2522 struct active_regions active_regions = { };2523 2524 qla27xx_get_active_image(vha, &active_regions);2525 regions.global_image = active_regions.global;2526 2527 if (IS_QLA27XX(ha))2528 regions.nvme_params = QLA27XX_PRIMARY_IMAGE;2529 2530 if (IS_QLA28XX(ha)) {2531 qla28xx_get_aux_images(vha, &active_regions);2532 regions.board_config = active_regions.aux.board_config;2533 regions.vpd_nvram = active_regions.aux.vpd_nvram;2534 regions.npiv_config_0_1 = active_regions.aux.npiv_config_0_1;2535 regions.npiv_config_2_3 = active_regions.aux.npiv_config_2_3;2536 regions.nvme_params = active_regions.aux.nvme_params;2537 }2538 2539 ql_dbg(ql_dbg_user, vha, 0x70e1,2540 "%s(%lu): FW=%u BCFG=%u VPDNVR=%u NPIV01=%u NPIV02=%u NVME_PARAMS=%u\n",2541 __func__, vha->host_no, regions.global_image,2542 regions.board_config, regions.vpd_nvram,2543 regions.npiv_config_0_1, regions.npiv_config_2_3, regions.nvme_params);2544 2545 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2546 bsg_job->reply_payload.sg_cnt, ®ions, sizeof(regions));2547 2548 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;2549 bsg_reply->reply_payload_rcv_len = sizeof(regions);2550 bsg_reply->result = DID_OK << 16;2551 bsg_job->reply_len = sizeof(struct fc_bsg_reply);2552 bsg_job_done(bsg_job, bsg_reply->result,2553 bsg_reply->reply_payload_rcv_len);2554 2555 return 0;2556}2557 2558static int2559qla2x00_manage_host_stats(struct bsg_job *bsg_job)2560{2561 scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));2562 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2563 struct ql_vnd_mng_host_stats_param *req_data;2564 struct ql_vnd_mng_host_stats_resp rsp_data;2565 u32 req_data_len;2566 int ret = 0;2567 2568 if (!vha->flags.online) {2569 ql_log(ql_log_warn, vha, 0x0000, "Host is not online.\n");2570 return -EIO;2571 }2572 2573 req_data_len = bsg_job->request_payload.payload_len;2574 2575 if (req_data_len != sizeof(struct ql_vnd_mng_host_stats_param)) {2576 ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");2577 return -EIO;2578 }2579 2580 req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);2581 if (!req_data) {2582 ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n");2583 return -ENOMEM;2584 }2585 2586 /* Copy the request buffer in req_data */2587 sg_copy_to_buffer(bsg_job->request_payload.sg_list,2588 bsg_job->request_payload.sg_cnt, req_data,2589 req_data_len);2590 2591 switch (req_data->action) {2592 case QLA_STOP:2593 ret = qla2xxx_stop_stats(vha->host, req_data->stat_type);2594 break;2595 case QLA_START:2596 ret = qla2xxx_start_stats(vha->host, req_data->stat_type);2597 break;2598 case QLA_CLEAR:2599 ret = qla2xxx_reset_stats(vha->host, req_data->stat_type);2600 break;2601 default:2602 ql_log(ql_log_warn, vha, 0x0000, "Invalid action.\n");2603 ret = -EIO;2604 break;2605 }2606 2607 kfree(req_data);2608 2609 /* Prepare response */2610 rsp_data.status = ret;2611 bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_stats_resp);2612 2613 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;2614 bsg_reply->reply_payload_rcv_len =2615 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2616 bsg_job->reply_payload.sg_cnt,2617 &rsp_data,2618 sizeof(struct ql_vnd_mng_host_stats_resp));2619 2620 bsg_reply->result = DID_OK;2621 bsg_job_done(bsg_job, bsg_reply->result,2622 bsg_reply->reply_payload_rcv_len);2623 2624 return ret;2625}2626 2627static int2628qla2x00_get_host_stats(struct bsg_job *bsg_job)2629{2630 scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));2631 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2632 struct ql_vnd_stats_param *req_data;2633 struct ql_vnd_host_stats_resp rsp_data;2634 u32 req_data_len;2635 int ret = 0;2636 u64 ini_entry_count = 0;2637 u64 entry_count = 0;2638 u64 tgt_num = 0;2639 u64 tmp_stat_type = 0;2640 u64 response_len = 0;2641 void *data;2642 2643 req_data_len = bsg_job->request_payload.payload_len;2644 2645 if (req_data_len != sizeof(struct ql_vnd_stats_param)) {2646 ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");2647 return -EIO;2648 }2649 2650 req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);2651 if (!req_data) {2652 ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n");2653 return -ENOMEM;2654 }2655 2656 /* Copy the request buffer in req_data */2657 sg_copy_to_buffer(bsg_job->request_payload.sg_list,2658 bsg_job->request_payload.sg_cnt, req_data, req_data_len);2659 2660 /* Copy stat type to work on it */2661 tmp_stat_type = req_data->stat_type;2662 2663 if (tmp_stat_type & QLA2XX_TGT_SHT_LNK_DOWN) {2664 /* Num of tgts connected to this host */2665 tgt_num = qla2x00_get_num_tgts(vha);2666 /* unset BIT_17 */2667 tmp_stat_type &= ~(1 << 17);2668 }2669 2670 /* Total ini stats */2671 ini_entry_count = qla2x00_count_set_bits(tmp_stat_type);2672 2673 /* Total number of entries */2674 entry_count = ini_entry_count + tgt_num;2675 2676 response_len = sizeof(struct ql_vnd_host_stats_resp) +2677 (sizeof(struct ql_vnd_stat_entry) * entry_count);2678 2679 if (response_len > bsg_job->reply_payload.payload_len) {2680 rsp_data.status = EXT_STATUS_BUFFER_TOO_SMALL;2681 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_BUFFER_TOO_SMALL;2682 bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_stats_resp);2683 2684 bsg_reply->reply_payload_rcv_len =2685 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2686 bsg_job->reply_payload.sg_cnt, &rsp_data,2687 sizeof(struct ql_vnd_mng_host_stats_resp));2688 2689 bsg_reply->result = DID_OK;2690 bsg_job_done(bsg_job, bsg_reply->result,2691 bsg_reply->reply_payload_rcv_len);2692 goto host_stat_out;2693 }2694 2695 data = kzalloc(response_len, GFP_KERNEL);2696 if (!data) {2697 ret = -ENOMEM;2698 goto host_stat_out;2699 }2700 2701 ret = qla2xxx_get_ini_stats(fc_bsg_to_shost(bsg_job), req_data->stat_type,2702 data, response_len);2703 2704 rsp_data.status = EXT_STATUS_OK;2705 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;2706 2707 bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2708 bsg_job->reply_payload.sg_cnt,2709 data, response_len);2710 bsg_reply->result = DID_OK;2711 bsg_job_done(bsg_job, bsg_reply->result,2712 bsg_reply->reply_payload_rcv_len);2713 2714 kfree(data);2715host_stat_out:2716 kfree(req_data);2717 return ret;2718}2719 2720static struct fc_rport *2721qla2xxx_find_rport(scsi_qla_host_t *vha, uint32_t tgt_num)2722{2723 fc_port_t *fcport = NULL;2724 2725 list_for_each_entry(fcport, &vha->vp_fcports, list) {2726 if (fcport->rport->number == tgt_num)2727 return fcport->rport;2728 }2729 return NULL;2730}2731 2732static int2733qla2x00_get_tgt_stats(struct bsg_job *bsg_job)2734{2735 scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));2736 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2737 struct ql_vnd_tgt_stats_param *req_data;2738 u32 req_data_len;2739 int ret = 0;2740 u64 response_len = 0;2741 struct ql_vnd_tgt_stats_resp *data = NULL;2742 struct fc_rport *rport = NULL;2743 2744 if (!vha->flags.online) {2745 ql_log(ql_log_warn, vha, 0x0000, "Host is not online.\n");2746 return -EIO;2747 }2748 2749 req_data_len = bsg_job->request_payload.payload_len;2750 2751 if (req_data_len != sizeof(struct ql_vnd_stat_entry)) {2752 ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");2753 return -EIO;2754 }2755 2756 req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);2757 if (!req_data) {2758 ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n");2759 return -ENOMEM;2760 }2761 2762 /* Copy the request buffer in req_data */2763 sg_copy_to_buffer(bsg_job->request_payload.sg_list,2764 bsg_job->request_payload.sg_cnt,2765 req_data, req_data_len);2766 2767 response_len = sizeof(struct ql_vnd_tgt_stats_resp) +2768 sizeof(struct ql_vnd_stat_entry);2769 2770 /* structure + size for one entry */2771 data = kzalloc(response_len, GFP_KERNEL);2772 if (!data) {2773 kfree(req_data);2774 return -ENOMEM;2775 }2776 2777 if (response_len > bsg_job->reply_payload.payload_len) {2778 data->status = EXT_STATUS_BUFFER_TOO_SMALL;2779 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_BUFFER_TOO_SMALL;2780 bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_stats_resp);2781 2782 bsg_reply->reply_payload_rcv_len =2783 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2784 bsg_job->reply_payload.sg_cnt, data,2785 sizeof(struct ql_vnd_tgt_stats_resp));2786 2787 bsg_reply->result = DID_OK;2788 bsg_job_done(bsg_job, bsg_reply->result,2789 bsg_reply->reply_payload_rcv_len);2790 goto tgt_stat_out;2791 }2792 2793 rport = qla2xxx_find_rport(vha, req_data->tgt_id);2794 if (!rport) {2795 ql_log(ql_log_warn, vha, 0x0000, "target %d not found.\n", req_data->tgt_id);2796 ret = EXT_STATUS_INVALID_PARAM;2797 data->status = EXT_STATUS_INVALID_PARAM;2798 goto reply;2799 }2800 2801 ret = qla2xxx_get_tgt_stats(fc_bsg_to_shost(bsg_job), req_data->stat_type,2802 rport, (void *)data, response_len);2803 2804 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;2805reply:2806 bsg_reply->reply_payload_rcv_len =2807 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2808 bsg_job->reply_payload.sg_cnt, data,2809 response_len);2810 bsg_reply->result = DID_OK;2811 bsg_job_done(bsg_job, bsg_reply->result,2812 bsg_reply->reply_payload_rcv_len);2813 2814tgt_stat_out:2815 kfree(data);2816 kfree(req_data);2817 2818 return ret;2819}2820 2821static int2822qla2x00_manage_host_port(struct bsg_job *bsg_job)2823{2824 scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));2825 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2826 struct ql_vnd_mng_host_port_param *req_data;2827 struct ql_vnd_mng_host_port_resp rsp_data;2828 u32 req_data_len;2829 int ret = 0;2830 2831 req_data_len = bsg_job->request_payload.payload_len;2832 2833 if (req_data_len != sizeof(struct ql_vnd_mng_host_port_param)) {2834 ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");2835 return -EIO;2836 }2837 2838 req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);2839 if (!req_data) {2840 ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n");2841 return -ENOMEM;2842 }2843 2844 /* Copy the request buffer in req_data */2845 sg_copy_to_buffer(bsg_job->request_payload.sg_list,2846 bsg_job->request_payload.sg_cnt, req_data, req_data_len);2847 2848 switch (req_data->action) {2849 case QLA_ENABLE:2850 ret = qla2xxx_enable_port(vha->host);2851 break;2852 case QLA_DISABLE:2853 ret = qla2xxx_disable_port(vha->host);2854 break;2855 default:2856 ql_log(ql_log_warn, vha, 0x0000, "Invalid action.\n");2857 ret = -EIO;2858 break;2859 }2860 2861 kfree(req_data);2862 2863 /* Prepare response */2864 rsp_data.status = ret;2865 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;2866 bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_port_resp);2867 2868 bsg_reply->reply_payload_rcv_len =2869 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,2870 bsg_job->reply_payload.sg_cnt, &rsp_data,2871 sizeof(struct ql_vnd_mng_host_port_resp));2872 bsg_reply->result = DID_OK;2873 bsg_job_done(bsg_job, bsg_reply->result,2874 bsg_reply->reply_payload_rcv_len);2875 2876 return ret;2877}2878 2879static int2880qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_job)2881{2882 struct fc_bsg_request *bsg_request = bsg_job->request;2883 2884 ql_dbg(ql_dbg_edif, vha, 0x911b, "%s FC_BSG_HST_VENDOR cmd[0]=0x%x\n",2885 __func__, bsg_request->rqst_data.h_vendor.vendor_cmd[0]);2886 2887 switch (bsg_request->rqst_data.h_vendor.vendor_cmd[0]) {2888 case QL_VND_LOOPBACK:2889 return qla2x00_process_loopback(bsg_job);2890 2891 case QL_VND_A84_RESET:2892 return qla84xx_reset(bsg_job);2893 2894 case QL_VND_A84_UPDATE_FW:2895 return qla84xx_updatefw(bsg_job);2896 2897 case QL_VND_A84_MGMT_CMD:2898 return qla84xx_mgmt_cmd(bsg_job);2899 2900 case QL_VND_IIDMA:2901 return qla24xx_iidma(bsg_job);2902 2903 case QL_VND_FCP_PRIO_CFG_CMD:2904 return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job);2905 2906 case QL_VND_READ_FLASH:2907 return qla2x00_read_optrom(bsg_job);2908 2909 case QL_VND_UPDATE_FLASH:2910 return qla2x00_update_optrom(bsg_job);2911 2912 case QL_VND_SET_FRU_VERSION:2913 return qla2x00_update_fru_versions(bsg_job);2914 2915 case QL_VND_READ_FRU_STATUS:2916 return qla2x00_read_fru_status(bsg_job);2917 2918 case QL_VND_WRITE_FRU_STATUS:2919 return qla2x00_write_fru_status(bsg_job);2920 2921 case QL_VND_WRITE_I2C:2922 return qla2x00_write_i2c(bsg_job);2923 2924 case QL_VND_READ_I2C:2925 return qla2x00_read_i2c(bsg_job);2926 2927 case QL_VND_DIAG_IO_CMD:2928 return qla24xx_process_bidir_cmd(bsg_job);2929 2930 case QL_VND_FX00_MGMT_CMD:2931 return qlafx00_mgmt_cmd(bsg_job);2932 2933 case QL_VND_SERDES_OP:2934 return qla26xx_serdes_op(bsg_job);2935 2936 case QL_VND_SERDES_OP_EX:2937 return qla8044_serdes_op(bsg_job);2938 2939 case QL_VND_GET_FLASH_UPDATE_CAPS:2940 return qla27xx_get_flash_upd_cap(bsg_job);2941 2942 case QL_VND_SET_FLASH_UPDATE_CAPS:2943 return qla27xx_set_flash_upd_cap(bsg_job);2944 2945 case QL_VND_GET_BBCR_DATA:2946 return qla27xx_get_bbcr_data(bsg_job);2947 2948 case QL_VND_GET_PRIV_STATS:2949 case QL_VND_GET_PRIV_STATS_EX:2950 return qla2x00_get_priv_stats(bsg_job);2951 2952 case QL_VND_DPORT_DIAGNOSTICS:2953 return qla2x00_do_dport_diagnostics(bsg_job);2954 2955 case QL_VND_DPORT_DIAGNOSTICS_V2:2956 return qla2x00_do_dport_diagnostics_v2(bsg_job);2957 2958 case QL_VND_EDIF_MGMT:2959 return qla_edif_app_mgmt(bsg_job);2960 2961 case QL_VND_SS_GET_FLASH_IMAGE_STATUS:2962 return qla2x00_get_flash_image_status(bsg_job);2963 2964 case QL_VND_MANAGE_HOST_STATS:2965 return qla2x00_manage_host_stats(bsg_job);2966 2967 case QL_VND_GET_HOST_STATS:2968 return qla2x00_get_host_stats(bsg_job);2969 2970 case QL_VND_GET_TGT_STATS:2971 return qla2x00_get_tgt_stats(bsg_job);2972 2973 case QL_VND_MANAGE_HOST_PORT:2974 return qla2x00_manage_host_port(bsg_job);2975 2976 case QL_VND_MBX_PASSTHRU:2977 return qla2x00_mailbox_passthru(bsg_job);2978 2979 default:2980 return -ENOSYS;2981 }2982}2983 2984int2985qla24xx_bsg_request(struct bsg_job *bsg_job)2986{2987 struct fc_bsg_request *bsg_request = bsg_job->request;2988 struct fc_bsg_reply *bsg_reply = bsg_job->reply;2989 int ret = -EINVAL;2990 struct fc_rport *rport;2991 struct Scsi_Host *host;2992 scsi_qla_host_t *vha;2993 2994 /* In case no data transferred. */2995 bsg_reply->reply_payload_rcv_len = 0;2996 2997 if (bsg_request->msgcode == FC_BSG_RPT_ELS) {2998 rport = fc_bsg_to_rport(bsg_job);2999 if (!rport)3000 return ret;3001 host = rport_to_shost(rport);3002 vha = shost_priv(host);3003 } else {3004 host = fc_bsg_to_shost(bsg_job);3005 vha = shost_priv(host);3006 }3007 3008 /* Disable port will bring down the chip, allow enable command */3009 if (bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_MANAGE_HOST_PORT ||3010 bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_GET_HOST_STATS)3011 goto skip_chip_chk;3012 3013 if (vha->hw->flags.port_isolated) {3014 bsg_reply->result = DID_ERROR;3015 /* operation not permitted */3016 return -EPERM;3017 }3018 3019 if (qla2x00_chip_is_down(vha)) {3020 ql_dbg(ql_dbg_user, vha, 0x709f,3021 "BSG: ISP abort active/needed -- cmd=%d.\n",3022 bsg_request->msgcode);3023 SET_DID_STATUS(bsg_reply->result, DID_ERROR);3024 return -EBUSY;3025 }3026 3027 if (test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags)) {3028 SET_DID_STATUS(bsg_reply->result, DID_ERROR);3029 return -EIO;3030 }3031 3032skip_chip_chk:3033 ql_dbg(ql_dbg_user + ql_dbg_verbose, vha, 0x7000,3034 "Entered %s msgcode=0x%x. bsg ptr %px\n",3035 __func__, bsg_request->msgcode, bsg_job);3036 3037 switch (bsg_request->msgcode) {3038 case FC_BSG_RPT_ELS:3039 case FC_BSG_HST_ELS_NOLOGIN:3040 ret = qla2x00_process_els(bsg_job);3041 break;3042 case FC_BSG_HST_CT:3043 ret = qla2x00_process_ct(bsg_job);3044 break;3045 case FC_BSG_HST_VENDOR:3046 ret = qla2x00_process_vendor_specific(vha, bsg_job);3047 break;3048 case FC_BSG_HST_ADD_RPORT:3049 case FC_BSG_HST_DEL_RPORT:3050 case FC_BSG_RPT_CT:3051 default:3052 ql_log(ql_log_warn, vha, 0x705a, "Unsupported BSG request.\n");3053 break;3054 }3055 3056 ql_dbg(ql_dbg_user + ql_dbg_verbose, vha, 0x7000,3057 "%s done with return %x\n", __func__, ret);3058 3059 return ret;3060}3061 3062static bool qla_bsg_found(struct qla_qpair *qpair, struct bsg_job *bsg_job)3063{3064 bool found = false;3065 struct fc_bsg_reply *bsg_reply = bsg_job->reply;3066 scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));3067 struct qla_hw_data *ha = vha->hw;3068 srb_t *sp = NULL;3069 int cnt;3070 unsigned long flags;3071 struct req_que *req;3072 3073 spin_lock_irqsave(qpair->qp_lock_ptr, flags);3074 req = qpair->req;3075 3076 for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {3077 sp = req->outstanding_cmds[cnt];3078 if (sp &&3079 (sp->type == SRB_CT_CMD ||3080 sp->type == SRB_ELS_CMD_HST ||3081 sp->type == SRB_ELS_CMD_HST_NOLOGIN) &&3082 sp->u.bsg_job == bsg_job) {3083 req->outstanding_cmds[cnt] = NULL;3084 spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);3085 3086 if (!ha->flags.eeh_busy && ha->isp_ops->abort_command(sp)) {3087 ql_log(ql_log_warn, vha, 0x7089,3088 "mbx abort_command failed.\n");3089 bsg_reply->result = -EIO;3090 } else {3091 ql_dbg(ql_dbg_user, vha, 0x708a,3092 "mbx abort_command success.\n");3093 bsg_reply->result = 0;3094 }3095 /* ref: INIT */3096 kref_put(&sp->cmd_kref, qla2x00_sp_release);3097 3098 found = true;3099 goto done;3100 }3101 }3102 spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);3103 3104done:3105 return found;3106}3107 3108int3109qla24xx_bsg_timeout(struct bsg_job *bsg_job)3110{3111 struct fc_bsg_reply *bsg_reply = bsg_job->reply;3112 scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));3113 struct qla_hw_data *ha = vha->hw;3114 int i;3115 struct qla_qpair *qpair;3116 3117 ql_log(ql_log_info, vha, 0x708b, "%s CMD timeout. bsg ptr %p.\n",3118 __func__, bsg_job);3119 3120 if (qla2x00_isp_reg_stat(ha)) {3121 ql_log(ql_log_info, vha, 0x9007,3122 "PCI/Register disconnect.\n");3123 qla_pci_set_eeh_busy(vha);3124 }3125 3126 if (qla_bsg_found(ha->base_qpair, bsg_job))3127 goto done;3128 3129 /* find the bsg job from the active list of commands */3130 for (i = 0; i < ha->max_qpairs; i++) {3131 qpair = vha->hw->queue_pair_map[i];3132 if (!qpair)3133 continue;3134 if (qla_bsg_found(qpair, bsg_job))3135 goto done;3136 }3137 3138 ql_log(ql_log_info, vha, 0x708b, "SRB not found to abort.\n");3139 bsg_reply->result = -ENXIO;3140 3141done:3142 return 0;3143}3144 3145int qla2x00_mailbox_passthru(struct bsg_job *bsg_job)3146{3147 struct fc_bsg_reply *bsg_reply = bsg_job->reply;3148 scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));3149 int ret = -EINVAL;3150 int ptsize = sizeof(struct qla_mbx_passthru);3151 struct qla_mbx_passthru *req_data = NULL;3152 uint32_t req_data_len;3153 3154 req_data_len = bsg_job->request_payload.payload_len;3155 if (req_data_len != ptsize) {3156 ql_log(ql_log_warn, vha, 0xf0a3, "req_data_len invalid.\n");3157 return -EIO;3158 }3159 req_data = kzalloc(ptsize, GFP_KERNEL);3160 if (!req_data) {3161 ql_log(ql_log_warn, vha, 0xf0a4,3162 "req_data memory allocation failure.\n");3163 return -ENOMEM;3164 }3165 3166 /* Copy the request buffer in req_data */3167 sg_copy_to_buffer(bsg_job->request_payload.sg_list,3168 bsg_job->request_payload.sg_cnt, req_data, ptsize);3169 ret = qla_mailbox_passthru(vha, req_data->mbx_in, req_data->mbx_out);3170 3171 /* Copy the req_data in request buffer */3172 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,3173 bsg_job->reply_payload.sg_cnt, req_data, ptsize);3174 3175 bsg_reply->reply_payload_rcv_len = ptsize;3176 if (ret == QLA_SUCCESS)3177 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;3178 else3179 bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_ERR;3180 3181 bsg_job->reply_len = sizeof(*bsg_job->reply);3182 bsg_reply->result = DID_OK << 16;3183 bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len);3184 3185 kfree(req_data);3186 3187 return ret;3188}3189