18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * zfcp device driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Registration and callback for the s390 common I/O layer. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2002, 2010 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/module.h> 148c2ecf20Sopenharmony_ci#include "zfcp_ext.h" 158c2ecf20Sopenharmony_ci#include "zfcp_reqlist.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define ZFCP_MODEL_PRIV 0x4 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(zfcp_ccw_adapter_ref_lock); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistruct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *cdev) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter; 248c2ecf20Sopenharmony_ci unsigned long flags; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags); 278c2ecf20Sopenharmony_ci adapter = dev_get_drvdata(&cdev->dev); 288c2ecf20Sopenharmony_ci if (adapter) 298c2ecf20Sopenharmony_ci kref_get(&adapter->ref); 308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); 318c2ecf20Sopenharmony_ci return adapter; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_civoid zfcp_ccw_adapter_put(struct zfcp_adapter *adapter) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci unsigned long flags; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags); 398c2ecf20Sopenharmony_ci kref_put(&adapter->ref, zfcp_adapter_release); 408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/** 448c2ecf20Sopenharmony_ci * zfcp_ccw_activate - activate adapter and wait for it to finish 458c2ecf20Sopenharmony_ci * @cdev: pointer to belonging ccw device 468c2ecf20Sopenharmony_ci * @clear: Status flags to clear. 478c2ecf20Sopenharmony_ci * @tag: s390dbf trace record tag 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_cistatic int zfcp_ccw_activate(struct ccw_device *cdev, int clear, char *tag) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (!adapter) 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci zfcp_erp_clear_adapter_status(adapter, clear); 578c2ecf20Sopenharmony_ci zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); 588c2ecf20Sopenharmony_ci zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 598c2ecf20Sopenharmony_ci tag); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* 628c2ecf20Sopenharmony_ci * We want to scan ports here, with some random backoff and without 638c2ecf20Sopenharmony_ci * rate limit. Recovery has already scheduled a port scan for us, 648c2ecf20Sopenharmony_ci * but with both random delay and rate limit. Nevertheless we get 658c2ecf20Sopenharmony_ci * what we want here by flushing the scheduled work after sleeping 668c2ecf20Sopenharmony_ci * an equivalent random time. 678c2ecf20Sopenharmony_ci * Let the port scan random delay elapse first. If recovery finishes 688c2ecf20Sopenharmony_ci * up to that point in time, that would be perfect for both recovery 698c2ecf20Sopenharmony_ci * and port scan. If not, i.e. recovery takes ages, there was no 708c2ecf20Sopenharmony_ci * point in waiting a random delay on top of the time consumed by 718c2ecf20Sopenharmony_ci * recovery. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci msleep(zfcp_fc_port_scan_backoff()); 748c2ecf20Sopenharmony_ci zfcp_erp_wait(adapter); 758c2ecf20Sopenharmony_ci flush_delayed_work(&adapter->scan_work); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci zfcp_ccw_adapter_put(adapter); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic struct ccw_device_id zfcp_ccw_device_id[] = { 838c2ecf20Sopenharmony_ci { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, 848c2ecf20Sopenharmony_ci { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) }, 858c2ecf20Sopenharmony_ci {}, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/** 908c2ecf20Sopenharmony_ci * zfcp_ccw_probe - probe function of zfcp driver 918c2ecf20Sopenharmony_ci * @cdev: pointer to belonging ccw device 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * This function gets called by the common i/o layer for each FCP 948c2ecf20Sopenharmony_ci * device found on the current system. This is only a stub to make cio 958c2ecf20Sopenharmony_ci * work: To only allocate adapter resources for devices actually used, 968c2ecf20Sopenharmony_ci * the allocation is deferred to the first call to ccw_set_online. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_cistatic int zfcp_ccw_probe(struct ccw_device *cdev) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/** 1048c2ecf20Sopenharmony_ci * zfcp_ccw_remove - remove function of zfcp driver 1058c2ecf20Sopenharmony_ci * @cdev: pointer to belonging ccw device 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * This function gets called by the common i/o layer and removes an adapter 1088c2ecf20Sopenharmony_ci * from the system. Task of this function is to get rid of all units and 1098c2ecf20Sopenharmony_ci * ports that belong to this adapter. And in addition all resources of this 1108c2ecf20Sopenharmony_ci * adapter will be freed too. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_cistatic void zfcp_ccw_remove(struct ccw_device *cdev) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter; 1158c2ecf20Sopenharmony_ci struct zfcp_port *port, *p; 1168c2ecf20Sopenharmony_ci struct zfcp_unit *unit, *u; 1178c2ecf20Sopenharmony_ci LIST_HEAD(unit_remove_lh); 1188c2ecf20Sopenharmony_ci LIST_HEAD(port_remove_lh); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci ccw_device_set_offline(cdev); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci adapter = zfcp_ccw_adapter_by_cdev(cdev); 1238c2ecf20Sopenharmony_ci if (!adapter) 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci write_lock_irq(&adapter->port_list_lock); 1278c2ecf20Sopenharmony_ci list_for_each_entry(port, &adapter->port_list, list) { 1288c2ecf20Sopenharmony_ci write_lock(&port->unit_list_lock); 1298c2ecf20Sopenharmony_ci list_splice_init(&port->unit_list, &unit_remove_lh); 1308c2ecf20Sopenharmony_ci write_unlock(&port->unit_list_lock); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci list_splice_init(&adapter->port_list, &port_remove_lh); 1338c2ecf20Sopenharmony_ci write_unlock_irq(&adapter->port_list_lock); 1348c2ecf20Sopenharmony_ci zfcp_ccw_adapter_put(adapter); /* put from zfcp_ccw_adapter_by_cdev */ 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci list_for_each_entry_safe(unit, u, &unit_remove_lh, list) 1378c2ecf20Sopenharmony_ci device_unregister(&unit->dev); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci list_for_each_entry_safe(port, p, &port_remove_lh, list) 1408c2ecf20Sopenharmony_ci device_unregister(&port->dev); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci zfcp_adapter_unregister(adapter); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/** 1468c2ecf20Sopenharmony_ci * zfcp_ccw_set_online - set_online function of zfcp driver 1478c2ecf20Sopenharmony_ci * @cdev: pointer to belonging ccw device 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * This function gets called by the common i/o layer and sets an 1508c2ecf20Sopenharmony_ci * adapter into state online. The first call will allocate all 1518c2ecf20Sopenharmony_ci * adapter resources that will be retained until the device is removed 1528c2ecf20Sopenharmony_ci * via zfcp_ccw_remove. 1538c2ecf20Sopenharmony_ci * 1548c2ecf20Sopenharmony_ci * Setting an fcp device online means that it will be registered with 1558c2ecf20Sopenharmony_ci * the SCSI stack, that the QDIO queues will be set up and that the 1568c2ecf20Sopenharmony_ci * adapter will be opened. 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistatic int zfcp_ccw_set_online(struct ccw_device *cdev) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (!adapter) { 1638c2ecf20Sopenharmony_ci adapter = zfcp_adapter_enqueue(cdev); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (IS_ERR(adapter)) { 1668c2ecf20Sopenharmony_ci dev_err(&cdev->dev, 1678c2ecf20Sopenharmony_ci "Setting up data structures for the " 1688c2ecf20Sopenharmony_ci "FCP adapter failed\n"); 1698c2ecf20Sopenharmony_ci return PTR_ERR(adapter); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci kref_get(&adapter->ref); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* initialize request counter */ 1758c2ecf20Sopenharmony_ci BUG_ON(!zfcp_reqlist_isempty(adapter->req_list)); 1768c2ecf20Sopenharmony_ci adapter->req_no = 0; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci zfcp_ccw_activate(cdev, 0, "ccsonl1"); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* 1818c2ecf20Sopenharmony_ci * We want to scan ports here, always, with some random delay and 1828c2ecf20Sopenharmony_ci * without rate limit - basically what zfcp_ccw_activate() has 1838c2ecf20Sopenharmony_ci * achieved for us. Not quite! That port scan depended on 1848c2ecf20Sopenharmony_ci * !no_auto_port_rescan. So let's cover the no_auto_port_rescan 1858c2ecf20Sopenharmony_ci * case here to make sure a port scan is done unconditionally. 1868c2ecf20Sopenharmony_ci * Since zfcp_ccw_activate() has waited the desired random time, 1878c2ecf20Sopenharmony_ci * we can immediately schedule and flush a port scan for the 1888c2ecf20Sopenharmony_ci * remaining cases. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci zfcp_fc_inverse_conditional_port_scan(adapter); 1918c2ecf20Sopenharmony_ci flush_delayed_work(&adapter->scan_work); 1928c2ecf20Sopenharmony_ci zfcp_ccw_adapter_put(adapter); 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/** 1978c2ecf20Sopenharmony_ci * zfcp_ccw_offline_sync - shut down adapter and wait for it to finish 1988c2ecf20Sopenharmony_ci * @cdev: pointer to belonging ccw device 1998c2ecf20Sopenharmony_ci * @set: Status flags to set. 2008c2ecf20Sopenharmony_ci * @tag: s390dbf trace record tag 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * This function gets called by the common i/o layer and sets an adapter 2038c2ecf20Sopenharmony_ci * into state offline. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_cistatic int zfcp_ccw_offline_sync(struct ccw_device *cdev, int set, char *tag) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (!adapter) 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci zfcp_erp_set_adapter_status(adapter, set); 2138c2ecf20Sopenharmony_ci zfcp_erp_adapter_shutdown(adapter, 0, tag); 2148c2ecf20Sopenharmony_ci zfcp_erp_wait(adapter); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci zfcp_ccw_adapter_put(adapter); 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/** 2218c2ecf20Sopenharmony_ci * zfcp_ccw_set_offline - set_offline function of zfcp driver 2228c2ecf20Sopenharmony_ci * @cdev: pointer to belonging ccw device 2238c2ecf20Sopenharmony_ci * 2248c2ecf20Sopenharmony_ci * This function gets called by the common i/o layer and sets an adapter 2258c2ecf20Sopenharmony_ci * into state offline. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_cistatic int zfcp_ccw_set_offline(struct ccw_device *cdev) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci return zfcp_ccw_offline_sync(cdev, 0, "ccsoff1"); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/** 2338c2ecf20Sopenharmony_ci * zfcp_ccw_notify - ccw notify function 2348c2ecf20Sopenharmony_ci * @cdev: pointer to belonging ccw device 2358c2ecf20Sopenharmony_ci * @event: indicates if adapter was detached or attached 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * This function gets called by the common i/o layer if an adapter has gone 2388c2ecf20Sopenharmony_ci * or reappeared. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_cistatic int zfcp_ccw_notify(struct ccw_device *cdev, int event) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (!adapter) 2458c2ecf20Sopenharmony_ci return 1; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci switch (event) { 2488c2ecf20Sopenharmony_ci case CIO_GONE: 2498c2ecf20Sopenharmony_ci if (atomic_read(&adapter->status) & 2508c2ecf20Sopenharmony_ci ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */ 2518c2ecf20Sopenharmony_ci zfcp_dbf_hba_basic("ccnigo1", adapter); 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci dev_warn(&cdev->dev, "The FCP device has been detached\n"); 2558c2ecf20Sopenharmony_ci zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1"); 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci case CIO_NO_PATH: 2588c2ecf20Sopenharmony_ci dev_warn(&cdev->dev, 2598c2ecf20Sopenharmony_ci "The CHPID for the FCP device is offline\n"); 2608c2ecf20Sopenharmony_ci zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2"); 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci case CIO_OPER: 2638c2ecf20Sopenharmony_ci if (atomic_read(&adapter->status) & 2648c2ecf20Sopenharmony_ci ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */ 2658c2ecf20Sopenharmony_ci zfcp_dbf_hba_basic("ccniop1", adapter); 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci dev_info(&cdev->dev, "The FCP device is operational again\n"); 2698c2ecf20Sopenharmony_ci zfcp_erp_set_adapter_status(adapter, 2708c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_RUNNING); 2718c2ecf20Sopenharmony_ci zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 2728c2ecf20Sopenharmony_ci "ccnoti4"); 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci case CIO_BOXED: 2758c2ecf20Sopenharmony_ci dev_warn(&cdev->dev, "The FCP device did not respond within " 2768c2ecf20Sopenharmony_ci "the specified time\n"); 2778c2ecf20Sopenharmony_ci zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5"); 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci zfcp_ccw_adapter_put(adapter); 2828c2ecf20Sopenharmony_ci return 1; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/** 2868c2ecf20Sopenharmony_ci * zfcp_ccw_shutdown - handle shutdown from cio 2878c2ecf20Sopenharmony_ci * @cdev: device for adapter to shutdown. 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_cistatic void zfcp_ccw_shutdown(struct ccw_device *cdev) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (!adapter) 2948c2ecf20Sopenharmony_ci return; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1"); 2978c2ecf20Sopenharmony_ci zfcp_erp_wait(adapter); 2988c2ecf20Sopenharmony_ci zfcp_erp_thread_kill(adapter); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci zfcp_ccw_adapter_put(adapter); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int zfcp_ccw_suspend(struct ccw_device *cdev) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci zfcp_ccw_offline_sync(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccsusp1"); 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int zfcp_ccw_thaw(struct ccw_device *cdev) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci /* trace records for thaw and final shutdown during suspend 3128c2ecf20Sopenharmony_ci can only be found in system dump until the end of suspend 3138c2ecf20Sopenharmony_ci but not after resume because it's based on the memory image 3148c2ecf20Sopenharmony_ci right after the very first suspend (freeze) callback */ 3158c2ecf20Sopenharmony_ci zfcp_ccw_activate(cdev, 0, "ccthaw1"); 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic int zfcp_ccw_resume(struct ccw_device *cdev) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci zfcp_ccw_activate(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccresu1"); 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistruct ccw_driver zfcp_ccw_driver = { 3268c2ecf20Sopenharmony_ci .driver = { 3278c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3288c2ecf20Sopenharmony_ci .name = "zfcp", 3298c2ecf20Sopenharmony_ci }, 3308c2ecf20Sopenharmony_ci .ids = zfcp_ccw_device_id, 3318c2ecf20Sopenharmony_ci .probe = zfcp_ccw_probe, 3328c2ecf20Sopenharmony_ci .remove = zfcp_ccw_remove, 3338c2ecf20Sopenharmony_ci .set_online = zfcp_ccw_set_online, 3348c2ecf20Sopenharmony_ci .set_offline = zfcp_ccw_set_offline, 3358c2ecf20Sopenharmony_ci .notify = zfcp_ccw_notify, 3368c2ecf20Sopenharmony_ci .shutdown = zfcp_ccw_shutdown, 3378c2ecf20Sopenharmony_ci .freeze = zfcp_ccw_suspend, 3388c2ecf20Sopenharmony_ci .thaw = zfcp_ccw_thaw, 3398c2ecf20Sopenharmony_ci .restore = zfcp_ccw_resume, 3408c2ecf20Sopenharmony_ci}; 341