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

snic_ctl.c (7208B)


      1/*
      2 * Copyright 2014 Cisco Systems, Inc.  All rights reserved.
      3 *
      4 * This program is free software; you may redistribute it and/or modify
      5 * it under the terms of the GNU General Public License as published by
      6 * the Free Software Foundation; version 2 of the License.
      7 *
      8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     15 * SOFTWARE.
     16 */
     17
     18#include <linux/errno.h>
     19#include <linux/pci.h>
     20#include <linux/slab.h>
     21
     22#include <linux/interrupt.h>
     23#include <linux/workqueue.h>
     24#include <linux/spinlock.h>
     25#include <linux/mempool.h>
     26#include <scsi/scsi_tcq.h>
     27#include <linux/ctype.h>
     28
     29#include "snic_io.h"
     30#include "snic.h"
     31#include "cq_enet_desc.h"
     32#include "snic_fwint.h"
     33
     34/*
     35 * snic_handle_link : Handles link flaps.
     36 */
     37void
     38snic_handle_link(struct work_struct *work)
     39{
     40	struct snic *snic = container_of(work, struct snic, link_work);
     41
     42	if (snic->config.xpt_type == SNIC_DAS)
     43		return;
     44
     45	snic->link_status = svnic_dev_link_status(snic->vdev);
     46	snic->link_down_cnt = svnic_dev_link_down_cnt(snic->vdev);
     47	SNIC_HOST_INFO(snic->shost, "Link Event: Link %s.\n",
     48		       ((snic->link_status) ? "Up" : "Down"));
     49
     50	SNIC_ASSERT_NOT_IMPL(1);
     51}
     52
     53
     54/*
     55 * snic_ver_enc : Encodes version str to int
     56 * version string is similar to netmask string
     57 */
     58static int
     59snic_ver_enc(const char *s)
     60{
     61	int v[4] = {0};
     62	int  i = 0, x = 0;
     63	char c;
     64	const char *p = s;
     65
     66	/* validate version string */
     67	if ((strlen(s) > 15) || (strlen(s) < 7))
     68		goto end;
     69
     70	while ((c = *p++)) {
     71		if (c == '.') {
     72			i++;
     73			continue;
     74		}
     75
     76		if (i > 3 || !isdigit(c))
     77			goto end;
     78
     79		v[i] = v[i] * 10 + (c - '0');
     80	}
     81
     82	/* validate sub version numbers */
     83	for (i = 3; i >= 0; i--)
     84		if (v[i] > 0xff)
     85			goto end;
     86
     87	x |= (v[0] << 24) | v[1] << 16 | v[2] << 8 | v[3];
     88
     89end:
     90	if (x == 0) {
     91		SNIC_ERR("Invalid version string [%s].\n", s);
     92
     93		return -1;
     94	}
     95
     96	return x;
     97} /* end of snic_ver_enc */
     98
     99/*
    100 * snic_qeueue_exch_ver_req :
    101 *
    102 * Queues Exchange Version Request, to communicate host information
    103 * in return, it gets firmware version details
    104 */
    105int
    106snic_queue_exch_ver_req(struct snic *snic)
    107{
    108	struct snic_req_info *rqi = NULL;
    109	struct snic_host_req *req = NULL;
    110	u32 ver = 0;
    111	int ret = 0;
    112
    113	SNIC_HOST_INFO(snic->shost, "Exch Ver Req Preparing...\n");
    114
    115	rqi = snic_req_init(snic, 0);
    116	if (!rqi) {
    117		SNIC_HOST_ERR(snic->shost, "Init Exch Ver Req failed\n");
    118		ret = -ENOMEM;
    119		goto error;
    120	}
    121
    122	req = rqi_to_req(rqi);
    123
    124	/* Initialize snic_host_req */
    125	snic_io_hdr_enc(&req->hdr, SNIC_REQ_EXCH_VER, 0, SCSI_NO_TAG,
    126			snic->config.hid, 0, (ulong)rqi);
    127	ver = snic_ver_enc(SNIC_DRV_VERSION);
    128	req->u.exch_ver.drvr_ver = cpu_to_le32(ver);
    129	req->u.exch_ver.os_type = cpu_to_le32(SNIC_OS_LINUX);
    130
    131	snic_handle_untagged_req(snic, rqi);
    132
    133	ret = snic_queue_wq_desc(snic, req, sizeof(*req));
    134	if (ret) {
    135		snic_release_untagged_req(snic, rqi);
    136		SNIC_HOST_ERR(snic->shost,
    137			      "Queuing Exch Ver Req failed, err = %d\n",
    138			      ret);
    139		goto error;
    140	}
    141
    142	SNIC_HOST_INFO(snic->shost, "Exch Ver Req is issued. ret = %d\n", ret);
    143
    144error:
    145	return ret;
    146} /* end of snic_queue_exch_ver_req */
    147
    148/*
    149 * snic_io_exch_ver_cmpl_handler
    150 */
    151void
    152snic_io_exch_ver_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq)
    153{
    154	struct snic_req_info *rqi = NULL;
    155	struct snic_exch_ver_rsp *exv_cmpl = &fwreq->u.exch_ver_cmpl;
    156	u8 typ, hdr_stat;
    157	u32 cmnd_id, hid, max_sgs;
    158	ulong ctx = 0;
    159	unsigned long flags;
    160
    161	SNIC_HOST_INFO(snic->shost, "Exch Ver Compl Received.\n");
    162	snic_io_hdr_dec(&fwreq->hdr, &typ, &hdr_stat, &cmnd_id, &hid, &ctx);
    163	SNIC_BUG_ON(snic->config.hid != hid);
    164	rqi = (struct snic_req_info *) ctx;
    165
    166	if (hdr_stat) {
    167		SNIC_HOST_ERR(snic->shost,
    168			      "Exch Ver Completed w/ err status %d\n",
    169			      hdr_stat);
    170
    171		goto exch_cmpl_end;
    172	}
    173
    174	spin_lock_irqsave(&snic->snic_lock, flags);
    175	snic->fwinfo.fw_ver = le32_to_cpu(exv_cmpl->version);
    176	snic->fwinfo.hid = le32_to_cpu(exv_cmpl->hid);
    177	snic->fwinfo.max_concur_ios = le32_to_cpu(exv_cmpl->max_concur_ios);
    178	snic->fwinfo.max_sgs_per_cmd = le32_to_cpu(exv_cmpl->max_sgs_per_cmd);
    179	snic->fwinfo.max_io_sz = le32_to_cpu(exv_cmpl->max_io_sz);
    180	snic->fwinfo.max_tgts = le32_to_cpu(exv_cmpl->max_tgts);
    181	snic->fwinfo.io_tmo = le16_to_cpu(exv_cmpl->io_timeout);
    182
    183	SNIC_HOST_INFO(snic->shost,
    184		       "vers %u hid %u max_concur_ios %u max_sgs_per_cmd %u max_io_sz %u max_tgts %u fw tmo %u\n",
    185		       snic->fwinfo.fw_ver,
    186		       snic->fwinfo.hid,
    187		       snic->fwinfo.max_concur_ios,
    188		       snic->fwinfo.max_sgs_per_cmd,
    189		       snic->fwinfo.max_io_sz,
    190		       snic->fwinfo.max_tgts,
    191		       snic->fwinfo.io_tmo);
    192
    193	SNIC_HOST_INFO(snic->shost,
    194		       "HBA Capabilities = 0x%x\n",
    195		       le32_to_cpu(exv_cmpl->hba_cap));
    196
    197	/* Updating SGList size */
    198	max_sgs = snic->fwinfo.max_sgs_per_cmd;
    199	if (max_sgs && max_sgs < SNIC_MAX_SG_DESC_CNT) {
    200		snic->shost->sg_tablesize = max_sgs;
    201		SNIC_HOST_INFO(snic->shost, "Max SGs set to %d\n",
    202			       snic->shost->sg_tablesize);
    203	} else if (max_sgs > snic->shost->sg_tablesize) {
    204		SNIC_HOST_INFO(snic->shost,
    205			       "Target type %d Supports Larger Max SGList %d than driver's Max SG List %d.\n",
    206			       snic->config.xpt_type, max_sgs,
    207			       snic->shost->sg_tablesize);
    208	}
    209
    210	if (snic->shost->can_queue > snic->fwinfo.max_concur_ios)
    211		snic->shost->can_queue = snic->fwinfo.max_concur_ios;
    212
    213	snic->shost->max_sectors = snic->fwinfo.max_io_sz >> 9;
    214	if (snic->fwinfo.wait)
    215		complete(snic->fwinfo.wait);
    216
    217	spin_unlock_irqrestore(&snic->snic_lock, flags);
    218
    219exch_cmpl_end:
    220	snic_release_untagged_req(snic, rqi);
    221
    222	SNIC_HOST_INFO(snic->shost, "Exch_cmpl Done, hdr_stat %d.\n", hdr_stat);
    223} /* end of snic_io_exch_ver_cmpl_handler */
    224
    225/*
    226 * snic_get_conf
    227 *
    228 * Synchronous call, and Retrieves snic params.
    229 */
    230int
    231snic_get_conf(struct snic *snic)
    232{
    233	DECLARE_COMPLETION_ONSTACK(wait);
    234	unsigned long flags;
    235	int ret;
    236	int nr_retries = 3;
    237
    238	SNIC_HOST_INFO(snic->shost, "Retrieving snic params.\n");
    239	spin_lock_irqsave(&snic->snic_lock, flags);
    240	memset(&snic->fwinfo, 0, sizeof(snic->fwinfo));
    241	snic->fwinfo.wait = &wait;
    242	spin_unlock_irqrestore(&snic->snic_lock, flags);
    243
    244	/* Additional delay to handle HW Resource initialization. */
    245	msleep(50);
    246
    247	/*
    248	 * Exch ver req can be ignored by FW, if HW Resource initialization
    249	 * is in progress, Hence retry.
    250	 */
    251	do {
    252		ret = snic_queue_exch_ver_req(snic);
    253		if (ret)
    254			return ret;
    255
    256		wait_for_completion_timeout(&wait, msecs_to_jiffies(2000));
    257		spin_lock_irqsave(&snic->snic_lock, flags);
    258		ret = (snic->fwinfo.fw_ver != 0) ? 0 : -ETIMEDOUT;
    259		if (ret)
    260			SNIC_HOST_ERR(snic->shost,
    261				      "Failed to retrieve snic params,\n");
    262
    263		/* Unset fwinfo.wait, on success or on last retry */
    264		if (ret == 0 || nr_retries == 1)
    265			snic->fwinfo.wait = NULL;
    266
    267		spin_unlock_irqrestore(&snic->snic_lock, flags);
    268	} while (ret && --nr_retries);
    269
    270	return ret;
    271} /* end of snic_get_info */