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

[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
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -97,9 +97,7 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
	ccw_device_set_online(adapter->ccw_device);

	zfcp_erp_wait(adapter);
	wait_event(adapter->erp_done_wqh,
		   !(atomic_read(&unit->status) &
				ZFCP_STATUS_UNIT_SCSI_WORK_PENDING));
	flush_work(&unit->scsi_work);

	down(&zfcp_data.config_sema);
	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);
	init_waitqueue_head(&unit->remove_wq);
	INIT_WORK(&unit->scsi_work, zfcp_scsi_scan);

	unit->port = port;
	unit->fcp_lun = fcp_lun;
+1 −1
Original line number Diff line number Diff line
@@ -255,7 +255,6 @@ enum zfcp_wka_status {
/* logical unit status */
#define ZFCP_STATUS_UNIT_SHARED			0x00000004
#define ZFCP_STATUS_UNIT_READONLY		0x00000008
#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING	0x00000020

/* FSF request status (this does not have a common part) */
#define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT	0x00000002
@@ -530,6 +529,7 @@ struct zfcp_unit {
	struct zfcp_erp_action erp_action;     /* pending error recovery */
        atomic_t               erp_counter;
	struct zfcp_latencies	latencies;
	struct work_struct	scsi_work;
};

/* FSF request */
+4 −46
Original line number Diff line number Diff line
@@ -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)
{
	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) {
	case ZFCP_ERP_ACTION_REOPEN_UNIT:
		flush_work(&port->rport_work);
		if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
			if (!(atomic_read(&unit->status) &
			      ZFCP_STATUS_UNIT_SCSI_WORK_PENDING))
				zfcp_erp_schedule_work(unit);
			zfcp_unit_get(unit);
			if (scsi_queue_work(unit->port->adapter->scsi_host,
					    &unit->scsi_work) <= 0)
				zfcp_unit_put(unit);
		}
		zfcp_unit_put(unit);
		break;
+1 −0
Original line number Diff line number Diff line
@@ -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_block(struct zfcp_port *);
extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *);
extern void zfcp_scsi_scan(struct work_struct *);

/* zfcp_sysfs.c */
extern struct attribute_group zfcp_sysfs_unit_attrs;
+17 −0
Original line number Diff line number Diff line
@@ -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 = {
	.show_starget_port_id = 1,
	.show_starget_port_name = 1,