Commit ecf0c772 authored by Swen Schillig's avatar Swen Schillig Committed by James Bottomley

[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: default avatarSwen Schillig <swen@vnet.ibm.com>
Signed-off-by: default avatarChristof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 0a55256d
...@@ -187,7 +187,6 @@ static int __init zfcp_module_init(void) ...@@ -187,7 +187,6 @@ static int __init zfcp_module_init(void)
goto out_gid_cache; goto out_gid_cache;
mutex_init(&zfcp_data.config_mutex); mutex_init(&zfcp_data.config_mutex);
rwlock_init(&zfcp_data.config_lock);
zfcp_data.scsi_transport_template = zfcp_data.scsi_transport_template =
fc_attach_transport(&zfcp_transport_functions); fc_attach_transport(&zfcp_transport_functions);
...@@ -238,12 +237,18 @@ module_init(zfcp_module_init); ...@@ -238,12 +237,18 @@ module_init(zfcp_module_init);
*/ */
struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
{ {
unsigned long flags;
struct zfcp_unit *unit; 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) && if ((unit->fcp_lun == fcp_lun) &&
!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) {
return unit; zfcp_unit_get(unit);
read_unlock_irqrestore(&port->unit_list_lock, flags);
return unit;
}
read_unlock_irqrestore(&port->unit_list_lock, flags);
return NULL; return NULL;
} }
...@@ -257,12 +262,18 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) ...@@ -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, struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter,
u64 wwpn) u64 wwpn)
{ {
unsigned long flags;
struct zfcp_port *port; 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) && 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; return port;
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
return NULL; return NULL;
} }
...@@ -284,12 +295,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) ...@@ -284,12 +295,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
{ {
struct zfcp_unit *unit; struct zfcp_unit *unit;
read_lock_irq(&zfcp_data.config_lock); unit = zfcp_get_unit_by_lun(port, fcp_lun);
if (zfcp_get_unit_by_lun(port, fcp_lun)) { if (unit) {
read_unlock_irq(&zfcp_data.config_lock); zfcp_unit_put(unit);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
read_unlock_irq(&zfcp_data.config_lock);
unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
if (!unit) if (!unit)
...@@ -335,13 +345,13 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) ...@@ -335,13 +345,13 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
zfcp_unit_get(unit); zfcp_unit_get(unit);
write_lock_irq(&zfcp_data.config_lock); write_lock_irq(&port->unit_list_lock);
list_add_tail(&unit->list, &port->unit_list_head); 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_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status);
write_unlock_irq(&zfcp_data.config_lock);
zfcp_port_get(port); zfcp_port_get(port);
return unit; return unit;
...@@ -356,11 +366,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) ...@@ -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) void zfcp_unit_dequeue(struct zfcp_unit *unit)
{ {
struct zfcp_port *port = unit->port;
wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0); wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0);
write_lock_irq(&zfcp_data.config_lock); list_del(&unit->list); /* no list locking required */
list_del(&unit->list); zfcp_port_put(port);
write_unlock_irq(&zfcp_data.config_lock);
zfcp_port_put(unit->port);
sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs);
device_unregister(&unit->sysfs_device); device_unregister(&unit->sysfs_device);
} }
...@@ -539,11 +549,13 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -539,11 +549,13 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
if (zfcp_fc_gs_setup(adapter)) if (zfcp_fc_gs_setup(adapter))
goto generic_services_failed; 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->remove_wq);
init_waitqueue_head(&adapter->erp_ready_wq); init_waitqueue_head(&adapter->erp_ready_wq);
init_waitqueue_head(&adapter->erp_done_wqh); 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_ready_head);
INIT_LIST_HEAD(&adapter->erp_running_head); INIT_LIST_HEAD(&adapter->erp_running_head);
...@@ -650,19 +662,20 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, ...@@ -650,19 +662,20 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
{ {
struct zfcp_port *port; struct zfcp_port *port;
read_lock_irq(&zfcp_data.config_lock); port = zfcp_get_port_by_wwpn(adapter, wwpn);
if (zfcp_get_port_by_wwpn(adapter, wwpn)) { if (port) {
read_unlock_irq(&zfcp_data.config_lock); zfcp_port_put(port);
return ERR_PTR(-EINVAL); return ERR_PTR(-EEXIST);
} }
read_unlock_irq(&zfcp_data.config_lock);
port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL);
if (!port) if (!port)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
rwlock_init(&port->unit_list_lock);
INIT_LIST_HEAD(&port->unit_list);
init_waitqueue_head(&port->remove_wq); 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->gid_pn_work, zfcp_fc_port_did_lookup);
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
INIT_WORK(&port->rport_work, zfcp_scsi_rport_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, ...@@ -698,13 +711,13 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
zfcp_port_get(port); zfcp_port_get(port);
write_lock_irq(&zfcp_data.config_lock); write_lock_irq(&adapter->port_list_lock);
list_add_tail(&port->list, &adapter->port_list_head); 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_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status);
write_unlock_irq(&zfcp_data.config_lock);
zfcp_adapter_get(adapter); zfcp_adapter_get(adapter);
return port; return port;
} }
...@@ -715,12 +728,11 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, ...@@ -715,12 +728,11 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
*/ */
void zfcp_port_dequeue(struct zfcp_port *port) void zfcp_port_dequeue(struct zfcp_port *port)
{ {
write_lock_irq(&zfcp_data.config_lock); struct zfcp_adapter *adapter = port->adapter;
list_del(&port->list);
write_unlock_irq(&zfcp_data.config_lock); list_del(&port->list); /* no list locking required here */
wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
cancel_work_sync(&port->rport_work); /* usually not necessary */ zfcp_adapter_put(adapter);
zfcp_adapter_put(port->adapter);
sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs);
device_unregister(&port->sysfs_device); device_unregister(&port->sysfs_device);
} }
......
...@@ -100,10 +100,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) ...@@ -100,10 +100,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
mutex_lock(&zfcp_data.config_mutex); mutex_lock(&zfcp_data.config_mutex);
adapter = dev_get_drvdata(&ccw_device->dev); adapter = dev_get_drvdata(&ccw_device->dev);
if (!adapter)
goto out;
mutex_unlock(&zfcp_data.config_mutex); mutex_unlock(&zfcp_data.config_mutex);
if (!adapter)
return;
cancel_work_sync(&adapter->scan_work); cancel_work_sync(&adapter->scan_work);
mutex_lock(&zfcp_data.config_mutex); mutex_lock(&zfcp_data.config_mutex);
...@@ -111,18 +112,21 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) ...@@ -111,18 +112,21 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
/* this also removes the scsi devices, so call it first */ /* this also removes the scsi devices, so call it first */
zfcp_adapter_scsi_unregister(adapter); zfcp_adapter_scsi_unregister(adapter);
write_lock_irq(&zfcp_data.config_lock); write_lock_irq(&adapter->port_list_lock);
list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { list_for_each_entry_safe(port, p, &adapter->port_list, list) {
list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { write_lock(&port->unit_list_lock);
list_move(&unit->list, &unit_remove_lh); list_for_each_entry_safe(unit, u, &port->unit_list, list) {
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE,
&unit->status); &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); 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); 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(port, p, &port_remove_lh, list) {
list_for_each_entry_safe(unit, u, &unit_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) ...@@ -131,9 +135,6 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
} }
wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
zfcp_adapter_dequeue(adapter); zfcp_adapter_dequeue(adapter);
out:
mutex_unlock(&zfcp_data.config_mutex);
} }
/** /**
......
...@@ -461,7 +461,8 @@ struct zfcp_adapter { ...@@ -461,7 +461,8 @@ struct zfcp_adapter {
u32 hardware_version; /* of FCP channel */ u32 hardware_version; /* of FCP channel */
u16 timer_ticks; /* time int for a tick */ u16 timer_ticks; /* time int for a tick */
struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ 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 */ unsigned long req_no; /* unique FSF req number */
struct list_head *req_list; /* list of pending reqs */ struct list_head *req_list; /* list of pending reqs */
spinlock_t req_list_lock; /* request list lock */ spinlock_t req_list_lock; /* request list lock */
...@@ -504,7 +505,8 @@ struct zfcp_port { ...@@ -504,7 +505,8 @@ struct zfcp_port {
wait_queue_head_t remove_wq; /* can be used to wait for wait_queue_head_t remove_wq; /* can be used to wait for
refcount drop to zero */ refcount drop to zero */
struct zfcp_adapter *adapter; /* adapter used to access port */ 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 */ atomic_t status; /* status of this remote port */
u64 wwnn; /* WWNN if known */ u64 wwnn; /* WWNN if known */
u64 wwpn; /* WWPN */ u64 wwpn; /* WWPN */
...@@ -601,9 +603,6 @@ struct zfcp_fsf_req { ...@@ -601,9 +603,6 @@ struct zfcp_fsf_req {
struct zfcp_data { struct zfcp_data {
struct scsi_host_template scsi_host_template; struct scsi_host_template scsi_host_template;
struct scsi_transport_template *scsi_transport_template; struct scsi_transport_template *scsi_transport_template;
rwlock_t config_lock; /* serialises changes
to adapter/port/unit
lists */
struct mutex config_mutex; struct mutex config_mutex;
struct kmem_cache *gpn_ft_cache; struct kmem_cache *gpn_ft_cache;
struct kmem_cache *qtcb_cache; struct kmem_cache *qtcb_cache;
......
This diff is collapsed.
...@@ -145,10 +145,11 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, ...@@ -145,10 +145,11 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
struct fcp_rscn_element *elem) struct fcp_rscn_element *elem)
{ {
unsigned long flags; unsigned long flags;
struct zfcp_adapter *adapter = fsf_req->adapter;
struct zfcp_port *port; struct zfcp_port *port;
read_lock_irqsave(&zfcp_data.config_lock, flags); read_lock_irqsave(&adapter->port_list_lock, flags);
list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { list_for_each_entry(port, &adapter->port_list, list) {
if ((port->d_id & range) == (elem->nport_did & range)) if ((port->d_id & range) == (elem->nport_did & range))
zfcp_fc_test_link(port); zfcp_fc_test_link(port);
if (!port->d_id) if (!port->d_id)
...@@ -156,8 +157,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, ...@@ -156,8 +157,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_STATUS_COMMON_ERP_FAILED,
"fcrscn1", NULL); "fcrscn1", NULL);
} }
read_unlock_irqrestore(&adapter->port_list_lock, flags);
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
} }
static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) 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) ...@@ -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) static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn)
{ {
unsigned long flags;
struct zfcp_adapter *adapter = req->adapter; struct zfcp_adapter *adapter = req->adapter;
struct zfcp_port *port; struct zfcp_port *port;
unsigned long flags;
read_lock_irqsave(&zfcp_data.config_lock, flags); read_lock_irqsave(&adapter->port_list_lock, flags);
list_for_each_entry(port, &adapter->port_list_head, list) list_for_each_entry(port, &adapter->port_list, list)
if (port->wwpn == wwpn) if (port->wwpn == wwpn) {
zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req);
break; break;
read_unlock_irqrestore(&zfcp_data.config_lock, flags); }
read_unlock_irqrestore(&adapter->port_list_lock, flags);
if (port && (port->wwpn == wwpn))
zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req);
} }
static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) 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, ...@@ -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) 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)) if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC))
return; return;
atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status);
if ((port->supported_classes != 0) || if ((port->supported_classes != 0) ||
!list_empty(&port->unit_list_head)) { !list_empty(&port->unit_list)) {
zfcp_port_put(port); zfcp_port_put(port);
return; return;
} }
zfcp_erp_port_shutdown(port, 0, "fcpval1", NULL); zfcp_erp_port_shutdown(port, 0, "fcpval1", NULL);
zfcp_erp_wait(adapter);
zfcp_port_put(port); zfcp_port_put(port);
zfcp_port_dequeue(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) ...@@ -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 gpn_ft_resp_acc *acc = sg_virt(sg);
struct zfcp_adapter *adapter = ct->wka_port->adapter; struct zfcp_adapter *adapter = ct->wka_port->adapter;
struct zfcp_port *port, *tmp; struct zfcp_port *port, *tmp;
unsigned long flags;
u32 d_id; u32 d_id;
int ret = 0, x, last = 0; 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) ...@@ -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 */ /* skip the adapter's port and known remote ports */
if (acc->wwpn == fc_host_port_name(adapter->scsi_host)) if (acc->wwpn == fc_host_port_name(adapter->scsi_host))
continue; continue;
port = zfcp_get_port_by_wwpn(adapter, acc->wwpn);
if (port)
continue;
port = zfcp_port_enqueue(adapter, acc->wwpn, port = zfcp_port_enqueue(adapter, acc->wwpn,
ZFCP_STATUS_COMMON_NOESC, d_id); ZFCP_STATUS_COMMON_NOESC, d_id);
if (IS_ERR(port)) if (!IS_ERR(port))
ret = PTR_ERR(port);
else
zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL); zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL);
else if (PTR_ERR(port) != -EEXIST)
ret = PTR_ERR(port);
} }
zfcp_erp_wait(adapter); 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); zfcp_fc_validate_port(port);
write_unlock_irqrestore(&adapter->port_list_lock, flags);
mutex_unlock(&zfcp_data.config_mutex); mutex_unlock(&zfcp_data.config_mutex);
return ret; return ret;
} }
...@@ -760,15 +756,14 @@ int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job) ...@@ -760,15 +756,14 @@ int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job)
els_fc_job->els.adapter = adapter; els_fc_job->els.adapter = adapter;
if (rport) { if (rport) {
read_lock_irq(&zfcp_data.config_lock);
port = zfcp_get_port_by_wwpn(adapter, rport->port_name); 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) { if (!port) {
kfree(els_fc_job); kfree(els_fc_job);
return -EINVAL; return -EINVAL;
} }
els_fc_job->els.d_id = port->d_id;
zfcp_port_put(port);
} else { } else {
port_did = job->request->rqst_data.h_els.port_id; port_did = job->request->rqst_data.h_els.port_id;
els_fc_job->els.d_id = (port_did[0] << 16) + els_fc_job->els.d_id = (port_did[0] << 16) +
......
...@@ -122,36 +122,32 @@ void zfcp_fsf_req_free(struct zfcp_fsf_req *req) ...@@ -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) 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 fsf_status_read_buffer *sr_buf = req->data;
struct zfcp_adapter *adapter = req->adapter; struct zfcp_adapter *adapter = req->adapter;
struct zfcp_port *port; struct zfcp_port *port;
int d_id = sr_buf->d_id & ZFCP_DID_MASK; int d_id = sr_buf->d_id & ZFCP_DID_MASK;
unsigned long flags;
read_lock_irqsave(&zfcp_data.config_lock, flags); read_lock_irqsave(&adapter->port_list_lock, flags);
list_for_each_entry(port, &adapter->port_list_head, list) list_for_each_entry(port, &adapter->port_list, list)
if (port->d_id == d_id) { if (port->d_id == d_id) {
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
zfcp_erp_port_reopen(port, 0, "fssrpc1", req); 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, static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
struct fsf_link_down_info *link_down) struct fsf_link_down_info *link_down)
{ {
struct zfcp_adapter *adapter = req->adapter; struct zfcp_adapter *adapter = req->adapter;
unsigned long flags;
if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)
return; return;
atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
read_lock_irqsave(&zfcp_data.config_lock, flags);
zfcp_scsi_schedule_rports_block(adapter); zfcp_scsi_schedule_rports_block(adapter);
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
if (!link_down) if (!link_down)
goto out; goto out;
...@@ -1765,9 +1761,11 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) ...@@ -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 /* can't use generic zfcp_erp_modify_port_status because
* ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); 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, atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
&unit->status); &unit->status);
read_unlock(&port->unit_list_lock);
zfcp_erp_port_boxed(port, "fscpph2", req); zfcp_erp_port_boxed(port, "fscpph2", req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR | req->status |= ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY; ZFCP_STATUS_FSFREQ_RETRY;
...@@ -1787,9 +1785,11 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) ...@@ -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 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
*/ */
atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); 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, atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
&unit->status); &unit->status);
read_unlock(&port->unit_list_lock);
break; break;
} }
} }
......
...@@ -128,49 +128,44 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, ...@@ -128,49 +128,44 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
} }
static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter, static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter,
int channel, unsigned int id, unsigned int id, u64 lun)
unsigned int lun)
{ {
unsigned long flags;
struct zfcp_port *port; struct zfcp_port *port;
struct zfcp_unit *unit; struct zfcp_unit *unit = NULL;
int scsi_lun;
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)) if (!port->rport || (id != port->rport->scsi_target_id))
continue; continue;
list_for_each_entry(unit, &port->unit_list_head, list) { unit = zfcp_get_unit_by_lun(port, lun);
scsi_lun = scsilun_to_int( if (unit)
(struct scsi_lun *)&unit->fcp_lun); break;
if (lun == scsi_lun)
return unit;
}
} }
read_unlock_irqrestore(&adapter->port_list_lock, flags);
return NULL; return unit;
} }
static int zfcp_scsi_slave_alloc(struct scsi_device *sdp) static int zfcp_scsi_slave_alloc(struct scsi_device *sdp)
{ {
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter;
struct zfcp_unit *unit; struct zfcp_unit *unit;
unsigned long flags; u64 lun;
int retval = -ENXIO;
adapter = (struct zfcp_adapter *) sdp->host->hostdata[0]; adapter = (struct zfcp_adapter *) sdp->host->hostdata[0];
if (!adapter) if (!adapter)
goto out; goto out;
read_lock_irqsave(&zfcp_data.config_lock, flags); int_to_scsilun(sdp->lun, (struct scsi_lun *)&lun);
unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun); unit = zfcp_unit_lookup(adapter, sdp->id, lun);
if (unit) { if (unit) {
sdp->hostdata = unit; sdp->hostdata = unit;
unit->device = sdp; unit->device = sdp;
zfcp_unit_get(unit); return 0;
retval = 0;
} }
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
out: out:
return retval; return -ENXIO;
} }
static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
...@@ -338,12 +333,12 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) ...@@ -338,12 +333,12 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
if (!shost) if (!shost)
return; return;
read_lock_irq(&zfcp_data.config_lock); read_lock_irq(&adapter->port_list_lock);
list_for_each_entry(port, &adapter->port_list_head, list) list_for_each_entry(port, &adapter->port_list, list)
if (port->rport) if (port->rport)
port->rport = NULL; port->rport = NULL;
read_unlock_irq(&adapter->port_list_lock);
read_unlock_irq(&zfcp_data.config_lock);
fc_remove_host(shost); fc_remove_host(shost);
scsi_remove_host(shost); scsi_remove_host(shost);
scsi_host_put(shost); scsi_host_put(shost);
...@@ -508,7 +503,7 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) ...@@ -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 * @rport: The FC rport where to teminate I/O
* *
* Abort all pending SCSI commands for a port by closing the * 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. * overwriting a reopen.
*/ */
static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) 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) ...@@ -518,11 +513,7 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
struct zfcp_adapter *adapter = struct zfcp_adapter *adapter =
(struct zfcp_adapter *)shost->hostdata[0]; (struct zfcp_adapter *)shost->hostdata[0];
write_lock_irq(&zfcp_data.config_lock);
port = zfcp_get_port_by_wwpn(adapter, rport->port_name); 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) { if (port) {
zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
...@@ -589,10 +580,13 @@ void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) ...@@ -589,10 +580,13 @@ void zfcp_scsi_schedule_rport_block(struct zfcp_port *port)
void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter)
{ {
unsigned long flags;
struct zfcp_port *port; 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); zfcp_scsi_schedule_rport_block(port);
read_unlock_irqrestore(&adapter->port_list_lock, flags);
} }
void zfcp_scsi_rport_work(struct work_struct *work) void zfcp_scsi_rport_work(struct work_struct *work)
......
...@@ -153,15 +153,14 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, ...@@ -153,15 +153,14 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
goto out; goto out;
} }
write_lock_irq(&zfcp_data.config_lock);
port = zfcp_get_port_by_wwpn(adapter, wwpn); port = zfcp_get_port_by_wwpn(adapter, wwpn);
if (port && (atomic_read(&port->refcount) == 0)) { if (port && (atomic_read(&port->refcount) == 1)) {
zfcp_port_get(port);
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
write_lock_irq(&adapter->port_list_lock);
list_move(&port->list, &port_remove_lh); list_move(&port->list, &port_remove_lh);
write_unlock_irq(&adapter->port_list_lock);
} else } else
port = NULL; port = NULL;
write_unlock_irq(&zfcp_data.config_lock);
if (!port) { if (!port) {
retval = -ENXIO; retval = -ENXIO;
...@@ -253,35 +252,28 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, ...@@ -253,35 +252,28 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
goto out; goto out;
} }
write_lock_irq(&zfcp_data.config_lock);
unit = zfcp_get_unit_by_lun(port, fcp_lun); 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) { if (!unit) {
retval = -ENXIO; retval = -EINVAL;
goto out; goto out;
} }
zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); /* wait for possible timeout during SCSI probe */
zfcp_erp_wait(unit->port->adapter); flush_work(&unit->scsi_work);
zfcp_unit_put(unit);
zfcp_unit_dequeue(unit); 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: out:
mutex_unlock(&zfcp_data.config_mutex); mutex_unlock(&zfcp_data.config_mutex);
return retval ? retval : (ssize_t) count; return retval ? retval : (ssize_t) count;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment