xref: /openbmc/linux/drivers/s390/scsi/zfcp_sysfs.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
260221920SSwen Schillig /*
360221920SSwen Schillig  * zfcp device driver
460221920SSwen Schillig  *
560221920SSwen Schillig  * sysfs attributes.
660221920SSwen Schillig  *
7a17c7846SJens Remus  * Copyright IBM Corp. 2008, 2020
860221920SSwen Schillig  */
960221920SSwen Schillig 
10ecf39d42SChristof Schmitt #define KMSG_COMPONENT "zfcp"
11ecf39d42SChristof Schmitt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12ecf39d42SChristof Schmitt 
135a0e3ad6STejun Heo #include <linux/slab.h>
146028f7c4SBenjamin Block #include "zfcp_diag.h"
1560221920SSwen Schillig #include "zfcp_ext.h"
1660221920SSwen Schillig 
1760221920SSwen Schillig #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \
1860221920SSwen Schillig struct device_attribute dev_attr_##_feat##_##_name = __ATTR(_name, _mode,\
1960221920SSwen Schillig 							    _show, _store)
2060221920SSwen Schillig #define ZFCP_DEFINE_ATTR(_feat_def, _feat, _name, _format, _value)	       \
2160221920SSwen Schillig static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev,	       \
2260221920SSwen Schillig 						   struct device_attribute *at,\
2360221920SSwen Schillig 						   char *buf)		       \
2460221920SSwen Schillig {									       \
25615f59e0SChristof Schmitt 	struct _feat_def *_feat = container_of(dev, struct _feat_def, dev);    \
2660221920SSwen Schillig 									       \
2760221920SSwen Schillig 	return sprintf(buf, _format, _value);				       \
2860221920SSwen Schillig }									       \
2960221920SSwen Schillig static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO,				       \
3060221920SSwen Schillig 		     zfcp_sysfs_##_feat##_##_name##_show, NULL);
3160221920SSwen Schillig 
32b5dc3c48SMartin Peschke #define ZFCP_DEFINE_ATTR_CONST(_feat, _name, _format, _value)		       \
33b5dc3c48SMartin Peschke static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev,	       \
34b5dc3c48SMartin Peschke 						   struct device_attribute *at,\
35b5dc3c48SMartin Peschke 						   char *buf)		       \
36b5dc3c48SMartin Peschke {									       \
37b5dc3c48SMartin Peschke 	return sprintf(buf, _format, _value);				       \
38b5dc3c48SMartin Peschke }									       \
39b5dc3c48SMartin Peschke static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO,				       \
40b5dc3c48SMartin Peschke 		     zfcp_sysfs_##_feat##_##_name##_show, NULL);
41b5dc3c48SMartin Peschke 
42de3dc572SSwen Schillig #define ZFCP_DEFINE_A_ATTR(_name, _format, _value)			     \
43de3dc572SSwen Schillig static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev,	     \
44de3dc572SSwen Schillig 						 struct device_attribute *at,\
45de3dc572SSwen Schillig 						 char *buf)		     \
46de3dc572SSwen Schillig {									     \
47de3dc572SSwen Schillig 	struct ccw_device *cdev = to_ccwdev(dev);			     \
48de3dc572SSwen Schillig 	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);	     \
49de3dc572SSwen Schillig 	int i;								     \
50de3dc572SSwen Schillig 									     \
51de3dc572SSwen Schillig 	if (!adapter)							     \
52de3dc572SSwen Schillig 		return -ENODEV;						     \
53de3dc572SSwen Schillig 									     \
54de3dc572SSwen Schillig 	i = sprintf(buf, _format, _value);				     \
55de3dc572SSwen Schillig 	zfcp_ccw_adapter_put(adapter);					     \
56de3dc572SSwen Schillig 	return i;							     \
57de3dc572SSwen Schillig }									     \
58de3dc572SSwen Schillig static ZFCP_DEV_ATTR(adapter, _name, S_IRUGO,				     \
59de3dc572SSwen Schillig 		     zfcp_sysfs_adapter_##_name##_show, NULL);
60de3dc572SSwen Schillig 
61de3dc572SSwen Schillig ZFCP_DEFINE_A_ATTR(status, "0x%08x\n", atomic_read(&adapter->status));
62de3dc572SSwen Schillig ZFCP_DEFINE_A_ATTR(peer_wwnn, "0x%016llx\n",
637ba58c9cSSwen Schillig 		   (unsigned long long) adapter->peer_wwnn);
64de3dc572SSwen Schillig ZFCP_DEFINE_A_ATTR(peer_wwpn, "0x%016llx\n",
657ba58c9cSSwen Schillig 		   (unsigned long long) adapter->peer_wwpn);
66de3dc572SSwen Schillig ZFCP_DEFINE_A_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id);
67de3dc572SSwen Schillig ZFCP_DEFINE_A_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
68de3dc572SSwen Schillig ZFCP_DEFINE_A_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
69de3dc572SSwen Schillig ZFCP_DEFINE_A_ATTR(hardware_version, "0x%08x\n", adapter->hardware_version);
70de3dc572SSwen Schillig ZFCP_DEFINE_A_ATTR(in_recovery, "%d\n", (atomic_read(&adapter->status) &
7160221920SSwen Schillig 					 ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
7260221920SSwen Schillig 
7360221920SSwen Schillig ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n",
7460221920SSwen Schillig 		 atomic_read(&port->status));
7560221920SSwen Schillig ZFCP_DEFINE_ATTR(zfcp_port, port, in_recovery, "%d\n",
7660221920SSwen Schillig 		 (atomic_read(&port->status) &
7760221920SSwen Schillig 		  ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
781b33ef23SMartin Peschke ZFCP_DEFINE_ATTR_CONST(port, access_denied, "%d\n", 0);
7960221920SSwen Schillig 
8060221920SSwen Schillig ZFCP_DEFINE_ATTR(zfcp_unit, unit, status, "0x%08x\n",
81b62a8d9bSChristof Schmitt 		 zfcp_unit_sdev_status(unit));
8260221920SSwen Schillig ZFCP_DEFINE_ATTR(zfcp_unit, unit, in_recovery, "%d\n",
83b62a8d9bSChristof Schmitt 		 (zfcp_unit_sdev_status(unit) &
8460221920SSwen Schillig 		  ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
8560221920SSwen Schillig ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n",
86b62a8d9bSChristof Schmitt 		 (zfcp_unit_sdev_status(unit) &
8760221920SSwen Schillig 		  ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0);
88b5dc3c48SMartin Peschke ZFCP_DEFINE_ATTR_CONST(unit, access_shared, "%d\n", 0);
89b5dc3c48SMartin Peschke ZFCP_DEFINE_ATTR_CONST(unit, access_readonly, "%d\n", 0);
9060221920SSwen Schillig 
zfcp_sysfs_port_failed_show(struct device * dev,struct device_attribute * attr,char * buf)91e4b9857fSChristof Schmitt static ssize_t zfcp_sysfs_port_failed_show(struct device *dev,
92e4b9857fSChristof Schmitt 					   struct device_attribute *attr,
93e4b9857fSChristof Schmitt 					   char *buf)
94e4b9857fSChristof Schmitt {
95e4b9857fSChristof Schmitt 	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
9660221920SSwen Schillig 
97e4b9857fSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
98e4b9857fSChristof Schmitt 		return sprintf(buf, "1\n");
99e4b9857fSChristof Schmitt 
100e4b9857fSChristof Schmitt 	return sprintf(buf, "0\n");
101e4b9857fSChristof Schmitt }
102e4b9857fSChristof Schmitt 
zfcp_sysfs_port_failed_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)103e4b9857fSChristof Schmitt static ssize_t zfcp_sysfs_port_failed_store(struct device *dev,
104e4b9857fSChristof Schmitt 					    struct device_attribute *attr,
105e4b9857fSChristof Schmitt 					    const char *buf, size_t count)
106e4b9857fSChristof Schmitt {
107e4b9857fSChristof Schmitt 	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
108e4b9857fSChristof Schmitt 	unsigned long val;
109e4b9857fSChristof Schmitt 
110ee732ea8SMartin Peschke 	if (kstrtoul(buf, 0, &val) || val != 0)
111e4b9857fSChristof Schmitt 		return -EINVAL;
112e4b9857fSChristof Schmitt 
113edaed859SSwen Schillig 	zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_RUNNING);
114ea4a3a6aSSwen Schillig 	zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2");
115e4b9857fSChristof Schmitt 	zfcp_erp_wait(port->adapter);
116e4b9857fSChristof Schmitt 
117e4b9857fSChristof Schmitt 	return count;
118e4b9857fSChristof Schmitt }
119e4b9857fSChristof Schmitt static ZFCP_DEV_ATTR(port, failed, S_IWUSR | S_IRUGO,
120e4b9857fSChristof Schmitt 		     zfcp_sysfs_port_failed_show,
121e4b9857fSChristof Schmitt 		     zfcp_sysfs_port_failed_store);
122e4b9857fSChristof Schmitt 
zfcp_sysfs_unit_failed_show(struct device * dev,struct device_attribute * attr,char * buf)123e4b9857fSChristof Schmitt static ssize_t zfcp_sysfs_unit_failed_show(struct device *dev,
124e4b9857fSChristof Schmitt 					   struct device_attribute *attr,
125e4b9857fSChristof Schmitt 					   char *buf)
126e4b9857fSChristof Schmitt {
127e4b9857fSChristof Schmitt 	struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
128b62a8d9bSChristof Schmitt 	struct scsi_device *sdev;
129b62a8d9bSChristof Schmitt 	unsigned int status, failed = 1;
130e4b9857fSChristof Schmitt 
131b62a8d9bSChristof Schmitt 	sdev = zfcp_unit_sdev(unit);
132b62a8d9bSChristof Schmitt 	if (sdev) {
133b62a8d9bSChristof Schmitt 		status = atomic_read(&sdev_to_zfcp(sdev)->status);
134b62a8d9bSChristof Schmitt 		failed = status & ZFCP_STATUS_COMMON_ERP_FAILED ? 1 : 0;
135b62a8d9bSChristof Schmitt 		scsi_device_put(sdev);
136b62a8d9bSChristof Schmitt 	}
137e4b9857fSChristof Schmitt 
138b62a8d9bSChristof Schmitt 	return sprintf(buf, "%d\n", failed);
139e4b9857fSChristof Schmitt }
140e4b9857fSChristof Schmitt 
zfcp_sysfs_unit_failed_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)141e4b9857fSChristof Schmitt static ssize_t zfcp_sysfs_unit_failed_store(struct device *dev,
142e4b9857fSChristof Schmitt 					    struct device_attribute *attr,
143e4b9857fSChristof Schmitt 					    const char *buf, size_t count)
144e4b9857fSChristof Schmitt {
145e4b9857fSChristof Schmitt 	struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
146e4b9857fSChristof Schmitt 	unsigned long val;
147b62a8d9bSChristof Schmitt 	struct scsi_device *sdev;
148e4b9857fSChristof Schmitt 
149ee732ea8SMartin Peschke 	if (kstrtoul(buf, 0, &val) || val != 0)
150e4b9857fSChristof Schmitt 		return -EINVAL;
151e4b9857fSChristof Schmitt 
152b62a8d9bSChristof Schmitt 	sdev = zfcp_unit_sdev(unit);
153b62a8d9bSChristof Schmitt 	if (sdev) {
154edaed859SSwen Schillig 		zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);
155b62a8d9bSChristof Schmitt 		zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
156ea4a3a6aSSwen Schillig 				    "syufai2");
157e4b9857fSChristof Schmitt 		zfcp_erp_wait(unit->port->adapter);
158b62a8d9bSChristof Schmitt 	} else
159b62a8d9bSChristof Schmitt 		zfcp_unit_scsi_scan(unit);
160e4b9857fSChristof Schmitt 
161e4b9857fSChristof Schmitt 	return count;
162e4b9857fSChristof Schmitt }
163e4b9857fSChristof Schmitt static ZFCP_DEV_ATTR(unit, failed, S_IWUSR | S_IRUGO,
164e4b9857fSChristof Schmitt 		     zfcp_sysfs_unit_failed_show,
165e4b9857fSChristof Schmitt 		     zfcp_sysfs_unit_failed_store);
16660221920SSwen Schillig 
zfcp_sysfs_adapter_failed_show(struct device * dev,struct device_attribute * attr,char * buf)167de3dc572SSwen Schillig static ssize_t zfcp_sysfs_adapter_failed_show(struct device *dev,
168de3dc572SSwen Schillig 					      struct device_attribute *attr,
169de3dc572SSwen Schillig 					      char *buf)
170de3dc572SSwen Schillig {
171de3dc572SSwen Schillig 	struct ccw_device *cdev = to_ccwdev(dev);
172de3dc572SSwen Schillig 	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
173de3dc572SSwen Schillig 	int i;
174de3dc572SSwen Schillig 
175de3dc572SSwen Schillig 	if (!adapter)
176de3dc572SSwen Schillig 		return -ENODEV;
177de3dc572SSwen Schillig 
178de3dc572SSwen Schillig 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
179de3dc572SSwen Schillig 		i = sprintf(buf, "1\n");
180de3dc572SSwen Schillig 	else
181de3dc572SSwen Schillig 		i = sprintf(buf, "0\n");
182de3dc572SSwen Schillig 
183de3dc572SSwen Schillig 	zfcp_ccw_adapter_put(adapter);
184de3dc572SSwen Schillig 	return i;
185de3dc572SSwen Schillig }
186de3dc572SSwen Schillig 
zfcp_sysfs_adapter_failed_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)187de3dc572SSwen Schillig static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev,
188de3dc572SSwen Schillig 					       struct device_attribute *attr,
189de3dc572SSwen Schillig 					       const char *buf, size_t count)
190de3dc572SSwen Schillig {
191de3dc572SSwen Schillig 	struct ccw_device *cdev = to_ccwdev(dev);
192de3dc572SSwen Schillig 	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
193de3dc572SSwen Schillig 	unsigned long val;
194de3dc572SSwen Schillig 	int retval = 0;
195de3dc572SSwen Schillig 
196de3dc572SSwen Schillig 	if (!adapter)
197de3dc572SSwen Schillig 		return -ENODEV;
198de3dc572SSwen Schillig 
199ee732ea8SMartin Peschke 	if (kstrtoul(buf, 0, &val) || val != 0) {
200de3dc572SSwen Schillig 		retval = -EINVAL;
201de3dc572SSwen Schillig 		goto out;
202de3dc572SSwen Schillig 	}
203de3dc572SSwen Schillig 
20435e9111aSSteffen Maier 	zfcp_erp_adapter_reset_sync(adapter, "syafai2");
205de3dc572SSwen Schillig out:
206de3dc572SSwen Schillig 	zfcp_ccw_adapter_put(adapter);
207de3dc572SSwen Schillig 	return retval ? retval : (ssize_t) count;
208de3dc572SSwen Schillig }
209de3dc572SSwen Schillig static ZFCP_DEV_ATTR(adapter, failed, S_IWUSR | S_IRUGO,
210de3dc572SSwen Schillig 		     zfcp_sysfs_adapter_failed_show,
211de3dc572SSwen Schillig 		     zfcp_sysfs_adapter_failed_store);
212de3dc572SSwen Schillig 
zfcp_sysfs_port_rescan_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)21360221920SSwen Schillig static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
21460221920SSwen Schillig 					    struct device_attribute *attr,
21560221920SSwen Schillig 					    const char *buf, size_t count)
21660221920SSwen Schillig {
217de3dc572SSwen Schillig 	struct ccw_device *cdev = to_ccwdev(dev);
218de3dc572SSwen Schillig 	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
21971159b6eSBenjamin Block 	int retval = 0;
22060221920SSwen Schillig 
221de3dc572SSwen Schillig 	if (!adapter)
222de3dc572SSwen Schillig 		return -ENODEV;
223de3dc572SSwen Schillig 
22418f87a67SMartin Peschke 	/*
22571159b6eSBenjamin Block 	 * If `scsi_host` is missing, we can't schedule `scan_work`, as it
22671159b6eSBenjamin Block 	 * makes use of the corresponding fc_host object. But this state is
22771159b6eSBenjamin Block 	 * only possible if xconfig/xport data has never completed yet,
22871159b6eSBenjamin Block 	 * and we couldn't successfully scan for ports anyway.
22971159b6eSBenjamin Block 	 */
23071159b6eSBenjamin Block 	if (adapter->scsi_host == NULL) {
23171159b6eSBenjamin Block 		retval = -ENODEV;
23271159b6eSBenjamin Block 		goto out;
23371159b6eSBenjamin Block 	}
23471159b6eSBenjamin Block 
23571159b6eSBenjamin Block 	/*
23618f87a67SMartin Peschke 	 * Users wish is our command: immediately schedule and flush a
23718f87a67SMartin Peschke 	 * worker to conduct a synchronous port scan, that is, neither
23818f87a67SMartin Peschke 	 * a random delay nor a rate limit is applied here.
23918f87a67SMartin Peschke 	 */
24018f87a67SMartin Peschke 	queue_delayed_work(adapter->work_queue, &adapter->scan_work, 0);
24118f87a67SMartin Peschke 	flush_delayed_work(&adapter->scan_work);
24271159b6eSBenjamin Block out:
243de3dc572SSwen Schillig 	zfcp_ccw_adapter_put(adapter);
24471159b6eSBenjamin Block 	return retval ? retval : (ssize_t) count;
24560221920SSwen Schillig }
24660221920SSwen Schillig static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
24760221920SSwen Schillig 		     zfcp_sysfs_port_rescan_store);
24860221920SSwen Schillig 
249d99b601bSSteffen Maier DEFINE_MUTEX(zfcp_sysfs_port_units_mutex);
250d99b601bSSteffen Maier 
zfcp_sysfs_port_set_removing(struct zfcp_port * const port)251ef4021feSSteffen Maier static void zfcp_sysfs_port_set_removing(struct zfcp_port *const port)
252ef4021feSSteffen Maier {
253ef4021feSSteffen Maier 	lockdep_assert_held(&zfcp_sysfs_port_units_mutex);
254ef4021feSSteffen Maier 	atomic_set(&port->units, -1);
255ef4021feSSteffen Maier }
256ef4021feSSteffen Maier 
zfcp_sysfs_port_is_removing(const struct zfcp_port * const port)257ef4021feSSteffen Maier bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port)
258ef4021feSSteffen Maier {
259ef4021feSSteffen Maier 	lockdep_assert_held(&zfcp_sysfs_port_units_mutex);
260ef4021feSSteffen Maier 	return atomic_read(&port->units) == -1;
261ef4021feSSteffen Maier }
262ef4021feSSteffen Maier 
zfcp_sysfs_port_in_use(struct zfcp_port * const port)263ef4021feSSteffen Maier static bool zfcp_sysfs_port_in_use(struct zfcp_port *const port)
264ef4021feSSteffen Maier {
265ef4021feSSteffen Maier 	struct zfcp_adapter *const adapter = port->adapter;
266ef4021feSSteffen Maier 	unsigned long flags;
267ef4021feSSteffen Maier 	struct scsi_device *sdev;
268ef4021feSSteffen Maier 	bool in_use = true;
269ef4021feSSteffen Maier 
270ef4021feSSteffen Maier 	mutex_lock(&zfcp_sysfs_port_units_mutex);
271ef4021feSSteffen Maier 	if (atomic_read(&port->units) > 0)
272ef4021feSSteffen Maier 		goto unlock_port_units_mutex; /* zfcp_unit(s) under port */
273ef4021feSSteffen Maier 
274ef4021feSSteffen Maier 	spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
275ef4021feSSteffen Maier 	__shost_for_each_device(sdev, adapter->scsi_host) {
276ef4021feSSteffen Maier 		const struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
277ef4021feSSteffen Maier 
278ef4021feSSteffen Maier 		if (sdev->sdev_state == SDEV_DEL ||
279ef4021feSSteffen Maier 		    sdev->sdev_state == SDEV_CANCEL)
280ef4021feSSteffen Maier 			continue;
281ef4021feSSteffen Maier 		if (zsdev->port != port)
282ef4021feSSteffen Maier 			continue;
283ef4021feSSteffen Maier 		/* alive scsi_device under port of interest */
284ef4021feSSteffen Maier 		goto unlock_host_lock;
285ef4021feSSteffen Maier 	}
286ef4021feSSteffen Maier 
287ef4021feSSteffen Maier 	/* port is about to be removed, so no more unit_add or slave_alloc */
288ef4021feSSteffen Maier 	zfcp_sysfs_port_set_removing(port);
289ef4021feSSteffen Maier 	in_use = false;
290ef4021feSSteffen Maier 
291ef4021feSSteffen Maier unlock_host_lock:
292ef4021feSSteffen Maier 	spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
293ef4021feSSteffen Maier unlock_port_units_mutex:
294ef4021feSSteffen Maier 	mutex_unlock(&zfcp_sysfs_port_units_mutex);
295ef4021feSSteffen Maier 	return in_use;
296ef4021feSSteffen Maier }
297ef4021feSSteffen Maier 
zfcp_sysfs_port_remove_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)29860221920SSwen Schillig static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
29960221920SSwen Schillig 					    struct device_attribute *attr,
30060221920SSwen Schillig 					    const char *buf, size_t count)
30160221920SSwen Schillig {
302de3dc572SSwen Schillig 	struct ccw_device *cdev = to_ccwdev(dev);
303de3dc572SSwen Schillig 	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
30460221920SSwen Schillig 	struct zfcp_port *port;
3057ba58c9cSSwen Schillig 	u64 wwpn;
3066b183334SSwen Schillig 	int retval = -EINVAL;
30760221920SSwen Schillig 
308de3dc572SSwen Schillig 	if (!adapter)
309de3dc572SSwen Schillig 		return -ENODEV;
310de3dc572SSwen Schillig 
311ee732ea8SMartin Peschke 	if (kstrtoull(buf, 0, (unsigned long long *) &wwpn))
31260221920SSwen Schillig 		goto out;
31360221920SSwen Schillig 
31460221920SSwen Schillig 	port = zfcp_get_port_by_wwpn(adapter, wwpn);
3156b183334SSwen Schillig 	if (!port)
31660221920SSwen Schillig 		goto out;
3176b183334SSwen Schillig 	else
3186b183334SSwen Schillig 		retval = 0;
319f3450c7bSSwen Schillig 
320ef4021feSSteffen Maier 	if (zfcp_sysfs_port_in_use(port)) {
321d99b601bSSteffen Maier 		retval = -EBUSY;
322d27e5e07SSteffen Maier 		put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */
323d99b601bSSteffen Maier 		goto out;
324d99b601bSSteffen Maier 	}
325d99b601bSSteffen Maier 
326f3450c7bSSwen Schillig 	write_lock_irq(&adapter->port_list_lock);
327f3450c7bSSwen Schillig 	list_del(&port->list);
328f3450c7bSSwen Schillig 	write_unlock_irq(&adapter->port_list_lock);
329f3450c7bSSwen Schillig 
330ea4a3a6aSSwen Schillig 	zfcp_erp_port_shutdown(port, 0, "syprs_1");
33183d4e1c3SSebastian Ott 	device_unregister(&port->dev);
332be46e39aSQinglang Miao 
333be46e39aSQinglang Miao 	put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */
33460221920SSwen Schillig  out:
335de3dc572SSwen Schillig 	zfcp_ccw_adapter_put(adapter);
33660221920SSwen Schillig 	return retval ? retval : (ssize_t) count;
33760221920SSwen Schillig }
33860221920SSwen Schillig static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL,
33960221920SSwen Schillig 		     zfcp_sysfs_port_remove_store);
34060221920SSwen Schillig 
34148910f8cSBenjamin Block static ssize_t
zfcp_sysfs_adapter_diag_max_age_show(struct device * dev,struct device_attribute * attr,char * buf)34248910f8cSBenjamin Block zfcp_sysfs_adapter_diag_max_age_show(struct device *dev,
34348910f8cSBenjamin Block 				     struct device_attribute *attr, char *buf)
34448910f8cSBenjamin Block {
34548910f8cSBenjamin Block 	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev));
34648910f8cSBenjamin Block 	ssize_t rc;
34748910f8cSBenjamin Block 
34848910f8cSBenjamin Block 	if (!adapter)
34948910f8cSBenjamin Block 		return -ENODEV;
35048910f8cSBenjamin Block 
35148910f8cSBenjamin Block 	/* ceil(log(2^64 - 1) / log(10)) = 20 */
35248910f8cSBenjamin Block 	rc = scnprintf(buf, 20 + 2, "%lu\n", adapter->diagnostics->max_age);
35348910f8cSBenjamin Block 
35448910f8cSBenjamin Block 	zfcp_ccw_adapter_put(adapter);
35548910f8cSBenjamin Block 	return rc;
35648910f8cSBenjamin Block }
35748910f8cSBenjamin Block 
35848910f8cSBenjamin Block static ssize_t
zfcp_sysfs_adapter_diag_max_age_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)35948910f8cSBenjamin Block zfcp_sysfs_adapter_diag_max_age_store(struct device *dev,
36048910f8cSBenjamin Block 				      struct device_attribute *attr,
36148910f8cSBenjamin Block 				      const char *buf, size_t count)
36248910f8cSBenjamin Block {
36348910f8cSBenjamin Block 	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev));
36448910f8cSBenjamin Block 	unsigned long max_age;
36548910f8cSBenjamin Block 	ssize_t rc;
36648910f8cSBenjamin Block 
36748910f8cSBenjamin Block 	if (!adapter)
36848910f8cSBenjamin Block 		return -ENODEV;
36948910f8cSBenjamin Block 
37048910f8cSBenjamin Block 	rc = kstrtoul(buf, 10, &max_age);
37148910f8cSBenjamin Block 	if (rc != 0)
37248910f8cSBenjamin Block 		goto out;
37348910f8cSBenjamin Block 
37448910f8cSBenjamin Block 	adapter->diagnostics->max_age = max_age;
37548910f8cSBenjamin Block 
37648910f8cSBenjamin Block 	rc = count;
37748910f8cSBenjamin Block out:
37848910f8cSBenjamin Block 	zfcp_ccw_adapter_put(adapter);
37948910f8cSBenjamin Block 	return rc;
38048910f8cSBenjamin Block }
38148910f8cSBenjamin Block static ZFCP_DEV_ATTR(adapter, diag_max_age, 0644,
38248910f8cSBenjamin Block 		     zfcp_sysfs_adapter_diag_max_age_show,
38348910f8cSBenjamin Block 		     zfcp_sysfs_adapter_diag_max_age_store);
38448910f8cSBenjamin Block 
zfcp_sysfs_adapter_fc_security_show(struct device * dev,struct device_attribute * attr,char * buf)385a17c7846SJens Remus static ssize_t zfcp_sysfs_adapter_fc_security_show(
386a17c7846SJens Remus 	struct device *dev, struct device_attribute *attr, char *buf)
387a17c7846SJens Remus {
388a17c7846SJens Remus 	struct ccw_device *cdev = to_ccwdev(dev);
389a17c7846SJens Remus 	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
390a17c7846SJens Remus 	unsigned int status;
391a17c7846SJens Remus 	int i;
392a17c7846SJens Remus 
393a17c7846SJens Remus 	if (!adapter)
394a17c7846SJens Remus 		return -ENODEV;
395a17c7846SJens Remus 
396a17c7846SJens Remus 	/*
397a17c7846SJens Remus 	 * Adapter status COMMON_OPEN implies xconf data and xport data
398a17c7846SJens Remus 	 * was done. Adapter FC Endpoint Security capability remains
399a17c7846SJens Remus 	 * unchanged in case of COMMON_ERP_FAILED (e.g. due to local link
400a17c7846SJens Remus 	 * down).
401a17c7846SJens Remus 	 */
402a17c7846SJens Remus 	status = atomic_read(&adapter->status);
403a17c7846SJens Remus 	if (0 == (status & ZFCP_STATUS_COMMON_OPEN))
404a17c7846SJens Remus 		i = sprintf(buf, "unknown\n");
405a17c7846SJens Remus 	else if (!(adapter->adapter_features & FSF_FEATURE_FC_SECURITY))
406a17c7846SJens Remus 		i = sprintf(buf, "unsupported\n");
407a17c7846SJens Remus 	else {
408a17c7846SJens Remus 		i = zfcp_fsf_scnprint_fc_security(
409a17c7846SJens Remus 			buf, PAGE_SIZE - 1, adapter->fc_security_algorithms,
410a17c7846SJens Remus 			ZFCP_FSF_PRINT_FMT_LIST);
411a17c7846SJens Remus 		i += scnprintf(buf + i, PAGE_SIZE - i, "\n");
412a17c7846SJens Remus 	}
413a17c7846SJens Remus 
414a17c7846SJens Remus 	zfcp_ccw_adapter_put(adapter);
415a17c7846SJens Remus 	return i;
416a17c7846SJens Remus }
417a17c7846SJens Remus static ZFCP_DEV_ATTR(adapter, fc_security, S_IRUGO,
418a17c7846SJens Remus 		     zfcp_sysfs_adapter_fc_security_show,
419a17c7846SJens Remus 		     NULL);
420a17c7846SJens Remus 
42160221920SSwen Schillig static struct attribute *zfcp_adapter_attrs[] = {
42260221920SSwen Schillig 	&dev_attr_adapter_failed.attr,
42360221920SSwen Schillig 	&dev_attr_adapter_in_recovery.attr,
42460221920SSwen Schillig 	&dev_attr_adapter_port_remove.attr,
42560221920SSwen Schillig 	&dev_attr_adapter_port_rescan.attr,
42660221920SSwen Schillig 	&dev_attr_adapter_peer_wwnn.attr,
42760221920SSwen Schillig 	&dev_attr_adapter_peer_wwpn.attr,
42860221920SSwen Schillig 	&dev_attr_adapter_peer_d_id.attr,
42960221920SSwen Schillig 	&dev_attr_adapter_card_version.attr,
43060221920SSwen Schillig 	&dev_attr_adapter_lic_version.attr,
43160221920SSwen Schillig 	&dev_attr_adapter_status.attr,
43260221920SSwen Schillig 	&dev_attr_adapter_hardware_version.attr,
43348910f8cSBenjamin Block 	&dev_attr_adapter_diag_max_age.attr,
434a17c7846SJens Remus 	&dev_attr_adapter_fc_security.attr,
43560221920SSwen Schillig 	NULL
43660221920SSwen Schillig };
43760221920SSwen Schillig 
43820540a56SJulian Wiedmann static const struct attribute_group zfcp_sysfs_adapter_attr_group = {
43960221920SSwen Schillig 	.attrs = zfcp_adapter_attrs,
44060221920SSwen Schillig };
44160221920SSwen Schillig 
zfcp_sysfs_unit_add_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)44260221920SSwen Schillig static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
44360221920SSwen Schillig 					 struct device_attribute *attr,
44460221920SSwen Schillig 					 const char *buf, size_t count)
44560221920SSwen Schillig {
446615f59e0SChristof Schmitt 	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
4477ba58c9cSSwen Schillig 	u64 fcp_lun;
448d99b601bSSteffen Maier 	int retval;
44960221920SSwen Schillig 
450ee732ea8SMartin Peschke 	if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
4511daa4eb5SChristof Schmitt 		return -EINVAL;
45260221920SSwen Schillig 
453d99b601bSSteffen Maier 	retval = zfcp_unit_add(port, fcp_lun);
454d99b601bSSteffen Maier 	if (retval)
455d99b601bSSteffen Maier 		return retval;
45660221920SSwen Schillig 
4571daa4eb5SChristof Schmitt 	return count;
45860221920SSwen Schillig }
45960221920SSwen Schillig static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store);
46060221920SSwen Schillig 
zfcp_sysfs_unit_remove_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)46160221920SSwen Schillig static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
46260221920SSwen Schillig 					    struct device_attribute *attr,
46360221920SSwen Schillig 					    const char *buf, size_t count)
46460221920SSwen Schillig {
465615f59e0SChristof Schmitt 	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
4667ba58c9cSSwen Schillig 	u64 fcp_lun;
46760221920SSwen Schillig 
468ee732ea8SMartin Peschke 	if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
4691daa4eb5SChristof Schmitt 		return -EINVAL;
47060221920SSwen Schillig 
4711daa4eb5SChristof Schmitt 	if (zfcp_unit_remove(port, fcp_lun))
4721daa4eb5SChristof Schmitt 		return -EINVAL;
47360221920SSwen Schillig 
4741daa4eb5SChristof Schmitt 	return count;
47560221920SSwen Schillig }
47660221920SSwen Schillig static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
47760221920SSwen Schillig 
zfcp_sysfs_port_fc_security_show(struct device * dev,struct device_attribute * attr,char * buf)478a17c7846SJens Remus static ssize_t zfcp_sysfs_port_fc_security_show(struct device *dev,
479a17c7846SJens Remus 						struct device_attribute *attr,
480a17c7846SJens Remus 						char *buf)
481a17c7846SJens Remus {
482a17c7846SJens Remus 	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
483a17c7846SJens Remus 	struct zfcp_adapter *adapter = port->adapter;
484a17c7846SJens Remus 	unsigned int status = atomic_read(&port->status);
485a17c7846SJens Remus 	int i;
486a17c7846SJens Remus 
487a17c7846SJens Remus 	if (0 == (status & ZFCP_STATUS_COMMON_OPEN) ||
488a17c7846SJens Remus 	    0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) ||
489a17c7846SJens Remus 	    0 == (status & ZFCP_STATUS_PORT_PHYS_OPEN) ||
4908b3bdd99SSteffen Maier 	    0 != (status & ZFCP_STATUS_PORT_LINK_TEST) ||
491a17c7846SJens Remus 	    0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED) ||
492a17c7846SJens Remus 	    0 != (status & ZFCP_STATUS_COMMON_ACCESS_BOXED))
493a17c7846SJens Remus 		i = sprintf(buf, "unknown\n");
494a17c7846SJens Remus 	else if (!(adapter->adapter_features & FSF_FEATURE_FC_SECURITY))
495a17c7846SJens Remus 		i = sprintf(buf, "unsupported\n");
496a17c7846SJens Remus 	else {
497a17c7846SJens Remus 		i = zfcp_fsf_scnprint_fc_security(
498a17c7846SJens Remus 			buf, PAGE_SIZE - 1, port->connection_info,
499a17c7846SJens Remus 			ZFCP_FSF_PRINT_FMT_SINGLEITEM);
500a17c7846SJens Remus 		i += scnprintf(buf + i, PAGE_SIZE - i, "\n");
501a17c7846SJens Remus 	}
502a17c7846SJens Remus 
503a17c7846SJens Remus 	return i;
504a17c7846SJens Remus }
505a17c7846SJens Remus static ZFCP_DEV_ATTR(port, fc_security, S_IRUGO,
506a17c7846SJens Remus 		     zfcp_sysfs_port_fc_security_show,
507a17c7846SJens Remus 		     NULL);
508a17c7846SJens Remus 
5095ab944f9SSwen Schillig static struct attribute *zfcp_port_attrs[] = {
51060221920SSwen Schillig 	&dev_attr_unit_add.attr,
51160221920SSwen Schillig 	&dev_attr_unit_remove.attr,
51260221920SSwen Schillig 	&dev_attr_port_failed.attr,
51360221920SSwen Schillig 	&dev_attr_port_in_recovery.attr,
51460221920SSwen Schillig 	&dev_attr_port_status.attr,
51560221920SSwen Schillig 	&dev_attr_port_access_denied.attr,
516a17c7846SJens Remus 	&dev_attr_port_fc_security.attr,
51760221920SSwen Schillig 	NULL
51860221920SSwen Schillig };
51983d4e1c3SSebastian Ott static struct attribute_group zfcp_port_attr_group = {
5205ab944f9SSwen Schillig 	.attrs = zfcp_port_attrs,
52160221920SSwen Schillig };
52283d4e1c3SSebastian Ott const struct attribute_group *zfcp_port_attr_groups[] = {
52383d4e1c3SSebastian Ott 	&zfcp_port_attr_group,
52483d4e1c3SSebastian Ott 	NULL,
52583d4e1c3SSebastian Ott };
52660221920SSwen Schillig 
52760221920SSwen Schillig static struct attribute *zfcp_unit_attrs[] = {
52860221920SSwen Schillig 	&dev_attr_unit_failed.attr,
52960221920SSwen Schillig 	&dev_attr_unit_in_recovery.attr,
53060221920SSwen Schillig 	&dev_attr_unit_status.attr,
53160221920SSwen Schillig 	&dev_attr_unit_access_denied.attr,
532b5dc3c48SMartin Peschke 	&dev_attr_unit_access_shared.attr,
533b5dc3c48SMartin Peschke 	&dev_attr_unit_access_readonly.attr,
53460221920SSwen Schillig 	NULL
53560221920SSwen Schillig };
53686bdf218SSebastian Ott static struct attribute_group zfcp_unit_attr_group = {
53760221920SSwen Schillig 	.attrs = zfcp_unit_attrs,
53860221920SSwen Schillig };
53986bdf218SSebastian Ott const struct attribute_group *zfcp_unit_attr_groups[] = {
54086bdf218SSebastian Ott 	&zfcp_unit_attr_group,
54186bdf218SSebastian Ott 	NULL,
54286bdf218SSebastian Ott };
54360221920SSwen Schillig 
54460221920SSwen Schillig #define ZFCP_DEFINE_LATENCY_ATTR(_name) 				\
54560221920SSwen Schillig static ssize_t								\
54660221920SSwen Schillig zfcp_sysfs_unit_##_name##_latency_show(struct device *dev,		\
54760221920SSwen Schillig 				       struct device_attribute *attr,	\
54860221920SSwen Schillig 				       char *buf) {			\
54960221920SSwen Schillig 	struct scsi_device *sdev = to_scsi_device(dev);			\
550b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);		\
551b62a8d9bSChristof Schmitt 	struct zfcp_latencies *lat = &zfcp_sdev->latencies;		\
552b62a8d9bSChristof Schmitt 	struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;	\
55360221920SSwen Schillig 	unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc;	\
55460221920SSwen Schillig 									\
55549f0f01cSChristof Schmitt 	spin_lock_bh(&lat->lock);					\
55660221920SSwen Schillig 	fsum = lat->_name.fabric.sum * adapter->timer_ticks;		\
55760221920SSwen Schillig 	fmin = lat->_name.fabric.min * adapter->timer_ticks;		\
55860221920SSwen Schillig 	fmax = lat->_name.fabric.max * adapter->timer_ticks;		\
55960221920SSwen Schillig 	csum = lat->_name.channel.sum * adapter->timer_ticks;		\
56060221920SSwen Schillig 	cmin = lat->_name.channel.min * adapter->timer_ticks;		\
56160221920SSwen Schillig 	cmax = lat->_name.channel.max * adapter->timer_ticks;		\
56260221920SSwen Schillig 	cc  = lat->_name.counter;					\
56349f0f01cSChristof Schmitt 	spin_unlock_bh(&lat->lock);					\
56460221920SSwen Schillig 									\
56560221920SSwen Schillig 	do_div(fsum, 1000);						\
56660221920SSwen Schillig 	do_div(fmin, 1000);						\
56760221920SSwen Schillig 	do_div(fmax, 1000);						\
56860221920SSwen Schillig 	do_div(csum, 1000);						\
56960221920SSwen Schillig 	do_div(cmin, 1000);						\
57060221920SSwen Schillig 	do_div(cmax, 1000);						\
57160221920SSwen Schillig 									\
57260221920SSwen Schillig 	return sprintf(buf, "%llu %llu %llu %llu %llu %llu %llu\n",	\
57360221920SSwen Schillig 		       fmin, fmax, fsum, cmin, cmax, csum, cc); 	\
57460221920SSwen Schillig }									\
57560221920SSwen Schillig static ssize_t								\
57660221920SSwen Schillig zfcp_sysfs_unit_##_name##_latency_store(struct device *dev,		\
57760221920SSwen Schillig 					struct device_attribute *attr,	\
57860221920SSwen Schillig 					const char *buf, size_t count)	\
57960221920SSwen Schillig {									\
58060221920SSwen Schillig 	struct scsi_device *sdev = to_scsi_device(dev);			\
581b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);		\
582b62a8d9bSChristof Schmitt 	struct zfcp_latencies *lat = &zfcp_sdev->latencies;		\
58360221920SSwen Schillig 	unsigned long flags;						\
58460221920SSwen Schillig 									\
58560221920SSwen Schillig 	spin_lock_irqsave(&lat->lock, flags);				\
58660221920SSwen Schillig 	lat->_name.fabric.sum = 0;					\
58760221920SSwen Schillig 	lat->_name.fabric.min = 0xFFFFFFFF;				\
58860221920SSwen Schillig 	lat->_name.fabric.max = 0;					\
58960221920SSwen Schillig 	lat->_name.channel.sum = 0;					\
59060221920SSwen Schillig 	lat->_name.channel.min = 0xFFFFFFFF;				\
59160221920SSwen Schillig 	lat->_name.channel.max = 0;					\
59260221920SSwen Schillig 	lat->_name.counter = 0;						\
59360221920SSwen Schillig 	spin_unlock_irqrestore(&lat->lock, flags);			\
59460221920SSwen Schillig 									\
59560221920SSwen Schillig 	return (ssize_t) count;						\
59660221920SSwen Schillig }									\
59760221920SSwen Schillig static DEVICE_ATTR(_name##_latency, S_IWUSR | S_IRUGO,			\
59860221920SSwen Schillig 		   zfcp_sysfs_unit_##_name##_latency_show,		\
59960221920SSwen Schillig 		   zfcp_sysfs_unit_##_name##_latency_store);
60060221920SSwen Schillig 
60160221920SSwen Schillig ZFCP_DEFINE_LATENCY_ATTR(read);
60260221920SSwen Schillig ZFCP_DEFINE_LATENCY_ATTR(write);
60360221920SSwen Schillig ZFCP_DEFINE_LATENCY_ATTR(cmd);
60460221920SSwen Schillig 
60560221920SSwen Schillig #define ZFCP_DEFINE_SCSI_ATTR(_name, _format, _value)			\
60660221920SSwen Schillig static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev,	\
60760221920SSwen Schillig 					      struct device_attribute *attr,\
60860221920SSwen Schillig 					      char *buf)                 \
60960221920SSwen Schillig {                                                                        \
61060221920SSwen Schillig 	struct scsi_device *sdev = to_scsi_device(dev);			 \
611b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);		 \
61260221920SSwen Schillig 									 \
61360221920SSwen Schillig 	return sprintf(buf, _format, _value);                            \
61460221920SSwen Schillig }                                                                        \
61560221920SSwen Schillig static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL);
61660221920SSwen Schillig 
61760221920SSwen Schillig ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n",
618c8bba144SSteffen Maier 		      dev_name(&zfcp_sdev->port->adapter->ccw_device->dev));
6197ba58c9cSSwen Schillig ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n",
620c8bba144SSteffen Maier 		      (unsigned long long) zfcp_sdev->port->wwpn);
621e4b9857fSChristof Schmitt 
zfcp_sysfs_scsi_fcp_lun_show(struct device * dev,struct device_attribute * attr,char * buf)622e4b9857fSChristof Schmitt static ssize_t zfcp_sysfs_scsi_fcp_lun_show(struct device *dev,
623e4b9857fSChristof Schmitt 					    struct device_attribute *attr,
624e4b9857fSChristof Schmitt 					    char *buf)
625e4b9857fSChristof Schmitt {
626e4b9857fSChristof Schmitt 	struct scsi_device *sdev = to_scsi_device(dev);
627e4b9857fSChristof Schmitt 
628b62a8d9bSChristof Schmitt 	return sprintf(buf, "0x%016llx\n", zfcp_scsi_dev_lun(sdev));
629e4b9857fSChristof Schmitt }
630e4b9857fSChristof Schmitt static DEVICE_ATTR(fcp_lun, S_IRUGO, zfcp_sysfs_scsi_fcp_lun_show, NULL);
63160221920SSwen Schillig 
632c8bba144SSteffen Maier ZFCP_DEFINE_SCSI_ATTR(zfcp_access_denied, "%d\n",
633c8bba144SSteffen Maier 		      (atomic_read(&zfcp_sdev->status) &
634c8bba144SSteffen Maier 		       ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0);
635c8bba144SSteffen Maier 
zfcp_sysfs_scsi_zfcp_failed_show(struct device * dev,struct device_attribute * attr,char * buf)636c8bba144SSteffen Maier static ssize_t zfcp_sysfs_scsi_zfcp_failed_show(struct device *dev,
637c8bba144SSteffen Maier 					   struct device_attribute *attr,
638c8bba144SSteffen Maier 					   char *buf)
639c8bba144SSteffen Maier {
640c8bba144SSteffen Maier 	struct scsi_device *sdev = to_scsi_device(dev);
641c8bba144SSteffen Maier 	unsigned int status = atomic_read(&sdev_to_zfcp(sdev)->status);
642c8bba144SSteffen Maier 	unsigned int failed = status & ZFCP_STATUS_COMMON_ERP_FAILED ? 1 : 0;
643c8bba144SSteffen Maier 
644c8bba144SSteffen Maier 	return sprintf(buf, "%d\n", failed);
645c8bba144SSteffen Maier }
646c8bba144SSteffen Maier 
zfcp_sysfs_scsi_zfcp_failed_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)647c8bba144SSteffen Maier static ssize_t zfcp_sysfs_scsi_zfcp_failed_store(struct device *dev,
648c8bba144SSteffen Maier 					    struct device_attribute *attr,
649c8bba144SSteffen Maier 					    const char *buf, size_t count)
650c8bba144SSteffen Maier {
651c8bba144SSteffen Maier 	struct scsi_device *sdev = to_scsi_device(dev);
652c8bba144SSteffen Maier 	unsigned long val;
653c8bba144SSteffen Maier 
654c8bba144SSteffen Maier 	if (kstrtoul(buf, 0, &val) || val != 0)
655c8bba144SSteffen Maier 		return -EINVAL;
656c8bba144SSteffen Maier 
657c8bba144SSteffen Maier 	zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);
658c8bba144SSteffen Maier 	zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
659c8bba144SSteffen Maier 			    "syufai3");
660c8bba144SSteffen Maier 	zfcp_erp_wait(sdev_to_zfcp(sdev)->port->adapter);
661c8bba144SSteffen Maier 
662c8bba144SSteffen Maier 	return count;
663c8bba144SSteffen Maier }
664c8bba144SSteffen Maier static DEVICE_ATTR(zfcp_failed, S_IWUSR | S_IRUGO,
665c8bba144SSteffen Maier 		   zfcp_sysfs_scsi_zfcp_failed_show,
666c8bba144SSteffen Maier 		   zfcp_sysfs_scsi_zfcp_failed_store);
667c8bba144SSteffen Maier 
668c8bba144SSteffen Maier ZFCP_DEFINE_SCSI_ATTR(zfcp_in_recovery, "%d\n",
669c8bba144SSteffen Maier 		      (atomic_read(&zfcp_sdev->status) &
670c8bba144SSteffen Maier 		       ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
671c8bba144SSteffen Maier 
672c8bba144SSteffen Maier ZFCP_DEFINE_SCSI_ATTR(zfcp_status, "0x%08x\n",
673c8bba144SSteffen Maier 		      atomic_read(&zfcp_sdev->status));
674c8bba144SSteffen Maier 
675*b9787bdfSJulian Wiedmann static struct attribute *zfcp_sdev_attrs[] = {
676d8d7cf3fSBart Van Assche 	&dev_attr_fcp_lun.attr,
677d8d7cf3fSBart Van Assche 	&dev_attr_wwpn.attr,
678d8d7cf3fSBart Van Assche 	&dev_attr_hba_id.attr,
679d8d7cf3fSBart Van Assche 	&dev_attr_read_latency.attr,
680d8d7cf3fSBart Van Assche 	&dev_attr_write_latency.attr,
681d8d7cf3fSBart Van Assche 	&dev_attr_cmd_latency.attr,
682d8d7cf3fSBart Van Assche 	&dev_attr_zfcp_access_denied.attr,
683d8d7cf3fSBart Van Assche 	&dev_attr_zfcp_failed.attr,
684d8d7cf3fSBart Van Assche 	&dev_attr_zfcp_in_recovery.attr,
685d8d7cf3fSBart Van Assche 	&dev_attr_zfcp_status.attr,
686d8d7cf3fSBart Van Assche 	NULL
687d8d7cf3fSBart Van Assche };
688d8d7cf3fSBart Van Assche 
689d8d7cf3fSBart Van Assche static const struct attribute_group zfcp_sysfs_sdev_attr_group = {
690d8d7cf3fSBart Van Assche 	.attrs = zfcp_sdev_attrs
691d8d7cf3fSBart Van Assche };
692d8d7cf3fSBart Van Assche 
693d8d7cf3fSBart Van Assche const struct attribute_group *zfcp_sysfs_sdev_attr_groups[] = {
694d8d7cf3fSBart Van Assche 	&zfcp_sysfs_sdev_attr_group,
69560221920SSwen Schillig 	NULL
69660221920SSwen Schillig };
69760221920SSwen Schillig 
zfcp_sysfs_adapter_util_show(struct device * dev,struct device_attribute * attr,char * buf)69860221920SSwen Schillig static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev,
69960221920SSwen Schillig 					    struct device_attribute *attr,
70060221920SSwen Schillig 					    char *buf)
70160221920SSwen Schillig {
70260221920SSwen Schillig 	struct Scsi_Host *scsi_host = dev_to_shost(dev);
70360221920SSwen Schillig 	struct fsf_qtcb_bottom_port *qtcb_port;
70460221920SSwen Schillig 	struct zfcp_adapter *adapter;
70560221920SSwen Schillig 	int retval;
70660221920SSwen Schillig 
70760221920SSwen Schillig 	adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
70860221920SSwen Schillig 	if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA))
70960221920SSwen Schillig 		return -EOPNOTSUPP;
71060221920SSwen Schillig 
71160221920SSwen Schillig 	qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL);
71260221920SSwen Schillig 	if (!qtcb_port)
71360221920SSwen Schillig 		return -ENOMEM;
71460221920SSwen Schillig 
715564e1c86SSwen Schillig 	retval = zfcp_fsf_exchange_port_data_sync(adapter->qdio, qtcb_port);
71692953c6eSBenjamin Block 	if (retval == 0 || retval == -EAGAIN)
71760221920SSwen Schillig 		retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util,
71860221920SSwen Schillig 				 qtcb_port->cb_util, qtcb_port->a_util);
71960221920SSwen Schillig 	kfree(qtcb_port);
72060221920SSwen Schillig 	return retval;
72160221920SSwen Schillig }
72260221920SSwen Schillig static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL);
72360221920SSwen Schillig 
zfcp_sysfs_adapter_ex_config(struct device * dev,struct fsf_statistics_info * stat_inf)72460221920SSwen Schillig static int zfcp_sysfs_adapter_ex_config(struct device *dev,
72560221920SSwen Schillig 					struct fsf_statistics_info *stat_inf)
72660221920SSwen Schillig {
72760221920SSwen Schillig 	struct Scsi_Host *scsi_host = dev_to_shost(dev);
72860221920SSwen Schillig 	struct fsf_qtcb_bottom_config *qtcb_config;
72960221920SSwen Schillig 	struct zfcp_adapter *adapter;
73060221920SSwen Schillig 	int retval;
73160221920SSwen Schillig 
73260221920SSwen Schillig 	adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
73360221920SSwen Schillig 	if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA))
73460221920SSwen Schillig 		return -EOPNOTSUPP;
73560221920SSwen Schillig 
73660221920SSwen Schillig 	qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config),
73760221920SSwen Schillig 			      GFP_KERNEL);
73860221920SSwen Schillig 	if (!qtcb_config)
73960221920SSwen Schillig 		return -ENOMEM;
74060221920SSwen Schillig 
741564e1c86SSwen Schillig 	retval = zfcp_fsf_exchange_config_data_sync(adapter->qdio, qtcb_config);
74292953c6eSBenjamin Block 	if (retval == 0 || retval == -EAGAIN)
74360221920SSwen Schillig 		*stat_inf = qtcb_config->stat_info;
74460221920SSwen Schillig 
74560221920SSwen Schillig 	kfree(qtcb_config);
74660221920SSwen Schillig 	return retval;
74760221920SSwen Schillig }
74860221920SSwen Schillig 
74960221920SSwen Schillig #define ZFCP_SHOST_ATTR(_name, _format, _arg...)			\
75060221920SSwen Schillig static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev,	\
75160221920SSwen Schillig 						 struct device_attribute *attr,\
75260221920SSwen Schillig 						 char *buf)		\
75360221920SSwen Schillig {									\
75460221920SSwen Schillig 	struct fsf_statistics_info stat_info;				\
75560221920SSwen Schillig 	int retval;							\
75660221920SSwen Schillig 									\
75760221920SSwen Schillig 	retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info);		\
75860221920SSwen Schillig 	if (retval)							\
75960221920SSwen Schillig 		return retval;						\
76060221920SSwen Schillig 									\
76160221920SSwen Schillig 	return sprintf(buf, _format, ## _arg);				\
76260221920SSwen Schillig }									\
76360221920SSwen Schillig static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL);
76460221920SSwen Schillig 
76560221920SSwen Schillig ZFCP_SHOST_ATTR(requests, "%llu %llu %llu\n",
76660221920SSwen Schillig 		(unsigned long long) stat_info.input_req,
76760221920SSwen Schillig 		(unsigned long long) stat_info.output_req,
76860221920SSwen Schillig 		(unsigned long long) stat_info.control_req);
76960221920SSwen Schillig 
77060221920SSwen Schillig ZFCP_SHOST_ATTR(megabytes, "%llu %llu\n",
77160221920SSwen Schillig 		(unsigned long long) stat_info.input_mb,
77260221920SSwen Schillig 		(unsigned long long) stat_info.output_mb);
77360221920SSwen Schillig 
77460221920SSwen Schillig ZFCP_SHOST_ATTR(seconds_active, "%llu\n",
77560221920SSwen Schillig 		(unsigned long long) stat_info.seconds_act);
77660221920SSwen Schillig 
zfcp_sysfs_adapter_q_full_show(struct device * dev,struct device_attribute * attr,char * buf)7772450d3e7SStefan Raspl static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev,
7782450d3e7SStefan Raspl 					      struct device_attribute *attr,
7792450d3e7SStefan Raspl 					      char *buf)
7802450d3e7SStefan Raspl {
7812450d3e7SStefan Raspl 	struct Scsi_Host *scsi_host = class_to_shost(dev);
782564e1c86SSwen Schillig 	struct zfcp_qdio *qdio =
783564e1c86SSwen Schillig 		((struct zfcp_adapter *) scsi_host->hostdata[0])->qdio;
784acf7b861SChristof Schmitt 	u64 util;
785acf7b861SChristof Schmitt 
786564e1c86SSwen Schillig 	spin_lock_bh(&qdio->stat_lock);
787564e1c86SSwen Schillig 	util = qdio->req_q_util;
788564e1c86SSwen Schillig 	spin_unlock_bh(&qdio->stat_lock);
7892450d3e7SStefan Raspl 
790564e1c86SSwen Schillig 	return sprintf(buf, "%d %llu\n", atomic_read(&qdio->req_q_full),
791acf7b861SChristof Schmitt 		       (unsigned long long)util);
7922450d3e7SStefan Raspl }
7932450d3e7SStefan Raspl static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL);
7942450d3e7SStefan Raspl 
795d8d7cf3fSBart Van Assche static struct attribute *zfcp_sysfs_shost_attrs[] = {
796d8d7cf3fSBart Van Assche 	&dev_attr_utilization.attr,
797d8d7cf3fSBart Van Assche 	&dev_attr_requests.attr,
798d8d7cf3fSBart Van Assche 	&dev_attr_megabytes.attr,
799d8d7cf3fSBart Van Assche 	&dev_attr_seconds_active.attr,
800d8d7cf3fSBart Van Assche 	&dev_attr_queue_full.attr,
801d8d7cf3fSBart Van Assche 	NULL
802d8d7cf3fSBart Van Assche };
803d8d7cf3fSBart Van Assche 
804d8d7cf3fSBart Van Assche static const struct attribute_group zfcp_sysfs_shost_attr_group = {
805d8d7cf3fSBart Van Assche 	.attrs = zfcp_sysfs_shost_attrs
806d8d7cf3fSBart Van Assche };
807d8d7cf3fSBart Van Assche 
808d8d7cf3fSBart Van Assche const struct attribute_group *zfcp_sysfs_shost_attr_groups[] = {
809d8d7cf3fSBart Van Assche 	&zfcp_sysfs_shost_attr_group,
81060221920SSwen Schillig 	NULL
81160221920SSwen Schillig };
8126028f7c4SBenjamin Block 
zfcp_sysfs_adapter_diag_b2b_credit_show(struct device * dev,struct device_attribute * attr,char * buf)8135a2876f0SBenjamin Block static ssize_t zfcp_sysfs_adapter_diag_b2b_credit_show(
8145a2876f0SBenjamin Block 	struct device *dev, struct device_attribute *attr, char *buf)
8155a2876f0SBenjamin Block {
8165a2876f0SBenjamin Block 	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev));
8175a2876f0SBenjamin Block 	struct zfcp_diag_header *diag_hdr;
8185a2876f0SBenjamin Block 	struct fc_els_flogi *nsp;
8195a2876f0SBenjamin Block 	ssize_t rc = -ENOLINK;
8205a2876f0SBenjamin Block 	unsigned long flags;
8215a2876f0SBenjamin Block 	unsigned int status;
8225a2876f0SBenjamin Block 
8235a2876f0SBenjamin Block 	if (!adapter)
8245a2876f0SBenjamin Block 		return -ENODEV;
8255a2876f0SBenjamin Block 
8265a2876f0SBenjamin Block 	status = atomic_read(&adapter->status);
8275a2876f0SBenjamin Block 	if (0 == (status & ZFCP_STATUS_COMMON_OPEN) ||
8285a2876f0SBenjamin Block 	    0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) ||
8295a2876f0SBenjamin Block 	    0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED))
8305a2876f0SBenjamin Block 		goto out;
8315a2876f0SBenjamin Block 
8325a2876f0SBenjamin Block 	diag_hdr = &adapter->diagnostics->config_data.header;
8335a2876f0SBenjamin Block 
8348a72db70SBenjamin Block 	rc = zfcp_diag_update_buffer_limited(
8358a72db70SBenjamin Block 		adapter, diag_hdr, zfcp_diag_update_config_data_buffer);
8368a72db70SBenjamin Block 	if (rc != 0)
8378a72db70SBenjamin Block 		goto out;
8388a72db70SBenjamin Block 
8395a2876f0SBenjamin Block 	spin_lock_irqsave(&diag_hdr->access_lock, flags);
8405a2876f0SBenjamin Block 	/* nport_serv_param doesn't contain the ELS_Command code */
8415a2876f0SBenjamin Block 	nsp = (struct fc_els_flogi *)((unsigned long)
8425a2876f0SBenjamin Block 					      adapter->diagnostics->config_data
8435a2876f0SBenjamin Block 						      .data.nport_serv_param -
8445a2876f0SBenjamin Block 				      sizeof(u32));
8455a2876f0SBenjamin Block 
8465a2876f0SBenjamin Block 	rc = scnprintf(buf, 5 + 2, "%hu\n",
8475a2876f0SBenjamin Block 		       be16_to_cpu(nsp->fl_csp.sp_bb_cred));
8485a2876f0SBenjamin Block 	spin_unlock_irqrestore(&diag_hdr->access_lock, flags);
8495a2876f0SBenjamin Block 
8505a2876f0SBenjamin Block out:
8515a2876f0SBenjamin Block 	zfcp_ccw_adapter_put(adapter);
8525a2876f0SBenjamin Block 	return rc;
8535a2876f0SBenjamin Block }
8545a2876f0SBenjamin Block static ZFCP_DEV_ATTR(adapter_diag, b2b_credit, 0400,
8555a2876f0SBenjamin Block 		     zfcp_sysfs_adapter_diag_b2b_credit_show, NULL);
8565a2876f0SBenjamin Block 
8576028f7c4SBenjamin Block #define ZFCP_DEFINE_DIAG_SFP_ATTR(_name, _qtcb_member, _prtsize, _prtfmt)      \
8586028f7c4SBenjamin Block 	static ssize_t zfcp_sysfs_adapter_diag_sfp_##_name##_show(	       \
8596028f7c4SBenjamin Block 		struct device *dev, struct device_attribute *attr, char *buf)  \
8606028f7c4SBenjamin Block 	{								       \
8616028f7c4SBenjamin Block 		struct zfcp_adapter *const adapter =			       \
8626028f7c4SBenjamin Block 			zfcp_ccw_adapter_by_cdev(to_ccwdev(dev));	       \
8636028f7c4SBenjamin Block 		struct zfcp_diag_header *diag_hdr;			       \
8646028f7c4SBenjamin Block 		ssize_t rc = -ENOLINK;					       \
8656028f7c4SBenjamin Block 		unsigned long flags;					       \
8666028f7c4SBenjamin Block 		unsigned int status;					       \
8676028f7c4SBenjamin Block 									       \
8686028f7c4SBenjamin Block 		if (!adapter)						       \
8696028f7c4SBenjamin Block 			return -ENODEV;					       \
8706028f7c4SBenjamin Block 									       \
8716028f7c4SBenjamin Block 		status = atomic_read(&adapter->status);			       \
8726028f7c4SBenjamin Block 		if (0 == (status & ZFCP_STATUS_COMMON_OPEN) ||		       \
8736028f7c4SBenjamin Block 		    0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) ||	       \
8746028f7c4SBenjamin Block 		    0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED))	       \
8756028f7c4SBenjamin Block 			goto out;					       \
8766028f7c4SBenjamin Block 									       \
8776028f7c4SBenjamin Block 		if (!zfcp_diag_support_sfp(adapter)) {			       \
8786028f7c4SBenjamin Block 			rc = -EOPNOTSUPP;				       \
8796028f7c4SBenjamin Block 			goto out;					       \
8806028f7c4SBenjamin Block 		}							       \
8816028f7c4SBenjamin Block 									       \
8826028f7c4SBenjamin Block 		diag_hdr = &adapter->diagnostics->port_data.header;	       \
8836028f7c4SBenjamin Block 									       \
8848155eb07SBenjamin Block 		rc = zfcp_diag_update_buffer_limited(			       \
8858155eb07SBenjamin Block 			adapter, diag_hdr, zfcp_diag_update_port_data_buffer); \
8868155eb07SBenjamin Block 		if (rc != 0)						       \
8878155eb07SBenjamin Block 			goto out;					       \
8888155eb07SBenjamin Block 									       \
8896028f7c4SBenjamin Block 		spin_lock_irqsave(&diag_hdr->access_lock, flags);	       \
8906028f7c4SBenjamin Block 		rc = scnprintf(						       \
8916028f7c4SBenjamin Block 			buf, (_prtsize) + 2, _prtfmt "\n",		       \
8926028f7c4SBenjamin Block 			adapter->diagnostics->port_data.data._qtcb_member);    \
8936028f7c4SBenjamin Block 		spin_unlock_irqrestore(&diag_hdr->access_lock, flags);	       \
8946028f7c4SBenjamin Block 									       \
8956028f7c4SBenjamin Block 	out:								       \
8966028f7c4SBenjamin Block 		zfcp_ccw_adapter_put(adapter);				       \
8976028f7c4SBenjamin Block 		return rc;						       \
8986028f7c4SBenjamin Block 	}								       \
8996028f7c4SBenjamin Block 	static ZFCP_DEV_ATTR(adapter_diag_sfp, _name, 0400,		       \
9006028f7c4SBenjamin Block 			     zfcp_sysfs_adapter_diag_sfp_##_name##_show, NULL)
9016028f7c4SBenjamin Block 
902a3fd4bfeSBenjamin Block ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, 6, "%hd");
9036028f7c4SBenjamin Block ZFCP_DEFINE_DIAG_SFP_ATTR(vcc, vcc, 5, "%hu");
9046028f7c4SBenjamin Block ZFCP_DEFINE_DIAG_SFP_ATTR(tx_bias, tx_bias, 5, "%hu");
9056028f7c4SBenjamin Block ZFCP_DEFINE_DIAG_SFP_ATTR(tx_power, tx_power, 5, "%hu");
9066028f7c4SBenjamin Block ZFCP_DEFINE_DIAG_SFP_ATTR(rx_power, rx_power, 5, "%hu");
9076028f7c4SBenjamin Block ZFCP_DEFINE_DIAG_SFP_ATTR(port_tx_type, sfp_flags.port_tx_type, 2, "%hu");
9086028f7c4SBenjamin Block ZFCP_DEFINE_DIAG_SFP_ATTR(optical_port, sfp_flags.optical_port, 1, "%hu");
9096028f7c4SBenjamin Block ZFCP_DEFINE_DIAG_SFP_ATTR(sfp_invalid, sfp_flags.sfp_invalid, 1, "%hu");
9106028f7c4SBenjamin Block ZFCP_DEFINE_DIAG_SFP_ATTR(connector_type, sfp_flags.connector_type, 1, "%hu");
9116028f7c4SBenjamin Block ZFCP_DEFINE_DIAG_SFP_ATTR(fec_active, sfp_flags.fec_active, 1, "%hu");
9126028f7c4SBenjamin Block 
9136028f7c4SBenjamin Block static struct attribute *zfcp_sysfs_diag_attrs[] = {
9146028f7c4SBenjamin Block 	&dev_attr_adapter_diag_sfp_temperature.attr,
9156028f7c4SBenjamin Block 	&dev_attr_adapter_diag_sfp_vcc.attr,
9166028f7c4SBenjamin Block 	&dev_attr_adapter_diag_sfp_tx_bias.attr,
9176028f7c4SBenjamin Block 	&dev_attr_adapter_diag_sfp_tx_power.attr,
9186028f7c4SBenjamin Block 	&dev_attr_adapter_diag_sfp_rx_power.attr,
9196028f7c4SBenjamin Block 	&dev_attr_adapter_diag_sfp_port_tx_type.attr,
9206028f7c4SBenjamin Block 	&dev_attr_adapter_diag_sfp_optical_port.attr,
9216028f7c4SBenjamin Block 	&dev_attr_adapter_diag_sfp_sfp_invalid.attr,
9226028f7c4SBenjamin Block 	&dev_attr_adapter_diag_sfp_connector_type.attr,
9236028f7c4SBenjamin Block 	&dev_attr_adapter_diag_sfp_fec_active.attr,
9245a2876f0SBenjamin Block 	&dev_attr_adapter_diag_b2b_credit.attr,
9256028f7c4SBenjamin Block 	NULL,
9266028f7c4SBenjamin Block };
9276028f7c4SBenjamin Block 
92820540a56SJulian Wiedmann static const struct attribute_group zfcp_sysfs_diag_attr_group = {
9296028f7c4SBenjamin Block 	.name = "diagnostics",
9306028f7c4SBenjamin Block 	.attrs = zfcp_sysfs_diag_attrs,
9316028f7c4SBenjamin Block };
93220540a56SJulian Wiedmann 
93320540a56SJulian Wiedmann const struct attribute_group *zfcp_sysfs_adapter_attr_groups[] = {
93420540a56SJulian Wiedmann 	&zfcp_sysfs_adapter_attr_group,
93520540a56SJulian Wiedmann 	&zfcp_sysfs_diag_attr_group,
93620540a56SJulian Wiedmann 	NULL,
93720540a56SJulian Wiedmann };
938