diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/s390/scsi/zfcp_aux.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/s390/scsi/zfcp_aux.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 445 |
1 files changed, 205 insertions, 240 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 2889e5f2dfd3..1e6183a86ce5 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Module interface and handling of zfcp data structures. | 4 | * Module interface and handling of zfcp data structures. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2002, 2009 | 6 | * Copyright IBM Corporation 2002, 2010 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
@@ -30,7 +30,10 @@ | |||
30 | 30 | ||
31 | #include <linux/miscdevice.h> | 31 | #include <linux/miscdevice.h> |
32 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
33 | #include <linux/slab.h> | ||
33 | #include "zfcp_ext.h" | 34 | #include "zfcp_ext.h" |
35 | #include "zfcp_fc.h" | ||
36 | #include "zfcp_reqlist.h" | ||
34 | 37 | ||
35 | #define ZFCP_BUS_ID_SIZE 20 | 38 | #define ZFCP_BUS_ID_SIZE 20 |
36 | 39 | ||
@@ -48,80 +51,42 @@ static struct kmem_cache *zfcp_cache_hw_align(const char *name, | |||
48 | return kmem_cache_create(name, size, roundup_pow_of_two(size), 0, NULL); | 51 | return kmem_cache_create(name, size, roundup_pow_of_two(size), 0, NULL); |
49 | } | 52 | } |
50 | 53 | ||
51 | static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) | ||
52 | { | ||
53 | int idx; | ||
54 | |||
55 | adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head), | ||
56 | GFP_KERNEL); | ||
57 | if (!adapter->req_list) | ||
58 | return -ENOMEM; | ||
59 | |||
60 | for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) | ||
61 | INIT_LIST_HEAD(&adapter->req_list[idx]); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * zfcp_reqlist_isempty - is the request list empty | ||
67 | * @adapter: pointer to struct zfcp_adapter | ||
68 | * | ||
69 | * Returns: true if list is empty, false otherwise | ||
70 | */ | ||
71 | int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) | ||
72 | { | ||
73 | unsigned int idx; | ||
74 | |||
75 | for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) | ||
76 | if (!list_empty(&adapter->req_list[idx])) | ||
77 | return 0; | ||
78 | return 1; | ||
79 | } | ||
80 | |||
81 | static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) | 54 | static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) |
82 | { | 55 | { |
83 | struct ccw_device *ccwdev; | 56 | struct ccw_device *cdev; |
84 | struct zfcp_adapter *adapter; | 57 | struct zfcp_adapter *adapter; |
85 | struct zfcp_port *port; | 58 | struct zfcp_port *port; |
86 | struct zfcp_unit *unit; | 59 | struct zfcp_unit *unit; |
87 | 60 | ||
88 | ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); | 61 | cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); |
89 | if (!ccwdev) | 62 | if (!cdev) |
90 | return; | 63 | return; |
91 | 64 | ||
92 | if (ccw_device_set_online(ccwdev)) | 65 | if (ccw_device_set_online(cdev)) |
93 | goto out_ccwdev; | 66 | goto out_ccw_device; |
94 | 67 | ||
95 | mutex_lock(&zfcp_data.config_mutex); | 68 | adapter = zfcp_ccw_adapter_by_cdev(cdev); |
96 | adapter = dev_get_drvdata(&ccwdev->dev); | ||
97 | if (!adapter) | 69 | if (!adapter) |
98 | goto out_unlock; | 70 | goto out_ccw_device; |
99 | zfcp_adapter_get(adapter); | ||
100 | 71 | ||
101 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | 72 | port = zfcp_get_port_by_wwpn(adapter, wwpn); |
102 | if (!port) | 73 | if (!port) |
103 | goto out_port; | 74 | goto out_port; |
104 | 75 | ||
105 | zfcp_port_get(port); | ||
106 | unit = zfcp_unit_enqueue(port, lun); | 76 | unit = zfcp_unit_enqueue(port, lun); |
107 | if (IS_ERR(unit)) | 77 | if (IS_ERR(unit)) |
108 | goto out_unit; | 78 | goto out_unit; |
109 | mutex_unlock(&zfcp_data.config_mutex); | ||
110 | 79 | ||
111 | zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL); | 80 | zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL); |
112 | zfcp_erp_wait(adapter); | 81 | zfcp_erp_wait(adapter); |
113 | flush_work(&unit->scsi_work); | 82 | flush_work(&unit->scsi_work); |
114 | 83 | ||
115 | mutex_lock(&zfcp_data.config_mutex); | ||
116 | zfcp_unit_put(unit); | ||
117 | out_unit: | 84 | out_unit: |
118 | zfcp_port_put(port); | 85 | put_device(&port->dev); |
119 | out_port: | 86 | out_port: |
120 | zfcp_adapter_put(adapter); | 87 | zfcp_ccw_adapter_put(adapter); |
121 | out_unlock: | 88 | out_ccw_device: |
122 | mutex_unlock(&zfcp_data.config_mutex); | 89 | put_device(&cdev->dev); |
123 | out_ccwdev: | ||
124 | put_device(&ccwdev->dev); | ||
125 | return; | 90 | return; |
126 | } | 91 | } |
127 | 92 | ||
@@ -167,7 +132,7 @@ static int __init zfcp_module_init(void) | |||
167 | int retval = -ENOMEM; | 132 | int retval = -ENOMEM; |
168 | 133 | ||
169 | zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn", | 134 | zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn", |
170 | sizeof(struct ct_iu_gpn_ft_req)); | 135 | sizeof(struct zfcp_fc_gpn_ft_req)); |
171 | if (!zfcp_data.gpn_ft_cache) | 136 | if (!zfcp_data.gpn_ft_cache) |
172 | goto out; | 137 | goto out; |
173 | 138 | ||
@@ -182,12 +147,14 @@ static int __init zfcp_module_init(void) | |||
182 | goto out_sr_cache; | 147 | goto out_sr_cache; |
183 | 148 | ||
184 | zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid", | 149 | zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid", |
185 | sizeof(struct zfcp_gid_pn_data)); | 150 | sizeof(struct zfcp_fc_gid_pn)); |
186 | if (!zfcp_data.gid_pn_cache) | 151 | if (!zfcp_data.gid_pn_cache) |
187 | goto out_gid_cache; | 152 | goto out_gid_cache; |
188 | 153 | ||
189 | mutex_init(&zfcp_data.config_mutex); | 154 | zfcp_data.adisc_cache = zfcp_cache_hw_align("zfcp_adisc", |
190 | rwlock_init(&zfcp_data.config_lock); | 155 | sizeof(struct zfcp_fc_els_adisc)); |
156 | if (!zfcp_data.adisc_cache) | ||
157 | goto out_adisc_cache; | ||
191 | 158 | ||
192 | zfcp_data.scsi_transport_template = | 159 | zfcp_data.scsi_transport_template = |
193 | fc_attach_transport(&zfcp_transport_functions); | 160 | fc_attach_transport(&zfcp_transport_functions); |
@@ -200,7 +167,7 @@ static int __init zfcp_module_init(void) | |||
200 | goto out_misc; | 167 | goto out_misc; |
201 | } | 168 | } |
202 | 169 | ||
203 | retval = zfcp_ccw_register(); | 170 | retval = ccw_driver_register(&zfcp_ccw_driver); |
204 | if (retval) { | 171 | if (retval) { |
205 | pr_err("The zfcp device driver could not register with " | 172 | pr_err("The zfcp device driver could not register with " |
206 | "the common I/O layer\n"); | 173 | "the common I/O layer\n"); |
@@ -216,6 +183,8 @@ out_ccw_register: | |||
216 | out_misc: | 183 | out_misc: |
217 | fc_release_transport(zfcp_data.scsi_transport_template); | 184 | fc_release_transport(zfcp_data.scsi_transport_template); |
218 | out_transport: | 185 | out_transport: |
186 | kmem_cache_destroy(zfcp_data.adisc_cache); | ||
187 | out_adisc_cache: | ||
219 | kmem_cache_destroy(zfcp_data.gid_pn_cache); | 188 | kmem_cache_destroy(zfcp_data.gid_pn_cache); |
220 | out_gid_cache: | 189 | out_gid_cache: |
221 | kmem_cache_destroy(zfcp_data.sr_buffer_cache); | 190 | kmem_cache_destroy(zfcp_data.sr_buffer_cache); |
@@ -229,6 +198,20 @@ out: | |||
229 | 198 | ||
230 | module_init(zfcp_module_init); | 199 | module_init(zfcp_module_init); |
231 | 200 | ||
201 | static void __exit zfcp_module_exit(void) | ||
202 | { | ||
203 | ccw_driver_unregister(&zfcp_ccw_driver); | ||
204 | misc_deregister(&zfcp_cfdc_misc); | ||
205 | fc_release_transport(zfcp_data.scsi_transport_template); | ||
206 | kmem_cache_destroy(zfcp_data.adisc_cache); | ||
207 | kmem_cache_destroy(zfcp_data.gid_pn_cache); | ||
208 | kmem_cache_destroy(zfcp_data.sr_buffer_cache); | ||
209 | kmem_cache_destroy(zfcp_data.qtcb_cache); | ||
210 | kmem_cache_destroy(zfcp_data.gpn_ft_cache); | ||
211 | } | ||
212 | |||
213 | module_exit(zfcp_module_exit); | ||
214 | |||
232 | /** | 215 | /** |
233 | * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN | 216 | * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN |
234 | * @port: pointer to port to search for unit | 217 | * @port: pointer to port to search for unit |
@@ -238,12 +221,18 @@ module_init(zfcp_module_init); | |||
238 | */ | 221 | */ |
239 | struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) | 222 | struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) |
240 | { | 223 | { |
224 | unsigned long flags; | ||
241 | struct zfcp_unit *unit; | 225 | struct zfcp_unit *unit; |
242 | 226 | ||
243 | list_for_each_entry(unit, &port->unit_list_head, list) | 227 | read_lock_irqsave(&port->unit_list_lock, flags); |
244 | if ((unit->fcp_lun == fcp_lun) && | 228 | list_for_each_entry(unit, &port->unit_list, list) |
245 | !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) | 229 | if (unit->fcp_lun == fcp_lun) { |
246 | return unit; | 230 | if (!get_device(&unit->dev)) |
231 | unit = NULL; | ||
232 | read_unlock_irqrestore(&port->unit_list_lock, flags); | ||
233 | return unit; | ||
234 | } | ||
235 | read_unlock_irqrestore(&port->unit_list_lock, flags); | ||
247 | return NULL; | 236 | return NULL; |
248 | } | 237 | } |
249 | 238 | ||
@@ -257,18 +246,34 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) | |||
257 | struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, | 246 | struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, |
258 | u64 wwpn) | 247 | u64 wwpn) |
259 | { | 248 | { |
249 | unsigned long flags; | ||
260 | struct zfcp_port *port; | 250 | struct zfcp_port *port; |
261 | 251 | ||
262 | list_for_each_entry(port, &adapter->port_list_head, list) | 252 | read_lock_irqsave(&adapter->port_list_lock, flags); |
263 | if ((port->wwpn == wwpn) && | 253 | list_for_each_entry(port, &adapter->port_list, list) |
264 | !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE)) | 254 | if (port->wwpn == wwpn) { |
255 | if (!get_device(&port->dev)) | ||
256 | port = NULL; | ||
257 | read_unlock_irqrestore(&adapter->port_list_lock, flags); | ||
265 | return port; | 258 | return port; |
259 | } | ||
260 | read_unlock_irqrestore(&adapter->port_list_lock, flags); | ||
266 | return NULL; | 261 | return NULL; |
267 | } | 262 | } |
268 | 263 | ||
269 | static void zfcp_sysfs_unit_release(struct device *dev) | 264 | /** |
265 | * zfcp_unit_release - dequeue unit | ||
266 | * @dev: pointer to device | ||
267 | * | ||
268 | * waits until all work is done on unit and removes it then from the unit->list | ||
269 | * of the associated port. | ||
270 | */ | ||
271 | static void zfcp_unit_release(struct device *dev) | ||
270 | { | 272 | { |
271 | kfree(container_of(dev, struct zfcp_unit, sysfs_device)); | 273 | struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); |
274 | |||
275 | put_device(&unit->port->dev); | ||
276 | kfree(unit); | ||
272 | } | 277 | } |
273 | 278 | ||
274 | /** | 279 | /** |
@@ -276,43 +281,40 @@ static void zfcp_sysfs_unit_release(struct device *dev) | |||
276 | * @port: pointer to port where unit is added | 281 | * @port: pointer to port where unit is added |
277 | * @fcp_lun: FCP LUN of unit to be enqueued | 282 | * @fcp_lun: FCP LUN of unit to be enqueued |
278 | * Returns: pointer to enqueued unit on success, ERR_PTR on error | 283 | * Returns: pointer to enqueued unit on success, ERR_PTR on error |
279 | * Locks: config_mutex must be held to serialize changes to the unit list | ||
280 | * | 284 | * |
281 | * Sets up some unit internal structures and creates sysfs entry. | 285 | * Sets up some unit internal structures and creates sysfs entry. |
282 | */ | 286 | */ |
283 | struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) | 287 | struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) |
284 | { | 288 | { |
285 | struct zfcp_unit *unit; | 289 | struct zfcp_unit *unit; |
290 | int retval = -ENOMEM; | ||
291 | |||
292 | get_device(&port->dev); | ||
286 | 293 | ||
287 | read_lock_irq(&zfcp_data.config_lock); | 294 | unit = zfcp_get_unit_by_lun(port, fcp_lun); |
288 | if (zfcp_get_unit_by_lun(port, fcp_lun)) { | 295 | if (unit) { |
289 | read_unlock_irq(&zfcp_data.config_lock); | 296 | put_device(&unit->dev); |
290 | return ERR_PTR(-EINVAL); | 297 | retval = -EEXIST; |
298 | goto err_out; | ||
291 | } | 299 | } |
292 | read_unlock_irq(&zfcp_data.config_lock); | ||
293 | 300 | ||
294 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); | 301 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); |
295 | if (!unit) | 302 | if (!unit) |
296 | return ERR_PTR(-ENOMEM); | 303 | goto err_out; |
297 | |||
298 | atomic_set(&unit->refcount, 0); | ||
299 | init_waitqueue_head(&unit->remove_wq); | ||
300 | INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); | ||
301 | 304 | ||
302 | unit->port = port; | 305 | unit->port = port; |
303 | unit->fcp_lun = fcp_lun; | 306 | unit->fcp_lun = fcp_lun; |
307 | unit->dev.parent = &port->dev; | ||
308 | unit->dev.release = zfcp_unit_release; | ||
304 | 309 | ||
305 | if (dev_set_name(&unit->sysfs_device, "0x%016llx", | 310 | if (dev_set_name(&unit->dev, "0x%016llx", |
306 | (unsigned long long) fcp_lun)) { | 311 | (unsigned long long) fcp_lun)) { |
307 | kfree(unit); | 312 | kfree(unit); |
308 | return ERR_PTR(-ENOMEM); | 313 | goto err_out; |
309 | } | 314 | } |
310 | unit->sysfs_device.parent = &port->sysfs_device; | 315 | retval = -EINVAL; |
311 | unit->sysfs_device.release = zfcp_sysfs_unit_release; | ||
312 | dev_set_drvdata(&unit->sysfs_device, unit); | ||
313 | 316 | ||
314 | /* mark unit unusable as long as sysfs registration is not complete */ | 317 | INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); |
315 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | ||
316 | 318 | ||
317 | spin_lock_init(&unit->latencies.lock); | 319 | spin_lock_init(&unit->latencies.lock); |
318 | unit->latencies.write.channel.min = 0xFFFFFFFF; | 320 | unit->latencies.write.channel.min = 0xFFFFFFFF; |
@@ -322,52 +324,31 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) | |||
322 | unit->latencies.cmd.channel.min = 0xFFFFFFFF; | 324 | unit->latencies.cmd.channel.min = 0xFFFFFFFF; |
323 | unit->latencies.cmd.fabric.min = 0xFFFFFFFF; | 325 | unit->latencies.cmd.fabric.min = 0xFFFFFFFF; |
324 | 326 | ||
325 | if (device_register(&unit->sysfs_device)) { | 327 | if (device_register(&unit->dev)) { |
326 | put_device(&unit->sysfs_device); | 328 | put_device(&unit->dev); |
327 | return ERR_PTR(-EINVAL); | 329 | goto err_out; |
328 | } | 330 | } |
329 | 331 | ||
330 | if (sysfs_create_group(&unit->sysfs_device.kobj, | 332 | if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) |
331 | &zfcp_sysfs_unit_attrs)) { | 333 | goto err_out_put; |
332 | device_unregister(&unit->sysfs_device); | ||
333 | return ERR_PTR(-EINVAL); | ||
334 | } | ||
335 | 334 | ||
336 | zfcp_unit_get(unit); | 335 | write_lock_irq(&port->unit_list_lock); |
336 | list_add_tail(&unit->list, &port->unit_list); | ||
337 | write_unlock_irq(&port->unit_list_lock); | ||
337 | 338 | ||
338 | write_lock_irq(&zfcp_data.config_lock); | ||
339 | list_add_tail(&unit->list, &port->unit_list_head); | ||
340 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | ||
341 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); | 339 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); |
342 | 340 | ||
343 | write_unlock_irq(&zfcp_data.config_lock); | ||
344 | |||
345 | zfcp_port_get(port); | ||
346 | |||
347 | return unit; | 341 | return unit; |
348 | } | ||
349 | 342 | ||
350 | /** | 343 | err_out_put: |
351 | * zfcp_unit_dequeue - dequeue unit | 344 | device_unregister(&unit->dev); |
352 | * @unit: pointer to zfcp_unit | 345 | err_out: |
353 | * | 346 | put_device(&port->dev); |
354 | * waits until all work is done on unit and removes it then from the unit->list | 347 | return ERR_PTR(retval); |
355 | * of the associated port. | ||
356 | */ | ||
357 | void zfcp_unit_dequeue(struct zfcp_unit *unit) | ||
358 | { | ||
359 | wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0); | ||
360 | write_lock_irq(&zfcp_data.config_lock); | ||
361 | list_del(&unit->list); | ||
362 | write_unlock_irq(&zfcp_data.config_lock); | ||
363 | zfcp_port_put(unit->port); | ||
364 | sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); | ||
365 | device_unregister(&unit->sysfs_device); | ||
366 | } | 348 | } |
367 | 349 | ||
368 | static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) | 350 | static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) |
369 | { | 351 | { |
370 | /* must only be called with zfcp_data.config_mutex taken */ | ||
371 | adapter->pool.erp_req = | 352 | adapter->pool.erp_req = |
372 | mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); | 353 | mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); |
373 | if (!adapter->pool.erp_req) | 354 | if (!adapter->pool.erp_req) |
@@ -405,9 +386,9 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) | |||
405 | if (!adapter->pool.status_read_data) | 386 | if (!adapter->pool.status_read_data) |
406 | return -ENOMEM; | 387 | return -ENOMEM; |
407 | 388 | ||
408 | adapter->pool.gid_pn_data = | 389 | adapter->pool.gid_pn = |
409 | mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); | 390 | mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); |
410 | if (!adapter->pool.gid_pn_data) | 391 | if (!adapter->pool.gid_pn) |
411 | return -ENOMEM; | 392 | return -ENOMEM; |
412 | 393 | ||
413 | return 0; | 394 | return 0; |
@@ -415,7 +396,6 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) | |||
415 | 396 | ||
416 | static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) | 397 | static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) |
417 | { | 398 | { |
418 | /* zfcp_data.config_mutex must be held */ | ||
419 | if (adapter->pool.erp_req) | 399 | if (adapter->pool.erp_req) |
420 | mempool_destroy(adapter->pool.erp_req); | 400 | mempool_destroy(adapter->pool.erp_req); |
421 | if (adapter->pool.scsi_req) | 401 | if (adapter->pool.scsi_req) |
@@ -428,8 +408,8 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) | |||
428 | mempool_destroy(adapter->pool.status_read_req); | 408 | mempool_destroy(adapter->pool.status_read_req); |
429 | if (adapter->pool.status_read_data) | 409 | if (adapter->pool.status_read_data) |
430 | mempool_destroy(adapter->pool.status_read_data); | 410 | mempool_destroy(adapter->pool.status_read_data); |
431 | if (adapter->pool.gid_pn_data) | 411 | if (adapter->pool.gid_pn) |
432 | mempool_destroy(adapter->pool.gid_pn_data); | 412 | mempool_destroy(adapter->pool.gid_pn); |
433 | } | 413 | } |
434 | 414 | ||
435 | /** | 415 | /** |
@@ -497,139 +477,142 @@ static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter) | |||
497 | * zfcp_adapter_enqueue - enqueue a new adapter to the list | 477 | * zfcp_adapter_enqueue - enqueue a new adapter to the list |
498 | * @ccw_device: pointer to the struct cc_device | 478 | * @ccw_device: pointer to the struct cc_device |
499 | * | 479 | * |
500 | * Returns: 0 if a new adapter was successfully enqueued | 480 | * Returns: struct zfcp_adapter* |
501 | * -ENOMEM if alloc failed | ||
502 | * Enqueues an adapter at the end of the adapter list in the driver data. | 481 | * Enqueues an adapter at the end of the adapter list in the driver data. |
503 | * All adapter internal structures are set up. | 482 | * All adapter internal structures are set up. |
504 | * Proc-fs entries are also created. | 483 | * Proc-fs entries are also created. |
505 | * locks: config_mutex must be held to serialize changes to the adapter list | ||
506 | */ | 484 | */ |
507 | int zfcp_adapter_enqueue(struct ccw_device *ccw_device) | 485 | struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) |
508 | { | 486 | { |
509 | struct zfcp_adapter *adapter; | 487 | struct zfcp_adapter *adapter; |
510 | 488 | ||
511 | /* | 489 | if (!get_device(&ccw_device->dev)) |
512 | * Note: It is safe to release the list_lock, as any list changes | 490 | return ERR_PTR(-ENODEV); |
513 | * are protected by the config_mutex, which must be held to get here | ||
514 | */ | ||
515 | 491 | ||
516 | adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); | 492 | adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); |
517 | if (!adapter) | 493 | if (!adapter) { |
518 | return -ENOMEM; | 494 | put_device(&ccw_device->dev); |
495 | return ERR_PTR(-ENOMEM); | ||
496 | } | ||
497 | |||
498 | kref_init(&adapter->ref); | ||
519 | 499 | ||
520 | ccw_device->handler = NULL; | 500 | ccw_device->handler = NULL; |
521 | adapter->ccw_device = ccw_device; | 501 | adapter->ccw_device = ccw_device; |
522 | atomic_set(&adapter->refcount, 0); | 502 | |
503 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); | ||
504 | INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports); | ||
523 | 505 | ||
524 | if (zfcp_qdio_setup(adapter)) | 506 | if (zfcp_qdio_setup(adapter)) |
525 | goto qdio_failed; | 507 | goto failed; |
526 | 508 | ||
527 | if (zfcp_allocate_low_mem_buffers(adapter)) | 509 | if (zfcp_allocate_low_mem_buffers(adapter)) |
528 | goto low_mem_buffers_failed; | 510 | goto failed; |
529 | 511 | ||
530 | if (zfcp_reqlist_alloc(adapter)) | 512 | adapter->req_list = zfcp_reqlist_alloc(); |
531 | goto low_mem_buffers_failed; | 513 | if (!adapter->req_list) |
514 | goto failed; | ||
532 | 515 | ||
533 | if (zfcp_dbf_adapter_register(adapter)) | 516 | if (zfcp_dbf_adapter_register(adapter)) |
534 | goto debug_register_failed; | 517 | goto failed; |
535 | 518 | ||
536 | if (zfcp_setup_adapter_work_queue(adapter)) | 519 | if (zfcp_setup_adapter_work_queue(adapter)) |
537 | goto work_queue_failed; | 520 | goto failed; |
538 | 521 | ||
539 | if (zfcp_fc_gs_setup(adapter)) | 522 | if (zfcp_fc_gs_setup(adapter)) |
540 | goto generic_services_failed; | 523 | goto failed; |
524 | |||
525 | rwlock_init(&adapter->port_list_lock); | ||
526 | INIT_LIST_HEAD(&adapter->port_list); | ||
541 | 527 | ||
542 | init_waitqueue_head(&adapter->remove_wq); | ||
543 | init_waitqueue_head(&adapter->erp_ready_wq); | 528 | init_waitqueue_head(&adapter->erp_ready_wq); |
544 | init_waitqueue_head(&adapter->erp_done_wqh); | 529 | init_waitqueue_head(&adapter->erp_done_wqh); |
545 | 530 | ||
546 | INIT_LIST_HEAD(&adapter->port_list_head); | ||
547 | INIT_LIST_HEAD(&adapter->erp_ready_head); | 531 | INIT_LIST_HEAD(&adapter->erp_ready_head); |
548 | INIT_LIST_HEAD(&adapter->erp_running_head); | 532 | INIT_LIST_HEAD(&adapter->erp_running_head); |
549 | 533 | ||
550 | spin_lock_init(&adapter->req_list_lock); | ||
551 | |||
552 | rwlock_init(&adapter->erp_lock); | 534 | rwlock_init(&adapter->erp_lock); |
553 | rwlock_init(&adapter->abort_lock); | 535 | rwlock_init(&adapter->abort_lock); |
554 | 536 | ||
555 | if (zfcp_erp_thread_setup(adapter)) | 537 | if (zfcp_erp_thread_setup(adapter)) |
556 | goto erp_thread_failed; | 538 | goto failed; |
557 | |||
558 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); | ||
559 | INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); | ||
560 | 539 | ||
561 | adapter->service_level.seq_print = zfcp_print_sl; | 540 | adapter->service_level.seq_print = zfcp_print_sl; |
562 | 541 | ||
563 | /* mark adapter unusable as long as sysfs registration is not complete */ | ||
564 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | ||
565 | |||
566 | dev_set_drvdata(&ccw_device->dev, adapter); | 542 | dev_set_drvdata(&ccw_device->dev, adapter); |
567 | 543 | ||
568 | if (sysfs_create_group(&ccw_device->dev.kobj, | 544 | if (sysfs_create_group(&ccw_device->dev.kobj, |
569 | &zfcp_sysfs_adapter_attrs)) | 545 | &zfcp_sysfs_adapter_attrs)) |
570 | goto sysfs_failed; | 546 | goto failed; |
571 | |||
572 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | ||
573 | 547 | ||
574 | if (!zfcp_adapter_scsi_register(adapter)) | 548 | if (!zfcp_adapter_scsi_register(adapter)) |
575 | return 0; | 549 | return adapter; |
576 | 550 | ||
577 | sysfs_failed: | 551 | failed: |
578 | zfcp_erp_thread_kill(adapter); | 552 | zfcp_adapter_unregister(adapter); |
579 | erp_thread_failed: | 553 | return ERR_PTR(-ENOMEM); |
580 | zfcp_fc_gs_destroy(adapter); | 554 | } |
581 | generic_services_failed: | 555 | |
556 | void zfcp_adapter_unregister(struct zfcp_adapter *adapter) | ||
557 | { | ||
558 | struct ccw_device *cdev = adapter->ccw_device; | ||
559 | |||
560 | cancel_work_sync(&adapter->scan_work); | ||
561 | cancel_work_sync(&adapter->stat_work); | ||
582 | zfcp_destroy_adapter_work_queue(adapter); | 562 | zfcp_destroy_adapter_work_queue(adapter); |
583 | work_queue_failed: | 563 | |
564 | zfcp_fc_wka_ports_force_offline(adapter->gs); | ||
565 | zfcp_adapter_scsi_unregister(adapter); | ||
566 | sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs); | ||
567 | |||
568 | zfcp_erp_thread_kill(adapter); | ||
584 | zfcp_dbf_adapter_unregister(adapter->dbf); | 569 | zfcp_dbf_adapter_unregister(adapter->dbf); |
585 | debug_register_failed: | ||
586 | dev_set_drvdata(&ccw_device->dev, NULL); | ||
587 | kfree(adapter->req_list); | ||
588 | low_mem_buffers_failed: | ||
589 | zfcp_free_low_mem_buffers(adapter); | ||
590 | qdio_failed: | ||
591 | zfcp_qdio_destroy(adapter->qdio); | 570 | zfcp_qdio_destroy(adapter->qdio); |
592 | kfree(adapter); | 571 | |
593 | return -ENOMEM; | 572 | zfcp_ccw_adapter_put(adapter); /* final put to release */ |
594 | } | 573 | } |
595 | 574 | ||
596 | /** | 575 | /** |
597 | * zfcp_adapter_dequeue - remove the adapter from the resource list | 576 | * zfcp_adapter_release - remove the adapter from the resource list |
598 | * @adapter: pointer to struct zfcp_adapter which should be removed | 577 | * @ref: pointer to struct kref |
599 | * locks: adapter list write lock is assumed to be held by caller | 578 | * locks: adapter list write lock is assumed to be held by caller |
600 | */ | 579 | */ |
601 | void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | 580 | void zfcp_adapter_release(struct kref *ref) |
602 | { | 581 | { |
603 | int retval = 0; | 582 | struct zfcp_adapter *adapter = container_of(ref, struct zfcp_adapter, |
604 | unsigned long flags; | 583 | ref); |
584 | struct ccw_device *cdev = adapter->ccw_device; | ||
605 | 585 | ||
606 | cancel_work_sync(&adapter->stat_work); | ||
607 | zfcp_fc_wka_ports_force_offline(adapter->gs); | ||
608 | sysfs_remove_group(&adapter->ccw_device->dev.kobj, | ||
609 | &zfcp_sysfs_adapter_attrs); | ||
610 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); | 586 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); |
611 | /* sanity check: no pending FSF requests */ | ||
612 | spin_lock_irqsave(&adapter->req_list_lock, flags); | ||
613 | retval = zfcp_reqlist_isempty(adapter); | ||
614 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); | ||
615 | if (!retval) | ||
616 | return; | ||
617 | |||
618 | zfcp_fc_gs_destroy(adapter); | 587 | zfcp_fc_gs_destroy(adapter); |
619 | zfcp_erp_thread_kill(adapter); | ||
620 | zfcp_destroy_adapter_work_queue(adapter); | ||
621 | zfcp_dbf_adapter_unregister(adapter->dbf); | ||
622 | zfcp_free_low_mem_buffers(adapter); | 588 | zfcp_free_low_mem_buffers(adapter); |
623 | zfcp_qdio_destroy(adapter->qdio); | ||
624 | kfree(adapter->req_list); | 589 | kfree(adapter->req_list); |
625 | kfree(adapter->fc_stats); | 590 | kfree(adapter->fc_stats); |
626 | kfree(adapter->stats_reset_data); | 591 | kfree(adapter->stats_reset_data); |
627 | kfree(adapter); | 592 | kfree(adapter); |
593 | put_device(&cdev->dev); | ||
628 | } | 594 | } |
629 | 595 | ||
630 | static void zfcp_sysfs_port_release(struct device *dev) | 596 | /** |
597 | * zfcp_device_unregister - remove port, unit from system | ||
598 | * @dev: reference to device which is to be removed | ||
599 | * @grp: related reference to attribute group | ||
600 | * | ||
601 | * Helper function to unregister port, unit from system | ||
602 | */ | ||
603 | void zfcp_device_unregister(struct device *dev, | ||
604 | const struct attribute_group *grp) | ||
631 | { | 605 | { |
632 | kfree(container_of(dev, struct zfcp_port, sysfs_device)); | 606 | sysfs_remove_group(&dev->kobj, grp); |
607 | device_unregister(dev); | ||
608 | } | ||
609 | |||
610 | static void zfcp_port_release(struct device *dev) | ||
611 | { | ||
612 | struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); | ||
613 | |||
614 | zfcp_ccw_adapter_put(port->adapter); | ||
615 | kfree(port); | ||
633 | } | 616 | } |
634 | 617 | ||
635 | /** | 618 | /** |
@@ -639,7 +622,6 @@ static void zfcp_sysfs_port_release(struct device *dev) | |||
639 | * @status: initial status for the port | 622 | * @status: initial status for the port |
640 | * @d_id: destination id of the remote port to be enqueued | 623 | * @d_id: destination id of the remote port to be enqueued |
641 | * Returns: pointer to enqueued port on success, ERR_PTR on error | 624 | * Returns: pointer to enqueued port on success, ERR_PTR on error |
642 | * Locks: config_mutex must be held to serialize changes to the port list | ||
643 | * | 625 | * |
644 | * All port internal structures are set up and the sysfs entry is generated. | 626 | * All port internal structures are set up and the sysfs entry is generated. |
645 | * d_id is used to enqueue ports with a well known address like the Directory | 627 | * d_id is used to enqueue ports with a well known address like the Directory |
@@ -649,20 +631,24 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, | |||
649 | u32 status, u32 d_id) | 631 | u32 status, u32 d_id) |
650 | { | 632 | { |
651 | struct zfcp_port *port; | 633 | struct zfcp_port *port; |
634 | int retval = -ENOMEM; | ||
635 | |||
636 | kref_get(&adapter->ref); | ||
652 | 637 | ||
653 | read_lock_irq(&zfcp_data.config_lock); | 638 | port = zfcp_get_port_by_wwpn(adapter, wwpn); |
654 | if (zfcp_get_port_by_wwpn(adapter, wwpn)) { | 639 | if (port) { |
655 | read_unlock_irq(&zfcp_data.config_lock); | 640 | put_device(&port->dev); |
656 | return ERR_PTR(-EINVAL); | 641 | retval = -EEXIST; |
642 | goto err_out; | ||
657 | } | 643 | } |
658 | read_unlock_irq(&zfcp_data.config_lock); | ||
659 | 644 | ||
660 | port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); | 645 | port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); |
661 | if (!port) | 646 | if (!port) |
662 | return ERR_PTR(-ENOMEM); | 647 | goto err_out; |
648 | |||
649 | rwlock_init(&port->unit_list_lock); | ||
650 | INIT_LIST_HEAD(&port->unit_list); | ||
663 | 651 | ||
664 | init_waitqueue_head(&port->remove_wq); | ||
665 | INIT_LIST_HEAD(&port->unit_list_head); | ||
666 | INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); | 652 | INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); |
667 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); | 653 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); |
668 | INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); | 654 | INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); |
@@ -671,58 +657,37 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, | |||
671 | port->d_id = d_id; | 657 | port->d_id = d_id; |
672 | port->wwpn = wwpn; | 658 | port->wwpn = wwpn; |
673 | port->rport_task = RPORT_NONE; | 659 | port->rport_task = RPORT_NONE; |
660 | port->dev.parent = &adapter->ccw_device->dev; | ||
661 | port->dev.release = zfcp_port_release; | ||
674 | 662 | ||
675 | /* mark port unusable as long as sysfs registration is not complete */ | 663 | if (dev_set_name(&port->dev, "0x%016llx", (unsigned long long)wwpn)) { |
676 | atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
677 | atomic_set(&port->refcount, 0); | ||
678 | |||
679 | if (dev_set_name(&port->sysfs_device, "0x%016llx", | ||
680 | (unsigned long long)wwpn)) { | ||
681 | kfree(port); | 664 | kfree(port); |
682 | return ERR_PTR(-ENOMEM); | 665 | goto err_out; |
683 | } | ||
684 | port->sysfs_device.parent = &adapter->ccw_device->dev; | ||
685 | port->sysfs_device.release = zfcp_sysfs_port_release; | ||
686 | dev_set_drvdata(&port->sysfs_device, port); | ||
687 | |||
688 | if (device_register(&port->sysfs_device)) { | ||
689 | put_device(&port->sysfs_device); | ||
690 | return ERR_PTR(-EINVAL); | ||
691 | } | 666 | } |
667 | retval = -EINVAL; | ||
692 | 668 | ||
693 | if (sysfs_create_group(&port->sysfs_device.kobj, | 669 | if (device_register(&port->dev)) { |
694 | &zfcp_sysfs_port_attrs)) { | 670 | put_device(&port->dev); |
695 | device_unregister(&port->sysfs_device); | 671 | goto err_out; |
696 | return ERR_PTR(-EINVAL); | ||
697 | } | 672 | } |
698 | 673 | ||
699 | zfcp_port_get(port); | 674 | if (sysfs_create_group(&port->dev.kobj, |
675 | &zfcp_sysfs_port_attrs)) | ||
676 | goto err_out_put; | ||
700 | 677 | ||
701 | write_lock_irq(&zfcp_data.config_lock); | 678 | write_lock_irq(&adapter->port_list_lock); |
702 | list_add_tail(&port->list, &adapter->port_list_head); | 679 | list_add_tail(&port->list, &adapter->port_list); |
703 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | 680 | write_unlock_irq(&adapter->port_list_lock); |
704 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); | ||
705 | 681 | ||
706 | write_unlock_irq(&zfcp_data.config_lock); | 682 | atomic_set_mask(status | ZFCP_STATUS_COMMON_RUNNING, &port->status); |
707 | 683 | ||
708 | zfcp_adapter_get(adapter); | ||
709 | return port; | 684 | return port; |
710 | } | ||
711 | 685 | ||
712 | /** | 686 | err_out_put: |
713 | * zfcp_port_dequeue - dequeues a port from the port list of the adapter | 687 | device_unregister(&port->dev); |
714 | * @port: pointer to struct zfcp_port which should be removed | 688 | err_out: |
715 | */ | 689 | zfcp_ccw_adapter_put(adapter); |
716 | void zfcp_port_dequeue(struct zfcp_port *port) | 690 | return ERR_PTR(retval); |
717 | { | ||
718 | write_lock_irq(&zfcp_data.config_lock); | ||
719 | list_del(&port->list); | ||
720 | write_unlock_irq(&zfcp_data.config_lock); | ||
721 | wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); | ||
722 | cancel_work_sync(&port->rport_work); /* usually not necessary */ | ||
723 | zfcp_adapter_put(port->adapter); | ||
724 | sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); | ||
725 | device_unregister(&port->sysfs_device); | ||
726 | } | 691 | } |
727 | 692 | ||
728 | /** | 693 | /** |