Skip to content

Commit a2fa0ae

Browse files
Christof SchmittJames Bottomley
Christof Schmitt
authored and
James Bottomley
committed
[SCSI] zfcp: Block FC transport rports early on errors
Use the I/O blocking mechanism in the FC transport class to allow faster failovers for multipathing: - Call fc_remote_port_delete early to set the rport to BLOCKED. - Check the rport status in queuecommand with fc_remote_portchkready to no longer accept new I/O for this port and fail the I/O with the appropriate scsi_cmnd result. - Implement the terminate_rport_io handler to abort all pending I/O requests - Return SCSI commands with DID_TRANSPORT_DISRUPTED while erp is running. - When updating the remote port status, check for late changes and update the remote ports status accordingly. Acked-by: Swen Schillig <[email protected]> Signed-off-by: Christof Schmitt <[email protected]> Signed-off-by: James Bottomley <[email protected]>
1 parent 2409549 commit a2fa0ae

File tree

7 files changed

+157
-56
lines changed

7 files changed

+157
-56
lines changed

drivers/s390/scsi/zfcp_aux.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Module interface and handling of zfcp data structures.
55
*
6-
* Copyright IBM Corporation 2002, 2008
6+
* Copyright IBM Corporation 2002, 2009
77
*/
88

99
/*
@@ -606,10 +606,12 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
606606
INIT_LIST_HEAD(&port->unit_list_head);
607607
INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup);
608608
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
609+
INIT_WORK(&port->rport_work, zfcp_scsi_rport_work);
609610

610611
port->adapter = adapter;
611612
port->d_id = d_id;
612613
port->wwpn = wwpn;
614+
port->rport_task = RPORT_NONE;
613615

614616
/* mark port unusable as long as sysfs registration is not complete */
615617
atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);

drivers/s390/scsi/zfcp_def.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Global definitions for the zfcp device driver.
55
*
6-
* Copyright IBM Corporation 2002, 2008
6+
* Copyright IBM Corporation 2002, 2009
77
*/
88

99
#ifndef ZFCP_DEF_H
@@ -512,6 +512,8 @@ struct zfcp_port {
512512
u32 supported_classes;
513513
struct work_struct gid_pn_work;
514514
struct work_struct test_link_work;
515+
struct work_struct rport_work;
516+
enum { RPORT_NONE, RPORT_ADD, RPORT_DEL } rport_task;
515517
};
516518

517519
struct zfcp_unit {

drivers/s390/scsi/zfcp_erp.c

Lines changed: 11 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Error Recovery Procedures (ERP).
55
*
6-
* Copyright IBM Corporation 2002, 2008
6+
* Copyright IBM Corporation 2002, 2009
77
*/
88

99
#define KMSG_COMPONENT "zfcp"
@@ -240,6 +240,7 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
240240
int clear_mask, char *id, void *ref)
241241
{
242242
zfcp_erp_adapter_block(adapter, clear_mask);
243+
zfcp_scsi_schedule_rports_block(adapter);
243244

244245
/* ensure propagation of failed status to new devices */
245246
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
@@ -322,6 +323,7 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
322323
int clear, char *id, void *ref)
323324
{
324325
zfcp_erp_port_block(port, clear);
326+
zfcp_scsi_schedule_rport_block(port);
325327

326328
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
327329
return;
@@ -353,6 +355,7 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
353355
void *ref)
354356
{
355357
zfcp_erp_port_block(port, clear);
358+
zfcp_scsi_schedule_rport_block(port);
356359

357360
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
358361
/* ensure propagation of failed status to new devices */
@@ -1211,37 +1214,6 @@ static void zfcp_erp_schedule_work(struct zfcp_unit *unit)
12111214
queue_work(zfcp_data.work_queue, &p->work);
12121215
}
12131216

1214-
static void zfcp_erp_rport_register(struct zfcp_port *port)
1215-
{
1216-
struct fc_rport_identifiers ids;
1217-
ids.node_name = port->wwnn;
1218-
ids.port_name = port->wwpn;
1219-
ids.port_id = port->d_id;
1220-
ids.roles = FC_RPORT_ROLE_FCP_TARGET;
1221-
port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
1222-
if (!port->rport) {
1223-
dev_err(&port->adapter->ccw_device->dev,
1224-
"Registering port 0x%016Lx failed\n",
1225-
(unsigned long long)port->wwpn);
1226-
return;
1227-
}
1228-
1229-
scsi_target_unblock(&port->rport->dev);
1230-
port->rport->maxframe_size = port->maxframe_size;
1231-
port->rport->supported_classes = port->supported_classes;
1232-
}
1233-
1234-
static void zfcp_erp_rports_del(struct zfcp_adapter *adapter)
1235-
{
1236-
struct zfcp_port *port;
1237-
list_for_each_entry(port, &adapter->port_list_head, list) {
1238-
if (!port->rport)
1239-
continue;
1240-
fc_remote_port_delete(port->rport);
1241-
port->rport = NULL;
1242-
}
1243-
}
1244-
12451217
static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
12461218
{
12471219
struct zfcp_adapter *adapter = act->adapter;
@@ -1250,8 +1222,8 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
12501222

12511223
switch (act->action) {
12521224
case ZFCP_ERP_ACTION_REOPEN_UNIT:
1253-
if ((result == ZFCP_ERP_SUCCEEDED) &&
1254-
!unit->device && port->rport) {
1225+
flush_work(&port->rport_work);
1226+
if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
12551227
if (!(atomic_read(&unit->status) &
12561228
ZFCP_STATUS_UNIT_SCSI_WORK_PENDING))
12571229
zfcp_erp_schedule_work(unit);
@@ -1261,23 +1233,17 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
12611233

12621234
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
12631235
case ZFCP_ERP_ACTION_REOPEN_PORT:
1264-
if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport)
1265-
zfcp_erp_rport_register(port);
1266-
if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) {
1267-
fc_remote_port_delete(port->rport);
1268-
port->rport = NULL;
1269-
}
1236+
if (result == ZFCP_ERP_SUCCEEDED)
1237+
zfcp_scsi_schedule_rport_register(port);
12701238
zfcp_port_put(port);
12711239
break;
12721240

12731241
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1274-
if (result != ZFCP_ERP_SUCCEEDED) {
1275-
unregister_service_level(&adapter->service_level);
1276-
zfcp_erp_rports_del(adapter);
1277-
} else {
1242+
if (result == ZFCP_ERP_SUCCEEDED) {
12781243
register_service_level(&adapter->service_level);
12791244
schedule_work(&adapter->scan_work);
1280-
}
1245+
} else
1246+
unregister_service_level(&adapter->service_level);
12811247
zfcp_adapter_put(adapter);
12821248
break;
12831249
}

drivers/s390/scsi/zfcp_ext.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* External function declarations.
55
*
6-
* Copyright IBM Corporation 2002, 2008
6+
* Copyright IBM Corporation 2002, 2009
77
*/
88

99
#ifndef ZFCP_EXT_H
@@ -154,6 +154,10 @@ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
154154
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
155155
extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
156156
extern struct fc_function_template zfcp_transport_functions;
157+
extern void zfcp_scsi_rport_work(struct work_struct *);
158+
extern void zfcp_scsi_schedule_rport_register(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 *);
157161

158162
/* zfcp_sysfs.c */
159163
extern struct attribute_group zfcp_sysfs_unit_attrs;

drivers/s390/scsi/zfcp_fc.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Fibre Channel related functions for the zfcp device driver.
55
*
6-
* Copyright IBM Corporation 2008
6+
* Copyright IBM Corporation 2008, 2009
77
*/
88

99
#define KMSG_COMPONENT "zfcp"
@@ -376,10 +376,14 @@ static void zfcp_fc_adisc_handler(unsigned long data)
376376
port->wwnn = ls_adisc->wwnn;
377377

378378
if ((port->wwpn != ls_adisc->wwpn) ||
379-
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN))
379+
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) {
380380
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
381381
"fcadh_2", NULL);
382+
goto out;
383+
}
382384

385+
/* port is good, unblock rport without going through erp */
386+
zfcp_scsi_schedule_rport_register(port);
383387
out:
384388
zfcp_port_put(port);
385389
kfree(adisc);
@@ -423,14 +427,23 @@ void zfcp_fc_link_test_work(struct work_struct *work)
423427
container_of(work, struct zfcp_port, test_link_work);
424428
int retval;
425429

430+
if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_UNBLOCKED)) {
431+
zfcp_port_put(port);
432+
return; /* port erp is running and will update rport status */
433+
}
434+
435+
zfcp_port_get(port);
436+
port->rport_task = RPORT_DEL;
437+
zfcp_scsi_rport_work(&port->rport_work);
438+
426439
retval = zfcp_fc_adisc(port);
427440
if (retval == 0)
428441
return;
429442

430443
/* send of ADISC was not possible */
444+
zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
445+
431446
zfcp_port_put(port);
432-
if (retval != -EBUSY)
433-
zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
434447
}
435448

436449
/**

drivers/s390/scsi/zfcp_fsf.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Implementation of FSF commands.
55
*
6-
* Copyright IBM Corporation 2002, 2008
6+
* Copyright IBM Corporation 2002, 2009
77
*/
88

99
#define KMSG_COMPONENT "zfcp"
@@ -177,6 +177,7 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
177177
return;
178178

179179
atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
180+
zfcp_scsi_schedule_rports_block(adapter);
180181

181182
if (!link_down)
182183
goto out;

drivers/s390/scsi/zfcp_scsi.c

Lines changed: 116 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Interface to Linux SCSI midlayer.
55
*
6-
* Copyright IBM Corporation 2002, 2008
6+
* Copyright IBM Corporation 2002, 2009
77
*/
88

99
#define KMSG_COMPONENT "zfcp"
@@ -57,8 +57,8 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
5757
{
5858
struct zfcp_unit *unit;
5959
struct zfcp_adapter *adapter;
60-
int status;
61-
int ret;
60+
int status, scsi_result, ret;
61+
struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device));
6262

6363
/* reset the status for this request */
6464
scpnt->result = 0;
@@ -80,6 +80,14 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
8080
return 0;
8181
}
8282

83+
scsi_result = fc_remote_port_chkready(rport);
84+
if (unlikely(scsi_result)) {
85+
scpnt->result = scsi_result;
86+
zfcp_scsi_dbf_event_result("fail", 4, adapter, scpnt, NULL);
87+
scpnt->scsi_done(scpnt);
88+
return 0;
89+
}
90+
8391
status = atomic_read(&unit->status);
8492
if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) ||
8593
!(status & ZFCP_STATUS_COMMON_RUNNING))) {
@@ -473,6 +481,109 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
473481
rport->dev_loss_tmo = timeout;
474482
}
475483

484+
/**
485+
* zfcp_scsi_dev_loss_tmo_callbk - Free any reference to rport
486+
* @rport: The rport that is about to be deleted.
487+
*/
488+
static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport)
489+
{
490+
struct zfcp_port *port = rport->dd_data;
491+
492+
write_lock_irq(&zfcp_data.config_lock);
493+
port->rport = NULL;
494+
write_unlock_irq(&zfcp_data.config_lock);
495+
}
496+
497+
/**
498+
* zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport
499+
* @rport: The FC rport where to teminate I/O
500+
*
501+
* Abort all pending SCSI commands for a port by closing the
502+
* port. Using a reopen for avoids a conflict with a shutdown
503+
* overwriting a reopen.
504+
*/
505+
static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
506+
{
507+
struct zfcp_port *port = rport->dd_data;
508+
509+
zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
510+
}
511+
512+
static void zfcp_scsi_rport_register(struct zfcp_port *port)
513+
{
514+
struct fc_rport_identifiers ids;
515+
struct fc_rport *rport;
516+
517+
ids.node_name = port->wwnn;
518+
ids.port_name = port->wwpn;
519+
ids.port_id = port->d_id;
520+
ids.roles = FC_RPORT_ROLE_FCP_TARGET;
521+
522+
rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
523+
if (!rport) {
524+
dev_err(&port->adapter->ccw_device->dev,
525+
"Registering port 0x%016Lx failed\n",
526+
(unsigned long long)port->wwpn);
527+
return;
528+
}
529+
530+
rport->dd_data = port;
531+
rport->maxframe_size = port->maxframe_size;
532+
rport->supported_classes = port->supported_classes;
533+
port->rport = rport;
534+
}
535+
536+
static void zfcp_scsi_rport_block(struct zfcp_port *port)
537+
{
538+
if (port->rport)
539+
fc_remote_port_delete(port->rport);
540+
}
541+
542+
void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
543+
{
544+
zfcp_port_get(port);
545+
port->rport_task = RPORT_ADD;
546+
547+
if (!queue_work(zfcp_data.work_queue, &port->rport_work))
548+
zfcp_port_put(port);
549+
}
550+
551+
void zfcp_scsi_schedule_rport_block(struct zfcp_port *port)
552+
{
553+
zfcp_port_get(port);
554+
port->rport_task = RPORT_DEL;
555+
556+
if (!queue_work(zfcp_data.work_queue, &port->rport_work))
557+
zfcp_port_put(port);
558+
}
559+
560+
void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter)
561+
{
562+
struct zfcp_port *port;
563+
564+
list_for_each_entry(port, &adapter->port_list_head, list)
565+
zfcp_scsi_schedule_rport_block(port);
566+
}
567+
568+
void zfcp_scsi_rport_work(struct work_struct *work)
569+
{
570+
struct zfcp_port *port = container_of(work, struct zfcp_port,
571+
rport_work);
572+
573+
while (port->rport_task) {
574+
if (port->rport_task == RPORT_ADD) {
575+
port->rport_task = RPORT_NONE;
576+
zfcp_scsi_rport_register(port);
577+
} else {
578+
port->rport_task = RPORT_NONE;
579+
zfcp_scsi_rport_block(port);
580+
}
581+
}
582+
583+
zfcp_port_put(port);
584+
}
585+
586+
476587
struct fc_function_template zfcp_transport_functions = {
477588
.show_starget_port_id = 1,
478589
.show_starget_port_name = 1,
@@ -491,6 +602,8 @@ struct fc_function_template zfcp_transport_functions = {
491602
.reset_fc_host_stats = zfcp_reset_fc_host_stats,
492603
.set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo,
493604
.get_host_port_state = zfcp_get_host_port_state,
605+
.dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk,
606+
.terminate_rport_io = zfcp_scsi_terminate_rport_io,
494607
.show_host_port_state = 1,
495608
/* no functions registered for following dynamic attributes but
496609
directly set by LLDD */

0 commit comments

Comments
 (0)