[SCSI] zfcp: transport class adaptations
[pandora-kernel.git] / drivers / s390 / scsi / zfcp_sysfs_adapter.c
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)                      \
53 static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, struct device_attribute *attr,          \
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(peer_wwnn, "0x%016llx\n", adapter->peer_wwnn);
66 ZFCP_DEFINE_ADAPTER_ATTR(peer_wwpn, "0x%016llx\n", adapter->peer_wwpn);
67 ZFCP_DEFINE_ADAPTER_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id);
68 ZFCP_DEFINE_ADAPTER_ATTR(physical_wwpn, "0x%016llx\n", adapter->physical_wwpn);
69 ZFCP_DEFINE_ADAPTER_ATTR(physical_s_id, "0x%06x\n", adapter->physical_s_id);
70 ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
71 ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
72 ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n",
73                          fc_topologies[adapter->fc_topology]);
74 ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n",
75                          adapter->hardware_version);
76 ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask
77                          (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status));
78
79 /**
80  * zfcp_sysfs_port_add_store - add a port to sysfs tree
81  * @dev: pointer to belonging device
82  * @buf: pointer to input buffer
83  * @count: number of bytes in buffer
84  *
85  * Store function of the "port_add" attribute of an adapter.
86  */
87 static ssize_t
88 zfcp_sysfs_port_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
89 {
90         wwn_t wwpn;
91         char *endp;
92         struct zfcp_adapter *adapter;
93         struct zfcp_port *port;
94         int retval = -EINVAL;
95
96         down(&zfcp_data.config_sema);
97
98         adapter = dev_get_drvdata(dev);
99         if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) {
100                 retval = -EBUSY;
101                 goto out;
102         }
103
104         wwpn = simple_strtoull(buf, &endp, 0);
105         if ((endp + 1) < (buf + count))
106                 goto out;
107
108         port = zfcp_port_enqueue(adapter, wwpn, 0, 0);
109         if (!port)
110                 goto out;
111
112         retval = 0;
113
114         zfcp_erp_port_reopen(port, 0);
115         zfcp_erp_wait(port->adapter);
116         zfcp_port_put(port);
117  out:
118         up(&zfcp_data.config_sema);
119         return retval ? retval : (ssize_t) count;
120 }
121
122 static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store);
123
124 /**
125  * zfcp_sysfs_port_remove_store - remove a port from sysfs tree
126  * @dev: pointer to belonging device
127  * @buf: pointer to input buffer
128  * @count: number of bytes in buffer
129  *
130  * Store function of the "port_remove" attribute of an adapter.
131  */
132 static ssize_t
133 zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
134 {
135         struct zfcp_adapter *adapter;
136         struct zfcp_port *port;
137         wwn_t wwpn;
138         char *endp;
139         int retval = 0;
140
141         down(&zfcp_data.config_sema);
142
143         adapter = dev_get_drvdata(dev);
144         if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) {
145                 retval = -EBUSY;
146                 goto out;
147         }
148
149         wwpn = simple_strtoull(buf, &endp, 0);
150         if ((endp + 1) < (buf + count)) {
151                 retval = -EINVAL;
152                 goto out;
153         }
154
155         write_lock_irq(&zfcp_data.config_lock);
156         port = zfcp_get_port_by_wwpn(adapter, wwpn);
157         if (port && (atomic_read(&port->refcount) == 0)) {
158                 zfcp_port_get(port);
159                 atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
160                 list_move(&port->list, &adapter->port_remove_lh);
161         }
162         else {
163                 port = NULL;
164         }
165         write_unlock_irq(&zfcp_data.config_lock);
166
167         if (!port) {
168                 retval = -ENXIO;
169                 goto out;
170         }
171
172         zfcp_erp_port_shutdown(port, 0);
173         zfcp_erp_wait(adapter);
174         zfcp_port_put(port);
175         zfcp_port_dequeue(port);
176  out:
177         up(&zfcp_data.config_sema);
178         return retval ? retval : (ssize_t) count;
179 }
180
181 static DEVICE_ATTR(port_remove, S_IWUSR, NULL, zfcp_sysfs_port_remove_store);
182
183 /**
184  * zfcp_sysfs_adapter_failed_store - failed state of adapter
185  * @dev: pointer to belonging device
186  * @buf: pointer to input buffer
187  * @count: number of bytes in buffer
188  *
189  * Store function of the "failed" attribute of an adapter.
190  * If a "0" gets written to "failed", error recovery will be
191  * started for the belonging adapter.
192  */
193 static ssize_t
194 zfcp_sysfs_adapter_failed_store(struct device *dev, struct device_attribute *attr,
195                                 const char *buf, size_t count)
196 {
197         struct zfcp_adapter *adapter;
198         unsigned int val;
199         char *endp;
200         int retval = 0;
201
202         down(&zfcp_data.config_sema);
203
204         adapter = dev_get_drvdata(dev);
205         if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) {
206                 retval = -EBUSY;
207                 goto out;
208         }
209
210         val = simple_strtoul(buf, &endp, 0);
211         if (((endp + 1) < (buf + count)) || (val != 0)) {
212                 retval = -EINVAL;
213                 goto out;
214         }
215
216         zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
217                                        ZFCP_SET);
218         zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
219         zfcp_erp_wait(adapter);
220  out:
221         up(&zfcp_data.config_sema);
222         return retval ? retval : (ssize_t) count;
223 }
224
225 /**
226  * zfcp_sysfs_adapter_failed_show - failed state of adapter
227  * @dev: pointer to belonging device
228  * @buf: pointer to input buffer
229  *
230  * Show function of "failed" attribute of adapter. Will be
231  * "0" if adapter is working, otherwise "1".
232  */
233 static ssize_t
234 zfcp_sysfs_adapter_failed_show(struct device *dev, struct device_attribute *attr, char *buf)
235 {
236         struct zfcp_adapter *adapter;
237
238         adapter = dev_get_drvdata(dev);
239         if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status))
240                 return sprintf(buf, "1\n");
241         else
242                 return sprintf(buf, "0\n");
243 }
244
245 static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_adapter_failed_show,
246                    zfcp_sysfs_adapter_failed_store);
247
248 static struct attribute *zfcp_adapter_attrs[] = {
249         &dev_attr_failed.attr,
250         &dev_attr_in_recovery.attr,
251         &dev_attr_port_remove.attr,
252         &dev_attr_port_add.attr,
253         &dev_attr_peer_wwnn.attr,
254         &dev_attr_peer_wwpn.attr,
255         &dev_attr_peer_d_id.attr,
256         &dev_attr_physical_wwpn.attr,
257         &dev_attr_physical_s_id.attr,
258         &dev_attr_card_version.attr,
259         &dev_attr_lic_version.attr,
260         &dev_attr_fc_topology.attr,
261         &dev_attr_status.attr,
262         &dev_attr_hardware_version.attr,
263         NULL
264 };
265
266 static struct attribute_group zfcp_adapter_attr_group = {
267         .attrs = zfcp_adapter_attrs,
268 };
269
270 /**
271  * zfcp_sysfs_create_adapter_files - create sysfs adapter files
272  * @dev: pointer to belonging device
273  *
274  * Create all attributes of the sysfs representation of an adapter.
275  */
276 int
277 zfcp_sysfs_adapter_create_files(struct device *dev)
278 {
279         return sysfs_create_group(&dev->kobj, &zfcp_adapter_attr_group);
280 }
281
282 /**
283  * zfcp_sysfs_remove_adapter_files - remove sysfs adapter files
284  * @dev: pointer to belonging device
285  *
286  * Remove all attributes of the sysfs representation of an adapter.
287  */
288 void
289 zfcp_sysfs_adapter_remove_files(struct device *dev)
290 {
291         sysfs_remove_group(&dev->kobj, &zfcp_adapter_attr_group);
292 }
293
294 #undef ZFCP_LOG_AREA