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