From e881a172dac4d9ea3b2a1540041d872963c269bd Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 15 Oct 2009 17:46:39 -0700 Subject: [SCSI] modify change_queue_depth to take in reason why it is being called This patch modifies scsi_host_template->change_queue_depth so that it takes an argument indicating why it is being called. This will be used so that if a LLD needs to do some extra processing when handling queue fulls or later ramp ups, it can do so. This is a simple port of the drivers setting a change_queue_depth callback. In the patch I just have these LLDs adjust the queue depth if the user was requesting it. Signed-off-by: Mike Christie [Vasu.Dev: v2 Also converted pmcraid_change_queue_depth and then verified all modules compile using "make allmodconfig" for any new build warnings on X86_64. Updated original description after combing two original patches from Mike to make this patch git bisectable.] Signed-off-by: Vasu Dev [jejb: fixed up 53c700] Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_scsi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 0e1a34627a2..ad115470172 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -29,8 +29,12 @@ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) return fcp_sns_info_ptr; } -static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth) +static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, + int reason) { + if (reason != SCSI_QDEPTH_DEFAULT) + return -EOPNOTSUPP; + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); return sdev->queue_depth; } -- cgit v1.2.3 From 42e62a74377bcbb526565a31aa18da8f712b93ee Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 15 Oct 2009 17:47:11 -0700 Subject: [SCSI] zfcp: Adapt change_queue_depth for queue full tracking Adapt the change_queue_depth callback in zfcp for the new reason parameter. Simply pass each call back to the SCSI midlayer, there are no resource adjustments necessary for zfcp. Signed-off-by: Christof Schmitt Removes check for (depth <= default_depth) in case of SCSI_QDEPTH_RAMP_UP call back, not needed after added max_queue_depth per sdev. Signed-off-by: Vasu Dev Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_scsi.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index ad115470172..f54655998bd 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -32,10 +32,19 @@ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason) { - if (reason != SCSI_QDEPTH_DEFAULT) + switch (reason) { + case SCSI_QDEPTH_DEFAULT: + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + break; + case SCSI_QDEPTH_QFULL: + scsi_track_queue_full(sdev, depth); + break; + case SCSI_QDEPTH_RAMP_UP: + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + break; + default: return -EOPNOTSUPP; - - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + } return sdev->queue_depth; } -- cgit v1.2.3 From ecf0c7721b104c0ce9c8ca534c911f6310cf92a8 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 24 Nov 2009 16:53:58 +0100 Subject: [SCSI] zfcp: Replace global config_lock with local list locks The global config_lock was used to protect the configuration organized in independent lists. It is not necessary to have a lock on driver level for this purpose. This patch replaces the global config_lock with a set of local list locks. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 80 ++++++++++++++++------------ drivers/s390/scsi/zfcp_ccw.c | 23 ++++---- drivers/s390/scsi/zfcp_def.h | 9 ++-- drivers/s390/scsi/zfcp_erp.c | 116 ++++++++++++++++++++++------------------- drivers/s390/scsi/zfcp_fc.c | 49 ++++++++--------- drivers/s390/scsi/zfcp_fsf.c | 22 ++++---- drivers/s390/scsi/zfcp_scsi.c | 52 ++++++++---------- drivers/s390/scsi/zfcp_sysfs.c | 48 +++++++---------- 8 files changed, 199 insertions(+), 200 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 2889e5f2dfd..883e13948ac 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -187,7 +187,6 @@ static int __init zfcp_module_init(void) goto out_gid_cache; mutex_init(&zfcp_data.config_mutex); - rwlock_init(&zfcp_data.config_lock); zfcp_data.scsi_transport_template = fc_attach_transport(&zfcp_transport_functions); @@ -238,12 +237,18 @@ module_init(zfcp_module_init); */ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) { + unsigned long flags; struct zfcp_unit *unit; - list_for_each_entry(unit, &port->unit_list_head, list) + read_lock_irqsave(&port->unit_list_lock, flags); + list_for_each_entry(unit, &port->unit_list, list) if ((unit->fcp_lun == fcp_lun) && - !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) - return unit; + !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) { + zfcp_unit_get(unit); + read_unlock_irqrestore(&port->unit_list_lock, flags); + return unit; + } + read_unlock_irqrestore(&port->unit_list_lock, flags); return NULL; } @@ -257,12 +262,18 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, u64 wwpn) { + unsigned long flags; struct zfcp_port *port; - list_for_each_entry(port, &adapter->port_list_head, list) + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) if ((port->wwpn == wwpn) && - !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE)) + !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE)) { + zfcp_port_get(port); + read_unlock_irqrestore(&adapter->port_list_lock, flags); return port; + } + read_unlock_irqrestore(&adapter->port_list_lock, flags); return NULL; } @@ -284,12 +295,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) { struct zfcp_unit *unit; - read_lock_irq(&zfcp_data.config_lock); - if (zfcp_get_unit_by_lun(port, fcp_lun)) { - read_unlock_irq(&zfcp_data.config_lock); + unit = zfcp_get_unit_by_lun(port, fcp_lun); + if (unit) { + zfcp_unit_put(unit); return ERR_PTR(-EINVAL); } - read_unlock_irq(&zfcp_data.config_lock); unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); if (!unit) @@ -335,13 +345,13 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) zfcp_unit_get(unit); - write_lock_irq(&zfcp_data.config_lock); - list_add_tail(&unit->list, &port->unit_list_head); + write_lock_irq(&port->unit_list_lock); + list_add_tail(&unit->list, &port->unit_list); + write_unlock_irq(&port->unit_list_lock); + atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); - write_unlock_irq(&zfcp_data.config_lock); - zfcp_port_get(port); return unit; @@ -356,11 +366,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) */ void zfcp_unit_dequeue(struct zfcp_unit *unit) { + struct zfcp_port *port = unit->port; + wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0); - write_lock_irq(&zfcp_data.config_lock); - list_del(&unit->list); - write_unlock_irq(&zfcp_data.config_lock); - zfcp_port_put(unit->port); + list_del(&unit->list); /* no list locking required */ + zfcp_port_put(port); sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); device_unregister(&unit->sysfs_device); } @@ -539,11 +549,13 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) if (zfcp_fc_gs_setup(adapter)) goto generic_services_failed; + rwlock_init(&adapter->port_list_lock); + INIT_LIST_HEAD(&adapter->port_list); + init_waitqueue_head(&adapter->remove_wq); init_waitqueue_head(&adapter->erp_ready_wq); init_waitqueue_head(&adapter->erp_done_wqh); - INIT_LIST_HEAD(&adapter->port_list_head); INIT_LIST_HEAD(&adapter->erp_ready_head); INIT_LIST_HEAD(&adapter->erp_running_head); @@ -650,19 +662,20 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, { struct zfcp_port *port; - read_lock_irq(&zfcp_data.config_lock); - if (zfcp_get_port_by_wwpn(adapter, wwpn)) { - read_unlock_irq(&zfcp_data.config_lock); - return ERR_PTR(-EINVAL); + port = zfcp_get_port_by_wwpn(adapter, wwpn); + if (port) { + zfcp_port_put(port); + return ERR_PTR(-EEXIST); } - read_unlock_irq(&zfcp_data.config_lock); port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); if (!port) return ERR_PTR(-ENOMEM); + rwlock_init(&port->unit_list_lock); + INIT_LIST_HEAD(&port->unit_list); + init_waitqueue_head(&port->remove_wq); - INIT_LIST_HEAD(&port->unit_list_head); INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); @@ -698,13 +711,13 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, zfcp_port_get(port); - write_lock_irq(&zfcp_data.config_lock); - list_add_tail(&port->list, &adapter->port_list_head); + write_lock_irq(&adapter->port_list_lock); + list_add_tail(&port->list, &adapter->port_list); + write_unlock_irq(&adapter->port_list_lock); + atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); - write_unlock_irq(&zfcp_data.config_lock); - zfcp_adapter_get(adapter); return port; } @@ -715,12 +728,11 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, */ void zfcp_port_dequeue(struct zfcp_port *port) { - write_lock_irq(&zfcp_data.config_lock); - list_del(&port->list); - write_unlock_irq(&zfcp_data.config_lock); + struct zfcp_adapter *adapter = port->adapter; + + list_del(&port->list); /* no list locking required here */ wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); - cancel_work_sync(&port->rport_work); /* usually not necessary */ - zfcp_adapter_put(port->adapter); + zfcp_adapter_put(adapter); sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); device_unregister(&port->sysfs_device); } diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index e08339428ec..aca2047dc2d 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -100,10 +100,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) mutex_lock(&zfcp_data.config_mutex); adapter = dev_get_drvdata(&ccw_device->dev); - if (!adapter) - goto out; mutex_unlock(&zfcp_data.config_mutex); + if (!adapter) + return; + cancel_work_sync(&adapter->scan_work); mutex_lock(&zfcp_data.config_mutex); @@ -111,18 +112,21 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) /* this also removes the scsi devices, so call it first */ zfcp_adapter_scsi_unregister(adapter); - write_lock_irq(&zfcp_data.config_lock); - list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { - list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { - list_move(&unit->list, &unit_remove_lh); + write_lock_irq(&adapter->port_list_lock); + list_for_each_entry_safe(port, p, &adapter->port_list, list) { + write_lock(&port->unit_list_lock); + list_for_each_entry_safe(unit, u, &port->unit_list, list) { atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); + list_move(&unit->list, &unit_remove_lh); } - list_move(&port->list, &port_remove_lh); + write_unlock(&port->unit_list_lock); atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); + list_move(&port->list, &port_remove_lh); } atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); - write_unlock_irq(&zfcp_data.config_lock); + write_unlock_irq(&adapter->port_list_lock); + mutex_unlock(&zfcp_data.config_mutex); list_for_each_entry_safe(port, p, &port_remove_lh, list) { list_for_each_entry_safe(unit, u, &unit_remove_lh, list) @@ -131,9 +135,6 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) } wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); zfcp_adapter_dequeue(adapter); - -out: - mutex_unlock(&zfcp_data.config_mutex); } /** diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 7da2fad8f51..e45a08d6c98 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -461,7 +461,8 @@ struct zfcp_adapter { u32 hardware_version; /* of FCP channel */ u16 timer_ticks; /* time int for a tick */ struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ - struct list_head port_list_head; /* remote port list */ + struct list_head port_list; /* remote port list */ + rwlock_t port_list_lock; /* port list lock */ unsigned long req_no; /* unique FSF req number */ struct list_head *req_list; /* list of pending reqs */ spinlock_t req_list_lock; /* request list lock */ @@ -504,7 +505,8 @@ struct zfcp_port { wait_queue_head_t remove_wq; /* can be used to wait for refcount drop to zero */ struct zfcp_adapter *adapter; /* adapter used to access port */ - struct list_head unit_list_head; /* head of logical unit list */ + struct list_head unit_list; /* head of logical unit list */ + rwlock_t unit_list_lock; /* unit list lock */ atomic_t status; /* status of this remote port */ u64 wwnn; /* WWNN if known */ u64 wwpn; /* WWPN */ @@ -601,9 +603,6 @@ struct zfcp_fsf_req { struct zfcp_data { struct scsi_host_template scsi_host_template; struct scsi_transport_template *scsi_transport_template; - rwlock_t config_lock; /* serialises changes - to adapter/port/unit - lists */ struct mutex config_mutex; struct kmem_cache *gpn_ft_cache; struct kmem_cache *qtcb_cache; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index f73e2180f33..464f0473877 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -99,9 +99,12 @@ static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) zfcp_erp_action_dismiss(&port->erp_action); - else - list_for_each_entry(unit, &port->unit_list_head, list) - zfcp_erp_action_dismiss_unit(unit); + else { + read_lock(&port->unit_list_lock); + list_for_each_entry(unit, &port->unit_list, list) + zfcp_erp_action_dismiss_unit(unit); + read_unlock(&port->unit_list_lock); + } } static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) @@ -110,9 +113,12 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE) zfcp_erp_action_dismiss(&adapter->erp_action); - else - list_for_each_entry(port, &adapter->port_list_head, list) + else { + read_lock(&adapter->port_list_lock); + list_for_each_entry(port, &adapter->port_list, list) zfcp_erp_action_dismiss_port(port); + read_unlock(&adapter->port_list_lock); + } } static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, @@ -264,11 +270,16 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, { unsigned long flags; - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); - _zfcp_erp_adapter_reopen(adapter, clear, id, ref); - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + zfcp_erp_adapter_block(adapter, clear); + zfcp_scsi_schedule_rports_block(adapter); + + write_lock_irqsave(&adapter->erp_lock, flags); + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + zfcp_erp_adapter_failed(adapter, "erareo1", NULL); + else + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, + NULL, NULL, id, ref); + write_unlock_irqrestore(&adapter->erp_lock, flags); } /** @@ -345,11 +356,9 @@ void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id, unsigned long flags; struct zfcp_adapter *adapter = port->adapter; - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); + write_lock_irqsave(&adapter->erp_lock, flags); _zfcp_erp_port_forced_reopen(port, clear, id, ref); - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + write_unlock_irqrestore(&adapter->erp_lock, flags); } static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, @@ -377,15 +386,13 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, */ int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref) { - unsigned long flags; int retval; + unsigned long flags; struct zfcp_adapter *adapter = port->adapter; - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); + write_lock_irqsave(&adapter->erp_lock, flags); retval = _zfcp_erp_port_reopen(port, clear, id, ref); - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + write_unlock_irqrestore(&adapter->erp_lock, flags); return retval; } @@ -424,11 +431,9 @@ void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, struct zfcp_port *port = unit->port; struct zfcp_adapter *adapter = port->adapter; - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); + write_lock_irqsave(&adapter->erp_lock, flags); _zfcp_erp_unit_reopen(unit, clear, id, ref); - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + write_unlock_irqrestore(&adapter->erp_lock, flags); } static int status_change_set(unsigned long mask, atomic_t *status) @@ -540,8 +545,10 @@ static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, { struct zfcp_port *port; - list_for_each_entry(port, &adapter->port_list_head, list) + read_lock(&adapter->port_list_lock); + list_for_each_entry(port, &adapter->port_list, list) _zfcp_erp_port_reopen(port, clear, id, ref); + read_unlock(&adapter->port_list_lock); } static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, @@ -549,8 +556,10 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, { struct zfcp_unit *unit; - list_for_each_entry(unit, &port->unit_list_head, list) + read_lock(&port->unit_list_lock); + list_for_each_entry(unit, &port->unit_list, list) _zfcp_erp_unit_reopen(unit, clear, id, ref); + read_unlock(&port->unit_list_lock); } static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) @@ -590,16 +599,14 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) { unsigned long flags; - read_lock_irqsave(&zfcp_data.config_lock, flags); - read_lock(&adapter->erp_lock); + read_lock_irqsave(&adapter->erp_lock, flags); if (list_empty(&adapter->erp_ready_head) && list_empty(&adapter->erp_running_head)) { atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); wake_up(&adapter->erp_done_wqh); } - read_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + read_unlock_irqrestore(&adapter->erp_lock, flags); } static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) @@ -1214,11 +1221,10 @@ static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) { int retval; - struct zfcp_adapter *adapter = erp_action->adapter; unsigned long flags; + struct zfcp_adapter *adapter = erp_action->adapter; - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); + write_lock_irqsave(&adapter->erp_lock, flags); zfcp_erp_strategy_check_fsfreq(erp_action); @@ -1231,11 +1237,9 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) zfcp_erp_action_to_running(erp_action); /* no lock to allow for blocking operations */ - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + write_unlock_irqrestore(&adapter->erp_lock, flags); retval = zfcp_erp_strategy_do_action(erp_action); - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); + write_lock_irqsave(&adapter->erp_lock, flags); if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) retval = ZFCP_ERP_CONTINUES; @@ -1273,8 +1277,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) zfcp_erp_strategy_followup_failed(erp_action); unlock: - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + write_unlock_irqrestore(&adapter->erp_lock, flags); if (retval != ZFCP_ERP_CONTINUES) zfcp_erp_action_cleanup(erp_action, retval); @@ -1415,6 +1418,7 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, void *ref, u32 mask, int set_or_clear) { struct zfcp_port *port; + unsigned long flags; u32 common_mask = mask & ZFCP_COMMON_FLAGS; if (set_or_clear == ZFCP_SET) { @@ -1429,10 +1433,13 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, atomic_set(&adapter->erp_counter, 0); } - if (common_mask) - list_for_each_entry(port, &adapter->port_list_head, list) + if (common_mask) { + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) zfcp_erp_modify_port_status(port, id, ref, common_mask, set_or_clear); + read_unlock_irqrestore(&adapter->port_list_lock, flags); + } } /** @@ -1449,6 +1456,7 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, u32 mask, int set_or_clear) { struct zfcp_unit *unit; + unsigned long flags; u32 common_mask = mask & ZFCP_COMMON_FLAGS; if (set_or_clear == ZFCP_SET) { @@ -1463,10 +1471,13 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, atomic_set(&port->erp_counter, 0); } - if (common_mask) - list_for_each_entry(unit, &port->unit_list_head, list) + if (common_mask) { + read_lock_irqsave(&port->unit_list_lock, flags); + list_for_each_entry(unit, &port->unit_list, list) zfcp_erp_modify_unit_status(unit, id, ref, common_mask, set_or_clear); + read_unlock_irqrestore(&port->unit_list_lock, flags); + } } /** @@ -1502,12 +1513,8 @@ void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref, */ void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref) { - unsigned long flags; - - read_lock_irqsave(&zfcp_data.config_lock, flags); zfcp_erp_modify_port_status(port, id, ref, ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); } @@ -1535,13 +1542,9 @@ void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref) */ void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref) { - unsigned long flags; - - read_lock_irqsave(&zfcp_data.config_lock, flags); zfcp_erp_modify_port_status(port, id, ref, ZFCP_STATUS_COMMON_ERP_FAILED | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); } /** @@ -1574,12 +1577,15 @@ static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id, void *ref) { struct zfcp_unit *unit; + unsigned long flags; int status = atomic_read(&port->status); if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | ZFCP_STATUS_COMMON_ACCESS_BOXED))) { - list_for_each_entry(unit, &port->unit_list_head, list) + read_lock_irqsave(&port->unit_list_lock, flags); + list_for_each_entry(unit, &port->unit_list, list) zfcp_erp_unit_access_changed(unit, id, ref); + read_unlock_irqrestore(&port->unit_list_lock, flags); return; } @@ -1595,14 +1601,14 @@ static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id, void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id, void *ref) { - struct zfcp_port *port; unsigned long flags; + struct zfcp_port *port; if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) return; - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &adapter->port_list_head, list) + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) zfcp_erp_port_access_changed(port, id, ref); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + read_unlock_irqrestore(&adapter->port_list_lock, flags); } diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index df23bcead23..c7efdc51df6 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -145,10 +145,11 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, struct fcp_rscn_element *elem) { unsigned long flags; + struct zfcp_adapter *adapter = fsf_req->adapter; struct zfcp_port *port; - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) { if ((port->d_id & range) == (elem->nport_did & range)) zfcp_fc_test_link(port); if (!port->d_id) @@ -156,8 +157,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, ZFCP_STATUS_COMMON_ERP_FAILED, "fcrscn1", NULL); } - - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + read_unlock_irqrestore(&adapter->port_list_lock, flags); } static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) @@ -187,18 +187,17 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) { + unsigned long flags; struct zfcp_adapter *adapter = req->adapter; struct zfcp_port *port; - unsigned long flags; - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &adapter->port_list_head, list) - if (port->wwpn == wwpn) + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) + if (port->wwpn == wwpn) { + zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req); break; - read_unlock_irqrestore(&zfcp_data.config_lock, flags); - - if (port && (port->wwpn == wwpn)) - zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req); + } + read_unlock_irqrestore(&adapter->port_list_lock, flags); } static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) @@ -579,20 +578,17 @@ static int zfcp_fc_send_gpn_ft(struct zfcp_gpn_ft *gpn_ft, static void zfcp_fc_validate_port(struct zfcp_port *port) { - struct zfcp_adapter *adapter = port->adapter; - if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)) return; atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); if ((port->supported_classes != 0) || - !list_empty(&port->unit_list_head)) { + !list_empty(&port->unit_list)) { zfcp_port_put(port); return; } zfcp_erp_port_shutdown(port, 0, "fcpval1", NULL); - zfcp_erp_wait(adapter); zfcp_port_put(port); zfcp_port_dequeue(port); } @@ -605,6 +601,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) struct gpn_ft_resp_acc *acc = sg_virt(sg); struct zfcp_adapter *adapter = ct->wka_port->adapter; struct zfcp_port *port, *tmp; + unsigned long flags; u32 d_id; int ret = 0, x, last = 0; @@ -643,21 +640,20 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) /* skip the adapter's port and known remote ports */ if (acc->wwpn == fc_host_port_name(adapter->scsi_host)) continue; - port = zfcp_get_port_by_wwpn(adapter, acc->wwpn); - if (port) - continue; port = zfcp_port_enqueue(adapter, acc->wwpn, ZFCP_STATUS_COMMON_NOESC, d_id); - if (IS_ERR(port)) - ret = PTR_ERR(port); - else + if (!IS_ERR(port)) zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL); + else if (PTR_ERR(port) != -EEXIST) + ret = PTR_ERR(port); } zfcp_erp_wait(adapter); - list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list) + write_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry_safe(port, tmp, &adapter->port_list, list) zfcp_fc_validate_port(port); + write_unlock_irqrestore(&adapter->port_list_lock, flags); mutex_unlock(&zfcp_data.config_mutex); return ret; } @@ -760,15 +756,14 @@ int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job) els_fc_job->els.adapter = adapter; if (rport) { - read_lock_irq(&zfcp_data.config_lock); port = zfcp_get_port_by_wwpn(adapter, rport->port_name); - if (port) - els_fc_job->els.d_id = port->d_id; - read_unlock_irq(&zfcp_data.config_lock); if (!port) { kfree(els_fc_job); return -EINVAL; } + + els_fc_job->els.d_id = port->d_id; + zfcp_port_put(port); } else { port_did = job->request->rqst_data.h_els.port_id; els_fc_job->els.d_id = (port_did[0] << 16) + diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 4e41baa0c14..9df62f68681 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -122,36 +122,32 @@ void zfcp_fsf_req_free(struct zfcp_fsf_req *req) static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) { + unsigned long flags; struct fsf_status_read_buffer *sr_buf = req->data; struct zfcp_adapter *adapter = req->adapter; struct zfcp_port *port; int d_id = sr_buf->d_id & ZFCP_DID_MASK; - unsigned long flags; - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &adapter->port_list_head, list) + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) if (port->d_id == d_id) { - read_unlock_irqrestore(&zfcp_data.config_lock, flags); zfcp_erp_port_reopen(port, 0, "fssrpc1", req); - return; + break; } - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + read_unlock_irqrestore(&adapter->port_list_lock, flags); } static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id, struct fsf_link_down_info *link_down) { struct zfcp_adapter *adapter = req->adapter; - unsigned long flags; if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) return; atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); - read_lock_irqsave(&zfcp_data.config_lock, flags); zfcp_scsi_schedule_rports_block(adapter); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); if (!link_down) goto out; @@ -1765,9 +1761,11 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) /* can't use generic zfcp_erp_modify_port_status because * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); - list_for_each_entry(unit, &port->unit_list_head, list) + read_lock(&port->unit_list_lock); + list_for_each_entry(unit, &port->unit_list, list) atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); + read_unlock(&port->unit_list_lock); zfcp_erp_port_boxed(port, "fscpph2", req); req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; @@ -1787,9 +1785,11 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); - list_for_each_entry(unit, &port->unit_list_head, list) + read_lock(&port->unit_list_lock); + list_for_each_entry(unit, &port->unit_list, list) atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); + read_unlock(&port->unit_list_lock); break; } } diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index f54655998bd..6feece3b2e3 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -128,49 +128,44 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, } static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter, - int channel, unsigned int id, - unsigned int lun) + unsigned int id, u64 lun) { + unsigned long flags; struct zfcp_port *port; - struct zfcp_unit *unit; - int scsi_lun; + struct zfcp_unit *unit = NULL; - list_for_each_entry(port, &adapter->port_list_head, list) { + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) { if (!port->rport || (id != port->rport->scsi_target_id)) continue; - list_for_each_entry(unit, &port->unit_list_head, list) { - scsi_lun = scsilun_to_int( - (struct scsi_lun *)&unit->fcp_lun); - if (lun == scsi_lun) - return unit; - } + unit = zfcp_get_unit_by_lun(port, lun); + if (unit) + break; } + read_unlock_irqrestore(&adapter->port_list_lock, flags); - return NULL; + return unit; } static int zfcp_scsi_slave_alloc(struct scsi_device *sdp) { struct zfcp_adapter *adapter; struct zfcp_unit *unit; - unsigned long flags; - int retval = -ENXIO; + u64 lun; adapter = (struct zfcp_adapter *) sdp->host->hostdata[0]; if (!adapter) goto out; - read_lock_irqsave(&zfcp_data.config_lock, flags); - unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun); + int_to_scsilun(sdp->lun, (struct scsi_lun *)&lun); + unit = zfcp_unit_lookup(adapter, sdp->id, lun); if (unit) { sdp->hostdata = unit; unit->device = sdp; - zfcp_unit_get(unit); - retval = 0; + return 0; } - read_unlock_irqrestore(&zfcp_data.config_lock, flags); out: - return retval; + return -ENXIO; } static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) @@ -338,12 +333,12 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) if (!shost) return; - read_lock_irq(&zfcp_data.config_lock); - list_for_each_entry(port, &adapter->port_list_head, list) + read_lock_irq(&adapter->port_list_lock); + list_for_each_entry(port, &adapter->port_list, list) if (port->rport) port->rport = NULL; + read_unlock_irq(&adapter->port_list_lock); - read_unlock_irq(&zfcp_data.config_lock); fc_remove_host(shost); scsi_remove_host(shost); scsi_host_put(shost); @@ -508,7 +503,7 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) * @rport: The FC rport where to teminate I/O * * Abort all pending SCSI commands for a port by closing the - * port. Using a reopen for avoids a conflict with a shutdown + * port. Using a reopen avoiding a conflict with a shutdown * overwriting a reopen. */ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) @@ -518,11 +513,7 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0]; - write_lock_irq(&zfcp_data.config_lock); port = zfcp_get_port_by_wwpn(adapter, rport->port_name); - if (port) - zfcp_port_get(port); - write_unlock_irq(&zfcp_data.config_lock); if (port) { zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); @@ -589,10 +580,13 @@ void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) { + unsigned long flags; struct zfcp_port *port; - list_for_each_entry(port, &adapter->port_list_head, list) + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) zfcp_scsi_schedule_rport_block(port); + read_unlock_irqrestore(&adapter->port_list_lock, flags); } void zfcp_scsi_rport_work(struct work_struct *work) diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index d31000886ca..8430b518357 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -153,15 +153,14 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, goto out; } - write_lock_irq(&zfcp_data.config_lock); port = zfcp_get_port_by_wwpn(adapter, wwpn); - if (port && (atomic_read(&port->refcount) == 0)) { - zfcp_port_get(port); + if (port && (atomic_read(&port->refcount) == 1)) { atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); + write_lock_irq(&adapter->port_list_lock); list_move(&port->list, &port_remove_lh); + write_unlock_irq(&adapter->port_list_lock); } else port = NULL; - write_unlock_irq(&zfcp_data.config_lock); if (!port) { retval = -ENXIO; @@ -253,35 +252,28 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, goto out; } - write_lock_irq(&zfcp_data.config_lock); unit = zfcp_get_unit_by_lun(port, fcp_lun); - if (unit) { - write_unlock_irq(&zfcp_data.config_lock); - /* wait for possible timeout during SCSI probe */ - flush_work(&unit->scsi_work); - write_lock_irq(&zfcp_data.config_lock); - - if (atomic_read(&unit->refcount) == 0) { - zfcp_unit_get(unit); - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, - &unit->status); - list_move(&unit->list, &unit_remove_lh); - } else { - unit = NULL; - } - } - - write_unlock_irq(&zfcp_data.config_lock); - if (!unit) { - retval = -ENXIO; + retval = -EINVAL; goto out; } - zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); - zfcp_erp_wait(unit->port->adapter); - zfcp_unit_put(unit); - zfcp_unit_dequeue(unit); + /* wait for possible timeout during SCSI probe */ + flush_work(&unit->scsi_work); + + if (atomic_read(&unit->refcount) == 1) { + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); + + write_lock_irq(&port->unit_list_lock); + list_move(&unit->list, &unit_remove_lh); + write_unlock_irq(&port->unit_list_lock); + + zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); + zfcp_erp_wait(unit->port->adapter); + zfcp_unit_put(unit); + zfcp_unit_dequeue(unit); + } else + zfcp_unit_put(unit); out: mutex_unlock(&zfcp_data.config_mutex); return retval ? retval : (ssize_t) count; -- cgit v1.2.3 From f3450c7b917201bb49d67032e9f60d5125675d6a Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 24 Nov 2009 16:53:59 +0100 Subject: [SCSI] zfcp: Replace local reference counting with common kref Replace the local reference counting by already available mechanisms offered by kref. Where possible existing device structures were used, including the same functionality. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 231 +++++++++++++++++++---------------------- drivers/s390/scsi/zfcp_ccw.c | 16 +-- drivers/s390/scsi/zfcp_cfdc.c | 5 +- drivers/s390/scsi/zfcp_dbf.c | 2 + drivers/s390/scsi/zfcp_def.h | 53 +--------- drivers/s390/scsi/zfcp_erp.c | 20 ++-- drivers/s390/scsi/zfcp_ext.h | 6 +- drivers/s390/scsi/zfcp_fc.c | 42 +++++--- drivers/s390/scsi/zfcp_fsf.c | 12 +-- drivers/s390/scsi/zfcp_scsi.c | 23 ++-- drivers/s390/scsi/zfcp_sysfs.c | 44 ++++---- 11 files changed, 196 insertions(+), 258 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 883e13948ac..8492ceac140 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -96,13 +96,12 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) adapter = dev_get_drvdata(&ccwdev->dev); if (!adapter) goto out_unlock; - zfcp_adapter_get(adapter); + kref_get(&adapter->ref); port = zfcp_get_port_by_wwpn(adapter, wwpn); if (!port) goto out_port; - zfcp_port_get(port); unit = zfcp_unit_enqueue(port, lun); if (IS_ERR(unit)) goto out_unit; @@ -113,11 +112,10 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) flush_work(&unit->scsi_work); mutex_lock(&zfcp_data.config_mutex); - zfcp_unit_put(unit); out_unit: - zfcp_port_put(port); + put_device(&port->sysfs_device); out_port: - zfcp_adapter_put(adapter); + kref_put(&adapter->ref, zfcp_adapter_release); out_unlock: mutex_unlock(&zfcp_data.config_mutex); out_ccwdev: @@ -244,7 +242,7 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) list_for_each_entry(unit, &port->unit_list, list) if ((unit->fcp_lun == fcp_lun) && !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) { - zfcp_unit_get(unit); + get_device(&unit->sysfs_device); read_unlock_irqrestore(&port->unit_list_lock, flags); return unit; } @@ -269,7 +267,7 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, list_for_each_entry(port, &adapter->port_list, list) if ((port->wwpn == wwpn) && !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE)) { - zfcp_port_get(port); + get_device(&port->sysfs_device); read_unlock_irqrestore(&adapter->port_list_lock, flags); return port; } @@ -277,9 +275,20 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, return NULL; } -static void zfcp_sysfs_unit_release(struct device *dev) +/** + * zfcp_unit_release - dequeue unit + * @dev: pointer to device + * + * waits until all work is done on unit and removes it then from the unit->list + * of the associated port. + */ +static void zfcp_unit_release(struct device *dev) { - kfree(container_of(dev, struct zfcp_unit, sysfs_device)); + struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, + sysfs_device); + + put_device(&unit->port->sysfs_device); + kfree(unit); } /** @@ -294,36 +303,39 @@ static void zfcp_sysfs_unit_release(struct device *dev) struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) { struct zfcp_unit *unit; + int retval = -ENOMEM; + + get_device(&port->sysfs_device); unit = zfcp_get_unit_by_lun(port, fcp_lun); if (unit) { - zfcp_unit_put(unit); - return ERR_PTR(-EINVAL); + put_device(&unit->sysfs_device); + retval = -EEXIST; + goto err_out; } unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); if (!unit) - return ERR_PTR(-ENOMEM); - - atomic_set(&unit->refcount, 0); - init_waitqueue_head(&unit->remove_wq); - INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); + goto err_out; unit->port = port; unit->fcp_lun = fcp_lun; + unit->sysfs_device.parent = &port->sysfs_device; + unit->sysfs_device.release = zfcp_unit_release; if (dev_set_name(&unit->sysfs_device, "0x%016llx", (unsigned long long) fcp_lun)) { kfree(unit); - return ERR_PTR(-ENOMEM); + goto err_out; } - unit->sysfs_device.parent = &port->sysfs_device; - unit->sysfs_device.release = zfcp_sysfs_unit_release; dev_set_drvdata(&unit->sysfs_device, unit); + retval = -EINVAL; /* mark unit unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); + INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); + spin_lock_init(&unit->latencies.lock); unit->latencies.write.channel.min = 0xFFFFFFFF; unit->latencies.write.fabric.min = 0xFFFFFFFF; @@ -334,16 +346,12 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) if (device_register(&unit->sysfs_device)) { put_device(&unit->sysfs_device); - return ERR_PTR(-EINVAL); + goto err_out; } if (sysfs_create_group(&unit->sysfs_device.kobj, - &zfcp_sysfs_unit_attrs)) { - device_unregister(&unit->sysfs_device); - return ERR_PTR(-EINVAL); - } - - zfcp_unit_get(unit); + &zfcp_sysfs_unit_attrs)) + goto err_out_put; write_lock_irq(&port->unit_list_lock); list_add_tail(&unit->list, &port->unit_list); @@ -352,27 +360,13 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); - zfcp_port_get(port); - return unit; -} - -/** - * zfcp_unit_dequeue - dequeue unit - * @unit: pointer to zfcp_unit - * - * waits until all work is done on unit and removes it then from the unit->list - * of the associated port. - */ -void zfcp_unit_dequeue(struct zfcp_unit *unit) -{ - struct zfcp_port *port = unit->port; - wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0); - list_del(&unit->list); /* no list locking required */ - zfcp_port_put(port); - sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); +err_out_put: device_unregister(&unit->sysfs_device); +err_out: + put_device(&port->sysfs_device); + return ERR_PTR(retval); } static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) @@ -518,41 +512,44 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; - /* - * Note: It is safe to release the list_lock, as any list changes - * are protected by the config_mutex, which must be held to get here - */ + if (!get_device(&ccw_device->dev)) + return -ENODEV; adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); - if (!adapter) + if (!adapter) { + put_device(&ccw_device->dev); return -ENOMEM; + } + + kref_init(&adapter->ref); ccw_device->handler = NULL; adapter->ccw_device = ccw_device; - atomic_set(&adapter->refcount, 0); + + INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); + INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); if (zfcp_qdio_setup(adapter)) - goto qdio_failed; + goto failed; if (zfcp_allocate_low_mem_buffers(adapter)) - goto low_mem_buffers_failed; + goto failed; if (zfcp_reqlist_alloc(adapter)) - goto low_mem_buffers_failed; + goto failed; if (zfcp_dbf_adapter_register(adapter)) - goto debug_register_failed; + goto failed; if (zfcp_setup_adapter_work_queue(adapter)) - goto work_queue_failed; + goto failed; if (zfcp_fc_gs_setup(adapter)) - goto generic_services_failed; + goto failed; rwlock_init(&adapter->port_list_lock); INIT_LIST_HEAD(&adapter->port_list); - init_waitqueue_head(&adapter->remove_wq); init_waitqueue_head(&adapter->erp_ready_wq); init_waitqueue_head(&adapter->erp_done_wqh); @@ -565,10 +562,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) rwlock_init(&adapter->abort_lock); if (zfcp_erp_thread_setup(adapter)) - goto erp_thread_failed; - - INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); - INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); + goto failed; adapter->service_level.seq_print = zfcp_print_sl; @@ -579,54 +573,37 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) if (sysfs_create_group(&ccw_device->dev.kobj, &zfcp_sysfs_adapter_attrs)) - goto sysfs_failed; + goto failed; atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); if (!zfcp_adapter_scsi_register(adapter)) return 0; -sysfs_failed: - zfcp_erp_thread_kill(adapter); -erp_thread_failed: - zfcp_fc_gs_destroy(adapter); -generic_services_failed: - zfcp_destroy_adapter_work_queue(adapter); -work_queue_failed: - zfcp_dbf_adapter_unregister(adapter->dbf); -debug_register_failed: - dev_set_drvdata(&ccw_device->dev, NULL); - kfree(adapter->req_list); -low_mem_buffers_failed: - zfcp_free_low_mem_buffers(adapter); -qdio_failed: - zfcp_qdio_destroy(adapter->qdio); - kfree(adapter); +failed: + kref_put(&adapter->ref, zfcp_adapter_release); return -ENOMEM; } /** - * zfcp_adapter_dequeue - remove the adapter from the resource list - * @adapter: pointer to struct zfcp_adapter which should be removed + * zfcp_adapter_release - remove the adapter from the resource list + * @ref: pointer to struct kref * locks: adapter list write lock is assumed to be held by caller */ -void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) +void zfcp_adapter_release(struct kref *ref) { - int retval = 0; - unsigned long flags; + struct zfcp_adapter *adapter = container_of(ref, struct zfcp_adapter, + ref); + struct ccw_device *ccw_device = adapter->ccw_device; cancel_work_sync(&adapter->stat_work); + zfcp_fc_wka_ports_force_offline(adapter->gs); - sysfs_remove_group(&adapter->ccw_device->dev.kobj, - &zfcp_sysfs_adapter_attrs); - dev_set_drvdata(&adapter->ccw_device->dev, NULL); - /* sanity check: no pending FSF requests */ - spin_lock_irqsave(&adapter->req_list_lock, flags); - retval = zfcp_reqlist_isempty(adapter); - spin_unlock_irqrestore(&adapter->req_list_lock, flags); - if (!retval) - return; + sysfs_remove_group(&ccw_device->dev.kobj, &zfcp_sysfs_adapter_attrs); + + dev_set_drvdata(&ccw_device->dev, NULL); + dev_set_drvdata(&adapter->ccw_device->dev, NULL); zfcp_fc_gs_destroy(adapter); zfcp_erp_thread_kill(adapter); zfcp_destroy_adapter_work_queue(adapter); @@ -637,11 +614,30 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) kfree(adapter->fc_stats); kfree(adapter->stats_reset_data); kfree(adapter); + put_device(&ccw_device->dev); +} + +/** + * zfcp_device_unregister - remove port, unit from system + * @dev: reference to device which is to be removed + * @grp: related reference to attribute group + * + * Helper function to unregister port, unit from system + */ +void zfcp_device_unregister(struct device *dev, + const struct attribute_group *grp) +{ + sysfs_remove_group(&dev->kobj, grp); + device_unregister(dev); } -static void zfcp_sysfs_port_release(struct device *dev) +static void zfcp_port_release(struct device *dev) { - kfree(container_of(dev, struct zfcp_port, sysfs_device)); + struct zfcp_port *port = container_of(dev, struct zfcp_port, + sysfs_device); + + kref_put(&port->adapter->ref, zfcp_adapter_release); + kfree(port); } /** @@ -661,21 +657,24 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, u32 status, u32 d_id) { struct zfcp_port *port; + int retval = -ENOMEM; + + kref_get(&adapter->ref); port = zfcp_get_port_by_wwpn(adapter, wwpn); if (port) { - zfcp_port_put(port); - return ERR_PTR(-EEXIST); + put_device(&port->sysfs_device); + retval = -EEXIST; + goto err_out; } port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); if (!port) - return ERR_PTR(-ENOMEM); + goto err_out; rwlock_init(&port->unit_list_lock); INIT_LIST_HEAD(&port->unit_list); - init_waitqueue_head(&port->remove_wq); INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); @@ -684,32 +683,28 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, port->d_id = d_id; port->wwpn = wwpn; port->rport_task = RPORT_NONE; + port->sysfs_device.parent = &adapter->ccw_device->dev; + port->sysfs_device.release = zfcp_port_release; /* mark port unusable as long as sysfs registration is not complete */ atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); - atomic_set(&port->refcount, 0); if (dev_set_name(&port->sysfs_device, "0x%016llx", (unsigned long long)wwpn)) { kfree(port); - return ERR_PTR(-ENOMEM); + goto err_out; } - port->sysfs_device.parent = &adapter->ccw_device->dev; - port->sysfs_device.release = zfcp_sysfs_port_release; dev_set_drvdata(&port->sysfs_device, port); + retval = -EINVAL; if (device_register(&port->sysfs_device)) { put_device(&port->sysfs_device); - return ERR_PTR(-EINVAL); + goto err_out; } if (sysfs_create_group(&port->sysfs_device.kobj, - &zfcp_sysfs_port_attrs)) { - device_unregister(&port->sysfs_device); - return ERR_PTR(-EINVAL); - } - - zfcp_port_get(port); + &zfcp_sysfs_port_attrs)) + goto err_out_put; write_lock_irq(&adapter->port_list_lock); list_add_tail(&port->list, &adapter->port_list); @@ -718,23 +713,13 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); - zfcp_adapter_get(adapter); return port; -} -/** - * zfcp_port_dequeue - dequeues a port from the port list of the adapter - * @port: pointer to struct zfcp_port which should be removed - */ -void zfcp_port_dequeue(struct zfcp_port *port) -{ - struct zfcp_adapter *adapter = port->adapter; - - list_del(&port->list); /* no list locking required here */ - wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); - zfcp_adapter_put(adapter); - sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); +err_out_put: device_unregister(&port->sysfs_device); +err_out: + kref_put(&adapter->ref, zfcp_adapter_release); + return ERR_PTR(retval); } /** diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index aca2047dc2d..c89dbe25037 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -128,13 +128,15 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) write_unlock_irq(&adapter->port_list_lock); mutex_unlock(&zfcp_data.config_mutex); - list_for_each_entry_safe(port, p, &port_remove_lh, list) { - list_for_each_entry_safe(unit, u, &unit_remove_lh, list) - zfcp_unit_dequeue(unit); - zfcp_port_dequeue(port); - } - wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); - zfcp_adapter_dequeue(adapter); + list_for_each_entry_safe(unit, u, &unit_remove_lh, list) + zfcp_device_unregister(&unit->sysfs_device, + &zfcp_sysfs_unit_attrs); + + list_for_each_entry_safe(port, p, &port_remove_lh, list) + zfcp_device_unregister(&port->sysfs_device, + &zfcp_sysfs_port_attrs); + + kref_put(&adapter->ref, zfcp_adapter_release); } /** diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index ef681dfed0c..856f82dbcb1 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -98,7 +98,7 @@ static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno) if (!adapter) goto out_put; - zfcp_adapter_get(adapter); + kref_get(&adapter->ref); out_put: put_device(&ccwdev->dev); out: @@ -212,7 +212,6 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, retval = -ENXIO; goto free_buffer; } - zfcp_adapter_get(adapter); retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg, data_user->control_file); @@ -245,7 +244,7 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, free_sg: zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES); adapter_put: - zfcp_adapter_put(adapter); + kref_put(&adapter->ref, zfcp_adapter_release); free_buffer: kfree(data); no_mem_sense: diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 215b70749e9..fe818cd29dc 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -1067,6 +1067,8 @@ err_out: */ void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf) { + if (!dbf) + return; debug_unregister(dbf->scsi); debug_unregister(dbf->san); debug_unregister(dbf->hba); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index e45a08d6c98..55dc402c3ae 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -446,9 +446,7 @@ struct zfcp_qdio { }; struct zfcp_adapter { - atomic_t refcount; /* reference count */ - wait_queue_head_t remove_wq; /* can be used to wait for - refcount drop to zero */ + struct kref ref; u64 peer_wwnn; /* P2P peer WWNN */ u64 peer_wwpn; /* P2P peer WWPN */ u32 peer_d_id; /* P2P peer D_ID */ @@ -501,9 +499,6 @@ struct zfcp_port { struct device sysfs_device; /* sysfs device */ struct fc_rport *rport; /* rport of fc transport class */ struct list_head list; /* list of remote ports */ - atomic_t refcount; /* reference count */ - wait_queue_head_t remove_wq; /* can be used to wait for - refcount drop to zero */ struct zfcp_adapter *adapter; /* adapter used to access port */ struct list_head unit_list; /* head of logical unit list */ rwlock_t unit_list_lock; /* unit list lock */ @@ -525,9 +520,6 @@ struct zfcp_port { struct zfcp_unit { struct device sysfs_device; /* sysfs device */ struct list_head list; /* list of logical units */ - atomic_t refcount; /* reference count */ - wait_queue_head_t remove_wq; /* can be used to wait for - refcount drop to zero */ struct zfcp_port *port; /* remote port of unit */ atomic_t status; /* status of this logical unit */ u64 fcp_lun; /* own FCP_LUN */ @@ -656,47 +648,4 @@ zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req) return NULL; } -/* - * functions needed for reference/usage counting - */ - -static inline void -zfcp_unit_get(struct zfcp_unit *unit) -{ - atomic_inc(&unit->refcount); -} - -static inline void -zfcp_unit_put(struct zfcp_unit *unit) -{ - if (atomic_dec_return(&unit->refcount) == 0) - wake_up(&unit->remove_wq); -} - -static inline void -zfcp_port_get(struct zfcp_port *port) -{ - atomic_inc(&port->refcount); -} - -static inline void -zfcp_port_put(struct zfcp_port *port) -{ - if (atomic_dec_return(&port->refcount) == 0) - wake_up(&port->remove_wq); -} - -static inline void -zfcp_adapter_get(struct zfcp_adapter *adapter) -{ - atomic_inc(&adapter->refcount); -} - -static inline void -zfcp_adapter_put(struct zfcp_adapter *adapter) -{ - if (atomic_dec_return(&adapter->refcount) == 0) - wake_up(&adapter->remove_wq); -} - #endif /* ZFCP_DEF_H */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 464f0473877..788fd3a4cd2 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -174,7 +174,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, switch (need) { case ZFCP_ERP_ACTION_REOPEN_UNIT: - zfcp_unit_get(unit); + get_device(&unit->sysfs_device); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); erp_action = &unit->erp_action; if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) @@ -183,7 +183,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, case ZFCP_ERP_ACTION_REOPEN_PORT: case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - zfcp_port_get(port); + get_device(&port->sysfs_device); zfcp_erp_action_dismiss_port(port); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); erp_action = &port->erp_action; @@ -192,7 +192,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - zfcp_adapter_get(adapter); + kref_get(&adapter->ref); zfcp_erp_action_dismiss_adapter(adapter); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); erp_action = &adapter->erp_action; @@ -1177,19 +1177,19 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) switch (act->action) { case ZFCP_ERP_ACTION_REOPEN_UNIT: if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { - zfcp_unit_get(unit); + get_device(&unit->sysfs_device); if (scsi_queue_work(unit->port->adapter->scsi_host, &unit->scsi_work) <= 0) - zfcp_unit_put(unit); + put_device(&unit->sysfs_device); } - zfcp_unit_put(unit); + put_device(&unit->sysfs_device); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT: if (result == ZFCP_ERP_SUCCEEDED) zfcp_scsi_schedule_rport_register(port); - zfcp_port_put(port); + put_device(&port->sysfs_device); break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: @@ -1198,7 +1198,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) schedule_work(&adapter->scan_work); } else unregister_service_level(&adapter->service_level); - zfcp_adapter_put(adapter); + kref_put(&adapter->ref, zfcp_adapter_release); break; } } @@ -1224,8 +1224,9 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) unsigned long flags; struct zfcp_adapter *adapter = erp_action->adapter; - write_lock_irqsave(&adapter->erp_lock, flags); + kref_get(&adapter->ref); + write_lock_irqsave(&adapter->erp_lock, flags); zfcp_erp_strategy_check_fsfreq(erp_action); if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { @@ -1282,6 +1283,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) if (retval != ZFCP_ERP_CONTINUES) zfcp_erp_action_cleanup(erp_action, retval); + kref_put(&adapter->ref, zfcp_adapter_release); return retval; } diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index b3f28deb450..3106c3be639 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -15,15 +15,15 @@ extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64); extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64); extern int zfcp_adapter_enqueue(struct ccw_device *); -extern void zfcp_adapter_dequeue(struct zfcp_adapter *); extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32, u32); -extern void zfcp_port_dequeue(struct zfcp_port *); extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64); -extern void zfcp_unit_dequeue(struct zfcp_unit *); extern int zfcp_reqlist_isempty(struct zfcp_adapter *); extern void zfcp_sg_free_table(struct scatterlist *, int); extern int zfcp_sg_setup_table(struct scatterlist *, int); +extern void zfcp_device_unregister(struct device *, + const struct attribute_group *); +extern void zfcp_adapter_release(struct kref *); /* zfcp_ccw.c */ extern int zfcp_ccw_register(void); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index c7efdc51df6..6fa1bcbec0a 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -134,6 +134,8 @@ static void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs) { + if (!gs) + return; zfcp_fc_wka_port_force_offline(&gs->ms); zfcp_fc_wka_port_force_offline(&gs->ts); zfcp_fc_wka_port_force_offline(&gs->ds); @@ -356,7 +358,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work) zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL); out: - zfcp_port_put(port); + put_device(&port->sysfs_device); } /** @@ -365,9 +367,9 @@ out: */ void zfcp_fc_trigger_did_lookup(struct zfcp_port *port) { - zfcp_port_get(port); + get_device(&port->sysfs_device); if (!queue_work(port->adapter->work_queue, &port->gid_pn_work)) - zfcp_port_put(port); + put_device(&port->sysfs_device); } /** @@ -426,7 +428,7 @@ static void zfcp_fc_adisc_handler(unsigned long data) zfcp_scsi_schedule_rport_register(port); out: atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); - zfcp_port_put(port); + put_device(&port->sysfs_device); kfree(adisc); } @@ -468,7 +470,7 @@ void zfcp_fc_link_test_work(struct work_struct *work) container_of(work, struct zfcp_port, test_link_work); int retval; - zfcp_port_get(port); + get_device(&port->sysfs_device); port->rport_task = RPORT_DEL; zfcp_scsi_rport_work(&port->rport_work); @@ -487,7 +489,7 @@ void zfcp_fc_link_test_work(struct work_struct *work) zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL); out: - zfcp_port_put(port); + put_device(&port->sysfs_device); } /** @@ -500,9 +502,9 @@ out: */ void zfcp_fc_test_link(struct zfcp_port *port) { - zfcp_port_get(port); + get_device(&port->sysfs_device); if (!queue_work(port->adapter->work_queue, &port->test_link_work)) - zfcp_port_put(port); + put_device(&port->sysfs_device); } static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) @@ -576,7 +578,7 @@ static int zfcp_fc_send_gpn_ft(struct zfcp_gpn_ft *gpn_ft, return ret; } -static void zfcp_fc_validate_port(struct zfcp_port *port) +static void zfcp_fc_validate_port(struct zfcp_port *port, struct list_head *lh) { if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)) return; @@ -584,13 +586,11 @@ static void zfcp_fc_validate_port(struct zfcp_port *port) atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); if ((port->supported_classes != 0) || - !list_empty(&port->unit_list)) { - zfcp_port_put(port); + !list_empty(&port->unit_list)) return; - } - zfcp_erp_port_shutdown(port, 0, "fcpval1", NULL); - zfcp_port_put(port); - zfcp_port_dequeue(port); + + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); + list_move_tail(&port->list, lh); } static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) @@ -602,6 +602,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) struct zfcp_adapter *adapter = ct->wka_port->adapter; struct zfcp_port *port, *tmp; unsigned long flags; + LIST_HEAD(remove_lh); u32 d_id; int ret = 0, x, last = 0; @@ -652,9 +653,16 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) zfcp_erp_wait(adapter); write_lock_irqsave(&adapter->port_list_lock, flags); list_for_each_entry_safe(port, tmp, &adapter->port_list, list) - zfcp_fc_validate_port(port); + zfcp_fc_validate_port(port, &remove_lh); write_unlock_irqrestore(&adapter->port_list_lock, flags); mutex_unlock(&zfcp_data.config_mutex); + + list_for_each_entry_safe(port, tmp, &remove_lh, list) { + zfcp_erp_port_shutdown(port, 0, "fcegpf2", NULL); + zfcp_device_unregister(&port->sysfs_device, + &zfcp_sysfs_port_attrs); + } + return ret; } @@ -763,7 +771,7 @@ int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job) } els_fc_job->els.d_id = port->d_id; - zfcp_port_put(port); + put_device(&port->sysfs_device); } else { port_did = job->request->rqst_data.h_els.port_id; els_fc_job->els.d_id = (port_did[0] << 16) + diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9df62f68681..3aad7091628 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1492,7 +1492,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) } out: - zfcp_port_put(port); + put_device(&port->sysfs_device); } /** @@ -1530,14 +1530,14 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) req->data = port; req->erp_action = erp_action; erp_action->fsf_req = req; - zfcp_port_get(port); + get_device(&port->sysfs_device); zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); erp_action->fsf_req = NULL; - zfcp_port_put(port); + put_device(&port->sysfs_device); } out: spin_unlock_bh(&qdio->req_q_lock); @@ -2335,7 +2335,7 @@ skip_fsfstatus: else { zfcp_fsf_send_fcp_command_task_handler(req); req->unit = NULL; - zfcp_unit_put(unit); + put_device(&unit->sysfs_device); } } @@ -2387,7 +2387,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - zfcp_unit_get(unit); + get_device(&unit->sysfs_device); req->unit = unit; req->data = scsi_cmnd; req->handler = zfcp_fsf_send_fcp_command_handler; @@ -2463,7 +2463,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, goto out; failed_scsi_cmnd: - zfcp_unit_put(unit); + put_device(&unit->sysfs_device); zfcp_fsf_req_free(req); scsi_cmnd->host_scribble = NULL; out: diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 6feece3b2e3..39a621d729e 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -52,7 +52,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) { struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; unit->device = NULL; - zfcp_unit_put(unit); + put_device(&unit->sysfs_device); } static int zfcp_scsi_slave_configure(struct scsi_device *sdp) @@ -335,8 +335,7 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) read_lock_irq(&adapter->port_list_lock); list_for_each_entry(port, &adapter->port_list, list) - if (port->rport) - port->rport = NULL; + port->rport = NULL; read_unlock_irq(&adapter->port_list_lock); fc_remove_host(shost); @@ -356,7 +355,7 @@ zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL); if (!fc_stats) return NULL; - adapter->fc_stats = fc_stats; /* freed in adater_dequeue */ + adapter->fc_stats = fc_stats; /* freed in adapter_release */ } memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats)); return adapter->fc_stats; @@ -472,7 +471,7 @@ static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost) adapter->stats_reset = jiffies/HZ; kfree(adapter->stats_reset_data); adapter->stats_reset_data = data; /* finally freed in - adapter_dequeue */ + adapter_release */ } } @@ -517,7 +516,7 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) if (port) { zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); - zfcp_port_put(port); + put_device(&port->sysfs_device); } } @@ -559,23 +558,23 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port) void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) { - zfcp_port_get(port); + get_device(&port->sysfs_device); port->rport_task = RPORT_ADD; if (!queue_work(port->adapter->work_queue, &port->rport_work)) - zfcp_port_put(port); + put_device(&port->sysfs_device); } void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) { - zfcp_port_get(port); + get_device(&port->sysfs_device); port->rport_task = RPORT_DEL; if (port->rport && queue_work(port->adapter->work_queue, &port->rport_work)) return; - zfcp_port_put(port); + put_device(&port->sysfs_device); } void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) @@ -604,7 +603,7 @@ void zfcp_scsi_rport_work(struct work_struct *work) } } - zfcp_port_put(port); + put_device(&port->sysfs_device); } @@ -622,7 +621,7 @@ void zfcp_scsi_scan(struct work_struct *work) scsilun_to_int((struct scsi_lun *) &unit->fcp_lun), 0); - zfcp_unit_put(unit); + put_device(&unit->sysfs_device); } static int zfcp_execute_fc_job(struct fc_bsg_job *job) diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 8430b518357..b4a7e17932c 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -3,7 +3,7 @@ * * sysfs attributes. * - * Copyright IBM Corporation 2008 + * Copyright IBM Corporation 2008, 2009 */ #define KMSG_COMPONENT "zfcp" @@ -140,7 +140,6 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, struct zfcp_port *port; u64 wwpn; int retval = 0; - LIST_HEAD(port_remove_lh); mutex_lock(&zfcp_data.config_mutex); if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { @@ -154,23 +153,21 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, } port = zfcp_get_port_by_wwpn(adapter, wwpn); - if (port && (atomic_read(&port->refcount) == 1)) { - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); - write_lock_irq(&adapter->port_list_lock); - list_move(&port->list, &port_remove_lh); - write_unlock_irq(&adapter->port_list_lock); - } else - port = NULL; - if (!port) { retval = -ENXIO; goto out; } + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); + + write_lock_irq(&adapter->port_list_lock); + list_del(&port->list); + write_unlock_irq(&adapter->port_list_lock); + + put_device(&port->sysfs_device); + zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL); - zfcp_erp_wait(adapter); - zfcp_port_put(port); - zfcp_port_dequeue(port); + zfcp_device_unregister(&port->sysfs_device, &zfcp_sysfs_port_attrs); out: mutex_unlock(&zfcp_data.config_mutex); return retval ? retval : (ssize_t) count; @@ -224,7 +221,6 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); zfcp_erp_wait(unit->port->adapter); flush_work(&unit->scsi_work); - zfcp_unit_put(unit); out: mutex_unlock(&zfcp_data.config_mutex); return retval ? retval : (ssize_t) count; @@ -239,7 +235,6 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, struct zfcp_unit *unit; u64 fcp_lun; int retval = 0; - LIST_HEAD(unit_remove_lh); mutex_lock(&zfcp_data.config_mutex); if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { @@ -261,19 +256,16 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, /* wait for possible timeout during SCSI probe */ flush_work(&unit->scsi_work); - if (atomic_read(&unit->refcount) == 1) { - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); + + write_lock_irq(&port->unit_list_lock); + list_del(&unit->list); + write_unlock_irq(&port->unit_list_lock); - write_lock_irq(&port->unit_list_lock); - list_move(&unit->list, &unit_remove_lh); - write_unlock_irq(&port->unit_list_lock); + put_device(&unit->sysfs_device); - zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); - zfcp_erp_wait(unit->port->adapter); - zfcp_unit_put(unit); - zfcp_unit_dequeue(unit); - } else - zfcp_unit_put(unit); + zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); + zfcp_device_unregister(&unit->sysfs_device, &zfcp_sysfs_unit_attrs); out: mutex_unlock(&zfcp_data.config_mutex); return retval ? retval : (ssize_t) count; -- cgit v1.2.3 From de3dc57214a1466034ecc4d4ffb10331d34c09a3 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 24 Nov 2009 16:54:00 +0100 Subject: [SCSI] zfcp: Remove global config_mutex The global config_mutex was required for the serialization of a configuration change within the zfcp driver. This global locking is now obsolete and can be removed. The requirement of serializing the access to a zfcp_adapter reference via a ccw_device is realized wth a static spinlock. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 86 ++++++++++++------------- drivers/s390/scsi/zfcp_ccw.c | 138 +++++++++++++++++++++++------------------ drivers/s390/scsi/zfcp_cfdc.c | 25 +++----- drivers/s390/scsi/zfcp_def.h | 1 - drivers/s390/scsi/zfcp_ext.h | 5 +- drivers/s390/scsi/zfcp_fc.c | 3 - drivers/s390/scsi/zfcp_sysfs.c | 132 ++++++++++++++++++++++++++++++--------- 7 files changed, 232 insertions(+), 158 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 8492ceac140..ed31bd0ff3f 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -80,23 +80,21 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) { - struct ccw_device *ccwdev; + struct ccw_device *cdev; struct zfcp_adapter *adapter; struct zfcp_port *port; struct zfcp_unit *unit; - ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); - if (!ccwdev) + cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); + if (!cdev) return; - if (ccw_device_set_online(ccwdev)) - goto out_ccwdev; + if (ccw_device_set_online(cdev)) + goto out_ccw_device; - mutex_lock(&zfcp_data.config_mutex); - adapter = dev_get_drvdata(&ccwdev->dev); + adapter = zfcp_ccw_adapter_by_cdev(cdev); if (!adapter) - goto out_unlock; - kref_get(&adapter->ref); + goto out_ccw_device; port = zfcp_get_port_by_wwpn(adapter, wwpn); if (!port) @@ -105,21 +103,17 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) unit = zfcp_unit_enqueue(port, lun); if (IS_ERR(unit)) goto out_unit; - mutex_unlock(&zfcp_data.config_mutex); zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL); zfcp_erp_wait(adapter); flush_work(&unit->scsi_work); - mutex_lock(&zfcp_data.config_mutex); out_unit: put_device(&port->sysfs_device); out_port: - kref_put(&adapter->ref, zfcp_adapter_release); -out_unlock: - mutex_unlock(&zfcp_data.config_mutex); -out_ccwdev: - put_device(&ccwdev->dev); + zfcp_ccw_adapter_put(adapter); +out_ccw_device: + put_device(&cdev->dev); return; } @@ -184,8 +178,6 @@ static int __init zfcp_module_init(void) if (!zfcp_data.gid_pn_cache) goto out_gid_cache; - mutex_init(&zfcp_data.config_mutex); - zfcp_data.scsi_transport_template = fc_attach_transport(&zfcp_transport_functions); if (!zfcp_data.scsi_transport_template) @@ -296,7 +288,6 @@ static void zfcp_unit_release(struct device *dev) * @port: pointer to port where unit is added * @fcp_lun: FCP LUN of unit to be enqueued * Returns: pointer to enqueued unit on success, ERR_PTR on error - * Locks: config_mutex must be held to serialize changes to the unit list * * Sets up some unit internal structures and creates sysfs entry. */ @@ -371,7 +362,6 @@ err_out: static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) { - /* must only be called with zfcp_data.config_mutex taken */ adapter->pool.erp_req = mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); if (!adapter->pool.erp_req) @@ -419,7 +409,6 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) { - /* zfcp_data.config_mutex must be held */ if (adapter->pool.erp_req) mempool_destroy(adapter->pool.erp_req); if (adapter->pool.scsi_req) @@ -501,24 +490,22 @@ static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter) * zfcp_adapter_enqueue - enqueue a new adapter to the list * @ccw_device: pointer to the struct cc_device * - * Returns: 0 if a new adapter was successfully enqueued - * -ENOMEM if alloc failed + * Returns: struct zfcp_adapter* * Enqueues an adapter at the end of the adapter list in the driver data. * All adapter internal structures are set up. * Proc-fs entries are also created. - * locks: config_mutex must be held to serialize changes to the adapter list */ -int zfcp_adapter_enqueue(struct ccw_device *ccw_device) +struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; if (!get_device(&ccw_device->dev)) - return -ENODEV; + return ERR_PTR(-ENODEV); adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); if (!adapter) { put_device(&ccw_device->dev); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } kref_init(&adapter->ref); @@ -578,11 +565,30 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); if (!zfcp_adapter_scsi_register(adapter)) - return 0; + return adapter; failed: - kref_put(&adapter->ref, zfcp_adapter_release); - return -ENOMEM; + zfcp_adapter_unregister(adapter); + return ERR_PTR(-ENOMEM); +} + +void zfcp_adapter_unregister(struct zfcp_adapter *adapter) +{ + struct ccw_device *cdev = adapter->ccw_device; + + cancel_work_sync(&adapter->scan_work); + cancel_work_sync(&adapter->stat_work); + zfcp_destroy_adapter_work_queue(adapter); + + zfcp_fc_wka_ports_force_offline(adapter->gs); + zfcp_adapter_scsi_unregister(adapter); + sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs); + + zfcp_erp_thread_kill(adapter); + zfcp_dbf_adapter_unregister(adapter->dbf); + zfcp_qdio_destroy(adapter->qdio); + + zfcp_ccw_adapter_put(adapter); /* final put to release */ } /** @@ -594,27 +600,16 @@ void zfcp_adapter_release(struct kref *ref) { struct zfcp_adapter *adapter = container_of(ref, struct zfcp_adapter, ref); - struct ccw_device *ccw_device = adapter->ccw_device; - - cancel_work_sync(&adapter->stat_work); - - zfcp_fc_wka_ports_force_offline(adapter->gs); - sysfs_remove_group(&ccw_device->dev.kobj, &zfcp_sysfs_adapter_attrs); - - dev_set_drvdata(&ccw_device->dev, NULL); + struct ccw_device *cdev = adapter->ccw_device; dev_set_drvdata(&adapter->ccw_device->dev, NULL); zfcp_fc_gs_destroy(adapter); - zfcp_erp_thread_kill(adapter); - zfcp_destroy_adapter_work_queue(adapter); - zfcp_dbf_adapter_unregister(adapter->dbf); zfcp_free_low_mem_buffers(adapter); - zfcp_qdio_destroy(adapter->qdio); kfree(adapter->req_list); kfree(adapter->fc_stats); kfree(adapter->stats_reset_data); kfree(adapter); - put_device(&ccw_device->dev); + put_device(&cdev->dev); } /** @@ -636,7 +631,7 @@ static void zfcp_port_release(struct device *dev) struct zfcp_port *port = container_of(dev, struct zfcp_port, sysfs_device); - kref_put(&port->adapter->ref, zfcp_adapter_release); + zfcp_ccw_adapter_put(port->adapter); kfree(port); } @@ -647,7 +642,6 @@ static void zfcp_port_release(struct device *dev) * @status: initial status for the port * @d_id: destination id of the remote port to be enqueued * Returns: pointer to enqueued port on success, ERR_PTR on error - * Locks: config_mutex must be held to serialize changes to the port list * * All port internal structures are set up and the sysfs entry is generated. * d_id is used to enqueue ports with a well known address like the Directory @@ -718,7 +712,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, err_out_put: device_unregister(&port->sysfs_device); err_out: - kref_put(&adapter->ref, zfcp_adapter_release); + zfcp_ccw_adapter_put(adapter); return ERR_PTR(retval); } diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index c89dbe25037..2433eaced20 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -13,20 +13,42 @@ #define ZFCP_MODEL_PRIV 0x4 +static DEFINE_SPINLOCK(zfcp_ccw_adapter_ref_lock); + +struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *cdev) +{ + struct zfcp_adapter *adapter; + unsigned long flags; + + spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags); + adapter = dev_get_drvdata(&cdev->dev); + if (adapter) + kref_get(&adapter->ref); + spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); + return adapter; +} + +void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter) +{ + unsigned long flags; + + spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags); + kref_put(&adapter->ref, zfcp_adapter_release); + spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); +} + static int zfcp_ccw_suspend(struct ccw_device *cdev) { - struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); if (!adapter) return 0; - mutex_lock(&zfcp_data.config_mutex); - zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); zfcp_erp_wait(adapter); - mutex_unlock(&zfcp_data.config_mutex); + zfcp_ccw_adapter_put(adapter); return 0; } @@ -34,7 +56,7 @@ static int zfcp_ccw_suspend(struct ccw_device *cdev) static int zfcp_ccw_activate(struct ccw_device *cdev) { - struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); if (!adapter) return 0; @@ -46,6 +68,8 @@ static int zfcp_ccw_activate(struct ccw_device *cdev) zfcp_erp_wait(adapter); flush_work(&adapter->scan_work); + zfcp_ccw_adapter_put(adapter); + return 0; } @@ -67,28 +91,28 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter) /** * zfcp_ccw_probe - probe function of zfcp driver - * @ccw_device: pointer to belonging ccw device + * @cdev: pointer to belonging ccw device * * This function gets called by the common i/o layer for each FCP * device found on the current system. This is only a stub to make cio * work: To only allocate adapter resources for devices actually used, * the allocation is deferred to the first call to ccw_set_online. */ -static int zfcp_ccw_probe(struct ccw_device *ccw_device) +static int zfcp_ccw_probe(struct ccw_device *cdev) { return 0; } /** * zfcp_ccw_remove - remove function of zfcp driver - * @ccw_device: pointer to belonging ccw device + * @cdev: pointer to belonging ccw device * * This function gets called by the common i/o layer and removes an adapter * from the system. Task of this function is to get rid of all units and * ports that belong to this adapter. And in addition all resources of this * adapter will be freed too. */ -static void zfcp_ccw_remove(struct ccw_device *ccw_device) +static void zfcp_ccw_remove(struct ccw_device *cdev) { struct zfcp_adapter *adapter; struct zfcp_port *port, *p; @@ -96,22 +120,12 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) LIST_HEAD(unit_remove_lh); LIST_HEAD(port_remove_lh); - ccw_device_set_offline(ccw_device); - - mutex_lock(&zfcp_data.config_mutex); - adapter = dev_get_drvdata(&ccw_device->dev); - mutex_unlock(&zfcp_data.config_mutex); + ccw_device_set_offline(cdev); + adapter = zfcp_ccw_adapter_by_cdev(cdev); if (!adapter) return; - cancel_work_sync(&adapter->scan_work); - - mutex_lock(&zfcp_data.config_mutex); - - /* this also removes the scsi devices, so call it first */ - zfcp_adapter_scsi_unregister(adapter); - write_lock_irq(&adapter->port_list_lock); list_for_each_entry_safe(port, p, &adapter->port_list, list) { write_lock(&port->unit_list_lock); @@ -126,7 +140,7 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) } atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); write_unlock_irq(&adapter->port_list_lock); - mutex_unlock(&zfcp_data.config_mutex); + zfcp_ccw_adapter_put(adapter); /* put from zfcp_ccw_adapter_by_cdev */ list_for_each_entry_safe(unit, u, &unit_remove_lh, list) zfcp_device_unregister(&unit->sysfs_device, @@ -136,12 +150,12 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) zfcp_device_unregister(&port->sysfs_device, &zfcp_sysfs_port_attrs); - kref_put(&adapter->ref, zfcp_adapter_release); + zfcp_adapter_unregister(adapter); } /** * zfcp_ccw_set_online - set_online function of zfcp driver - * @ccw_device: pointer to belonging ccw device + * @cdev: pointer to belonging ccw device * * This function gets called by the common i/o layer and sets an * adapter into state online. The first call will allocate all @@ -152,23 +166,20 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) * the SCSI stack, that the QDIO queues will be set up and that the * adapter will be opened. */ -static int zfcp_ccw_set_online(struct ccw_device *ccw_device) +static int zfcp_ccw_set_online(struct ccw_device *cdev) { - struct zfcp_adapter *adapter; - int ret = 0; - - mutex_lock(&zfcp_data.config_mutex); - adapter = dev_get_drvdata(&ccw_device->dev); + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); if (!adapter) { - ret = zfcp_adapter_enqueue(ccw_device); - if (ret) { - dev_err(&ccw_device->dev, + adapter = zfcp_adapter_enqueue(cdev); + + if (IS_ERR(adapter)) { + dev_err(&cdev->dev, "Setting up data structures for the " "FCP adapter failed\n"); - goto out; + return PTR_ERR(adapter); } - adapter = dev_get_drvdata(&ccw_device->dev); + kref_get(&adapter->ref); } /* initialize request counter */ @@ -180,58 +191,61 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "ccsonl2", NULL); zfcp_erp_wait(adapter); -out: - mutex_unlock(&zfcp_data.config_mutex); - if (!ret) - flush_work(&adapter->scan_work); - return ret; + + flush_work(&adapter->scan_work); + + zfcp_ccw_adapter_put(adapter); + return 0; } /** * zfcp_ccw_set_offline - set_offline function of zfcp driver - * @ccw_device: pointer to belonging ccw device + * @cdev: pointer to belonging ccw device * * This function gets called by the common i/o layer and sets an adapter * into state offline. */ -static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) +static int zfcp_ccw_set_offline(struct ccw_device *cdev) { - struct zfcp_adapter *adapter; + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); + + if (!adapter) + return 0; - mutex_lock(&zfcp_data.config_mutex); - adapter = dev_get_drvdata(&ccw_device->dev); zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); zfcp_erp_wait(adapter); - mutex_unlock(&zfcp_data.config_mutex); + + zfcp_ccw_adapter_put(adapter); return 0; } /** * zfcp_ccw_notify - ccw notify function - * @ccw_device: pointer to belonging ccw device + * @cdev: pointer to belonging ccw device * @event: indicates if adapter was detached or attached * * This function gets called by the common i/o layer if an adapter has gone * or reappeared. */ -static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) +static int zfcp_ccw_notify(struct ccw_device *cdev, int event) { - struct zfcp_adapter *adapter = dev_get_drvdata(&ccw_device->dev); + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); + + if (!adapter) + return 1; switch (event) { case CIO_GONE: - dev_warn(&adapter->ccw_device->dev, - "The FCP device has been detached\n"); + dev_warn(&cdev->dev, "The FCP device has been detached\n"); zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL); break; case CIO_NO_PATH: - dev_warn(&adapter->ccw_device->dev, + dev_warn(&cdev->dev, "The CHPID for the FCP device is offline\n"); zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL); break; case CIO_OPER: - dev_info(&adapter->ccw_device->dev, - "The FCP device is operational again\n"); + dev_info(&cdev->dev, "The FCP device is operational again\n"); zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); @@ -239,11 +253,13 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) "ccnoti4", NULL); break; case CIO_BOXED: - dev_warn(&adapter->ccw_device->dev, "The FCP device " - "did not respond within the specified time\n"); + dev_warn(&cdev->dev, "The FCP device did not respond within " + "the specified time\n"); zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); break; } + + zfcp_ccw_adapter_put(adapter); return 1; } @@ -253,18 +269,16 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) */ static void zfcp_ccw_shutdown(struct ccw_device *cdev) { - struct zfcp_adapter *adapter; + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); - mutex_lock(&zfcp_data.config_mutex); - adapter = dev_get_drvdata(&cdev->dev); if (!adapter) - goto out; + return; zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); zfcp_erp_wait(adapter); zfcp_erp_thread_kill(adapter); -out: - mutex_unlock(&zfcp_data.config_mutex); + + zfcp_ccw_adapter_put(adapter); } struct ccw_driver zfcp_ccw_driver = { diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index 856f82dbcb1..f932400e980 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -86,22 +86,17 @@ static int zfcp_cfdc_copy_to_user(void __user *user_buffer, static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno) { char busid[9]; - struct ccw_device *ccwdev; - struct zfcp_adapter *adapter = NULL; + struct ccw_device *cdev; + struct zfcp_adapter *adapter; snprintf(busid, sizeof(busid), "0.0.%04x", devno); - ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); - if (!ccwdev) - goto out; - - adapter = dev_get_drvdata(&ccwdev->dev); - if (!adapter) - goto out_put; - - kref_get(&adapter->ref); -out_put: - put_device(&ccwdev->dev); -out: + cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); + if (!cdev) + return NULL; + + adapter = zfcp_ccw_adapter_by_cdev(cdev); + + put_device(&cdev->dev); return adapter; } @@ -244,7 +239,7 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, free_sg: zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES); adapter_put: - kref_put(&adapter->ref, zfcp_adapter_release); + zfcp_ccw_adapter_put(adapter); free_buffer: kfree(data); no_mem_sense: diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 55dc402c3ae..7e84e1624d1 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -595,7 +595,6 @@ struct zfcp_fsf_req { struct zfcp_data { struct scsi_host_template scsi_host_template; struct scsi_transport_template *scsi_transport_template; - struct mutex config_mutex; struct kmem_cache *gpn_ft_cache; struct kmem_cache *qtcb_cache; struct kmem_cache *sr_buffer_cache; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 3106c3be639..1e3ec708505 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -14,7 +14,7 @@ /* zfcp_aux.c */ extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64); extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64); -extern int zfcp_adapter_enqueue(struct ccw_device *); +extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32, u32); extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64); @@ -24,11 +24,14 @@ extern int zfcp_sg_setup_table(struct scatterlist *, int); extern void zfcp_device_unregister(struct device *, const struct attribute_group *); extern void zfcp_adapter_release(struct kref *); +extern void zfcp_adapter_unregister(struct zfcp_adapter *); /* zfcp_ccw.c */ extern int zfcp_ccw_register(void); extern int zfcp_ccw_priv_sch(struct zfcp_adapter *); extern struct ccw_driver zfcp_ccw_driver; +extern struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *); +extern void zfcp_ccw_adapter_put(struct zfcp_adapter *); /* zfcp_cfdc.c */ extern struct miscdevice zfcp_cfdc_misc; diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 6fa1bcbec0a..3e3e72cc724 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -622,8 +622,6 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) return -E2BIG; } - mutex_lock(&zfcp_data.config_mutex); - /* first entry is the header */ for (x = 1; x < max_entries && !last; x++) { if (x % (ZFCP_GPN_FT_ENTRIES + 1)) @@ -655,7 +653,6 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) list_for_each_entry_safe(port, tmp, &adapter->port_list, list) zfcp_fc_validate_port(port, &remove_lh); write_unlock_irqrestore(&adapter->port_list_lock, flags); - mutex_unlock(&zfcp_data.config_mutex); list_for_each_entry_safe(port, tmp, &remove_lh, list) { zfcp_erp_port_shutdown(port, 0, "fcegpf2", NULL); diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index b4a7e17932c..181bea0f10f 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -26,23 +26,36 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \ static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \ zfcp_sysfs_##_feat##_##_name##_show, NULL); -ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, status, "0x%08x\n", - atomic_read(&adapter->status)); -ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwnn, "0x%016llx\n", - (unsigned long long) adapter->peer_wwnn); -ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwpn, "0x%016llx\n", - (unsigned long long) adapter->peer_wwpn); -ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_d_id, "0x%06x\n", - adapter->peer_d_id); -ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, card_version, "0x%04x\n", - adapter->hydra_version); -ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, lic_version, "0x%08x\n", - adapter->fsf_lic_version); -ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, hardware_version, "0x%08x\n", - adapter->hardware_version); -ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, in_recovery, "%d\n", - (atomic_read(&adapter->status) & - ZFCP_STATUS_COMMON_ERP_INUSE) != 0); +#define ZFCP_DEFINE_A_ATTR(_name, _format, _value) \ +static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \ + struct device_attribute *at,\ + char *buf) \ +{ \ + struct ccw_device *cdev = to_ccwdev(dev); \ + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); \ + int i; \ + \ + if (!adapter) \ + return -ENODEV; \ + \ + i = sprintf(buf, _format, _value); \ + zfcp_ccw_adapter_put(adapter); \ + return i; \ +} \ +static ZFCP_DEV_ATTR(adapter, _name, S_IRUGO, \ + zfcp_sysfs_adapter_##_name##_show, NULL); + +ZFCP_DEFINE_A_ATTR(status, "0x%08x\n", atomic_read(&adapter->status)); +ZFCP_DEFINE_A_ATTR(peer_wwnn, "0x%016llx\n", + (unsigned long long) adapter->peer_wwnn); +ZFCP_DEFINE_A_ATTR(peer_wwpn, "0x%016llx\n", + (unsigned long long) adapter->peer_wwpn); +ZFCP_DEFINE_A_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id); +ZFCP_DEFINE_A_ATTR(card_version, "0x%04x\n", adapter->hydra_version); +ZFCP_DEFINE_A_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version); +ZFCP_DEFINE_A_ATTR(hardware_version, "0x%08x\n", adapter->hardware_version); +ZFCP_DEFINE_A_ATTR(in_recovery, "%d\n", (atomic_read(&adapter->status) & + ZFCP_STATUS_COMMON_ERP_INUSE) != 0); ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n", atomic_read(&port->status)); @@ -88,7 +101,6 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ unsigned long val; \ int retval = 0; \ \ - mutex_lock(&zfcp_data.config_mutex); \ if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \ retval = -EBUSY; \ goto out; \ @@ -105,28 +117,89 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ _reopen_id, NULL); \ zfcp_erp_wait(_adapter); \ out: \ - mutex_unlock(&zfcp_data.config_mutex); \ return retval ? retval : (ssize_t) count; \ } \ static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \ zfcp_sysfs_##_feat##_failed_show, \ zfcp_sysfs_##_feat##_failed_store); -ZFCP_SYSFS_FAILED(zfcp_adapter, adapter, adapter, "syafai1", "syafai2"); ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, "sypfai1", "sypfai2"); ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, "syufai1", "syufai2"); +static ssize_t zfcp_sysfs_adapter_failed_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); + int i; + + if (!adapter) + return -ENODEV; + + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + i = sprintf(buf, "1\n"); + else + i = sprintf(buf, "0\n"); + + zfcp_ccw_adapter_put(adapter); + return i; +} + +static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); + unsigned long val; + int retval = 0; + + if (!adapter) + return -ENODEV; + + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { + retval = -EBUSY; + goto out; + } + + if (strict_strtoul(buf, 0, &val) || val != 0) { + retval = -EINVAL; + goto out; + } + + zfcp_erp_modify_adapter_status(adapter, "syafai1", NULL, + ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); + zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, + "syafai2", NULL); + zfcp_erp_wait(adapter); +out: + zfcp_ccw_adapter_put(adapter); + return retval ? retval : (ssize_t) count; +} +static ZFCP_DEV_ATTR(adapter, failed, S_IWUSR | S_IRUGO, + zfcp_sysfs_adapter_failed_show, + zfcp_sysfs_adapter_failed_store); + static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct zfcp_adapter *adapter = dev_get_drvdata(dev); + struct ccw_device *cdev = to_ccwdev(dev); + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); int ret; - if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) - return -EBUSY; + if (!adapter) + return -ENODEV; + + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { + ret = -EBUSY; + goto out; + } ret = zfcp_fc_scan_ports(adapter); +out: + zfcp_ccw_adapter_put(adapter); return ret ? ret : (ssize_t) count; } static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, @@ -136,12 +209,15 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct zfcp_adapter *adapter = dev_get_drvdata(dev); + struct ccw_device *cdev = to_ccwdev(dev); + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); struct zfcp_port *port; u64 wwpn; int retval = 0; - mutex_lock(&zfcp_data.config_mutex); + if (!adapter) + return -ENODEV; + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { retval = -EBUSY; goto out; @@ -169,7 +245,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL); zfcp_device_unregister(&port->sysfs_device, &zfcp_sysfs_port_attrs); out: - mutex_unlock(&zfcp_data.config_mutex); + zfcp_ccw_adapter_put(adapter); return retval ? retval : (ssize_t) count; } static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL, @@ -203,7 +279,6 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, u64 fcp_lun; int retval = -EINVAL; - mutex_lock(&zfcp_data.config_mutex); if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { retval = -EBUSY; goto out; @@ -222,7 +297,6 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, zfcp_erp_wait(unit->port->adapter); flush_work(&unit->scsi_work); out: - mutex_unlock(&zfcp_data.config_mutex); return retval ? retval : (ssize_t) count; } static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); @@ -236,7 +310,6 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, u64 fcp_lun; int retval = 0; - mutex_lock(&zfcp_data.config_mutex); if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { retval = -EBUSY; goto out; @@ -267,7 +340,6 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); zfcp_device_unregister(&unit->sysfs_device, &zfcp_sysfs_unit_attrs); out: - mutex_unlock(&zfcp_data.config_mutex); return retval ? retval : (ssize_t) count; } static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); -- cgit v1.2.3 From b42aeceb35c59484056b0eea81203a0911ebb50d Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 24 Nov 2009 16:54:01 +0100 Subject: [SCSI] zfcp: Remove suspend callback The callback for suspend is not required because it contains exactly the same functionality as the _set_offline routine does. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ccw.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 2433eaced20..ca8dffcd1e0 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -37,22 +37,6 @@ void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter) spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); } -static int zfcp_ccw_suspend(struct ccw_device *cdev) - -{ - struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); - - if (!adapter) - return 0; - - zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); - zfcp_erp_wait(adapter); - - zfcp_ccw_adapter_put(adapter); - - return 0; -} - static int zfcp_ccw_activate(struct ccw_device *cdev) { @@ -291,7 +275,7 @@ struct ccw_driver zfcp_ccw_driver = { .set_offline = zfcp_ccw_set_offline, .notify = zfcp_ccw_notify, .shutdown = zfcp_ccw_shutdown, - .freeze = zfcp_ccw_suspend, + .freeze = zfcp_ccw_set_offline, .thaw = zfcp_ccw_activate, .restore = zfcp_ccw_activate, }; -- cgit v1.2.3 From 25458eb791acf0e5e65183c5adb3918d8d71d756 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:02 +0100 Subject: [SCSI] zfcp: Access ports and units with container_of in sysfs code When accessing port and unit attributes, use container_of instead of dev_get_drvdata. This eliminates some code checker warnings about aliased access of data structures. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 2 -- drivers/s390/scsi/zfcp_sysfs.c | 15 ++++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index ed31bd0ff3f..baef2ec7482 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -319,7 +319,6 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) kfree(unit); goto err_out; } - dev_set_drvdata(&unit->sysfs_device, unit); retval = -EINVAL; /* mark unit unusable as long as sysfs registration is not complete */ @@ -688,7 +687,6 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, kfree(port); goto err_out; } - dev_set_drvdata(&port->sysfs_device, port); retval = -EINVAL; if (device_register(&port->sysfs_device)) { diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 181bea0f10f..901cc9a6ed2 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -19,7 +19,8 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \ struct device_attribute *at,\ char *buf) \ { \ - struct _feat_def *_feat = dev_get_drvdata(dev); \ + struct _feat_def *_feat = container_of(dev, struct _feat_def, \ + sysfs_device); \ \ return sprintf(buf, _format, _value); \ } \ @@ -86,7 +87,8 @@ static ssize_t zfcp_sysfs_##_feat##_failed_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - struct _feat_def *_feat = dev_get_drvdata(dev); \ + struct _feat_def *_feat = container_of(dev, struct _feat_def, \ + sysfs_device); \ \ if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \ return sprintf(buf, "1\n"); \ @@ -97,7 +99,8 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ struct device_attribute *attr,\ const char *buf, size_t count)\ { \ - struct _feat_def *_feat = dev_get_drvdata(dev); \ + struct _feat_def *_feat = container_of(dev, struct _feat_def, \ + sysfs_device); \ unsigned long val; \ int retval = 0; \ \ @@ -274,7 +277,8 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct zfcp_port *port = dev_get_drvdata(dev); + struct zfcp_port *port = container_of(dev, struct zfcp_port, + sysfs_device); struct zfcp_unit *unit; u64 fcp_lun; int retval = -EINVAL; @@ -305,7 +309,8 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct zfcp_port *port = dev_get_drvdata(dev); + struct zfcp_port *port = container_of(dev, struct zfcp_port, + sysfs_device); struct zfcp_unit *unit; u64 fcp_lun; int retval = 0; -- cgit v1.2.3 From d9742b42b5c76e2a3a39de0d187fac4f6852134e Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:03 +0100 Subject: [SCSI] zfcp: Merge trace code for fsf requests in one function The latencies traced per fsf request are traced for sysfs output and for blktrace, each in one function. Simplify the tracing code by merging both tracing functions into one. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 93 +++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 54 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 3aad7091628..5eb96052941 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -2109,64 +2109,52 @@ static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat) lat_rec->max = max(lat_rec->max, lat); } -static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req) +static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) { - struct fsf_qual_latency_info *lat_inf; - struct latency_cont *lat; + struct fsf_qual_latency_info *lat_in; + struct latency_cont *lat = NULL; struct zfcp_unit *unit = req->unit; + struct zfcp_blk_drv_data blktrc; + int ticks = req->adapter->timer_ticks; - lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info; + lat_in = &req->qtcb->prefix.prot_status_qual.latency_info; - switch (req->qtcb->bottom.io.data_direction) { - case FSF_DATADIR_READ: - lat = &unit->latencies.read; - break; - case FSF_DATADIR_WRITE: - lat = &unit->latencies.write; - break; - case FSF_DATADIR_CMND: - lat = &unit->latencies.cmd; - break; - default: - return; - } - - spin_lock(&unit->latencies.lock); - zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat); - zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat); - lat->counter++; - spin_unlock(&unit->latencies.lock); -} - -#ifdef CONFIG_BLK_DEV_IO_TRACE -static void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req) -{ - struct fsf_qual_latency_info *lat_inf; - struct scsi_cmnd *scsi_cmnd = (struct scsi_cmnd *)fsf_req->data; - struct request *req = scsi_cmnd->request; - struct zfcp_blk_drv_data trace; - int ticks = fsf_req->adapter->timer_ticks; + blktrc.flags = 0; + blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC; + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) + blktrc.flags |= ZFCP_BLK_REQ_ERROR; + blktrc.inb_usage = req->queue_req.qdio_inb_usage; + blktrc.outb_usage = req->queue_req.qdio_outb_usage; + + if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) { + blktrc.flags |= ZFCP_BLK_LAT_VALID; + blktrc.channel_lat = lat_in->channel_lat * ticks; + blktrc.fabric_lat = lat_in->fabric_lat * ticks; + + switch (req->qtcb->bottom.io.data_direction) { + case FSF_DATADIR_READ: + lat = &unit->latencies.read; + break; + case FSF_DATADIR_WRITE: + lat = &unit->latencies.write; + break; + case FSF_DATADIR_CMND: + lat = &unit->latencies.cmd; + break; + } - trace.flags = 0; - trace.magic = ZFCP_BLK_DRV_DATA_MAGIC; - if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) { - trace.flags |= ZFCP_BLK_LAT_VALID; - lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info; - trace.channel_lat = lat_inf->channel_lat * ticks; - trace.fabric_lat = lat_inf->fabric_lat * ticks; + if (lat) { + spin_lock(&unit->latencies.lock); + zfcp_fsf_update_lat(&lat->channel, lat_in->channel_lat); + zfcp_fsf_update_lat(&lat->fabric, lat_in->fabric_lat); + lat->counter++; + spin_unlock(&unit->latencies.lock); + } } - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) - trace.flags |= ZFCP_BLK_REQ_ERROR; - trace.inb_usage = fsf_req->queue_req.qdio_inb_usage; - trace.outb_usage = fsf_req->queue_req.qdio_outb_usage; - blk_add_driver_data(req->q, req, &trace, sizeof(trace)); -} -#else -static inline void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req) -{ + blk_add_driver_data(scsi->request->q, scsi->request, &blktrc, + sizeof(blktrc)); } -#endif static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) { @@ -2199,10 +2187,7 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) scpnt->result |= fcp_rsp_iu->scsi_status; - if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) - zfcp_fsf_req_latency(req); - - zfcp_fsf_trace_latency(req); + zfcp_fsf_req_trace(req, scpnt); if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { if (fcp_rsp_info[3] == RSP_CODE_GOOD) -- cgit v1.2.3 From c1fad4176464281e776022dee7d029144afbeb13 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:04 +0100 Subject: [SCSI] zfcp: Implement module unloading With the reference counting for zfcp data structures, it is now possible to implement module unloading again. Module unloading requires to free all data structures in the module exit function. This is done by unregistering zfcp from s390 cio and the SCSI midlayer first in the module exit function. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 15 ++++++++++++++- drivers/s390/scsi/zfcp_ccw.c | 11 ----------- drivers/s390/scsi/zfcp_ext.h | 1 - 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index baef2ec7482..12de1ce9a92 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -189,7 +189,7 @@ static int __init zfcp_module_init(void) goto out_misc; } - retval = zfcp_ccw_register(); + retval = ccw_driver_register(&zfcp_ccw_driver); if (retval) { pr_err("The zfcp device driver could not register with " "the common I/O layer\n"); @@ -218,6 +218,19 @@ out: module_init(zfcp_module_init); +static void __exit zfcp_module_exit(void) +{ + ccw_driver_unregister(&zfcp_ccw_driver); + misc_deregister(&zfcp_cfdc_misc); + fc_release_transport(zfcp_data.scsi_transport_template); + kmem_cache_destroy(zfcp_data.gid_pn_cache); + kmem_cache_destroy(zfcp_data.sr_buffer_cache); + kmem_cache_destroy(zfcp_data.qtcb_cache); + kmem_cache_destroy(zfcp_data.gpn_ft_cache); +} + +module_exit(zfcp_module_exit); + /** * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN * @port: pointer to port to search for unit diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index ca8dffcd1e0..4d35902a0cc 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -279,14 +279,3 @@ struct ccw_driver zfcp_ccw_driver = { .thaw = zfcp_ccw_activate, .restore = zfcp_ccw_activate, }; - -/** - * zfcp_ccw_register - ccw register function - * - * Registers the driver at the common i/o layer. This function will be called - * at module load time/system start. - */ -int __init zfcp_ccw_register(void) -{ - return ccw_driver_register(&zfcp_ccw_driver); -} diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 1e3ec708505..5f205f85e6f 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -27,7 +27,6 @@ extern void zfcp_adapter_release(struct kref *); extern void zfcp_adapter_unregister(struct zfcp_adapter *); /* zfcp_ccw.c */ -extern int zfcp_ccw_register(void); extern int zfcp_ccw_priv_sch(struct zfcp_adapter *); extern struct ccw_driver zfcp_ccw_driver; extern struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *); -- cgit v1.2.3 From 6b183334c23969d52d4d9f775da554480d05ca4d Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 24 Nov 2009 16:54:05 +0100 Subject: [SCSI] zfcp: Remove STATUS_COMMON_REMOVE flag as it is not required anymore The flag ZFCP_STATUS_COMMON_REMOVE was used to indicate that a resource is not ready to be used or about to be removed from the system. This is now better done by an improved list handling and therefore the additional indicator is not required anymore. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 27 +++++----------- drivers/s390/scsi/zfcp_ccw.c | 7 +---- drivers/s390/scsi/zfcp_def.h | 1 - drivers/s390/scsi/zfcp_erp.c | 6 ++-- drivers/s390/scsi/zfcp_fc.c | 1 - drivers/s390/scsi/zfcp_sysfs.c | 70 +++++++++++++----------------------------- 6 files changed, 34 insertions(+), 78 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 12de1ce9a92..6b94f8d0609 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -245,9 +245,9 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) read_lock_irqsave(&port->unit_list_lock, flags); list_for_each_entry(unit, &port->unit_list, list) - if ((unit->fcp_lun == fcp_lun) && - !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) { - get_device(&unit->sysfs_device); + if (unit->fcp_lun == fcp_lun) { + if (!get_device(&unit->sysfs_device)) + unit = NULL; read_unlock_irqrestore(&port->unit_list_lock, flags); return unit; } @@ -270,9 +270,9 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, read_lock_irqsave(&adapter->port_list_lock, flags); list_for_each_entry(port, &adapter->port_list, list) - if ((port->wwpn == wwpn) && - !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE)) { - get_device(&port->sysfs_device); + if (port->wwpn == wwpn) { + if (!get_device(&port->sysfs_device)) + port = NULL; read_unlock_irqrestore(&adapter->port_list_lock, flags); return port; } @@ -334,9 +334,6 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) } retval = -EINVAL; - /* mark unit unusable as long as sysfs registration is not complete */ - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); - INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); spin_lock_init(&unit->latencies.lock); @@ -360,7 +357,6 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) list_add_tail(&unit->list, &port->unit_list); write_unlock_irq(&port->unit_list_lock); - atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); return unit; @@ -565,17 +561,12 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) adapter->service_level.seq_print = zfcp_print_sl; - /* mark adapter unusable as long as sysfs registration is not complete */ - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); - dev_set_drvdata(&ccw_device->dev, adapter); if (sysfs_create_group(&ccw_device->dev.kobj, &zfcp_sysfs_adapter_attrs)) goto failed; - atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); - if (!zfcp_adapter_scsi_register(adapter)) return adapter; @@ -692,9 +683,6 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, port->sysfs_device.parent = &adapter->ccw_device->dev; port->sysfs_device.release = zfcp_port_release; - /* mark port unusable as long as sysfs registration is not complete */ - atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); - if (dev_set_name(&port->sysfs_device, "0x%016llx", (unsigned long long)wwpn)) { kfree(port); @@ -715,8 +703,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, list_add_tail(&port->list, &adapter->port_list); write_unlock_irq(&adapter->port_list_lock); - atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); - atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); + atomic_set_mask(status | ZFCP_STATUS_COMMON_RUNNING, &port->status); return port; diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 4d35902a0cc..c22cb72a5ae 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -113,16 +113,11 @@ static void zfcp_ccw_remove(struct ccw_device *cdev) write_lock_irq(&adapter->port_list_lock); list_for_each_entry_safe(port, p, &adapter->port_list, list) { write_lock(&port->unit_list_lock); - list_for_each_entry_safe(unit, u, &port->unit_list, list) { - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, - &unit->status); + list_for_each_entry_safe(unit, u, &port->unit_list, list) list_move(&unit->list, &unit_remove_lh); - } write_unlock(&port->unit_list_lock); - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); list_move(&port->list, &port_remove_lh); } - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); write_unlock_irq(&adapter->port_list_lock); zfcp_ccw_adapter_put(adapter); /* put from zfcp_ccw_adapter_by_cdev */ diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 7e84e1624d1..08fa31302f7 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -205,7 +205,6 @@ struct zfcp_ls_adisc { #define ZFCP_COMMON_FLAGS 0xfff00000 /* common status bits */ -#define ZFCP_STATUS_COMMON_REMOVE 0x80000000 #define ZFCP_STATUS_COMMON_RUNNING 0x40000000 #define ZFCP_STATUS_COMMON_ERP_FAILED 0x20000000 #define ZFCP_STATUS_COMMON_UNBLOCKED 0x10000000 diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 788fd3a4cd2..3454c2a3b6b 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -174,7 +174,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, switch (need) { case ZFCP_ERP_ACTION_REOPEN_UNIT: - get_device(&unit->sysfs_device); + if (!get_device(&unit->sysfs_device)) + return NULL; atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); erp_action = &unit->erp_action; if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) @@ -183,7 +184,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, case ZFCP_ERP_ACTION_REOPEN_PORT: case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - get_device(&port->sysfs_device); + if (!get_device(&port->sysfs_device)) + return NULL; zfcp_erp_action_dismiss_port(port); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); erp_action = &port->erp_action; diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 3e3e72cc724..9252b65a13a 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -589,7 +589,6 @@ static void zfcp_fc_validate_port(struct zfcp_port *port, struct list_head *lh) !list_empty(&port->unit_list)) return; - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); list_move_tail(&port->list, lh); } diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 901cc9a6ed2..35e920b4fd8 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -104,10 +104,8 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ unsigned long val; \ int retval = 0; \ \ - if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \ - retval = -EBUSY; \ - goto out; \ - } \ + if (!(_feat && get_device(&_feat->sysfs_device))) \ + return -EBUSY; \ \ if (strict_strtoul(buf, 0, &val) || val != 0) { \ retval = -EINVAL; \ @@ -120,6 +118,7 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ _reopen_id, NULL); \ zfcp_erp_wait(_adapter); \ out: \ + put_device(&_feat->sysfs_device); \ return retval ? retval : (ssize_t) count; \ } \ static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \ @@ -161,11 +160,6 @@ static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev, if (!adapter) return -ENODEV; - if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { - retval = -EBUSY; - goto out; - } - if (strict_strtoul(buf, 0, &val) || val != 0) { retval = -EINVAL; goto out; @@ -195,14 +189,9 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, if (!adapter) return -ENODEV; - if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { - ret = -EBUSY; - goto out; - } - ret = zfcp_fc_scan_ports(adapter); -out: zfcp_ccw_adapter_put(adapter); + return ret ? ret : (ssize_t) count; } static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, @@ -216,28 +205,19 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); struct zfcp_port *port; u64 wwpn; - int retval = 0; + int retval = -EINVAL; if (!adapter) return -ENODEV; - if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { - retval = -EBUSY; + if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) goto out; - } - - if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) { - retval = -EINVAL; - goto out; - } port = zfcp_get_port_by_wwpn(adapter, wwpn); - if (!port) { - retval = -ENXIO; + if (!port) goto out; - } - - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); + else + retval = 0; write_lock_irq(&adapter->port_list_lock); list_del(&port->list); @@ -283,10 +263,8 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, u64 fcp_lun; int retval = -EINVAL; - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { - retval = -EBUSY; - goto out; - } + if (!(port && get_device(&port->sysfs_device))) + return -EBUSY; if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) goto out; @@ -294,13 +272,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, unit = zfcp_unit_enqueue(port, fcp_lun); if (IS_ERR(unit)) goto out; - - retval = 0; + else + retval = 0; zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); zfcp_erp_wait(unit->port->adapter); flush_work(&unit->scsi_work); out: + put_device(&port->sysfs_device); return retval ? retval : (ssize_t) count; } static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); @@ -313,29 +292,23 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, sysfs_device); struct zfcp_unit *unit; u64 fcp_lun; - int retval = 0; + int retval = -EINVAL; - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { - retval = -EBUSY; - goto out; - } + if (!(port && get_device(&port->sysfs_device))) + return -EBUSY; - if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) { - retval = -EINVAL; + if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) goto out; - } unit = zfcp_get_unit_by_lun(port, fcp_lun); - if (!unit) { - retval = -EINVAL; + if (!unit) goto out; - } + else + retval = 0; /* wait for possible timeout during SCSI probe */ flush_work(&unit->scsi_work); - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); - write_lock_irq(&port->unit_list_lock); list_del(&unit->list); write_unlock_irq(&port->unit_list_lock); @@ -345,6 +318,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); zfcp_device_unregister(&unit->sysfs_device, &zfcp_sysfs_unit_attrs); out: + put_device(&port->sysfs_device); return retval ? retval : (ssize_t) count; } static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); -- cgit v1.2.3 From 9eae07ef6bb5988163d8bb82cd952905db47b721 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 24 Nov 2009 16:54:06 +0100 Subject: [SCSI] zfcp: Assign scheduled work to driver queue The port_scan work was scheduled to the work_queue provided by the kernel. This resulted on SMP systems to a likely situation that more than one scan_work were processed in parallel. This is not required and openes the possibility of race conditions between the removal of invalid ports and the enqueue of just scanned ports. This patch synchronizes the scan_work tasks by scheduling them to adapter local work_queue. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 2 +- drivers/s390/scsi/zfcp_erp.c | 2 +- drivers/s390/scsi/zfcp_ext.h | 3 +-- drivers/s390/scsi/zfcp_fc.c | 25 +++++++++---------------- drivers/s390/scsi/zfcp_fsf.c | 2 +- drivers/s390/scsi/zfcp_sysfs.c | 7 ++++--- 6 files changed, 17 insertions(+), 24 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 6b94f8d0609..107d3f2b6e9 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -522,7 +522,7 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) adapter->ccw_device = ccw_device; INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); - INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); + INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports); if (zfcp_qdio_setup(adapter)) goto failed; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 3454c2a3b6b..b51a11a82e6 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1197,7 +1197,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) case ZFCP_ERP_ACTION_REOPEN_ADAPTER: if (result == ZFCP_ERP_SUCCEEDED) { register_service_level(&adapter->service_level); - schedule_work(&adapter->scan_work); + queue_work(adapter->work_queue, &adapter->scan_work); } else unregister_service_level(&adapter->service_level); kref_put(&adapter->ref, zfcp_adapter_release); diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 5f205f85e6f..d372146af38 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -94,8 +94,7 @@ extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *, extern void zfcp_erp_timeout_handler(unsigned long); /* zfcp_fc.c */ -extern int zfcp_fc_scan_ports(struct zfcp_adapter *); -extern void _zfcp_fc_scan_ports_later(struct work_struct *); +extern void zfcp_fc_scan_ports(struct work_struct *); extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); extern void zfcp_fc_port_did_lookup(struct work_struct *); extern void zfcp_fc_trigger_did_lookup(struct zfcp_port *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 9252b65a13a..7d6b3cadfb7 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -184,7 +184,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) range_mask = rscn_range_mask[fcp_rscn_element->addr_format]; _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); } - schedule_work(&fsf_req->adapter->scan_work); + queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work); } static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) @@ -664,10 +664,12 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) /** * zfcp_fc_scan_ports - scan remote ports and attach new ports - * @adapter: pointer to struct zfcp_adapter + * @work: reference to scheduled work */ -int zfcp_fc_scan_ports(struct zfcp_adapter *adapter) +void zfcp_fc_scan_ports(struct work_struct *work) { + struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter, + scan_work); int ret, i; struct zfcp_gpn_ft *gpn_ft; int chain, max_entries, buf_num, max_bytes; @@ -679,17 +681,14 @@ int zfcp_fc_scan_ports(struct zfcp_adapter *adapter) if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT && fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) - return 0; + return; - ret = zfcp_fc_wka_port_get(&adapter->gs->ds); - if (ret) - return ret; + if (zfcp_fc_wka_port_get(&adapter->gs->ds)) + return; gpn_ft = zfcp_alloc_sg_env(buf_num); - if (!gpn_ft) { - ret = -ENOMEM; + if (!gpn_ft) goto out; - } for (i = 0; i < 3; i++) { ret = zfcp_fc_send_gpn_ft(gpn_ft, adapter, max_bytes); @@ -704,15 +703,9 @@ int zfcp_fc_scan_ports(struct zfcp_adapter *adapter) zfcp_free_sg_env(gpn_ft, buf_num); out: zfcp_fc_wka_port_put(&adapter->gs->ds); - return ret; } -void _zfcp_fc_scan_ports_later(struct work_struct *work) -{ - zfcp_fc_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); -} - struct zfcp_els_fc_job { struct zfcp_send_els els; struct fc_bsg_job *job; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 5eb96052941..b6f12c826b7 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -287,7 +287,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) zfcp_erp_adapter_access_changed(adapter, "fssrh_3", req); if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) - schedule_work(&adapter->scan_work); + queue_work(adapter->work_queue, &adapter->scan_work); break; case FSF_STATUS_READ_CFDC_UPDATED: zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req); diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 35e920b4fd8..f539e006683 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -184,15 +184,16 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, { struct ccw_device *cdev = to_ccwdev(dev); struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); - int ret; if (!adapter) return -ENODEV; - ret = zfcp_fc_scan_ports(adapter); + /* sync the user-space- with the kernel-invocation of scan_work */ + queue_work(adapter->work_queue, &adapter->scan_work); + flush_work(&adapter->scan_work); zfcp_ccw_adapter_put(adapter); - return ret ? ret : (ssize_t) count; + return (ssize_t) count; } static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, zfcp_sysfs_port_rescan_store); -- cgit v1.2.3 From 8830271c4819d86d8e87202a1fe8da0bb58912a2 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:07 +0100 Subject: [SCSI] zfcp: Dont fail SCSI commands when transitioning to blocked fc_rport If an error occurs that triggers the call to fc_remote_port_delete, ideally this call would happen before any I/O is passed back to the SCSI midlayer through scsi_done. The SCSI midlayer will retry the commands and fc_remote_port_chkready will return the correct status code. But with the delay between calling scsi_done in softirq context and the call to fc_remote_port_delete from the workqueue, there is a window where zfcp returns DID_ERROR. This leads to SCSI error recovery which then leads to offline SCSI devices since all recovery actions will fail with the rport now being blocked. In this window, zfcp has to return DID_IMM_RETRY just as the FC transport class would do in fc_remote_port_chkready for the blocked fc_rport. As soon as the fc_rport is BLOCKED, fc_remote_port_chkready will do the right thing. Additionally, there are two more cases to catch in zfcp_scsi_queuecommand: - After the port has been opened, the unit has to be opened. During this period I/O has to be retried. This can also be handled with DID_IMM_RETRY. - If the access to the unit fails, but the port is good, then this single unit cannot be accessed and I/O to this unit has to fail without involving the FC transport class. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_scsi.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 39a621d729e..0ecec9c1b49 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -112,12 +112,26 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, } status = atomic_read(&unit->status); - if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || - !(status & ZFCP_STATUS_COMMON_RUNNING))) { + if (unlikely(status & ZFCP_STATUS_COMMON_ERP_FAILED) && + !(atomic_read(&unit->port->status) & + ZFCP_STATUS_COMMON_ERP_FAILED)) { + /* only unit access denied, but port is good + * not covered by FC transport, have to fail here */ zfcp_scsi_command_fail(scpnt, DID_ERROR); return 0; } + if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) { + /* This could be either + * open unit pending: this is temporary, will result in + * open unit or ERP_FAILED, so retry command + * call to rport_delete pending: mimic retry from + * fc_remote_port_chkready until rport is BLOCKED + */ + zfcp_scsi_command_fail(scpnt, DID_IMM_RETRY); + return 0; + } + ret = zfcp_fsf_send_fcp_command_task(unit, scpnt); if (unlikely(ret == -EBUSY)) return SCSI_MLQUEUE_DEVICE_BUSY; -- cgit v1.2.3 From 4318e08c84e4916ac463002ffb7f9901ddb3c385 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:08 +0100 Subject: [SCSI] zfcp: Update FCP protocol related code Use common data structures for FCP CMND, FCP RSP and related definitions and remove zfcp private definitions. Split the FCP CMND setup and FCP RSP evaluation code in seperate functions. Use inline functions to not negatively impact the I/O path. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 35 +++++++------ drivers/s390/scsi/zfcp_dbf.h | 3 +- drivers/s390/scsi/zfcp_def.h | 57 --------------------- drivers/s390/scsi/zfcp_ext.h | 1 - drivers/s390/scsi/zfcp_fc.h | 112 ++++++++++++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_fsf.c | 97 +++++++----------------------------- drivers/s390/scsi/zfcp_scsi.c | 20 ++------ 7 files changed, 156 insertions(+), 169 deletions(-) create mode 100644 drivers/s390/scsi/zfcp_fc.h (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index fe818cd29dc..21e5316e500 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -870,8 +870,9 @@ void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level, struct zfcp_dbf_scsi_record *rec = &dbf->scsi_buf; struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec; unsigned long flags; - struct fcp_rsp_iu *fcp_rsp; - char *fcp_rsp_info = NULL, *fcp_sns_info = NULL; + struct fcp_resp_with_ext *fcp_rsp; + struct fcp_resp_rsp_info *fcp_rsp_info = NULL; + char *fcp_sns_info = NULL; int offset = 0, buflen = 0; spin_lock_irqsave(&dbf->scsi_lock, flags); @@ -895,20 +896,22 @@ void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level, rec->scsi_allowed = scsi_cmnd->allowed; } if (fsf_req != NULL) { - fcp_rsp = (struct fcp_rsp_iu *) - &(fsf_req->qtcb->bottom.io.fcp_rsp); - fcp_rsp_info = (unsigned char *) &fcp_rsp[1]; - fcp_sns_info = - zfcp_get_fcp_sns_info_ptr(fcp_rsp); - - rec->rsp_validity = fcp_rsp->validity.value; - rec->rsp_scsi_status = fcp_rsp->scsi_status; - rec->rsp_resid = fcp_rsp->fcp_resid; - if (fcp_rsp->validity.bits.fcp_rsp_len_valid) - rec->rsp_code = *(fcp_rsp_info + 3); - if (fcp_rsp->validity.bits.fcp_sns_len_valid) { - buflen = min((int)fcp_rsp->fcp_sns_len, - ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO); + fcp_rsp = (struct fcp_resp_with_ext *) + &(fsf_req->qtcb->bottom.io.fcp_rsp); + fcp_rsp_info = (struct fcp_resp_rsp_info *) + &fcp_rsp[1]; + fcp_sns_info = (char *) &fcp_rsp[1]; + if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) + fcp_sns_info += fcp_rsp->ext.fr_sns_len; + + rec->rsp_validity = fcp_rsp->resp.fr_flags; + rec->rsp_scsi_status = fcp_rsp->resp.fr_status; + rec->rsp_resid = fcp_rsp->ext.fr_resid; + if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) + rec->rsp_code = fcp_rsp_info->rsp_code; + if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) { + buflen = min(fcp_rsp->ext.fr_sns_len, + (u32)ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO); rec->sns_info_len = buflen; memcpy(rec->sns_info, fcp_sns_info, min(buflen, diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 6b1461e8f84..c3e25702df5 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -22,6 +22,7 @@ #ifndef ZFCP_DBF_H #define ZFCP_DBF_H +#include #include "zfcp_ext.h" #include "zfcp_fsf.h" #include "zfcp_def.h" @@ -343,7 +344,7 @@ static inline void zfcp_dbf_scsi_devreset(const char *tag, u8 flag, struct zfcp_unit *unit, struct scsi_cmnd *scsi_cmnd) { - zfcp_dbf_scsi(flag == FCP_TARGET_RESET ? "trst" : "lrst", tag, 1, + zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1, unit->port->adapter->dbf, scsi_cmnd, NULL, 0); } diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 08fa31302f7..0317e7f2085 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -73,65 +73,8 @@ /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/ -/* task attribute values in FCP-2 FCP_CMND IU */ -#define SIMPLE_Q 0 -#define HEAD_OF_Q 1 -#define ORDERED_Q 2 -#define ACA_Q 4 -#define UNTAGGED 5 - -/* task management flags in FCP-2 FCP_CMND IU */ -#define FCP_CLEAR_ACA 0x40 -#define FCP_TARGET_RESET 0x20 -#define FCP_LOGICAL_UNIT_RESET 0x10 -#define FCP_CLEAR_TASK_SET 0x04 -#define FCP_ABORT_TASK_SET 0x02 - -#define FCP_CDB_LENGTH 16 - #define ZFCP_DID_MASK 0x00FFFFFF -/* FCP(-2) FCP_CMND IU */ -struct fcp_cmnd_iu { - u64 fcp_lun; /* FCP logical unit number */ - u8 crn; /* command reference number */ - u8 reserved0:5; /* reserved */ - u8 task_attribute:3; /* task attribute */ - u8 task_management_flags; /* task management flags */ - u8 add_fcp_cdb_length:6; /* additional FCP_CDB length */ - u8 rddata:1; /* read data */ - u8 wddata:1; /* write data */ - u8 fcp_cdb[FCP_CDB_LENGTH]; -} __attribute__((packed)); - -/* FCP(-2) FCP_RSP IU */ -struct fcp_rsp_iu { - u8 reserved0[10]; - union { - struct { - u8 reserved1:3; - u8 fcp_conf_req:1; - u8 fcp_resid_under:1; - u8 fcp_resid_over:1; - u8 fcp_sns_len_valid:1; - u8 fcp_rsp_len_valid:1; - } bits; - u8 value; - } validity; - u8 scsi_status; - u32 fcp_resid; - u32 fcp_sns_len; - u32 fcp_rsp_len; -} __attribute__((packed)); - - -#define RSP_CODE_GOOD 0 -#define RSP_CODE_LENGTH_MISMATCH 1 -#define RSP_CODE_FIELD_INVALID 2 -#define RSP_CODE_RO_MISMATCH 3 -#define RSP_CODE_TASKMAN_UNSUPP 4 -#define RSP_CODE_TASKMAN_FAILED 5 - /* see fc-fs */ #define LS_RSCN 0x61 #define LS_LOGO 0x05 diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index d372146af38..3832fe0ae2e 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -154,7 +154,6 @@ extern void zfcp_qdio_close(struct zfcp_qdio *); extern struct zfcp_data zfcp_data; extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); -extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); extern struct fc_function_template zfcp_transport_functions; extern void zfcp_scsi_rport_work(struct work_struct *); extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h new file mode 100644 index 00000000000..814fc2d2525 --- /dev/null +++ b/drivers/s390/scsi/zfcp_fc.h @@ -0,0 +1,112 @@ +/* + * zfcp device driver + * + * Fibre Channel related definitions and inline functions for the zfcp + * device driver + * + * Copyright IBM Corporation 2009 + */ + +#ifndef ZFCP_FC_H +#define ZFCP_FC_H + +#include +#include +#include + +/** + * zfcp_fc_scsi_to_fcp - setup FCP command with data from scsi_cmnd + * @fcp: fcp_cmnd to setup + * @scsi: scsi_cmnd where to get LUN, task attributes/flags and CDB + */ +static inline +void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi) +{ + char tag[2]; + + int_to_scsilun(scsi->device->lun, (struct scsi_lun *) &fcp->fc_lun); + + if (scsi_populate_tag_msg(scsi, tag)) { + switch (tag[0]) { + case MSG_ORDERED_TAG: + fcp->fc_pri_ta |= FCP_PTA_ORDERED; + break; + case MSG_SIMPLE_TAG: + fcp->fc_pri_ta |= FCP_PTA_SIMPLE; + break; + }; + } else + fcp->fc_pri_ta = FCP_PTA_SIMPLE; + + if (scsi->sc_data_direction == DMA_FROM_DEVICE) + fcp->fc_flags |= FCP_CFL_RDDATA; + if (scsi->sc_data_direction == DMA_TO_DEVICE) + fcp->fc_flags |= FCP_CFL_WRDATA; + + memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len); + + fcp->fc_dl = scsi_bufflen(scsi); +} + +/** + * zfcp_fc_fcp_tm - setup FCP command as task management command + * @fcp: fcp_cmnd to setup + * @dev: scsi_device where to send the task management command + * @tm: task management flags to setup tm command + */ +static inline +void zfcp_fc_fcp_tm(struct fcp_cmnd *fcp, struct scsi_device *dev, u8 tm_flags) +{ + int_to_scsilun(dev->lun, (struct scsi_lun *) &fcp->fc_lun); + fcp->fc_tm_flags |= tm_flags; +} + +/** + * zfcp_fc_evap_fcp_rsp - evaluate FCP RSP IU and update scsi_cmnd accordingly + * @fcp_rsp: FCP RSP IU to evaluate + * @scsi: SCSI command where to update status and sense buffer + */ +static inline +void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp, + struct scsi_cmnd *scsi) +{ + struct fcp_resp_rsp_info *rsp_info; + char *sense; + u32 sense_len, resid; + u8 rsp_flags; + + set_msg_byte(scsi, COMMAND_COMPLETE); + scsi->result |= fcp_rsp->resp.fr_status; + + rsp_flags = fcp_rsp->resp.fr_flags; + + if (unlikely(rsp_flags & FCP_RSP_LEN_VAL)) { + rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; + if (rsp_info->rsp_code == FCP_TMF_CMPL) + set_host_byte(scsi, DID_OK); + else { + set_host_byte(scsi, DID_ERROR); + return; + } + } + + if (unlikely(rsp_flags & FCP_SNS_LEN_VAL)) { + sense = (char *) &fcp_rsp[1]; + if (rsp_flags & FCP_RSP_LEN_VAL) + sense += fcp_rsp->ext.fr_sns_len; + sense_len = min(fcp_rsp->ext.fr_sns_len, + (u32) SCSI_SENSE_BUFFERSIZE); + memcpy(scsi->sense_buffer, sense, sense_len); + } + + if (unlikely(rsp_flags & FCP_RESID_UNDER)) { + resid = fcp_rsp->ext.fr_resid; + scsi_set_resid(scsi, resid); + if (scsi_bufflen(scsi) - resid < scsi->underflow && + !(rsp_flags & FCP_SNS_LEN_VAL) && + fcp_rsp->resp.fr_status == SAM_STAT_GOOD) + set_host_byte(scsi, DID_ERROR); + } +} + +#endif diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index b6f12c826b7..5f4cd03797e 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -11,6 +11,7 @@ #include #include "zfcp_ext.h" +#include "zfcp_fc.h" #include "zfcp_dbf.h" static void zfcp_fsf_request_timeout_handler(unsigned long data) @@ -2159,10 +2160,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) { struct scsi_cmnd *scpnt; - struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) - &(req->qtcb->bottom.io.fcp_rsp); - u32 sns_len; - char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; + struct fcp_resp_with_ext *fcp_rsp; unsigned long flags; read_lock_irqsave(&req->adapter->abort_lock, flags); @@ -2183,37 +2181,11 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) goto skip_fsfstatus; } - set_msg_byte(scpnt, COMMAND_COMPLETE); - - scpnt->result |= fcp_rsp_iu->scsi_status; + fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; + zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt); zfcp_fsf_req_trace(req, scpnt); - if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { - if (fcp_rsp_info[3] == RSP_CODE_GOOD) - set_host_byte(scpnt, DID_OK); - else { - set_host_byte(scpnt, DID_ERROR); - goto skip_fsfstatus; - } - } - - if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) { - sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) + - fcp_rsp_iu->fcp_rsp_len; - sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE); - sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len); - - memcpy(scpnt->sense_buffer, - zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len); - } - - if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { - scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid); - if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) < - scpnt->underflow) - set_host_byte(scpnt, DID_ERROR); - } skip_fsfstatus: if (scpnt->result != 0) zfcp_dbf_scsi_result("erro", 3, req->adapter->dbf, scpnt, req); @@ -2235,11 +2207,13 @@ skip_fsfstatus: static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req) { - struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) - &(req->qtcb->bottom.io.fcp_rsp); - char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; + struct fcp_resp_with_ext *fcp_rsp; + struct fcp_resp_rsp_info *rsp_info; - if ((fcp_rsp_info[3] != RSP_CODE_GOOD) || + fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; + rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; + + if ((rsp_info->rsp_code != FCP_TMF_CMPL) || (req->status & ZFCP_STATUS_FSFREQ_ERROR)) req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; } @@ -2324,20 +2298,6 @@ skip_fsfstatus: } } -static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl) -{ - u32 *fcp_dl_ptr; - - /* - * fcp_dl_addr = start address of fcp_cmnd structure + - * size of fixed part + size of dynamically sized add_dcp_cdb field - * SEE FCP-2 documentation - */ - fcp_dl_ptr = (u32 *) ((unsigned char *) &fcp_cmd[1] + - (fcp_cmd->add_fcp_cdb_length << 2)); - *fcp_dl_ptr = fcp_dl; -} - /** * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) * @unit: unit where command is sent to @@ -2347,7 +2307,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, struct scsi_cmnd *scsi_cmnd) { struct zfcp_fsf_req *req; - struct fcp_cmnd_iu *fcp_cmnd_iu; + struct fcp_cmnd *fcp_cmnd; unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; int real_bytes, retval = -EIO; struct zfcp_adapter *adapter = unit->port->adapter; @@ -2379,16 +2339,14 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, req->qtcb->header.lun_handle = unit->handle; req->qtcb->header.port_handle = unit->port->handle; req->qtcb->bottom.io.service_class = FSF_CLASS_3; + req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN; scsi_cmnd->host_scribble = (unsigned char *) req->req_id; - fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd); - fcp_cmnd_iu->fcp_lun = unit->fcp_lun; /* * set depending on data direction: * data direction bits in SBALE (SB Type) * data direction bits in QTCB - * data direction bits in FCP_CMND IU */ switch (scsi_cmnd->sc_data_direction) { case DMA_NONE: @@ -2396,32 +2354,17 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, break; case DMA_FROM_DEVICE: req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; - fcp_cmnd_iu->rddata = 1; break; case DMA_TO_DEVICE: req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; sbtype = SBAL_FLAGS0_TYPE_WRITE; - fcp_cmnd_iu->wddata = 1; break; case DMA_BIDIRECTIONAL: goto failed_scsi_cmnd; } - if (likely((scsi_cmnd->device->simple_tags) || - ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) && - (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED)))) - fcp_cmnd_iu->task_attribute = SIMPLE_Q; - else - fcp_cmnd_iu->task_attribute = UNTAGGED; - - if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) - fcp_cmnd_iu->add_fcp_cdb_length = - (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; - - memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); - - req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + - fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32); + fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; + zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd); real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req, sbtype, scsi_sglist(scsi_cmnd), @@ -2439,8 +2382,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, goto failed_scsi_cmnd; } - zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); - retval = zfcp_fsf_req_send(req); if (unlikely(retval)) goto failed_scsi_cmnd; @@ -2466,7 +2407,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) { struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req = NULL; - struct fcp_cmnd_iu *fcp_cmnd_iu; + struct fcp_cmnd *fcp_cmnd; struct zfcp_qdio *qdio = unit->port->adapter->qdio; if (unlikely(!(atomic_read(&unit->status) & @@ -2492,16 +2433,14 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) req->qtcb->header.port_handle = unit->port->handle; req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; req->qtcb->bottom.io.service_class = FSF_CLASS_3; - req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + - sizeof(u32); + req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN; sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd; - fcp_cmnd_iu->fcp_lun = unit->fcp_lun; - fcp_cmnd_iu->task_management_flags = tm_flags; + fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; + zfcp_fc_fcp_tm(fcp_cmnd, unit->device, tm_flags); zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); if (!zfcp_fsf_req_send(req)) diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 0ecec9c1b49..3d168410036 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -9,6 +9,8 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include +#include #include #include "zfcp_ext.h" #include "zfcp_dbf.h" @@ -17,18 +19,6 @@ static unsigned int default_depth = 32; module_param_named(queue_depth, default_depth, uint, 0600); MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices"); -/* Find start of Sense Information in FCP response unit*/ -char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) -{ - char *fcp_sns_info_ptr; - - fcp_sns_info_ptr = (unsigned char *) &fcp_rsp_iu[1]; - if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid) - fcp_sns_info_ptr += fcp_rsp_iu->fcp_rsp_len; - - return fcp_sns_info_ptr; -} - static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason) { @@ -283,12 +273,12 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) { - return zfcp_task_mgmt_function(scpnt, FCP_LOGICAL_UNIT_RESET); + return zfcp_task_mgmt_function(scpnt, FCP_TMF_LUN_RESET); } static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) { - return zfcp_task_mgmt_function(scpnt, FCP_TARGET_RESET); + return zfcp_task_mgmt_function(scpnt, FCP_TMF_TGT_RESET); } static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) @@ -325,7 +315,7 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) adapter->scsi_host->max_lun = 1; adapter->scsi_host->max_channel = 0; adapter->scsi_host->unique_id = dev_id.devno; - adapter->scsi_host->max_cmd_len = 255; + adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */ adapter->scsi_host->transportt = zfcp_data.scsi_transport_template; adapter->scsi_host->hostdata[0] = (unsigned long) adapter; -- cgit v1.2.3 From 9d05ce2c0a6704ff84df02cbb3baef94fcac4f5d Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:09 +0100 Subject: [SCSI] zfcp: Use common code definitions for FC ELS structs Use common code definitions for FC plogi, logo, rscn and adisc structs instead of inventing private ones. Move the private struct for issuing ELS ADISC inside zfcp to zfcp_fc header file. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 45 --------------- drivers/s390/scsi/zfcp_ext.h | 4 +- drivers/s390/scsi/zfcp_fc.c | 131 ++++++++++++++++++++++--------------------- drivers/s390/scsi/zfcp_fc.h | 17 ++++++ drivers/s390/scsi/zfcp_fsf.c | 45 +++++++-------- drivers/s390/scsi/zfcp_fsf.h | 20 +------ 6 files changed, 108 insertions(+), 154 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 0317e7f2085..fae8f2ebd43 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -75,51 +75,6 @@ #define ZFCP_DID_MASK 0x00FFFFFF -/* see fc-fs */ -#define LS_RSCN 0x61 -#define LS_LOGO 0x05 -#define LS_PLOGI 0x03 - -struct fcp_rscn_head { - u8 command; - u8 page_length; /* always 0x04 */ - u16 payload_len; -} __attribute__((packed)); - -struct fcp_rscn_element { - u8 reserved:2; - u8 event_qual:4; - u8 addr_format:2; - u32 nport_did:24; -} __attribute__((packed)); - -/* see fc-ph */ -struct fcp_logo { - u32 command; - u32 nport_did; - u64 nport_wwpn; -} __attribute__((packed)); - -/* - * FC-FS stuff - */ -#define R_A_TOV 10 /* seconds */ - -#define ZFCP_LS_RLS 0x0f -#define ZFCP_LS_ADISC 0x52 -#define ZFCP_LS_RPS 0x56 -#define ZFCP_LS_RSCN 0x61 -#define ZFCP_LS_RNID 0x78 - -struct zfcp_ls_adisc { - u8 code; - u8 field[3]; - u32 hard_nport_id; - u64 wwpn; - u64 wwnn; - u32 nport_id; -} __attribute__ ((packed)); - /* * FC-GS-2 stuff */ diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 3832fe0ae2e..c2b23b5a3d0 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -9,6 +9,8 @@ #ifndef ZFCP_EXT_H #define ZFCP_EXT_H +#include +#include #include "zfcp_def.h" /* zfcp_aux.c */ @@ -98,7 +100,7 @@ extern void zfcp_fc_scan_ports(struct work_struct *); extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); extern void zfcp_fc_port_did_lookup(struct work_struct *); extern void zfcp_fc_trigger_did_lookup(struct zfcp_port *); -extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); +extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fc_els_flogi *); extern void zfcp_fc_test_link(struct zfcp_port *); extern void zfcp_fc_link_test_work(struct work_struct *); extern void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 7d6b3cadfb7..e03410043cd 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -9,20 +9,17 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include +#include +#include #include "zfcp_ext.h" +#include "zfcp_fc.h" -enum rscn_address_format { - RSCN_PORT_ADDRESS = 0x0, - RSCN_AREA_ADDRESS = 0x1, - RSCN_DOMAIN_ADDRESS = 0x2, - RSCN_FABRIC_ADDRESS = 0x3, -}; - -static u32 rscn_range_mask[] = { - [RSCN_PORT_ADDRESS] = 0xFFFFFF, - [RSCN_AREA_ADDRESS] = 0xFFFF00, - [RSCN_DOMAIN_ADDRESS] = 0xFF0000, - [RSCN_FABRIC_ADDRESS] = 0x000000, +static u32 zfcp_fc_rscn_range_mask[] = { + [ELS_ADDR_FMT_PORT] = 0xFFFFFF, + [ELS_ADDR_FMT_AREA] = 0xFFFF00, + [ELS_ADDR_FMT_DOM] = 0xFF0000, + [ELS_ADDR_FMT_FAB] = 0x000000, }; struct gpn_ft_resp_acc { @@ -144,7 +141,7 @@ void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs) } static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, - struct fcp_rscn_element *elem) + struct fc_els_rscn_page *page) { unsigned long flags; struct zfcp_adapter *adapter = fsf_req->adapter; @@ -152,7 +149,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, read_lock_irqsave(&adapter->port_list_lock, flags); list_for_each_entry(port, &adapter->port_list, list) { - if ((port->d_id & range) == (elem->nport_did & range)) + if ((port->d_id & range) == (ntoh24(page->rscn_fid) & range)) zfcp_fc_test_link(port); if (!port->d_id) zfcp_erp_port_reopen(port, @@ -165,24 +162,24 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) { struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data; - struct fcp_rscn_head *fcp_rscn_head; - struct fcp_rscn_element *fcp_rscn_element; + struct fc_els_rscn *head; + struct fc_els_rscn_page *page; u16 i; u16 no_entries; - u32 range_mask; + unsigned int afmt; - fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload.data; - fcp_rscn_element = (struct fcp_rscn_element *) fcp_rscn_head; + head = (struct fc_els_rscn *) status_buffer->payload.data; + page = (struct fc_els_rscn_page *) head; /* see FC-FS */ - no_entries = fcp_rscn_head->payload_len / - sizeof(struct fcp_rscn_element); + no_entries = head->rscn_plen / sizeof(struct fc_els_rscn_page); for (i = 1; i < no_entries; i++) { /* skip head and start with 1st element */ - fcp_rscn_element++; - range_mask = rscn_range_mask[fcp_rscn_element->addr_format]; - _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); + page++; + afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK; + _zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt], + page); } queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work); } @@ -204,22 +201,22 @@ static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) { - struct fsf_status_read_buffer *status_buffer = - (struct fsf_status_read_buffer *)req->data; - struct fsf_plogi *els_plogi = - (struct fsf_plogi *) status_buffer->payload.data; + struct fsf_status_read_buffer *status_buffer; + struct fc_els_flogi *plogi; - zfcp_fc_incoming_wwpn(req, els_plogi->serv_param.wwpn); + status_buffer = (struct fsf_status_read_buffer *) req->data; + plogi = (struct fc_els_flogi *) status_buffer->payload.data; + zfcp_fc_incoming_wwpn(req, plogi->fl_wwpn); } static void zfcp_fc_incoming_logo(struct zfcp_fsf_req *req) { struct fsf_status_read_buffer *status_buffer = (struct fsf_status_read_buffer *)req->data; - struct fcp_logo *els_logo = - (struct fcp_logo *) status_buffer->payload.data; + struct fc_els_logo *logo = + (struct fc_els_logo *) status_buffer->payload.data; - zfcp_fc_incoming_wwpn(req, els_logo->nport_wwpn); + zfcp_fc_incoming_wwpn(req, logo->fl_n_port_wwn); } /** @@ -233,11 +230,11 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req) unsigned int els_type = status_buffer->payload.data[0]; zfcp_dbf_san_incoming_els(fsf_req); - if (els_type == LS_PLOGI) + if (els_type == ELS_PLOGI) zfcp_fc_incoming_plogi(fsf_req); - else if (els_type == LS_LOGO) + else if (els_type == ELS_LOGO) zfcp_fc_incoming_logo(fsf_req); - else if (els_type == LS_RSCN) + else if (els_type == ELS_RSCN) zfcp_fc_incoming_rscn(fsf_req); } @@ -379,33 +376,36 @@ void zfcp_fc_trigger_did_lookup(struct zfcp_port *port) * * Evaluate PLOGI playload and copy important fields into zfcp_port structure */ -void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) -{ - port->maxframe_size = plogi->serv_param.common_serv_param[7] | - ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); - if (plogi->serv_param.class1_serv_param[0] & 0x80) +void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fc_els_flogi *plogi) +{ + if (plogi->fl_wwpn != port->wwpn) { + port->d_id = 0; + dev_warn(&port->adapter->ccw_device->dev, + "A port opened with WWPN 0x%016Lx returned data that " + "identifies it as WWPN 0x%016Lx\n", + (unsigned long long) port->wwpn, + (unsigned long long) plogi->fl_wwpn); + return; + } + + port->wwnn = plogi->fl_wwnn; + port->maxframe_size = plogi->fl_csp.sp_bb_data; + + if (plogi->fl_cssp[0].cp_class & FC_CPC_VALID) port->supported_classes |= FC_COS_CLASS1; - if (plogi->serv_param.class2_serv_param[0] & 0x80) + if (plogi->fl_cssp[1].cp_class & FC_CPC_VALID) port->supported_classes |= FC_COS_CLASS2; - if (plogi->serv_param.class3_serv_param[0] & 0x80) + if (plogi->fl_cssp[2].cp_class & FC_CPC_VALID) port->supported_classes |= FC_COS_CLASS3; - if (plogi->serv_param.class4_serv_param[0] & 0x80) + if (plogi->fl_cssp[3].cp_class & FC_CPC_VALID) port->supported_classes |= FC_COS_CLASS4; } -struct zfcp_els_adisc { - struct zfcp_send_els els; - struct scatterlist req; - struct scatterlist resp; - struct zfcp_ls_adisc ls_adisc; - struct zfcp_ls_adisc ls_adisc_acc; -}; - static void zfcp_fc_adisc_handler(unsigned long data) { - struct zfcp_els_adisc *adisc = (struct zfcp_els_adisc *) data; + struct zfcp_fc_els_adisc *adisc = (struct zfcp_fc_els_adisc *) data; struct zfcp_port *port = adisc->els.port; - struct zfcp_ls_adisc *ls_adisc = &adisc->ls_adisc_acc; + struct fc_els_adisc *adisc_resp = &adisc->adisc_resp; if (adisc->els.status) { /* request rejected or timed out */ @@ -415,9 +415,9 @@ static void zfcp_fc_adisc_handler(unsigned long data) } if (!port->wwnn) - port->wwnn = ls_adisc->wwnn; + port->wwnn = adisc_resp->adisc_wwnn; - if ((port->wwpn != ls_adisc->wwpn) || + if ((port->wwpn != adisc_resp->adisc_wwpn) || !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) { zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "fcadh_2", NULL); @@ -434,32 +434,33 @@ static void zfcp_fc_adisc_handler(unsigned long data) static int zfcp_fc_adisc(struct zfcp_port *port) { - struct zfcp_els_adisc *adisc; + struct zfcp_fc_els_adisc *adisc; struct zfcp_adapter *adapter = port->adapter; - adisc = kzalloc(sizeof(struct zfcp_els_adisc), GFP_ATOMIC); + adisc = kzalloc(sizeof(struct zfcp_fc_els_adisc), GFP_ATOMIC); if (!adisc) return -ENOMEM; adisc->els.req = &adisc->req; adisc->els.resp = &adisc->resp; - sg_init_one(adisc->els.req, &adisc->ls_adisc, - sizeof(struct zfcp_ls_adisc)); - sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, - sizeof(struct zfcp_ls_adisc)); + sg_init_one(adisc->els.req, &adisc->adisc_req, + sizeof(struct fc_els_adisc)); + sg_init_one(adisc->els.resp, &adisc->adisc_resp, + sizeof(struct fc_els_adisc)); adisc->els.adapter = adapter; adisc->els.port = port; adisc->els.d_id = port->d_id; adisc->els.handler = zfcp_fc_adisc_handler; adisc->els.handler_data = (unsigned long) adisc; - adisc->els.ls_code = adisc->ls_adisc.code = ZFCP_LS_ADISC; + adisc->els.ls_code = adisc->adisc_req.adisc_cmd = ELS_ADISC; /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports without FC-AL-2 capability, so we don't set it */ - adisc->ls_adisc.wwpn = fc_host_port_name(adapter->scsi_host); - adisc->ls_adisc.wwnn = fc_host_node_name(adapter->scsi_host); - adisc->ls_adisc.nport_id = fc_host_port_id(adapter->scsi_host); + adisc->adisc_req.adisc_wwpn = fc_host_port_name(adapter->scsi_host); + adisc->adisc_req.adisc_wwnn = fc_host_node_name(adapter->scsi_host); + hton24(adisc->adisc_req.adisc_port_id, + fc_host_port_id(adapter->scsi_host)); return zfcp_fsf_send_els(&adisc->els); } diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index 814fc2d2525..231e231b7fd 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -10,10 +10,27 @@ #ifndef ZFCP_FC_H #define ZFCP_FC_H +#include #include #include #include +/** + * struct zfcp_fc_els_adisc - everything required in zfcp for issuing ELS ADISC + * @els: data required for issuing els fsf command + * @req: scatterlist entry for ELS ADISC request + * @resp: scatterlist entry for ELS ADISC response + * @adisc_req: ELS ADISC request data + * @adisc_resp: ELS ADISC response data + */ +struct zfcp_fc_els_adisc { + struct zfcp_send_els els; + struct scatterlist req; + struct scatterlist resp; + struct fc_els_adisc adisc_req; + struct fc_els_adisc adisc_resp; +}; + /** * zfcp_fc_scsi_to_fcp - setup FCP command with data from scsi_cmnd * @fcp: fcp_cmnd to setup diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 5f4cd03797e..9d7bf965d39 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include +#include #include "zfcp_ext.h" #include "zfcp_fc.h" #include "zfcp_dbf.h" @@ -477,17 +478,22 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) { - struct fsf_qtcb_bottom_config *bottom; + struct fsf_qtcb_bottom_config *bottom = &req->qtcb->bottom.config; struct zfcp_adapter *adapter = req->adapter; struct Scsi_Host *shost = adapter->scsi_host; + struct fc_els_flogi *nsp, *plogi; - bottom = &req->qtcb->bottom.config; + /* adjust pointers for missing command code */ + nsp = (struct fc_els_flogi *) ((u8 *)&bottom->nport_serv_param + - sizeof(u32)); + plogi = (struct fc_els_flogi *) ((u8 *)&bottom->plogi_payload + - sizeof(u32)); if (req->data) memcpy(req->data, bottom, sizeof(*bottom)); - fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; - fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; + fc_host_port_name(shost) = nsp->fl_wwpn; + fc_host_node_name(shost) = nsp->fl_wwnn; fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; fc_host_speed(shost) = bottom->fc_link_speed; fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; @@ -501,8 +507,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) switch (bottom->fc_topology) { case FSF_TOPO_P2P: adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK; - adapter->peer_wwpn = bottom->plogi_payload.wwpn; - adapter->peer_wwnn = bottom->plogi_payload.wwnn; + adapter->peer_wwpn = plogi->fl_wwpn; + adapter->peer_wwnn = plogi->fl_wwnn; fc_host_port_type(shost) = FC_PORTTYPE_PTP; break; case FSF_TOPO_FABRIC: @@ -1068,15 +1074,17 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req, int max_sbals) { int ret; + unsigned int fcp_chan_timeout; ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals); if (ret) return ret; /* common settings for ct/gs and els requests */ + fcp_chan_timeout = 2 * FC_DEF_R_A_TOV / 1000; req->qtcb->bottom.support.service_class = FSF_CLASS_3; - req->qtcb->bottom.support.timeout = 2 * R_A_TOV; - zfcp_fsf_start_timer(req, (2 * R_A_TOV + 10) * HZ); + req->qtcb->bottom.support.timeout = fcp_chan_timeout; + zfcp_fsf_start_timer(req, (fcp_chan_timeout + 10) * HZ); return 0; } @@ -1151,7 +1159,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]){ case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - if (port && (send_els->ls_code != ZFCP_LS_ADISC)) + if (port && (send_els->ls_code != ELS_ADISC)) zfcp_fc_test_link(port); /*fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: @@ -1419,7 +1427,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) { struct zfcp_port *port = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; - struct fsf_plogi *plogi; + struct fc_els_flogi *plogi; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto out; @@ -1469,23 +1477,10 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) * another GID_PN straight after a port has been opened. * Alternately, an ADISC/PDISC ELS should suffice, as well. */ - plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; + plogi = (struct fc_els_flogi *) req->qtcb->bottom.support.els; if (req->qtcb->bottom.support.els1_length >= - FSF_PLOGI_MIN_LEN) { - if (plogi->serv_param.wwpn != port->wwpn) { - port->d_id = 0; - dev_warn(&port->adapter->ccw_device->dev, - "A port opened with WWPN 0x%016Lx " - "returned data that identifies it as " - "WWPN 0x%016Lx\n", - (unsigned long long) port->wwpn, - (unsigned long long) - plogi->serv_param.wwpn); - } else { - port->wwnn = plogi->serv_param.wwnn; + FSF_PLOGI_MIN_LEN) zfcp_fc_plogi_evaluate(port, plogi); - } - } break; case FSF_UNKNOWN_OP_SUBTYPE: req->status |= ZFCP_STATUS_FSFREQ_ERROR; diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index dcc7c1dbcf5..402e0235a35 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -309,22 +309,7 @@ struct fsf_qtcb_header { u8 res4[16]; } __attribute__ ((packed)); -struct fsf_nport_serv_param { - u8 common_serv_param[16]; - u64 wwpn; - u64 wwnn; - u8 class1_serv_param[16]; - u8 class2_serv_param[16]; - u8 class3_serv_param[16]; - u8 class4_serv_param[16]; - u8 vendor_version_level[16]; -} __attribute__ ((packed)); - #define FSF_PLOGI_MIN_LEN 112 -struct fsf_plogi { - u32 code; - struct fsf_nport_serv_param serv_param; -} __attribute__ ((packed)); #define FSF_FCP_CMND_SIZE 288 #define FSF_FCP_RSP_SIZE 128 @@ -377,13 +362,12 @@ struct fsf_qtcb_bottom_config { u16 timer_interval; u8 res2[8]; u32 s_id; - struct fsf_nport_serv_param nport_serv_param; - u8 reserved_nport_serv_param[16]; + u8 nport_serv_param[128]; u8 res3[8]; u32 adapter_ports; u32 hardware_version; u8 serial_number[32]; - struct fsf_nport_serv_param plogi_payload; + u8 plogi_payload[112]; struct fsf_statistics_info stat_info; u8 res4[112]; } __attribute__ ((packed)); -- cgit v1.2.3 From dbf5dfe9dbcecf159139eec25ad256738cbc3715 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:10 +0100 Subject: [SCSI] zfcp: Use common code definitions for FC CT structs Use common code definitions for FC GPN_FT and GID_PN instead of inventing private ones. Move the private structs still required inside zfcp to zfcp_fc header file. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 13 ++-- drivers/s390/scsi/zfcp_dbf.c | 36 +++++------ drivers/s390/scsi/zfcp_def.h | 74 +---------------------- drivers/s390/scsi/zfcp_fc.c | 138 +++++++++++++++++-------------------------- drivers/s390/scsi/zfcp_fc.h | 80 +++++++++++++++++++++++++ 5 files changed, 161 insertions(+), 180 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 107d3f2b6e9..58bb17732f5 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -31,6 +31,7 @@ #include #include #include "zfcp_ext.h" +#include "zfcp_fc.h" #define ZFCP_BUS_ID_SIZE 20 @@ -159,7 +160,7 @@ static int __init zfcp_module_init(void) int retval = -ENOMEM; zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn", - sizeof(struct ct_iu_gpn_ft_req)); + sizeof(struct zfcp_fc_gpn_ft_req)); if (!zfcp_data.gpn_ft_cache) goto out; @@ -174,7 +175,7 @@ static int __init zfcp_module_init(void) goto out_sr_cache; zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid", - sizeof(struct zfcp_gid_pn_data)); + sizeof(struct zfcp_fc_gid_pn)); if (!zfcp_data.gid_pn_cache) goto out_gid_cache; @@ -407,9 +408,9 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) if (!adapter->pool.status_read_data) return -ENOMEM; - adapter->pool.gid_pn_data = + adapter->pool.gid_pn = mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); - if (!adapter->pool.gid_pn_data) + if (!adapter->pool.gid_pn) return -ENOMEM; return 0; @@ -429,8 +430,8 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) mempool_destroy(adapter->pool.status_read_req); if (adapter->pool.status_read_data) mempool_destroy(adapter->pool.status_read_data); - if (adapter->pool.gid_pn_data) - mempool_destroy(adapter->pool.gid_pn_data); + if (adapter->pool.gid_pn) + mempool_destroy(adapter->pool.gid_pn); } /** diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 21e5316e500..d7a550af4a2 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -684,7 +684,7 @@ void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req) struct zfcp_wka_port *wka_port = ct->wka_port; struct zfcp_adapter *adapter = wka_port->adapter; struct zfcp_dbf *dbf = adapter->dbf; - struct ct_hdr *hdr = sg_virt(ct->req); + struct fc_ct_hdr *hdr = sg_virt(ct->req); struct zfcp_dbf_san_record *r = &dbf->san_buf; struct zfcp_dbf_san_record_ct_request *oct = &r->u.ct_req; int level = 3; @@ -697,17 +697,17 @@ void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req) r->fsf_seqno = fsf_req->seq_no; r->s_id = fc_host_port_id(adapter->scsi_host); r->d_id = wka_port->d_id; - oct->cmd_req_code = hdr->cmd_rsp_code; - oct->revision = hdr->revision; - oct->gs_type = hdr->gs_type; - oct->gs_subtype = hdr->gs_subtype; - oct->options = hdr->options; - oct->max_res_size = hdr->max_res_size; - oct->len = min((int)ct->req->length - (int)sizeof(struct ct_hdr), + oct->cmd_req_code = hdr->ct_cmd; + oct->revision = hdr->ct_rev; + oct->gs_type = hdr->ct_fs_type; + oct->gs_subtype = hdr->ct_fs_subtype; + oct->options = hdr->ct_options; + oct->max_res_size = hdr->ct_mr_size; + oct->len = min((int)ct->req->length - (int)sizeof(struct fc_ct_hdr), ZFCP_DBF_SAN_MAX_PAYLOAD); debug_event(dbf->san, level, r, sizeof(*r)); zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level, - (void *)hdr + sizeof(struct ct_hdr), oct->len); + (void *)hdr + sizeof(struct fc_ct_hdr), oct->len); spin_unlock_irqrestore(&dbf->san_lock, flags); } @@ -720,7 +720,7 @@ void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req) struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; struct zfcp_wka_port *wka_port = ct->wka_port; struct zfcp_adapter *adapter = wka_port->adapter; - struct ct_hdr *hdr = sg_virt(ct->resp); + struct fc_ct_hdr *hdr = sg_virt(ct->resp); struct zfcp_dbf *dbf = adapter->dbf; struct zfcp_dbf_san_record *r = &dbf->san_buf; struct zfcp_dbf_san_record_ct_response *rct = &r->u.ct_resp; @@ -734,17 +734,17 @@ void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req) r->fsf_seqno = fsf_req->seq_no; r->s_id = wka_port->d_id; r->d_id = fc_host_port_id(adapter->scsi_host); - rct->cmd_rsp_code = hdr->cmd_rsp_code; - rct->revision = hdr->revision; - rct->reason_code = hdr->reason_code; - rct->expl = hdr->reason_code_expl; - rct->vendor_unique = hdr->vendor_unique; - rct->max_res_size = hdr->max_res_size; - rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr), + rct->cmd_rsp_code = hdr->ct_cmd; + rct->revision = hdr->ct_rev; + rct->reason_code = hdr->ct_reason; + rct->expl = hdr->ct_explan; + rct->vendor_unique = hdr->ct_vendor; + rct->max_res_size = hdr->ct_mr_size; + rct->len = min((int)ct->resp->length - (int)sizeof(struct fc_ct_hdr), ZFCP_DBF_SAN_MAX_PAYLOAD); debug_event(dbf->san, level, r, sizeof(*r)); zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level, - (void *)hdr + sizeof(struct ct_hdr), rct->len); + (void *)hdr + sizeof(struct fc_ct_hdr), rct->len); spin_unlock_irqrestore(&dbf->san_lock, flags); } diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index fae8f2ebd43..c6482114547 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -75,25 +75,6 @@ #define ZFCP_DID_MASK 0x00FFFFFF -/* - * FC-GS-2 stuff - */ -#define ZFCP_CT_REVISION 0x01 -#define ZFCP_CT_DIRECTORY_SERVICE 0xFC -#define ZFCP_CT_NAME_SERVER 0x02 -#define ZFCP_CT_SYNCHRONOUS 0x00 -#define ZFCP_CT_SCSI_FCP 0x08 -#define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09 -#define ZFCP_CT_GID_PN 0x0121 -#define ZFCP_CT_GPN_FT 0x0172 -#define ZFCP_CT_ACCEPT 0x8002 -#define ZFCP_CT_REJECT 0x8001 - -/* - * FC-GS-4 stuff - */ -#define ZFCP_CT_TIMEOUT (3 * R_A_TOV) - /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ /* @@ -119,9 +100,6 @@ #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 -/* FC-PH/FC-GS well-known address identifiers for generic services */ -#define ZFCP_DID_WKA 0xFFFFF0 - /* remote port status */ #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 #define ZFCP_STATUS_PORT_LINK_TEST 0x00000002 @@ -162,50 +140,10 @@ struct zfcp_adapter_mempool { mempool_t *scsi_abort; mempool_t *status_read_req; mempool_t *status_read_data; - mempool_t *gid_pn_data; + mempool_t *gid_pn; mempool_t *qtcb_pool; }; -/* - * header for CT_IU - */ -struct ct_hdr { - u8 revision; // 0x01 - u8 in_id[3]; // 0x00 - u8 gs_type; // 0xFC Directory Service - u8 gs_subtype; // 0x02 Name Server - u8 options; // 0x00 single bidirectional exchange - u8 reserved0; - u16 cmd_rsp_code; // 0x0121 GID_PN, or 0x0100 GA_NXT - u16 max_res_size; // <= (4096 - 16) / 4 - u8 reserved1; - u8 reason_code; - u8 reason_code_expl; - u8 vendor_unique; -} __attribute__ ((packed)); - -/* nameserver request CT_IU -- for requests where - * a port name is required */ -struct ct_iu_gid_pn_req { - struct ct_hdr header; - u64 wwpn; -} __attribute__ ((packed)); - -/* FS_ACC IU and data unit for GID_PN nameserver request */ -struct ct_iu_gid_pn_resp { - struct ct_hdr header; - u32 d_id; -} __attribute__ ((packed)); - -struct ct_iu_gpn_ft_req { - struct ct_hdr header; - u8 flags; - u8 domain_id_scope; - u8 area_id_scope; - u8 fc4_type; -} __attribute__ ((packed)); - - /** * struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct * @wka_port: port where the request is sent to @@ -226,16 +164,6 @@ struct zfcp_send_ct { int status; }; -/* used for name server requests in error recovery */ -struct zfcp_gid_pn_data { - struct zfcp_send_ct ct; - struct scatterlist req; - struct scatterlist resp; - struct ct_iu_gid_pn_req ct_iu_req; - struct ct_iu_gid_pn_resp ct_iu_resp; - struct zfcp_port *port; -}; - /** * struct zfcp_send_els - used to pass parameters to function zfcp_fsf_send_els * @adapter: adapter where request is sent from diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index e03410043cd..7c306a5ef4d 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -22,32 +22,6 @@ static u32 zfcp_fc_rscn_range_mask[] = { [ELS_ADDR_FMT_FAB] = 0x000000, }; -struct gpn_ft_resp_acc { - u8 control; - u8 port_id[3]; - u8 reserved[4]; - u64 wwpn; -} __attribute__ ((packed)); - -#define ZFCP_CT_SIZE_ONE_PAGE (PAGE_SIZE - sizeof(struct ct_hdr)) -#define ZFCP_GPN_FT_ENTRIES (ZFCP_CT_SIZE_ONE_PAGE \ - / sizeof(struct gpn_ft_resp_acc)) -#define ZFCP_GPN_FT_BUFFERS 4 -#define ZFCP_GPN_FT_MAX_SIZE (ZFCP_GPN_FT_BUFFERS * PAGE_SIZE \ - - sizeof(struct ct_hdr)) -#define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1) - -struct ct_iu_gpn_ft_resp { - struct ct_hdr header; - struct gpn_ft_resp_acc accept[ZFCP_GPN_FT_ENTRIES]; -} __attribute__ ((packed)); - -struct zfcp_gpn_ft { - struct zfcp_send_ct ct; - struct scatterlist sg_req; - struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS]; -}; - struct zfcp_fc_ns_handler_data { struct completion done; void (*handler)(unsigned long); @@ -251,26 +225,26 @@ static void zfcp_fc_ns_handler(unsigned long data) static void zfcp_fc_ns_gid_pn_eval(unsigned long data) { - struct zfcp_gid_pn_data *gid_pn = (struct zfcp_gid_pn_data *) data; + struct zfcp_fc_gid_pn *gid_pn = (struct zfcp_fc_gid_pn *) data; struct zfcp_send_ct *ct = &gid_pn->ct; - struct ct_iu_gid_pn_req *ct_iu_req = sg_virt(ct->req); - struct ct_iu_gid_pn_resp *ct_iu_resp = sg_virt(ct->resp); + struct zfcp_fc_gid_pn_req *gid_pn_req = sg_virt(ct->req); + struct zfcp_fc_gid_pn_resp *gid_pn_resp = sg_virt(ct->resp); struct zfcp_port *port = gid_pn->port; if (ct->status) return; - if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) + if (gid_pn_resp->ct_hdr.ct_cmd != FC_FS_ACC) return; /* paranoia */ - if (ct_iu_req->wwpn != port->wwpn) + if (gid_pn_req->gid_pn.fn_wwpn != port->wwpn) return; /* looks like a valid d_id */ - port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; + port->d_id = ntoh24(gid_pn_resp->gid_pn.fp_fid); } static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port, - struct zfcp_gid_pn_data *gid_pn) + struct zfcp_fc_gid_pn *gid_pn) { struct zfcp_adapter *adapter = port->adapter; struct zfcp_fc_ns_handler_data compl_rec; @@ -281,21 +255,21 @@ static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port, gid_pn->ct.wka_port = &adapter->gs->ds; gid_pn->ct.handler = zfcp_fc_ns_handler; gid_pn->ct.handler_data = (unsigned long) &compl_rec; - gid_pn->ct.req = &gid_pn->req; - gid_pn->ct.resp = &gid_pn->resp; - sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, - sizeof(struct ct_iu_gid_pn_req)); - sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, - sizeof(struct ct_iu_gid_pn_resp)); + gid_pn->ct.req = &gid_pn->sg_req; + gid_pn->ct.resp = &gid_pn->sg_resp; + sg_init_one(&gid_pn->sg_req, &gid_pn->gid_pn_req, + sizeof(struct zfcp_fc_gid_pn_req)); + sg_init_one(&gid_pn->sg_resp, &gid_pn->gid_pn_resp, + sizeof(struct zfcp_fc_gid_pn_resp)); /* setup nameserver request */ - gid_pn->ct_iu_req.header.revision = ZFCP_CT_REVISION; - gid_pn->ct_iu_req.header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; - gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER; - gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; - gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; - gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4; - gid_pn->ct_iu_req.wwpn = port->wwpn; + gid_pn->gid_pn_req.ct_hdr.ct_rev = FC_CT_REV; + gid_pn->gid_pn_req.ct_hdr.ct_fs_type = FC_FST_DIR; + gid_pn->gid_pn_req.ct_hdr.ct_fs_subtype = FC_NS_SUBTYPE; + gid_pn->gid_pn_req.ct_hdr.ct_options = 0; + gid_pn->gid_pn_req.ct_hdr.ct_cmd = FC_NS_GID_PN; + gid_pn->gid_pn_req.ct_hdr.ct_mr_size = ZFCP_FC_CT_SIZE_PAGE / 4; + gid_pn->gid_pn_req.gid_pn.fn_wwpn = port->wwpn; init_completion(&compl_rec.done); compl_rec.handler = zfcp_fc_ns_gid_pn_eval; @@ -314,10 +288,10 @@ static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port, static int zfcp_fc_ns_gid_pn(struct zfcp_port *port) { int ret; - struct zfcp_gid_pn_data *gid_pn; + struct zfcp_fc_gid_pn *gid_pn; struct zfcp_adapter *adapter = port->adapter; - gid_pn = mempool_alloc(adapter->pool.gid_pn_data, GFP_ATOMIC); + gid_pn = mempool_alloc(adapter->pool.gid_pn, GFP_ATOMIC); if (!gid_pn) return -ENOMEM; @@ -331,7 +305,7 @@ static int zfcp_fc_ns_gid_pn(struct zfcp_port *port) zfcp_fc_wka_port_put(&adapter->gs->ds); out: - mempool_free(gid_pn, adapter->pool.gid_pn_data); + mempool_free(gid_pn, adapter->pool.gid_pn); return ret; } @@ -508,7 +482,7 @@ void zfcp_fc_test_link(struct zfcp_port *port) put_device(&port->sysfs_device); } -static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) +static void zfcp_free_sg_env(struct zfcp_fc_gpn_ft *gpn_ft, int buf_num) { struct scatterlist *sg = &gpn_ft->sg_req; @@ -518,10 +492,10 @@ static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) kfree(gpn_ft); } -static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num) +static struct zfcp_fc_gpn_ft *zfcp_alloc_sg_env(int buf_num) { - struct zfcp_gpn_ft *gpn_ft; - struct ct_iu_gpn_ft_req *req; + struct zfcp_fc_gpn_ft *gpn_ft; + struct zfcp_fc_gpn_ft_req *req; gpn_ft = kzalloc(sizeof(*gpn_ft), GFP_KERNEL); if (!gpn_ft) @@ -544,25 +518,24 @@ out: } -static int zfcp_fc_send_gpn_ft(struct zfcp_gpn_ft *gpn_ft, +static int zfcp_fc_send_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, struct zfcp_adapter *adapter, int max_bytes) { struct zfcp_send_ct *ct = &gpn_ft->ct; - struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); + struct zfcp_fc_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); struct zfcp_fc_ns_handler_data compl_rec; int ret; /* prepare CT IU for GPN_FT */ - req->header.revision = ZFCP_CT_REVISION; - req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; - req->header.gs_subtype = ZFCP_CT_NAME_SERVER; - req->header.options = ZFCP_CT_SYNCHRONOUS; - req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; - req->header.max_res_size = max_bytes / 4; - req->flags = 0; - req->domain_id_scope = 0; - req->area_id_scope = 0; - req->fc4_type = ZFCP_CT_SCSI_FCP; + req->ct_hdr.ct_rev = FC_CT_REV; + req->ct_hdr.ct_fs_type = FC_FST_DIR; + req->ct_hdr.ct_fs_subtype = FC_NS_SUBTYPE; + req->ct_hdr.ct_options = 0; + req->ct_hdr.ct_cmd = FC_NS_GPN_FT; + req->ct_hdr.ct_mr_size = max_bytes / 4; + req->gpn_ft.fn_domain_id_scope = 0; + req->gpn_ft.fn_area_id_scope = 0; + req->gpn_ft.fn_fc4_type = FC_TYPE_FCP; /* prepare zfcp_send_ct */ ct->wka_port = &adapter->gs->ds; @@ -593,12 +566,12 @@ static void zfcp_fc_validate_port(struct zfcp_port *port, struct list_head *lh) list_move_tail(&port->list, lh); } -static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) +static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, int max_entries) { struct zfcp_send_ct *ct = &gpn_ft->ct; struct scatterlist *sg = gpn_ft->sg_resp; - struct ct_hdr *hdr = sg_virt(sg); - struct gpn_ft_resp_acc *acc = sg_virt(sg); + struct fc_ct_hdr *hdr = sg_virt(sg); + struct fc_gpn_ft_resp *acc = sg_virt(sg); struct zfcp_adapter *adapter = ct->wka_port->adapter; struct zfcp_port *port, *tmp; unsigned long flags; @@ -609,38 +582,37 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) if (ct->status) return -EIO; - if (hdr->cmd_rsp_code != ZFCP_CT_ACCEPT) { - if (hdr->reason_code == ZFCP_CT_UNABLE_TO_PERFORM_CMD) + if (hdr->ct_cmd != FC_FS_ACC) { + if (hdr->ct_reason == FC_BA_RJT_UNABLE) return -EAGAIN; /* might be a temporary condition */ return -EIO; } - if (hdr->max_res_size) { + if (hdr->ct_mr_size) { dev_warn(&adapter->ccw_device->dev, "The name server reported %d words residual data\n", - hdr->max_res_size); + hdr->ct_mr_size); return -E2BIG; } /* first entry is the header */ for (x = 1; x < max_entries && !last; x++) { - if (x % (ZFCP_GPN_FT_ENTRIES + 1)) + if (x % (ZFCP_FC_GPN_FT_ENT_PAGE + 1)) acc++; else acc = sg_virt(++sg); - last = acc->control & 0x80; - d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 | - acc->port_id[2]; + last = acc->fp_flags & FC_NS_FID_LAST; + d_id = ntoh24(acc->fp_fid); /* don't attach ports with a well known address */ - if ((d_id & ZFCP_DID_WKA) == ZFCP_DID_WKA) + if (d_id >= FC_FID_WELL_KNOWN_BASE) continue; /* skip the adapter's port and known remote ports */ - if (acc->wwpn == fc_host_port_name(adapter->scsi_host)) + if (acc->fp_wwpn == fc_host_port_name(adapter->scsi_host)) continue; - port = zfcp_port_enqueue(adapter, acc->wwpn, + port = zfcp_port_enqueue(adapter, acc->fp_wwpn, ZFCP_STATUS_COMMON_NOESC, d_id); if (!IS_ERR(port)) zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL); @@ -672,13 +644,13 @@ void zfcp_fc_scan_ports(struct work_struct *work) struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter, scan_work); int ret, i; - struct zfcp_gpn_ft *gpn_ft; + struct zfcp_fc_gpn_ft *gpn_ft; int chain, max_entries, buf_num, max_bytes; chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS; - buf_num = chain ? ZFCP_GPN_FT_BUFFERS : 1; - max_entries = chain ? ZFCP_GPN_FT_MAX_ENTRIES : ZFCP_GPN_FT_ENTRIES; - max_bytes = chain ? ZFCP_GPN_FT_MAX_SIZE : ZFCP_CT_SIZE_ONE_PAGE; + buf_num = chain ? ZFCP_FC_GPN_FT_NUM_BUFS : 1; + max_entries = chain ? ZFCP_FC_GPN_FT_MAX_ENT : ZFCP_FC_GPN_FT_ENT_PAGE; + max_bytes = chain ? ZFCP_FC_GPN_FT_MAX_SIZE : ZFCP_FC_CT_SIZE_PAGE; if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT && fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index 231e231b7fd..12fc6ebbc24 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -12,9 +12,89 @@ #include #include +#include #include #include +#define ZFCP_FC_CT_SIZE_PAGE (PAGE_SIZE - sizeof(struct fc_ct_hdr)) +#define ZFCP_FC_GPN_FT_ENT_PAGE (ZFCP_FC_CT_SIZE_PAGE \ + / sizeof(struct fc_gpn_ft_resp)) +#define ZFCP_FC_GPN_FT_NUM_BUFS 4 /* memory pages */ + +#define ZFCP_FC_GPN_FT_MAX_SIZE (ZFCP_FC_GPN_FT_NUM_BUFS * PAGE_SIZE \ + - sizeof(struct fc_ct_hdr)) +#define ZFCP_FC_GPN_FT_MAX_ENT (ZFCP_FC_GPN_FT_NUM_BUFS * \ + (ZFCP_FC_GPN_FT_ENT_PAGE + 1)) + +/** + * struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request + * @ct_hdr: FC GS common transport header + * @gid_pn: GID_PN request + */ +struct zfcp_fc_gid_pn_req { + struct fc_ct_hdr ct_hdr; + struct fc_ns_gid_pn gid_pn; +} __packed; + +/** + * struct zfcp_fc_gid_pn_resp - container for ct header plus gid_pn response + * @ct_hdr: FC GS common transport header + * @gid_pn: GID_PN response + */ +struct zfcp_fc_gid_pn_resp { + struct fc_ct_hdr ct_hdr; + struct fc_gid_pn_resp gid_pn; +} __packed; + +/** + * struct zfcp_fc_gid_pn - everything required in zfcp for gid_pn request + * @ct: data passed to zfcp_fsf for issuing fsf request + * @sg_req: scatterlist entry for request data + * @sg_resp: scatterlist entry for response data + * @gid_pn_req: GID_PN request data + * @gid_pn_resp: GID_PN response data + */ +struct zfcp_fc_gid_pn { + struct zfcp_send_ct ct; + struct scatterlist sg_req; + struct scatterlist sg_resp; + struct zfcp_fc_gid_pn_req gid_pn_req; + struct zfcp_fc_gid_pn_resp gid_pn_resp; + struct zfcp_port *port; +}; + +/** + * struct zfcp_fc_gpn_ft - container for ct header plus gpn_ft request + * @ct_hdr: FC GS common transport header + * @gpn_ft: GPN_FT request + */ +struct zfcp_fc_gpn_ft_req { + struct fc_ct_hdr ct_hdr; + struct fc_ns_gid_ft gpn_ft; +} __packed; + +/** + * struct zfcp_fc_gpn_ft_resp - container for ct header plus gpn_ft response + * @ct_hdr: FC GS common transport header + * @gpn_ft: Array of gpn_ft response data to fill one memory page + */ +struct zfcp_fc_gpn_ft_resp { + struct fc_ct_hdr ct_hdr; + struct fc_gpn_ft_resp gpn_ft[ZFCP_FC_GPN_FT_ENT_PAGE]; +} __packed; + +/** + * struct zfcp_fc_gpn_ft - zfcp data for gpn_ft request + * @ct: data passed to zfcp_fsf for issuing fsf request + * @sg_req: scatter list entry for gpn_ft request + * @sg_resp: scatter list entries for gpn_ft responses (per memory page) + */ +struct zfcp_fc_gpn_ft { + struct zfcp_send_ct ct; + struct scatterlist sg_req; + struct scatterlist sg_resp[ZFCP_FC_GPN_FT_NUM_BUFS]; +}; + /** * struct zfcp_fc_els_adisc - everything required in zfcp for issuing ELS ADISC * @els: data required for issuing els fsf command -- cgit v1.2.3 From bd0072ecc449fb2ea8f6a2c9f6ff308f3ae0b078 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:11 +0100 Subject: [SCSI] zfcp: Move WKA port to zfcp FC code The well-known-address (WKA) port handling code is part of the FC code in zfcp. Move everything WKA related to the zfcp_fc files and use the common zfcp_fc prefix for structs and functions. Drop the unused key management service while renaming the struct, no request could ever reach this service in zfcp and it is obsolete anyway. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 5 +++-- drivers/s390/scsi/zfcp_def.h | 31 ++------------------------- drivers/s390/scsi/zfcp_ext.h | 6 +++--- drivers/s390/scsi/zfcp_fc.c | 44 +++++++++++++++++++------------------- drivers/s390/scsi/zfcp_fc.h | 50 ++++++++++++++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_fsf.c | 22 +++++++++---------- 6 files changed, 90 insertions(+), 68 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index d7a550af4a2..e945344ff71 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -13,6 +13,7 @@ #include #include "zfcp_dbf.h" #include "zfcp_ext.h" +#include "zfcp_fc.h" static u32 dbfsize = 4; @@ -681,7 +682,7 @@ void zfcp_dbf_rec_action(char *id2, struct zfcp_erp_action *erp_action) void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; - struct zfcp_wka_port *wka_port = ct->wka_port; + struct zfcp_fc_wka_port *wka_port = ct->wka_port; struct zfcp_adapter *adapter = wka_port->adapter; struct zfcp_dbf *dbf = adapter->dbf; struct fc_ct_hdr *hdr = sg_virt(ct->req); @@ -718,7 +719,7 @@ void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req) void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; - struct zfcp_wka_port *wka_port = ct->wka_port; + struct zfcp_fc_wka_port *wka_port = ct->wka_port; struct zfcp_adapter *adapter = wka_port->adapter; struct fc_ct_hdr *hdr = sg_virt(ct->resp); struct zfcp_dbf *dbf = adapter->dbf; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index c6482114547..c00aa2b174a 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -104,14 +104,6 @@ #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 #define ZFCP_STATUS_PORT_LINK_TEST 0x00000002 -/* well known address (WKA) port status*/ -enum zfcp_wka_status { - ZFCP_WKA_PORT_OFFLINE, - ZFCP_WKA_PORT_CLOSING, - ZFCP_WKA_PORT_OPENING, - ZFCP_WKA_PORT_ONLINE, -}; - /* logical unit status */ #define ZFCP_STATUS_UNIT_SHARED 0x00000004 #define ZFCP_STATUS_UNIT_READONLY 0x00000008 @@ -155,7 +147,7 @@ struct zfcp_adapter_mempool { * @status: used to pass error status to calling function */ struct zfcp_send_ct { - struct zfcp_wka_port *wka_port; + struct zfcp_fc_wka_port *wka_port; struct scatterlist *req; struct scatterlist *resp; void (*handler)(unsigned long); @@ -190,25 +182,6 @@ struct zfcp_send_els { int status; }; -struct zfcp_wka_port { - struct zfcp_adapter *adapter; - wait_queue_head_t completion_wq; - enum zfcp_wka_status status; - atomic_t refcount; - u32 d_id; - u32 handle; - struct mutex mutex; - struct delayed_work work; -}; - -struct zfcp_wka_ports { - struct zfcp_wka_port ms; /* management service */ - struct zfcp_wka_port ts; /* time service */ - struct zfcp_wka_port ds; /* directory service */ - struct zfcp_wka_port as; /* alias service */ - struct zfcp_wka_port ks; /* key distribution service */ -}; - struct zfcp_qdio_queue { struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; u8 first; /* index of next free bfr in queue */ @@ -309,7 +282,7 @@ struct zfcp_adapter { u32 erp_low_mem_count; /* nr of erp actions waiting for memory */ struct task_struct *erp_thread; - struct zfcp_wka_ports *gs; /* generic services */ + struct zfcp_fc_wka_ports *gs; /* generic services */ struct zfcp_dbf *dbf; /* debug traces */ struct zfcp_adapter_mempool pool; /* Adapter memory pools */ struct fc_host_statistics *fc_stats; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index c2b23b5a3d0..6a2d6e390b6 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -103,7 +103,7 @@ extern void zfcp_fc_trigger_did_lookup(struct zfcp_port *); extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fc_els_flogi *); extern void zfcp_fc_test_link(struct zfcp_port *); extern void zfcp_fc_link_test_work(struct work_struct *); -extern void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *); +extern void zfcp_fc_wka_ports_force_offline(struct zfcp_fc_wka_ports *); extern int zfcp_fc_gs_setup(struct zfcp_adapter *); extern void zfcp_fc_gs_destroy(struct zfcp_adapter *); extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *); @@ -111,8 +111,8 @@ extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *); /* zfcp_fsf.c */ extern int zfcp_fsf_open_port(struct zfcp_erp_action *); -extern int zfcp_fsf_open_wka_port(struct zfcp_wka_port *); -extern int zfcp_fsf_close_wka_port(struct zfcp_wka_port *); +extern int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *); +extern int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *); extern int zfcp_fsf_close_port(struct zfcp_erp_action *); extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 7c306a5ef4d..d6d1e78ba0f 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -28,25 +28,25 @@ struct zfcp_fc_ns_handler_data { unsigned long handler_data; }; -static int zfcp_fc_wka_port_get(struct zfcp_wka_port *wka_port) +static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port) { if (mutex_lock_interruptible(&wka_port->mutex)) return -ERESTARTSYS; - if (wka_port->status == ZFCP_WKA_PORT_OFFLINE || - wka_port->status == ZFCP_WKA_PORT_CLOSING) { - wka_port->status = ZFCP_WKA_PORT_OPENING; + if (wka_port->status == ZFCP_FC_WKA_PORT_OFFLINE || + wka_port->status == ZFCP_FC_WKA_PORT_CLOSING) { + wka_port->status = ZFCP_FC_WKA_PORT_OPENING; if (zfcp_fsf_open_wka_port(wka_port)) - wka_port->status = ZFCP_WKA_PORT_OFFLINE; + wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; } mutex_unlock(&wka_port->mutex); wait_event(wka_port->completion_wq, - wka_port->status == ZFCP_WKA_PORT_ONLINE || - wka_port->status == ZFCP_WKA_PORT_OFFLINE); + wka_port->status == ZFCP_FC_WKA_PORT_ONLINE || + wka_port->status == ZFCP_FC_WKA_PORT_OFFLINE); - if (wka_port->status == ZFCP_WKA_PORT_ONLINE) { + if (wka_port->status == ZFCP_FC_WKA_PORT_ONLINE) { atomic_inc(&wka_port->refcount); return 0; } @@ -56,24 +56,24 @@ static int zfcp_fc_wka_port_get(struct zfcp_wka_port *wka_port) static void zfcp_fc_wka_port_offline(struct work_struct *work) { struct delayed_work *dw = to_delayed_work(work); - struct zfcp_wka_port *wka_port = - container_of(dw, struct zfcp_wka_port, work); + struct zfcp_fc_wka_port *wka_port = + container_of(dw, struct zfcp_fc_wka_port, work); mutex_lock(&wka_port->mutex); if ((atomic_read(&wka_port->refcount) != 0) || - (wka_port->status != ZFCP_WKA_PORT_ONLINE)) + (wka_port->status != ZFCP_FC_WKA_PORT_ONLINE)) goto out; - wka_port->status = ZFCP_WKA_PORT_CLOSING; + wka_port->status = ZFCP_FC_WKA_PORT_CLOSING; if (zfcp_fsf_close_wka_port(wka_port)) { - wka_port->status = ZFCP_WKA_PORT_OFFLINE; + wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; wake_up(&wka_port->completion_wq); } out: mutex_unlock(&wka_port->mutex); } -static void zfcp_fc_wka_port_put(struct zfcp_wka_port *wka_port) +static void zfcp_fc_wka_port_put(struct zfcp_fc_wka_port *wka_port) { if (atomic_dec_return(&wka_port->refcount) != 0) return; @@ -81,7 +81,7 @@ static void zfcp_fc_wka_port_put(struct zfcp_wka_port *wka_port) schedule_delayed_work(&wka_port->work, HZ / 100); } -static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id, +static void zfcp_fc_wka_port_init(struct zfcp_fc_wka_port *wka_port, u32 d_id, struct zfcp_adapter *adapter) { init_waitqueue_head(&wka_port->completion_wq); @@ -89,21 +89,21 @@ static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id, wka_port->adapter = adapter; wka_port->d_id = d_id; - wka_port->status = ZFCP_WKA_PORT_OFFLINE; + wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; atomic_set(&wka_port->refcount, 0); mutex_init(&wka_port->mutex); INIT_DELAYED_WORK(&wka_port->work, zfcp_fc_wka_port_offline); } -static void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) +static void zfcp_fc_wka_port_force_offline(struct zfcp_fc_wka_port *wka) { cancel_delayed_work_sync(&wka->work); mutex_lock(&wka->mutex); - wka->status = ZFCP_WKA_PORT_OFFLINE; + wka->status = ZFCP_FC_WKA_PORT_OFFLINE; mutex_unlock(&wka->mutex); } -void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs) +void zfcp_fc_wka_ports_force_offline(struct zfcp_fc_wka_ports *gs) { if (!gs) return; @@ -111,7 +111,6 @@ void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs) zfcp_fc_wka_port_force_offline(&gs->ts); zfcp_fc_wka_port_force_offline(&gs->ds); zfcp_fc_wka_port_force_offline(&gs->as); - zfcp_fc_wka_port_force_offline(&gs->ks); } static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, @@ -834,9 +833,9 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) int zfcp_fc_gs_setup(struct zfcp_adapter *adapter) { - struct zfcp_wka_ports *wka_ports; + struct zfcp_fc_wka_ports *wka_ports; - wka_ports = kzalloc(sizeof(struct zfcp_wka_ports), GFP_KERNEL); + wka_ports = kzalloc(sizeof(struct zfcp_fc_wka_ports), GFP_KERNEL); if (!wka_ports) return -ENOMEM; @@ -845,7 +844,6 @@ int zfcp_fc_gs_setup(struct zfcp_adapter *adapter) zfcp_fc_wka_port_init(&wka_ports->ts, FC_FID_TIME_SERV, adapter); zfcp_fc_wka_port_init(&wka_ports->ds, FC_FID_DIR_SERV, adapter); zfcp_fc_wka_port_init(&wka_ports->as, FC_FID_ALIASES, adapter); - zfcp_fc_wka_port_init(&wka_ports->ks, FC_FID_SEC_KEY, adapter); return 0; } diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index 12fc6ebbc24..9c787e043ff 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -111,6 +111,56 @@ struct zfcp_fc_els_adisc { struct fc_els_adisc adisc_resp; }; +/** + * enum zfcp_fc_wka_status - FC WKA port status in zfcp + * @ZFCP_FC_WKA_PORT_OFFLINE: Port is closed and not in use + * @ZFCP_FC_WKA_PORT_CLOSING: The FSF "close port" request is pending + * @ZFCP_FC_WKA_PORT_OPENING: The FSF "open port" request is pending + * @ZFCP_FC_WKA_PORT_ONLINE: The port is open and the port handle is valid + */ +enum zfcp_fc_wka_status { + ZFCP_FC_WKA_PORT_OFFLINE, + ZFCP_FC_WKA_PORT_CLOSING, + ZFCP_FC_WKA_PORT_OPENING, + ZFCP_FC_WKA_PORT_ONLINE, +}; + +/** + * struct zfcp_fc_wka_port - representation of well-known-address (WKA) FC port + * @adapter: Pointer to adapter structure this WKA port belongs to + * @completion_wq: Wait for completion of open/close command + * @status: Current status of WKA port + * @refcount: Reference count to keep port open as long as it is in use + * @d_id: FC destination id or well-known-address + * @handle: FSF handle for the open WKA port + * @mutex: Mutex used during opening/closing state changes + * @work: For delaying the closing of the WKA port + */ +struct zfcp_fc_wka_port { + struct zfcp_adapter *adapter; + wait_queue_head_t completion_wq; + enum zfcp_fc_wka_status status; + atomic_t refcount; + u32 d_id; + u32 handle; + struct mutex mutex; + struct delayed_work work; +}; + +/** + * struct zfcp_fc_wka_ports - Data structures for FC generic services + * @ms: FC Management service + * @ts: FC time service + * @ds: FC directory service + * @as: FC alias service + */ +struct zfcp_fc_wka_ports { + struct zfcp_fc_wka_port ms; + struct zfcp_fc_wka_port ts; + struct zfcp_fc_wka_port ds; + struct zfcp_fc_wka_port as; +}; + /** * zfcp_fc_scsi_to_fcp - setup FCP command with data from scsi_cmnd * @fcp: fcp_cmnd to setup diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9d7bf965d39..9ada555ca5a 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1096,7 +1096,7 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req, */ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool) { - struct zfcp_wka_port *wka_port = ct->wka_port; + struct zfcp_fc_wka_port *wka_port = ct->wka_port; struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; int ret = -EIO; @@ -1610,11 +1610,11 @@ out: static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) { - struct zfcp_wka_port *wka_port = req->data; + struct zfcp_fc_wka_port *wka_port = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) { - wka_port->status = ZFCP_WKA_PORT_OFFLINE; + wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; goto out; } @@ -1627,13 +1627,13 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) req->status |= ZFCP_STATUS_FSFREQ_ERROR; /* fall through */ case FSF_ACCESS_DENIED: - wka_port->status = ZFCP_WKA_PORT_OFFLINE; + wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; break; case FSF_GOOD: wka_port->handle = header->port_handle; /* fall through */ case FSF_PORT_ALREADY_OPEN: - wka_port->status = ZFCP_WKA_PORT_ONLINE; + wka_port->status = ZFCP_FC_WKA_PORT_ONLINE; } out: wake_up(&wka_port->completion_wq); @@ -1641,10 +1641,10 @@ out: /** * zfcp_fsf_open_wka_port - create and send open wka-port request - * @wka_port: pointer to struct zfcp_wka_port + * @wka_port: pointer to struct zfcp_fc_wka_port * Returns: 0 on success, error otherwise */ -int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port) +int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) { struct qdio_buffer_element *sbale; struct zfcp_qdio *qdio = wka_port->adapter->qdio; @@ -1683,23 +1683,23 @@ out: static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req) { - struct zfcp_wka_port *wka_port = req->data; + struct zfcp_fc_wka_port *wka_port = req->data; if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) { req->status |= ZFCP_STATUS_FSFREQ_ERROR; zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req); } - wka_port->status = ZFCP_WKA_PORT_OFFLINE; + wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; wake_up(&wka_port->completion_wq); } /** * zfcp_fsf_close_wka_port - create and send close wka port request - * @erp_action: pointer to struct zfcp_erp_action + * @wka_port: WKA port to open * Returns: 0 on success, error otherwise */ -int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port) +int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) { struct qdio_buffer_element *sbale; struct zfcp_qdio *qdio = wka_port->adapter->qdio; -- cgit v1.2.3 From 800c0cad962dcf630cabf3efdc5983619e73d4c9 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:12 +0100 Subject: [SCSI] zfcp: Remove ZFCP_DID_MASK Instead of assigning 4 bytes with the highest byte masked out, use a 3 byte array with the ntoh24 and h24ton helper functions, thus eliminating the need for the ZFCP_DID_MASK. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 4 ++-- drivers/s390/scsi/zfcp_def.h | 4 ---- drivers/s390/scsi/zfcp_fsf.c | 12 ++++++------ drivers/s390/scsi/zfcp_fsf.h | 15 +++++++++------ 4 files changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index e945344ff71..517f196b4c5 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -178,7 +178,7 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level, case FSF_QTCB_SEND_ELS: send_els = (struct zfcp_send_els *)fsf_req->data; - response->u.els.d_id = qtcb->bottom.support.d_id; + response->u.els.d_id = ntoh24(qtcb->bottom.support.d_id); response->u.els.ls_code = send_els->ls_code >> 24; break; @@ -812,7 +812,7 @@ void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *fsf_req) int length = (int)buf->length - (int)((void *)&buf->payload - (void *)buf); - zfcp_dbf_san_els("iels", 1, fsf_req, buf->d_id, + zfcp_dbf_san_els("iels", 1, fsf_req, ntoh24(buf->d_id), fc_host_port_id(adapter->scsi_host), buf->payload.data[0], (void *)buf->payload.data, length); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index c00aa2b174a..ea11b4e45cd 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -71,10 +71,6 @@ /* timeout value for "default timer" for fsf requests */ #define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ) -/*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/ - -#define ZFCP_DID_MASK 0x00FFFFFF - /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ /* diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9ada555ca5a..057c93777f9 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -128,7 +128,7 @@ static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) struct fsf_status_read_buffer *sr_buf = req->data; struct zfcp_adapter *adapter = req->adapter; struct zfcp_port *port; - int d_id = sr_buf->d_id & ZFCP_DID_MASK; + int d_id = ntoh24(sr_buf->d_id); read_lock_irqsave(&adapter->port_list_lock, flags); list_for_each_entry(port, &adapter->port_list, list) @@ -494,7 +494,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) fc_host_port_name(shost) = nsp->fl_wwpn; fc_host_node_name(shost) = nsp->fl_wwnn; - fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; + fc_host_port_id(shost) = ntoh24(bottom->s_id); fc_host_speed(shost) = bottom->fc_link_speed; fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; @@ -506,7 +506,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) switch (bottom->fc_topology) { case FSF_TOPO_P2P: - adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK; + adapter->peer_d_id = ntoh24(bottom->peer_d_id); adapter->peer_wwpn = plogi->fl_wwpn; adapter->peer_wwnn = plogi->fl_wwnn; fc_host_port_type(shost) = FC_PORTTYPE_PTP; @@ -1216,7 +1216,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) if (ret) goto failed_send; - req->qtcb->bottom.support.d_id = els->d_id; + hton24(req->qtcb->bottom.support.d_id, els->d_id); req->handler = zfcp_fsf_send_els_handler; req->data = els; @@ -1522,7 +1522,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; req->handler = zfcp_fsf_open_port_handler; - req->qtcb->bottom.support.d_id = port->d_id; + hton24(req->qtcb->bottom.support.d_id, port->d_id); req->data = port; req->erp_action = erp_action; erp_action->fsf_req = req; @@ -1669,7 +1669,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; req->handler = zfcp_fsf_open_wka_port_handler; - req->qtcb->bottom.support.d_id = wka_port->d_id; + hton24(req->qtcb->bottom.support.d_id, wka_port->d_id); req->data = wka_port; zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 402e0235a35..206b7eaff5a 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -11,6 +11,7 @@ #include #include +#include #define FSF_QTCB_CURRENT_VERSION 0x00000001 @@ -228,7 +229,8 @@ struct fsf_status_read_buffer { u32 length; u32 res1; struct fsf_queue_designator queue_designator; - u32 d_id; + u8 res2; + u8 d_id[3]; u32 class; u64 fcp_lun; u8 res3[24]; @@ -327,8 +329,8 @@ struct fsf_qtcb_bottom_io { struct fsf_qtcb_bottom_support { u32 operation_subtype; - u8 res1[12]; - u32 d_id; + u8 res1[13]; + u8 d_id[3]; u32 option; u64 fcp_lun; u64 res2; @@ -357,11 +359,12 @@ struct fsf_qtcb_bottom_config { u32 fc_topology; u32 fc_link_speed; u32 adapter_type; - u32 peer_d_id; + u8 res0; + u8 peer_d_id[3]; u8 res1[2]; u16 timer_interval; - u8 res2[8]; - u32 s_id; + u8 res2[9]; + u8 s_id[3]; u8 nport_serv_param[128]; u8 res3[8]; u32 adapter_ports; -- cgit v1.2.3 From 7c7dc196814b9e1d5cc254dc579a5fa78ae524f7 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:13 +0100 Subject: [SCSI] zfcp: Simplify handling of ct and els requests Remove some redundancies in FC related code and trace: - drop redundant data from SAN trace (local s_id that only changes during link down, ls_code that is already part of payload, d_id in ct response trace that is always the same as in ct request trace) - use one common fsf struct to hold zfcp data for ct and els requests - leverage common fsf struct for FC passthrough job data, allocate it with dd_bsg_data for passthrough requests and unify common code for ct and els passthrough request - simplify callback handling in zfcp_fc Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 56 ++++------ drivers/s390/scsi/zfcp_dbf.h | 7 +- drivers/s390/scsi/zfcp_def.h | 46 -------- drivers/s390/scsi/zfcp_ext.h | 12 +- drivers/s390/scsi/zfcp_fc.c | 253 +++++++++++++++--------------------------- drivers/s390/scsi/zfcp_fc.h | 7 +- drivers/s390/scsi/zfcp_fsf.c | 28 +++-- drivers/s390/scsi/zfcp_fsf.h | 18 +++ drivers/s390/scsi/zfcp_scsi.c | 18 +-- 9 files changed, 160 insertions(+), 285 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 517f196b4c5..84450955ae1 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -179,7 +179,6 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level, case FSF_QTCB_SEND_ELS: send_els = (struct zfcp_send_els *)fsf_req->data; response->u.els.d_id = ntoh24(qtcb->bottom.support.d_id); - response->u.els.ls_code = send_els->ls_code >> 24; break; case FSF_QTCB_ABORT_FCP_CMND: @@ -349,7 +348,6 @@ static void zfcp_dbf_hba_view_response(char **p, case FSF_QTCB_SEND_ELS: zfcp_dbf_out(p, "d_id", "0x%06x", r->u.els.d_id); - zfcp_dbf_out(p, "ls_code", "0x%02x", r->u.els.ls_code); break; case FSF_QTCB_ABORT_FCP_CMND: @@ -678,12 +676,12 @@ void zfcp_dbf_rec_action(char *id2, struct zfcp_erp_action *erp_action) /** * zfcp_dbf_san_ct_request - trace event for issued CT request * @fsf_req: request containing issued CT data + * @d_id: destination id where ct request is sent to */ -void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req, u32 d_id) { - struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; - struct zfcp_fc_wka_port *wka_port = ct->wka_port; - struct zfcp_adapter *adapter = wka_port->adapter; + struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data; + struct zfcp_adapter *adapter = fsf_req->adapter; struct zfcp_dbf *dbf = adapter->dbf; struct fc_ct_hdr *hdr = sg_virt(ct->req); struct zfcp_dbf_san_record *r = &dbf->san_buf; @@ -696,8 +694,7 @@ void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req) strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE); r->fsf_reqid = fsf_req->req_id; r->fsf_seqno = fsf_req->seq_no; - r->s_id = fc_host_port_id(adapter->scsi_host); - r->d_id = wka_port->d_id; + oct->d_id = d_id; oct->cmd_req_code = hdr->ct_cmd; oct->revision = hdr->ct_rev; oct->gs_type = hdr->ct_fs_type; @@ -718,9 +715,8 @@ void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req) */ void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req) { - struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; - struct zfcp_fc_wka_port *wka_port = ct->wka_port; - struct zfcp_adapter *adapter = wka_port->adapter; + struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data; + struct zfcp_adapter *adapter = fsf_req->adapter; struct fc_ct_hdr *hdr = sg_virt(ct->resp); struct zfcp_dbf *dbf = adapter->dbf; struct zfcp_dbf_san_record *r = &dbf->san_buf; @@ -733,8 +729,6 @@ void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req) strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE); r->fsf_reqid = fsf_req->req_id; r->fsf_seqno = fsf_req->seq_no; - r->s_id = wka_port->d_id; - r->d_id = fc_host_port_id(adapter->scsi_host); rct->cmd_rsp_code = hdr->ct_cmd; rct->revision = hdr->ct_rev; rct->reason_code = hdr->ct_reason; @@ -750,8 +744,8 @@ void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req) } static void zfcp_dbf_san_els(const char *tag, int level, - struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id, - u8 ls_code, void *buffer, int buflen) + struct zfcp_fsf_req *fsf_req, u32 d_id, + void *buffer, int buflen) { struct zfcp_adapter *adapter = fsf_req->adapter; struct zfcp_dbf *dbf = adapter->dbf; @@ -763,9 +757,7 @@ static void zfcp_dbf_san_els(const char *tag, int level, strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); rec->fsf_reqid = fsf_req->req_id; rec->fsf_seqno = fsf_req->seq_no; - rec->s_id = s_id; - rec->d_id = d_id; - rec->u.els.ls_code = ls_code; + rec->u.els.d_id = d_id; debug_event(dbf->san, level, rec, sizeof(*rec)); zfcp_dbf_hexdump(dbf->san, rec, sizeof(*rec), level, buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD)); @@ -778,12 +770,11 @@ static void zfcp_dbf_san_els(const char *tag, int level, */ void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req) { - struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; + struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data; + u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id); - zfcp_dbf_san_els("oels", 2, fsf_req, - fc_host_port_id(els->adapter->scsi_host), - els->d_id, *(u8 *) sg_virt(els->req), - sg_virt(els->req), els->req->length); + zfcp_dbf_san_els("oels", 2, fsf_req, d_id, + sg_virt(els->req), els->req->length); } /** @@ -792,12 +783,11 @@ void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req) */ void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req) { - struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; + struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data; + u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id); - zfcp_dbf_san_els("rels", 2, fsf_req, els->d_id, - fc_host_port_id(els->adapter->scsi_host), - *(u8 *)sg_virt(els->req), sg_virt(els->resp), - els->resp->length); + zfcp_dbf_san_els("rels", 2, fsf_req, d_id, + sg_virt(els->resp), els->resp->length); } /** @@ -806,16 +796,13 @@ void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req) */ void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *fsf_req) { - struct zfcp_adapter *adapter = fsf_req->adapter; struct fsf_status_read_buffer *buf = (struct fsf_status_read_buffer *)fsf_req->data; int length = (int)buf->length - (int)((void *)&buf->payload - (void *)buf); zfcp_dbf_san_els("iels", 1, fsf_req, ntoh24(buf->d_id), - fc_host_port_id(adapter->scsi_host), - buf->payload.data[0], (void *)buf->payload.data, - length); + (void *)buf->payload.data, length); } static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view, @@ -830,11 +817,10 @@ static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_tag(&p, "tag", r->tag); zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid); zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno); - zfcp_dbf_out(&p, "s_id", "0x%06x", r->s_id); - zfcp_dbf_out(&p, "d_id", "0x%06x", r->d_id); if (strncmp(r->tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) { struct zfcp_dbf_san_record_ct_request *ct = &r->u.ct_req; + zfcp_dbf_out(&p, "d_id", "0x%06x", ct->d_id); zfcp_dbf_out(&p, "cmd_req_code", "0x%04x", ct->cmd_req_code); zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision); zfcp_dbf_out(&p, "gs_type", "0x%02x", ct->gs_type); @@ -853,7 +839,7 @@ static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view, strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) { struct zfcp_dbf_san_record_els *els = &r->u.els; - zfcp_dbf_out(&p, "ls_code", "0x%02x", els->ls_code); + zfcp_dbf_out(&p, "d_id", "0x%06x", els->d_id); } return p - out_buf; } diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index c3e25702df5..8b7fd9a1033 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -123,7 +123,6 @@ struct zfcp_dbf_hba_record_response { } unit; struct { u32 d_id; - u8 ls_code; } els; } u; } __attribute__ ((packed)); @@ -167,6 +166,7 @@ struct zfcp_dbf_san_record_ct_request { u8 options; u16 max_res_size; u32 len; + u32 d_id; } __attribute__ ((packed)); struct zfcp_dbf_san_record_ct_response { @@ -180,16 +180,13 @@ struct zfcp_dbf_san_record_ct_response { } __attribute__ ((packed)); struct zfcp_dbf_san_record_els { - u8 ls_code; - u32 len; + u32 d_id; } __attribute__ ((packed)); struct zfcp_dbf_san_record { u8 tag[ZFCP_DBF_TAG_SIZE]; u64 fsf_reqid; u32 fsf_seqno; - u32 s_id; - u32 d_id; union { struct zfcp_dbf_san_record_ct_request ct_req; struct zfcp_dbf_san_record_ct_response ct_resp; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index ea11b4e45cd..21b29804a7a 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -132,52 +132,6 @@ struct zfcp_adapter_mempool { mempool_t *qtcb_pool; }; -/** - * struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct - * @wka_port: port where the request is sent to - * @req: scatter-gather list for request - * @resp: scatter-gather list for response - * @handler: handler function (called for response to the request) - * @handler_data: data passed to handler function - * @completion: completion for synchronization purposes - * @status: used to pass error status to calling function - */ -struct zfcp_send_ct { - struct zfcp_fc_wka_port *wka_port; - struct scatterlist *req; - struct scatterlist *resp; - void (*handler)(unsigned long); - unsigned long handler_data; - struct completion *completion; - int status; -}; - -/** - * struct zfcp_send_els - used to pass parameters to function zfcp_fsf_send_els - * @adapter: adapter where request is sent from - * @port: port where ELS is destinated (port reference count has to be increased) - * @d_id: destiniation id of port where request is sent to - * @req: scatter-gather list for request - * @resp: scatter-gather list for response - * @handler: handler function (called for response to the request) - * @handler_data: data passed to handler function - * @completion: completion for synchronization purposes - * @ls_code: hex code of ELS command - * @status: used to pass error status to calling function - */ -struct zfcp_send_els { - struct zfcp_adapter *adapter; - struct zfcp_port *port; - u32 d_id; - struct scatterlist *req; - struct scatterlist *resp; - void (*handler)(unsigned long); - unsigned long handler_data; - struct completion *completion; - int ls_code; - int status; -}; - struct zfcp_qdio_queue { struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; u8 first; /* index of next free bfr in queue */ diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 6a2d6e390b6..03dec832b46 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -12,6 +12,7 @@ #include #include #include "zfcp_def.h" +#include "zfcp_fc.h" /* zfcp_aux.c */ extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64); @@ -55,7 +56,7 @@ extern void _zfcp_dbf_hba_fsf_unsol(const char *, int level, struct zfcp_dbf *, struct fsf_status_read_buffer *); extern void zfcp_dbf_hba_qdio(struct zfcp_dbf *, unsigned int, int, int); extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); -extern void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *); +extern void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *, u32); extern void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *); extern void zfcp_dbf_san_els_request(struct zfcp_fsf_req *); extern void zfcp_dbf_san_els_response(struct zfcp_fsf_req *); @@ -106,8 +107,7 @@ extern void zfcp_fc_link_test_work(struct work_struct *); extern void zfcp_fc_wka_ports_force_offline(struct zfcp_fc_wka_ports *); extern int zfcp_fc_gs_setup(struct zfcp_adapter *); extern void zfcp_fc_gs_destroy(struct zfcp_adapter *); -extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *); -extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *); +extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *); /* zfcp_fsf.c */ extern int zfcp_fsf_open_port(struct zfcp_erp_action *); @@ -128,8 +128,10 @@ extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *, extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern int zfcp_fsf_status_read(struct zfcp_qdio *); extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); -extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *); -extern int zfcp_fsf_send_els(struct zfcp_send_els *); +extern int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *, struct zfcp_fsf_ct_els *, + mempool_t *); +extern int zfcp_fsf_send_els(struct zfcp_adapter *, u32, + struct zfcp_fsf_ct_els *); extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *, struct scsi_cmnd *); extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index d6d1e78ba0f..6d5ccc053e3 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -22,12 +22,6 @@ static u32 zfcp_fc_rscn_range_mask[] = { [ELS_ADDR_FMT_FAB] = 0x000000, }; -struct zfcp_fc_ns_handler_data { - struct completion done; - void (*handler)(unsigned long); - unsigned long handler_data; -}; - static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port) { if (mutex_lock_interruptible(&wka_port->mutex)) @@ -211,21 +205,10 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req) zfcp_fc_incoming_rscn(fsf_req); } -static void zfcp_fc_ns_handler(unsigned long data) -{ - struct zfcp_fc_ns_handler_data *compl_rec = - (struct zfcp_fc_ns_handler_data *) data; - - if (compl_rec->handler) - compl_rec->handler(compl_rec->handler_data); - - complete(&compl_rec->done); -} - -static void zfcp_fc_ns_gid_pn_eval(unsigned long data) +static void zfcp_fc_ns_gid_pn_eval(void *data) { - struct zfcp_fc_gid_pn *gid_pn = (struct zfcp_fc_gid_pn *) data; - struct zfcp_send_ct *ct = &gid_pn->ct; + struct zfcp_fc_gid_pn *gid_pn = data; + struct zfcp_fsf_ct_els *ct = &gid_pn->ct; struct zfcp_fc_gid_pn_req *gid_pn_req = sg_virt(ct->req); struct zfcp_fc_gid_pn_resp *gid_pn_resp = sg_virt(ct->resp); struct zfcp_port *port = gid_pn->port; @@ -242,18 +225,22 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data) port->d_id = ntoh24(gid_pn_resp->gid_pn.fp_fid); } +static void zfcp_fc_complete(void *data) +{ + complete(data); +} + static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port, struct zfcp_fc_gid_pn *gid_pn) { struct zfcp_adapter *adapter = port->adapter; - struct zfcp_fc_ns_handler_data compl_rec; + DECLARE_COMPLETION_ONSTACK(completion); int ret; /* setup parameters for send generic command */ gid_pn->port = port; - gid_pn->ct.wka_port = &adapter->gs->ds; - gid_pn->ct.handler = zfcp_fc_ns_handler; - gid_pn->ct.handler_data = (unsigned long) &compl_rec; + gid_pn->ct.handler = zfcp_fc_complete; + gid_pn->ct.handler_data = &completion; gid_pn->ct.req = &gid_pn->sg_req; gid_pn->ct.resp = &gid_pn->sg_resp; sg_init_one(&gid_pn->sg_req, &gid_pn->gid_pn_req, @@ -270,12 +257,12 @@ static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port, gid_pn->gid_pn_req.ct_hdr.ct_mr_size = ZFCP_FC_CT_SIZE_PAGE / 4; gid_pn->gid_pn_req.gid_pn.fn_wwpn = port->wwpn; - init_completion(&compl_rec.done); - compl_rec.handler = zfcp_fc_ns_gid_pn_eval; - compl_rec.handler_data = (unsigned long) gid_pn; - ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.gid_pn_req); - if (!ret) - wait_for_completion(&compl_rec.done); + ret = zfcp_fsf_send_ct(&adapter->gs->ds, &gid_pn->ct, + adapter->pool.gid_pn_req); + if (!ret) { + wait_for_completion(&completion); + zfcp_fc_ns_gid_pn_eval(gid_pn); + } return ret; } @@ -374,9 +361,9 @@ void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fc_els_flogi *plogi) port->supported_classes |= FC_COS_CLASS4; } -static void zfcp_fc_adisc_handler(unsigned long data) +static void zfcp_fc_adisc_handler(void *data) { - struct zfcp_fc_els_adisc *adisc = (struct zfcp_fc_els_adisc *) data; + struct zfcp_fc_els_adisc *adisc = data; struct zfcp_port *port = adisc->els.port; struct fc_els_adisc *adisc_resp = &adisc->adisc_resp; @@ -414,6 +401,7 @@ static int zfcp_fc_adisc(struct zfcp_port *port) if (!adisc) return -ENOMEM; + adisc->els.port = port; adisc->els.req = &adisc->req; adisc->els.resp = &adisc->resp; sg_init_one(adisc->els.req, &adisc->adisc_req, @@ -421,21 +409,18 @@ static int zfcp_fc_adisc(struct zfcp_port *port) sg_init_one(adisc->els.resp, &adisc->adisc_resp, sizeof(struct fc_els_adisc)); - adisc->els.adapter = adapter; - adisc->els.port = port; - adisc->els.d_id = port->d_id; adisc->els.handler = zfcp_fc_adisc_handler; - adisc->els.handler_data = (unsigned long) adisc; - adisc->els.ls_code = adisc->adisc_req.adisc_cmd = ELS_ADISC; + adisc->els.handler_data = adisc; /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports without FC-AL-2 capability, so we don't set it */ adisc->adisc_req.adisc_wwpn = fc_host_port_name(adapter->scsi_host); adisc->adisc_req.adisc_wwnn = fc_host_node_name(adapter->scsi_host); + adisc->adisc_req.adisc_cmd = ELS_ADISC; hton24(adisc->adisc_req.adisc_port_id, fc_host_port_id(adapter->scsi_host)); - return zfcp_fsf_send_els(&adisc->els); + return zfcp_fsf_send_els(adapter, port->d_id, &adisc->els); } void zfcp_fc_link_test_work(struct work_struct *work) @@ -520,9 +505,9 @@ out: static int zfcp_fc_send_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, struct zfcp_adapter *adapter, int max_bytes) { - struct zfcp_send_ct *ct = &gpn_ft->ct; + struct zfcp_fsf_ct_els *ct = &gpn_ft->ct; struct zfcp_fc_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); - struct zfcp_fc_ns_handler_data compl_rec; + DECLARE_COMPLETION_ONSTACK(completion); int ret; /* prepare CT IU for GPN_FT */ @@ -537,17 +522,14 @@ static int zfcp_fc_send_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, req->gpn_ft.fn_fc4_type = FC_TYPE_FCP; /* prepare zfcp_send_ct */ - ct->wka_port = &adapter->gs->ds; - ct->handler = zfcp_fc_ns_handler; - ct->handler_data = (unsigned long)&compl_rec; + ct->handler = zfcp_fc_complete; + ct->handler_data = &completion; ct->req = &gpn_ft->sg_req; ct->resp = gpn_ft->sg_resp; - init_completion(&compl_rec.done); - compl_rec.handler = NULL; - ret = zfcp_fsf_send_ct(ct, NULL); + ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct, NULL); if (!ret) - wait_for_completion(&compl_rec.done); + wait_for_completion(&completion); return ret; } @@ -565,13 +547,13 @@ static void zfcp_fc_validate_port(struct zfcp_port *port, struct list_head *lh) list_move_tail(&port->list, lh); } -static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, int max_entries) +static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, + struct zfcp_adapter *adapter, int max_entries) { - struct zfcp_send_ct *ct = &gpn_ft->ct; + struct zfcp_fsf_ct_els *ct = &gpn_ft->ct; struct scatterlist *sg = gpn_ft->sg_resp; struct fc_ct_hdr *hdr = sg_virt(sg); struct fc_gpn_ft_resp *acc = sg_virt(sg); - struct zfcp_adapter *adapter = ct->wka_port->adapter; struct zfcp_port *port, *tmp; unsigned long flags; LIST_HEAD(remove_lh); @@ -665,7 +647,7 @@ void zfcp_fc_scan_ports(struct work_struct *work) for (i = 0; i < 3; i++) { ret = zfcp_fc_send_gpn_ft(gpn_ft, adapter, max_bytes); if (!ret) { - ret = zfcp_fc_eval_gpn_ft(gpn_ft, max_entries); + ret = zfcp_fc_eval_gpn_ft(gpn_ft, adapter, max_entries); if (ret == -EAGAIN) ssleep(1); else @@ -677,160 +659,109 @@ out: zfcp_fc_wka_port_put(&adapter->gs->ds); } - -struct zfcp_els_fc_job { - struct zfcp_send_els els; - struct fc_bsg_job *job; -}; - -static void zfcp_fc_generic_els_handler(unsigned long data) +static void zfcp_fc_ct_els_job_handler(void *data) { - struct zfcp_els_fc_job *els_fc_job = (struct zfcp_els_fc_job *) data; - struct fc_bsg_job *job = els_fc_job->job; - struct fc_bsg_reply *reply = job->reply; + struct fc_bsg_job *job = data; + struct zfcp_fsf_ct_els *zfcp_ct_els = job->dd_data; + int status = zfcp_ct_els->status; + int reply_status; - if (els_fc_job->els.status) { - /* request rejected or timed out */ - reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_REJECT; - goto out; - } - - reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; - reply->reply_payload_rcv_len = job->reply_payload.payload_len; - -out: - job->state_flags = FC_RQST_STATE_DONE; + reply_status = status ? FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK; + job->reply->reply_data.ctels_reply.status = reply_status; + job->reply->reply_payload_rcv_len = job->reply_payload.payload_len; job->job_done(job); - kfree(els_fc_job); } -int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job) +static int zfcp_fc_exec_els_job(struct fc_bsg_job *job, + struct zfcp_adapter *adapter) { - struct zfcp_els_fc_job *els_fc_job; + struct zfcp_fsf_ct_els *els = job->dd_data; struct fc_rport *rport = job->rport; - struct Scsi_Host *shost; - struct zfcp_adapter *adapter; struct zfcp_port *port; - u8 *port_did; - - shost = rport ? rport_to_shost(rport) : job->shost; - adapter = (struct zfcp_adapter *)shost->hostdata[0]; - - if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN)) - return -EINVAL; - - els_fc_job = kzalloc(sizeof(struct zfcp_els_fc_job), GFP_KERNEL); - if (!els_fc_job) - return -ENOMEM; + u32 d_id; - els_fc_job->els.adapter = adapter; if (rport) { port = zfcp_get_port_by_wwpn(adapter, rport->port_name); - if (!port) { - kfree(els_fc_job); + if (!port) return -EINVAL; - } - els_fc_job->els.d_id = port->d_id; + d_id = port->d_id; put_device(&port->sysfs_device); - } else { - port_did = job->request->rqst_data.h_els.port_id; - els_fc_job->els.d_id = (port_did[0] << 16) + - (port_did[1] << 8) + port_did[2]; - } - - els_fc_job->els.req = job->request_payload.sg_list; - els_fc_job->els.resp = job->reply_payload.sg_list; - els_fc_job->els.handler = zfcp_fc_generic_els_handler; - els_fc_job->els.handler_data = (unsigned long) els_fc_job; - els_fc_job->job = job; + } else + d_id = ntoh24(job->request->rqst_data.h_els.port_id); - return zfcp_fsf_send_els(&els_fc_job->els); + return zfcp_fsf_send_els(adapter, d_id, els); } -struct zfcp_ct_fc_job { - struct zfcp_send_ct ct; - struct fc_bsg_job *job; -}; - -static void zfcp_fc_generic_ct_handler(unsigned long data) -{ - struct zfcp_ct_fc_job *ct_fc_job = (struct zfcp_ct_fc_job *) data; - struct fc_bsg_job *job = ct_fc_job->job; - - job->reply->reply_data.ctels_reply.status = ct_fc_job->ct.status ? - FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK; - job->reply->reply_payload_rcv_len = job->reply_payload.payload_len; - job->state_flags = FC_RQST_STATE_DONE; - job->job_done(job); - - zfcp_fc_wka_port_put(ct_fc_job->ct.wka_port); - - kfree(ct_fc_job); -} - -int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) +static int zfcp_fc_exec_ct_job(struct fc_bsg_job *job, + struct zfcp_adapter *adapter) { int ret; u8 gs_type; - struct fc_rport *rport = job->rport; - struct Scsi_Host *shost; - struct zfcp_adapter *adapter; - struct zfcp_ct_fc_job *ct_fc_job; + struct zfcp_fsf_ct_els *ct = job->dd_data; + struct zfcp_fc_wka_port *wka_port; u32 preamble_word1; - shost = rport ? rport_to_shost(rport) : job->shost; - - adapter = (struct zfcp_adapter *)shost->hostdata[0]; - if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN)) - return -EINVAL; - - ct_fc_job = kzalloc(sizeof(struct zfcp_ct_fc_job), GFP_KERNEL); - if (!ct_fc_job) - return -ENOMEM; - preamble_word1 = job->request->rqst_data.r_ct.preamble_word1; gs_type = (preamble_word1 & 0xff000000) >> 24; switch (gs_type) { case FC_FST_ALIAS: - ct_fc_job->ct.wka_port = &adapter->gs->as; + wka_port = &adapter->gs->as; break; case FC_FST_MGMT: - ct_fc_job->ct.wka_port = &adapter->gs->ms; + wka_port = &adapter->gs->ms; break; case FC_FST_TIME: - ct_fc_job->ct.wka_port = &adapter->gs->ts; + wka_port = &adapter->gs->ts; break; case FC_FST_DIR: - ct_fc_job->ct.wka_port = &adapter->gs->ds; + wka_port = &adapter->gs->ds; break; default: - kfree(ct_fc_job); return -EINVAL; /* no such service */ } - ret = zfcp_fc_wka_port_get(ct_fc_job->ct.wka_port); - if (ret) { - kfree(ct_fc_job); + ret = zfcp_fc_wka_port_get(wka_port); + if (ret) return ret; - } - ct_fc_job->ct.req = job->request_payload.sg_list; - ct_fc_job->ct.resp = job->reply_payload.sg_list; - ct_fc_job->ct.handler = zfcp_fc_generic_ct_handler; - ct_fc_job->ct.handler_data = (unsigned long) ct_fc_job; - ct_fc_job->ct.completion = NULL; - ct_fc_job->job = job; + ret = zfcp_fsf_send_ct(wka_port, ct, NULL); + if (ret) + zfcp_fc_wka_port_put(wka_port); - ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL); - if (ret) { - kfree(ct_fc_job); - zfcp_fc_wka_port_put(ct_fc_job->ct.wka_port); - } return ret; } +int zfcp_fc_exec_bsg_job(struct fc_bsg_job *job) +{ + struct Scsi_Host *shost; + struct zfcp_adapter *adapter; + struct zfcp_fsf_ct_els *ct_els = job->dd_data; + + shost = job->rport ? rport_to_shost(job->rport) : job->shost; + adapter = (struct zfcp_adapter *)shost->hostdata[0]; + + if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN)) + return -EINVAL; + + ct_els->req = job->request_payload.sg_list; + ct_els->resp = job->reply_payload.sg_list; + ct_els->handler = zfcp_fc_ct_els_job_handler; + ct_els->handler_data = job; + + switch (job->request->msgcode) { + case FC_BSG_RPT_ELS: + case FC_BSG_HST_ELS_NOLOGIN: + return zfcp_fc_exec_els_job(job, adapter); + case FC_BSG_RPT_CT: + case FC_BSG_HST_CT: + return zfcp_fc_exec_ct_job(job, adapter); + default: + return -EINVAL; + } +} + int zfcp_fc_gs_setup(struct zfcp_adapter *adapter) { struct zfcp_fc_wka_ports *wka_ports; diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index 9c787e043ff..cb2a3669a38 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -15,6 +15,7 @@ #include #include #include +#include "zfcp_fsf.h" #define ZFCP_FC_CT_SIZE_PAGE (PAGE_SIZE - sizeof(struct fc_ct_hdr)) #define ZFCP_FC_GPN_FT_ENT_PAGE (ZFCP_FC_CT_SIZE_PAGE \ @@ -55,7 +56,7 @@ struct zfcp_fc_gid_pn_resp { * @gid_pn_resp: GID_PN response data */ struct zfcp_fc_gid_pn { - struct zfcp_send_ct ct; + struct zfcp_fsf_ct_els ct; struct scatterlist sg_req; struct scatterlist sg_resp; struct zfcp_fc_gid_pn_req gid_pn_req; @@ -90,7 +91,7 @@ struct zfcp_fc_gpn_ft_resp { * @sg_resp: scatter list entries for gpn_ft responses (per memory page) */ struct zfcp_fc_gpn_ft { - struct zfcp_send_ct ct; + struct zfcp_fsf_ct_els ct; struct scatterlist sg_req; struct scatterlist sg_resp[ZFCP_FC_GPN_FT_NUM_BUFS]; }; @@ -104,7 +105,7 @@ struct zfcp_fc_gpn_ft { * @adisc_resp: ELS ADISC response data */ struct zfcp_fc_els_adisc { - struct zfcp_send_els els; + struct zfcp_fsf_ct_els els; struct scatterlist req; struct scatterlist resp; struct fc_els_adisc adisc_req; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 057c93777f9..fb580b14a68 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -961,10 +961,10 @@ out: static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; - struct zfcp_send_ct *send_ct = req->data; + struct zfcp_fsf_ct_els *ct = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; - send_ct->status = -EINVAL; + ct->status = -EINVAL; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; @@ -972,7 +972,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_GOOD: zfcp_dbf_san_ct_response(req); - send_ct->status = 0; + ct->status = 0; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: zfcp_fsf_class_not_supp(req); @@ -1004,8 +1004,8 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) } skip_fsfstatus: - if (send_ct->handler) - send_ct->handler(send_ct->handler_data); + if (ct->handler) + ct->handler(ct->handler_data); } static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale, @@ -1094,9 +1094,9 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req, * @ct: pointer to struct zfcp_send_ct with data for request * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req */ -int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool) +int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, + struct zfcp_fsf_ct_els *ct, mempool_t *pool) { - struct zfcp_fc_wka_port *wka_port = ct->wka_port; struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; int ret = -EIO; @@ -1122,7 +1122,7 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool) req->qtcb->header.port_handle = wka_port->handle; req->data = ct; - zfcp_dbf_san_ct_request(req); + zfcp_dbf_san_ct_request(req, wka_port->d_id); ret = zfcp_fsf_req_send(req); if (ret) @@ -1139,7 +1139,7 @@ out: static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) { - struct zfcp_send_els *send_els = req->data; + struct zfcp_fsf_ct_els *send_els = req->data; struct zfcp_port *port = send_els->port; struct fsf_qtcb_header *header = &req->qtcb->header; @@ -1159,9 +1159,6 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]){ case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - if (port && (send_els->ls_code != ELS_ADISC)) - zfcp_fc_test_link(port); - /*fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: case FSF_SQ_RETRY_IF_POSSIBLE: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1193,10 +1190,11 @@ skip_fsfstatus: * zfcp_fsf_send_els - initiate an ELS command (FC-FS) * @els: pointer to struct zfcp_send_els with data for the command */ -int zfcp_fsf_send_els(struct zfcp_send_els *els) +int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, + struct zfcp_fsf_ct_els *els) { struct zfcp_fsf_req *req; - struct zfcp_qdio *qdio = els->adapter->qdio; + struct zfcp_qdio *qdio = adapter->qdio; int ret = -EIO; spin_lock_bh(&qdio->req_q_lock); @@ -1216,7 +1214,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) if (ret) goto failed_send; - hton24(req->qtcb->bottom.support.d_id, els->d_id); + hton24(req->qtcb->bottom.support.d_id, d_id); req->handler = zfcp_fsf_send_els_handler; req->data = els; diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 206b7eaff5a..b3de682b64c 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -437,4 +437,22 @@ struct zfcp_blk_drv_data { u64 fabric_lat; } __attribute__ ((packed)); +/** + * struct zfcp_fsf_ct_els - zfcp data for ct or els request + * @req: scatter-gather list for request + * @resp: scatter-gather list for response + * @handler: handler function (called for response to the request) + * @handler_data: data passed to handler function + * @port: Optional pointer to port for zfcp internal ELS (only test link ADISC) + * @status: used to pass error status to calling function + */ +struct zfcp_fsf_ct_els { + struct scatterlist *req; + struct scatterlist *resp; + void (*handler)(void *); + void *handler_data; + struct zfcp_port *port; + int status; +}; + #endif /* FSF_H */ diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 3d168410036..535f36cf281 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -14,6 +14,7 @@ #include #include "zfcp_ext.h" #include "zfcp_dbf.h" +#include "zfcp_fc.h" static unsigned int default_depth = 32; module_param_named(queue_depth, default_depth, uint, 0600); @@ -628,20 +629,6 @@ void zfcp_scsi_scan(struct work_struct *work) put_device(&unit->sysfs_device); } -static int zfcp_execute_fc_job(struct fc_bsg_job *job) -{ - switch (job->request->msgcode) { - case FC_BSG_RPT_ELS: - case FC_BSG_HST_ELS_NOLOGIN: - return zfcp_fc_execute_els_fc_job(job); - case FC_BSG_RPT_CT: - case FC_BSG_HST_CT: - return zfcp_fc_execute_ct_fc_job(job); - default: - return -EINVAL; - } -} - struct fc_function_template zfcp_transport_functions = { .show_starget_port_id = 1, .show_starget_port_name = 1, @@ -662,13 +649,14 @@ struct fc_function_template zfcp_transport_functions = { .get_host_port_state = zfcp_get_host_port_state, .terminate_rport_io = zfcp_scsi_terminate_rport_io, .show_host_port_state = 1, - .bsg_request = zfcp_execute_fc_job, + .bsg_request = zfcp_fc_exec_bsg_job, /* no functions registered for following dynamic attributes but directly set by LLDD */ .show_host_port_type = 1, .show_host_speed = 1, .show_host_port_id = 1, .disable_target_scan = 1, + .dd_bsg_size = sizeof(struct zfcp_fsf_ct_els), }; struct zfcp_data zfcp_data = { -- cgit v1.2.3 From ee744622c65cd66824e8dd1b9509e515c800de14 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:14 +0100 Subject: [SCSI] zfcp: Improve ELS ADISC handling Introduce kmem_cache for ELS ADISC data to guarantee the required hardware alignment and free the allocated memory in case the send failes. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 8 ++++++++ drivers/s390/scsi/zfcp_def.h | 1 + drivers/s390/scsi/zfcp_fc.c | 11 ++++++++--- 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 58bb17732f5..9d0c941b7d3 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -179,6 +179,11 @@ static int __init zfcp_module_init(void) if (!zfcp_data.gid_pn_cache) goto out_gid_cache; + zfcp_data.adisc_cache = zfcp_cache_hw_align("zfcp_adisc", + sizeof(struct zfcp_fc_els_adisc)); + if (!zfcp_data.adisc_cache) + goto out_adisc_cache; + zfcp_data.scsi_transport_template = fc_attach_transport(&zfcp_transport_functions); if (!zfcp_data.scsi_transport_template) @@ -206,6 +211,8 @@ out_ccw_register: out_misc: fc_release_transport(zfcp_data.scsi_transport_template); out_transport: + kmem_cache_destroy(zfcp_data.adisc_cache); +out_adisc_cache: kmem_cache_destroy(zfcp_data.gid_pn_cache); out_gid_cache: kmem_cache_destroy(zfcp_data.sr_buffer_cache); @@ -224,6 +231,7 @@ static void __exit zfcp_module_exit(void) ccw_driver_unregister(&zfcp_ccw_driver); misc_deregister(&zfcp_cfdc_misc); fc_release_transport(zfcp_data.scsi_transport_template); + kmem_cache_destroy(zfcp_data.adisc_cache); kmem_cache_destroy(zfcp_data.gid_pn_cache); kmem_cache_destroy(zfcp_data.sr_buffer_cache); kmem_cache_destroy(zfcp_data.qtcb_cache); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 21b29804a7a..469d57f105d 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -347,6 +347,7 @@ struct zfcp_data { struct kmem_cache *qtcb_cache; struct kmem_cache *sr_buffer_cache; struct kmem_cache *gid_pn_cache; + struct kmem_cache *adisc_cache; }; /********************** ZFCP SPECIFIC DEFINES ********************************/ diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 6d5ccc053e3..ac5e3b7a357 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -389,15 +389,16 @@ static void zfcp_fc_adisc_handler(void *data) out: atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); put_device(&port->sysfs_device); - kfree(adisc); + kmem_cache_free(zfcp_data.adisc_cache, adisc); } static int zfcp_fc_adisc(struct zfcp_port *port) { struct zfcp_fc_els_adisc *adisc; struct zfcp_adapter *adapter = port->adapter; + int ret; - adisc = kzalloc(sizeof(struct zfcp_fc_els_adisc), GFP_ATOMIC); + adisc = kmem_cache_alloc(zfcp_data.adisc_cache, GFP_ATOMIC); if (!adisc) return -ENOMEM; @@ -420,7 +421,11 @@ static int zfcp_fc_adisc(struct zfcp_port *port) hton24(adisc->adisc_req.adisc_port_id, fc_host_port_id(adapter->scsi_host)); - return zfcp_fsf_send_els(adapter, port->d_id, &adisc->els); + ret = zfcp_fsf_send_els(adapter, port->d_id, &adisc->els); + if (ret) + kmem_cache_free(zfcp_data.adisc_cache, adisc); + + return ret; } void zfcp_fc_link_test_work(struct work_struct *work) -- cgit v1.2.3 From 4c571c659e9d41332b6981ca5379047681ce9d2f Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:15 +0100 Subject: [SCSI] zfcp: Update FSF error reporting The SCSI midlayer retries commands based on the remote port state and the command status reported by the driver. Returning DID_TRANSPORT_DISRUPTED is a better approach, use this for reporting FSF errors back to the SCSI midlayer. See http://marc.info/?l=linux-scsi&m=125668044215051&w=2 as reference. There is also no need in special treatment of ABORTED commands, so remove the ZFCP_STATUS_FSFREQ_ABORTED, the commands are then returned with DID_TRANSPORT_DISRUPTED. Also remove the ZFCP_STATUS_FSFREQ_RETRY: It is useless, no retry is happening in the FSF layer and nobody checks the state of this flag. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 2 -- drivers/s390/scsi/zfcp_fsf.c | 38 +++++++++++--------------------------- 2 files changed, 11 insertions(+), 29 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 469d57f105d..e43c6334bf6 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -110,10 +110,8 @@ #define ZFCP_STATUS_FSFREQ_CLEANUP 0x00000010 #define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED 0x00000040 #define ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED 0x00000080 -#define ZFCP_STATUS_FSFREQ_ABORTED 0x00000100 #define ZFCP_STATUS_FSFREQ_TMFUNCFAILED 0x00000200 #define ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP 0x00000400 -#define ZFCP_STATUS_FSFREQ_RETRY 0x00000800 #define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000 /************************* STRUCTURE DEFINITIONS *****************************/ diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index fb580b14a68..3089a05c36a 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -315,7 +315,6 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req) case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: return; case FSF_SQ_COMMAND_ABORTED: - req->status |= ZFCP_STATUS_FSFREQ_ABORTED; break; case FSF_SQ_NO_RECOM: dev_err(&req->adapter->ccw_device->dev, @@ -356,8 +355,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) zfcp_dbf_hba_fsf_response(req); if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ + req->status |= ZFCP_STATUS_FSFREQ_ERROR; return; } @@ -375,7 +373,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) case FSF_PROT_ERROR_STATE: case FSF_PROT_SEQ_NUMB_ERROR: zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req); - req->status |= ZFCP_STATUS_FSFREQ_RETRY; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PROT_UNSUPP_QTCB_TYPE: dev_err(&adapter->ccw_device->dev, @@ -884,13 +882,11 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) break; case FSF_PORT_BOXED: zfcp_erp_port_boxed(unit->port, "fsafch3", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_BOXED: zfcp_erp_unit_boxed(unit, "fsafch4", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (fsq->word[0]) { @@ -988,8 +984,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) case FSF_ACCESS_DENIED: break; case FSF_PORT_BOXED: - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_HANDLE_NOT_VALID: zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req); @@ -1761,9 +1756,7 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) &unit->status); read_unlock(&port->unit_list_lock); zfcp_erp_port_boxed(port, "fscpph2", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; - + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { @@ -1867,8 +1860,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) break; case FSF_PORT_BOXED: zfcp_erp_port_boxed(unit->port, "fsouh_2", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_SHARING_VIOLATION: if (header->fsf_status_qual.word[0]) @@ -2030,8 +2022,7 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) break; case FSF_PORT_BOXED: zfcp_erp_port_boxed(unit->port, "fscuh_3", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (req->qtcb->header.fsf_status_qual.word[0]) { @@ -2164,13 +2155,8 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) return; } - if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { - set_host_byte(scpnt, DID_SOFT_ERROR); - goto skip_fsfstatus; - } - if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { - set_host_byte(scpnt, DID_ERROR); + set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED); goto skip_fsfstatus; } @@ -2266,13 +2252,11 @@ static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req) break; case FSF_PORT_BOXED: zfcp_erp_port_boxed(unit->port, "fssfch5", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_BOXED: zfcp_erp_unit_boxed(unit, "fssfch6", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: if (header->fsf_status_qual.word[0] == -- cgit v1.2.3 From af4de36d911ab907b92c5f3f81ceff8474ed7485 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:16 +0100 Subject: [SCSI] zfcp: Block scsi_eh thread for rport state BLOCKED In case the SCSI error recovery starts because of a SCSI command timeout, but then something else triggers the rport to be deleted, the SCSI error recovery will run to the end and set the SCSI device offline. To prevent this, call the FC transport function fc_block_scsi_eh which waits until the rport leaves the BLOCKED state. This guarantees that communication is possible if the rport is ONLINE, or the SCSI devices will be removed if the rport state switches to NOT_PRESENT. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_scsi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 535f36cf281..3f1011663af 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -209,6 +209,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) break; zfcp_erp_wait(adapter); + fc_block_scsi_eh(scpnt); if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL, @@ -248,6 +249,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) break; zfcp_erp_wait(adapter); + fc_block_scsi_eh(scpnt); if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt); @@ -289,6 +291,7 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt); zfcp_erp_wait(adapter); + fc_block_scsi_eh(scpnt); return SUCCESS; } -- cgit v1.2.3 From 0fdd21330a9d7bc6790eae0aed768052c315ae44 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:17 +0100 Subject: [SCSI] zfcp: Activate fc4s attributes for zfcp in FC transport class Enable the display of supported and active fc4s for zfcp in the FC transport class. zfcp only supports FCP, so simply hard-code this information. The zfcp hbaapi already has this information hardcoded, but this would allow to switch from the coding in the zfcp hbaapi to the common FC transport attributes in the future. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 2 ++ drivers/s390/scsi/zfcp_scsi.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 3089a05c36a..482dcd97aa5 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -495,6 +495,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) fc_host_port_id(shost) = ntoh24(bottom->s_id); fc_host_speed(shost) = bottom->fc_link_speed; fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; + fc_host_supported_fc4s(shost)[2] = 1; /* FCP */ + fc_host_active_fc4s(shost)[2] = 1; /* FCP */ adapter->hydra_version = bottom->adapter_type; adapter->timer_ticks = bottom->timer_interval; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 3f1011663af..72bb9bcf735 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -643,6 +643,7 @@ struct fc_function_template zfcp_transport_functions = { .show_host_port_name = 1, .show_host_permanent_port_name = 1, .show_host_supported_classes = 1, + .show_host_supported_fc4s = 1, .show_host_supported_speeds = 1, .show_host_maxframe_size = 1, .show_host_serial_number = 1, @@ -652,6 +653,7 @@ struct fc_function_template zfcp_transport_functions = { .get_host_port_state = zfcp_get_host_port_state, .terminate_rport_io = zfcp_scsi_terminate_rport_io, .show_host_port_state = 1, + .show_host_active_fc4s = 1, .bsg_request = zfcp_fc_exec_bsg_job, /* no functions registered for following dynamic attributes but directly set by LLDD */ -- cgit v1.2.3 From 54987386ee3790f3900de4df2ed4deb0e18dfc9f Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 24 Nov 2009 16:54:18 +0100 Subject: [SCSI] zfcp: Remove flag ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP The flag ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP is never set and hence can be removed. This is a leftover from the time when zfcp had to decide whether the target supports a "logical unit reset" or not. Nowadays, the SCSI midlayer calls the eh_device_reset_handler or the eh_target_reset_handler and zfcp simply maps this to a "logical unit reset" or a "target reset". Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 1 - drivers/s390/scsi/zfcp_scsi.c | 3 --- 2 files changed, 4 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index e43c6334bf6..e1b5b88e2dd 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -111,7 +111,6 @@ #define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED 0x00000040 #define ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED 0x00000080 #define ZFCP_STATUS_FSFREQ_TMFUNCFAILED 0x00000200 -#define ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP 0x00000400 #define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000 /************************* STRUCTURE DEFINITIONS *****************************/ diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 72bb9bcf735..771cc536a98 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -264,9 +264,6 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { zfcp_dbf_scsi_devreset("fail", tm_flags, unit, scpnt); retval = FAILED; - } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) { - zfcp_dbf_scsi_devreset("nsup", tm_flags, unit, scpnt); - retval = FAILED; } else zfcp_dbf_scsi_devreset("okay", tm_flags, unit, scpnt); -- cgit v1.2.3