[SCSI] zfcp: Adapter reopen for large number of unsolicited status
[linux-2.6] / drivers / s390 / scsi / zfcp_sysfs_adapter.c
1 /*
2  * zfcp device driver
3  *
4  * sysfs attributes for CCW device.
5  *
6  * Copyright IBM Corporation 2002, 2008
7  */
8
9 #include "zfcp_ext.h"
10
11 /**
12  * ZFCP_DEFINE_ADAPTER_ATTR
13  * @_name:   name of show attribute
14  * @_format: format string
15  * @_value:  value to print
16  *
17  * Generates attributes for an adapter.
18  */
19 #define ZFCP_DEFINE_ADAPTER_ATTR(_name, _format, _value)                      \
20 static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, struct device_attribute *attr,          \
21                                                  char *buf)                   \
22 {                                                                             \
23         struct zfcp_adapter *adapter;                                         \
24                                                                               \
25         adapter = dev_get_drvdata(dev);                                       \
26         return sprintf(buf, _format, _value);                                 \
27 }                                                                             \
28                                                                               \
29 static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL);
30
31 ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x\n", atomic_read(&adapter->status));
32 ZFCP_DEFINE_ADAPTER_ATTR(peer_wwnn, "0x%016llx\n", adapter->peer_wwnn);
33 ZFCP_DEFINE_ADAPTER_ATTR(peer_wwpn, "0x%016llx\n", adapter->peer_wwpn);
34 ZFCP_DEFINE_ADAPTER_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id);
35 ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
36 ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
37 ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n",
38                          adapter->hardware_version);
39 ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask
40                          (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status));
41
42 /**
43  * zfcp_sysfs_port_rescan - trigger manual port rescan
44  * @dev: pointer to belonging device
45  * @attr: pointer to struct device_attribute
46  * @buf: pointer to input buffer
47  * @count: number of bytes in buffer
48  */
49 static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
50                                             struct device_attribute *attr,
51                                             const char *buf, size_t count)
52 {
53         struct zfcp_adapter *adapter;
54         int ret;
55
56         adapter = dev_get_drvdata(dev);
57         if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status))
58                 return -EBUSY;
59
60         ret = zfcp_scan_ports(adapter);
61
62         return ret ? ret : (ssize_t) count;
63 }
64 static DEVICE_ATTR(port_rescan, S_IWUSR, NULL, zfcp_sysfs_port_rescan_store);
65
66 /**
67  * zfcp_sysfs_port_remove_store - remove a port from sysfs tree
68  * @dev: pointer to belonging device
69  * @buf: pointer to input buffer
70  * @count: number of bytes in buffer
71  *
72  * Store function of the "port_remove" attribute of an adapter.
73  */
74 static ssize_t
75 zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
76 {
77         struct zfcp_adapter *adapter;
78         struct zfcp_port *port;
79         wwn_t wwpn;
80         char *endp;
81         int retval = 0;
82
83         down(&zfcp_data.config_sema);
84
85         adapter = dev_get_drvdata(dev);
86         if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) {
87                 retval = -EBUSY;
88                 goto out;
89         }
90
91         wwpn = simple_strtoull(buf, &endp, 0);
92         if ((endp + 1) < (buf + count)) {
93                 retval = -EINVAL;
94                 goto out;
95         }
96
97         write_lock_irq(&zfcp_data.config_lock);
98         port = zfcp_get_port_by_wwpn(adapter, wwpn);
99         if (port && (atomic_read(&port->refcount) == 0)) {
100                 zfcp_port_get(port);
101                 atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
102                 list_move(&port->list, &adapter->port_remove_lh);
103         }
104         else {
105                 port = NULL;
106         }
107         write_unlock_irq(&zfcp_data.config_lock);
108
109         if (!port) {
110                 retval = -ENXIO;
111                 goto out;
112         }
113
114         zfcp_erp_port_shutdown(port, 0, 92, NULL);
115         zfcp_erp_wait(adapter);
116         zfcp_port_put(port);
117         zfcp_port_dequeue(port);
118  out:
119         up(&zfcp_data.config_sema);
120         return retval ? retval : (ssize_t) count;
121 }
122
123 static DEVICE_ATTR(port_remove, S_IWUSR, NULL, zfcp_sysfs_port_remove_store);
124
125 /**
126  * zfcp_sysfs_adapter_failed_store - failed state of adapter
127  * @dev: pointer to belonging device
128  * @buf: pointer to input buffer
129  * @count: number of bytes in buffer
130  *
131  * Store function of the "failed" attribute of an adapter.
132  * If a "0" gets written to "failed", error recovery will be
133  * started for the belonging adapter.
134  */
135 static ssize_t
136 zfcp_sysfs_adapter_failed_store(struct device *dev, struct device_attribute *attr,
137                                 const char *buf, size_t count)
138 {
139         struct zfcp_adapter *adapter;
140         unsigned int val;
141         char *endp;
142         int retval = 0;
143
144         down(&zfcp_data.config_sema);
145
146         adapter = dev_get_drvdata(dev);
147         if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) {
148                 retval = -EBUSY;
149                 goto out;
150         }
151
152         val = simple_strtoul(buf, &endp, 0);
153         if (((endp + 1) < (buf + count)) || (val != 0)) {
154                 retval = -EINVAL;
155                 goto out;
156         }
157
158         zfcp_erp_modify_adapter_status(adapter, 44, NULL,
159                                        ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
160         zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 93,
161                                 NULL);
162         zfcp_erp_wait(adapter);
163  out:
164         up(&zfcp_data.config_sema);
165         return retval ? retval : (ssize_t) count;
166 }
167
168 /**
169  * zfcp_sysfs_adapter_failed_show - failed state of adapter
170  * @dev: pointer to belonging device
171  * @buf: pointer to input buffer
172  *
173  * Show function of "failed" attribute of adapter. Will be
174  * "0" if adapter is working, otherwise "1".
175  */
176 static ssize_t
177 zfcp_sysfs_adapter_failed_show(struct device *dev, struct device_attribute *attr, char *buf)
178 {
179         struct zfcp_adapter *adapter;
180
181         adapter = dev_get_drvdata(dev);
182         if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status))
183                 return sprintf(buf, "1\n");
184         else
185                 return sprintf(buf, "0\n");
186 }
187
188 static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_adapter_failed_show,
189                    zfcp_sysfs_adapter_failed_store);
190
191 static struct attribute *zfcp_adapter_attrs[] = {
192         &dev_attr_failed.attr,
193         &dev_attr_in_recovery.attr,
194         &dev_attr_port_remove.attr,
195         &dev_attr_port_rescan.attr,
196         &dev_attr_peer_wwnn.attr,
197         &dev_attr_peer_wwpn.attr,
198         &dev_attr_peer_d_id.attr,
199         &dev_attr_card_version.attr,
200         &dev_attr_lic_version.attr,
201         &dev_attr_status.attr,
202         &dev_attr_hardware_version.attr,
203         NULL
204 };
205
206 static struct attribute_group zfcp_adapter_attr_group = {
207         .attrs = zfcp_adapter_attrs,
208 };
209
210 /**
211  * zfcp_sysfs_create_adapter_files - create sysfs adapter files
212  * @dev: pointer to belonging device
213  *
214  * Create all attributes of the sysfs representation of an adapter.
215  */
216 int
217 zfcp_sysfs_adapter_create_files(struct device *dev)
218 {
219         return sysfs_create_group(&dev->kobj, &zfcp_adapter_attr_group);
220 }
221
222 /**
223  * zfcp_sysfs_remove_adapter_files - remove sysfs adapter files
224  * @dev: pointer to belonging device
225  *
226  * Remove all attributes of the sysfs representation of an adapter.
227  */
228 void
229 zfcp_sysfs_adapter_remove_files(struct device *dev)
230 {
231         sysfs_remove_group(&dev->kobj, &zfcp_adapter_attr_group);
232 }