| 
									
										
										
										
											2013-08-23 10:35:45 -04:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-01 14:26:01 -04:00
										 |  |  | 	if (test_bit(AF_DEGRADED_MODE, &a->flags)) { | 
					
						
							| 
									
										
										
										
											2013-08-23 10:35:45 -04:00
										 |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2013-08-29 15:55:42 -04:00
										 |  |  | 			char buf[sizeof(cfg->data.init.fw_release) + 1]; | 
					
						
							| 
									
										
										
										
											2013-08-23 10:35:45 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-01 14:26:04 -04:00
										 |  |  | 			snprintf(buf, sizeof(buf), "%1.1u.%2.2u", | 
					
						
							|  |  |  | 				 (int)LOBYTE(le16_to_cpu(rsp->fw_release)), | 
					
						
							|  |  |  | 				 (int)HIBYTE(le16_to_cpu(rsp->fw_release))); | 
					
						
							| 
									
										
										
										
											2013-08-23 10:35:45 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-29 15:55:42 -04:00
										 |  |  | 			memcpy(&cfg->data.init.fw_release, buf, | 
					
						
							|  |  |  | 			       sizeof(cfg->data.init.fw_release)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-23 10:35:45 -04:00
										 |  |  | 			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) { | 
					
						
							| 
									
										
										
										
											2013-10-01 14:26:01 -04:00
										 |  |  | 		if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) { | 
					
						
							| 
									
										
										
										
											2013-08-23 10:35:45 -04:00
										 |  |  | 			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)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-01 14:26:01 -04:00
										 |  |  | 	if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) { | 
					
						
							| 
									
										
										
										
											2013-08-23 10:35:45 -04:00
										 |  |  | 		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); | 
					
						
							|  |  |  | } |