diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_sysfs.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 250 |
1 files changed, 143 insertions, 107 deletions
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index d31000886ca8..f539e006683c 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * sysfs attributes. | 4 | * sysfs attributes. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2008 | 6 | * Copyright IBM Corporation 2008, 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define KMSG_COMPONENT "zfcp" | 9 | #define KMSG_COMPONENT "zfcp" |
@@ -19,30 +19,44 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \ | |||
19 | struct device_attribute *at,\ | 19 | struct device_attribute *at,\ |
20 | char *buf) \ | 20 | char *buf) \ |
21 | { \ | 21 | { \ |
22 | struct _feat_def *_feat = dev_get_drvdata(dev); \ | 22 | struct _feat_def *_feat = container_of(dev, struct _feat_def, \ |
23 | sysfs_device); \ | ||
23 | \ | 24 | \ |
24 | return sprintf(buf, _format, _value); \ | 25 | return sprintf(buf, _format, _value); \ |
25 | } \ | 26 | } \ |
26 | static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \ | 27 | static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \ |
27 | zfcp_sysfs_##_feat##_##_name##_show, NULL); | 28 | zfcp_sysfs_##_feat##_##_name##_show, NULL); |
28 | 29 | ||
29 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, status, "0x%08x\n", | 30 | #define ZFCP_DEFINE_A_ATTR(_name, _format, _value) \ |
30 | atomic_read(&adapter->status)); | 31 | static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \ |
31 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwnn, "0x%016llx\n", | 32 | struct device_attribute *at,\ |
32 | (unsigned long long) adapter->peer_wwnn); | 33 | char *buf) \ |
33 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwpn, "0x%016llx\n", | 34 | { \ |
34 | (unsigned long long) adapter->peer_wwpn); | 35 | struct ccw_device *cdev = to_ccwdev(dev); \ |
35 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_d_id, "0x%06x\n", | 36 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); \ |
36 | adapter->peer_d_id); | 37 | int i; \ |
37 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, card_version, "0x%04x\n", | 38 | \ |
38 | adapter->hydra_version); | 39 | if (!adapter) \ |
39 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, lic_version, "0x%08x\n", | 40 | return -ENODEV; \ |
40 | adapter->fsf_lic_version); | 41 | \ |
41 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, hardware_version, "0x%08x\n", | 42 | i = sprintf(buf, _format, _value); \ |
42 | adapter->hardware_version); | 43 | zfcp_ccw_adapter_put(adapter); \ |
43 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, in_recovery, "%d\n", | 44 | return i; \ |
44 | (atomic_read(&adapter->status) & | 45 | } \ |
45 | ZFCP_STATUS_COMMON_ERP_INUSE) != 0); | 46 | static ZFCP_DEV_ATTR(adapter, _name, S_IRUGO, \ |
47 | zfcp_sysfs_adapter_##_name##_show, NULL); | ||
48 | |||
49 | ZFCP_DEFINE_A_ATTR(status, "0x%08x\n", atomic_read(&adapter->status)); | ||
50 | ZFCP_DEFINE_A_ATTR(peer_wwnn, "0x%016llx\n", | ||
51 | (unsigned long long) adapter->peer_wwnn); | ||
52 | ZFCP_DEFINE_A_ATTR(peer_wwpn, "0x%016llx\n", | ||
53 | (unsigned long long) adapter->peer_wwpn); | ||
54 | ZFCP_DEFINE_A_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id); | ||
55 | ZFCP_DEFINE_A_ATTR(card_version, "0x%04x\n", adapter->hydra_version); | ||
56 | ZFCP_DEFINE_A_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version); | ||
57 | ZFCP_DEFINE_A_ATTR(hardware_version, "0x%08x\n", adapter->hardware_version); | ||
58 | ZFCP_DEFINE_A_ATTR(in_recovery, "%d\n", (atomic_read(&adapter->status) & | ||
59 | ZFCP_STATUS_COMMON_ERP_INUSE) != 0); | ||
46 | 60 | ||
47 | ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n", | 61 | ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n", |
48 | atomic_read(&port->status)); | 62 | atomic_read(&port->status)); |
@@ -73,7 +87,8 @@ static ssize_t zfcp_sysfs_##_feat##_failed_show(struct device *dev, \ | |||
73 | struct device_attribute *attr, \ | 87 | struct device_attribute *attr, \ |
74 | char *buf) \ | 88 | char *buf) \ |
75 | { \ | 89 | { \ |
76 | struct _feat_def *_feat = dev_get_drvdata(dev); \ | 90 | struct _feat_def *_feat = container_of(dev, struct _feat_def, \ |
91 | sysfs_device); \ | ||
77 | \ | 92 | \ |
78 | if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \ | 93 | if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \ |
79 | return sprintf(buf, "1\n"); \ | 94 | return sprintf(buf, "1\n"); \ |
@@ -84,15 +99,13 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ | |||
84 | struct device_attribute *attr,\ | 99 | struct device_attribute *attr,\ |
85 | const char *buf, size_t count)\ | 100 | const char *buf, size_t count)\ |
86 | { \ | 101 | { \ |
87 | struct _feat_def *_feat = dev_get_drvdata(dev); \ | 102 | struct _feat_def *_feat = container_of(dev, struct _feat_def, \ |
103 | sysfs_device); \ | ||
88 | unsigned long val; \ | 104 | unsigned long val; \ |
89 | int retval = 0; \ | 105 | int retval = 0; \ |
90 | \ | 106 | \ |
91 | mutex_lock(&zfcp_data.config_mutex); \ | 107 | if (!(_feat && get_device(&_feat->sysfs_device))) \ |
92 | if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \ | 108 | return -EBUSY; \ |
93 | retval = -EBUSY; \ | ||
94 | goto out; \ | ||
95 | } \ | ||
96 | \ | 109 | \ |
97 | if (strict_strtoul(buf, 0, &val) || val != 0) { \ | 110 | if (strict_strtoul(buf, 0, &val) || val != 0) { \ |
98 | retval = -EINVAL; \ | 111 | retval = -EINVAL; \ |
@@ -105,29 +118,82 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ | |||
105 | _reopen_id, NULL); \ | 118 | _reopen_id, NULL); \ |
106 | zfcp_erp_wait(_adapter); \ | 119 | zfcp_erp_wait(_adapter); \ |
107 | out: \ | 120 | out: \ |
108 | mutex_unlock(&zfcp_data.config_mutex); \ | 121 | put_device(&_feat->sysfs_device); \ |
109 | return retval ? retval : (ssize_t) count; \ | 122 | return retval ? retval : (ssize_t) count; \ |
110 | } \ | 123 | } \ |
111 | static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \ | 124 | static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \ |
112 | zfcp_sysfs_##_feat##_failed_show, \ | 125 | zfcp_sysfs_##_feat##_failed_show, \ |
113 | zfcp_sysfs_##_feat##_failed_store); | 126 | zfcp_sysfs_##_feat##_failed_store); |
114 | 127 | ||
115 | ZFCP_SYSFS_FAILED(zfcp_adapter, adapter, adapter, "syafai1", "syafai2"); | ||
116 | ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, "sypfai1", "sypfai2"); | 128 | ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, "sypfai1", "sypfai2"); |
117 | ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, "syufai1", "syufai2"); | 129 | ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, "syufai1", "syufai2"); |
118 | 130 | ||
131 | static ssize_t zfcp_sysfs_adapter_failed_show(struct device *dev, | ||
132 | struct device_attribute *attr, | ||
133 | char *buf) | ||
134 | { | ||
135 | struct ccw_device *cdev = to_ccwdev(dev); | ||
136 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); | ||
137 | int i; | ||
138 | |||
139 | if (!adapter) | ||
140 | return -ENODEV; | ||
141 | |||
142 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
143 | i = sprintf(buf, "1\n"); | ||
144 | else | ||
145 | i = sprintf(buf, "0\n"); | ||
146 | |||
147 | zfcp_ccw_adapter_put(adapter); | ||
148 | return i; | ||
149 | } | ||
150 | |||
151 | static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev, | ||
152 | struct device_attribute *attr, | ||
153 | const char *buf, size_t count) | ||
154 | { | ||
155 | struct ccw_device *cdev = to_ccwdev(dev); | ||
156 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); | ||
157 | unsigned long val; | ||
158 | int retval = 0; | ||
159 | |||
160 | if (!adapter) | ||
161 | return -ENODEV; | ||
162 | |||
163 | if (strict_strtoul(buf, 0, &val) || val != 0) { | ||
164 | retval = -EINVAL; | ||
165 | goto out; | ||
166 | } | ||
167 | |||
168 | zfcp_erp_modify_adapter_status(adapter, "syafai1", NULL, | ||
169 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); | ||
170 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, | ||
171 | "syafai2", NULL); | ||
172 | zfcp_erp_wait(adapter); | ||
173 | out: | ||
174 | zfcp_ccw_adapter_put(adapter); | ||
175 | return retval ? retval : (ssize_t) count; | ||
176 | } | ||
177 | static ZFCP_DEV_ATTR(adapter, failed, S_IWUSR | S_IRUGO, | ||
178 | zfcp_sysfs_adapter_failed_show, | ||
179 | zfcp_sysfs_adapter_failed_store); | ||
180 | |||
119 | static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, | 181 | static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, |
120 | struct device_attribute *attr, | 182 | struct device_attribute *attr, |
121 | const char *buf, size_t count) | 183 | const char *buf, size_t count) |
122 | { | 184 | { |
123 | struct zfcp_adapter *adapter = dev_get_drvdata(dev); | 185 | struct ccw_device *cdev = to_ccwdev(dev); |
124 | int ret; | 186 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
125 | 187 | ||
126 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) | 188 | if (!adapter) |
127 | return -EBUSY; | 189 | return -ENODEV; |
128 | 190 | ||
129 | ret = zfcp_fc_scan_ports(adapter); | 191 | /* sync the user-space- with the kernel-invocation of scan_work */ |
130 | return ret ? ret : (ssize_t) count; | 192 | queue_work(adapter->work_queue, &adapter->scan_work); |
193 | flush_work(&adapter->scan_work); | ||
194 | zfcp_ccw_adapter_put(adapter); | ||
195 | |||
196 | return (ssize_t) count; | ||
131 | } | 197 | } |
132 | static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, | 198 | static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, |
133 | zfcp_sysfs_port_rescan_store); | 199 | zfcp_sysfs_port_rescan_store); |
@@ -136,44 +202,34 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, | |||
136 | struct device_attribute *attr, | 202 | struct device_attribute *attr, |
137 | const char *buf, size_t count) | 203 | const char *buf, size_t count) |
138 | { | 204 | { |
139 | struct zfcp_adapter *adapter = dev_get_drvdata(dev); | 205 | struct ccw_device *cdev = to_ccwdev(dev); |
206 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); | ||
140 | struct zfcp_port *port; | 207 | struct zfcp_port *port; |
141 | u64 wwpn; | 208 | u64 wwpn; |
142 | int retval = 0; | 209 | int retval = -EINVAL; |
143 | LIST_HEAD(port_remove_lh); | ||
144 | 210 | ||
145 | mutex_lock(&zfcp_data.config_mutex); | 211 | if (!adapter) |
146 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { | 212 | return -ENODEV; |
147 | retval = -EBUSY; | ||
148 | goto out; | ||
149 | } | ||
150 | 213 | ||
151 | if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) { | 214 | if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) |
152 | retval = -EINVAL; | ||
153 | goto out; | 215 | goto out; |
154 | } | ||
155 | 216 | ||
156 | write_lock_irq(&zfcp_data.config_lock); | ||
157 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | 217 | port = zfcp_get_port_by_wwpn(adapter, wwpn); |
158 | if (port && (atomic_read(&port->refcount) == 0)) { | 218 | if (!port) |
159 | zfcp_port_get(port); | ||
160 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
161 | list_move(&port->list, &port_remove_lh); | ||
162 | } else | ||
163 | port = NULL; | ||
164 | write_unlock_irq(&zfcp_data.config_lock); | ||
165 | |||
166 | if (!port) { | ||
167 | retval = -ENXIO; | ||
168 | goto out; | 219 | goto out; |
169 | } | 220 | else |
221 | retval = 0; | ||
222 | |||
223 | write_lock_irq(&adapter->port_list_lock); | ||
224 | list_del(&port->list); | ||
225 | write_unlock_irq(&adapter->port_list_lock); | ||
226 | |||
227 | put_device(&port->sysfs_device); | ||
170 | 228 | ||
171 | zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL); | 229 | zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL); |
172 | zfcp_erp_wait(adapter); | 230 | zfcp_device_unregister(&port->sysfs_device, &zfcp_sysfs_port_attrs); |
173 | zfcp_port_put(port); | ||
174 | zfcp_port_dequeue(port); | ||
175 | out: | 231 | out: |
176 | mutex_unlock(&zfcp_data.config_mutex); | 232 | zfcp_ccw_adapter_put(adapter); |
177 | return retval ? retval : (ssize_t) count; | 233 | return retval ? retval : (ssize_t) count; |
178 | } | 234 | } |
179 | static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL, | 235 | static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL, |
@@ -202,16 +258,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, | |||
202 | struct device_attribute *attr, | 258 | struct device_attribute *attr, |
203 | const char *buf, size_t count) | 259 | const char *buf, size_t count) |
204 | { | 260 | { |
205 | struct zfcp_port *port = dev_get_drvdata(dev); | 261 | struct zfcp_port *port = container_of(dev, struct zfcp_port, |
262 | sysfs_device); | ||
206 | struct zfcp_unit *unit; | 263 | struct zfcp_unit *unit; |
207 | u64 fcp_lun; | 264 | u64 fcp_lun; |
208 | int retval = -EINVAL; | 265 | int retval = -EINVAL; |
209 | 266 | ||
210 | mutex_lock(&zfcp_data.config_mutex); | 267 | if (!(port && get_device(&port->sysfs_device))) |
211 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { | 268 | return -EBUSY; |
212 | retval = -EBUSY; | ||
213 | goto out; | ||
214 | } | ||
215 | 269 | ||
216 | if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) | 270 | if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) |
217 | goto out; | 271 | goto out; |
@@ -219,15 +273,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, | |||
219 | unit = zfcp_unit_enqueue(port, fcp_lun); | 273 | unit = zfcp_unit_enqueue(port, fcp_lun); |
220 | if (IS_ERR(unit)) | 274 | if (IS_ERR(unit)) |
221 | goto out; | 275 | goto out; |
222 | 276 | else | |
223 | retval = 0; | 277 | retval = 0; |
224 | 278 | ||
225 | zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); | 279 | zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); |
226 | zfcp_erp_wait(unit->port->adapter); | 280 | zfcp_erp_wait(unit->port->adapter); |
227 | flush_work(&unit->scsi_work); | 281 | flush_work(&unit->scsi_work); |
228 | zfcp_unit_put(unit); | ||
229 | out: | 282 | out: |
230 | mutex_unlock(&zfcp_data.config_mutex); | 283 | put_device(&port->sysfs_device); |
231 | return retval ? retval : (ssize_t) count; | 284 | return retval ? retval : (ssize_t) count; |
232 | } | 285 | } |
233 | static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); | 286 | static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); |
@@ -236,54 +289,37 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, | |||
236 | struct device_attribute *attr, | 289 | struct device_attribute *attr, |
237 | const char *buf, size_t count) | 290 | const char *buf, size_t count) |
238 | { | 291 | { |
239 | struct zfcp_port *port = dev_get_drvdata(dev); | 292 | struct zfcp_port *port = container_of(dev, struct zfcp_port, |
293 | sysfs_device); | ||
240 | struct zfcp_unit *unit; | 294 | struct zfcp_unit *unit; |
241 | u64 fcp_lun; | 295 | u64 fcp_lun; |
242 | int retval = 0; | 296 | int retval = -EINVAL; |
243 | LIST_HEAD(unit_remove_lh); | ||
244 | 297 | ||
245 | mutex_lock(&zfcp_data.config_mutex); | 298 | if (!(port && get_device(&port->sysfs_device))) |
246 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { | 299 | return -EBUSY; |
247 | retval = -EBUSY; | ||
248 | goto out; | ||
249 | } | ||
250 | 300 | ||
251 | if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) { | 301 | if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) |
252 | retval = -EINVAL; | ||
253 | goto out; | 302 | goto out; |
254 | } | ||
255 | 303 | ||
256 | write_lock_irq(&zfcp_data.config_lock); | ||
257 | unit = zfcp_get_unit_by_lun(port, fcp_lun); | 304 | unit = zfcp_get_unit_by_lun(port, fcp_lun); |
258 | if (unit) { | 305 | if (!unit) |
259 | write_unlock_irq(&zfcp_data.config_lock); | 306 | goto out; |
260 | /* wait for possible timeout during SCSI probe */ | 307 | else |
261 | flush_work(&unit->scsi_work); | 308 | retval = 0; |
262 | write_lock_irq(&zfcp_data.config_lock); | ||
263 | |||
264 | if (atomic_read(&unit->refcount) == 0) { | ||
265 | zfcp_unit_get(unit); | ||
266 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, | ||
267 | &unit->status); | ||
268 | list_move(&unit->list, &unit_remove_lh); | ||
269 | } else { | ||
270 | unit = NULL; | ||
271 | } | ||
272 | } | ||
273 | 309 | ||
274 | write_unlock_irq(&zfcp_data.config_lock); | 310 | /* wait for possible timeout during SCSI probe */ |
311 | flush_work(&unit->scsi_work); | ||
275 | 312 | ||
276 | if (!unit) { | 313 | write_lock_irq(&port->unit_list_lock); |
277 | retval = -ENXIO; | 314 | list_del(&unit->list); |
278 | goto out; | 315 | write_unlock_irq(&port->unit_list_lock); |
279 | } | 316 | |
317 | put_device(&unit->sysfs_device); | ||
280 | 318 | ||
281 | zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); | 319 | zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); |
282 | zfcp_erp_wait(unit->port->adapter); | 320 | zfcp_device_unregister(&unit->sysfs_device, &zfcp_sysfs_unit_attrs); |
283 | zfcp_unit_put(unit); | ||
284 | zfcp_unit_dequeue(unit); | ||
285 | out: | 321 | out: |
286 | mutex_unlock(&zfcp_data.config_mutex); | 322 | put_device(&port->sysfs_device); |
287 | return retval ? retval : (ssize_t) count; | 323 | return retval ? retval : (ssize_t) count; |
288 | } | 324 | } |
289 | static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); | 325 | static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); |