Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/drivers/s390/scsi/zfcp_sysfs_adapter.c | |
3 | * | |
4 | * FCP adapter driver for IBM eServer zSeries | |
5 | * | |
6 | * sysfs adapter related routines | |
7 | * | |
8 | * (C) Copyright IBM Corp. 2003, 2004 | |
9 | * | |
10 | * Authors: | |
11 | * Martin Peschke <mpeschke@de.ibm.com> | |
12 | * Heiko Carstens <heiko.carstens@de.ibm.com> | |
13 | * Andreas Herrmann <aherrman@de.ibm.com> | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or modify | |
16 | * it under the terms of the GNU General Public License as published by | |
17 | * the Free Software Foundation; either version 2, or (at your option) | |
18 | * any later version. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, | |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | * GNU General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, write to the Free Software | |
27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
28 | */ | |
29 | ||
30 | #define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.38 $" | |
31 | ||
32 | #include "zfcp_ext.h" | |
33 | ||
34 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | |
35 | ||
36 | static const char fc_topologies[5][25] = { | |
37 | "<error>", | |
38 | "point-to-point", | |
39 | "fabric", | |
40 | "arbitrated loop", | |
41 | "fabric (virt. adapter)" | |
42 | }; | |
43 | ||
44 | /** | |
45 | * ZFCP_DEFINE_ADAPTER_ATTR | |
46 | * @_name: name of show attribute | |
47 | * @_format: format string | |
48 | * @_value: value to print | |
49 | * | |
50 | * Generates attributes for an adapter. | |
51 | */ | |
52 | #define ZFCP_DEFINE_ADAPTER_ATTR(_name, _format, _value) \ | |
10523b3b | 53 | static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, struct device_attribute *attr, \ |
1da177e4 LT |
54 | char *buf) \ |
55 | { \ | |
56 | struct zfcp_adapter *adapter; \ | |
57 | \ | |
58 | adapter = dev_get_drvdata(dev); \ | |
59 | return sprintf(buf, _format, _value); \ | |
60 | } \ | |
61 | \ | |
62 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL); | |
63 | ||
64 | ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x\n", atomic_read(&adapter->status)); | |
65 | ZFCP_DEFINE_ADAPTER_ATTR(wwnn, "0x%016llx\n", adapter->wwnn); | |
66 | ZFCP_DEFINE_ADAPTER_ATTR(wwpn, "0x%016llx\n", adapter->wwpn); | |
67 | ZFCP_DEFINE_ADAPTER_ATTR(s_id, "0x%06x\n", adapter->s_id); | |
6f71d9bc | 68 | ZFCP_DEFINE_ADAPTER_ATTR(peer_wwnn, "0x%016llx\n", adapter->peer_wwnn); |
69 | ZFCP_DEFINE_ADAPTER_ATTR(peer_wwpn, "0x%016llx\n", adapter->peer_wwpn); | |
70 | ZFCP_DEFINE_ADAPTER_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id); | |
1da177e4 LT |
71 | ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version); |
72 | ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version); | |
73 | ZFCP_DEFINE_ADAPTER_ATTR(fc_link_speed, "%d Gb/s\n", adapter->fc_link_speed); | |
74 | ZFCP_DEFINE_ADAPTER_ATTR(fc_service_class, "%d\n", adapter->fc_service_class); | |
75 | ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n", | |
76 | fc_topologies[adapter->fc_topology]); | |
77 | ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n", | |
78 | adapter->hardware_version); | |
79 | ZFCP_DEFINE_ADAPTER_ATTR(serial_number, "%17s\n", adapter->serial_number); | |
80 | ZFCP_DEFINE_ADAPTER_ATTR(scsi_host_no, "0x%x\n", adapter->scsi_host_no); | |
81 | ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask | |
82 | (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)); | |
83 | ||
84 | /** | |
85 | * zfcp_sysfs_port_add_store - add a port to sysfs tree | |
86 | * @dev: pointer to belonging device | |
87 | * @buf: pointer to input buffer | |
88 | * @count: number of bytes in buffer | |
89 | * | |
90 | * Store function of the "port_add" attribute of an adapter. | |
91 | */ | |
92 | static ssize_t | |
10523b3b | 93 | zfcp_sysfs_port_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
1da177e4 LT |
94 | { |
95 | wwn_t wwpn; | |
96 | char *endp; | |
97 | struct zfcp_adapter *adapter; | |
98 | struct zfcp_port *port; | |
99 | int retval = -EINVAL; | |
100 | ||
101 | down(&zfcp_data.config_sema); | |
102 | ||
103 | adapter = dev_get_drvdata(dev); | |
104 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { | |
105 | retval = -EBUSY; | |
106 | goto out; | |
107 | } | |
108 | ||
109 | wwpn = simple_strtoull(buf, &endp, 0); | |
110 | if ((endp + 1) < (buf + count)) | |
111 | goto out; | |
112 | ||
113 | port = zfcp_port_enqueue(adapter, wwpn, 0, 0); | |
114 | if (!port) | |
115 | goto out; | |
116 | ||
117 | retval = 0; | |
118 | ||
119 | zfcp_erp_port_reopen(port, 0); | |
120 | zfcp_erp_wait(port->adapter); | |
121 | zfcp_port_put(port); | |
122 | out: | |
123 | up(&zfcp_data.config_sema); | |
124 | return retval ? retval : (ssize_t) count; | |
125 | } | |
126 | ||
127 | static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store); | |
128 | ||
129 | /** | |
130 | * zfcp_sysfs_port_remove_store - remove a port from sysfs tree | |
131 | * @dev: pointer to belonging device | |
132 | * @buf: pointer to input buffer | |
133 | * @count: number of bytes in buffer | |
134 | * | |
135 | * Store function of the "port_remove" attribute of an adapter. | |
136 | */ | |
137 | static ssize_t | |
10523b3b | 138 | zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
1da177e4 LT |
139 | { |
140 | struct zfcp_adapter *adapter; | |
141 | struct zfcp_port *port; | |
142 | wwn_t wwpn; | |
143 | char *endp; | |
144 | int retval = 0; | |
145 | ||
146 | down(&zfcp_data.config_sema); | |
147 | ||
148 | adapter = dev_get_drvdata(dev); | |
149 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { | |
150 | retval = -EBUSY; | |
151 | goto out; | |
152 | } | |
153 | ||
154 | wwpn = simple_strtoull(buf, &endp, 0); | |
155 | if ((endp + 1) < (buf + count)) { | |
156 | retval = -EINVAL; | |
157 | goto out; | |
158 | } | |
159 | ||
160 | write_lock_irq(&zfcp_data.config_lock); | |
161 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | |
162 | if (port && (atomic_read(&port->refcount) == 0)) { | |
163 | zfcp_port_get(port); | |
164 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | |
165 | list_move(&port->list, &adapter->port_remove_lh); | |
166 | } | |
167 | else { | |
168 | port = NULL; | |
169 | } | |
170 | write_unlock_irq(&zfcp_data.config_lock); | |
171 | ||
172 | if (!port) { | |
173 | retval = -ENXIO; | |
174 | goto out; | |
175 | } | |
176 | ||
177 | zfcp_erp_port_shutdown(port, 0); | |
178 | zfcp_erp_wait(adapter); | |
179 | zfcp_port_put(port); | |
180 | zfcp_port_dequeue(port); | |
181 | out: | |
182 | up(&zfcp_data.config_sema); | |
183 | return retval ? retval : (ssize_t) count; | |
184 | } | |
185 | ||
186 | static DEVICE_ATTR(port_remove, S_IWUSR, NULL, zfcp_sysfs_port_remove_store); | |
187 | ||
188 | /** | |
189 | * zfcp_sysfs_adapter_failed_store - failed state of adapter | |
190 | * @dev: pointer to belonging device | |
191 | * @buf: pointer to input buffer | |
192 | * @count: number of bytes in buffer | |
193 | * | |
194 | * Store function of the "failed" attribute of an adapter. | |
195 | * If a "0" gets written to "failed", error recovery will be | |
196 | * started for the belonging adapter. | |
197 | */ | |
198 | static ssize_t | |
10523b3b | 199 | zfcp_sysfs_adapter_failed_store(struct device *dev, struct device_attribute *attr, |
1da177e4 LT |
200 | const char *buf, size_t count) |
201 | { | |
202 | struct zfcp_adapter *adapter; | |
203 | unsigned int val; | |
204 | char *endp; | |
205 | int retval = 0; | |
206 | ||
207 | down(&zfcp_data.config_sema); | |
208 | ||
209 | adapter = dev_get_drvdata(dev); | |
210 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { | |
211 | retval = -EBUSY; | |
212 | goto out; | |
213 | } | |
214 | ||
215 | val = simple_strtoul(buf, &endp, 0); | |
216 | if (((endp + 1) < (buf + count)) || (val != 0)) { | |
217 | retval = -EINVAL; | |
218 | goto out; | |
219 | } | |
220 | ||
221 | zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING, | |
222 | ZFCP_SET); | |
223 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); | |
224 | zfcp_erp_wait(adapter); | |
225 | out: | |
226 | up(&zfcp_data.config_sema); | |
227 | return retval ? retval : (ssize_t) count; | |
228 | } | |
229 | ||
230 | /** | |
231 | * zfcp_sysfs_adapter_failed_show - failed state of adapter | |
232 | * @dev: pointer to belonging device | |
233 | * @buf: pointer to input buffer | |
234 | * | |
235 | * Show function of "failed" attribute of adapter. Will be | |
236 | * "0" if adapter is working, otherwise "1". | |
237 | */ | |
238 | static ssize_t | |
10523b3b | 239 | zfcp_sysfs_adapter_failed_show(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4 LT |
240 | { |
241 | struct zfcp_adapter *adapter; | |
242 | ||
243 | adapter = dev_get_drvdata(dev); | |
244 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) | |
245 | return sprintf(buf, "1\n"); | |
246 | else | |
247 | return sprintf(buf, "0\n"); | |
248 | } | |
249 | ||
250 | static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_adapter_failed_show, | |
251 | zfcp_sysfs_adapter_failed_store); | |
252 | ||
253 | static struct attribute *zfcp_adapter_attrs[] = { | |
254 | &dev_attr_failed.attr, | |
255 | &dev_attr_in_recovery.attr, | |
256 | &dev_attr_port_remove.attr, | |
257 | &dev_attr_port_add.attr, | |
258 | &dev_attr_wwnn.attr, | |
259 | &dev_attr_wwpn.attr, | |
260 | &dev_attr_s_id.attr, | |
6f71d9bc | 261 | &dev_attr_peer_wwnn.attr, |
262 | &dev_attr_peer_wwpn.attr, | |
263 | &dev_attr_peer_d_id.attr, | |
1da177e4 LT |
264 | &dev_attr_card_version.attr, |
265 | &dev_attr_lic_version.attr, | |
266 | &dev_attr_fc_link_speed.attr, | |
267 | &dev_attr_fc_service_class.attr, | |
268 | &dev_attr_fc_topology.attr, | |
269 | &dev_attr_scsi_host_no.attr, | |
270 | &dev_attr_status.attr, | |
271 | &dev_attr_hardware_version.attr, | |
272 | &dev_attr_serial_number.attr, | |
273 | NULL | |
274 | }; | |
275 | ||
276 | static struct attribute_group zfcp_adapter_attr_group = { | |
277 | .attrs = zfcp_adapter_attrs, | |
278 | }; | |
279 | ||
280 | /** | |
281 | * zfcp_sysfs_create_adapter_files - create sysfs adapter files | |
282 | * @dev: pointer to belonging device | |
283 | * | |
284 | * Create all attributes of the sysfs representation of an adapter. | |
285 | */ | |
286 | int | |
287 | zfcp_sysfs_adapter_create_files(struct device *dev) | |
288 | { | |
289 | return sysfs_create_group(&dev->kobj, &zfcp_adapter_attr_group); | |
290 | } | |
291 | ||
292 | /** | |
293 | * zfcp_sysfs_remove_adapter_files - remove sysfs adapter files | |
294 | * @dev: pointer to belonging device | |
295 | * | |
296 | * Remove all attributes of the sysfs representation of an adapter. | |
297 | */ | |
298 | void | |
299 | zfcp_sysfs_adapter_remove_files(struct device *dev) | |
300 | { | |
301 | sysfs_remove_group(&dev->kobj, &zfcp_adapter_attr_group); | |
302 | } | |
303 | ||
304 | #undef ZFCP_LOG_AREA |