162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/scsi/esas2r/esas2r_vda.c 362306a36Sopenharmony_ci * esas2r driver VDA firmware interface functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2001-2013 ATTO Technology, Inc. 662306a36Sopenharmony_ci * (mailto:linuxdrivers@attotech.com) 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 1162306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 1262306a36Sopenharmony_ci * the Free Software Foundation; version 2 of the License. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful, 1562306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1662306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1762306a36Sopenharmony_ci * GNU General Public License for more details. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * NO WARRANTY 2062306a36Sopenharmony_ci * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 2162306a36Sopenharmony_ci * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 2262306a36Sopenharmony_ci * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 2362306a36Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 2462306a36Sopenharmony_ci * solely responsible for determining the appropriateness of using and 2562306a36Sopenharmony_ci * distributing the Program and assumes all risks associated with its 2662306a36Sopenharmony_ci * exercise of rights under this Agreement, including but not limited to 2762306a36Sopenharmony_ci * the risks and costs of program errors, damage to or loss of data, 2862306a36Sopenharmony_ci * programs or equipment, and unavailability or interruption of operations. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * DISCLAIMER OF LIABILITY 3162306a36Sopenharmony_ci * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 3262306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3362306a36Sopenharmony_ci * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 3462306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 3562306a36Sopenharmony_ci * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 3662306a36Sopenharmony_ci * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 3762306a36Sopenharmony_ci * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 4062306a36Sopenharmony_ci * along with this program; if not, write to the Free Software 4162306a36Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include "esas2r.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic u8 esas2r_vdaioctl_versions[] = { 4862306a36Sopenharmony_ci ATTO_VDA_VER_UNSUPPORTED, 4962306a36Sopenharmony_ci ATTO_VDA_FLASH_VER, 5062306a36Sopenharmony_ci ATTO_VDA_VER_UNSUPPORTED, 5162306a36Sopenharmony_ci ATTO_VDA_VER_UNSUPPORTED, 5262306a36Sopenharmony_ci ATTO_VDA_CLI_VER, 5362306a36Sopenharmony_ci ATTO_VDA_VER_UNSUPPORTED, 5462306a36Sopenharmony_ci ATTO_VDA_CFG_VER, 5562306a36Sopenharmony_ci ATTO_VDA_MGT_VER, 5662306a36Sopenharmony_ci ATTO_VDA_GSV_VER 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void clear_vda_request(struct esas2r_request *rq); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void esas2r_complete_vda_ioctl(struct esas2r_adapter *a, 6262306a36Sopenharmony_ci struct esas2r_request *rq); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Prepare a VDA IOCTL request to be sent to the firmware. */ 6562306a36Sopenharmony_cibool esas2r_process_vda_ioctl(struct esas2r_adapter *a, 6662306a36Sopenharmony_ci struct atto_ioctl_vda *vi, 6762306a36Sopenharmony_ci struct esas2r_request *rq, 6862306a36Sopenharmony_ci struct esas2r_sg_context *sgc) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci u32 datalen = 0; 7162306a36Sopenharmony_ci struct atto_vda_sge *firstsg = NULL; 7262306a36Sopenharmony_ci u8 vercnt = (u8)ARRAY_SIZE(esas2r_vdaioctl_versions); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci vi->status = ATTO_STS_SUCCESS; 7562306a36Sopenharmony_ci vi->vda_status = RS_PENDING; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (vi->function >= vercnt) { 7862306a36Sopenharmony_ci vi->status = ATTO_STS_INV_FUNC; 7962306a36Sopenharmony_ci return false; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (vi->version > esas2r_vdaioctl_versions[vi->function]) { 8362306a36Sopenharmony_ci vi->status = ATTO_STS_INV_VERSION; 8462306a36Sopenharmony_ci return false; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (test_bit(AF_DEGRADED_MODE, &a->flags)) { 8862306a36Sopenharmony_ci vi->status = ATTO_STS_DEGRADED; 8962306a36Sopenharmony_ci return false; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (vi->function != VDA_FUNC_SCSI) 9362306a36Sopenharmony_ci clear_vda_request(rq); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci rq->vrq->scsi.function = vi->function; 9662306a36Sopenharmony_ci rq->interrupt_cb = esas2r_complete_vda_ioctl; 9762306a36Sopenharmony_ci rq->interrupt_cx = vi; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci switch (vi->function) { 10062306a36Sopenharmony_ci case VDA_FUNC_FLASH: 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (vi->cmd.flash.sub_func != VDA_FLASH_FREAD 10362306a36Sopenharmony_ci && vi->cmd.flash.sub_func != VDA_FLASH_FWRITE 10462306a36Sopenharmony_ci && vi->cmd.flash.sub_func != VDA_FLASH_FINFO) { 10562306a36Sopenharmony_ci vi->status = ATTO_STS_INV_FUNC; 10662306a36Sopenharmony_ci return false; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (vi->cmd.flash.sub_func != VDA_FLASH_FINFO) 11062306a36Sopenharmony_ci datalen = vi->data_length; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci rq->vrq->flash.length = cpu_to_le32(datalen); 11362306a36Sopenharmony_ci rq->vrq->flash.sub_func = vi->cmd.flash.sub_func; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci memcpy(rq->vrq->flash.data.file.file_name, 11662306a36Sopenharmony_ci vi->cmd.flash.data.file.file_name, 11762306a36Sopenharmony_ci sizeof(vi->cmd.flash.data.file.file_name)); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci firstsg = rq->vrq->flash.data.file.sge; 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci case VDA_FUNC_CLI: 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci datalen = vi->data_length; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci rq->vrq->cli.cmd_rsp_len = 12762306a36Sopenharmony_ci cpu_to_le32(vi->cmd.cli.cmd_rsp_len); 12862306a36Sopenharmony_ci rq->vrq->cli.length = cpu_to_le32(datalen); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci firstsg = rq->vrq->cli.sge; 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci case VDA_FUNC_MGT: 13462306a36Sopenharmony_ci { 13562306a36Sopenharmony_ci u8 *cmdcurr_offset = sgc->cur_offset 13662306a36Sopenharmony_ci - offsetof(struct atto_ioctl_vda, data) 13762306a36Sopenharmony_ci + offsetof(struct atto_ioctl_vda, cmd) 13862306a36Sopenharmony_ci + offsetof(struct atto_ioctl_vda_mgt_cmd, 13962306a36Sopenharmony_ci data); 14062306a36Sopenharmony_ci /* 14162306a36Sopenharmony_ci * build the data payload SGL here first since 14262306a36Sopenharmony_ci * esas2r_sgc_init() will modify the S/G list offset for the 14362306a36Sopenharmony_ci * management SGL (which is built below where the data SGL is 14462306a36Sopenharmony_ci * usually built). 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (vi->data_length) { 14862306a36Sopenharmony_ci u32 payldlen = 0; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_HEALTH_REQ 15162306a36Sopenharmony_ci || vi->cmd.mgt.mgt_func == VDAMGT_DEV_METRICS) { 15262306a36Sopenharmony_ci rq->vrq->mgt.payld_sglst_offset = 15362306a36Sopenharmony_ci (u8)offsetof(struct atto_vda_mgmt_req, 15462306a36Sopenharmony_ci payld_sge); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci payldlen = vi->data_length; 15762306a36Sopenharmony_ci datalen = vi->cmd.mgt.data_length; 15862306a36Sopenharmony_ci } else if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_INFO2 15962306a36Sopenharmony_ci || vi->cmd.mgt.mgt_func == 16062306a36Sopenharmony_ci VDAMGT_DEV_INFO2_BYADDR) { 16162306a36Sopenharmony_ci datalen = vi->data_length; 16262306a36Sopenharmony_ci cmdcurr_offset = sgc->cur_offset; 16362306a36Sopenharmony_ci } else { 16462306a36Sopenharmony_ci vi->status = ATTO_STS_INV_PARAM; 16562306a36Sopenharmony_ci return false; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* Setup the length so building the payload SGL works */ 16962306a36Sopenharmony_ci rq->vrq->mgt.length = cpu_to_le32(datalen); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (payldlen) { 17262306a36Sopenharmony_ci rq->vrq->mgt.payld_length = 17362306a36Sopenharmony_ci cpu_to_le32(payldlen); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci esas2r_sgc_init(sgc, a, rq, 17662306a36Sopenharmony_ci rq->vrq->mgt.payld_sge); 17762306a36Sopenharmony_ci sgc->length = payldlen; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (!esas2r_build_sg_list(a, rq, sgc)) { 18062306a36Sopenharmony_ci vi->status = ATTO_STS_OUT_OF_RSRC; 18162306a36Sopenharmony_ci return false; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci } else { 18562306a36Sopenharmony_ci datalen = vi->cmd.mgt.data_length; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci rq->vrq->mgt.length = cpu_to_le32(datalen); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * Now that the payload SGL is built, if any, setup to build 19262306a36Sopenharmony_ci * the management SGL. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci firstsg = rq->vrq->mgt.sge; 19562306a36Sopenharmony_ci sgc->cur_offset = cmdcurr_offset; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* Finish initializing the management request. */ 19862306a36Sopenharmony_ci rq->vrq->mgt.mgt_func = vi->cmd.mgt.mgt_func; 19962306a36Sopenharmony_ci rq->vrq->mgt.scan_generation = vi->cmd.mgt.scan_generation; 20062306a36Sopenharmony_ci rq->vrq->mgt.dev_index = 20162306a36Sopenharmony_ci cpu_to_le32(vi->cmd.mgt.dev_index); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data); 20462306a36Sopenharmony_ci break; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci case VDA_FUNC_CFG: 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (vi->data_length 21062306a36Sopenharmony_ci || vi->cmd.cfg.data_length == 0) { 21162306a36Sopenharmony_ci vi->status = ATTO_STS_INV_PARAM; 21262306a36Sopenharmony_ci return false; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (vi->cmd.cfg.cfg_func == VDA_CFG_INIT) { 21662306a36Sopenharmony_ci vi->status = ATTO_STS_INV_FUNC; 21762306a36Sopenharmony_ci return false; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci rq->vrq->cfg.sub_func = vi->cmd.cfg.cfg_func; 22162306a36Sopenharmony_ci rq->vrq->cfg.length = cpu_to_le32(vi->cmd.cfg.data_length); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) { 22462306a36Sopenharmony_ci memcpy(&rq->vrq->cfg.data, 22562306a36Sopenharmony_ci &vi->cmd.cfg.data, 22662306a36Sopenharmony_ci vi->cmd.cfg.data_length); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func, 22962306a36Sopenharmony_ci &rq->vrq->cfg.data); 23062306a36Sopenharmony_ci } else { 23162306a36Sopenharmony_ci vi->status = ATTO_STS_INV_FUNC; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return false; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci case VDA_FUNC_GSV: 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci vi->cmd.gsv.rsp_len = vercnt; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci memcpy(vi->cmd.gsv.version_info, esas2r_vdaioctl_versions, 24362306a36Sopenharmony_ci vercnt); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci vi->vda_status = RS_SUCCESS; 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci default: 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci vi->status = ATTO_STS_INV_FUNC; 25162306a36Sopenharmony_ci return false; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (datalen) { 25562306a36Sopenharmony_ci esas2r_sgc_init(sgc, a, rq, firstsg); 25662306a36Sopenharmony_ci sgc->length = datalen; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!esas2r_build_sg_list(a, rq, sgc)) { 25962306a36Sopenharmony_ci vi->status = ATTO_STS_OUT_OF_RSRC; 26062306a36Sopenharmony_ci return false; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci esas2r_start_request(a, rq); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return true; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic void esas2r_complete_vda_ioctl(struct esas2r_adapter *a, 27062306a36Sopenharmony_ci struct esas2r_request *rq) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct atto_ioctl_vda *vi = (struct atto_ioctl_vda *)rq->interrupt_cx; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci vi->vda_status = rq->req_stat; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci switch (vi->function) { 27762306a36Sopenharmony_ci case VDA_FUNC_FLASH: 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (vi->cmd.flash.sub_func == VDA_FLASH_FINFO 28062306a36Sopenharmony_ci || vi->cmd.flash.sub_func == VDA_FLASH_FREAD) 28162306a36Sopenharmony_ci vi->cmd.flash.data.file.file_size = 28262306a36Sopenharmony_ci le32_to_cpu(rq->func_rsp.flash_rsp.file_size); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci case VDA_FUNC_MGT: 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci vi->cmd.mgt.scan_generation = 28962306a36Sopenharmony_ci rq->func_rsp.mgt_rsp.scan_generation; 29062306a36Sopenharmony_ci vi->cmd.mgt.dev_index = le16_to_cpu( 29162306a36Sopenharmony_ci rq->func_rsp.mgt_rsp.dev_index); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (vi->data_length == 0) 29462306a36Sopenharmony_ci vi->cmd.mgt.data_length = 29562306a36Sopenharmony_ci le32_to_cpu(rq->func_rsp.mgt_rsp.length); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data); 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci case VDA_FUNC_CFG: 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) { 30362306a36Sopenharmony_ci struct atto_ioctl_vda_cfg_cmd *cfg = &vi->cmd.cfg; 30462306a36Sopenharmony_ci struct atto_vda_cfg_rsp *rsp = &rq->func_rsp.cfg_rsp; 30562306a36Sopenharmony_ci char buf[sizeof(cfg->data.init.fw_release) + 1]; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci cfg->data_length = 30862306a36Sopenharmony_ci cpu_to_le32(sizeof(struct atto_vda_cfg_init)); 30962306a36Sopenharmony_ci cfg->data.init.vda_version = 31062306a36Sopenharmony_ci le32_to_cpu(rsp->vda_version); 31162306a36Sopenharmony_ci cfg->data.init.fw_build = rsp->fw_build; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "%1.1u.%2.2u", 31462306a36Sopenharmony_ci (int)LOBYTE(le16_to_cpu(rsp->fw_release)), 31562306a36Sopenharmony_ci (int)HIBYTE(le16_to_cpu(rsp->fw_release))); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci memcpy(&cfg->data.init.fw_release, buf, 31862306a36Sopenharmony_ci sizeof(cfg->data.init.fw_release)); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (LOWORD(LOBYTE(cfg->data.init.fw_build)) == 'A') 32162306a36Sopenharmony_ci cfg->data.init.fw_version = 32262306a36Sopenharmony_ci cfg->data.init.fw_build; 32362306a36Sopenharmony_ci else 32462306a36Sopenharmony_ci cfg->data.init.fw_version = 32562306a36Sopenharmony_ci cfg->data.init.fw_release; 32662306a36Sopenharmony_ci } else { 32762306a36Sopenharmony_ci esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func, 32862306a36Sopenharmony_ci &vi->cmd.cfg.data); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci case VDA_FUNC_CLI: 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci vi->cmd.cli.cmd_rsp_len = 33662306a36Sopenharmony_ci le32_to_cpu(rq->func_rsp.cli_rsp.cmd_rsp_len); 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci default: 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci/* Build a flash VDA request. */ 34662306a36Sopenharmony_civoid esas2r_build_flash_req(struct esas2r_adapter *a, 34762306a36Sopenharmony_ci struct esas2r_request *rq, 34862306a36Sopenharmony_ci u8 sub_func, 34962306a36Sopenharmony_ci u8 cksum, 35062306a36Sopenharmony_ci u32 addr, 35162306a36Sopenharmony_ci u32 length) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct atto_vda_flash_req *vrq = &rq->vrq->flash; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci clear_vda_request(rq); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci rq->vrq->scsi.function = VDA_FUNC_FLASH; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (sub_func == VDA_FLASH_BEGINW 36062306a36Sopenharmony_ci || sub_func == VDA_FLASH_WRITE 36162306a36Sopenharmony_ci || sub_func == VDA_FLASH_READ) 36262306a36Sopenharmony_ci vrq->sg_list_offset = (u8)offsetof(struct atto_vda_flash_req, 36362306a36Sopenharmony_ci data.sge); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci vrq->length = cpu_to_le32(length); 36662306a36Sopenharmony_ci vrq->flash_addr = cpu_to_le32(addr); 36762306a36Sopenharmony_ci vrq->checksum = cksum; 36862306a36Sopenharmony_ci vrq->sub_func = sub_func; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/* Build a VDA management request. */ 37262306a36Sopenharmony_civoid esas2r_build_mgt_req(struct esas2r_adapter *a, 37362306a36Sopenharmony_ci struct esas2r_request *rq, 37462306a36Sopenharmony_ci u8 sub_func, 37562306a36Sopenharmony_ci u8 scan_gen, 37662306a36Sopenharmony_ci u16 dev_index, 37762306a36Sopenharmony_ci u32 length, 37862306a36Sopenharmony_ci void *data) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct atto_vda_mgmt_req *vrq = &rq->vrq->mgt; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci clear_vda_request(rq); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci rq->vrq->scsi.function = VDA_FUNC_MGT; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci vrq->mgt_func = sub_func; 38762306a36Sopenharmony_ci vrq->scan_generation = scan_gen; 38862306a36Sopenharmony_ci vrq->dev_index = cpu_to_le16(dev_index); 38962306a36Sopenharmony_ci vrq->length = cpu_to_le32(length); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (vrq->length) { 39262306a36Sopenharmony_ci if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) { 39362306a36Sopenharmony_ci vrq->sg_list_offset = (u8)offsetof( 39462306a36Sopenharmony_ci struct atto_vda_mgmt_req, sge); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci vrq->sge[0].length = cpu_to_le32(SGE_LAST | length); 39762306a36Sopenharmony_ci vrq->sge[0].address = cpu_to_le64( 39862306a36Sopenharmony_ci rq->vrq_md->phys_addr + 39962306a36Sopenharmony_ci sizeof(union atto_vda_req)); 40062306a36Sopenharmony_ci } else { 40162306a36Sopenharmony_ci vrq->sg_list_offset = (u8)offsetof( 40262306a36Sopenharmony_ci struct atto_vda_mgmt_req, prde); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci vrq->prde[0].ctl_len = cpu_to_le32(length); 40562306a36Sopenharmony_ci vrq->prde[0].address = cpu_to_le64( 40662306a36Sopenharmony_ci rq->vrq_md->phys_addr + 40762306a36Sopenharmony_ci sizeof(union atto_vda_req)); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (data) { 41262306a36Sopenharmony_ci esas2r_nuxi_mgt_data(sub_func, data); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci memcpy(&rq->vda_rsp_data->mgt_data.data.bytes[0], data, 41562306a36Sopenharmony_ci length); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/* Build a VDA asyncronous event (AE) request. */ 42062306a36Sopenharmony_civoid esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct atto_vda_ae_req *vrq = &rq->vrq->ae; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci clear_vda_request(rq); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci rq->vrq->scsi.function = VDA_FUNC_AE; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci vrq->length = cpu_to_le32(sizeof(struct atto_vda_ae_data)); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) { 43162306a36Sopenharmony_ci vrq->sg_list_offset = 43262306a36Sopenharmony_ci (u8)offsetof(struct atto_vda_ae_req, sge); 43362306a36Sopenharmony_ci vrq->sge[0].length = cpu_to_le32(SGE_LAST | vrq->length); 43462306a36Sopenharmony_ci vrq->sge[0].address = cpu_to_le64( 43562306a36Sopenharmony_ci rq->vrq_md->phys_addr + 43662306a36Sopenharmony_ci sizeof(union atto_vda_req)); 43762306a36Sopenharmony_ci } else { 43862306a36Sopenharmony_ci vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ae_req, 43962306a36Sopenharmony_ci prde); 44062306a36Sopenharmony_ci vrq->prde[0].ctl_len = cpu_to_le32(vrq->length); 44162306a36Sopenharmony_ci vrq->prde[0].address = cpu_to_le64( 44262306a36Sopenharmony_ci rq->vrq_md->phys_addr + 44362306a36Sopenharmony_ci sizeof(union atto_vda_req)); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/* Build a VDA CLI request. */ 44862306a36Sopenharmony_civoid esas2r_build_cli_req(struct esas2r_adapter *a, 44962306a36Sopenharmony_ci struct esas2r_request *rq, 45062306a36Sopenharmony_ci u32 length, 45162306a36Sopenharmony_ci u32 cmd_rsp_len) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct atto_vda_cli_req *vrq = &rq->vrq->cli; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci clear_vda_request(rq); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci rq->vrq->scsi.function = VDA_FUNC_CLI; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci vrq->length = cpu_to_le32(length); 46062306a36Sopenharmony_ci vrq->cmd_rsp_len = cpu_to_le32(cmd_rsp_len); 46162306a36Sopenharmony_ci vrq->sg_list_offset = (u8)offsetof(struct atto_vda_cli_req, sge); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci/* Build a VDA IOCTL request. */ 46562306a36Sopenharmony_civoid esas2r_build_ioctl_req(struct esas2r_adapter *a, 46662306a36Sopenharmony_ci struct esas2r_request *rq, 46762306a36Sopenharmony_ci u32 length, 46862306a36Sopenharmony_ci u8 sub_func) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci struct atto_vda_ioctl_req *vrq = &rq->vrq->ioctl; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci clear_vda_request(rq); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci rq->vrq->scsi.function = VDA_FUNC_IOCTL; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci vrq->length = cpu_to_le32(length); 47762306a36Sopenharmony_ci vrq->sub_func = sub_func; 47862306a36Sopenharmony_ci vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ioctl_req, sge); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci/* Build a VDA configuration request. */ 48262306a36Sopenharmony_civoid esas2r_build_cfg_req(struct esas2r_adapter *a, 48362306a36Sopenharmony_ci struct esas2r_request *rq, 48462306a36Sopenharmony_ci u8 sub_func, 48562306a36Sopenharmony_ci u32 length, 48662306a36Sopenharmony_ci void *data) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct atto_vda_cfg_req *vrq = &rq->vrq->cfg; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci clear_vda_request(rq); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci rq->vrq->scsi.function = VDA_FUNC_CFG; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci vrq->sub_func = sub_func; 49562306a36Sopenharmony_ci vrq->length = cpu_to_le32(length); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (data) { 49862306a36Sopenharmony_ci esas2r_nuxi_cfg_data(sub_func, data); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci memcpy(&vrq->data, data, length); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic void clear_vda_request(struct esas2r_request *rq) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci u32 handle = rq->vrq->scsi.handle; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci memset(rq->vrq, 0, sizeof(*rq->vrq)); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci rq->vrq->scsi.handle = handle; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci rq->req_stat = RS_PENDING; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* since the data buffer is separate clear that too */ 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci memset(rq->data_buf, 0, ESAS2R_DATA_BUF_LEN); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* 51962306a36Sopenharmony_ci * Setup next and prev pointer in case the request is not going through 52062306a36Sopenharmony_ci * esas2r_start_request(). 52162306a36Sopenharmony_ci */ 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci INIT_LIST_HEAD(&rq->req_list); 52462306a36Sopenharmony_ci} 525