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 142a355943cSVikas Chaudhary /** 143a355943cSVikas Chaudhary * qla4xxx_process_vendor_specific - handle vendor specific bsg request 144a355943cSVikas Chaudhary * @job: iscsi_bsg_job to handle 145a355943cSVikas Chaudhary **/ 146a355943cSVikas Chaudhary int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job) 147a355943cSVikas Chaudhary { 148a355943cSVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; 149a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 150a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 151a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 152a355943cSVikas Chaudhary 153a355943cSVikas Chaudhary switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) { 154a355943cSVikas Chaudhary case QLISCSI_VND_READ_FLASH: 155a355943cSVikas Chaudhary return qla4xxx_read_flash(bsg_job); 156a355943cSVikas Chaudhary 157a355943cSVikas Chaudhary case QLISCSI_VND_UPDATE_FLASH: 158a355943cSVikas Chaudhary return qla4xxx_update_flash(bsg_job); 159a355943cSVikas Chaudhary 160a355943cSVikas Chaudhary default: 161a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: " 162a355943cSVikas Chaudhary "0x%x\n", __func__, bsg_req->msgcode); 163a355943cSVikas Chaudhary bsg_reply->result = (DID_ERROR << 16); 164a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0; 165a355943cSVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result, 166a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len); 167a355943cSVikas Chaudhary return -ENOSYS; 168a355943cSVikas Chaudhary } 169a355943cSVikas Chaudhary } 170a355943cSVikas Chaudhary 171a355943cSVikas Chaudhary /** 172a355943cSVikas Chaudhary * qla4xxx_bsg_request - handle bsg request from ISCSI transport 173a355943cSVikas Chaudhary * @job: iscsi_bsg_job to handle 174a355943cSVikas Chaudhary */ 175a355943cSVikas Chaudhary int qla4xxx_bsg_request(struct bsg_job *bsg_job) 176a355943cSVikas Chaudhary { 177a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request; 178a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); 179a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 180a355943cSVikas Chaudhary 181a355943cSVikas Chaudhary switch (bsg_req->msgcode) { 182a355943cSVikas Chaudhary case ISCSI_BSG_HST_VENDOR: 183a355943cSVikas Chaudhary return qla4xxx_process_vendor_specific(bsg_job); 184a355943cSVikas Chaudhary 185a355943cSVikas Chaudhary default: 186a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n", 187a355943cSVikas Chaudhary __func__, bsg_req->msgcode); 188a355943cSVikas Chaudhary } 189a355943cSVikas Chaudhary 190a355943cSVikas Chaudhary return -ENOSYS; 191a355943cSVikas Chaudhary } 192