Commit 92d5193b authored by Swen Schillig's avatar Swen Schillig Committed by James Bottomley

[SCSI] zfcp: Dont block zfcp_wq with scan

When running the scsi_scan from the zfcp workqueue and the target
device does not respond, the zfcp workqueue can block until the
scsi_scan hits a timeout. Move the work to the scsi host workqueue,
since this one is also used for the scan from the SCSI midlayer.
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@HansenPartnership.com>
parent ada81b74
...@@ -97,9 +97,7 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) ...@@ -97,9 +97,7 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
ccw_device_set_online(adapter->ccw_device); ccw_device_set_online(adapter->ccw_device);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
wait_event(adapter->erp_done_wqh, flush_work(&unit->scsi_work);
!(atomic_read(&unit->status) &
ZFCP_STATUS_UNIT_SCSI_WORK_PENDING));
down(&zfcp_data.config_sema); down(&zfcp_data.config_sema);
zfcp_unit_put(unit); zfcp_unit_put(unit);
...@@ -279,6 +277,7 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) ...@@ -279,6 +277,7 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
atomic_set(&unit->refcount, 0); atomic_set(&unit->refcount, 0);
init_waitqueue_head(&unit->remove_wq); init_waitqueue_head(&unit->remove_wq);
INIT_WORK(&unit->scsi_work, zfcp_scsi_scan);
unit->port = port; unit->port = port;
unit->fcp_lun = fcp_lun; unit->fcp_lun = fcp_lun;
......
...@@ -255,7 +255,6 @@ enum zfcp_wka_status { ...@@ -255,7 +255,6 @@ enum zfcp_wka_status {
/* logical unit status */ /* logical unit status */
#define ZFCP_STATUS_UNIT_SHARED 0x00000004 #define ZFCP_STATUS_UNIT_SHARED 0x00000004
#define ZFCP_STATUS_UNIT_READONLY 0x00000008 #define ZFCP_STATUS_UNIT_READONLY 0x00000008
#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020
/* FSF request status (this does not have a common part) */ /* FSF request status (this does not have a common part) */
#define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002 #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002
...@@ -530,6 +529,7 @@ struct zfcp_unit { ...@@ -530,6 +529,7 @@ struct zfcp_unit {
struct zfcp_erp_action erp_action; /* pending error recovery */ struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter; atomic_t erp_counter;
struct zfcp_latencies latencies; struct zfcp_latencies latencies;
struct work_struct scsi_work;
}; };
/* FSF request */ /* FSF request */
......
...@@ -1176,48 +1176,6 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) ...@@ -1176,48 +1176,6 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
} }
} }
struct zfcp_erp_add_work {
struct zfcp_unit *unit;
struct work_struct work;
};
static void zfcp_erp_scsi_scan(struct work_struct *work)
{
struct zfcp_erp_add_work *p =
container_of(work, struct zfcp_erp_add_work, work);
struct zfcp_unit *unit = p->unit;
struct fc_rport *rport = unit->port->rport;
if (rport && rport->port_state == FC_PORTSTATE_ONLINE)
scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
scsilun_to_int((struct scsi_lun *)&unit->fcp_lun), 0);
atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
zfcp_unit_put(unit);
wake_up(&unit->port->adapter->erp_done_wqh);
kfree(p);
}
static void zfcp_erp_schedule_work(struct zfcp_unit *unit)
{
struct zfcp_erp_add_work *p;
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) {
dev_err(&unit->port->adapter->ccw_device->dev,
"Registering unit 0x%016Lx on port 0x%016Lx failed\n",
(unsigned long long)unit->fcp_lun,
(unsigned long long)unit->port->wwpn);
return;
}
zfcp_unit_get(unit);
atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
INIT_WORK(&p->work, zfcp_erp_scsi_scan);
p->unit = unit;
if (!queue_work(zfcp_data.work_queue, &p->work))
zfcp_unit_put(unit);
}
static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
{ {
struct zfcp_adapter *adapter = act->adapter; struct zfcp_adapter *adapter = act->adapter;
...@@ -1226,11 +1184,11 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) ...@@ -1226,11 +1184,11 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
switch (act->action) { switch (act->action) {
case ZFCP_ERP_ACTION_REOPEN_UNIT: case ZFCP_ERP_ACTION_REOPEN_UNIT:
flush_work(&port->rport_work);
if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
if (!(atomic_read(&unit->status) & zfcp_unit_get(unit);
ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)) if (scsi_queue_work(unit->port->adapter->scsi_host,
zfcp_erp_schedule_work(unit); &unit->scsi_work) <= 0)
zfcp_unit_put(unit);
} }
zfcp_unit_put(unit); zfcp_unit_put(unit);
break; break;
......
...@@ -158,6 +158,7 @@ extern void zfcp_scsi_rport_work(struct work_struct *); ...@@ -158,6 +158,7 @@ extern void zfcp_scsi_rport_work(struct work_struct *);
extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *);
extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *);
extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *);
extern void zfcp_scsi_scan(struct work_struct *);
/* zfcp_sysfs.c */ /* zfcp_sysfs.c */
extern struct attribute_group zfcp_sysfs_unit_attrs; extern struct attribute_group zfcp_sysfs_unit_attrs;
......
...@@ -583,6 +583,23 @@ void zfcp_scsi_rport_work(struct work_struct *work) ...@@ -583,6 +583,23 @@ void zfcp_scsi_rport_work(struct work_struct *work)
} }
void zfcp_scsi_scan(struct work_struct *work)
{
struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
scsi_work);
struct fc_rport *rport;
flush_work(&unit->port->rport_work);
rport = unit->port->rport;
if (rport && rport->port_state == FC_PORTSTATE_ONLINE)
scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
scsilun_to_int((struct scsi_lun *)
&unit->fcp_lun), 0);
zfcp_unit_put(unit);
}
struct fc_function_template zfcp_transport_functions = { struct fc_function_template zfcp_transport_functions = {
.show_starget_port_id = 1, .show_starget_port_id = 1,
.show_starget_port_name = 1, .show_starget_port_name = 1,
......
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