1a355943cSVikas Chaudhary /* 2a355943cSVikas Chaudhary * QLogic iSCSI HBA Driver 34a4f51e9SVikas Chaudhary * Copyright (c) 2011-2013 QLogic Corporation 4a355943cSVikas Chaudhary * 5a355943cSVikas Chaudhary * See LICENSE.qla4xxx for copyright and licensing details. 6a355943cSVikas Chaudhary */ 7a355943cSVikas Chaudhary 8a355943cSVikas Chaudhary #include "ql4_def.h" 9a355943cSVikas Chaudhary #include "ql4_glbl.h" 10a355943cSVikas Chaudhary #include "ql4_bsg.h" 11a355943cSVikas Chaudhary 12a355943cSVikas Chaudhary static int 13a355943cSVikas Chaudhary qla4xxx_read_flash(struct bsg_job *bsg_job) 14a355943cSVikas Chaudhary { 15a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 16a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 17a355943cSVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 18a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 19a355943cSVikas Chaudhary uint32_t offset = 0; 20a355943cSVikas Chaudhary uint32_t length = 0; 21a355943cSVikas Chaudhary dma_addr_t flash_dma; 22a355943cSVikas Chaudhary uint8_t *flash = NULL; 23ef7830bbSHarish Zunjarrao int rval = -EINVAL; 24a355943cSVikas Chaudhary 25a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0; 26a355943cSVikas Chaudhary 27a355943cSVikas Chaudhary if (unlikely(pci_channel_offline(ha->pdev))) 28ef7830bbSHarish Zunjarrao goto leave; 29a355943cSVikas Chaudhary 30ef7830bbSHarish Zunjarrao if (ql4xxx_reset_active(ha)) { 31ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 32ef7830bbSHarish Zunjarrao rval = -EBUSY; 33ef7830bbSHarish Zunjarrao goto leave; 34a355943cSVikas Chaudhary } 35a355943cSVikas Chaudhary 36ef7830bbSHarish Zunjarrao if (ha->flash_state != QLFLASH_WAITING) { 37ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: another flash operation " 38ef7830bbSHarish Zunjarrao "active\n", __func__); 39ef7830bbSHarish Zunjarrao rval = -EBUSY; 40ef7830bbSHarish Zunjarrao goto leave; 41ef7830bbSHarish Zunjarrao } 42ef7830bbSHarish Zunjarrao 43ef7830bbSHarish Zunjarrao ha->flash_state = QLFLASH_READING; 44a355943cSVikas Chaudhary offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 45a355943cSVikas Chaudhary length = bsg_job->reply_payload.payload_len; 46a355943cSVikas Chaudhary 47a355943cSVikas Chaudhary flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma, 48a355943cSVikas Chaudhary GFP_KERNEL); 49a355943cSVikas Chaudhary if (!flash) { 50a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " 51a355943cSVikas Chaudhary "data\n", __func__); 52a355943cSVikas Chaudhary rval = -ENOMEM; 53ef7830bbSHarish Zunjarrao goto leave; 54a355943cSVikas Chaudhary } 55a355943cSVikas Chaudhary 56ef7830bbSHarish Zunjarrao rval = qla4xxx_get_flash(ha, flash_dma, offset, length); 57ef7830bbSHarish Zunjarrao if (rval) { 58ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: get flash failed\n", __func__); 59ef7830bbSHarish Zunjarrao bsg_reply->result = DID_ERROR << 16; 60ef7830bbSHarish Zunjarrao rval = -EIO; 61ef7830bbSHarish Zunjarrao } else { 62ef7830bbSHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 63a355943cSVikas Chaudhary sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 64a355943cSVikas Chaudhary bsg_job->reply_payload.sg_cnt, 65a355943cSVikas Chaudhary flash, length); 66ef7830bbSHarish Zunjarrao bsg_reply->result = DID_OK << 16; 67a355943cSVikas Chaudhary } 68a355943cSVikas Chaudhary 69a355943cSVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result, 70a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len); 71ef7830bbSHarish Zunjarrao dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma); 72ef7830bbSHarish Zunjarrao leave: 73ef7830bbSHarish Zunjarrao ha->flash_state = QLFLASH_WAITING; 74a355943cSVikas Chaudhary return rval; 75a355943cSVikas Chaudhary } 76a355943cSVikas Chaudhary 77a355943cSVikas Chaudhary static int 78a355943cSVikas Chaudhary qla4xxx_update_flash(struct bsg_job *bsg_job) 79a355943cSVikas Chaudhary { 80a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 81a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 82a355943cSVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 83a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 84a355943cSVikas Chaudhary uint32_t length = 0; 85a355943cSVikas Chaudhary uint32_t offset = 0; 86a355943cSVikas Chaudhary uint32_t options = 0; 87a355943cSVikas Chaudhary dma_addr_t flash_dma; 88a355943cSVikas Chaudhary uint8_t *flash = NULL; 89ef7830bbSHarish Zunjarrao int rval = -EINVAL; 90a355943cSVikas Chaudhary 91a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0; 92a355943cSVikas Chaudhary 93a355943cSVikas Chaudhary if (unlikely(pci_channel_offline(ha->pdev))) 94ef7830bbSHarish Zunjarrao goto leave; 95a355943cSVikas Chaudhary 96ef7830bbSHarish Zunjarrao if (ql4xxx_reset_active(ha)) { 97ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 98ef7830bbSHarish Zunjarrao rval = -EBUSY; 99ef7830bbSHarish Zunjarrao goto leave; 100a355943cSVikas Chaudhary } 101a355943cSVikas Chaudhary 102ef7830bbSHarish Zunjarrao if (ha->flash_state != QLFLASH_WAITING) { 103ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: another flash operation " 104ef7830bbSHarish Zunjarrao "active\n", __func__); 105ef7830bbSHarish Zunjarrao rval = -EBUSY; 106ef7830bbSHarish Zunjarrao goto leave; 107ef7830bbSHarish Zunjarrao } 108ef7830bbSHarish Zunjarrao 109ef7830bbSHarish Zunjarrao ha->flash_state = QLFLASH_WRITING; 110a355943cSVikas Chaudhary length = bsg_job->request_payload.payload_len; 111a355943cSVikas Chaudhary offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 112a355943cSVikas Chaudhary options = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; 113a355943cSVikas Chaudhary 114a355943cSVikas Chaudhary flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma, 115a355943cSVikas Chaudhary GFP_KERNEL); 116a355943cSVikas Chaudhary if (!flash) { 117a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " 118a355943cSVikas Chaudhary "data\n", __func__); 119a355943cSVikas Chaudhary rval = -ENOMEM; 120ef7830bbSHarish Zunjarrao goto leave; 121a355943cSVikas Chaudhary } 122a355943cSVikas Chaudhary 123a355943cSVikas Chaudhary sg_copy_to_buffer(bsg_job->request_payload.sg_list, 124a355943cSVikas Chaudhary bsg_job->request_payload.sg_cnt, flash, length); 125a355943cSVikas Chaudhary 126ef7830bbSHarish Zunjarrao rval = qla4xxx_set_flash(ha, flash_dma, offset, length, options); 127ef7830bbSHarish Zunjarrao if (rval) { 128ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: set flash failed\n", __func__); 129ef7830bbSHarish Zunjarrao bsg_reply->result = DID_ERROR << 16; 130ef7830bbSHarish Zunjarrao rval = -EIO; 131ef7830bbSHarish Zunjarrao } else 132ef7830bbSHarish Zunjarrao bsg_reply->result = DID_OK << 16; 133a355943cSVikas Chaudhary 134a355943cSVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result, 135a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len); 136ef7830bbSHarish Zunjarrao dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma); 137ef7830bbSHarish Zunjarrao leave: 138ef7830bbSHarish Zunjarrao ha->flash_state = QLFLASH_WAITING; 139a355943cSVikas Chaudhary return rval; 140a355943cSVikas Chaudhary } 141a355943cSVikas Chaudhary 1428b0402e1SHarish Zunjarrao static int 1438b0402e1SHarish Zunjarrao qla4xxx_get_acb_state(struct bsg_job *bsg_job) 1448b0402e1SHarish Zunjarrao { 1458b0402e1SHarish Zunjarrao struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 1468b0402e1SHarish Zunjarrao struct scsi_qla_host *ha = to_qla_host(host); 1478b0402e1SHarish Zunjarrao struct iscsi_bsg_request *bsg_req = bsg_job->request; 1488b0402e1SHarish Zunjarrao struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 1498b0402e1SHarish Zunjarrao uint32_t status[MBOX_REG_COUNT]; 1508b0402e1SHarish Zunjarrao uint32_t acb_idx; 1518b0402e1SHarish Zunjarrao uint32_t ip_idx; 1528b0402e1SHarish Zunjarrao int rval = -EINVAL; 1538b0402e1SHarish Zunjarrao 1548b0402e1SHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 0; 1558b0402e1SHarish Zunjarrao 1568b0402e1SHarish Zunjarrao if (unlikely(pci_channel_offline(ha->pdev))) 1578b0402e1SHarish Zunjarrao goto leave; 1588b0402e1SHarish Zunjarrao 1598b0402e1SHarish Zunjarrao /* Only 4022 and above adapters are supported */ 1608b0402e1SHarish Zunjarrao if (is_qla4010(ha)) 1618b0402e1SHarish Zunjarrao goto leave; 1628b0402e1SHarish Zunjarrao 1638b0402e1SHarish Zunjarrao if (ql4xxx_reset_active(ha)) { 1648b0402e1SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 1658b0402e1SHarish Zunjarrao rval = -EBUSY; 1668b0402e1SHarish Zunjarrao goto leave; 1678b0402e1SHarish Zunjarrao } 1688b0402e1SHarish Zunjarrao 1698b0402e1SHarish Zunjarrao if (bsg_job->reply_payload.payload_len < sizeof(status)) { 1708b0402e1SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: invalid payload len %d\n", 1718b0402e1SHarish Zunjarrao __func__, bsg_job->reply_payload.payload_len); 1728b0402e1SHarish Zunjarrao rval = -EINVAL; 1738b0402e1SHarish Zunjarrao goto leave; 1748b0402e1SHarish Zunjarrao } 1758b0402e1SHarish Zunjarrao 1768b0402e1SHarish Zunjarrao acb_idx = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 1778b0402e1SHarish Zunjarrao ip_idx = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; 1788b0402e1SHarish Zunjarrao 1798b0402e1SHarish Zunjarrao rval = qla4xxx_get_ip_state(ha, acb_idx, ip_idx, status); 1808b0402e1SHarish Zunjarrao if (rval) { 1818b0402e1SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: get ip state failed\n", 1828b0402e1SHarish Zunjarrao __func__); 1838b0402e1SHarish Zunjarrao bsg_reply->result = DID_ERROR << 16; 1848b0402e1SHarish Zunjarrao rval = -EIO; 1858b0402e1SHarish Zunjarrao } else { 1868b0402e1SHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 1878b0402e1SHarish Zunjarrao sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 1888b0402e1SHarish Zunjarrao bsg_job->reply_payload.sg_cnt, 1898b0402e1SHarish Zunjarrao status, sizeof(status)); 1908b0402e1SHarish Zunjarrao bsg_reply->result = DID_OK << 16; 1918b0402e1SHarish Zunjarrao } 1928b0402e1SHarish Zunjarrao 1938b0402e1SHarish Zunjarrao bsg_job_done(bsg_job, bsg_reply->result, 1948b0402e1SHarish Zunjarrao bsg_reply->reply_payload_rcv_len); 1958b0402e1SHarish Zunjarrao leave: 1968b0402e1SHarish Zunjarrao return rval; 1978b0402e1SHarish Zunjarrao } 1988b0402e1SHarish Zunjarrao 1997c07d139SHarish Zunjarrao static int 2007c07d139SHarish Zunjarrao qla4xxx_read_nvram(struct bsg_job *bsg_job) 2017c07d139SHarish Zunjarrao { 2027c07d139SHarish Zunjarrao struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 2037c07d139SHarish Zunjarrao struct scsi_qla_host *ha = to_qla_host(host); 2047c07d139SHarish Zunjarrao struct iscsi_bsg_request *bsg_req = bsg_job->request; 2057c07d139SHarish Zunjarrao struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 2067c07d139SHarish Zunjarrao uint32_t offset = 0; 2077c07d139SHarish Zunjarrao uint32_t len = 0; 2087c07d139SHarish Zunjarrao uint32_t total_len = 0; 2097c07d139SHarish Zunjarrao dma_addr_t nvram_dma; 2107c07d139SHarish Zunjarrao uint8_t *nvram = NULL; 2117c07d139SHarish Zunjarrao int rval = -EINVAL; 2127c07d139SHarish Zunjarrao 2137c07d139SHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 0; 2147c07d139SHarish Zunjarrao 2157c07d139SHarish Zunjarrao if (unlikely(pci_channel_offline(ha->pdev))) 2167c07d139SHarish Zunjarrao goto leave; 2177c07d139SHarish Zunjarrao 2187c07d139SHarish Zunjarrao /* Only 40xx adapters are supported */ 2197c07d139SHarish Zunjarrao if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha))) 2207c07d139SHarish Zunjarrao goto leave; 2217c07d139SHarish Zunjarrao 2227c07d139SHarish Zunjarrao if (ql4xxx_reset_active(ha)) { 2237c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 2247c07d139SHarish Zunjarrao rval = -EBUSY; 2257c07d139SHarish Zunjarrao goto leave; 2267c07d139SHarish Zunjarrao } 2277c07d139SHarish Zunjarrao 2287c07d139SHarish Zunjarrao offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 2297c07d139SHarish Zunjarrao len = bsg_job->reply_payload.payload_len; 2307c07d139SHarish Zunjarrao total_len = offset + len; 2317c07d139SHarish Zunjarrao 2327c07d139SHarish Zunjarrao /* total len should not be greater than max NVRAM size */ 2337c07d139SHarish Zunjarrao if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) || 2347c07d139SHarish Zunjarrao ((is_qla4022(ha) || is_qla4032(ha)) && 2357c07d139SHarish Zunjarrao total_len > QL40X2_NVRAM_SIZE)) { 2367c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max" 2377c07d139SHarish Zunjarrao " nvram size, offset=%d len=%d\n", 2387c07d139SHarish Zunjarrao __func__, offset, len); 2397c07d139SHarish Zunjarrao goto leave; 2407c07d139SHarish Zunjarrao } 2417c07d139SHarish Zunjarrao 2427c07d139SHarish Zunjarrao nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma, 2437c07d139SHarish Zunjarrao GFP_KERNEL); 2447c07d139SHarish Zunjarrao if (!nvram) { 2457c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for nvram " 2467c07d139SHarish Zunjarrao "data\n", __func__); 2477c07d139SHarish Zunjarrao rval = -ENOMEM; 2487c07d139SHarish Zunjarrao goto leave; 2497c07d139SHarish Zunjarrao } 2507c07d139SHarish Zunjarrao 2517c07d139SHarish Zunjarrao rval = qla4xxx_get_nvram(ha, nvram_dma, offset, len); 2527c07d139SHarish Zunjarrao if (rval) { 2537c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: get nvram failed\n", __func__); 2547c07d139SHarish Zunjarrao bsg_reply->result = DID_ERROR << 16; 2557c07d139SHarish Zunjarrao rval = -EIO; 2567c07d139SHarish Zunjarrao } else { 2577c07d139SHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 2587c07d139SHarish Zunjarrao sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 2597c07d139SHarish Zunjarrao bsg_job->reply_payload.sg_cnt, 2607c07d139SHarish Zunjarrao nvram, len); 2617c07d139SHarish Zunjarrao bsg_reply->result = DID_OK << 16; 2627c07d139SHarish Zunjarrao } 2637c07d139SHarish Zunjarrao 2647c07d139SHarish Zunjarrao bsg_job_done(bsg_job, bsg_reply->result, 2657c07d139SHarish Zunjarrao bsg_reply->reply_payload_rcv_len); 2667c07d139SHarish Zunjarrao dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma); 2677c07d139SHarish Zunjarrao leave: 2687c07d139SHarish Zunjarrao return rval; 2697c07d139SHarish Zunjarrao } 2707c07d139SHarish Zunjarrao 2717c07d139SHarish Zunjarrao static int 2727c07d139SHarish Zunjarrao qla4xxx_update_nvram(struct bsg_job *bsg_job) 2737c07d139SHarish Zunjarrao { 2747c07d139SHarish Zunjarrao struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 2757c07d139SHarish Zunjarrao struct scsi_qla_host *ha = to_qla_host(host); 2767c07d139SHarish Zunjarrao struct iscsi_bsg_request *bsg_req = bsg_job->request; 2777c07d139SHarish Zunjarrao struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 2787c07d139SHarish Zunjarrao uint32_t offset = 0; 2797c07d139SHarish Zunjarrao uint32_t len = 0; 2807c07d139SHarish Zunjarrao uint32_t total_len = 0; 2817c07d139SHarish Zunjarrao dma_addr_t nvram_dma; 2827c07d139SHarish Zunjarrao uint8_t *nvram = NULL; 2837c07d139SHarish Zunjarrao int rval = -EINVAL; 2847c07d139SHarish Zunjarrao 2857c07d139SHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 0; 2867c07d139SHarish Zunjarrao 2877c07d139SHarish Zunjarrao if (unlikely(pci_channel_offline(ha->pdev))) 2887c07d139SHarish Zunjarrao goto leave; 2897c07d139SHarish Zunjarrao 2907c07d139SHarish Zunjarrao if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha))) 2917c07d139SHarish Zunjarrao goto leave; 2927c07d139SHarish Zunjarrao 2937c07d139SHarish Zunjarrao if (ql4xxx_reset_active(ha)) { 2947c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 2957c07d139SHarish Zunjarrao rval = -EBUSY; 2967c07d139SHarish Zunjarrao goto leave; 2977c07d139SHarish Zunjarrao } 2987c07d139SHarish Zunjarrao 2997c07d139SHarish Zunjarrao offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 3007c07d139SHarish Zunjarrao len = bsg_job->request_payload.payload_len; 3017c07d139SHarish Zunjarrao total_len = offset + len; 3027c07d139SHarish Zunjarrao 3037c07d139SHarish Zunjarrao /* total len should not be greater than max NVRAM size */ 3047c07d139SHarish Zunjarrao if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) || 3057c07d139SHarish Zunjarrao ((is_qla4022(ha) || is_qla4032(ha)) && 3067c07d139SHarish Zunjarrao total_len > QL40X2_NVRAM_SIZE)) { 3077c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max" 3087c07d139SHarish Zunjarrao " nvram size, offset=%d len=%d\n", 3097c07d139SHarish Zunjarrao __func__, offset, len); 3107c07d139SHarish Zunjarrao goto leave; 3117c07d139SHarish Zunjarrao } 3127c07d139SHarish Zunjarrao 3137c07d139SHarish Zunjarrao nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma, 3147c07d139SHarish Zunjarrao GFP_KERNEL); 3157c07d139SHarish Zunjarrao if (!nvram) { 3167c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " 3177c07d139SHarish Zunjarrao "data\n", __func__); 3187c07d139SHarish Zunjarrao rval = -ENOMEM; 3197c07d139SHarish Zunjarrao goto leave; 3207c07d139SHarish Zunjarrao } 3217c07d139SHarish Zunjarrao 3227c07d139SHarish Zunjarrao sg_copy_to_buffer(bsg_job->request_payload.sg_list, 3237c07d139SHarish Zunjarrao bsg_job->request_payload.sg_cnt, nvram, len); 3247c07d139SHarish Zunjarrao 3257c07d139SHarish Zunjarrao rval = qla4xxx_set_nvram(ha, nvram_dma, offset, len); 3267c07d139SHarish Zunjarrao if (rval) { 3277c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__); 3287c07d139SHarish Zunjarrao bsg_reply->result = DID_ERROR << 16; 3297c07d139SHarish Zunjarrao rval = -EIO; 3307c07d139SHarish Zunjarrao } else 3317c07d139SHarish Zunjarrao bsg_reply->result = DID_OK << 16; 3327c07d139SHarish Zunjarrao 3337c07d139SHarish Zunjarrao bsg_job_done(bsg_job, bsg_reply->result, 3347c07d139SHarish Zunjarrao bsg_reply->reply_payload_rcv_len); 3357c07d139SHarish Zunjarrao dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma); 3367c07d139SHarish Zunjarrao leave: 3377c07d139SHarish Zunjarrao return rval; 3387c07d139SHarish Zunjarrao } 3397c07d139SHarish Zunjarrao 3405232f801SHarish Zunjarrao static int 3415232f801SHarish Zunjarrao qla4xxx_restore_defaults(struct bsg_job *bsg_job) 3425232f801SHarish Zunjarrao { 3435232f801SHarish Zunjarrao struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 3445232f801SHarish Zunjarrao struct scsi_qla_host *ha = to_qla_host(host); 3455232f801SHarish Zunjarrao struct iscsi_bsg_request *bsg_req = bsg_job->request; 3465232f801SHarish Zunjarrao struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 3475232f801SHarish Zunjarrao uint32_t region = 0; 3485232f801SHarish Zunjarrao uint32_t field0 = 0; 3495232f801SHarish Zunjarrao uint32_t field1 = 0; 3505232f801SHarish Zunjarrao int rval = -EINVAL; 3515232f801SHarish Zunjarrao 3525232f801SHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 0; 3535232f801SHarish Zunjarrao 3545232f801SHarish Zunjarrao if (unlikely(pci_channel_offline(ha->pdev))) 3555232f801SHarish Zunjarrao goto leave; 3565232f801SHarish Zunjarrao 3575232f801SHarish Zunjarrao if (is_qla4010(ha)) 3585232f801SHarish Zunjarrao goto leave; 3595232f801SHarish Zunjarrao 3605232f801SHarish Zunjarrao if (ql4xxx_reset_active(ha)) { 3615232f801SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 3625232f801SHarish Zunjarrao rval = -EBUSY; 3635232f801SHarish Zunjarrao goto leave; 3645232f801SHarish Zunjarrao } 3655232f801SHarish Zunjarrao 3665232f801SHarish Zunjarrao region = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 3675232f801SHarish Zunjarrao field0 = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; 3685232f801SHarish Zunjarrao field1 = bsg_req->rqst_data.h_vendor.vendor_cmd[3]; 3695232f801SHarish Zunjarrao 3705232f801SHarish Zunjarrao rval = qla4xxx_restore_factory_defaults(ha, region, field0, field1); 3715232f801SHarish Zunjarrao if (rval) { 3725232f801SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__); 3735232f801SHarish Zunjarrao bsg_reply->result = DID_ERROR << 16; 3745232f801SHarish Zunjarrao rval = -EIO; 3755232f801SHarish Zunjarrao } else 3765232f801SHarish Zunjarrao bsg_reply->result = DID_OK << 16; 3775232f801SHarish Zunjarrao 3785232f801SHarish Zunjarrao bsg_job_done(bsg_job, bsg_reply->result, 3795232f801SHarish Zunjarrao bsg_reply->reply_payload_rcv_len); 3805232f801SHarish Zunjarrao leave: 3815232f801SHarish Zunjarrao return rval; 3825232f801SHarish Zunjarrao } 3835232f801SHarish Zunjarrao 3846085491cSHarish Zunjarrao static int 3856085491cSHarish Zunjarrao qla4xxx_bsg_get_acb(struct bsg_job *bsg_job) 3866085491cSHarish Zunjarrao { 3876085491cSHarish Zunjarrao struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 3886085491cSHarish Zunjarrao struct scsi_qla_host *ha = to_qla_host(host); 3896085491cSHarish Zunjarrao struct iscsi_bsg_request *bsg_req = bsg_job->request; 3906085491cSHarish Zunjarrao struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 3916085491cSHarish Zunjarrao uint32_t acb_type = 0; 3926085491cSHarish Zunjarrao uint32_t len = 0; 3936085491cSHarish Zunjarrao dma_addr_t acb_dma; 3946085491cSHarish Zunjarrao uint8_t *acb = NULL; 3956085491cSHarish Zunjarrao int rval = -EINVAL; 3966085491cSHarish Zunjarrao 3976085491cSHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 0; 3986085491cSHarish Zunjarrao 3996085491cSHarish Zunjarrao if (unlikely(pci_channel_offline(ha->pdev))) 4006085491cSHarish Zunjarrao goto leave; 4016085491cSHarish Zunjarrao 4026085491cSHarish Zunjarrao /* Only 4022 and above adapters are supported */ 4036085491cSHarish Zunjarrao if (is_qla4010(ha)) 4046085491cSHarish Zunjarrao goto leave; 4056085491cSHarish Zunjarrao 4066085491cSHarish Zunjarrao if (ql4xxx_reset_active(ha)) { 4076085491cSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); 4086085491cSHarish Zunjarrao rval = -EBUSY; 4096085491cSHarish Zunjarrao goto leave; 4106085491cSHarish Zunjarrao } 4116085491cSHarish Zunjarrao 4126085491cSHarish Zunjarrao acb_type = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 4136085491cSHarish Zunjarrao len = bsg_job->reply_payload.payload_len; 4146085491cSHarish Zunjarrao if (len < sizeof(struct addr_ctrl_blk)) { 4156085491cSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: invalid acb len %d\n", 4166085491cSHarish Zunjarrao __func__, len); 4176085491cSHarish Zunjarrao rval = -EINVAL; 4186085491cSHarish Zunjarrao goto leave; 4196085491cSHarish Zunjarrao } 4206085491cSHarish Zunjarrao 4216085491cSHarish Zunjarrao acb = dma_alloc_coherent(&ha->pdev->dev, len, &acb_dma, GFP_KERNEL); 4226085491cSHarish Zunjarrao if (!acb) { 4236085491cSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for acb " 4246085491cSHarish Zunjarrao "data\n", __func__); 4256085491cSHarish Zunjarrao rval = -ENOMEM; 4266085491cSHarish Zunjarrao goto leave; 4276085491cSHarish Zunjarrao } 4286085491cSHarish Zunjarrao 4296085491cSHarish Zunjarrao rval = qla4xxx_get_acb(ha, acb_dma, acb_type, len); 4306085491cSHarish Zunjarrao if (rval) { 4316085491cSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: get acb failed\n", __func__); 4326085491cSHarish Zunjarrao bsg_reply->result = DID_ERROR << 16; 4336085491cSHarish Zunjarrao rval = -EIO; 4346085491cSHarish Zunjarrao } else { 4356085491cSHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 4366085491cSHarish Zunjarrao sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 4376085491cSHarish Zunjarrao bsg_job->reply_payload.sg_cnt, 4386085491cSHarish Zunjarrao acb, len); 4396085491cSHarish Zunjarrao bsg_reply->result = DID_OK << 16; 4406085491cSHarish Zunjarrao } 4416085491cSHarish Zunjarrao 4426085491cSHarish Zunjarrao bsg_job_done(bsg_job, bsg_reply->result, 4436085491cSHarish Zunjarrao bsg_reply->reply_payload_rcv_len); 4446085491cSHarish Zunjarrao dma_free_coherent(&ha->pdev->dev, len, acb, acb_dma); 4456085491cSHarish Zunjarrao leave: 4466085491cSHarish Zunjarrao return rval; 4476085491cSHarish Zunjarrao } 4486085491cSHarish Zunjarrao 449df86f771SVikas Chaudhary static void ql4xxx_execute_diag_cmd(struct bsg_job *bsg_job) 450df86f771SVikas Chaudhary { 451df86f771SVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 452df86f771SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 453df86f771SVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 454df86f771SVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 455df86f771SVikas Chaudhary uint8_t *rsp_ptr = NULL; 456df86f771SVikas Chaudhary uint32_t mbox_cmd[MBOX_REG_COUNT]; 457df86f771SVikas Chaudhary uint32_t mbox_sts[MBOX_REG_COUNT]; 458df86f771SVikas Chaudhary int status = QLA_ERROR; 459df86f771SVikas Chaudhary 460df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__)); 461df86f771SVikas Chaudhary 462df86f771SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 463df86f771SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: Adapter reset in progress. Invalid Request\n", 464df86f771SVikas Chaudhary __func__); 465df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16; 466df86f771SVikas Chaudhary goto exit_diag_mem_test; 467df86f771SVikas Chaudhary } 468df86f771SVikas Chaudhary 469df86f771SVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0; 470df86f771SVikas Chaudhary memcpy(mbox_cmd, &bsg_req->rqst_data.h_vendor.vendor_cmd[1], 471df86f771SVikas Chaudhary sizeof(uint32_t) * MBOX_REG_COUNT); 472df86f771SVikas Chaudhary 473df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 474df86f771SVikas Chaudhary "%s: mbox_cmd: %08X %08X %08X %08X %08X %08X %08X %08X\n", 475df86f771SVikas Chaudhary __func__, mbox_cmd[0], mbox_cmd[1], mbox_cmd[2], 476df86f771SVikas Chaudhary mbox_cmd[3], mbox_cmd[4], mbox_cmd[5], mbox_cmd[6], 477df86f771SVikas Chaudhary mbox_cmd[7])); 478df86f771SVikas Chaudhary 479df86f771SVikas Chaudhary status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0], 480df86f771SVikas Chaudhary &mbox_sts[0]); 481df86f771SVikas Chaudhary 482df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 483df86f771SVikas Chaudhary "%s: mbox_sts: %08X %08X %08X %08X %08X %08X %08X %08X\n", 484df86f771SVikas Chaudhary __func__, mbox_sts[0], mbox_sts[1], mbox_sts[2], 485df86f771SVikas Chaudhary mbox_sts[3], mbox_sts[4], mbox_sts[5], mbox_sts[6], 486df86f771SVikas Chaudhary mbox_sts[7])); 487df86f771SVikas Chaudhary 488df86f771SVikas Chaudhary if (status == QLA_SUCCESS) 489df86f771SVikas Chaudhary bsg_reply->result = DID_OK << 16; 490df86f771SVikas Chaudhary else 491df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16; 492df86f771SVikas Chaudhary 493df86f771SVikas Chaudhary /* Send mbox_sts to application */ 494df86f771SVikas Chaudhary bsg_job->reply_len = sizeof(struct iscsi_bsg_reply) + sizeof(mbox_sts); 495df86f771SVikas Chaudhary rsp_ptr = ((uint8_t *)bsg_reply) + sizeof(struct iscsi_bsg_reply); 496df86f771SVikas Chaudhary memcpy(rsp_ptr, mbox_sts, sizeof(mbox_sts)); 497df86f771SVikas Chaudhary 498df86f771SVikas Chaudhary exit_diag_mem_test: 499df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 500df86f771SVikas Chaudhary "%s: bsg_reply->result = x%x, status = %s\n", 501df86f771SVikas Chaudhary __func__, bsg_reply->result, STATUS(status))); 502df86f771SVikas Chaudhary 503df86f771SVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result, 504df86f771SVikas Chaudhary bsg_reply->reply_payload_rcv_len); 505df86f771SVikas Chaudhary } 506df86f771SVikas Chaudhary 507df86f771SVikas Chaudhary static int qla4_83xx_wait_for_loopback_config_comp(struct scsi_qla_host *ha, 508df86f771SVikas Chaudhary int wait_for_link) 509df86f771SVikas Chaudhary { 510df86f771SVikas Chaudhary int status = QLA_SUCCESS; 511df86f771SVikas Chaudhary 512df86f771SVikas Chaudhary if (!wait_for_completion_timeout(&ha->idc_comp, (IDC_COMP_TOV * HZ))) { 513df86f771SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: IDC Complete notification not received, Waiting for another %d timeout", 514df86f771SVikas Chaudhary __func__, ha->idc_extend_tmo); 515df86f771SVikas Chaudhary if (ha->idc_extend_tmo) { 516df86f771SVikas Chaudhary if (!wait_for_completion_timeout(&ha->idc_comp, 517df86f771SVikas Chaudhary (ha->idc_extend_tmo * HZ))) { 518df86f771SVikas Chaudhary ha->notify_idc_comp = 0; 519df86f771SVikas Chaudhary ha->notify_link_up_comp = 0; 52056ccb988SNilesh Javali ql4_printk(KERN_WARNING, ha, "%s: Aborting: IDC Complete notification not received", 521df86f771SVikas Chaudhary __func__); 522df86f771SVikas Chaudhary status = QLA_ERROR; 523df86f771SVikas Chaudhary goto exit_wait; 524df86f771SVikas Chaudhary } else { 525df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 526df86f771SVikas Chaudhary "%s: IDC Complete notification received\n", 527df86f771SVikas Chaudhary __func__)); 528df86f771SVikas Chaudhary } 529df86f771SVikas Chaudhary } 530df86f771SVikas Chaudhary } else { 531df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 532df86f771SVikas Chaudhary "%s: IDC Complete notification received\n", 533df86f771SVikas Chaudhary __func__)); 534df86f771SVikas Chaudhary } 535df86f771SVikas Chaudhary ha->notify_idc_comp = 0; 536df86f771SVikas Chaudhary 537df86f771SVikas Chaudhary if (wait_for_link) { 538df86f771SVikas Chaudhary if (!wait_for_completion_timeout(&ha->link_up_comp, 539df86f771SVikas Chaudhary (IDC_COMP_TOV * HZ))) { 540df86f771SVikas Chaudhary ha->notify_link_up_comp = 0; 54156ccb988SNilesh Javali ql4_printk(KERN_WARNING, ha, "%s: Aborting: LINK UP notification not received", 542df86f771SVikas Chaudhary __func__); 543df86f771SVikas Chaudhary status = QLA_ERROR; 544df86f771SVikas Chaudhary goto exit_wait; 545df86f771SVikas Chaudhary } else { 546df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 547df86f771SVikas Chaudhary "%s: LINK UP notification received\n", 548df86f771SVikas Chaudhary __func__)); 549df86f771SVikas Chaudhary } 550df86f771SVikas Chaudhary ha->notify_link_up_comp = 0; 551df86f771SVikas Chaudhary } 552df86f771SVikas Chaudhary 553df86f771SVikas Chaudhary exit_wait: 554df86f771SVikas Chaudhary return status; 555df86f771SVikas Chaudhary } 556df86f771SVikas Chaudhary 557df86f771SVikas Chaudhary static int qla4_83xx_pre_loopback_config(struct scsi_qla_host *ha, 558df86f771SVikas Chaudhary uint32_t *mbox_cmd) 559df86f771SVikas Chaudhary { 560df86f771SVikas Chaudhary uint32_t config = 0; 561df86f771SVikas Chaudhary int status = QLA_SUCCESS; 562df86f771SVikas Chaudhary 563df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__)); 564df86f771SVikas Chaudhary 565df86f771SVikas Chaudhary status = qla4_83xx_get_port_config(ha, &config); 566df86f771SVikas Chaudhary if (status != QLA_SUCCESS) 567df86f771SVikas Chaudhary goto exit_pre_loopback_config; 568df86f771SVikas Chaudhary 569df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Default port config=%08X\n", 570df86f771SVikas Chaudhary __func__, config)); 571df86f771SVikas Chaudhary 572df86f771SVikas Chaudhary if ((config & ENABLE_INTERNAL_LOOPBACK) || 573df86f771SVikas Chaudhary (config & ENABLE_EXTERNAL_LOOPBACK)) { 5748c519319SMasanari Iida ql4_printk(KERN_INFO, ha, "%s: Loopback diagnostics already in progress. Invalid request\n", 575df86f771SVikas Chaudhary __func__); 576df86f771SVikas Chaudhary goto exit_pre_loopback_config; 577df86f771SVikas Chaudhary } 578df86f771SVikas Chaudhary 579df86f771SVikas Chaudhary if (mbox_cmd[1] == QL_DIAG_CMD_TEST_INT_LOOPBACK) 580df86f771SVikas Chaudhary config |= ENABLE_INTERNAL_LOOPBACK; 581df86f771SVikas Chaudhary 582df86f771SVikas Chaudhary if (mbox_cmd[1] == QL_DIAG_CMD_TEST_EXT_LOOPBACK) 583df86f771SVikas Chaudhary config |= ENABLE_EXTERNAL_LOOPBACK; 584df86f771SVikas Chaudhary 585df86f771SVikas Chaudhary config &= ~ENABLE_DCBX; 586df86f771SVikas Chaudhary 587df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: New port config=%08X\n", 588df86f771SVikas Chaudhary __func__, config)); 589df86f771SVikas Chaudhary 590df86f771SVikas Chaudhary ha->notify_idc_comp = 1; 591df86f771SVikas Chaudhary ha->notify_link_up_comp = 1; 592df86f771SVikas Chaudhary 593df86f771SVikas Chaudhary /* get the link state */ 594df86f771SVikas Chaudhary qla4xxx_get_firmware_state(ha); 595df86f771SVikas Chaudhary 596df86f771SVikas Chaudhary status = qla4_83xx_set_port_config(ha, &config); 597df86f771SVikas Chaudhary if (status != QLA_SUCCESS) { 598df86f771SVikas Chaudhary ha->notify_idc_comp = 0; 599df86f771SVikas Chaudhary ha->notify_link_up_comp = 0; 600df86f771SVikas Chaudhary goto exit_pre_loopback_config; 601df86f771SVikas Chaudhary } 602df86f771SVikas Chaudhary exit_pre_loopback_config: 603df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: status = %s\n", __func__, 604df86f771SVikas Chaudhary STATUS(status))); 605df86f771SVikas Chaudhary return status; 606df86f771SVikas Chaudhary } 607df86f771SVikas Chaudhary 608df86f771SVikas Chaudhary static int qla4_83xx_post_loopback_config(struct scsi_qla_host *ha, 609df86f771SVikas Chaudhary uint32_t *mbox_cmd) 610df86f771SVikas Chaudhary { 611df86f771SVikas Chaudhary int status = QLA_SUCCESS; 612df86f771SVikas Chaudhary uint32_t config = 0; 613df86f771SVikas Chaudhary 614df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__)); 615df86f771SVikas Chaudhary 616df86f771SVikas Chaudhary status = qla4_83xx_get_port_config(ha, &config); 617df86f771SVikas Chaudhary if (status != QLA_SUCCESS) 618df86f771SVikas Chaudhary goto exit_post_loopback_config; 619df86f771SVikas Chaudhary 620df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: port config=%08X\n", __func__, 621df86f771SVikas Chaudhary config)); 622df86f771SVikas Chaudhary 623df86f771SVikas Chaudhary if (mbox_cmd[1] == QL_DIAG_CMD_TEST_INT_LOOPBACK) 624df86f771SVikas Chaudhary config &= ~ENABLE_INTERNAL_LOOPBACK; 625df86f771SVikas Chaudhary else if (mbox_cmd[1] == QL_DIAG_CMD_TEST_EXT_LOOPBACK) 626df86f771SVikas Chaudhary config &= ~ENABLE_EXTERNAL_LOOPBACK; 627df86f771SVikas Chaudhary 628df86f771SVikas Chaudhary config |= ENABLE_DCBX; 629df86f771SVikas Chaudhary 630df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 631df86f771SVikas Chaudhary "%s: Restore default port config=%08X\n", __func__, 632df86f771SVikas Chaudhary config)); 633df86f771SVikas Chaudhary 634df86f771SVikas Chaudhary ha->notify_idc_comp = 1; 635df86f771SVikas Chaudhary if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) 636df86f771SVikas Chaudhary ha->notify_link_up_comp = 1; 637df86f771SVikas Chaudhary 638df86f771SVikas Chaudhary status = qla4_83xx_set_port_config(ha, &config); 639df86f771SVikas Chaudhary if (status != QLA_SUCCESS) { 640df86f771SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: Scheduling adapter reset\n", 641df86f771SVikas Chaudhary __func__); 642df86f771SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 643df86f771SVikas Chaudhary clear_bit(AF_LOOPBACK, &ha->flags); 644df86f771SVikas Chaudhary goto exit_post_loopback_config; 645df86f771SVikas Chaudhary } 646df86f771SVikas Chaudhary 647df86f771SVikas Chaudhary exit_post_loopback_config: 648df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: status = %s\n", __func__, 649df86f771SVikas Chaudhary STATUS(status))); 650df86f771SVikas Chaudhary return status; 651df86f771SVikas Chaudhary } 652df86f771SVikas Chaudhary 653df86f771SVikas Chaudhary static void qla4xxx_execute_diag_loopback_cmd(struct bsg_job *bsg_job) 654df86f771SVikas Chaudhary { 655df86f771SVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 656df86f771SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 657df86f771SVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 658df86f771SVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 659df86f771SVikas Chaudhary uint8_t *rsp_ptr = NULL; 660df86f771SVikas Chaudhary uint32_t mbox_cmd[MBOX_REG_COUNT]; 661df86f771SVikas Chaudhary uint32_t mbox_sts[MBOX_REG_COUNT]; 662df86f771SVikas Chaudhary int wait_for_link = 1; 663df86f771SVikas Chaudhary int status = QLA_ERROR; 664df86f771SVikas Chaudhary 665df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__)); 666df86f771SVikas Chaudhary 667df86f771SVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0; 668df86f771SVikas Chaudhary 669df86f771SVikas Chaudhary if (test_bit(AF_LOOPBACK, &ha->flags)) { 670df86f771SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: Loopback Diagnostics already in progress. Invalid Request\n", 671df86f771SVikas Chaudhary __func__); 672df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16; 673df86f771SVikas Chaudhary goto exit_loopback_cmd; 674df86f771SVikas Chaudhary } 675df86f771SVikas Chaudhary 676df86f771SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 677df86f771SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: Adapter reset in progress. Invalid Request\n", 678df86f771SVikas Chaudhary __func__); 679df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16; 680df86f771SVikas Chaudhary goto exit_loopback_cmd; 681df86f771SVikas Chaudhary } 682df86f771SVikas Chaudhary 683df86f771SVikas Chaudhary memcpy(mbox_cmd, &bsg_req->rqst_data.h_vendor.vendor_cmd[1], 684df86f771SVikas Chaudhary sizeof(uint32_t) * MBOX_REG_COUNT); 685df86f771SVikas Chaudhary 686df86f771SVikas Chaudhary if (is_qla8032(ha) || is_qla8042(ha)) { 687df86f771SVikas Chaudhary status = qla4_83xx_pre_loopback_config(ha, mbox_cmd); 688df86f771SVikas Chaudhary if (status != QLA_SUCCESS) { 689df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16; 690df86f771SVikas Chaudhary goto exit_loopback_cmd; 691df86f771SVikas Chaudhary } 692df86f771SVikas Chaudhary 693df86f771SVikas Chaudhary status = qla4_83xx_wait_for_loopback_config_comp(ha, 694df86f771SVikas Chaudhary wait_for_link); 695df86f771SVikas Chaudhary if (status != QLA_SUCCESS) { 696df86f771SVikas Chaudhary bsg_reply->result = DID_TIME_OUT << 16; 697df86f771SVikas Chaudhary goto restore; 698df86f771SVikas Chaudhary } 699df86f771SVikas Chaudhary } 700df86f771SVikas Chaudhary 701df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 702df86f771SVikas Chaudhary "%s: mbox_cmd: %08X %08X %08X %08X %08X %08X %08X %08X\n", 703df86f771SVikas Chaudhary __func__, mbox_cmd[0], mbox_cmd[1], mbox_cmd[2], 704df86f771SVikas Chaudhary mbox_cmd[3], mbox_cmd[4], mbox_cmd[5], mbox_cmd[6], 705df86f771SVikas Chaudhary mbox_cmd[7])); 706df86f771SVikas Chaudhary 707df86f771SVikas Chaudhary status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0], 708df86f771SVikas Chaudhary &mbox_sts[0]); 709df86f771SVikas Chaudhary 710df86f771SVikas Chaudhary if (status == QLA_SUCCESS) 711df86f771SVikas Chaudhary bsg_reply->result = DID_OK << 16; 712df86f771SVikas Chaudhary else 713df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16; 714df86f771SVikas Chaudhary 715df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 716df86f771SVikas Chaudhary "%s: mbox_sts: %08X %08X %08X %08X %08X %08X %08X %08X\n", 717df86f771SVikas Chaudhary __func__, mbox_sts[0], mbox_sts[1], mbox_sts[2], 718df86f771SVikas Chaudhary mbox_sts[3], mbox_sts[4], mbox_sts[5], mbox_sts[6], 719df86f771SVikas Chaudhary mbox_sts[7])); 720df86f771SVikas Chaudhary 721df86f771SVikas Chaudhary /* Send mbox_sts to application */ 722df86f771SVikas Chaudhary bsg_job->reply_len = sizeof(struct iscsi_bsg_reply) + sizeof(mbox_sts); 723df86f771SVikas Chaudhary rsp_ptr = ((uint8_t *)bsg_reply) + sizeof(struct iscsi_bsg_reply); 724df86f771SVikas Chaudhary memcpy(rsp_ptr, mbox_sts, sizeof(mbox_sts)); 725df86f771SVikas Chaudhary restore: 726df86f771SVikas Chaudhary if (is_qla8032(ha) || is_qla8042(ha)) { 727df86f771SVikas Chaudhary status = qla4_83xx_post_loopback_config(ha, mbox_cmd); 728df86f771SVikas Chaudhary if (status != QLA_SUCCESS) { 729df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16; 730df86f771SVikas Chaudhary goto exit_loopback_cmd; 731df86f771SVikas Chaudhary } 732df86f771SVikas Chaudhary 733df86f771SVikas Chaudhary /* for pre_loopback_config() wait for LINK UP only 734df86f771SVikas Chaudhary * if PHY LINK is UP */ 735df86f771SVikas Chaudhary if (!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP)) 736df86f771SVikas Chaudhary wait_for_link = 0; 737df86f771SVikas Chaudhary 738df86f771SVikas Chaudhary status = qla4_83xx_wait_for_loopback_config_comp(ha, 739df86f771SVikas Chaudhary wait_for_link); 740df86f771SVikas Chaudhary if (status != QLA_SUCCESS) { 741df86f771SVikas Chaudhary bsg_reply->result = DID_TIME_OUT << 16; 742df86f771SVikas Chaudhary goto exit_loopback_cmd; 743df86f771SVikas Chaudhary } 744df86f771SVikas Chaudhary } 745df86f771SVikas Chaudhary exit_loopback_cmd: 746df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 747df86f771SVikas Chaudhary "%s: bsg_reply->result = x%x, status = %s\n", 748df86f771SVikas Chaudhary __func__, bsg_reply->result, STATUS(status))); 749df86f771SVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result, 750df86f771SVikas Chaudhary bsg_reply->reply_payload_rcv_len); 751df86f771SVikas Chaudhary } 752df86f771SVikas Chaudhary 753df86f771SVikas Chaudhary static int qla4xxx_execute_diag_test(struct bsg_job *bsg_job) 754df86f771SVikas Chaudhary { 755df86f771SVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 756df86f771SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 757df86f771SVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 758df86f771SVikas Chaudhary uint32_t diag_cmd; 759df86f771SVikas Chaudhary int rval = -EINVAL; 760df86f771SVikas Chaudhary 761df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__)); 762df86f771SVikas Chaudhary 763df86f771SVikas Chaudhary diag_cmd = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; 764df86f771SVikas Chaudhary if (diag_cmd == MBOX_CMD_DIAG_TEST) { 765df86f771SVikas Chaudhary switch (bsg_req->rqst_data.h_vendor.vendor_cmd[2]) { 766df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_DDR_SIZE: 767df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_DDR_RW: 768df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_ONCHIP_MEM_RW: 769df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_NVRAM: 770df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_FLASH_ROM: 771df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_DMA_XFER: 772df86f771SVikas Chaudhary case QL_DIAG_CMD_SELF_DDR_RW: 773df86f771SVikas Chaudhary case QL_DIAG_CMD_SELF_ONCHIP_MEM_RW: 774df86f771SVikas Chaudhary /* Execute diag test for adapter RAM/FLASH */ 775df86f771SVikas Chaudhary ql4xxx_execute_diag_cmd(bsg_job); 776df86f771SVikas Chaudhary /* Always return success as we want to sent bsg_reply 777df86f771SVikas Chaudhary * to Application */ 778df86f771SVikas Chaudhary rval = QLA_SUCCESS; 779df86f771SVikas Chaudhary break; 780df86f771SVikas Chaudhary 781df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_INT_LOOPBACK: 782df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_EXT_LOOPBACK: 783df86f771SVikas Chaudhary /* Execute diag test for Network */ 784df86f771SVikas Chaudhary qla4xxx_execute_diag_loopback_cmd(bsg_job); 785df86f771SVikas Chaudhary /* Always return success as we want to sent bsg_reply 786df86f771SVikas Chaudhary * to Application */ 787df86f771SVikas Chaudhary rval = QLA_SUCCESS; 788df86f771SVikas Chaudhary break; 789df86f771SVikas Chaudhary default: 790df86f771SVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: Invalid diag test: 0x%x\n", 791df86f771SVikas Chaudhary __func__, 792df86f771SVikas Chaudhary bsg_req->rqst_data.h_vendor.vendor_cmd[2]); 793df86f771SVikas Chaudhary } 794df86f771SVikas Chaudhary } else if ((diag_cmd == MBOX_CMD_SET_LED_CONFIG) || 795df86f771SVikas Chaudhary (diag_cmd == MBOX_CMD_GET_LED_CONFIG)) { 796df86f771SVikas Chaudhary ql4xxx_execute_diag_cmd(bsg_job); 797df86f771SVikas Chaudhary rval = QLA_SUCCESS; 798df86f771SVikas Chaudhary } else { 799df86f771SVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: Invalid diag cmd: 0x%x\n", 800df86f771SVikas Chaudhary __func__, diag_cmd); 801df86f771SVikas Chaudhary } 802df86f771SVikas Chaudhary 803df86f771SVikas Chaudhary return rval; 804df86f771SVikas Chaudhary } 805df86f771SVikas Chaudhary 806a355943cSVikas Chaudhary /** 807a355943cSVikas Chaudhary * qla4xxx_process_vendor_specific - handle vendor specific bsg request 808a355943cSVikas Chaudhary * @job: iscsi_bsg_job to handle 809a355943cSVikas Chaudhary **/ 810a355943cSVikas Chaudhary int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job) 811a355943cSVikas Chaudhary { 812a355943cSVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 813a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 814a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 815a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 816a355943cSVikas Chaudhary 817a355943cSVikas Chaudhary switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) { 818a355943cSVikas Chaudhary case QLISCSI_VND_READ_FLASH: 819a355943cSVikas Chaudhary return qla4xxx_read_flash(bsg_job); 820a355943cSVikas Chaudhary 821a355943cSVikas Chaudhary case QLISCSI_VND_UPDATE_FLASH: 822a355943cSVikas Chaudhary return qla4xxx_update_flash(bsg_job); 823a355943cSVikas Chaudhary 8248b0402e1SHarish Zunjarrao case QLISCSI_VND_GET_ACB_STATE: 8258b0402e1SHarish Zunjarrao return qla4xxx_get_acb_state(bsg_job); 8268b0402e1SHarish Zunjarrao 8277c07d139SHarish Zunjarrao case QLISCSI_VND_READ_NVRAM: 8287c07d139SHarish Zunjarrao return qla4xxx_read_nvram(bsg_job); 8297c07d139SHarish Zunjarrao 8307c07d139SHarish Zunjarrao case QLISCSI_VND_UPDATE_NVRAM: 8317c07d139SHarish Zunjarrao return qla4xxx_update_nvram(bsg_job); 8327c07d139SHarish Zunjarrao 8335232f801SHarish Zunjarrao case QLISCSI_VND_RESTORE_DEFAULTS: 8345232f801SHarish Zunjarrao return qla4xxx_restore_defaults(bsg_job); 8355232f801SHarish Zunjarrao 8366085491cSHarish Zunjarrao case QLISCSI_VND_GET_ACB: 8376085491cSHarish Zunjarrao return qla4xxx_bsg_get_acb(bsg_job); 8386085491cSHarish Zunjarrao 839df86f771SVikas Chaudhary case QLISCSI_VND_DIAG_TEST: 840df86f771SVikas Chaudhary return qla4xxx_execute_diag_test(bsg_job); 841df86f771SVikas Chaudhary 842a355943cSVikas Chaudhary default: 843a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: " 844a355943cSVikas Chaudhary "0x%x\n", __func__, bsg_req->msgcode); 845a355943cSVikas Chaudhary bsg_reply->result = (DID_ERROR << 16); 846a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0; 847a355943cSVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result, 848a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len); 849a355943cSVikas Chaudhary return -ENOSYS; 850a355943cSVikas Chaudhary } 851a355943cSVikas Chaudhary } 852a355943cSVikas Chaudhary 853a355943cSVikas Chaudhary /** 854a355943cSVikas Chaudhary * qla4xxx_bsg_request - handle bsg request from ISCSI transport 855a355943cSVikas Chaudhary * @job: iscsi_bsg_job to handle 856a355943cSVikas Chaudhary */ 857a355943cSVikas Chaudhary int qla4xxx_bsg_request(struct bsg_job *bsg_job) 858a355943cSVikas Chaudhary { 859a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 860a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 861a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 862a355943cSVikas Chaudhary 863a355943cSVikas Chaudhary switch (bsg_req->msgcode) { 864a355943cSVikas Chaudhary case ISCSI_BSG_HST_VENDOR: 865a355943cSVikas Chaudhary return qla4xxx_process_vendor_specific(bsg_job); 866a355943cSVikas Chaudhary 867a355943cSVikas Chaudhary default: 868a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n", 869a355943cSVikas Chaudhary __func__, bsg_req->msgcode); 870a355943cSVikas Chaudhary } 871a355943cSVikas Chaudhary 872a355943cSVikas Chaudhary return -ENOSYS; 873a355943cSVikas Chaudhary } 874