diff options
author | Swen Schillig <swen@vnet.ibm.com> | 2009-04-17 09:08:04 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-04-27 11:07:26 -0400 |
commit | 92d5193b467c68e8432d6878980621c787e735af (patch) | |
tree | f38286d32216e23adfd4f8a8dc0e8ef152cd4de4 /drivers/s390/scsi | |
parent | ada81b748b768eb5b75567fd1db5e87ba5c98bf0 (diff) |
[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>
Diffstat (limited to 'drivers/s390/scsi')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 5 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 50 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 17 |
5 files changed, 25 insertions, 50 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 616c60ffcf2c..5a01ef9aeb66 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -97,9 +97,7 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) | |||
97 | ccw_device_set_online(adapter->ccw_device); | 97 | ccw_device_set_online(adapter->ccw_device); |
98 | 98 | ||
99 | zfcp_erp_wait(adapter); | 99 | zfcp_erp_wait(adapter); |
100 | wait_event(adapter->erp_done_wqh, | 100 | flush_work(&unit->scsi_work); |
101 | !(atomic_read(&unit->status) & | ||
102 | ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)); | ||
103 | 101 | ||
104 | down(&zfcp_data.config_sema); | 102 | down(&zfcp_data.config_sema); |
105 | zfcp_unit_put(unit); | 103 | zfcp_unit_put(unit); |
@@ -279,6 +277,7 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) | |||
279 | 277 | ||
280 | atomic_set(&unit->refcount, 0); | 278 | atomic_set(&unit->refcount, 0); |
281 | init_waitqueue_head(&unit->remove_wq); | 279 | init_waitqueue_head(&unit->remove_wq); |
280 | INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); | ||
282 | 281 | ||
283 | unit->port = port; | 282 | unit->port = port; |
284 | unit->fcp_lun = fcp_lun; | 283 | unit->fcp_lun = fcp_lun; |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index a0318630f047..4c362a9069f0 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -255,7 +255,6 @@ enum zfcp_wka_status { | |||
255 | /* logical unit status */ | 255 | /* logical unit status */ |
256 | #define ZFCP_STATUS_UNIT_SHARED 0x00000004 | 256 | #define ZFCP_STATUS_UNIT_SHARED 0x00000004 |
257 | #define ZFCP_STATUS_UNIT_READONLY 0x00000008 | 257 | #define ZFCP_STATUS_UNIT_READONLY 0x00000008 |
258 | #define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020 | ||
259 | 258 | ||
260 | /* FSF request status (this does not have a common part) */ | 259 | /* FSF request status (this does not have a common part) */ |
261 | #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002 | 260 | #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002 |
@@ -530,6 +529,7 @@ struct zfcp_unit { | |||
530 | struct zfcp_erp_action erp_action; /* pending error recovery */ | 529 | struct zfcp_erp_action erp_action; /* pending error recovery */ |
531 | atomic_t erp_counter; | 530 | atomic_t erp_counter; |
532 | struct zfcp_latencies latencies; | 531 | struct zfcp_latencies latencies; |
532 | struct work_struct scsi_work; | ||
533 | }; | 533 | }; |
534 | 534 | ||
535 | /* FSF request */ | 535 | /* FSF request */ |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 631bdb1dfd6c..4e160523c31b 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -1176,48 +1176,6 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) | |||
1176 | } | 1176 | } |
1177 | } | 1177 | } |
1178 | 1178 | ||
1179 | struct zfcp_erp_add_work { | ||
1180 | struct zfcp_unit *unit; | ||
1181 | struct work_struct work; | ||
1182 | }; | ||
1183 | |||
1184 | static void zfcp_erp_scsi_scan(struct work_struct *work) | ||
1185 | { | ||
1186 | struct zfcp_erp_add_work *p = | ||
1187 | container_of(work, struct zfcp_erp_add_work, work); | ||
1188 | struct zfcp_unit *unit = p->unit; | ||
1189 | struct fc_rport *rport = unit->port->rport; | ||
1190 | |||
1191 | if (rport && rport->port_state == FC_PORTSTATE_ONLINE) | ||
1192 | scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, | ||
1193 | scsilun_to_int((struct scsi_lun *)&unit->fcp_lun), 0); | ||
1194 | atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1195 | zfcp_unit_put(unit); | ||
1196 | wake_up(&unit->port->adapter->erp_done_wqh); | ||
1197 | kfree(p); | ||
1198 | } | ||
1199 | |||
1200 | static void zfcp_erp_schedule_work(struct zfcp_unit *unit) | ||
1201 | { | ||
1202 | struct zfcp_erp_add_work *p; | ||
1203 | |||
1204 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
1205 | if (!p) { | ||
1206 | dev_err(&unit->port->adapter->ccw_device->dev, | ||
1207 | "Registering unit 0x%016Lx on port 0x%016Lx failed\n", | ||
1208 | (unsigned long long)unit->fcp_lun, | ||
1209 | (unsigned long long)unit->port->wwpn); | ||
1210 | return; | ||
1211 | } | ||
1212 | |||
1213 | zfcp_unit_get(unit); | ||
1214 | atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1215 | INIT_WORK(&p->work, zfcp_erp_scsi_scan); | ||
1216 | p->unit = unit; | ||
1217 | if (!queue_work(zfcp_data.work_queue, &p->work)) | ||
1218 | zfcp_unit_put(unit); | ||
1219 | } | ||
1220 | |||
1221 | static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | 1179 | static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) |
1222 | { | 1180 | { |
1223 | struct zfcp_adapter *adapter = act->adapter; | 1181 | struct zfcp_adapter *adapter = act->adapter; |
@@ -1226,11 +1184,11 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | |||
1226 | 1184 | ||
1227 | switch (act->action) { | 1185 | switch (act->action) { |
1228 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 1186 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
1229 | flush_work(&port->rport_work); | ||
1230 | if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { | 1187 | if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { |
1231 | if (!(atomic_read(&unit->status) & | 1188 | zfcp_unit_get(unit); |
1232 | ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)) | 1189 | if (scsi_queue_work(unit->port->adapter->scsi_host, |
1233 | zfcp_erp_schedule_work(unit); | 1190 | &unit->scsi_work) <= 0) |
1191 | zfcp_unit_put(unit); | ||
1234 | } | 1192 | } |
1235 | zfcp_unit_put(unit); | 1193 | zfcp_unit_put(unit); |
1236 | break; | 1194 | break; |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index f6399ca97bcb..df740f10d26a 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -158,6 +158,7 @@ extern void zfcp_scsi_rport_work(struct work_struct *); | |||
158 | extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); | 158 | extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); |
159 | extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); | 159 | extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); |
160 | extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); | 160 | extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); |
161 | extern void zfcp_scsi_scan(struct work_struct *); | ||
161 | 162 | ||
162 | /* zfcp_sysfs.c */ | 163 | /* zfcp_sysfs.c */ |
163 | extern struct attribute_group zfcp_sysfs_unit_attrs; | 164 | extern struct attribute_group zfcp_sysfs_unit_attrs; |
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 58201e1ae478..5b11386d70bb 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -583,6 +583,23 @@ void zfcp_scsi_rport_work(struct work_struct *work) | |||
583 | } | 583 | } |
584 | 584 | ||
585 | 585 | ||
586 | void zfcp_scsi_scan(struct work_struct *work) | ||
587 | { | ||
588 | struct zfcp_unit *unit = container_of(work, struct zfcp_unit, | ||
589 | scsi_work); | ||
590 | struct fc_rport *rport; | ||
591 | |||
592 | flush_work(&unit->port->rport_work); | ||
593 | rport = unit->port->rport; | ||
594 | |||
595 | if (rport && rport->port_state == FC_PORTSTATE_ONLINE) | ||
596 | scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, | ||
597 | scsilun_to_int((struct scsi_lun *) | ||
598 | &unit->fcp_lun), 0); | ||
599 | |||
600 | zfcp_unit_put(unit); | ||
601 | } | ||
602 | |||
586 | struct fc_function_template zfcp_transport_functions = { | 603 | struct fc_function_template zfcp_transport_functions = { |
587 | .show_starget_port_id = 1, | 604 | .show_starget_port_id = 1, |
588 | .show_starget_port_name = 1, | 605 | .show_starget_port_name = 1, |