18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * zfcp device driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Module interface and handling of zfcp data structures. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2002, 2020 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * Driver authors: 128c2ecf20Sopenharmony_ci * Martin Peschke (originator of the driver) 138c2ecf20Sopenharmony_ci * Raimund Schroeder 148c2ecf20Sopenharmony_ci * Aron Zeh 158c2ecf20Sopenharmony_ci * Wolfgang Taphorn 168c2ecf20Sopenharmony_ci * Stefan Bader 178c2ecf20Sopenharmony_ci * Heiko Carstens (kernel 2.6 port of the driver) 188c2ecf20Sopenharmony_ci * Andreas Herrmann 198c2ecf20Sopenharmony_ci * Maxim Shchetynin 208c2ecf20Sopenharmony_ci * Volker Sameske 218c2ecf20Sopenharmony_ci * Ralph Wuerthner 228c2ecf20Sopenharmony_ci * Michael Loehr 238c2ecf20Sopenharmony_ci * Swen Schillig 248c2ecf20Sopenharmony_ci * Christof Schmitt 258c2ecf20Sopenharmony_ci * Martin Petermann 268c2ecf20Sopenharmony_ci * Sven Schuetz 278c2ecf20Sopenharmony_ci * Steffen Maier 288c2ecf20Sopenharmony_ci * Benjamin Block 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "zfcp" 328c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 358c2ecf20Sopenharmony_ci#include <linux/slab.h> 368c2ecf20Sopenharmony_ci#include <linux/module.h> 378c2ecf20Sopenharmony_ci#include "zfcp_ext.h" 388c2ecf20Sopenharmony_ci#include "zfcp_fc.h" 398c2ecf20Sopenharmony_ci#include "zfcp_reqlist.h" 408c2ecf20Sopenharmony_ci#include "zfcp_diag.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define ZFCP_BUS_ID_SIZE 20 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciMODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com"); 458c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("FCP HBA driver"); 468c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic char *init_device; 498c2ecf20Sopenharmony_cimodule_param_named(device, init_device, charp, 0400); 508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(device, "specify initial device"); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic struct kmem_cache * __init zfcp_cache_hw_align(const char *name, 538c2ecf20Sopenharmony_ci unsigned long size) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci return kmem_cache_create(name, size, roundup_pow_of_two(size), 0, NULL); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct ccw_device *cdev; 618c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter; 628c2ecf20Sopenharmony_ci struct zfcp_port *port; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); 658c2ecf20Sopenharmony_ci if (!cdev) 668c2ecf20Sopenharmony_ci return; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (ccw_device_set_online(cdev)) 698c2ecf20Sopenharmony_ci goto out_ccw_device; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci adapter = zfcp_ccw_adapter_by_cdev(cdev); 728c2ecf20Sopenharmony_ci if (!adapter) 738c2ecf20Sopenharmony_ci goto out_ccw_device; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci port = zfcp_get_port_by_wwpn(adapter, wwpn); 768c2ecf20Sopenharmony_ci if (!port) 778c2ecf20Sopenharmony_ci goto out_port; 788c2ecf20Sopenharmony_ci flush_work(&port->rport_work); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci zfcp_unit_add(port, lun); 818c2ecf20Sopenharmony_ci put_device(&port->dev); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciout_port: 848c2ecf20Sopenharmony_ci zfcp_ccw_adapter_put(adapter); 858c2ecf20Sopenharmony_ciout_ccw_device: 868c2ecf20Sopenharmony_ci put_device(&cdev->dev); 878c2ecf20Sopenharmony_ci return; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void __init zfcp_init_device_setup(char *devstr) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci char *token; 938c2ecf20Sopenharmony_ci char *str, *str_saved; 948c2ecf20Sopenharmony_ci char busid[ZFCP_BUS_ID_SIZE]; 958c2ecf20Sopenharmony_ci u64 wwpn, lun; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* duplicate devstr and keep the original for sysfs presentation*/ 988c2ecf20Sopenharmony_ci str_saved = kstrdup(devstr, GFP_KERNEL); 998c2ecf20Sopenharmony_ci str = str_saved; 1008c2ecf20Sopenharmony_ci if (!str) 1018c2ecf20Sopenharmony_ci return; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci token = strsep(&str, ","); 1048c2ecf20Sopenharmony_ci if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE) 1058c2ecf20Sopenharmony_ci goto err_out; 1068c2ecf20Sopenharmony_ci strlcpy(busid, token, ZFCP_BUS_ID_SIZE); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci token = strsep(&str, ","); 1098c2ecf20Sopenharmony_ci if (!token || kstrtoull(token, 0, (unsigned long long *) &wwpn)) 1108c2ecf20Sopenharmony_ci goto err_out; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci token = strsep(&str, ","); 1138c2ecf20Sopenharmony_ci if (!token || kstrtoull(token, 0, (unsigned long long *) &lun)) 1148c2ecf20Sopenharmony_ci goto err_out; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci kfree(str_saved); 1178c2ecf20Sopenharmony_ci zfcp_init_device_configure(busid, wwpn, lun); 1188c2ecf20Sopenharmony_ci return; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cierr_out: 1218c2ecf20Sopenharmony_ci kfree(str_saved); 1228c2ecf20Sopenharmony_ci pr_err("%s is not a valid SCSI device\n", devstr); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int __init zfcp_module_init(void) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci int retval = -ENOMEM; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (zfcp_experimental_dix) 1308c2ecf20Sopenharmony_ci pr_warn("DIX is enabled. It is experimental and might cause problems\n"); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci zfcp_fsf_qtcb_cache = zfcp_cache_hw_align("zfcp_fsf_qtcb", 1338c2ecf20Sopenharmony_ci sizeof(struct fsf_qtcb)); 1348c2ecf20Sopenharmony_ci if (!zfcp_fsf_qtcb_cache) 1358c2ecf20Sopenharmony_ci goto out_qtcb_cache; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci zfcp_fc_req_cache = zfcp_cache_hw_align("zfcp_fc_req", 1388c2ecf20Sopenharmony_ci sizeof(struct zfcp_fc_req)); 1398c2ecf20Sopenharmony_ci if (!zfcp_fc_req_cache) 1408c2ecf20Sopenharmony_ci goto out_fc_cache; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci zfcp_scsi_transport_template = 1438c2ecf20Sopenharmony_ci fc_attach_transport(&zfcp_transport_functions); 1448c2ecf20Sopenharmony_ci if (!zfcp_scsi_transport_template) 1458c2ecf20Sopenharmony_ci goto out_transport; 1468c2ecf20Sopenharmony_ci scsi_transport_reserve_device(zfcp_scsi_transport_template, 1478c2ecf20Sopenharmony_ci sizeof(struct zfcp_scsi_dev)); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci retval = ccw_driver_register(&zfcp_ccw_driver); 1508c2ecf20Sopenharmony_ci if (retval) { 1518c2ecf20Sopenharmony_ci pr_err("The zfcp device driver could not register with " 1528c2ecf20Sopenharmony_ci "the common I/O layer\n"); 1538c2ecf20Sopenharmony_ci goto out_ccw_register; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (init_device) 1578c2ecf20Sopenharmony_ci zfcp_init_device_setup(init_device); 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ciout_ccw_register: 1618c2ecf20Sopenharmony_ci fc_release_transport(zfcp_scsi_transport_template); 1628c2ecf20Sopenharmony_ciout_transport: 1638c2ecf20Sopenharmony_ci kmem_cache_destroy(zfcp_fc_req_cache); 1648c2ecf20Sopenharmony_ciout_fc_cache: 1658c2ecf20Sopenharmony_ci kmem_cache_destroy(zfcp_fsf_qtcb_cache); 1668c2ecf20Sopenharmony_ciout_qtcb_cache: 1678c2ecf20Sopenharmony_ci return retval; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cimodule_init(zfcp_module_init); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void __exit zfcp_module_exit(void) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci ccw_driver_unregister(&zfcp_ccw_driver); 1758c2ecf20Sopenharmony_ci fc_release_transport(zfcp_scsi_transport_template); 1768c2ecf20Sopenharmony_ci kmem_cache_destroy(zfcp_fc_req_cache); 1778c2ecf20Sopenharmony_ci kmem_cache_destroy(zfcp_fsf_qtcb_cache); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cimodule_exit(zfcp_module_exit); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/** 1838c2ecf20Sopenharmony_ci * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn 1848c2ecf20Sopenharmony_ci * @adapter: pointer to adapter to search for port 1858c2ecf20Sopenharmony_ci * @wwpn: wwpn to search for 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * Returns: pointer to zfcp_port or NULL 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_cistruct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, 1908c2ecf20Sopenharmony_ci u64 wwpn) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci unsigned long flags; 1938c2ecf20Sopenharmony_ci struct zfcp_port *port; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci read_lock_irqsave(&adapter->port_list_lock, flags); 1968c2ecf20Sopenharmony_ci list_for_each_entry(port, &adapter->port_list, list) 1978c2ecf20Sopenharmony_ci if (port->wwpn == wwpn) { 1988c2ecf20Sopenharmony_ci if (!get_device(&port->dev)) 1998c2ecf20Sopenharmony_ci port = NULL; 2008c2ecf20Sopenharmony_ci read_unlock_irqrestore(&adapter->port_list_lock, flags); 2018c2ecf20Sopenharmony_ci return port; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci read_unlock_irqrestore(&adapter->port_list_lock, flags); 2048c2ecf20Sopenharmony_ci return NULL; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci adapter->pool.erp_req = 2108c2ecf20Sopenharmony_ci mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); 2118c2ecf20Sopenharmony_ci if (!adapter->pool.erp_req) 2128c2ecf20Sopenharmony_ci return -ENOMEM; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci adapter->pool.gid_pn_req = 2158c2ecf20Sopenharmony_ci mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); 2168c2ecf20Sopenharmony_ci if (!adapter->pool.gid_pn_req) 2178c2ecf20Sopenharmony_ci return -ENOMEM; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci adapter->pool.scsi_req = 2208c2ecf20Sopenharmony_ci mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); 2218c2ecf20Sopenharmony_ci if (!adapter->pool.scsi_req) 2228c2ecf20Sopenharmony_ci return -ENOMEM; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci adapter->pool.scsi_abort = 2258c2ecf20Sopenharmony_ci mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); 2268c2ecf20Sopenharmony_ci if (!adapter->pool.scsi_abort) 2278c2ecf20Sopenharmony_ci return -ENOMEM; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci adapter->pool.status_read_req = 2308c2ecf20Sopenharmony_ci mempool_create_kmalloc_pool(FSF_STATUS_READS_RECOM, 2318c2ecf20Sopenharmony_ci sizeof(struct zfcp_fsf_req)); 2328c2ecf20Sopenharmony_ci if (!adapter->pool.status_read_req) 2338c2ecf20Sopenharmony_ci return -ENOMEM; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci adapter->pool.qtcb_pool = 2368c2ecf20Sopenharmony_ci mempool_create_slab_pool(4, zfcp_fsf_qtcb_cache); 2378c2ecf20Sopenharmony_ci if (!adapter->pool.qtcb_pool) 2388c2ecf20Sopenharmony_ci return -ENOMEM; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct fsf_status_read_buffer) > PAGE_SIZE); 2418c2ecf20Sopenharmony_ci adapter->pool.sr_data = 2428c2ecf20Sopenharmony_ci mempool_create_page_pool(FSF_STATUS_READS_RECOM, 0); 2438c2ecf20Sopenharmony_ci if (!adapter->pool.sr_data) 2448c2ecf20Sopenharmony_ci return -ENOMEM; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci adapter->pool.gid_pn = 2478c2ecf20Sopenharmony_ci mempool_create_slab_pool(1, zfcp_fc_req_cache); 2488c2ecf20Sopenharmony_ci if (!adapter->pool.gid_pn) 2498c2ecf20Sopenharmony_ci return -ENOMEM; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci mempool_destroy(adapter->pool.erp_req); 2578c2ecf20Sopenharmony_ci mempool_destroy(adapter->pool.scsi_req); 2588c2ecf20Sopenharmony_ci mempool_destroy(adapter->pool.scsi_abort); 2598c2ecf20Sopenharmony_ci mempool_destroy(adapter->pool.qtcb_pool); 2608c2ecf20Sopenharmony_ci mempool_destroy(adapter->pool.status_read_req); 2618c2ecf20Sopenharmony_ci mempool_destroy(adapter->pool.sr_data); 2628c2ecf20Sopenharmony_ci mempool_destroy(adapter->pool.gid_pn); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci/** 2668c2ecf20Sopenharmony_ci * zfcp_status_read_refill - refill the long running status_read_requests 2678c2ecf20Sopenharmony_ci * @adapter: ptr to struct zfcp_adapter for which the buffers should be refilled 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * Return: 2708c2ecf20Sopenharmony_ci * * 0 on success meaning at least one status read is pending 2718c2ecf20Sopenharmony_ci * * 1 if posting failed and not a single status read buffer is pending, 2728c2ecf20Sopenharmony_ci * also triggers adapter reopen recovery 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ciint zfcp_status_read_refill(struct zfcp_adapter *adapter) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci while (atomic_add_unless(&adapter->stat_miss, -1, 0)) 2778c2ecf20Sopenharmony_ci if (zfcp_fsf_status_read(adapter->qdio)) { 2788c2ecf20Sopenharmony_ci atomic_inc(&adapter->stat_miss); /* undo add -1 */ 2798c2ecf20Sopenharmony_ci if (atomic_read(&adapter->stat_miss) >= 2808c2ecf20Sopenharmony_ci adapter->stat_read_buf_num) { 2818c2ecf20Sopenharmony_ci zfcp_erp_adapter_reopen(adapter, 0, "axsref1"); 2828c2ecf20Sopenharmony_ci return 1; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void _zfcp_status_read_scheduler(struct work_struct *work) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci zfcp_status_read_refill(container_of(work, struct zfcp_adapter, 2928c2ecf20Sopenharmony_ci stat_work)); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic void zfcp_print_sl(struct seq_file *m, struct service_level *sl) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = 2988c2ecf20Sopenharmony_ci container_of(sl, struct zfcp_adapter, service_level); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci seq_printf(m, "zfcp: %s microcode level %x\n", 3018c2ecf20Sopenharmony_ci dev_name(&adapter->ccw_device->dev), 3028c2ecf20Sopenharmony_ci adapter->fsf_lic_version); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int zfcp_setup_adapter_work_queue(struct zfcp_adapter *adapter) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci char name[TASK_COMM_LEN]; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "zfcp_q_%s", 3108c2ecf20Sopenharmony_ci dev_name(&adapter->ccw_device->dev)); 3118c2ecf20Sopenharmony_ci adapter->work_queue = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (adapter->work_queue) 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci return -ENOMEM; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci if (adapter->work_queue) 3218c2ecf20Sopenharmony_ci destroy_workqueue(adapter->work_queue); 3228c2ecf20Sopenharmony_ci adapter->work_queue = NULL; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci/** 3278c2ecf20Sopenharmony_ci * zfcp_adapter_enqueue - enqueue a new adapter to the list 3288c2ecf20Sopenharmony_ci * @ccw_device: pointer to the struct cc_device 3298c2ecf20Sopenharmony_ci * 3308c2ecf20Sopenharmony_ci * Returns: struct zfcp_adapter* 3318c2ecf20Sopenharmony_ci * Enqueues an adapter at the end of the adapter list in the driver data. 3328c2ecf20Sopenharmony_ci * All adapter internal structures are set up. 3338c2ecf20Sopenharmony_ci * Proc-fs entries are also created. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_cistruct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (!get_device(&ccw_device->dev)) 3408c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); 3438c2ecf20Sopenharmony_ci if (!adapter) { 3448c2ecf20Sopenharmony_ci put_device(&ccw_device->dev); 3458c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci kref_init(&adapter->ref); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci ccw_device->handler = NULL; 3518c2ecf20Sopenharmony_ci adapter->ccw_device = ccw_device; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); 3548c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&adapter->scan_work, zfcp_fc_scan_ports); 3558c2ecf20Sopenharmony_ci INIT_WORK(&adapter->ns_up_work, zfcp_fc_sym_name_update); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci adapter->next_port_scan = jiffies; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci adapter->erp_action.adapter = adapter; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (zfcp_diag_adapter_setup(adapter)) 3628c2ecf20Sopenharmony_ci goto failed; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (zfcp_qdio_setup(adapter)) 3658c2ecf20Sopenharmony_ci goto failed; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (zfcp_allocate_low_mem_buffers(adapter)) 3688c2ecf20Sopenharmony_ci goto failed; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci adapter->req_list = zfcp_reqlist_alloc(); 3718c2ecf20Sopenharmony_ci if (!adapter->req_list) 3728c2ecf20Sopenharmony_ci goto failed; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (zfcp_dbf_adapter_register(adapter)) 3758c2ecf20Sopenharmony_ci goto failed; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (zfcp_setup_adapter_work_queue(adapter)) 3788c2ecf20Sopenharmony_ci goto failed; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (zfcp_fc_gs_setup(adapter)) 3818c2ecf20Sopenharmony_ci goto failed; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci rwlock_init(&adapter->port_list_lock); 3848c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->port_list); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->events.list); 3878c2ecf20Sopenharmony_ci INIT_WORK(&adapter->events.work, zfcp_fc_post_event); 3888c2ecf20Sopenharmony_ci spin_lock_init(&adapter->events.list_lock); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci init_waitqueue_head(&adapter->erp_ready_wq); 3918c2ecf20Sopenharmony_ci init_waitqueue_head(&adapter->erp_done_wqh); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->erp_ready_head); 3948c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->erp_running_head); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci rwlock_init(&adapter->erp_lock); 3978c2ecf20Sopenharmony_ci rwlock_init(&adapter->abort_lock); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (zfcp_erp_thread_setup(adapter)) 4008c2ecf20Sopenharmony_ci goto failed; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci adapter->service_level.seq_print = zfcp_print_sl; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci dev_set_drvdata(&ccw_device->dev, adapter); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (sysfs_create_group(&ccw_device->dev.kobj, 4078c2ecf20Sopenharmony_ci &zfcp_sysfs_adapter_attrs)) 4088c2ecf20Sopenharmony_ci goto failed; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (zfcp_diag_sysfs_setup(adapter)) 4118c2ecf20Sopenharmony_ci goto failed; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* report size limit per scatter-gather segment */ 4148c2ecf20Sopenharmony_ci adapter->ccw_device->dev.dma_parms = &adapter->dma_parms; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci adapter->stat_read_buf_num = FSF_STATUS_READS_RECOM; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return adapter; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cifailed: 4218c2ecf20Sopenharmony_ci zfcp_adapter_unregister(adapter); 4228c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_civoid zfcp_adapter_unregister(struct zfcp_adapter *adapter) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct ccw_device *cdev = adapter->ccw_device; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&adapter->scan_work); 4308c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->stat_work); 4318c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->ns_up_work); 4328c2ecf20Sopenharmony_ci zfcp_destroy_adapter_work_queue(adapter); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci zfcp_fc_wka_ports_force_offline(adapter->gs); 4358c2ecf20Sopenharmony_ci zfcp_scsi_adapter_unregister(adapter); 4368c2ecf20Sopenharmony_ci zfcp_diag_sysfs_destroy(adapter); 4378c2ecf20Sopenharmony_ci sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci zfcp_erp_thread_kill(adapter); 4408c2ecf20Sopenharmony_ci zfcp_dbf_adapter_unregister(adapter); 4418c2ecf20Sopenharmony_ci zfcp_qdio_destroy(adapter->qdio); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci zfcp_ccw_adapter_put(adapter); /* final put to release */ 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/** 4478c2ecf20Sopenharmony_ci * zfcp_adapter_release - remove the adapter from the resource list 4488c2ecf20Sopenharmony_ci * @ref: pointer to struct kref 4498c2ecf20Sopenharmony_ci * locks: adapter list write lock is assumed to be held by caller 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_civoid zfcp_adapter_release(struct kref *ref) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = container_of(ref, struct zfcp_adapter, 4548c2ecf20Sopenharmony_ci ref); 4558c2ecf20Sopenharmony_ci struct ccw_device *cdev = adapter->ccw_device; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci dev_set_drvdata(&adapter->ccw_device->dev, NULL); 4588c2ecf20Sopenharmony_ci zfcp_fc_gs_destroy(adapter); 4598c2ecf20Sopenharmony_ci zfcp_free_low_mem_buffers(adapter); 4608c2ecf20Sopenharmony_ci zfcp_diag_adapter_free(adapter); 4618c2ecf20Sopenharmony_ci kfree(adapter->req_list); 4628c2ecf20Sopenharmony_ci kfree(adapter->fc_stats); 4638c2ecf20Sopenharmony_ci kfree(adapter->stats_reset_data); 4648c2ecf20Sopenharmony_ci kfree(adapter); 4658c2ecf20Sopenharmony_ci put_device(&cdev->dev); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic void zfcp_port_release(struct device *dev) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci zfcp_ccw_adapter_put(port->adapter); 4738c2ecf20Sopenharmony_ci kfree(port); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci/** 4778c2ecf20Sopenharmony_ci * zfcp_port_enqueue - enqueue port to port list of adapter 4788c2ecf20Sopenharmony_ci * @adapter: adapter where remote port is added 4798c2ecf20Sopenharmony_ci * @wwpn: WWPN of the remote port to be enqueued 4808c2ecf20Sopenharmony_ci * @status: initial status for the port 4818c2ecf20Sopenharmony_ci * @d_id: destination id of the remote port to be enqueued 4828c2ecf20Sopenharmony_ci * Returns: pointer to enqueued port on success, ERR_PTR on error 4838c2ecf20Sopenharmony_ci * 4848c2ecf20Sopenharmony_ci * All port internal structures are set up and the sysfs entry is generated. 4858c2ecf20Sopenharmony_ci * d_id is used to enqueue ports with a well known address like the Directory 4868c2ecf20Sopenharmony_ci * Service for nameserver lookup. 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_cistruct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, 4898c2ecf20Sopenharmony_ci u32 status, u32 d_id) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct zfcp_port *port; 4928c2ecf20Sopenharmony_ci int retval = -ENOMEM; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci kref_get(&adapter->ref); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci port = zfcp_get_port_by_wwpn(adapter, wwpn); 4978c2ecf20Sopenharmony_ci if (port) { 4988c2ecf20Sopenharmony_ci put_device(&port->dev); 4998c2ecf20Sopenharmony_ci retval = -EEXIST; 5008c2ecf20Sopenharmony_ci goto err_put; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); 5048c2ecf20Sopenharmony_ci if (!port) 5058c2ecf20Sopenharmony_ci goto err_put; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci rwlock_init(&port->unit_list_lock); 5088c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&port->unit_list); 5098c2ecf20Sopenharmony_ci atomic_set(&port->units, 0); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); 5128c2ecf20Sopenharmony_ci INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); 5138c2ecf20Sopenharmony_ci INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci port->adapter = adapter; 5168c2ecf20Sopenharmony_ci port->d_id = d_id; 5178c2ecf20Sopenharmony_ci port->wwpn = wwpn; 5188c2ecf20Sopenharmony_ci port->rport_task = RPORT_NONE; 5198c2ecf20Sopenharmony_ci port->dev.parent = &adapter->ccw_device->dev; 5208c2ecf20Sopenharmony_ci port->dev.groups = zfcp_port_attr_groups; 5218c2ecf20Sopenharmony_ci port->dev.release = zfcp_port_release; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci port->erp_action.adapter = adapter; 5248c2ecf20Sopenharmony_ci port->erp_action.port = port; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (dev_set_name(&port->dev, "0x%016llx", (unsigned long long)wwpn)) { 5278c2ecf20Sopenharmony_ci kfree(port); 5288c2ecf20Sopenharmony_ci goto err_put; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci retval = -EINVAL; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (device_register(&port->dev)) { 5338c2ecf20Sopenharmony_ci put_device(&port->dev); 5348c2ecf20Sopenharmony_ci goto err_out; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci write_lock_irq(&adapter->port_list_lock); 5388c2ecf20Sopenharmony_ci list_add_tail(&port->list, &adapter->port_list); 5398c2ecf20Sopenharmony_ci write_unlock_irq(&adapter->port_list_lock); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci atomic_or(status | ZFCP_STATUS_COMMON_RUNNING, &port->status); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return port; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cierr_put: 5468c2ecf20Sopenharmony_ci zfcp_ccw_adapter_put(adapter); 5478c2ecf20Sopenharmony_cierr_out: 5488c2ecf20Sopenharmony_ci return ERR_PTR(retval); 5498c2ecf20Sopenharmony_ci} 550