525 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			525 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  linux/drivers/scsi/esas2r/esas2r_vda.c
 | |
|  *      esas2r driver VDA firmware interface functions
 | |
|  *
 | |
|  *  Copyright (c) 2001-2013 ATTO Technology, Inc.
 | |
|  *  (mailto:linuxdrivers@attotech.com)
 | |
|  */
 | |
| /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 | |
| /*
 | |
|  *  This program is free software; you can redistribute it and/or modify
 | |
|  *  it under the terms of the GNU General Public License as published by
 | |
|  *  the Free Software Foundation; version 2 of the License.
 | |
|  *
 | |
|  *  This program is distributed in the hope that it will be useful,
 | |
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  *  GNU General Public License for more details.
 | |
|  *
 | |
|  *  NO WARRANTY
 | |
|  *  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
 | |
|  *  CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
 | |
|  *  LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
 | |
|  *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
 | |
|  *  solely responsible for determining the appropriateness of using and
 | |
|  *  distributing the Program and assumes all risks associated with its
 | |
|  *  exercise of rights under this Agreement, including but not limited to
 | |
|  *  the risks and costs of program errors, damage to or loss of data,
 | |
|  *  programs or equipment, and unavailability or interruption of operations.
 | |
|  *
 | |
|  *  DISCLAIMER OF LIABILITY
 | |
|  *  NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
 | |
|  *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | |
|  *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
 | |
|  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 | |
|  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | |
|  *  USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
 | |
|  *  HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
 | |
|  *
 | |
|  *  You should have received a copy of the GNU General Public License
 | |
|  *  along with this program; if not, write to the Free Software
 | |
|  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
|  */
 | |
| /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 | |
| 
 | |
| #include "esas2r.h"
 | |
| 
 | |
| static u8 esas2r_vdaioctl_versions[] = {
 | |
| 	ATTO_VDA_VER_UNSUPPORTED,
 | |
| 	ATTO_VDA_FLASH_VER,
 | |
| 	ATTO_VDA_VER_UNSUPPORTED,
 | |
| 	ATTO_VDA_VER_UNSUPPORTED,
 | |
| 	ATTO_VDA_CLI_VER,
 | |
| 	ATTO_VDA_VER_UNSUPPORTED,
 | |
| 	ATTO_VDA_CFG_VER,
 | |
| 	ATTO_VDA_MGT_VER,
 | |
| 	ATTO_VDA_GSV_VER
 | |
| };
 | |
| 
 | |
| static void clear_vda_request(struct esas2r_request *rq);
 | |
| 
 | |
| static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
 | |
| 				      struct esas2r_request *rq);
 | |
| 
 | |
| /* Prepare a VDA IOCTL request to be sent to the firmware. */
 | |
| bool esas2r_process_vda_ioctl(struct esas2r_adapter *a,
 | |
| 			      struct atto_ioctl_vda *vi,
 | |
| 			      struct esas2r_request *rq,
 | |
| 			      struct esas2r_sg_context *sgc)
 | |
| {
 | |
| 	u32 datalen = 0;
 | |
| 	struct atto_vda_sge *firstsg = NULL;
 | |
| 	u8 vercnt = (u8)ARRAY_SIZE(esas2r_vdaioctl_versions);
 | |
| 
 | |
| 	vi->status = ATTO_STS_SUCCESS;
 | |
| 	vi->vda_status = RS_PENDING;
 | |
| 
 | |
| 	if (vi->function >= vercnt) {
 | |
| 		vi->status = ATTO_STS_INV_FUNC;
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (vi->version > esas2r_vdaioctl_versions[vi->function]) {
 | |
| 		vi->status = ATTO_STS_INV_VERSION;
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (test_bit(AF_DEGRADED_MODE, &a->flags)) {
 | |
| 		vi->status = ATTO_STS_DEGRADED;
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (vi->function != VDA_FUNC_SCSI)
 | |
| 		clear_vda_request(rq);
 | |
| 
 | |
| 	rq->vrq->scsi.function = vi->function;
 | |
| 	rq->interrupt_cb = esas2r_complete_vda_ioctl;
 | |
| 	rq->interrupt_cx = vi;
 | |
| 
 | |
| 	switch (vi->function) {
 | |
| 	case VDA_FUNC_FLASH:
 | |
| 
 | |
| 		if (vi->cmd.flash.sub_func != VDA_FLASH_FREAD
 | |
| 		    && vi->cmd.flash.sub_func != VDA_FLASH_FWRITE
 | |
| 		    && vi->cmd.flash.sub_func != VDA_FLASH_FINFO) {
 | |
| 			vi->status = ATTO_STS_INV_FUNC;
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		if (vi->cmd.flash.sub_func != VDA_FLASH_FINFO)
 | |
| 			datalen = vi->data_length;
 | |
| 
 | |
| 		rq->vrq->flash.length = cpu_to_le32(datalen);
 | |
| 		rq->vrq->flash.sub_func = vi->cmd.flash.sub_func;
 | |
| 
 | |
| 		memcpy(rq->vrq->flash.data.file.file_name,
 | |
| 		       vi->cmd.flash.data.file.file_name,
 | |
| 		       sizeof(vi->cmd.flash.data.file.file_name));
 | |
| 
 | |
| 		firstsg = rq->vrq->flash.data.file.sge;
 | |
| 		break;
 | |
| 
 | |
| 	case VDA_FUNC_CLI:
 | |
| 
 | |
| 		datalen = vi->data_length;
 | |
| 
 | |
| 		rq->vrq->cli.cmd_rsp_len =
 | |
| 			cpu_to_le32(vi->cmd.cli.cmd_rsp_len);
 | |
| 		rq->vrq->cli.length = cpu_to_le32(datalen);
 | |
| 
 | |
| 		firstsg = rq->vrq->cli.sge;
 | |
| 		break;
 | |
| 
 | |
| 	case VDA_FUNC_MGT:
 | |
| 	{
 | |
| 		u8 *cmdcurr_offset = sgc->cur_offset
 | |
| 				     - offsetof(struct atto_ioctl_vda, data)
 | |
| 				     + offsetof(struct atto_ioctl_vda, cmd)
 | |
| 				     + offsetof(struct atto_ioctl_vda_mgt_cmd,
 | |
| 						data);
 | |
| 		/*
 | |
| 		 * build the data payload SGL here first since
 | |
| 		 * esas2r_sgc_init() will modify the S/G list offset for the
 | |
| 		 * management SGL (which is built below where the data SGL is
 | |
| 		 * usually built).
 | |
| 		 */
 | |
| 
 | |
| 		if (vi->data_length) {
 | |
| 			u32 payldlen = 0;
 | |
| 
 | |
| 			if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_HEALTH_REQ
 | |
| 			    || vi->cmd.mgt.mgt_func == VDAMGT_DEV_METRICS) {
 | |
| 				rq->vrq->mgt.payld_sglst_offset =
 | |
| 					(u8)offsetof(struct atto_vda_mgmt_req,
 | |
| 						     payld_sge);
 | |
| 
 | |
| 				payldlen = vi->data_length;
 | |
| 				datalen = vi->cmd.mgt.data_length;
 | |
| 			} else if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_INFO2
 | |
| 				   || vi->cmd.mgt.mgt_func ==
 | |
| 				   VDAMGT_DEV_INFO2_BYADDR) {
 | |
| 				datalen = vi->data_length;
 | |
| 				cmdcurr_offset = sgc->cur_offset;
 | |
| 			} else {
 | |
| 				vi->status = ATTO_STS_INV_PARAM;
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			/* Setup the length so building the payload SGL works */
 | |
| 			rq->vrq->mgt.length = cpu_to_le32(datalen);
 | |
| 
 | |
| 			if (payldlen) {
 | |
| 				rq->vrq->mgt.payld_length =
 | |
| 					cpu_to_le32(payldlen);
 | |
| 
 | |
| 				esas2r_sgc_init(sgc, a, rq,
 | |
| 						rq->vrq->mgt.payld_sge);
 | |
| 				sgc->length = payldlen;
 | |
| 
 | |
| 				if (!esas2r_build_sg_list(a, rq, sgc)) {
 | |
| 					vi->status = ATTO_STS_OUT_OF_RSRC;
 | |
| 					return false;
 | |
| 				}
 | |
| 			}
 | |
| 		} else {
 | |
| 			datalen = vi->cmd.mgt.data_length;
 | |
| 
 | |
| 			rq->vrq->mgt.length = cpu_to_le32(datalen);
 | |
| 		}
 | |
| 
 | |
| 		/*
 | |
| 		 * Now that the payload SGL is built, if any, setup to build
 | |
| 		 * the management SGL.
 | |
| 		 */
 | |
| 		firstsg = rq->vrq->mgt.sge;
 | |
| 		sgc->cur_offset = cmdcurr_offset;
 | |
| 
 | |
| 		/* Finish initializing the management request. */
 | |
| 		rq->vrq->mgt.mgt_func = vi->cmd.mgt.mgt_func;
 | |
| 		rq->vrq->mgt.scan_generation = vi->cmd.mgt.scan_generation;
 | |
| 		rq->vrq->mgt.dev_index =
 | |
| 			cpu_to_le32(vi->cmd.mgt.dev_index);
 | |
| 
 | |
| 		esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	case VDA_FUNC_CFG:
 | |
| 
 | |
| 		if (vi->data_length
 | |
| 		    || vi->cmd.cfg.data_length == 0) {
 | |
| 			vi->status = ATTO_STS_INV_PARAM;
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		if (vi->cmd.cfg.cfg_func == VDA_CFG_INIT) {
 | |
| 			vi->status = ATTO_STS_INV_FUNC;
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		rq->vrq->cfg.sub_func = vi->cmd.cfg.cfg_func;
 | |
| 		rq->vrq->cfg.length = cpu_to_le32(vi->cmd.cfg.data_length);
 | |
| 
 | |
| 		if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
 | |
| 			memcpy(&rq->vrq->cfg.data,
 | |
| 			       &vi->cmd.cfg.data,
 | |
| 			       vi->cmd.cfg.data_length);
 | |
| 
 | |
| 			esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
 | |
| 					     &rq->vrq->cfg.data);
 | |
| 		} else {
 | |
| 			vi->status = ATTO_STS_INV_FUNC;
 | |
| 
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		break;
 | |
| 
 | |
| 	case VDA_FUNC_GSV:
 | |
| 
 | |
| 		vi->cmd.gsv.rsp_len = vercnt;
 | |
| 
 | |
| 		memcpy(vi->cmd.gsv.version_info, esas2r_vdaioctl_versions,
 | |
| 		       vercnt);
 | |
| 
 | |
| 		vi->vda_status = RS_SUCCESS;
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 
 | |
| 		vi->status = ATTO_STS_INV_FUNC;
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (datalen) {
 | |
| 		esas2r_sgc_init(sgc, a, rq, firstsg);
 | |
| 		sgc->length = datalen;
 | |
| 
 | |
| 		if (!esas2r_build_sg_list(a, rq, sgc)) {
 | |
| 			vi->status = ATTO_STS_OUT_OF_RSRC;
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	esas2r_start_request(a, rq);
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
 | |
| 				      struct esas2r_request *rq)
 | |
| {
 | |
| 	struct atto_ioctl_vda *vi = (struct atto_ioctl_vda *)rq->interrupt_cx;
 | |
| 
 | |
| 	vi->vda_status = rq->req_stat;
 | |
| 
 | |
| 	switch (vi->function) {
 | |
| 	case VDA_FUNC_FLASH:
 | |
| 
 | |
| 		if (vi->cmd.flash.sub_func == VDA_FLASH_FINFO
 | |
| 		    || vi->cmd.flash.sub_func == VDA_FLASH_FREAD)
 | |
| 			vi->cmd.flash.data.file.file_size =
 | |
| 				le32_to_cpu(rq->func_rsp.flash_rsp.file_size);
 | |
| 
 | |
| 		break;
 | |
| 
 | |
| 	case VDA_FUNC_MGT:
 | |
| 
 | |
| 		vi->cmd.mgt.scan_generation =
 | |
| 			rq->func_rsp.mgt_rsp.scan_generation;
 | |
| 		vi->cmd.mgt.dev_index = le16_to_cpu(
 | |
| 			rq->func_rsp.mgt_rsp.dev_index);
 | |
| 
 | |
| 		if (vi->data_length == 0)
 | |
| 			vi->cmd.mgt.data_length =
 | |
| 				le32_to_cpu(rq->func_rsp.mgt_rsp.length);
 | |
| 
 | |
| 		esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
 | |
| 		break;
 | |
| 
 | |
| 	case VDA_FUNC_CFG:
 | |
| 
 | |
| 		if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
 | |
| 			struct atto_ioctl_vda_cfg_cmd *cfg = &vi->cmd.cfg;
 | |
| 			struct atto_vda_cfg_rsp *rsp = &rq->func_rsp.cfg_rsp;
 | |
| 			char buf[sizeof(cfg->data.init.fw_release) + 1];
 | |
| 
 | |
| 			cfg->data_length =
 | |
| 				cpu_to_le32(sizeof(struct atto_vda_cfg_init));
 | |
| 			cfg->data.init.vda_version =
 | |
| 				le32_to_cpu(rsp->vda_version);
 | |
| 			cfg->data.init.fw_build = rsp->fw_build;
 | |
| 
 | |
| 			snprintf(buf, sizeof(buf), "%1.1u.%2.2u",
 | |
| 				 (int)LOBYTE(le16_to_cpu(rsp->fw_release)),
 | |
| 				 (int)HIBYTE(le16_to_cpu(rsp->fw_release)));
 | |
| 
 | |
| 			memcpy(&cfg->data.init.fw_release, buf,
 | |
| 			       sizeof(cfg->data.init.fw_release));
 | |
| 
 | |
| 			if (LOWORD(LOBYTE(cfg->data.init.fw_build)) == 'A')
 | |
| 				cfg->data.init.fw_version =
 | |
| 					cfg->data.init.fw_build;
 | |
| 			else
 | |
| 				cfg->data.init.fw_version =
 | |
| 					cfg->data.init.fw_release;
 | |
| 		} else {
 | |
| 			esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
 | |
| 					     &vi->cmd.cfg.data);
 | |
| 		}
 | |
| 
 | |
| 		break;
 | |
| 
 | |
| 	case VDA_FUNC_CLI:
 | |
| 
 | |
| 		vi->cmd.cli.cmd_rsp_len =
 | |
| 			le32_to_cpu(rq->func_rsp.cli_rsp.cmd_rsp_len);
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 
 | |
| 		break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Build a flash VDA request. */
 | |
| void esas2r_build_flash_req(struct esas2r_adapter *a,
 | |
| 			    struct esas2r_request *rq,
 | |
| 			    u8 sub_func,
 | |
| 			    u8 cksum,
 | |
| 			    u32 addr,
 | |
| 			    u32 length)
 | |
| {
 | |
| 	struct atto_vda_flash_req *vrq = &rq->vrq->flash;
 | |
| 
 | |
| 	clear_vda_request(rq);
 | |
| 
 | |
| 	rq->vrq->scsi.function = VDA_FUNC_FLASH;
 | |
| 
 | |
| 	if (sub_func == VDA_FLASH_BEGINW
 | |
| 	    || sub_func == VDA_FLASH_WRITE
 | |
| 	    || sub_func == VDA_FLASH_READ)
 | |
| 		vrq->sg_list_offset = (u8)offsetof(struct atto_vda_flash_req,
 | |
| 						   data.sge);
 | |
| 
 | |
| 	vrq->length = cpu_to_le32(length);
 | |
| 	vrq->flash_addr = cpu_to_le32(addr);
 | |
| 	vrq->checksum = cksum;
 | |
| 	vrq->sub_func = sub_func;
 | |
| }
 | |
| 
 | |
| /* Build a VDA management request. */
 | |
| void esas2r_build_mgt_req(struct esas2r_adapter *a,
 | |
| 			  struct esas2r_request *rq,
 | |
| 			  u8 sub_func,
 | |
| 			  u8 scan_gen,
 | |
| 			  u16 dev_index,
 | |
| 			  u32 length,
 | |
| 			  void *data)
 | |
| {
 | |
| 	struct atto_vda_mgmt_req *vrq = &rq->vrq->mgt;
 | |
| 
 | |
| 	clear_vda_request(rq);
 | |
| 
 | |
| 	rq->vrq->scsi.function = VDA_FUNC_MGT;
 | |
| 
 | |
| 	vrq->mgt_func = sub_func;
 | |
| 	vrq->scan_generation = scan_gen;
 | |
| 	vrq->dev_index = cpu_to_le16(dev_index);
 | |
| 	vrq->length = cpu_to_le32(length);
 | |
| 
 | |
| 	if (vrq->length) {
 | |
| 		if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
 | |
| 			vrq->sg_list_offset = (u8)offsetof(
 | |
| 				struct atto_vda_mgmt_req, sge);
 | |
| 
 | |
| 			vrq->sge[0].length = cpu_to_le32(SGE_LAST | length);
 | |
| 			vrq->sge[0].address = cpu_to_le64(
 | |
| 				rq->vrq_md->phys_addr +
 | |
| 				sizeof(union atto_vda_req));
 | |
| 		} else {
 | |
| 			vrq->sg_list_offset = (u8)offsetof(
 | |
| 				struct atto_vda_mgmt_req, prde);
 | |
| 
 | |
| 			vrq->prde[0].ctl_len = cpu_to_le32(length);
 | |
| 			vrq->prde[0].address = cpu_to_le64(
 | |
| 				rq->vrq_md->phys_addr +
 | |
| 				sizeof(union atto_vda_req));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (data) {
 | |
| 		esas2r_nuxi_mgt_data(sub_func, data);
 | |
| 
 | |
| 		memcpy(&rq->vda_rsp_data->mgt_data.data.bytes[0], data,
 | |
| 		       length);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Build a VDA asyncronous event (AE) request. */
 | |
| void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq)
 | |
| {
 | |
| 	struct atto_vda_ae_req *vrq = &rq->vrq->ae;
 | |
| 
 | |
| 	clear_vda_request(rq);
 | |
| 
 | |
| 	rq->vrq->scsi.function = VDA_FUNC_AE;
 | |
| 
 | |
| 	vrq->length = cpu_to_le32(sizeof(struct atto_vda_ae_data));
 | |
| 
 | |
| 	if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
 | |
| 		vrq->sg_list_offset =
 | |
| 			(u8)offsetof(struct atto_vda_ae_req, sge);
 | |
| 		vrq->sge[0].length = cpu_to_le32(SGE_LAST | vrq->length);
 | |
| 		vrq->sge[0].address = cpu_to_le64(
 | |
| 			rq->vrq_md->phys_addr +
 | |
| 			sizeof(union atto_vda_req));
 | |
| 	} else {
 | |
| 		vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ae_req,
 | |
| 						   prde);
 | |
| 		vrq->prde[0].ctl_len = cpu_to_le32(vrq->length);
 | |
| 		vrq->prde[0].address = cpu_to_le64(
 | |
| 			rq->vrq_md->phys_addr +
 | |
| 			sizeof(union atto_vda_req));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Build a VDA CLI request. */
 | |
| void esas2r_build_cli_req(struct esas2r_adapter *a,
 | |
| 			  struct esas2r_request *rq,
 | |
| 			  u32 length,
 | |
| 			  u32 cmd_rsp_len)
 | |
| {
 | |
| 	struct atto_vda_cli_req *vrq = &rq->vrq->cli;
 | |
| 
 | |
| 	clear_vda_request(rq);
 | |
| 
 | |
| 	rq->vrq->scsi.function = VDA_FUNC_CLI;
 | |
| 
 | |
| 	vrq->length = cpu_to_le32(length);
 | |
| 	vrq->cmd_rsp_len = cpu_to_le32(cmd_rsp_len);
 | |
| 	vrq->sg_list_offset = (u8)offsetof(struct atto_vda_cli_req, sge);
 | |
| }
 | |
| 
 | |
| /* Build a VDA IOCTL request. */
 | |
| void esas2r_build_ioctl_req(struct esas2r_adapter *a,
 | |
| 			    struct esas2r_request *rq,
 | |
| 			    u32 length,
 | |
| 			    u8 sub_func)
 | |
| {
 | |
| 	struct atto_vda_ioctl_req *vrq = &rq->vrq->ioctl;
 | |
| 
 | |
| 	clear_vda_request(rq);
 | |
| 
 | |
| 	rq->vrq->scsi.function = VDA_FUNC_IOCTL;
 | |
| 
 | |
| 	vrq->length = cpu_to_le32(length);
 | |
| 	vrq->sub_func = sub_func;
 | |
| 	vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ioctl_req, sge);
 | |
| }
 | |
| 
 | |
| /* Build a VDA configuration request. */
 | |
| void esas2r_build_cfg_req(struct esas2r_adapter *a,
 | |
| 			  struct esas2r_request *rq,
 | |
| 			  u8 sub_func,
 | |
| 			  u32 length,
 | |
| 			  void *data)
 | |
| {
 | |
| 	struct atto_vda_cfg_req *vrq = &rq->vrq->cfg;
 | |
| 
 | |
| 	clear_vda_request(rq);
 | |
| 
 | |
| 	rq->vrq->scsi.function = VDA_FUNC_CFG;
 | |
| 
 | |
| 	vrq->sub_func = sub_func;
 | |
| 	vrq->length = cpu_to_le32(length);
 | |
| 
 | |
| 	if (data) {
 | |
| 		esas2r_nuxi_cfg_data(sub_func, data);
 | |
| 
 | |
| 		memcpy(&vrq->data, data, length);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void clear_vda_request(struct esas2r_request *rq)
 | |
| {
 | |
| 	u32 handle = rq->vrq->scsi.handle;
 | |
| 
 | |
| 	memset(rq->vrq, 0, sizeof(*rq->vrq));
 | |
| 
 | |
| 	rq->vrq->scsi.handle = handle;
 | |
| 
 | |
| 	rq->req_stat = RS_PENDING;
 | |
| 
 | |
| 	/* since the data buffer is separate clear that too */
 | |
| 
 | |
| 	memset(rq->data_buf, 0, ESAS2R_DATA_BUF_LEN);
 | |
| 
 | |
| 	/*
 | |
| 	 * Setup next and prev pointer in case the request is not going through
 | |
| 	 * esas2r_start_request().
 | |
| 	 */
 | |
| 
 | |
| 	INIT_LIST_HEAD(&rq->req_list);
 | |
| }
 |