cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

esas2r_vda.c (13784B)


      1/*
      2 *  linux/drivers/scsi/esas2r/esas2r_vda.c
      3 *      esas2r driver VDA firmware interface functions
      4 *
      5 *  Copyright (c) 2001-2013 ATTO Technology, Inc.
      6 *  (mailto:linuxdrivers@attotech.com)
      7 */
      8/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
      9/*
     10 *  This program is free software; you can redistribute it and/or modify
     11 *  it under the terms of the GNU General Public License as published by
     12 *  the Free Software Foundation; version 2 of the License.
     13 *
     14 *  This program is distributed in the hope that it will be useful,
     15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 *  GNU General Public License for more details.
     18 *
     19 *  NO WARRANTY
     20 *  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
     21 *  CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
     22 *  LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
     23 *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
     24 *  solely responsible for determining the appropriateness of using and
     25 *  distributing the Program and assumes all risks associated with its
     26 *  exercise of rights under this Agreement, including but not limited to
     27 *  the risks and costs of program errors, damage to or loss of data,
     28 *  programs or equipment, and unavailability or interruption of operations.
     29 *
     30 *  DISCLAIMER OF LIABILITY
     31 *  NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
     32 *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     33 *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
     34 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
     35 *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
     36 *  USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
     37 *  HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
     38 *
     39 *  You should have received a copy of the GNU General Public License
     40 *  along with this program; if not, write to the Free Software
     41 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     42 */
     43/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
     44
     45#include "esas2r.h"
     46
     47static u8 esas2r_vdaioctl_versions[] = {
     48	ATTO_VDA_VER_UNSUPPORTED,
     49	ATTO_VDA_FLASH_VER,
     50	ATTO_VDA_VER_UNSUPPORTED,
     51	ATTO_VDA_VER_UNSUPPORTED,
     52	ATTO_VDA_CLI_VER,
     53	ATTO_VDA_VER_UNSUPPORTED,
     54	ATTO_VDA_CFG_VER,
     55	ATTO_VDA_MGT_VER,
     56	ATTO_VDA_GSV_VER
     57};
     58
     59static void clear_vda_request(struct esas2r_request *rq);
     60
     61static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
     62				      struct esas2r_request *rq);
     63
     64/* Prepare a VDA IOCTL request to be sent to the firmware. */
     65bool esas2r_process_vda_ioctl(struct esas2r_adapter *a,
     66			      struct atto_ioctl_vda *vi,
     67			      struct esas2r_request *rq,
     68			      struct esas2r_sg_context *sgc)
     69{
     70	u32 datalen = 0;
     71	struct atto_vda_sge *firstsg = NULL;
     72	u8 vercnt = (u8)ARRAY_SIZE(esas2r_vdaioctl_versions);
     73
     74	vi->status = ATTO_STS_SUCCESS;
     75	vi->vda_status = RS_PENDING;
     76
     77	if (vi->function >= vercnt) {
     78		vi->status = ATTO_STS_INV_FUNC;
     79		return false;
     80	}
     81
     82	if (vi->version > esas2r_vdaioctl_versions[vi->function]) {
     83		vi->status = ATTO_STS_INV_VERSION;
     84		return false;
     85	}
     86
     87	if (test_bit(AF_DEGRADED_MODE, &a->flags)) {
     88		vi->status = ATTO_STS_DEGRADED;
     89		return false;
     90	}
     91
     92	if (vi->function != VDA_FUNC_SCSI)
     93		clear_vda_request(rq);
     94
     95	rq->vrq->scsi.function = vi->function;
     96	rq->interrupt_cb = esas2r_complete_vda_ioctl;
     97	rq->interrupt_cx = vi;
     98
     99	switch (vi->function) {
    100	case VDA_FUNC_FLASH:
    101
    102		if (vi->cmd.flash.sub_func != VDA_FLASH_FREAD
    103		    && vi->cmd.flash.sub_func != VDA_FLASH_FWRITE
    104		    && vi->cmd.flash.sub_func != VDA_FLASH_FINFO) {
    105			vi->status = ATTO_STS_INV_FUNC;
    106			return false;
    107		}
    108
    109		if (vi->cmd.flash.sub_func != VDA_FLASH_FINFO)
    110			datalen = vi->data_length;
    111
    112		rq->vrq->flash.length = cpu_to_le32(datalen);
    113		rq->vrq->flash.sub_func = vi->cmd.flash.sub_func;
    114
    115		memcpy(rq->vrq->flash.data.file.file_name,
    116		       vi->cmd.flash.data.file.file_name,
    117		       sizeof(vi->cmd.flash.data.file.file_name));
    118
    119		firstsg = rq->vrq->flash.data.file.sge;
    120		break;
    121
    122	case VDA_FUNC_CLI:
    123
    124		datalen = vi->data_length;
    125
    126		rq->vrq->cli.cmd_rsp_len =
    127			cpu_to_le32(vi->cmd.cli.cmd_rsp_len);
    128		rq->vrq->cli.length = cpu_to_le32(datalen);
    129
    130		firstsg = rq->vrq->cli.sge;
    131		break;
    132
    133	case VDA_FUNC_MGT:
    134	{
    135		u8 *cmdcurr_offset = sgc->cur_offset
    136				     - offsetof(struct atto_ioctl_vda, data)
    137				     + offsetof(struct atto_ioctl_vda, cmd)
    138				     + offsetof(struct atto_ioctl_vda_mgt_cmd,
    139						data);
    140		/*
    141		 * build the data payload SGL here first since
    142		 * esas2r_sgc_init() will modify the S/G list offset for the
    143		 * management SGL (which is built below where the data SGL is
    144		 * usually built).
    145		 */
    146
    147		if (vi->data_length) {
    148			u32 payldlen = 0;
    149
    150			if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_HEALTH_REQ
    151			    || vi->cmd.mgt.mgt_func == VDAMGT_DEV_METRICS) {
    152				rq->vrq->mgt.payld_sglst_offset =
    153					(u8)offsetof(struct atto_vda_mgmt_req,
    154						     payld_sge);
    155
    156				payldlen = vi->data_length;
    157				datalen = vi->cmd.mgt.data_length;
    158			} else if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_INFO2
    159				   || vi->cmd.mgt.mgt_func ==
    160				   VDAMGT_DEV_INFO2_BYADDR) {
    161				datalen = vi->data_length;
    162				cmdcurr_offset = sgc->cur_offset;
    163			} else {
    164				vi->status = ATTO_STS_INV_PARAM;
    165				return false;
    166			}
    167
    168			/* Setup the length so building the payload SGL works */
    169			rq->vrq->mgt.length = cpu_to_le32(datalen);
    170
    171			if (payldlen) {
    172				rq->vrq->mgt.payld_length =
    173					cpu_to_le32(payldlen);
    174
    175				esas2r_sgc_init(sgc, a, rq,
    176						rq->vrq->mgt.payld_sge);
    177				sgc->length = payldlen;
    178
    179				if (!esas2r_build_sg_list(a, rq, sgc)) {
    180					vi->status = ATTO_STS_OUT_OF_RSRC;
    181					return false;
    182				}
    183			}
    184		} else {
    185			datalen = vi->cmd.mgt.data_length;
    186
    187			rq->vrq->mgt.length = cpu_to_le32(datalen);
    188		}
    189
    190		/*
    191		 * Now that the payload SGL is built, if any, setup to build
    192		 * the management SGL.
    193		 */
    194		firstsg = rq->vrq->mgt.sge;
    195		sgc->cur_offset = cmdcurr_offset;
    196
    197		/* Finish initializing the management request. */
    198		rq->vrq->mgt.mgt_func = vi->cmd.mgt.mgt_func;
    199		rq->vrq->mgt.scan_generation = vi->cmd.mgt.scan_generation;
    200		rq->vrq->mgt.dev_index =
    201			cpu_to_le32(vi->cmd.mgt.dev_index);
    202
    203		esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
    204		break;
    205	}
    206
    207	case VDA_FUNC_CFG:
    208
    209		if (vi->data_length
    210		    || vi->cmd.cfg.data_length == 0) {
    211			vi->status = ATTO_STS_INV_PARAM;
    212			return false;
    213		}
    214
    215		if (vi->cmd.cfg.cfg_func == VDA_CFG_INIT) {
    216			vi->status = ATTO_STS_INV_FUNC;
    217			return false;
    218		}
    219
    220		rq->vrq->cfg.sub_func = vi->cmd.cfg.cfg_func;
    221		rq->vrq->cfg.length = cpu_to_le32(vi->cmd.cfg.data_length);
    222
    223		if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
    224			memcpy(&rq->vrq->cfg.data,
    225			       &vi->cmd.cfg.data,
    226			       vi->cmd.cfg.data_length);
    227
    228			esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
    229					     &rq->vrq->cfg.data);
    230		} else {
    231			vi->status = ATTO_STS_INV_FUNC;
    232
    233			return false;
    234		}
    235
    236		break;
    237
    238	case VDA_FUNC_GSV:
    239
    240		vi->cmd.gsv.rsp_len = vercnt;
    241
    242		memcpy(vi->cmd.gsv.version_info, esas2r_vdaioctl_versions,
    243		       vercnt);
    244
    245		vi->vda_status = RS_SUCCESS;
    246		break;
    247
    248	default:
    249
    250		vi->status = ATTO_STS_INV_FUNC;
    251		return false;
    252	}
    253
    254	if (datalen) {
    255		esas2r_sgc_init(sgc, a, rq, firstsg);
    256		sgc->length = datalen;
    257
    258		if (!esas2r_build_sg_list(a, rq, sgc)) {
    259			vi->status = ATTO_STS_OUT_OF_RSRC;
    260			return false;
    261		}
    262	}
    263
    264	esas2r_start_request(a, rq);
    265
    266	return true;
    267}
    268
    269static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
    270				      struct esas2r_request *rq)
    271{
    272	struct atto_ioctl_vda *vi = (struct atto_ioctl_vda *)rq->interrupt_cx;
    273
    274	vi->vda_status = rq->req_stat;
    275
    276	switch (vi->function) {
    277	case VDA_FUNC_FLASH:
    278
    279		if (vi->cmd.flash.sub_func == VDA_FLASH_FINFO
    280		    || vi->cmd.flash.sub_func == VDA_FLASH_FREAD)
    281			vi->cmd.flash.data.file.file_size =
    282				le32_to_cpu(rq->func_rsp.flash_rsp.file_size);
    283
    284		break;
    285
    286	case VDA_FUNC_MGT:
    287
    288		vi->cmd.mgt.scan_generation =
    289			rq->func_rsp.mgt_rsp.scan_generation;
    290		vi->cmd.mgt.dev_index = le16_to_cpu(
    291			rq->func_rsp.mgt_rsp.dev_index);
    292
    293		if (vi->data_length == 0)
    294			vi->cmd.mgt.data_length =
    295				le32_to_cpu(rq->func_rsp.mgt_rsp.length);
    296
    297		esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
    298		break;
    299
    300	case VDA_FUNC_CFG:
    301
    302		if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
    303			struct atto_ioctl_vda_cfg_cmd *cfg = &vi->cmd.cfg;
    304			struct atto_vda_cfg_rsp *rsp = &rq->func_rsp.cfg_rsp;
    305			char buf[sizeof(cfg->data.init.fw_release) + 1];
    306
    307			cfg->data_length =
    308				cpu_to_le32(sizeof(struct atto_vda_cfg_init));
    309			cfg->data.init.vda_version =
    310				le32_to_cpu(rsp->vda_version);
    311			cfg->data.init.fw_build = rsp->fw_build;
    312
    313			snprintf(buf, sizeof(buf), "%1.1u.%2.2u",
    314				 (int)LOBYTE(le16_to_cpu(rsp->fw_release)),
    315				 (int)HIBYTE(le16_to_cpu(rsp->fw_release)));
    316
    317			memcpy(&cfg->data.init.fw_release, buf,
    318			       sizeof(cfg->data.init.fw_release));
    319
    320			if (LOWORD(LOBYTE(cfg->data.init.fw_build)) == 'A')
    321				cfg->data.init.fw_version =
    322					cfg->data.init.fw_build;
    323			else
    324				cfg->data.init.fw_version =
    325					cfg->data.init.fw_release;
    326		} else {
    327			esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
    328					     &vi->cmd.cfg.data);
    329		}
    330
    331		break;
    332
    333	case VDA_FUNC_CLI:
    334
    335		vi->cmd.cli.cmd_rsp_len =
    336			le32_to_cpu(rq->func_rsp.cli_rsp.cmd_rsp_len);
    337		break;
    338
    339	default:
    340
    341		break;
    342	}
    343}
    344
    345/* Build a flash VDA request. */
    346void esas2r_build_flash_req(struct esas2r_adapter *a,
    347			    struct esas2r_request *rq,
    348			    u8 sub_func,
    349			    u8 cksum,
    350			    u32 addr,
    351			    u32 length)
    352{
    353	struct atto_vda_flash_req *vrq = &rq->vrq->flash;
    354
    355	clear_vda_request(rq);
    356
    357	rq->vrq->scsi.function = VDA_FUNC_FLASH;
    358
    359	if (sub_func == VDA_FLASH_BEGINW
    360	    || sub_func == VDA_FLASH_WRITE
    361	    || sub_func == VDA_FLASH_READ)
    362		vrq->sg_list_offset = (u8)offsetof(struct atto_vda_flash_req,
    363						   data.sge);
    364
    365	vrq->length = cpu_to_le32(length);
    366	vrq->flash_addr = cpu_to_le32(addr);
    367	vrq->checksum = cksum;
    368	vrq->sub_func = sub_func;
    369}
    370
    371/* Build a VDA management request. */
    372void esas2r_build_mgt_req(struct esas2r_adapter *a,
    373			  struct esas2r_request *rq,
    374			  u8 sub_func,
    375			  u8 scan_gen,
    376			  u16 dev_index,
    377			  u32 length,
    378			  void *data)
    379{
    380	struct atto_vda_mgmt_req *vrq = &rq->vrq->mgt;
    381
    382	clear_vda_request(rq);
    383
    384	rq->vrq->scsi.function = VDA_FUNC_MGT;
    385
    386	vrq->mgt_func = sub_func;
    387	vrq->scan_generation = scan_gen;
    388	vrq->dev_index = cpu_to_le16(dev_index);
    389	vrq->length = cpu_to_le32(length);
    390
    391	if (vrq->length) {
    392		if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
    393			vrq->sg_list_offset = (u8)offsetof(
    394				struct atto_vda_mgmt_req, sge);
    395
    396			vrq->sge[0].length = cpu_to_le32(SGE_LAST | length);
    397			vrq->sge[0].address = cpu_to_le64(
    398				rq->vrq_md->phys_addr +
    399				sizeof(union atto_vda_req));
    400		} else {
    401			vrq->sg_list_offset = (u8)offsetof(
    402				struct atto_vda_mgmt_req, prde);
    403
    404			vrq->prde[0].ctl_len = cpu_to_le32(length);
    405			vrq->prde[0].address = cpu_to_le64(
    406				rq->vrq_md->phys_addr +
    407				sizeof(union atto_vda_req));
    408		}
    409	}
    410
    411	if (data) {
    412		esas2r_nuxi_mgt_data(sub_func, data);
    413
    414		memcpy(&rq->vda_rsp_data->mgt_data.data.bytes[0], data,
    415		       length);
    416	}
    417}
    418
    419/* Build a VDA asyncronous event (AE) request. */
    420void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq)
    421{
    422	struct atto_vda_ae_req *vrq = &rq->vrq->ae;
    423
    424	clear_vda_request(rq);
    425
    426	rq->vrq->scsi.function = VDA_FUNC_AE;
    427
    428	vrq->length = cpu_to_le32(sizeof(struct atto_vda_ae_data));
    429
    430	if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
    431		vrq->sg_list_offset =
    432			(u8)offsetof(struct atto_vda_ae_req, sge);
    433		vrq->sge[0].length = cpu_to_le32(SGE_LAST | vrq->length);
    434		vrq->sge[0].address = cpu_to_le64(
    435			rq->vrq_md->phys_addr +
    436			sizeof(union atto_vda_req));
    437	} else {
    438		vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ae_req,
    439						   prde);
    440		vrq->prde[0].ctl_len = cpu_to_le32(vrq->length);
    441		vrq->prde[0].address = cpu_to_le64(
    442			rq->vrq_md->phys_addr +
    443			sizeof(union atto_vda_req));
    444	}
    445}
    446
    447/* Build a VDA CLI request. */
    448void esas2r_build_cli_req(struct esas2r_adapter *a,
    449			  struct esas2r_request *rq,
    450			  u32 length,
    451			  u32 cmd_rsp_len)
    452{
    453	struct atto_vda_cli_req *vrq = &rq->vrq->cli;
    454
    455	clear_vda_request(rq);
    456
    457	rq->vrq->scsi.function = VDA_FUNC_CLI;
    458
    459	vrq->length = cpu_to_le32(length);
    460	vrq->cmd_rsp_len = cpu_to_le32(cmd_rsp_len);
    461	vrq->sg_list_offset = (u8)offsetof(struct atto_vda_cli_req, sge);
    462}
    463
    464/* Build a VDA IOCTL request. */
    465void esas2r_build_ioctl_req(struct esas2r_adapter *a,
    466			    struct esas2r_request *rq,
    467			    u32 length,
    468			    u8 sub_func)
    469{
    470	struct atto_vda_ioctl_req *vrq = &rq->vrq->ioctl;
    471
    472	clear_vda_request(rq);
    473
    474	rq->vrq->scsi.function = VDA_FUNC_IOCTL;
    475
    476	vrq->length = cpu_to_le32(length);
    477	vrq->sub_func = sub_func;
    478	vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ioctl_req, sge);
    479}
    480
    481/* Build a VDA configuration request. */
    482void esas2r_build_cfg_req(struct esas2r_adapter *a,
    483			  struct esas2r_request *rq,
    484			  u8 sub_func,
    485			  u32 length,
    486			  void *data)
    487{
    488	struct atto_vda_cfg_req *vrq = &rq->vrq->cfg;
    489
    490	clear_vda_request(rq);
    491
    492	rq->vrq->scsi.function = VDA_FUNC_CFG;
    493
    494	vrq->sub_func = sub_func;
    495	vrq->length = cpu_to_le32(length);
    496
    497	if (data) {
    498		esas2r_nuxi_cfg_data(sub_func, data);
    499
    500		memcpy(&vrq->data, data, length);
    501	}
    502}
    503
    504static void clear_vda_request(struct esas2r_request *rq)
    505{
    506	u32 handle = rq->vrq->scsi.handle;
    507
    508	memset(rq->vrq, 0, sizeof(*rq->vrq));
    509
    510	rq->vrq->scsi.handle = handle;
    511
    512	rq->req_stat = RS_PENDING;
    513
    514	/* since the data buffer is separate clear that too */
    515
    516	memset(rq->data_buf, 0, ESAS2R_DATA_BUF_LEN);
    517
    518	/*
    519	 * Setup next and prev pointer in case the request is not going through
    520	 * esas2r_start_request().
    521	 */
    522
    523	INIT_LIST_HEAD(&rq->req_list);
    524}