873 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * QLogic iSCSI HBA Driver4 * Copyright (c) 2011-2013 QLogic Corporation5 */6 7#include "ql4_def.h"8#include "ql4_glbl.h"9#include "ql4_bsg.h"10 11static int12qla4xxx_read_flash(struct bsg_job *bsg_job)13{14 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);15 struct scsi_qla_host *ha = to_qla_host(host);16 struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;17 struct iscsi_bsg_request *bsg_req = bsg_job->request;18 uint32_t offset = 0;19 uint32_t length = 0;20 dma_addr_t flash_dma;21 uint8_t *flash = NULL;22 int rval = -EINVAL;23 24 bsg_reply->reply_payload_rcv_len = 0;25 26 if (unlikely(pci_channel_offline(ha->pdev)))27 goto leave;28 29 if (ql4xxx_reset_active(ha)) {30 ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);31 rval = -EBUSY;32 goto leave;33 }34 35 if (ha->flash_state != QLFLASH_WAITING) {36 ql4_printk(KERN_ERR, ha, "%s: another flash operation "37 "active\n", __func__);38 rval = -EBUSY;39 goto leave;40 }41 42 ha->flash_state = QLFLASH_READING;43 offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];44 length = bsg_job->reply_payload.payload_len;45 46 flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma,47 GFP_KERNEL);48 if (!flash) {49 ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash "50 "data\n", __func__);51 rval = -ENOMEM;52 goto leave;53 }54 55 rval = qla4xxx_get_flash(ha, flash_dma, offset, length);56 if (rval) {57 ql4_printk(KERN_ERR, ha, "%s: get flash failed\n", __func__);58 bsg_reply->result = DID_ERROR << 16;59 rval = -EIO;60 } else {61 bsg_reply->reply_payload_rcv_len =62 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,63 bsg_job->reply_payload.sg_cnt,64 flash, length);65 bsg_reply->result = DID_OK << 16;66 }67 68 bsg_job_done(bsg_job, bsg_reply->result,69 bsg_reply->reply_payload_rcv_len);70 dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma);71leave:72 ha->flash_state = QLFLASH_WAITING;73 return rval;74}75 76static int77qla4xxx_update_flash(struct bsg_job *bsg_job)78{79 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);80 struct scsi_qla_host *ha = to_qla_host(host);81 struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;82 struct iscsi_bsg_request *bsg_req = bsg_job->request;83 uint32_t length = 0;84 uint32_t offset = 0;85 uint32_t options = 0;86 dma_addr_t flash_dma;87 uint8_t *flash = NULL;88 int rval = -EINVAL;89 90 bsg_reply->reply_payload_rcv_len = 0;91 92 if (unlikely(pci_channel_offline(ha->pdev)))93 goto leave;94 95 if (ql4xxx_reset_active(ha)) {96 ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);97 rval = -EBUSY;98 goto leave;99 }100 101 if (ha->flash_state != QLFLASH_WAITING) {102 ql4_printk(KERN_ERR, ha, "%s: another flash operation "103 "active\n", __func__);104 rval = -EBUSY;105 goto leave;106 }107 108 ha->flash_state = QLFLASH_WRITING;109 length = bsg_job->request_payload.payload_len;110 offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];111 options = bsg_req->rqst_data.h_vendor.vendor_cmd[2];112 113 flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma,114 GFP_KERNEL);115 if (!flash) {116 ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash "117 "data\n", __func__);118 rval = -ENOMEM;119 goto leave;120 }121 122 sg_copy_to_buffer(bsg_job->request_payload.sg_list,123 bsg_job->request_payload.sg_cnt, flash, length);124 125 rval = qla4xxx_set_flash(ha, flash_dma, offset, length, options);126 if (rval) {127 ql4_printk(KERN_ERR, ha, "%s: set flash failed\n", __func__);128 bsg_reply->result = DID_ERROR << 16;129 rval = -EIO;130 } else131 bsg_reply->result = DID_OK << 16;132 133 bsg_job_done(bsg_job, bsg_reply->result,134 bsg_reply->reply_payload_rcv_len);135 dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma);136leave:137 ha->flash_state = QLFLASH_WAITING;138 return rval;139}140 141static int142qla4xxx_get_acb_state(struct bsg_job *bsg_job)143{144 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);145 struct scsi_qla_host *ha = to_qla_host(host);146 struct iscsi_bsg_request *bsg_req = bsg_job->request;147 struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;148 uint32_t status[MBOX_REG_COUNT];149 uint32_t acb_idx;150 uint32_t ip_idx;151 int rval = -EINVAL;152 153 bsg_reply->reply_payload_rcv_len = 0;154 155 if (unlikely(pci_channel_offline(ha->pdev)))156 goto leave;157 158 /* Only 4022 and above adapters are supported */159 if (is_qla4010(ha))160 goto leave;161 162 if (ql4xxx_reset_active(ha)) {163 ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);164 rval = -EBUSY;165 goto leave;166 }167 168 if (bsg_job->reply_payload.payload_len < sizeof(status)) {169 ql4_printk(KERN_ERR, ha, "%s: invalid payload len %d\n",170 __func__, bsg_job->reply_payload.payload_len);171 rval = -EINVAL;172 goto leave;173 }174 175 acb_idx = bsg_req->rqst_data.h_vendor.vendor_cmd[1];176 ip_idx = bsg_req->rqst_data.h_vendor.vendor_cmd[2];177 178 rval = qla4xxx_get_ip_state(ha, acb_idx, ip_idx, status);179 if (rval) {180 ql4_printk(KERN_ERR, ha, "%s: get ip state failed\n",181 __func__);182 bsg_reply->result = DID_ERROR << 16;183 rval = -EIO;184 } else {185 bsg_reply->reply_payload_rcv_len =186 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,187 bsg_job->reply_payload.sg_cnt,188 status, sizeof(status));189 bsg_reply->result = DID_OK << 16;190 }191 192 bsg_job_done(bsg_job, bsg_reply->result,193 bsg_reply->reply_payload_rcv_len);194leave:195 return rval;196}197 198static int199qla4xxx_read_nvram(struct bsg_job *bsg_job)200{201 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);202 struct scsi_qla_host *ha = to_qla_host(host);203 struct iscsi_bsg_request *bsg_req = bsg_job->request;204 struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;205 uint32_t offset = 0;206 uint32_t len = 0;207 uint32_t total_len = 0;208 dma_addr_t nvram_dma;209 uint8_t *nvram = NULL;210 int rval = -EINVAL;211 212 bsg_reply->reply_payload_rcv_len = 0;213 214 if (unlikely(pci_channel_offline(ha->pdev)))215 goto leave;216 217 /* Only 40xx adapters are supported */218 if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha)))219 goto leave;220 221 if (ql4xxx_reset_active(ha)) {222 ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);223 rval = -EBUSY;224 goto leave;225 }226 227 offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];228 len = bsg_job->reply_payload.payload_len;229 total_len = offset + len;230 231 /* total len should not be greater than max NVRAM size */232 if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) ||233 ((is_qla4022(ha) || is_qla4032(ha)) &&234 total_len > QL40X2_NVRAM_SIZE)) {235 ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max"236 " nvram size, offset=%d len=%d\n",237 __func__, offset, len);238 goto leave;239 }240 241 nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma,242 GFP_KERNEL);243 if (!nvram) {244 ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for nvram "245 "data\n", __func__);246 rval = -ENOMEM;247 goto leave;248 }249 250 rval = qla4xxx_get_nvram(ha, nvram_dma, offset, len);251 if (rval) {252 ql4_printk(KERN_ERR, ha, "%s: get nvram failed\n", __func__);253 bsg_reply->result = DID_ERROR << 16;254 rval = -EIO;255 } else {256 bsg_reply->reply_payload_rcv_len =257 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,258 bsg_job->reply_payload.sg_cnt,259 nvram, len);260 bsg_reply->result = DID_OK << 16;261 }262 263 bsg_job_done(bsg_job, bsg_reply->result,264 bsg_reply->reply_payload_rcv_len);265 dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma);266leave:267 return rval;268}269 270static int271qla4xxx_update_nvram(struct bsg_job *bsg_job)272{273 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);274 struct scsi_qla_host *ha = to_qla_host(host);275 struct iscsi_bsg_request *bsg_req = bsg_job->request;276 struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;277 uint32_t offset = 0;278 uint32_t len = 0;279 uint32_t total_len = 0;280 dma_addr_t nvram_dma;281 uint8_t *nvram = NULL;282 int rval = -EINVAL;283 284 bsg_reply->reply_payload_rcv_len = 0;285 286 if (unlikely(pci_channel_offline(ha->pdev)))287 goto leave;288 289 if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha)))290 goto leave;291 292 if (ql4xxx_reset_active(ha)) {293 ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);294 rval = -EBUSY;295 goto leave;296 }297 298 offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];299 len = bsg_job->request_payload.payload_len;300 total_len = offset + len;301 302 /* total len should not be greater than max NVRAM size */303 if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) ||304 ((is_qla4022(ha) || is_qla4032(ha)) &&305 total_len > QL40X2_NVRAM_SIZE)) {306 ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max"307 " nvram size, offset=%d len=%d\n",308 __func__, offset, len);309 goto leave;310 }311 312 nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma,313 GFP_KERNEL);314 if (!nvram) {315 ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash "316 "data\n", __func__);317 rval = -ENOMEM;318 goto leave;319 }320 321 sg_copy_to_buffer(bsg_job->request_payload.sg_list,322 bsg_job->request_payload.sg_cnt, nvram, len);323 324 rval = qla4xxx_set_nvram(ha, nvram_dma, offset, len);325 if (rval) {326 ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__);327 bsg_reply->result = DID_ERROR << 16;328 rval = -EIO;329 } else330 bsg_reply->result = DID_OK << 16;331 332 bsg_job_done(bsg_job, bsg_reply->result,333 bsg_reply->reply_payload_rcv_len);334 dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma);335leave:336 return rval;337}338 339static int340qla4xxx_restore_defaults(struct bsg_job *bsg_job)341{342 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);343 struct scsi_qla_host *ha = to_qla_host(host);344 struct iscsi_bsg_request *bsg_req = bsg_job->request;345 struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;346 uint32_t region = 0;347 uint32_t field0 = 0;348 uint32_t field1 = 0;349 int rval = -EINVAL;350 351 bsg_reply->reply_payload_rcv_len = 0;352 353 if (unlikely(pci_channel_offline(ha->pdev)))354 goto leave;355 356 if (is_qla4010(ha))357 goto leave;358 359 if (ql4xxx_reset_active(ha)) {360 ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);361 rval = -EBUSY;362 goto leave;363 }364 365 region = bsg_req->rqst_data.h_vendor.vendor_cmd[1];366 field0 = bsg_req->rqst_data.h_vendor.vendor_cmd[2];367 field1 = bsg_req->rqst_data.h_vendor.vendor_cmd[3];368 369 rval = qla4xxx_restore_factory_defaults(ha, region, field0, field1);370 if (rval) {371 ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__);372 bsg_reply->result = DID_ERROR << 16;373 rval = -EIO;374 } else375 bsg_reply->result = DID_OK << 16;376 377 bsg_job_done(bsg_job, bsg_reply->result,378 bsg_reply->reply_payload_rcv_len);379leave:380 return rval;381}382 383static int384qla4xxx_bsg_get_acb(struct bsg_job *bsg_job)385{386 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);387 struct scsi_qla_host *ha = to_qla_host(host);388 struct iscsi_bsg_request *bsg_req = bsg_job->request;389 struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;390 uint32_t acb_type = 0;391 uint32_t len = 0;392 dma_addr_t acb_dma;393 uint8_t *acb = NULL;394 int rval = -EINVAL;395 396 bsg_reply->reply_payload_rcv_len = 0;397 398 if (unlikely(pci_channel_offline(ha->pdev)))399 goto leave;400 401 /* Only 4022 and above adapters are supported */402 if (is_qla4010(ha))403 goto leave;404 405 if (ql4xxx_reset_active(ha)) {406 ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);407 rval = -EBUSY;408 goto leave;409 }410 411 acb_type = bsg_req->rqst_data.h_vendor.vendor_cmd[1];412 len = bsg_job->reply_payload.payload_len;413 if (len < sizeof(struct addr_ctrl_blk)) {414 ql4_printk(KERN_ERR, ha, "%s: invalid acb len %d\n",415 __func__, len);416 rval = -EINVAL;417 goto leave;418 }419 420 acb = dma_alloc_coherent(&ha->pdev->dev, len, &acb_dma, GFP_KERNEL);421 if (!acb) {422 ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for acb "423 "data\n", __func__);424 rval = -ENOMEM;425 goto leave;426 }427 428 rval = qla4xxx_get_acb(ha, acb_dma, acb_type, len);429 if (rval) {430 ql4_printk(KERN_ERR, ha, "%s: get acb failed\n", __func__);431 bsg_reply->result = DID_ERROR << 16;432 rval = -EIO;433 } else {434 bsg_reply->reply_payload_rcv_len =435 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,436 bsg_job->reply_payload.sg_cnt,437 acb, len);438 bsg_reply->result = DID_OK << 16;439 }440 441 bsg_job_done(bsg_job, bsg_reply->result,442 bsg_reply->reply_payload_rcv_len);443 dma_free_coherent(&ha->pdev->dev, len, acb, acb_dma);444leave:445 return rval;446}447 448static void ql4xxx_execute_diag_cmd(struct bsg_job *bsg_job)449{450 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);451 struct scsi_qla_host *ha = to_qla_host(host);452 struct iscsi_bsg_request *bsg_req = bsg_job->request;453 struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;454 uint8_t *rsp_ptr = NULL;455 uint32_t mbox_cmd[MBOX_REG_COUNT];456 uint32_t mbox_sts[MBOX_REG_COUNT];457 int status = QLA_ERROR;458 459 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__));460 461 if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) {462 ql4_printk(KERN_INFO, ha, "%s: Adapter reset in progress. Invalid Request\n",463 __func__);464 bsg_reply->result = DID_ERROR << 16;465 goto exit_diag_mem_test;466 }467 468 bsg_reply->reply_payload_rcv_len = 0;469 memcpy(mbox_cmd, &bsg_req->rqst_data.h_vendor.vendor_cmd[1],470 sizeof(uint32_t) * MBOX_REG_COUNT);471 472 DEBUG2(ql4_printk(KERN_INFO, ha,473 "%s: mbox_cmd: %08X %08X %08X %08X %08X %08X %08X %08X\n",474 __func__, mbox_cmd[0], mbox_cmd[1], mbox_cmd[2],475 mbox_cmd[3], mbox_cmd[4], mbox_cmd[5], mbox_cmd[6],476 mbox_cmd[7]));477 478 status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0],479 &mbox_sts[0]);480 481 DEBUG2(ql4_printk(KERN_INFO, ha,482 "%s: mbox_sts: %08X %08X %08X %08X %08X %08X %08X %08X\n",483 __func__, mbox_sts[0], mbox_sts[1], mbox_sts[2],484 mbox_sts[3], mbox_sts[4], mbox_sts[5], mbox_sts[6],485 mbox_sts[7]));486 487 if (status == QLA_SUCCESS)488 bsg_reply->result = DID_OK << 16;489 else490 bsg_reply->result = DID_ERROR << 16;491 492 /* Send mbox_sts to application */493 bsg_job->reply_len = sizeof(struct iscsi_bsg_reply) + sizeof(mbox_sts);494 rsp_ptr = ((uint8_t *)bsg_reply) + sizeof(struct iscsi_bsg_reply);495 memcpy(rsp_ptr, mbox_sts, sizeof(mbox_sts));496 497exit_diag_mem_test:498 DEBUG2(ql4_printk(KERN_INFO, ha,499 "%s: bsg_reply->result = x%x, status = %s\n",500 __func__, bsg_reply->result, STATUS(status)));501 502 bsg_job_done(bsg_job, bsg_reply->result,503 bsg_reply->reply_payload_rcv_len);504}505 506static int qla4_83xx_wait_for_loopback_config_comp(struct scsi_qla_host *ha,507 int wait_for_link)508{509 int status = QLA_SUCCESS;510 511 if (!wait_for_completion_timeout(&ha->idc_comp, (IDC_COMP_TOV * HZ))) {512 ql4_printk(KERN_INFO, ha, "%s: IDC Complete notification not received, Waiting for another %d timeout",513 __func__, ha->idc_extend_tmo);514 if (ha->idc_extend_tmo) {515 if (!wait_for_completion_timeout(&ha->idc_comp,516 (ha->idc_extend_tmo * HZ))) {517 ha->notify_idc_comp = 0;518 ha->notify_link_up_comp = 0;519 ql4_printk(KERN_WARNING, ha, "%s: Aborting: IDC Complete notification not received",520 __func__);521 status = QLA_ERROR;522 goto exit_wait;523 } else {524 DEBUG2(ql4_printk(KERN_INFO, ha,525 "%s: IDC Complete notification received\n",526 __func__));527 }528 }529 } else {530 DEBUG2(ql4_printk(KERN_INFO, ha,531 "%s: IDC Complete notification received\n",532 __func__));533 }534 ha->notify_idc_comp = 0;535 536 if (wait_for_link) {537 if (!wait_for_completion_timeout(&ha->link_up_comp,538 (IDC_COMP_TOV * HZ))) {539 ha->notify_link_up_comp = 0;540 ql4_printk(KERN_WARNING, ha, "%s: Aborting: LINK UP notification not received",541 __func__);542 status = QLA_ERROR;543 goto exit_wait;544 } else {545 DEBUG2(ql4_printk(KERN_INFO, ha,546 "%s: LINK UP notification received\n",547 __func__));548 }549 ha->notify_link_up_comp = 0;550 }551 552exit_wait:553 return status;554}555 556static int qla4_83xx_pre_loopback_config(struct scsi_qla_host *ha,557 uint32_t *mbox_cmd)558{559 uint32_t config = 0;560 int status = QLA_SUCCESS;561 562 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__));563 564 status = qla4_83xx_get_port_config(ha, &config);565 if (status != QLA_SUCCESS)566 goto exit_pre_loopback_config;567 568 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Default port config=%08X\n",569 __func__, config));570 571 if ((config & ENABLE_INTERNAL_LOOPBACK) ||572 (config & ENABLE_EXTERNAL_LOOPBACK)) {573 ql4_printk(KERN_INFO, ha, "%s: Loopback diagnostics already in progress. Invalid request\n",574 __func__);575 goto exit_pre_loopback_config;576 }577 578 if (mbox_cmd[1] == QL_DIAG_CMD_TEST_INT_LOOPBACK)579 config |= ENABLE_INTERNAL_LOOPBACK;580 581 if (mbox_cmd[1] == QL_DIAG_CMD_TEST_EXT_LOOPBACK)582 config |= ENABLE_EXTERNAL_LOOPBACK;583 584 config &= ~ENABLE_DCBX;585 586 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: New port config=%08X\n",587 __func__, config));588 589 ha->notify_idc_comp = 1;590 ha->notify_link_up_comp = 1;591 592 /* get the link state */593 qla4xxx_get_firmware_state(ha);594 595 status = qla4_83xx_set_port_config(ha, &config);596 if (status != QLA_SUCCESS) {597 ha->notify_idc_comp = 0;598 ha->notify_link_up_comp = 0;599 goto exit_pre_loopback_config;600 }601exit_pre_loopback_config:602 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: status = %s\n", __func__,603 STATUS(status)));604 return status;605}606 607static int qla4_83xx_post_loopback_config(struct scsi_qla_host *ha,608 uint32_t *mbox_cmd)609{610 int status = QLA_SUCCESS;611 uint32_t config = 0;612 613 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__));614 615 status = qla4_83xx_get_port_config(ha, &config);616 if (status != QLA_SUCCESS)617 goto exit_post_loopback_config;618 619 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: port config=%08X\n", __func__,620 config));621 622 if (mbox_cmd[1] == QL_DIAG_CMD_TEST_INT_LOOPBACK)623 config &= ~ENABLE_INTERNAL_LOOPBACK;624 else if (mbox_cmd[1] == QL_DIAG_CMD_TEST_EXT_LOOPBACK)625 config &= ~ENABLE_EXTERNAL_LOOPBACK;626 627 config |= ENABLE_DCBX;628 629 DEBUG2(ql4_printk(KERN_INFO, ha,630 "%s: Restore default port config=%08X\n", __func__,631 config));632 633 ha->notify_idc_comp = 1;634 if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP)635 ha->notify_link_up_comp = 1;636 637 status = qla4_83xx_set_port_config(ha, &config);638 if (status != QLA_SUCCESS) {639 ql4_printk(KERN_INFO, ha, "%s: Scheduling adapter reset\n",640 __func__);641 set_bit(DPC_RESET_HA, &ha->dpc_flags);642 clear_bit(AF_LOOPBACK, &ha->flags);643 goto exit_post_loopback_config;644 }645 646exit_post_loopback_config:647 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: status = %s\n", __func__,648 STATUS(status)));649 return status;650}651 652static void qla4xxx_execute_diag_loopback_cmd(struct bsg_job *bsg_job)653{654 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);655 struct scsi_qla_host *ha = to_qla_host(host);656 struct iscsi_bsg_request *bsg_req = bsg_job->request;657 struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;658 uint8_t *rsp_ptr = NULL;659 uint32_t mbox_cmd[MBOX_REG_COUNT];660 uint32_t mbox_sts[MBOX_REG_COUNT];661 int wait_for_link = 1;662 int status = QLA_ERROR;663 664 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__));665 666 bsg_reply->reply_payload_rcv_len = 0;667 668 if (test_bit(AF_LOOPBACK, &ha->flags)) {669 ql4_printk(KERN_INFO, ha, "%s: Loopback Diagnostics already in progress. Invalid Request\n",670 __func__);671 bsg_reply->result = DID_ERROR << 16;672 goto exit_loopback_cmd;673 }674 675 if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) {676 ql4_printk(KERN_INFO, ha, "%s: Adapter reset in progress. Invalid Request\n",677 __func__);678 bsg_reply->result = DID_ERROR << 16;679 goto exit_loopback_cmd;680 }681 682 memcpy(mbox_cmd, &bsg_req->rqst_data.h_vendor.vendor_cmd[1],683 sizeof(uint32_t) * MBOX_REG_COUNT);684 685 if (is_qla8032(ha) || is_qla8042(ha)) {686 status = qla4_83xx_pre_loopback_config(ha, mbox_cmd);687 if (status != QLA_SUCCESS) {688 bsg_reply->result = DID_ERROR << 16;689 goto exit_loopback_cmd;690 }691 692 status = qla4_83xx_wait_for_loopback_config_comp(ha,693 wait_for_link);694 if (status != QLA_SUCCESS) {695 bsg_reply->result = DID_TIME_OUT << 16;696 goto restore;697 }698 }699 700 DEBUG2(ql4_printk(KERN_INFO, ha,701 "%s: mbox_cmd: %08X %08X %08X %08X %08X %08X %08X %08X\n",702 __func__, mbox_cmd[0], mbox_cmd[1], mbox_cmd[2],703 mbox_cmd[3], mbox_cmd[4], mbox_cmd[5], mbox_cmd[6],704 mbox_cmd[7]));705 706 status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0],707 &mbox_sts[0]);708 709 if (status == QLA_SUCCESS)710 bsg_reply->result = DID_OK << 16;711 else712 bsg_reply->result = DID_ERROR << 16;713 714 DEBUG2(ql4_printk(KERN_INFO, ha,715 "%s: mbox_sts: %08X %08X %08X %08X %08X %08X %08X %08X\n",716 __func__, mbox_sts[0], mbox_sts[1], mbox_sts[2],717 mbox_sts[3], mbox_sts[4], mbox_sts[5], mbox_sts[6],718 mbox_sts[7]));719 720 /* Send mbox_sts to application */721 bsg_job->reply_len = sizeof(struct iscsi_bsg_reply) + sizeof(mbox_sts);722 rsp_ptr = ((uint8_t *)bsg_reply) + sizeof(struct iscsi_bsg_reply);723 memcpy(rsp_ptr, mbox_sts, sizeof(mbox_sts));724restore:725 if (is_qla8032(ha) || is_qla8042(ha)) {726 status = qla4_83xx_post_loopback_config(ha, mbox_cmd);727 if (status != QLA_SUCCESS) {728 bsg_reply->result = DID_ERROR << 16;729 goto exit_loopback_cmd;730 }731 732 /* for pre_loopback_config() wait for LINK UP only733 * if PHY LINK is UP */734 if (!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP))735 wait_for_link = 0;736 737 status = qla4_83xx_wait_for_loopback_config_comp(ha,738 wait_for_link);739 if (status != QLA_SUCCESS) {740 bsg_reply->result = DID_TIME_OUT << 16;741 goto exit_loopback_cmd;742 }743 }744exit_loopback_cmd:745 DEBUG2(ql4_printk(KERN_INFO, ha,746 "%s: bsg_reply->result = x%x, status = %s\n",747 __func__, bsg_reply->result, STATUS(status)));748 bsg_job_done(bsg_job, bsg_reply->result,749 bsg_reply->reply_payload_rcv_len);750}751 752static int qla4xxx_execute_diag_test(struct bsg_job *bsg_job)753{754 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);755 struct scsi_qla_host *ha = to_qla_host(host);756 struct iscsi_bsg_request *bsg_req = bsg_job->request;757 uint32_t diag_cmd;758 int rval = -EINVAL;759 760 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__));761 762 diag_cmd = bsg_req->rqst_data.h_vendor.vendor_cmd[1];763 if (diag_cmd == MBOX_CMD_DIAG_TEST) {764 switch (bsg_req->rqst_data.h_vendor.vendor_cmd[2]) {765 case QL_DIAG_CMD_TEST_DDR_SIZE:766 case QL_DIAG_CMD_TEST_DDR_RW:767 case QL_DIAG_CMD_TEST_ONCHIP_MEM_RW:768 case QL_DIAG_CMD_TEST_NVRAM:769 case QL_DIAG_CMD_TEST_FLASH_ROM:770 case QL_DIAG_CMD_TEST_DMA_XFER:771 case QL_DIAG_CMD_SELF_DDR_RW:772 case QL_DIAG_CMD_SELF_ONCHIP_MEM_RW:773 /* Execute diag test for adapter RAM/FLASH */774 ql4xxx_execute_diag_cmd(bsg_job);775 /* Always return success as we want to sent bsg_reply776 * to Application */777 rval = QLA_SUCCESS;778 break;779 780 case QL_DIAG_CMD_TEST_INT_LOOPBACK:781 case QL_DIAG_CMD_TEST_EXT_LOOPBACK:782 /* Execute diag test for Network */783 qla4xxx_execute_diag_loopback_cmd(bsg_job);784 /* Always return success as we want to sent bsg_reply785 * to Application */786 rval = QLA_SUCCESS;787 break;788 default:789 ql4_printk(KERN_ERR, ha, "%s: Invalid diag test: 0x%x\n",790 __func__,791 bsg_req->rqst_data.h_vendor.vendor_cmd[2]);792 }793 } else if ((diag_cmd == MBOX_CMD_SET_LED_CONFIG) ||794 (diag_cmd == MBOX_CMD_GET_LED_CONFIG)) {795 ql4xxx_execute_diag_cmd(bsg_job);796 rval = QLA_SUCCESS;797 } else {798 ql4_printk(KERN_ERR, ha, "%s: Invalid diag cmd: 0x%x\n",799 __func__, diag_cmd);800 }801 802 return rval;803}804 805/**806 * qla4xxx_process_vendor_specific - handle vendor specific bsg request807 * @bsg_job: iscsi_bsg_job to handle808 **/809int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job)810{811 struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;812 struct iscsi_bsg_request *bsg_req = bsg_job->request;813 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);814 struct scsi_qla_host *ha = to_qla_host(host);815 816 switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {817 case QLISCSI_VND_READ_FLASH:818 return qla4xxx_read_flash(bsg_job);819 820 case QLISCSI_VND_UPDATE_FLASH:821 return qla4xxx_update_flash(bsg_job);822 823 case QLISCSI_VND_GET_ACB_STATE:824 return qla4xxx_get_acb_state(bsg_job);825 826 case QLISCSI_VND_READ_NVRAM:827 return qla4xxx_read_nvram(bsg_job);828 829 case QLISCSI_VND_UPDATE_NVRAM:830 return qla4xxx_update_nvram(bsg_job);831 832 case QLISCSI_VND_RESTORE_DEFAULTS:833 return qla4xxx_restore_defaults(bsg_job);834 835 case QLISCSI_VND_GET_ACB:836 return qla4xxx_bsg_get_acb(bsg_job);837 838 case QLISCSI_VND_DIAG_TEST:839 return qla4xxx_execute_diag_test(bsg_job);840 841 default:842 ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: "843 "0x%x\n", __func__, bsg_req->msgcode);844 bsg_reply->result = (DID_ERROR << 16);845 bsg_reply->reply_payload_rcv_len = 0;846 bsg_job_done(bsg_job, bsg_reply->result,847 bsg_reply->reply_payload_rcv_len);848 return -ENOSYS;849 }850}851 852/**853 * qla4xxx_bsg_request - handle bsg request from ISCSI transport854 * @bsg_job: iscsi_bsg_job to handle855 */856int qla4xxx_bsg_request(struct bsg_job *bsg_job)857{858 struct iscsi_bsg_request *bsg_req = bsg_job->request;859 struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);860 struct scsi_qla_host *ha = to_qla_host(host);861 862 switch (bsg_req->msgcode) {863 case ISCSI_BSG_HST_VENDOR:864 return qla4xxx_process_vendor_specific(bsg_job);865 866 default:867 ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n",868 __func__, bsg_req->msgcode);869 }870 871 return -ENOSYS;872}873