[SCSI] zfcp: Cleanup of code in zfcp_scsi.c
[safe/jmp/linux-2.6] / drivers / s390 / scsi / zfcp_sysfs_port.c
1 /*
2  * zfcp device driver
3  *
4  * sysfs attributes for zfcp port.
5  *
6  * Copyright IBM Corporation 2002, 2008
7  */
8
9 #include "zfcp_ext.h"
10
11 /**
12  * zfcp_sysfs_port_release - gets called when a struct device port is released
13  * @dev: pointer to belonging device
14  */
15 void
16 zfcp_sysfs_port_release(struct device *dev)
17 {
18         kfree(dev);
19 }
20
21 /**
22  * ZFCP_DEFINE_PORT_ATTR
23  * @_name:   name of show attribute
24  * @_format: format string
25  * @_value:  value to print
26  *
27  * Generates attributes for a port.
28  */
29 #define ZFCP_DEFINE_PORT_ATTR(_name, _format, _value)                    \
30 static ssize_t zfcp_sysfs_port_##_name##_show(struct device *dev, struct device_attribute *attr,        \
31                                               char *buf)                 \
32 {                                                                        \
33         struct zfcp_port *port;                                          \
34                                                                          \
35         port = dev_get_drvdata(dev);                                     \
36         return sprintf(buf, _format, _value);                            \
37 }                                                                        \
38                                                                          \
39 static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_port_##_name##_show, NULL);
40
41 ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status));
42 ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask
43                       (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status));
44 ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask
45                       (ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status));
46
47 /**
48  * zfcp_sysfs_unit_add_store - add a unit to sysfs tree
49  * @dev: pointer to belonging device
50  * @buf: pointer to input buffer
51  * @count: number of bytes in buffer
52  *
53  * Store function of the "unit_add" attribute of a port.
54  */
55 static ssize_t
56 zfcp_sysfs_unit_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
57 {
58         fcp_lun_t fcp_lun;
59         char *endp;
60         struct zfcp_port *port;
61         struct zfcp_unit *unit;
62         int retval = -EINVAL;
63
64         down(&zfcp_data.config_sema);
65
66         port = dev_get_drvdata(dev);
67         if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) {
68                 retval = -EBUSY;
69                 goto out;
70         }
71
72         fcp_lun = simple_strtoull(buf, &endp, 0);
73         if ((endp + 1) < (buf + count))
74                 goto out;
75
76         unit = zfcp_unit_enqueue(port, fcp_lun);
77         if (!unit)
78                 goto out;
79
80         retval = 0;
81
82         zfcp_erp_unit_reopen(unit, 0, 94, NULL);
83         zfcp_erp_wait(unit->port->adapter);
84         zfcp_unit_put(unit);
85  out:
86         up(&zfcp_data.config_sema);
87         return retval ? retval : (ssize_t) count;
88 }
89
90 static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store);
91
92 /**
93  * zfcp_sysfs_unit_remove_store - remove a unit from sysfs tree
94  * @dev: pointer to belonging device
95  * @buf: pointer to input buffer
96  * @count: number of bytes in buffer
97  */
98 static ssize_t
99 zfcp_sysfs_unit_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
100 {
101         struct zfcp_port *port;
102         struct zfcp_unit *unit;
103         fcp_lun_t fcp_lun;
104         char *endp;
105         int retval = 0;
106
107         down(&zfcp_data.config_sema);
108
109         port = dev_get_drvdata(dev);
110         if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) {
111                 retval = -EBUSY;
112                 goto out;
113         }
114
115         fcp_lun = simple_strtoull(buf, &endp, 0);
116         if ((endp + 1) < (buf + count)) {
117                 retval = -EINVAL;
118                 goto out;
119         }
120
121         write_lock_irq(&zfcp_data.config_lock);
122         unit = zfcp_get_unit_by_lun(port, fcp_lun);
123         if (unit && (atomic_read(&unit->refcount) == 0)) {
124                 zfcp_unit_get(unit);
125                 atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
126                 list_move(&unit->list, &port->unit_remove_lh);
127         }
128         else {
129                 unit = NULL;
130         }
131         write_unlock_irq(&zfcp_data.config_lock);
132
133         if (!unit) {
134                 retval = -ENXIO;
135                 goto out;
136         }
137
138         zfcp_erp_unit_shutdown(unit, 0, 95, NULL);
139         zfcp_erp_wait(unit->port->adapter);
140         zfcp_unit_put(unit);
141         zfcp_unit_dequeue(unit);
142  out:
143         up(&zfcp_data.config_sema);
144         return retval ? retval : (ssize_t) count;
145 }
146
147 static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
148
149 /**
150  * zfcp_sysfs_port_failed_store - failed state of port
151  * @dev: pointer to belonging device
152  * @buf: pointer to input buffer
153  * @count: number of bytes in buffer
154  *
155  * Store function of the "failed" attribute of a port.
156  * If a "0" gets written to "failed", error recovery will be
157  * started for the belonging port.
158  */
159 static ssize_t
160 zfcp_sysfs_port_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
161 {
162         struct zfcp_port *port;
163         unsigned int val;
164         char *endp;
165         int retval = 0;
166
167         down(&zfcp_data.config_sema);
168
169         port = dev_get_drvdata(dev);
170         if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) {
171                 retval = -EBUSY;
172                 goto out;
173         }
174
175         val = simple_strtoul(buf, &endp, 0);
176         if (((endp + 1) < (buf + count)) || (val != 0)) {
177                 retval = -EINVAL;
178                 goto out;
179         }
180
181         zfcp_erp_modify_port_status(port, 45, NULL,
182                                     ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
183         zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, 96, NULL);
184         zfcp_erp_wait(port->adapter);
185  out:
186         up(&zfcp_data.config_sema);
187         return retval ? retval : (ssize_t) count;
188 }
189
190 /**
191  * zfcp_sysfs_port_failed_show - failed state of port
192  * @dev: pointer to belonging device
193  * @buf: pointer to input buffer
194  *
195  * Show function of "failed" attribute of port. Will be
196  * "0" if port is working, otherwise "1".
197  */
198 static ssize_t
199 zfcp_sysfs_port_failed_show(struct device *dev, struct device_attribute *attr, char *buf)
200 {
201         struct zfcp_port *port;
202
203         port = dev_get_drvdata(dev);
204         if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status))
205                 return sprintf(buf, "1\n");
206         else
207                 return sprintf(buf, "0\n");
208 }
209
210 static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_port_failed_show,
211                    zfcp_sysfs_port_failed_store);
212
213 /**
214  * zfcp_port_common_attrs
215  * sysfs attributes that are common for all kind of fc ports.
216  */
217 static struct attribute *zfcp_port_common_attrs[] = {
218         &dev_attr_failed.attr,
219         &dev_attr_in_recovery.attr,
220         &dev_attr_status.attr,
221         &dev_attr_access_denied.attr,
222         NULL
223 };
224
225 static struct attribute_group zfcp_port_common_attr_group = {
226         .attrs = zfcp_port_common_attrs,
227 };
228
229 /**
230  * zfcp_port_no_ns_attrs
231  * sysfs attributes not to be used for nameserver ports.
232  */
233 static struct attribute *zfcp_port_no_ns_attrs[] = {
234         &dev_attr_unit_add.attr,
235         &dev_attr_unit_remove.attr,
236         NULL
237 };
238
239 static struct attribute_group zfcp_port_no_ns_attr_group = {
240         .attrs = zfcp_port_no_ns_attrs,
241 };
242
243 /**
244  * zfcp_sysfs_port_create_files - create sysfs port files
245  * @dev: pointer to belonging device
246  *
247  * Create all attributes of the sysfs representation of a port.
248  */
249 int
250 zfcp_sysfs_port_create_files(struct device *dev, u32 flags)
251 {
252         int retval;
253
254         retval = sysfs_create_group(&dev->kobj, &zfcp_port_common_attr_group);
255
256         if ((flags & ZFCP_STATUS_PORT_WKA) || retval)
257                 return retval;
258
259         retval = sysfs_create_group(&dev->kobj, &zfcp_port_no_ns_attr_group);
260         if (retval)
261                 sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group);
262
263         return retval;
264 }
265
266 /**
267  * zfcp_sysfs_port_remove_files - remove sysfs port files
268  * @dev: pointer to belonging device
269  *
270  * Remove all attributes of the sysfs representation of a port.
271  */
272 void
273 zfcp_sysfs_port_remove_files(struct device *dev, u32 flags)
274 {
275         sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group);
276         if (!(flags & ZFCP_STATUS_PORT_WKA))
277                 sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group);
278 }