diff options
author | Christof Schmitt <christof.schmitt@de.ibm.com> | 2010-09-08 08:39:52 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-09-16 22:54:15 -0400 |
commit | 1daa4eb50fa5cd4c8f9c55452606e786fd42053b (patch) | |
tree | 2c299aacb948264e716ca6651c2f4ef234fc310a | |
parent | 57c237731b92fadc7d44824276313ec330b1989b (diff) |
[SCSI] zfcp: Move code for managing zfcp_unit devices to new file
Move the code for managing zfcp_unit devices to the new file
zfcp_unit.c. This is in preparation for the change that zfcp_unit will
only track the LUNs configured via unit_add, other data will be moved
from zfcp_unit to the new struct zfcp_scsi_dev.
Reviewed-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r-- | drivers/s390/scsi/Makefile | 5 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 122 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 13 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 41 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 56 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_unit.c | 255 |
6 files changed, 279 insertions, 213 deletions
diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index cb301cc6178c..c454ffebb63e 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile | |||
@@ -2,7 +2,8 @@ | |||
2 | # Makefile for the S/390 specific device drivers | 2 | # Makefile for the S/390 specific device drivers |
3 | # | 3 | # |
4 | 4 | ||
5 | zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ | 5 | zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_cfdc.o zfcp_dbf.o zfcp_erp.o \ |
6 | zfcp_fsf.o zfcp_dbf.o zfcp_sysfs.o zfcp_fc.o zfcp_cfdc.o | 6 | zfcp_fc.o zfcp_fsf.o zfcp_qdio.o zfcp_scsi.o zfcp_sysfs.o \ |
7 | zfcp_unit.o | ||
7 | 8 | ||
8 | obj-$(CONFIG_ZFCP) += zfcp.o | 9 | obj-$(CONFIG_ZFCP) += zfcp.o |
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 5c4b874591ea..044fb22718d2 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -56,7 +56,6 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) | |||
56 | struct ccw_device *cdev; | 56 | struct ccw_device *cdev; |
57 | struct zfcp_adapter *adapter; | 57 | struct zfcp_adapter *adapter; |
58 | struct zfcp_port *port; | 58 | struct zfcp_port *port; |
59 | struct zfcp_unit *unit; | ||
60 | 59 | ||
61 | cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); | 60 | cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); |
62 | if (!cdev) | 61 | if (!cdev) |
@@ -72,18 +71,11 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) | |||
72 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | 71 | port = zfcp_get_port_by_wwpn(adapter, wwpn); |
73 | if (!port) | 72 | if (!port) |
74 | goto out_port; | 73 | goto out_port; |
75 | |||
76 | flush_work(&port->rport_work); | 74 | flush_work(&port->rport_work); |
77 | unit = zfcp_unit_enqueue(port, lun); | ||
78 | if (IS_ERR(unit)) | ||
79 | goto out_unit; | ||
80 | |||
81 | zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL); | ||
82 | zfcp_erp_wait(adapter); | ||
83 | zfcp_scsi_scan(unit); | ||
84 | 75 | ||
85 | out_unit: | 76 | zfcp_unit_add(port, lun); |
86 | put_device(&port->dev); | 77 | put_device(&port->dev); |
78 | |||
87 | out_port: | 79 | out_port: |
88 | zfcp_ccw_adapter_put(adapter); | 80 | zfcp_ccw_adapter_put(adapter); |
89 | out_ccw_device: | 81 | out_ccw_device: |
@@ -215,30 +207,6 @@ static void __exit zfcp_module_exit(void) | |||
215 | module_exit(zfcp_module_exit); | 207 | module_exit(zfcp_module_exit); |
216 | 208 | ||
217 | /** | 209 | /** |
218 | * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN | ||
219 | * @port: pointer to port to search for unit | ||
220 | * @fcp_lun: FCP LUN to search for | ||
221 | * | ||
222 | * Returns: pointer to zfcp_unit or NULL | ||
223 | */ | ||
224 | struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) | ||
225 | { | ||
226 | unsigned long flags; | ||
227 | struct zfcp_unit *unit; | ||
228 | |||
229 | read_lock_irqsave(&port->unit_list_lock, flags); | ||
230 | list_for_each_entry(unit, &port->unit_list, list) | ||
231 | if (unit->fcp_lun == fcp_lun) { | ||
232 | if (!get_device(&unit->dev)) | ||
233 | unit = NULL; | ||
234 | read_unlock_irqrestore(&port->unit_list_lock, flags); | ||
235 | return unit; | ||
236 | } | ||
237 | read_unlock_irqrestore(&port->unit_list_lock, flags); | ||
238 | return NULL; | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn | 210 | * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn |
243 | * @adapter: pointer to adapter to search for port | 211 | * @adapter: pointer to adapter to search for port |
244 | * @wwpn: wwpn to search for | 212 | * @wwpn: wwpn to search for |
@@ -263,92 +231,6 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, | |||
263 | return NULL; | 231 | return NULL; |
264 | } | 232 | } |
265 | 233 | ||
266 | /** | ||
267 | * zfcp_unit_release - dequeue unit | ||
268 | * @dev: pointer to device | ||
269 | * | ||
270 | * waits until all work is done on unit and removes it then from the unit->list | ||
271 | * of the associated port. | ||
272 | */ | ||
273 | static void zfcp_unit_release(struct device *dev) | ||
274 | { | ||
275 | struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); | ||
276 | |||
277 | put_device(&unit->port->dev); | ||
278 | kfree(unit); | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * zfcp_unit_enqueue - enqueue unit to unit list of a port. | ||
283 | * @port: pointer to port where unit is added | ||
284 | * @fcp_lun: FCP LUN of unit to be enqueued | ||
285 | * Returns: pointer to enqueued unit on success, ERR_PTR on error | ||
286 | * | ||
287 | * Sets up some unit internal structures and creates sysfs entry. | ||
288 | */ | ||
289 | struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) | ||
290 | { | ||
291 | struct zfcp_unit *unit; | ||
292 | int retval = -ENOMEM; | ||
293 | |||
294 | get_device(&port->dev); | ||
295 | |||
296 | unit = zfcp_get_unit_by_lun(port, fcp_lun); | ||
297 | if (unit) { | ||
298 | put_device(&unit->dev); | ||
299 | retval = -EEXIST; | ||
300 | goto err_out; | ||
301 | } | ||
302 | |||
303 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); | ||
304 | if (!unit) | ||
305 | goto err_out; | ||
306 | |||
307 | unit->port = port; | ||
308 | unit->fcp_lun = fcp_lun; | ||
309 | unit->dev.parent = &port->dev; | ||
310 | unit->dev.release = zfcp_unit_release; | ||
311 | |||
312 | if (dev_set_name(&unit->dev, "0x%016llx", | ||
313 | (unsigned long long) fcp_lun)) { | ||
314 | kfree(unit); | ||
315 | goto err_out; | ||
316 | } | ||
317 | retval = -EINVAL; | ||
318 | |||
319 | INIT_WORK(&unit->scsi_work, zfcp_scsi_scan_work); | ||
320 | |||
321 | spin_lock_init(&unit->latencies.lock); | ||
322 | unit->latencies.write.channel.min = 0xFFFFFFFF; | ||
323 | unit->latencies.write.fabric.min = 0xFFFFFFFF; | ||
324 | unit->latencies.read.channel.min = 0xFFFFFFFF; | ||
325 | unit->latencies.read.fabric.min = 0xFFFFFFFF; | ||
326 | unit->latencies.cmd.channel.min = 0xFFFFFFFF; | ||
327 | unit->latencies.cmd.fabric.min = 0xFFFFFFFF; | ||
328 | |||
329 | if (device_register(&unit->dev)) { | ||
330 | put_device(&unit->dev); | ||
331 | goto err_out; | ||
332 | } | ||
333 | |||
334 | if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) | ||
335 | goto err_out_put; | ||
336 | |||
337 | write_lock_irq(&port->unit_list_lock); | ||
338 | list_add_tail(&unit->list, &port->unit_list); | ||
339 | write_unlock_irq(&port->unit_list_lock); | ||
340 | |||
341 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); | ||
342 | |||
343 | return unit; | ||
344 | |||
345 | err_out_put: | ||
346 | device_unregister(&unit->dev); | ||
347 | err_out: | ||
348 | put_device(&port->dev); | ||
349 | return ERR_PTR(retval); | ||
350 | } | ||
351 | |||
352 | static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) | 234 | static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) |
353 | { | 235 | { |
354 | adapter->pool.erp_req = | 236 | adapter->pool.erp_req = |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 3b93239c6f69..5c3966eaca51 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -15,12 +15,10 @@ | |||
15 | #include "zfcp_fc.h" | 15 | #include "zfcp_fc.h" |
16 | 16 | ||
17 | /* zfcp_aux.c */ | 17 | /* zfcp_aux.c */ |
18 | extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64); | ||
19 | extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64); | 18 | extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64); |
20 | extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); | 19 | extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); |
21 | extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32, | 20 | extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32, |
22 | u32); | 21 | u32); |
23 | extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64); | ||
24 | extern void zfcp_sg_free_table(struct scatterlist *, int); | 22 | extern void zfcp_sg_free_table(struct scatterlist *, int); |
25 | extern int zfcp_sg_setup_table(struct scatterlist *, int); | 23 | extern int zfcp_sg_setup_table(struct scatterlist *, int); |
26 | extern void zfcp_device_unregister(struct device *, | 24 | extern void zfcp_device_unregister(struct device *, |
@@ -163,8 +161,6 @@ extern void zfcp_scsi_rport_work(struct work_struct *); | |||
163 | extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); | 161 | extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); |
164 | extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); | 162 | extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); |
165 | extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); | 163 | extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); |
166 | extern void zfcp_scsi_scan(struct zfcp_unit *); | ||
167 | extern void zfcp_scsi_scan_work(struct work_struct *); | ||
168 | extern void zfcp_scsi_set_prot(struct zfcp_adapter *); | 164 | extern void zfcp_scsi_set_prot(struct zfcp_adapter *); |
169 | extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int); | 165 | extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int); |
170 | 166 | ||
@@ -175,4 +171,13 @@ extern struct attribute_group zfcp_sysfs_port_attrs; | |||
175 | extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; | 171 | extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; |
176 | extern struct device_attribute *zfcp_sysfs_shost_attrs[]; | 172 | extern struct device_attribute *zfcp_sysfs_shost_attrs[]; |
177 | 173 | ||
174 | /* zfcp_unit.c */ | ||
175 | extern int zfcp_unit_add(struct zfcp_port *, u64); | ||
176 | extern int zfcp_unit_remove(struct zfcp_port *, u64); | ||
177 | extern struct zfcp_unit *zfcp_unit_find(struct zfcp_port *, u64); | ||
178 | extern struct scsi_device *zfcp_unit_sdev(struct zfcp_unit *unit); | ||
179 | extern void zfcp_unit_scsi_scan(struct zfcp_unit *); | ||
180 | extern void zfcp_unit_queue_scsi_scan(struct zfcp_port *); | ||
181 | extern unsigned int zfcp_unit_sdev_status(struct zfcp_unit *); | ||
182 | |||
178 | #endif /* ZFCP_EXT_H */ | 183 | #endif /* ZFCP_EXT_H */ |
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index cb000c9833bb..03837797c45e 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -144,7 +144,7 @@ static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter, | |||
144 | list_for_each_entry(port, &adapter->port_list, list) { | 144 | list_for_each_entry(port, &adapter->port_list, list) { |
145 | if (!port->rport || (id != port->rport->scsi_target_id)) | 145 | if (!port->rport || (id != port->rport->scsi_target_id)) |
146 | continue; | 146 | continue; |
147 | unit = zfcp_get_unit_by_lun(port, lun); | 147 | unit = zfcp_unit_find(port, lun); |
148 | if (unit) | 148 | if (unit) |
149 | break; | 149 | break; |
150 | } | 150 | } |
@@ -534,20 +534,6 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) | |||
534 | } | 534 | } |
535 | } | 535 | } |
536 | 536 | ||
537 | static void zfcp_scsi_queue_unit_register(struct zfcp_port *port) | ||
538 | { | ||
539 | struct zfcp_unit *unit; | ||
540 | |||
541 | read_lock_irq(&port->unit_list_lock); | ||
542 | list_for_each_entry(unit, &port->unit_list, list) { | ||
543 | get_device(&unit->dev); | ||
544 | if (scsi_queue_work(port->adapter->scsi_host, | ||
545 | &unit->scsi_work) <= 0) | ||
546 | put_device(&unit->dev); | ||
547 | } | ||
548 | read_unlock_irq(&port->unit_list_lock); | ||
549 | } | ||
550 | |||
551 | static void zfcp_scsi_rport_register(struct zfcp_port *port) | 537 | static void zfcp_scsi_rport_register(struct zfcp_port *port) |
552 | { | 538 | { |
553 | struct fc_rport_identifiers ids; | 539 | struct fc_rport_identifiers ids; |
@@ -574,7 +560,7 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port) | |||
574 | port->rport = rport; | 560 | port->rport = rport; |
575 | port->starget_id = rport->scsi_target_id; | 561 | port->starget_id = rport->scsi_target_id; |
576 | 562 | ||
577 | zfcp_scsi_queue_unit_register(port); | 563 | zfcp_unit_queue_scsi_scan(port); |
578 | } | 564 | } |
579 | 565 | ||
580 | static void zfcp_scsi_rport_block(struct zfcp_port *port) | 566 | static void zfcp_scsi_rport_block(struct zfcp_port *port) |
@@ -638,29 +624,6 @@ void zfcp_scsi_rport_work(struct work_struct *work) | |||
638 | } | 624 | } |
639 | 625 | ||
640 | /** | 626 | /** |
641 | * zfcp_scsi_scan - Register LUN with SCSI midlayer | ||
642 | * @unit: The LUN/unit to register | ||
643 | */ | ||
644 | void zfcp_scsi_scan(struct zfcp_unit *unit) | ||
645 | { | ||
646 | struct fc_rport *rport = unit->port->rport; | ||
647 | |||
648 | if (rport && rport->port_state == FC_PORTSTATE_ONLINE) | ||
649 | scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, | ||
650 | scsilun_to_int((struct scsi_lun *) | ||
651 | &unit->fcp_lun), 0); | ||
652 | } | ||
653 | |||
654 | void zfcp_scsi_scan_work(struct work_struct *work) | ||
655 | { | ||
656 | struct zfcp_unit *unit = container_of(work, struct zfcp_unit, | ||
657 | scsi_work); | ||
658 | |||
659 | zfcp_scsi_scan(unit); | ||
660 | put_device(&unit->dev); | ||
661 | } | ||
662 | |||
663 | /** | ||
664 | * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host | 627 | * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host |
665 | * @adapter: The adapter where to configure DIF/DIX for the SCSI host | 628 | * @adapter: The adapter where to configure DIF/DIX for the SCSI host |
666 | */ | 629 | */ |
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index b4561c86e230..56c46e09d2d4 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c | |||
@@ -257,28 +257,15 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, | |||
257 | const char *buf, size_t count) | 257 | const char *buf, size_t count) |
258 | { | 258 | { |
259 | struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); | 259 | struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); |
260 | struct zfcp_unit *unit; | ||
261 | u64 fcp_lun; | 260 | u64 fcp_lun; |
262 | int retval = -EINVAL; | ||
263 | |||
264 | if (!(port && get_device(&port->dev))) | ||
265 | return -EBUSY; | ||
266 | 261 | ||
267 | if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) | 262 | if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) |
268 | goto out; | 263 | return -EINVAL; |
269 | 264 | ||
270 | unit = zfcp_unit_enqueue(port, fcp_lun); | 265 | if (zfcp_unit_add(port, fcp_lun)) |
271 | if (IS_ERR(unit)) | 266 | return -EINVAL; |
272 | goto out; | ||
273 | else | ||
274 | retval = 0; | ||
275 | 267 | ||
276 | zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); | 268 | return count; |
277 | zfcp_erp_wait(unit->port->adapter); | ||
278 | zfcp_scsi_scan(unit); | ||
279 | out: | ||
280 | put_device(&port->dev); | ||
281 | return retval ? retval : (ssize_t) count; | ||
282 | } | 269 | } |
283 | static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); | 270 | static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); |
284 | 271 | ||
@@ -287,42 +274,15 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, | |||
287 | const char *buf, size_t count) | 274 | const char *buf, size_t count) |
288 | { | 275 | { |
289 | struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); | 276 | struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); |
290 | struct zfcp_unit *unit; | ||
291 | u64 fcp_lun; | 277 | u64 fcp_lun; |
292 | int retval = -EINVAL; | ||
293 | struct scsi_device *sdev; | ||
294 | |||
295 | if (!(port && get_device(&port->dev))) | ||
296 | return -EBUSY; | ||
297 | 278 | ||
298 | if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) | 279 | if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) |
299 | goto out; | 280 | return -EINVAL; |
300 | |||
301 | unit = zfcp_get_unit_by_lun(port, fcp_lun); | ||
302 | if (!unit) | ||
303 | goto out; | ||
304 | else | ||
305 | retval = 0; | ||
306 | 281 | ||
307 | sdev = scsi_device_lookup(port->adapter->scsi_host, 0, | 282 | if (zfcp_unit_remove(port, fcp_lun)) |
308 | port->starget_id, | 283 | return -EINVAL; |
309 | scsilun_to_int((struct scsi_lun *)&fcp_lun)); | ||
310 | if (sdev) { | ||
311 | scsi_remove_device(sdev); | ||
312 | scsi_device_put(sdev); | ||
313 | } | ||
314 | 284 | ||
315 | write_lock_irq(&port->unit_list_lock); | 285 | return count; |
316 | list_del(&unit->list); | ||
317 | write_unlock_irq(&port->unit_list_lock); | ||
318 | |||
319 | put_device(&unit->dev); | ||
320 | |||
321 | zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); | ||
322 | zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs); | ||
323 | out: | ||
324 | put_device(&port->dev); | ||
325 | return retval ? retval : (ssize_t) count; | ||
326 | } | 286 | } |
327 | static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); | 287 | static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); |
328 | 288 | ||
diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c new file mode 100644 index 000000000000..e210c41ee389 --- /dev/null +++ b/drivers/s390/scsi/zfcp_unit.c | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | * zfcp device driver | ||
3 | * | ||
4 | * Tracking of manually configured LUNs and helper functions to | ||
5 | * register the LUNs with the SCSI midlayer. | ||
6 | * | ||
7 | * Copyright IBM Corporation 2010 | ||
8 | */ | ||
9 | |||
10 | #include "zfcp_def.h" | ||
11 | #include "zfcp_ext.h" | ||
12 | |||
13 | /** | ||
14 | * zfcp_unit_scsi_scan - Register LUN with SCSI midlayer | ||
15 | * @unit: The zfcp LUN/unit to register | ||
16 | * | ||
17 | * When the SCSI midlayer is not allowed to automatically scan and | ||
18 | * attach SCSI devices, zfcp has to register the single devices with | ||
19 | * the SCSI midlayer. | ||
20 | */ | ||
21 | void zfcp_unit_scsi_scan(struct zfcp_unit *unit) | ||
22 | { | ||
23 | struct fc_rport *rport = unit->port->rport; | ||
24 | unsigned int lun; | ||
25 | |||
26 | lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun); | ||
27 | |||
28 | if (rport && rport->port_state == FC_PORTSTATE_ONLINE) | ||
29 | scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, lun, 1); | ||
30 | } | ||
31 | |||
32 | static void zfcp_unit_scsi_scan_work(struct work_struct *work) | ||
33 | { | ||
34 | struct zfcp_unit *unit = container_of(work, struct zfcp_unit, | ||
35 | scsi_work); | ||
36 | |||
37 | zfcp_unit_scsi_scan(unit); | ||
38 | put_device(&unit->dev); | ||
39 | } | ||
40 | |||
41 | /** | ||
42 | * zfcp_unit_queue_scsi_scan - Register configured units on port | ||
43 | * @port: The zfcp_port where to register units | ||
44 | * | ||
45 | * After opening a port, all units configured on this port have to be | ||
46 | * registered with the SCSI midlayer. This function should be called | ||
47 | * after calling fc_remote_port_add, so that the fc_rport is already | ||
48 | * ONLINE and the call to scsi_scan_target runs the same way as the | ||
49 | * call in the FC transport class. | ||
50 | */ | ||
51 | void zfcp_unit_queue_scsi_scan(struct zfcp_port *port) | ||
52 | { | ||
53 | struct zfcp_unit *unit; | ||
54 | |||
55 | read_lock_irq(&port->unit_list_lock); | ||
56 | list_for_each_entry(unit, &port->unit_list, list) { | ||
57 | get_device(&unit->dev); | ||
58 | if (scsi_queue_work(port->adapter->scsi_host, | ||
59 | &unit->scsi_work) <= 0) | ||
60 | put_device(&unit->dev); | ||
61 | } | ||
62 | read_unlock_irq(&port->unit_list_lock); | ||
63 | } | ||
64 | |||
65 | static struct zfcp_unit *_zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun) | ||
66 | { | ||
67 | struct zfcp_unit *unit; | ||
68 | |||
69 | list_for_each_entry(unit, &port->unit_list, list) | ||
70 | if (unit->fcp_lun == fcp_lun) { | ||
71 | get_device(&unit->dev); | ||
72 | return unit; | ||
73 | } | ||
74 | |||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * zfcp_unit_find - Find and return zfcp_unit with specified FCP LUN | ||
80 | * @port: zfcp_port where to look for the unit | ||
81 | * @fcp_lun: 64 Bit FCP LUN used to identify the zfcp_unit | ||
82 | * | ||
83 | * If zfcp_unit is found, a reference is acquired that has to be | ||
84 | * released later. | ||
85 | * | ||
86 | * Returns: Pointer to the zfcp_unit, or NULL if there is no zfcp_unit | ||
87 | * with the specified FCP LUN. | ||
88 | */ | ||
89 | struct zfcp_unit *zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun) | ||
90 | { | ||
91 | struct zfcp_unit *unit; | ||
92 | |||
93 | read_lock_irq(&port->unit_list_lock); | ||
94 | unit = _zfcp_unit_find(port, fcp_lun); | ||
95 | read_unlock_irq(&port->unit_list_lock); | ||
96 | return unit; | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * zfcp_unit_release - Drop reference to zfcp_port and free memory of zfcp_unit. | ||
101 | * @dev: pointer to device in zfcp_unit | ||
102 | */ | ||
103 | static void zfcp_unit_release(struct device *dev) | ||
104 | { | ||
105 | struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); | ||
106 | |||
107 | put_device(&unit->port->dev); | ||
108 | kfree(unit); | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * zfcp_unit_enqueue - enqueue unit to unit list of a port. | ||
113 | * @port: pointer to port where unit is added | ||
114 | * @fcp_lun: FCP LUN of unit to be enqueued | ||
115 | * Returns: 0 success | ||
116 | * | ||
117 | * Sets up some unit internal structures and creates sysfs entry. | ||
118 | */ | ||
119 | int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) | ||
120 | { | ||
121 | struct zfcp_unit *unit; | ||
122 | |||
123 | unit = zfcp_unit_find(port, fcp_lun); | ||
124 | if (unit) { | ||
125 | put_device(&unit->dev); | ||
126 | return -EEXIST; | ||
127 | } | ||
128 | |||
129 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); | ||
130 | if (!unit) | ||
131 | return -ENOMEM; | ||
132 | |||
133 | unit->port = port; | ||
134 | unit->fcp_lun = fcp_lun; | ||
135 | unit->dev.parent = &port->dev; | ||
136 | unit->dev.release = zfcp_unit_release; | ||
137 | unit->latencies.write.channel.min = 0xFFFFFFFF; | ||
138 | unit->latencies.write.fabric.min = 0xFFFFFFFF; | ||
139 | unit->latencies.read.channel.min = 0xFFFFFFFF; | ||
140 | unit->latencies.read.fabric.min = 0xFFFFFFFF; | ||
141 | unit->latencies.cmd.channel.min = 0xFFFFFFFF; | ||
142 | unit->latencies.cmd.fabric.min = 0xFFFFFFFF; | ||
143 | INIT_WORK(&unit->scsi_work, zfcp_unit_scsi_scan_work); | ||
144 | spin_lock_init(&unit->latencies.lock); | ||
145 | |||
146 | if (dev_set_name(&unit->dev, "0x%016llx", | ||
147 | (unsigned long long) fcp_lun)) { | ||
148 | kfree(unit); | ||
149 | return -ENOMEM; | ||
150 | } | ||
151 | |||
152 | if (device_register(&unit->dev)) { | ||
153 | put_device(&unit->dev); | ||
154 | return -ENOMEM; | ||
155 | } | ||
156 | |||
157 | if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) { | ||
158 | device_unregister(&unit->dev); | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | get_device(&port->dev); | ||
163 | |||
164 | write_lock_irq(&port->unit_list_lock); | ||
165 | list_add_tail(&unit->list, &port->unit_list); | ||
166 | write_unlock_irq(&port->unit_list_lock); | ||
167 | |||
168 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); | ||
169 | zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); | ||
170 | zfcp_erp_wait(unit->port->adapter); | ||
171 | zfcp_unit_scsi_scan(unit); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * zfcp_unit_sdev - Return SCSI device for zfcp_unit | ||
178 | * @unit: The zfcp_unit where to get the SCSI device for | ||
179 | * | ||
180 | * Returns: scsi_device pointer on success, NULL if there is no SCSI | ||
181 | * device for this zfcp_unit | ||
182 | * | ||
183 | * On success, the caller also holds a reference to the SCSI device | ||
184 | * that must be released with scsi_device_put. | ||
185 | */ | ||
186 | struct scsi_device *zfcp_unit_sdev(struct zfcp_unit *unit) | ||
187 | { | ||
188 | struct Scsi_Host *shost; | ||
189 | struct zfcp_port *port; | ||
190 | unsigned int lun; | ||
191 | |||
192 | lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun); | ||
193 | port = unit->port; | ||
194 | shost = port->adapter->scsi_host; | ||
195 | return scsi_device_lookup(shost, 0, port->starget_id, lun); | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * zfcp_unit_sdev_status - Return zfcp LUN status for SCSI device | ||
200 | * @unit: The unit to lookup the SCSI device for | ||
201 | * | ||
202 | * Returns the zfcp LUN status field of the SCSI device if the SCSI device | ||
203 | * for the zfcp_unit exists, 0 otherwise. | ||
204 | */ | ||
205 | unsigned int zfcp_unit_sdev_status(struct zfcp_unit *unit) | ||
206 | { | ||
207 | unsigned int status = 0; | ||
208 | struct scsi_device *sdev; | ||
209 | struct zfcp_scsi_dev *zfcp_sdev; | ||
210 | |||
211 | sdev = zfcp_unit_sdev(unit); | ||
212 | if (sdev) { | ||
213 | zfcp_sdev = sdev_to_zfcp(sdev); | ||
214 | status = atomic_read(&zfcp_sdev->status); | ||
215 | scsi_device_put(sdev); | ||
216 | } | ||
217 | |||
218 | return status; | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * zfcp_unit_remove - Remove entry from list of configured units | ||
223 | * @port: The port where to remove the unit from the configuration | ||
224 | * @fcp_lun: The 64 bit LUN of the unit to remove | ||
225 | * | ||
226 | * Returns: -EINVAL if a unit with the specified LUN does not exist, | ||
227 | * 0 on success. | ||
228 | */ | ||
229 | int zfcp_unit_remove(struct zfcp_port *port, u64 fcp_lun) | ||
230 | { | ||
231 | struct zfcp_unit *unit; | ||
232 | struct scsi_device *sdev; | ||
233 | |||
234 | write_lock_irq(&port->unit_list_lock); | ||
235 | unit = _zfcp_unit_find(port, fcp_lun); | ||
236 | if (unit) | ||
237 | list_del(&unit->list); | ||
238 | write_unlock_irq(&port->unit_list_lock); | ||
239 | |||
240 | if (!unit) | ||
241 | return -EINVAL; | ||
242 | |||
243 | sdev = zfcp_unit_sdev(unit); | ||
244 | if (sdev) { | ||
245 | scsi_remove_device(sdev); | ||
246 | scsi_device_put(sdev); | ||
247 | } | ||
248 | |||
249 | put_device(&unit->dev); | ||
250 | |||
251 | zfcp_erp_unit_shutdown(unit, 0, "unrem_1", NULL); | ||
252 | zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs); | ||
253 | |||
254 | return 0; | ||
255 | } | ||