18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * zfcp device driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Setup and helper functions to access QDIO.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2002, 2020
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "zfcp"
118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include "zfcp_ext.h"
168c2ecf20Sopenharmony_ci#include "zfcp_qdio.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic bool enable_multibuffer = true;
198c2ecf20Sopenharmony_cimodule_param_named(datarouter, enable_multibuffer, bool, 0400);
208c2ecf20Sopenharmony_ciMODULE_PARM_DESC(datarouter, "Enable hardware data router support (default on)");
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *dbftag,
238c2ecf20Sopenharmony_ci				    unsigned int qdio_err)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = qdio->adapter;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	if (qdio_err & QDIO_ERROR_SLSB_STATE) {
308c2ecf20Sopenharmony_ci		zfcp_qdio_siosl(adapter);
318c2ecf20Sopenharmony_ci		zfcp_erp_adapter_shutdown(adapter, 0, dbftag);
328c2ecf20Sopenharmony_ci		return;
338c2ecf20Sopenharmony_ci	}
348c2ecf20Sopenharmony_ci	zfcp_erp_adapter_reopen(adapter,
358c2ecf20Sopenharmony_ci				ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
368c2ecf20Sopenharmony_ci				ZFCP_STATUS_COMMON_ERP_FAILED, dbftag);
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	int i, sbal_idx;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	for (i = first; i < first + cnt; i++) {
448c2ecf20Sopenharmony_ci		sbal_idx = i % QDIO_MAX_BUFFERS_PER_Q;
458c2ecf20Sopenharmony_ci		memset(sbal[sbal_idx], 0, sizeof(struct qdio_buffer));
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* this needs to be called prior to updating the queue fill level */
508c2ecf20Sopenharmony_cistatic inline void zfcp_qdio_account(struct zfcp_qdio *qdio)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	unsigned long long now, span;
538c2ecf20Sopenharmony_ci	int used;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	now = get_tod_clock_monotonic();
568c2ecf20Sopenharmony_ci	span = (now - qdio->req_q_time) >> 12;
578c2ecf20Sopenharmony_ci	used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free);
588c2ecf20Sopenharmony_ci	qdio->req_q_util += used * span;
598c2ecf20Sopenharmony_ci	qdio->req_q_time = now;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,
638c2ecf20Sopenharmony_ci			      int queue_no, int idx, int count,
648c2ecf20Sopenharmony_ci			      unsigned long parm)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (unlikely(qdio_err)) {
698c2ecf20Sopenharmony_ci		zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err);
708c2ecf20Sopenharmony_ci		return;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	/* cleanup all SBALs being program-owned now */
748c2ecf20Sopenharmony_ci	zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	spin_lock_irq(&qdio->stat_lock);
778c2ecf20Sopenharmony_ci	zfcp_qdio_account(qdio);
788c2ecf20Sopenharmony_ci	spin_unlock_irq(&qdio->stat_lock);
798c2ecf20Sopenharmony_ci	atomic_add(count, &qdio->req_q_free);
808c2ecf20Sopenharmony_ci	wake_up(&qdio->req_q_wq);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
848c2ecf20Sopenharmony_ci			       int queue_no, int idx, int count,
858c2ecf20Sopenharmony_ci			       unsigned long parm)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
888c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = qdio->adapter;
898c2ecf20Sopenharmony_ci	int sbal_no, sbal_idx;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (unlikely(qdio_err)) {
928c2ecf20Sopenharmony_ci		if (zfcp_adapter_multi_buffer_active(adapter)) {
938c2ecf20Sopenharmony_ci			void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1];
948c2ecf20Sopenharmony_ci			struct qdio_buffer_element *sbale;
958c2ecf20Sopenharmony_ci			u64 req_id;
968c2ecf20Sopenharmony_ci			u8 scount;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci			memset(pl, 0,
998c2ecf20Sopenharmony_ci			       ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *));
1008c2ecf20Sopenharmony_ci			sbale = qdio->res_q[idx]->element;
1018c2ecf20Sopenharmony_ci			req_id = sbale->addr;
1028c2ecf20Sopenharmony_ci			scount = min(sbale->scount + 1,
1038c2ecf20Sopenharmony_ci				     ZFCP_QDIO_MAX_SBALS_PER_REQ + 1);
1048c2ecf20Sopenharmony_ci				     /* incl. signaling SBAL */
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci			for (sbal_no = 0; sbal_no < scount; sbal_no++) {
1078c2ecf20Sopenharmony_ci				sbal_idx = (idx + sbal_no) %
1088c2ecf20Sopenharmony_ci					QDIO_MAX_BUFFERS_PER_Q;
1098c2ecf20Sopenharmony_ci				pl[sbal_no] = qdio->res_q[sbal_idx];
1108c2ecf20Sopenharmony_ci			}
1118c2ecf20Sopenharmony_ci			zfcp_dbf_hba_def_err(adapter, req_id, scount, pl);
1128c2ecf20Sopenharmony_ci		}
1138c2ecf20Sopenharmony_ci		zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
1148c2ecf20Sopenharmony_ci		return;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/*
1188c2ecf20Sopenharmony_ci	 * go through all SBALs from input queue currently
1198c2ecf20Sopenharmony_ci	 * returned by QDIO layer
1208c2ecf20Sopenharmony_ci	 */
1218c2ecf20Sopenharmony_ci	for (sbal_no = 0; sbal_no < count; sbal_no++) {
1228c2ecf20Sopenharmony_ci		sbal_idx = (idx + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
1238c2ecf20Sopenharmony_ci		/* go through all SBALEs of SBAL */
1248c2ecf20Sopenharmony_ci		zfcp_fsf_reqid_check(qdio, sbal_idx);
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/*
1288c2ecf20Sopenharmony_ci	 * put SBALs back to response queue
1298c2ecf20Sopenharmony_ci	 */
1308c2ecf20Sopenharmony_ci	if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count))
1318c2ecf20Sopenharmony_ci		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2");
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic struct qdio_buffer_element *
1358c2ecf20Sopenharmony_cizfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	struct qdio_buffer_element *sbale;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/* set last entry flag in current SBALE of current SBAL */
1408c2ecf20Sopenharmony_ci	sbale = zfcp_qdio_sbale_curr(qdio, q_req);
1418c2ecf20Sopenharmony_ci	sbale->eflags |= SBAL_EFLAGS_LAST_ENTRY;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/* don't exceed last allowed SBAL */
1448c2ecf20Sopenharmony_ci	if (q_req->sbal_last == q_req->sbal_limit)
1458c2ecf20Sopenharmony_ci		return NULL;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* set chaining flag in first SBALE of current SBAL */
1488c2ecf20Sopenharmony_ci	sbale = zfcp_qdio_sbale_req(qdio, q_req);
1498c2ecf20Sopenharmony_ci	sbale->sflags |= SBAL_SFLAGS0_MORE_SBALS;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* calculate index of next SBAL */
1528c2ecf20Sopenharmony_ci	q_req->sbal_last++;
1538c2ecf20Sopenharmony_ci	q_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* keep this requests number of SBALs up-to-date */
1568c2ecf20Sopenharmony_ci	q_req->sbal_number++;
1578c2ecf20Sopenharmony_ci	BUG_ON(q_req->sbal_number > ZFCP_QDIO_MAX_SBALS_PER_REQ);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* start at first SBALE of new SBAL */
1608c2ecf20Sopenharmony_ci	q_req->sbale_curr = 0;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* set storage-block type for new SBAL */
1638c2ecf20Sopenharmony_ci	sbale = zfcp_qdio_sbale_curr(qdio, q_req);
1648c2ecf20Sopenharmony_ci	sbale->sflags |= q_req->sbtype;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	return sbale;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic struct qdio_buffer_element *
1708c2ecf20Sopenharmony_cizfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	if (q_req->sbale_curr == qdio->max_sbale_per_sbal - 1)
1738c2ecf20Sopenharmony_ci		return zfcp_qdio_sbal_chain(qdio, q_req);
1748c2ecf20Sopenharmony_ci	q_req->sbale_curr++;
1758c2ecf20Sopenharmony_ci	return zfcp_qdio_sbale_curr(qdio, q_req);
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci/**
1798c2ecf20Sopenharmony_ci * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
1808c2ecf20Sopenharmony_ci * @qdio: pointer to struct zfcp_qdio
1818c2ecf20Sopenharmony_ci * @q_req: pointer to struct zfcp_qdio_req
1828c2ecf20Sopenharmony_ci * @sg: scatter-gather list
1838c2ecf20Sopenharmony_ci * Returns: zero or -EINVAL on error
1848c2ecf20Sopenharmony_ci */
1858c2ecf20Sopenharmony_ciint zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
1868c2ecf20Sopenharmony_ci			    struct scatterlist *sg)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct qdio_buffer_element *sbale;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	/* set storage-block type for this request */
1918c2ecf20Sopenharmony_ci	sbale = zfcp_qdio_sbale_req(qdio, q_req);
1928c2ecf20Sopenharmony_ci	sbale->sflags |= q_req->sbtype;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	for (; sg; sg = sg_next(sg)) {
1958c2ecf20Sopenharmony_ci		sbale = zfcp_qdio_sbale_next(qdio, q_req);
1968c2ecf20Sopenharmony_ci		if (!sbale) {
1978c2ecf20Sopenharmony_ci			atomic_inc(&qdio->req_q_full);
1988c2ecf20Sopenharmony_ci			zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
1998c2ecf20Sopenharmony_ci					     q_req->sbal_number);
2008c2ecf20Sopenharmony_ci			return -EINVAL;
2018c2ecf20Sopenharmony_ci		}
2028c2ecf20Sopenharmony_ci		sbale->addr = sg_phys(sg);
2038c2ecf20Sopenharmony_ci		sbale->length = sg->length;
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci	return 0;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	if (atomic_read(&qdio->req_q_free) ||
2118c2ecf20Sopenharmony_ci	    !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
2128c2ecf20Sopenharmony_ci		return 1;
2138c2ecf20Sopenharmony_ci	return 0;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci/**
2178c2ecf20Sopenharmony_ci * zfcp_qdio_sbal_get - get free sbal in request queue, wait if necessary
2188c2ecf20Sopenharmony_ci * @qdio: pointer to struct zfcp_qdio
2198c2ecf20Sopenharmony_ci *
2208c2ecf20Sopenharmony_ci * The req_q_lock must be held by the caller of this function, and
2218c2ecf20Sopenharmony_ci * this function may only be called from process context; it will
2228c2ecf20Sopenharmony_ci * sleep when waiting for a free sbal.
2238c2ecf20Sopenharmony_ci *
2248c2ecf20Sopenharmony_ci * Returns: 0 on success, -EIO if there is no free sbal after waiting.
2258c2ecf20Sopenharmony_ci */
2268c2ecf20Sopenharmony_ciint zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	long ret;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	ret = wait_event_interruptible_lock_irq_timeout(qdio->req_q_wq,
2318c2ecf20Sopenharmony_ci		       zfcp_qdio_sbal_check(qdio), qdio->req_q_lock, 5 * HZ);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
2348c2ecf20Sopenharmony_ci		return -EIO;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (ret > 0)
2378c2ecf20Sopenharmony_ci		return 0;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (!ret) {
2408c2ecf20Sopenharmony_ci		atomic_inc(&qdio->req_q_full);
2418c2ecf20Sopenharmony_ci		/* assume hanging outbound queue, try queue recovery */
2428c2ecf20Sopenharmony_ci		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1");
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return -EIO;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/**
2498c2ecf20Sopenharmony_ci * zfcp_qdio_send - send req to QDIO
2508c2ecf20Sopenharmony_ci * @qdio: pointer to struct zfcp_qdio
2518c2ecf20Sopenharmony_ci * @q_req: pointer to struct zfcp_qdio_req
2528c2ecf20Sopenharmony_ci * Returns: 0 on success, error otherwise
2538c2ecf20Sopenharmony_ci */
2548c2ecf20Sopenharmony_ciint zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	int retval;
2578c2ecf20Sopenharmony_ci	u8 sbal_number = q_req->sbal_number;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	spin_lock(&qdio->stat_lock);
2608c2ecf20Sopenharmony_ci	zfcp_qdio_account(qdio);
2618c2ecf20Sopenharmony_ci	spin_unlock(&qdio->stat_lock);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	atomic_sub(sbal_number, &qdio->req_q_free);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0,
2668c2ecf20Sopenharmony_ci			 q_req->sbal_first, sbal_number);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (unlikely(retval)) {
2698c2ecf20Sopenharmony_ci		/* Failed to submit the IO, roll back our modifications. */
2708c2ecf20Sopenharmony_ci		atomic_add(sbal_number, &qdio->req_q_free);
2718c2ecf20Sopenharmony_ci		zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
2728c2ecf20Sopenharmony_ci				     sbal_number);
2738c2ecf20Sopenharmony_ci		return retval;
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/* account for transferred buffers */
2778c2ecf20Sopenharmony_ci	qdio->req_q_idx += sbal_number;
2788c2ecf20Sopenharmony_ci	qdio->req_q_idx %= QDIO_MAX_BUFFERS_PER_Q;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return 0;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/**
2848c2ecf20Sopenharmony_ci * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
2858c2ecf20Sopenharmony_ci * @qdio: pointer to struct zfcp_qdio
2868c2ecf20Sopenharmony_ci * Returns: -ENOMEM on memory allocation error or return value from
2878c2ecf20Sopenharmony_ci *          qdio_allocate
2888c2ecf20Sopenharmony_ci */
2898c2ecf20Sopenharmony_cistatic int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	int ret;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	ret = qdio_alloc_buffers(qdio->req_q, QDIO_MAX_BUFFERS_PER_Q);
2948c2ecf20Sopenharmony_ci	if (ret)
2958c2ecf20Sopenharmony_ci		return -ENOMEM;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	ret = qdio_alloc_buffers(qdio->res_q, QDIO_MAX_BUFFERS_PER_Q);
2988c2ecf20Sopenharmony_ci	if (ret)
2998c2ecf20Sopenharmony_ci		goto free_req_q;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	init_waitqueue_head(&qdio->req_q_wq);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	ret = qdio_allocate(qdio->adapter->ccw_device, 1, 1);
3048c2ecf20Sopenharmony_ci	if (ret)
3058c2ecf20Sopenharmony_ci		goto free_res_q;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return 0;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cifree_res_q:
3108c2ecf20Sopenharmony_ci	qdio_free_buffers(qdio->res_q, QDIO_MAX_BUFFERS_PER_Q);
3118c2ecf20Sopenharmony_cifree_req_q:
3128c2ecf20Sopenharmony_ci	qdio_free_buffers(qdio->req_q, QDIO_MAX_BUFFERS_PER_Q);
3138c2ecf20Sopenharmony_ci	return ret;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci/**
3178c2ecf20Sopenharmony_ci * zfcp_close_qdio - close qdio queues for an adapter
3188c2ecf20Sopenharmony_ci * @qdio: pointer to structure zfcp_qdio
3198c2ecf20Sopenharmony_ci */
3208c2ecf20Sopenharmony_civoid zfcp_qdio_close(struct zfcp_qdio *qdio)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = qdio->adapter;
3238c2ecf20Sopenharmony_ci	int idx, count;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
3268c2ecf20Sopenharmony_ci		return;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
3298c2ecf20Sopenharmony_ci	spin_lock_irq(&qdio->req_q_lock);
3308c2ecf20Sopenharmony_ci	atomic_andnot(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
3318c2ecf20Sopenharmony_ci	spin_unlock_irq(&qdio->req_q_lock);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	wake_up(&qdio->req_q_wq);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* cleanup used outbound sbals */
3388c2ecf20Sopenharmony_ci	count = atomic_read(&qdio->req_q_free);
3398c2ecf20Sopenharmony_ci	if (count < QDIO_MAX_BUFFERS_PER_Q) {
3408c2ecf20Sopenharmony_ci		idx = (qdio->req_q_idx + count) % QDIO_MAX_BUFFERS_PER_Q;
3418c2ecf20Sopenharmony_ci		count = QDIO_MAX_BUFFERS_PER_Q - count;
3428c2ecf20Sopenharmony_ci		zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	qdio->req_q_idx = 0;
3458c2ecf20Sopenharmony_ci	atomic_set(&qdio->req_q_free, 0);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_civoid zfcp_qdio_shost_update(struct zfcp_adapter *const adapter,
3498c2ecf20Sopenharmony_ci			    const struct zfcp_qdio *const qdio)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct Scsi_Host *const shost = adapter->scsi_host;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (shost == NULL)
3548c2ecf20Sopenharmony_ci		return;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	shost->sg_tablesize = qdio->max_sbale_per_req;
3578c2ecf20Sopenharmony_ci	shost->max_sectors = qdio->max_sbale_per_req * 8;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci/**
3618c2ecf20Sopenharmony_ci * zfcp_qdio_open - prepare and initialize response queue
3628c2ecf20Sopenharmony_ci * @qdio: pointer to struct zfcp_qdio
3638c2ecf20Sopenharmony_ci * Returns: 0 on success, otherwise -EIO
3648c2ecf20Sopenharmony_ci */
3658c2ecf20Sopenharmony_ciint zfcp_qdio_open(struct zfcp_qdio *qdio)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	struct qdio_buffer **input_sbals[1] = {qdio->res_q};
3688c2ecf20Sopenharmony_ci	struct qdio_buffer **output_sbals[1] = {qdio->req_q};
3698c2ecf20Sopenharmony_ci	struct qdio_buffer_element *sbale;
3708c2ecf20Sopenharmony_ci	struct qdio_initialize init_data = {0};
3718c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = qdio->adapter;
3728c2ecf20Sopenharmony_ci	struct ccw_device *cdev = adapter->ccw_device;
3738c2ecf20Sopenharmony_ci	struct qdio_ssqd_desc ssqd;
3748c2ecf20Sopenharmony_ci	int cc;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
3778c2ecf20Sopenharmony_ci		return -EIO;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	atomic_andnot(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
3808c2ecf20Sopenharmony_ci			  &qdio->adapter->status);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	init_data.q_format = QDIO_ZFCP_QFMT;
3838c2ecf20Sopenharmony_ci	init_data.qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
3848c2ecf20Sopenharmony_ci	if (enable_multibuffer)
3858c2ecf20Sopenharmony_ci		init_data.qdr_ac |= QDR_AC_MULTI_BUFFER_ENABLE;
3868c2ecf20Sopenharmony_ci	init_data.no_input_qs = 1;
3878c2ecf20Sopenharmony_ci	init_data.no_output_qs = 1;
3888c2ecf20Sopenharmony_ci	init_data.input_handler = zfcp_qdio_int_resp;
3898c2ecf20Sopenharmony_ci	init_data.output_handler = zfcp_qdio_int_req;
3908c2ecf20Sopenharmony_ci	init_data.int_parm = (unsigned long) qdio;
3918c2ecf20Sopenharmony_ci	init_data.input_sbal_addr_array = input_sbals;
3928c2ecf20Sopenharmony_ci	init_data.output_sbal_addr_array = output_sbals;
3938c2ecf20Sopenharmony_ci	init_data.scan_threshold =
3948c2ecf20Sopenharmony_ci		QDIO_MAX_BUFFERS_PER_Q - ZFCP_QDIO_MAX_SBALS_PER_REQ * 2;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (qdio_establish(cdev, &init_data))
3978c2ecf20Sopenharmony_ci		goto failed_establish;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (qdio_get_ssqd_desc(cdev, &ssqd))
4008c2ecf20Sopenharmony_ci		goto failed_qdio;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED)
4038c2ecf20Sopenharmony_ci		atomic_or(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED,
4048c2ecf20Sopenharmony_ci				&qdio->adapter->status);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (ssqd.qdioac2 & CHSC_AC2_MULTI_BUFFER_ENABLED) {
4078c2ecf20Sopenharmony_ci		atomic_or(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status);
4088c2ecf20Sopenharmony_ci		qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER;
4098c2ecf20Sopenharmony_ci	} else {
4108c2ecf20Sopenharmony_ci		atomic_andnot(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status);
4118c2ecf20Sopenharmony_ci		qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER - 1;
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	qdio->max_sbale_per_req =
4158c2ecf20Sopenharmony_ci		ZFCP_QDIO_MAX_SBALS_PER_REQ * qdio->max_sbale_per_sbal
4168c2ecf20Sopenharmony_ci		- 2;
4178c2ecf20Sopenharmony_ci	if (qdio_activate(cdev))
4188c2ecf20Sopenharmony_ci		goto failed_qdio;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
4218c2ecf20Sopenharmony_ci		sbale = &(qdio->res_q[cc]->element[0]);
4228c2ecf20Sopenharmony_ci		sbale->length = 0;
4238c2ecf20Sopenharmony_ci		sbale->eflags = SBAL_EFLAGS_LAST_ENTRY;
4248c2ecf20Sopenharmony_ci		sbale->sflags = 0;
4258c2ecf20Sopenharmony_ci		sbale->addr = 0;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q))
4298c2ecf20Sopenharmony_ci		goto failed_qdio;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	/* set index of first available SBALS / number of available SBALS */
4328c2ecf20Sopenharmony_ci	qdio->req_q_idx = 0;
4338c2ecf20Sopenharmony_ci	atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q);
4348c2ecf20Sopenharmony_ci	atomic_or(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	zfcp_qdio_shost_update(adapter, qdio);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	return 0;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cifailed_qdio:
4418c2ecf20Sopenharmony_ci	qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
4428c2ecf20Sopenharmony_cifailed_establish:
4438c2ecf20Sopenharmony_ci	dev_err(&cdev->dev,
4448c2ecf20Sopenharmony_ci		"Setting up the QDIO connection to the FCP adapter failed\n");
4458c2ecf20Sopenharmony_ci	return -EIO;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_civoid zfcp_qdio_destroy(struct zfcp_qdio *qdio)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	if (!qdio)
4518c2ecf20Sopenharmony_ci		return;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (qdio->adapter->ccw_device)
4548c2ecf20Sopenharmony_ci		qdio_free(qdio->adapter->ccw_device);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	qdio_free_buffers(qdio->req_q, QDIO_MAX_BUFFERS_PER_Q);
4578c2ecf20Sopenharmony_ci	qdio_free_buffers(qdio->res_q, QDIO_MAX_BUFFERS_PER_Q);
4588c2ecf20Sopenharmony_ci	kfree(qdio);
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ciint zfcp_qdio_setup(struct zfcp_adapter *adapter)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	struct zfcp_qdio *qdio;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	qdio = kzalloc(sizeof(struct zfcp_qdio), GFP_KERNEL);
4668c2ecf20Sopenharmony_ci	if (!qdio)
4678c2ecf20Sopenharmony_ci		return -ENOMEM;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	qdio->adapter = adapter;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	if (zfcp_qdio_allocate(qdio)) {
4728c2ecf20Sopenharmony_ci		kfree(qdio);
4738c2ecf20Sopenharmony_ci		return -ENOMEM;
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	spin_lock_init(&qdio->req_q_lock);
4778c2ecf20Sopenharmony_ci	spin_lock_init(&qdio->stat_lock);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	adapter->qdio = qdio;
4808c2ecf20Sopenharmony_ci	return 0;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci/**
4848c2ecf20Sopenharmony_ci * zfcp_qdio_siosl - Trigger logging in FCP channel
4858c2ecf20Sopenharmony_ci * @adapter: The zfcp_adapter where to trigger logging
4868c2ecf20Sopenharmony_ci *
4878c2ecf20Sopenharmony_ci * Call the cio siosl function to trigger hardware logging.  This
4888c2ecf20Sopenharmony_ci * wrapper function sets a flag to ensure hardware logging is only
4898c2ecf20Sopenharmony_ci * triggered once before going through qdio shutdown.
4908c2ecf20Sopenharmony_ci *
4918c2ecf20Sopenharmony_ci * The triggers are always run from qdio tasklet context, so no
4928c2ecf20Sopenharmony_ci * additional synchronization is necessary.
4938c2ecf20Sopenharmony_ci */
4948c2ecf20Sopenharmony_civoid zfcp_qdio_siosl(struct zfcp_adapter *adapter)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	int rc;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_SIOSL_ISSUED)
4998c2ecf20Sopenharmony_ci		return;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	rc = ccw_device_siosl(adapter->ccw_device);
5028c2ecf20Sopenharmony_ci	if (!rc)
5038c2ecf20Sopenharmony_ci		atomic_or(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
5048c2ecf20Sopenharmony_ci				&adapter->status);
5058c2ecf20Sopenharmony_ci}
506