[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: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
committed by
James Bottomley
parent
ada81b748b
commit
92d5193b46
@@ -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)
|
|||||||
|
|
||||||
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 {
|
|||||||
/* 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 {
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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 *);
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
Reference in New Issue
Block a user