1a355943cSVikas Chaudhary /* 2a355943cSVikas Chaudhary * QLogic iSCSI HBA Driver 3a355943cSVikas Chaudhary * Copyright (c) 2011 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 449a355943cSVikas Chaudhary /** 450a355943cSVikas Chaudhary * qla4xxx_process_vendor_specific - handle vendor specific bsg request 451a355943cSVikas Chaudhary * @job: iscsi_bsg_job to handle 452a355943cSVikas Chaudhary **/ 453a355943cSVikas Chaudhary int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job) 454a355943cSVikas Chaudhary { 455a355943cSVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 456a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 457a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 458a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 459a355943cSVikas Chaudhary 460a355943cSVikas Chaudhary switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) { 461a355943cSVikas Chaudhary case QLISCSI_VND_READ_FLASH: 462a355943cSVikas Chaudhary return qla4xxx_read_flash(bsg_job); 463a355943cSVikas Chaudhary 464a355943cSVikas Chaudhary case QLISCSI_VND_UPDATE_FLASH: 465a355943cSVikas Chaudhary return qla4xxx_update_flash(bsg_job); 466a355943cSVikas Chaudhary 4678b0402e1SHarish Zunjarrao case QLISCSI_VND_GET_ACB_STATE: 4688b0402e1SHarish Zunjarrao return qla4xxx_get_acb_state(bsg_job); 4698b0402e1SHarish Zunjarrao 4707c07d139SHarish Zunjarrao case QLISCSI_VND_READ_NVRAM: 4717c07d139SHarish Zunjarrao return qla4xxx_read_nvram(bsg_job); 4727c07d139SHarish Zunjarrao 4737c07d139SHarish Zunjarrao case QLISCSI_VND_UPDATE_NVRAM: 4747c07d139SHarish Zunjarrao return qla4xxx_update_nvram(bsg_job); 4757c07d139SHarish Zunjarrao 4765232f801SHarish Zunjarrao case QLISCSI_VND_RESTORE_DEFAULTS: 4775232f801SHarish Zunjarrao return qla4xxx_restore_defaults(bsg_job); 4785232f801SHarish Zunjarrao 4796085491cSHarish Zunjarrao case QLISCSI_VND_GET_ACB: 4806085491cSHarish Zunjarrao return qla4xxx_bsg_get_acb(bsg_job); 4816085491cSHarish Zunjarrao 482a355943cSVikas Chaudhary default: 483a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: " 484a355943cSVikas Chaudhary "0x%x\n", __func__, bsg_req->msgcode); 485a355943cSVikas Chaudhary bsg_reply->result = (DID_ERROR << 16); 486a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0; 487a355943cSVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result, 488a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len); 489a355943cSVikas Chaudhary return -ENOSYS; 490a355943cSVikas Chaudhary } 491a355943cSVikas Chaudhary } 492a355943cSVikas Chaudhary 493a355943cSVikas Chaudhary /** 494a355943cSVikas Chaudhary * qla4xxx_bsg_request - handle bsg request from ISCSI transport 495a355943cSVikas Chaudhary * @job: iscsi_bsg_job to handle 496a355943cSVikas Chaudhary */ 497a355943cSVikas Chaudhary int qla4xxx_bsg_request(struct bsg_job *bsg_job) 498a355943cSVikas Chaudhary { 499a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 500a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 501a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 502a355943cSVikas Chaudhary 503a355943cSVikas Chaudhary switch (bsg_req->msgcode) { 504a355943cSVikas Chaudhary case ISCSI_BSG_HST_VENDOR: 505a355943cSVikas Chaudhary return qla4xxx_process_vendor_specific(bsg_job); 506a355943cSVikas Chaudhary 507a355943cSVikas Chaudhary default: 508a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n", 509a355943cSVikas Chaudhary __func__, bsg_req->msgcode); 510a355943cSVikas Chaudhary } 511a355943cSVikas Chaudhary 512a355943cSVikas Chaudhary return -ENOSYS; 513a355943cSVikas Chaudhary } 514