162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QLogic iSCSI HBA Driver 462306a36Sopenharmony_ci * Copyright (c) 2011-2013 QLogic Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "ql4_def.h" 862306a36Sopenharmony_ci#include "ql4_glbl.h" 962306a36Sopenharmony_ci#include "ql4_bsg.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic int 1262306a36Sopenharmony_ciqla4xxx_read_flash(struct bsg_job *bsg_job) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 1562306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 1662306a36Sopenharmony_ci struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 1762306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 1862306a36Sopenharmony_ci uint32_t offset = 0; 1962306a36Sopenharmony_ci uint32_t length = 0; 2062306a36Sopenharmony_ci dma_addr_t flash_dma; 2162306a36Sopenharmony_ci uint8_t *flash = NULL; 2262306a36Sopenharmony_ci int rval = -EINVAL; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 2762306a36Sopenharmony_ci goto leave; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (ql4xxx_reset_active(ha)) { 3062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 3162306a36Sopenharmony_ci rval = -EBUSY; 3262306a36Sopenharmony_ci goto leave; 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (ha->flash_state != QLFLASH_WAITING) { 3662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: another flash operation " 3762306a36Sopenharmony_ci "active\n", __func__); 3862306a36Sopenharmony_ci rval = -EBUSY; 3962306a36Sopenharmony_ci goto leave; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci ha->flash_state = QLFLASH_READING; 4362306a36Sopenharmony_ci offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 4462306a36Sopenharmony_ci length = bsg_job->reply_payload.payload_len; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma, 4762306a36Sopenharmony_ci GFP_KERNEL); 4862306a36Sopenharmony_ci if (!flash) { 4962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " 5062306a36Sopenharmony_ci "data\n", __func__); 5162306a36Sopenharmony_ci rval = -ENOMEM; 5262306a36Sopenharmony_ci goto leave; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci rval = qla4xxx_get_flash(ha, flash_dma, offset, length); 5662306a36Sopenharmony_ci if (rval) { 5762306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: get flash failed\n", __func__); 5862306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 5962306a36Sopenharmony_ci rval = -EIO; 6062306a36Sopenharmony_ci } else { 6162306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 6262306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 6362306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, 6462306a36Sopenharmony_ci flash, length); 6562306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 6962306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 7062306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma); 7162306a36Sopenharmony_cileave: 7262306a36Sopenharmony_ci ha->flash_state = QLFLASH_WAITING; 7362306a36Sopenharmony_ci return rval; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int 7762306a36Sopenharmony_ciqla4xxx_update_flash(struct bsg_job *bsg_job) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 8062306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 8162306a36Sopenharmony_ci struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 8262306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 8362306a36Sopenharmony_ci uint32_t length = 0; 8462306a36Sopenharmony_ci uint32_t offset = 0; 8562306a36Sopenharmony_ci uint32_t options = 0; 8662306a36Sopenharmony_ci dma_addr_t flash_dma; 8762306a36Sopenharmony_ci uint8_t *flash = NULL; 8862306a36Sopenharmony_ci int rval = -EINVAL; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 9362306a36Sopenharmony_ci goto leave; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (ql4xxx_reset_active(ha)) { 9662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 9762306a36Sopenharmony_ci rval = -EBUSY; 9862306a36Sopenharmony_ci goto leave; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (ha->flash_state != QLFLASH_WAITING) { 10262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: another flash operation " 10362306a36Sopenharmony_ci "active\n", __func__); 10462306a36Sopenharmony_ci rval = -EBUSY; 10562306a36Sopenharmony_ci goto leave; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci ha->flash_state = QLFLASH_WRITING; 10962306a36Sopenharmony_ci length = bsg_job->request_payload.payload_len; 11062306a36Sopenharmony_ci offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 11162306a36Sopenharmony_ci options = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma, 11462306a36Sopenharmony_ci GFP_KERNEL); 11562306a36Sopenharmony_ci if (!flash) { 11662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " 11762306a36Sopenharmony_ci "data\n", __func__); 11862306a36Sopenharmony_ci rval = -ENOMEM; 11962306a36Sopenharmony_ci goto leave; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 12362306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, flash, length); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci rval = qla4xxx_set_flash(ha, flash_dma, offset, length, options); 12662306a36Sopenharmony_ci if (rval) { 12762306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: set flash failed\n", __func__); 12862306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 12962306a36Sopenharmony_ci rval = -EIO; 13062306a36Sopenharmony_ci } else 13162306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 13462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 13562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma); 13662306a36Sopenharmony_cileave: 13762306a36Sopenharmony_ci ha->flash_state = QLFLASH_WAITING; 13862306a36Sopenharmony_ci return rval; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int 14262306a36Sopenharmony_ciqla4xxx_get_acb_state(struct bsg_job *bsg_job) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 14562306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 14662306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 14762306a36Sopenharmony_ci struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 14862306a36Sopenharmony_ci uint32_t status[MBOX_REG_COUNT]; 14962306a36Sopenharmony_ci uint32_t acb_idx; 15062306a36Sopenharmony_ci uint32_t ip_idx; 15162306a36Sopenharmony_ci int rval = -EINVAL; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 15662306a36Sopenharmony_ci goto leave; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Only 4022 and above adapters are supported */ 15962306a36Sopenharmony_ci if (is_qla4010(ha)) 16062306a36Sopenharmony_ci goto leave; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (ql4xxx_reset_active(ha)) { 16362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 16462306a36Sopenharmony_ci rval = -EBUSY; 16562306a36Sopenharmony_ci goto leave; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (bsg_job->reply_payload.payload_len < sizeof(status)) { 16962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: invalid payload len %d\n", 17062306a36Sopenharmony_ci __func__, bsg_job->reply_payload.payload_len); 17162306a36Sopenharmony_ci rval = -EINVAL; 17262306a36Sopenharmony_ci goto leave; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci acb_idx = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 17662306a36Sopenharmony_ci ip_idx = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci rval = qla4xxx_get_ip_state(ha, acb_idx, ip_idx, status); 17962306a36Sopenharmony_ci if (rval) { 18062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: get ip state failed\n", 18162306a36Sopenharmony_ci __func__); 18262306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 18362306a36Sopenharmony_ci rval = -EIO; 18462306a36Sopenharmony_ci } else { 18562306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 18662306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 18762306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, 18862306a36Sopenharmony_ci status, sizeof(status)); 18962306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 19362306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 19462306a36Sopenharmony_cileave: 19562306a36Sopenharmony_ci return rval; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int 19962306a36Sopenharmony_ciqla4xxx_read_nvram(struct bsg_job *bsg_job) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 20262306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 20362306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 20462306a36Sopenharmony_ci struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 20562306a36Sopenharmony_ci uint32_t offset = 0; 20662306a36Sopenharmony_ci uint32_t len = 0; 20762306a36Sopenharmony_ci uint32_t total_len = 0; 20862306a36Sopenharmony_ci dma_addr_t nvram_dma; 20962306a36Sopenharmony_ci uint8_t *nvram = NULL; 21062306a36Sopenharmony_ci int rval = -EINVAL; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 21562306a36Sopenharmony_ci goto leave; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* Only 40xx adapters are supported */ 21862306a36Sopenharmony_ci if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha))) 21962306a36Sopenharmony_ci goto leave; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (ql4xxx_reset_active(ha)) { 22262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 22362306a36Sopenharmony_ci rval = -EBUSY; 22462306a36Sopenharmony_ci goto leave; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 22862306a36Sopenharmony_ci len = bsg_job->reply_payload.payload_len; 22962306a36Sopenharmony_ci total_len = offset + len; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* total len should not be greater than max NVRAM size */ 23262306a36Sopenharmony_ci if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) || 23362306a36Sopenharmony_ci ((is_qla4022(ha) || is_qla4032(ha)) && 23462306a36Sopenharmony_ci total_len > QL40X2_NVRAM_SIZE)) { 23562306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max" 23662306a36Sopenharmony_ci " nvram size, offset=%d len=%d\n", 23762306a36Sopenharmony_ci __func__, offset, len); 23862306a36Sopenharmony_ci goto leave; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma, 24262306a36Sopenharmony_ci GFP_KERNEL); 24362306a36Sopenharmony_ci if (!nvram) { 24462306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for nvram " 24562306a36Sopenharmony_ci "data\n", __func__); 24662306a36Sopenharmony_ci rval = -ENOMEM; 24762306a36Sopenharmony_ci goto leave; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci rval = qla4xxx_get_nvram(ha, nvram_dma, offset, len); 25162306a36Sopenharmony_ci if (rval) { 25262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: get nvram failed\n", __func__); 25362306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 25462306a36Sopenharmony_ci rval = -EIO; 25562306a36Sopenharmony_ci } else { 25662306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 25762306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 25862306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, 25962306a36Sopenharmony_ci nvram, len); 26062306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 26462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 26562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma); 26662306a36Sopenharmony_cileave: 26762306a36Sopenharmony_ci return rval; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int 27162306a36Sopenharmony_ciqla4xxx_update_nvram(struct bsg_job *bsg_job) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 27462306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 27562306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 27662306a36Sopenharmony_ci struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 27762306a36Sopenharmony_ci uint32_t offset = 0; 27862306a36Sopenharmony_ci uint32_t len = 0; 27962306a36Sopenharmony_ci uint32_t total_len = 0; 28062306a36Sopenharmony_ci dma_addr_t nvram_dma; 28162306a36Sopenharmony_ci uint8_t *nvram = NULL; 28262306a36Sopenharmony_ci int rval = -EINVAL; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 28762306a36Sopenharmony_ci goto leave; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha))) 29062306a36Sopenharmony_ci goto leave; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (ql4xxx_reset_active(ha)) { 29362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 29462306a36Sopenharmony_ci rval = -EBUSY; 29562306a36Sopenharmony_ci goto leave; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 29962306a36Sopenharmony_ci len = bsg_job->request_payload.payload_len; 30062306a36Sopenharmony_ci total_len = offset + len; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* total len should not be greater than max NVRAM size */ 30362306a36Sopenharmony_ci if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) || 30462306a36Sopenharmony_ci ((is_qla4022(ha) || is_qla4032(ha)) && 30562306a36Sopenharmony_ci total_len > QL40X2_NVRAM_SIZE)) { 30662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max" 30762306a36Sopenharmony_ci " nvram size, offset=%d len=%d\n", 30862306a36Sopenharmony_ci __func__, offset, len); 30962306a36Sopenharmony_ci goto leave; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma, 31362306a36Sopenharmony_ci GFP_KERNEL); 31462306a36Sopenharmony_ci if (!nvram) { 31562306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " 31662306a36Sopenharmony_ci "data\n", __func__); 31762306a36Sopenharmony_ci rval = -ENOMEM; 31862306a36Sopenharmony_ci goto leave; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci sg_copy_to_buffer(bsg_job->request_payload.sg_list, 32262306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, nvram, len); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci rval = qla4xxx_set_nvram(ha, nvram_dma, offset, len); 32562306a36Sopenharmony_ci if (rval) { 32662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__); 32762306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 32862306a36Sopenharmony_ci rval = -EIO; 32962306a36Sopenharmony_ci } else 33062306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 33362306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 33462306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma); 33562306a36Sopenharmony_cileave: 33662306a36Sopenharmony_ci return rval; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic int 34062306a36Sopenharmony_ciqla4xxx_restore_defaults(struct bsg_job *bsg_job) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 34362306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 34462306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 34562306a36Sopenharmony_ci struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 34662306a36Sopenharmony_ci uint32_t region = 0; 34762306a36Sopenharmony_ci uint32_t field0 = 0; 34862306a36Sopenharmony_ci uint32_t field1 = 0; 34962306a36Sopenharmony_ci int rval = -EINVAL; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 35462306a36Sopenharmony_ci goto leave; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (is_qla4010(ha)) 35762306a36Sopenharmony_ci goto leave; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (ql4xxx_reset_active(ha)) { 36062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 36162306a36Sopenharmony_ci rval = -EBUSY; 36262306a36Sopenharmony_ci goto leave; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci region = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 36662306a36Sopenharmony_ci field0 = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; 36762306a36Sopenharmony_ci field1 = bsg_req->rqst_data.h_vendor.vendor_cmd[3]; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci rval = qla4xxx_restore_factory_defaults(ha, region, field0, field1); 37062306a36Sopenharmony_ci if (rval) { 37162306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__); 37262306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 37362306a36Sopenharmony_ci rval = -EIO; 37462306a36Sopenharmony_ci } else 37562306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 37862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 37962306a36Sopenharmony_cileave: 38062306a36Sopenharmony_ci return rval; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int 38462306a36Sopenharmony_ciqla4xxx_bsg_get_acb(struct bsg_job *bsg_job) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 38762306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 38862306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 38962306a36Sopenharmony_ci struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 39062306a36Sopenharmony_ci uint32_t acb_type = 0; 39162306a36Sopenharmony_ci uint32_t len = 0; 39262306a36Sopenharmony_ci dma_addr_t acb_dma; 39362306a36Sopenharmony_ci uint8_t *acb = NULL; 39462306a36Sopenharmony_ci int rval = -EINVAL; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 39962306a36Sopenharmony_ci goto leave; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Only 4022 and above adapters are supported */ 40262306a36Sopenharmony_ci if (is_qla4010(ha)) 40362306a36Sopenharmony_ci goto leave; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (ql4xxx_reset_active(ha)) { 40662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 40762306a36Sopenharmony_ci rval = -EBUSY; 40862306a36Sopenharmony_ci goto leave; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci acb_type = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 41262306a36Sopenharmony_ci len = bsg_job->reply_payload.payload_len; 41362306a36Sopenharmony_ci if (len < sizeof(struct addr_ctrl_blk)) { 41462306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: invalid acb len %d\n", 41562306a36Sopenharmony_ci __func__, len); 41662306a36Sopenharmony_ci rval = -EINVAL; 41762306a36Sopenharmony_ci goto leave; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci acb = dma_alloc_coherent(&ha->pdev->dev, len, &acb_dma, GFP_KERNEL); 42162306a36Sopenharmony_ci if (!acb) { 42262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for acb " 42362306a36Sopenharmony_ci "data\n", __func__); 42462306a36Sopenharmony_ci rval = -ENOMEM; 42562306a36Sopenharmony_ci goto leave; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci rval = qla4xxx_get_acb(ha, acb_dma, acb_type, len); 42962306a36Sopenharmony_ci if (rval) { 43062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: get acb failed\n", __func__); 43162306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 43262306a36Sopenharmony_ci rval = -EIO; 43362306a36Sopenharmony_ci } else { 43462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 43562306a36Sopenharmony_ci sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 43662306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, 43762306a36Sopenharmony_ci acb, len); 43862306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 44262306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 44362306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, len, acb, acb_dma); 44462306a36Sopenharmony_cileave: 44562306a36Sopenharmony_ci return rval; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void ql4xxx_execute_diag_cmd(struct bsg_job *bsg_job) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 45162306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 45262306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 45362306a36Sopenharmony_ci struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 45462306a36Sopenharmony_ci uint8_t *rsp_ptr = NULL; 45562306a36Sopenharmony_ci uint32_t mbox_cmd[MBOX_REG_COUNT]; 45662306a36Sopenharmony_ci uint32_t mbox_sts[MBOX_REG_COUNT]; 45762306a36Sopenharmony_ci int status = QLA_ERROR; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__)); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 46262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Adapter reset in progress. Invalid Request\n", 46362306a36Sopenharmony_ci __func__); 46462306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 46562306a36Sopenharmony_ci goto exit_diag_mem_test; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 46962306a36Sopenharmony_ci memcpy(mbox_cmd, &bsg_req->rqst_data.h_vendor.vendor_cmd[1], 47062306a36Sopenharmony_ci sizeof(uint32_t) * MBOX_REG_COUNT); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 47362306a36Sopenharmony_ci "%s: mbox_cmd: %08X %08X %08X %08X %08X %08X %08X %08X\n", 47462306a36Sopenharmony_ci __func__, mbox_cmd[0], mbox_cmd[1], mbox_cmd[2], 47562306a36Sopenharmony_ci mbox_cmd[3], mbox_cmd[4], mbox_cmd[5], mbox_cmd[6], 47662306a36Sopenharmony_ci mbox_cmd[7])); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0], 47962306a36Sopenharmony_ci &mbox_sts[0]); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 48262306a36Sopenharmony_ci "%s: mbox_sts: %08X %08X %08X %08X %08X %08X %08X %08X\n", 48362306a36Sopenharmony_ci __func__, mbox_sts[0], mbox_sts[1], mbox_sts[2], 48462306a36Sopenharmony_ci mbox_sts[3], mbox_sts[4], mbox_sts[5], mbox_sts[6], 48562306a36Sopenharmony_ci mbox_sts[7])); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (status == QLA_SUCCESS) 48862306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 48962306a36Sopenharmony_ci else 49062306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Send mbox_sts to application */ 49362306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct iscsi_bsg_reply) + sizeof(mbox_sts); 49462306a36Sopenharmony_ci rsp_ptr = ((uint8_t *)bsg_reply) + sizeof(struct iscsi_bsg_reply); 49562306a36Sopenharmony_ci memcpy(rsp_ptr, mbox_sts, sizeof(mbox_sts)); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ciexit_diag_mem_test: 49862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 49962306a36Sopenharmony_ci "%s: bsg_reply->result = x%x, status = %s\n", 50062306a36Sopenharmony_ci __func__, bsg_reply->result, STATUS(status))); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 50362306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic int qla4_83xx_wait_for_loopback_config_comp(struct scsi_qla_host *ha, 50762306a36Sopenharmony_ci int wait_for_link) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci int status = QLA_SUCCESS; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (!wait_for_completion_timeout(&ha->idc_comp, (IDC_COMP_TOV * HZ))) { 51262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: IDC Complete notification not received, Waiting for another %d timeout", 51362306a36Sopenharmony_ci __func__, ha->idc_extend_tmo); 51462306a36Sopenharmony_ci if (ha->idc_extend_tmo) { 51562306a36Sopenharmony_ci if (!wait_for_completion_timeout(&ha->idc_comp, 51662306a36Sopenharmony_ci (ha->idc_extend_tmo * HZ))) { 51762306a36Sopenharmony_ci ha->notify_idc_comp = 0; 51862306a36Sopenharmony_ci ha->notify_link_up_comp = 0; 51962306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "%s: Aborting: IDC Complete notification not received", 52062306a36Sopenharmony_ci __func__); 52162306a36Sopenharmony_ci status = QLA_ERROR; 52262306a36Sopenharmony_ci goto exit_wait; 52362306a36Sopenharmony_ci } else { 52462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 52562306a36Sopenharmony_ci "%s: IDC Complete notification received\n", 52662306a36Sopenharmony_ci __func__)); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci } else { 53062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 53162306a36Sopenharmony_ci "%s: IDC Complete notification received\n", 53262306a36Sopenharmony_ci __func__)); 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci ha->notify_idc_comp = 0; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (wait_for_link) { 53762306a36Sopenharmony_ci if (!wait_for_completion_timeout(&ha->link_up_comp, 53862306a36Sopenharmony_ci (IDC_COMP_TOV * HZ))) { 53962306a36Sopenharmony_ci ha->notify_link_up_comp = 0; 54062306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "%s: Aborting: LINK UP notification not received", 54162306a36Sopenharmony_ci __func__); 54262306a36Sopenharmony_ci status = QLA_ERROR; 54362306a36Sopenharmony_ci goto exit_wait; 54462306a36Sopenharmony_ci } else { 54562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 54662306a36Sopenharmony_ci "%s: LINK UP notification received\n", 54762306a36Sopenharmony_ci __func__)); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci ha->notify_link_up_comp = 0; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ciexit_wait: 55362306a36Sopenharmony_ci return status; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int qla4_83xx_pre_loopback_config(struct scsi_qla_host *ha, 55762306a36Sopenharmony_ci uint32_t *mbox_cmd) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci uint32_t config = 0; 56062306a36Sopenharmony_ci int status = QLA_SUCCESS; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__)); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci status = qla4_83xx_get_port_config(ha, &config); 56562306a36Sopenharmony_ci if (status != QLA_SUCCESS) 56662306a36Sopenharmony_ci goto exit_pre_loopback_config; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Default port config=%08X\n", 56962306a36Sopenharmony_ci __func__, config)); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if ((config & ENABLE_INTERNAL_LOOPBACK) || 57262306a36Sopenharmony_ci (config & ENABLE_EXTERNAL_LOOPBACK)) { 57362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Loopback diagnostics already in progress. Invalid request\n", 57462306a36Sopenharmony_ci __func__); 57562306a36Sopenharmony_ci goto exit_pre_loopback_config; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (mbox_cmd[1] == QL_DIAG_CMD_TEST_INT_LOOPBACK) 57962306a36Sopenharmony_ci config |= ENABLE_INTERNAL_LOOPBACK; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (mbox_cmd[1] == QL_DIAG_CMD_TEST_EXT_LOOPBACK) 58262306a36Sopenharmony_ci config |= ENABLE_EXTERNAL_LOOPBACK; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci config &= ~ENABLE_DCBX; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: New port config=%08X\n", 58762306a36Sopenharmony_ci __func__, config)); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci ha->notify_idc_comp = 1; 59062306a36Sopenharmony_ci ha->notify_link_up_comp = 1; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* get the link state */ 59362306a36Sopenharmony_ci qla4xxx_get_firmware_state(ha); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci status = qla4_83xx_set_port_config(ha, &config); 59662306a36Sopenharmony_ci if (status != QLA_SUCCESS) { 59762306a36Sopenharmony_ci ha->notify_idc_comp = 0; 59862306a36Sopenharmony_ci ha->notify_link_up_comp = 0; 59962306a36Sopenharmony_ci goto exit_pre_loopback_config; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ciexit_pre_loopback_config: 60262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: status = %s\n", __func__, 60362306a36Sopenharmony_ci STATUS(status))); 60462306a36Sopenharmony_ci return status; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int qla4_83xx_post_loopback_config(struct scsi_qla_host *ha, 60862306a36Sopenharmony_ci uint32_t *mbox_cmd) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci int status = QLA_SUCCESS; 61162306a36Sopenharmony_ci uint32_t config = 0; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__)); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci status = qla4_83xx_get_port_config(ha, &config); 61662306a36Sopenharmony_ci if (status != QLA_SUCCESS) 61762306a36Sopenharmony_ci goto exit_post_loopback_config; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: port config=%08X\n", __func__, 62062306a36Sopenharmony_ci config)); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (mbox_cmd[1] == QL_DIAG_CMD_TEST_INT_LOOPBACK) 62362306a36Sopenharmony_ci config &= ~ENABLE_INTERNAL_LOOPBACK; 62462306a36Sopenharmony_ci else if (mbox_cmd[1] == QL_DIAG_CMD_TEST_EXT_LOOPBACK) 62562306a36Sopenharmony_ci config &= ~ENABLE_EXTERNAL_LOOPBACK; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci config |= ENABLE_DCBX; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 63062306a36Sopenharmony_ci "%s: Restore default port config=%08X\n", __func__, 63162306a36Sopenharmony_ci config)); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci ha->notify_idc_comp = 1; 63462306a36Sopenharmony_ci if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) 63562306a36Sopenharmony_ci ha->notify_link_up_comp = 1; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci status = qla4_83xx_set_port_config(ha, &config); 63862306a36Sopenharmony_ci if (status != QLA_SUCCESS) { 63962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Scheduling adapter reset\n", 64062306a36Sopenharmony_ci __func__); 64162306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 64262306a36Sopenharmony_ci clear_bit(AF_LOOPBACK, &ha->flags); 64362306a36Sopenharmony_ci goto exit_post_loopback_config; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ciexit_post_loopback_config: 64762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: status = %s\n", __func__, 64862306a36Sopenharmony_ci STATUS(status))); 64962306a36Sopenharmony_ci return status; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic void qla4xxx_execute_diag_loopback_cmd(struct bsg_job *bsg_job) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 65562306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 65662306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 65762306a36Sopenharmony_ci struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 65862306a36Sopenharmony_ci uint8_t *rsp_ptr = NULL; 65962306a36Sopenharmony_ci uint32_t mbox_cmd[MBOX_REG_COUNT]; 66062306a36Sopenharmony_ci uint32_t mbox_sts[MBOX_REG_COUNT]; 66162306a36Sopenharmony_ci int wait_for_link = 1; 66262306a36Sopenharmony_ci int status = QLA_ERROR; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__)); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (test_bit(AF_LOOPBACK, &ha->flags)) { 66962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Loopback Diagnostics already in progress. Invalid Request\n", 67062306a36Sopenharmony_ci __func__); 67162306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 67262306a36Sopenharmony_ci goto exit_loopback_cmd; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 67662306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Adapter reset in progress. Invalid Request\n", 67762306a36Sopenharmony_ci __func__); 67862306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 67962306a36Sopenharmony_ci goto exit_loopback_cmd; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci memcpy(mbox_cmd, &bsg_req->rqst_data.h_vendor.vendor_cmd[1], 68362306a36Sopenharmony_ci sizeof(uint32_t) * MBOX_REG_COUNT); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 68662306a36Sopenharmony_ci status = qla4_83xx_pre_loopback_config(ha, mbox_cmd); 68762306a36Sopenharmony_ci if (status != QLA_SUCCESS) { 68862306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 68962306a36Sopenharmony_ci goto exit_loopback_cmd; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci status = qla4_83xx_wait_for_loopback_config_comp(ha, 69362306a36Sopenharmony_ci wait_for_link); 69462306a36Sopenharmony_ci if (status != QLA_SUCCESS) { 69562306a36Sopenharmony_ci bsg_reply->result = DID_TIME_OUT << 16; 69662306a36Sopenharmony_ci goto restore; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 70162306a36Sopenharmony_ci "%s: mbox_cmd: %08X %08X %08X %08X %08X %08X %08X %08X\n", 70262306a36Sopenharmony_ci __func__, mbox_cmd[0], mbox_cmd[1], mbox_cmd[2], 70362306a36Sopenharmony_ci mbox_cmd[3], mbox_cmd[4], mbox_cmd[5], mbox_cmd[6], 70462306a36Sopenharmony_ci mbox_cmd[7])); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0], 70762306a36Sopenharmony_ci &mbox_sts[0]); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (status == QLA_SUCCESS) 71062306a36Sopenharmony_ci bsg_reply->result = DID_OK << 16; 71162306a36Sopenharmony_ci else 71262306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 71562306a36Sopenharmony_ci "%s: mbox_sts: %08X %08X %08X %08X %08X %08X %08X %08X\n", 71662306a36Sopenharmony_ci __func__, mbox_sts[0], mbox_sts[1], mbox_sts[2], 71762306a36Sopenharmony_ci mbox_sts[3], mbox_sts[4], mbox_sts[5], mbox_sts[6], 71862306a36Sopenharmony_ci mbox_sts[7])); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* Send mbox_sts to application */ 72162306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct iscsi_bsg_reply) + sizeof(mbox_sts); 72262306a36Sopenharmony_ci rsp_ptr = ((uint8_t *)bsg_reply) + sizeof(struct iscsi_bsg_reply); 72362306a36Sopenharmony_ci memcpy(rsp_ptr, mbox_sts, sizeof(mbox_sts)); 72462306a36Sopenharmony_cirestore: 72562306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 72662306a36Sopenharmony_ci status = qla4_83xx_post_loopback_config(ha, mbox_cmd); 72762306a36Sopenharmony_ci if (status != QLA_SUCCESS) { 72862306a36Sopenharmony_ci bsg_reply->result = DID_ERROR << 16; 72962306a36Sopenharmony_ci goto exit_loopback_cmd; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* for pre_loopback_config() wait for LINK UP only 73362306a36Sopenharmony_ci * if PHY LINK is UP */ 73462306a36Sopenharmony_ci if (!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP)) 73562306a36Sopenharmony_ci wait_for_link = 0; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci status = qla4_83xx_wait_for_loopback_config_comp(ha, 73862306a36Sopenharmony_ci wait_for_link); 73962306a36Sopenharmony_ci if (status != QLA_SUCCESS) { 74062306a36Sopenharmony_ci bsg_reply->result = DID_TIME_OUT << 16; 74162306a36Sopenharmony_ci goto exit_loopback_cmd; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ciexit_loopback_cmd: 74562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 74662306a36Sopenharmony_ci "%s: bsg_reply->result = x%x, status = %s\n", 74762306a36Sopenharmony_ci __func__, bsg_reply->result, STATUS(status))); 74862306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 74962306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic int qla4xxx_execute_diag_test(struct bsg_job *bsg_job) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 75562306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 75662306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 75762306a36Sopenharmony_ci uint32_t diag_cmd; 75862306a36Sopenharmony_ci int rval = -EINVAL; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__)); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci diag_cmd = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 76362306a36Sopenharmony_ci if (diag_cmd == MBOX_CMD_DIAG_TEST) { 76462306a36Sopenharmony_ci switch (bsg_req->rqst_data.h_vendor.vendor_cmd[2]) { 76562306a36Sopenharmony_ci case QL_DIAG_CMD_TEST_DDR_SIZE: 76662306a36Sopenharmony_ci case QL_DIAG_CMD_TEST_DDR_RW: 76762306a36Sopenharmony_ci case QL_DIAG_CMD_TEST_ONCHIP_MEM_RW: 76862306a36Sopenharmony_ci case QL_DIAG_CMD_TEST_NVRAM: 76962306a36Sopenharmony_ci case QL_DIAG_CMD_TEST_FLASH_ROM: 77062306a36Sopenharmony_ci case QL_DIAG_CMD_TEST_DMA_XFER: 77162306a36Sopenharmony_ci case QL_DIAG_CMD_SELF_DDR_RW: 77262306a36Sopenharmony_ci case QL_DIAG_CMD_SELF_ONCHIP_MEM_RW: 77362306a36Sopenharmony_ci /* Execute diag test for adapter RAM/FLASH */ 77462306a36Sopenharmony_ci ql4xxx_execute_diag_cmd(bsg_job); 77562306a36Sopenharmony_ci /* Always return success as we want to sent bsg_reply 77662306a36Sopenharmony_ci * to Application */ 77762306a36Sopenharmony_ci rval = QLA_SUCCESS; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci case QL_DIAG_CMD_TEST_INT_LOOPBACK: 78162306a36Sopenharmony_ci case QL_DIAG_CMD_TEST_EXT_LOOPBACK: 78262306a36Sopenharmony_ci /* Execute diag test for Network */ 78362306a36Sopenharmony_ci qla4xxx_execute_diag_loopback_cmd(bsg_job); 78462306a36Sopenharmony_ci /* Always return success as we want to sent bsg_reply 78562306a36Sopenharmony_ci * to Application */ 78662306a36Sopenharmony_ci rval = QLA_SUCCESS; 78762306a36Sopenharmony_ci break; 78862306a36Sopenharmony_ci default: 78962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Invalid diag test: 0x%x\n", 79062306a36Sopenharmony_ci __func__, 79162306a36Sopenharmony_ci bsg_req->rqst_data.h_vendor.vendor_cmd[2]); 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci } else if ((diag_cmd == MBOX_CMD_SET_LED_CONFIG) || 79462306a36Sopenharmony_ci (diag_cmd == MBOX_CMD_GET_LED_CONFIG)) { 79562306a36Sopenharmony_ci ql4xxx_execute_diag_cmd(bsg_job); 79662306a36Sopenharmony_ci rval = QLA_SUCCESS; 79762306a36Sopenharmony_ci } else { 79862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Invalid diag cmd: 0x%x\n", 79962306a36Sopenharmony_ci __func__, diag_cmd); 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return rval; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci/** 80662306a36Sopenharmony_ci * qla4xxx_process_vendor_specific - handle vendor specific bsg request 80762306a36Sopenharmony_ci * @bsg_job: iscsi_bsg_job to handle 80862306a36Sopenharmony_ci **/ 80962306a36Sopenharmony_ciint qla4xxx_process_vendor_specific(struct bsg_job *bsg_job) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 81262306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 81362306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 81462306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) { 81762306a36Sopenharmony_ci case QLISCSI_VND_READ_FLASH: 81862306a36Sopenharmony_ci return qla4xxx_read_flash(bsg_job); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci case QLISCSI_VND_UPDATE_FLASH: 82162306a36Sopenharmony_ci return qla4xxx_update_flash(bsg_job); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci case QLISCSI_VND_GET_ACB_STATE: 82462306a36Sopenharmony_ci return qla4xxx_get_acb_state(bsg_job); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci case QLISCSI_VND_READ_NVRAM: 82762306a36Sopenharmony_ci return qla4xxx_read_nvram(bsg_job); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci case QLISCSI_VND_UPDATE_NVRAM: 83062306a36Sopenharmony_ci return qla4xxx_update_nvram(bsg_job); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci case QLISCSI_VND_RESTORE_DEFAULTS: 83362306a36Sopenharmony_ci return qla4xxx_restore_defaults(bsg_job); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci case QLISCSI_VND_GET_ACB: 83662306a36Sopenharmony_ci return qla4xxx_bsg_get_acb(bsg_job); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci case QLISCSI_VND_DIAG_TEST: 83962306a36Sopenharmony_ci return qla4xxx_execute_diag_test(bsg_job); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci default: 84262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: " 84362306a36Sopenharmony_ci "0x%x\n", __func__, bsg_req->msgcode); 84462306a36Sopenharmony_ci bsg_reply->result = (DID_ERROR << 16); 84562306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 84662306a36Sopenharmony_ci bsg_job_done(bsg_job, bsg_reply->result, 84762306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 84862306a36Sopenharmony_ci return -ENOSYS; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci/** 85362306a36Sopenharmony_ci * qla4xxx_bsg_request - handle bsg request from ISCSI transport 85462306a36Sopenharmony_ci * @bsg_job: iscsi_bsg_job to handle 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_ciint qla4xxx_bsg_request(struct bsg_job *bsg_job) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci struct iscsi_bsg_request *bsg_req = bsg_job->request; 85962306a36Sopenharmony_ci struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 86062306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci switch (bsg_req->msgcode) { 86362306a36Sopenharmony_ci case ISCSI_BSG_HST_VENDOR: 86462306a36Sopenharmony_ci return qla4xxx_process_vendor_specific(bsg_job); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci default: 86762306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n", 86862306a36Sopenharmony_ci __func__, bsg_req->msgcode); 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci return -ENOSYS; 87262306a36Sopenharmony_ci} 873