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