[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 <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:
parent
2409549068
commit
a2fa0aede0
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Module interface and handling of zfcp data structures.
|
* Module interface and handling of zfcp data structures.
|
||||||
*
|
*
|
||||||
* Copyright IBM Corporation 2002, 2008
|
* Copyright IBM Corporation 2002, 2009
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -606,10 +606,12 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
|
|||||||
INIT_LIST_HEAD(&port->unit_list_head);
|
INIT_LIST_HEAD(&port->unit_list_head);
|
||||||
INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup);
|
INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup);
|
||||||
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
|
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
|
||||||
|
INIT_WORK(&port->rport_work, zfcp_scsi_rport_work);
|
||||||
|
|
||||||
port->adapter = adapter;
|
port->adapter = adapter;
|
||||||
port->d_id = d_id;
|
port->d_id = d_id;
|
||||||
port->wwpn = wwpn;
|
port->wwpn = wwpn;
|
||||||
|
port->rport_task = RPORT_NONE;
|
||||||
|
|
||||||
/* mark port unusable as long as sysfs registration is not complete */
|
/* mark port unusable as long as sysfs registration is not complete */
|
||||||
atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);
|
atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Global definitions for the zfcp device driver.
|
* Global definitions for the zfcp device driver.
|
||||||
*
|
*
|
||||||
* Copyright IBM Corporation 2002, 2008
|
* Copyright IBM Corporation 2002, 2009
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ZFCP_DEF_H
|
#ifndef ZFCP_DEF_H
|
||||||
@ -512,6 +512,8 @@ struct zfcp_port {
|
|||||||
u32 supported_classes;
|
u32 supported_classes;
|
||||||
struct work_struct gid_pn_work;
|
struct work_struct gid_pn_work;
|
||||||
struct work_struct test_link_work;
|
struct work_struct test_link_work;
|
||||||
|
struct work_struct rport_work;
|
||||||
|
enum { RPORT_NONE, RPORT_ADD, RPORT_DEL } rport_task;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct zfcp_unit {
|
struct zfcp_unit {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Error Recovery Procedures (ERP).
|
* Error Recovery Procedures (ERP).
|
||||||
*
|
*
|
||||||
* Copyright IBM Corporation 2002, 2008
|
* Copyright IBM Corporation 2002, 2009
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define KMSG_COMPONENT "zfcp"
|
#define KMSG_COMPONENT "zfcp"
|
||||||
@ -240,6 +240,7 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
|
|||||||
int clear_mask, char *id, void *ref)
|
int clear_mask, char *id, void *ref)
|
||||||
{
|
{
|
||||||
zfcp_erp_adapter_block(adapter, clear_mask);
|
zfcp_erp_adapter_block(adapter, clear_mask);
|
||||||
|
zfcp_scsi_schedule_rports_block(adapter);
|
||||||
|
|
||||||
/* ensure propagation of failed status to new devices */
|
/* ensure propagation of failed status to new devices */
|
||||||
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
|
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,
|
|||||||
int clear, char *id, void *ref)
|
int clear, char *id, void *ref)
|
||||||
{
|
{
|
||||||
zfcp_erp_port_block(port, clear);
|
zfcp_erp_port_block(port, clear);
|
||||||
|
zfcp_scsi_schedule_rport_block(port);
|
||||||
|
|
||||||
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
|
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
|
||||||
return;
|
return;
|
||||||
@ -353,6 +355,7 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
|
|||||||
void *ref)
|
void *ref)
|
||||||
{
|
{
|
||||||
zfcp_erp_port_block(port, clear);
|
zfcp_erp_port_block(port, clear);
|
||||||
|
zfcp_scsi_schedule_rport_block(port);
|
||||||
|
|
||||||
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
|
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
|
||||||
/* ensure propagation of failed status to new devices */
|
/* ensure propagation of failed status to new devices */
|
||||||
@ -1211,37 +1214,6 @@ static void zfcp_erp_schedule_work(struct zfcp_unit *unit)
|
|||||||
queue_work(zfcp_data.work_queue, &p->work);
|
queue_work(zfcp_data.work_queue, &p->work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zfcp_erp_rport_register(struct zfcp_port *port)
|
|
||||||
{
|
|
||||||
struct fc_rport_identifiers ids;
|
|
||||||
ids.node_name = port->wwnn;
|
|
||||||
ids.port_name = port->wwpn;
|
|
||||||
ids.port_id = port->d_id;
|
|
||||||
ids.roles = FC_RPORT_ROLE_FCP_TARGET;
|
|
||||||
port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
|
|
||||||
if (!port->rport) {
|
|
||||||
dev_err(&port->adapter->ccw_device->dev,
|
|
||||||
"Registering port 0x%016Lx failed\n",
|
|
||||||
(unsigned long long)port->wwpn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scsi_target_unblock(&port->rport->dev);
|
|
||||||
port->rport->maxframe_size = port->maxframe_size;
|
|
||||||
port->rport->supported_classes = port->supported_classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void zfcp_erp_rports_del(struct zfcp_adapter *adapter)
|
|
||||||
{
|
|
||||||
struct zfcp_port *port;
|
|
||||||
list_for_each_entry(port, &adapter->port_list_head, list) {
|
|
||||||
if (!port->rport)
|
|
||||||
continue;
|
|
||||||
fc_remote_port_delete(port->rport);
|
|
||||||
port->rport = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
@ -1250,8 +1222,8 @@ 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:
|
||||||
if ((result == ZFCP_ERP_SUCCEEDED) &&
|
flush_work(&port->rport_work);
|
||||||
!unit->device && port->rport) {
|
if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
|
||||||
if (!(atomic_read(&unit->status) &
|
if (!(atomic_read(&unit->status) &
|
||||||
ZFCP_STATUS_UNIT_SCSI_WORK_PENDING))
|
ZFCP_STATUS_UNIT_SCSI_WORK_PENDING))
|
||||||
zfcp_erp_schedule_work(unit);
|
zfcp_erp_schedule_work(unit);
|
||||||
@ -1261,23 +1233,17 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
|||||||
|
|
||||||
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
|
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
|
||||||
case ZFCP_ERP_ACTION_REOPEN_PORT:
|
case ZFCP_ERP_ACTION_REOPEN_PORT:
|
||||||
if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport)
|
if (result == ZFCP_ERP_SUCCEEDED)
|
||||||
zfcp_erp_rport_register(port);
|
zfcp_scsi_schedule_rport_register(port);
|
||||||
if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) {
|
|
||||||
fc_remote_port_delete(port->rport);
|
|
||||||
port->rport = NULL;
|
|
||||||
}
|
|
||||||
zfcp_port_put(port);
|
zfcp_port_put(port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
|
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
|
||||||
if (result != ZFCP_ERP_SUCCEEDED) {
|
if (result == ZFCP_ERP_SUCCEEDED) {
|
||||||
unregister_service_level(&adapter->service_level);
|
|
||||||
zfcp_erp_rports_del(adapter);
|
|
||||||
} else {
|
|
||||||
register_service_level(&adapter->service_level);
|
register_service_level(&adapter->service_level);
|
||||||
schedule_work(&adapter->scan_work);
|
schedule_work(&adapter->scan_work);
|
||||||
}
|
} else
|
||||||
|
unregister_service_level(&adapter->service_level);
|
||||||
zfcp_adapter_put(adapter);
|
zfcp_adapter_put(adapter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* External function declarations.
|
* External function declarations.
|
||||||
*
|
*
|
||||||
* Copyright IBM Corporation 2002, 2008
|
* Copyright IBM Corporation 2002, 2009
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ZFCP_EXT_H
|
#ifndef ZFCP_EXT_H
|
||||||
@ -154,6 +154,10 @@ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
|
|||||||
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
|
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
|
||||||
extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
|
extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
|
||||||
extern struct fc_function_template zfcp_transport_functions;
|
extern struct fc_function_template zfcp_transport_functions;
|
||||||
|
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 *);
|
||||||
|
|
||||||
/* zfcp_sysfs.c */
|
/* zfcp_sysfs.c */
|
||||||
extern struct attribute_group zfcp_sysfs_unit_attrs;
|
extern struct attribute_group zfcp_sysfs_unit_attrs;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Fibre Channel related functions for the zfcp device driver.
|
* Fibre Channel related functions for the zfcp device driver.
|
||||||
*
|
*
|
||||||
* Copyright IBM Corporation 2008
|
* Copyright IBM Corporation 2008, 2009
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define KMSG_COMPONENT "zfcp"
|
#define KMSG_COMPONENT "zfcp"
|
||||||
@ -376,10 +376,14 @@ static void zfcp_fc_adisc_handler(unsigned long data)
|
|||||||
port->wwnn = ls_adisc->wwnn;
|
port->wwnn = ls_adisc->wwnn;
|
||||||
|
|
||||||
if ((port->wwpn != ls_adisc->wwpn) ||
|
if ((port->wwpn != ls_adisc->wwpn) ||
|
||||||
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN))
|
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) {
|
||||||
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
|
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||||
"fcadh_2", NULL);
|
"fcadh_2", NULL);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* port is good, unblock rport without going through erp */
|
||||||
|
zfcp_scsi_schedule_rport_register(port);
|
||||||
out:
|
out:
|
||||||
zfcp_port_put(port);
|
zfcp_port_put(port);
|
||||||
kfree(adisc);
|
kfree(adisc);
|
||||||
@ -423,14 +427,23 @@ void zfcp_fc_link_test_work(struct work_struct *work)
|
|||||||
container_of(work, struct zfcp_port, test_link_work);
|
container_of(work, struct zfcp_port, test_link_work);
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_UNBLOCKED)) {
|
||||||
|
zfcp_port_put(port);
|
||||||
|
return; /* port erp is running and will update rport status */
|
||||||
|
}
|
||||||
|
|
||||||
|
zfcp_port_get(port);
|
||||||
|
port->rport_task = RPORT_DEL;
|
||||||
|
zfcp_scsi_rport_work(&port->rport_work);
|
||||||
|
|
||||||
retval = zfcp_fc_adisc(port);
|
retval = zfcp_fc_adisc(port);
|
||||||
if (retval == 0)
|
if (retval == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* send of ADISC was not possible */
|
/* send of ADISC was not possible */
|
||||||
|
zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
|
||||||
|
|
||||||
zfcp_port_put(port);
|
zfcp_port_put(port);
|
||||||
if (retval != -EBUSY)
|
|
||||||
zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Implementation of FSF commands.
|
* Implementation of FSF commands.
|
||||||
*
|
*
|
||||||
* Copyright IBM Corporation 2002, 2008
|
* Copyright IBM Corporation 2002, 2009
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define KMSG_COMPONENT "zfcp"
|
#define KMSG_COMPONENT "zfcp"
|
||||||
@ -177,6 +177,7 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
|
atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
|
||||||
|
zfcp_scsi_schedule_rports_block(adapter);
|
||||||
|
|
||||||
if (!link_down)
|
if (!link_down)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Interface to Linux SCSI midlayer.
|
* Interface to Linux SCSI midlayer.
|
||||||
*
|
*
|
||||||
* Copyright IBM Corporation 2002, 2008
|
* Copyright IBM Corporation 2002, 2009
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define KMSG_COMPONENT "zfcp"
|
#define KMSG_COMPONENT "zfcp"
|
||||||
@ -57,8 +57,8 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
|
|||||||
{
|
{
|
||||||
struct zfcp_unit *unit;
|
struct zfcp_unit *unit;
|
||||||
struct zfcp_adapter *adapter;
|
struct zfcp_adapter *adapter;
|
||||||
int status;
|
int status, scsi_result, ret;
|
||||||
int ret;
|
struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device));
|
||||||
|
|
||||||
/* reset the status for this request */
|
/* reset the status for this request */
|
||||||
scpnt->result = 0;
|
scpnt->result = 0;
|
||||||
@ -80,6 +80,14 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scsi_result = fc_remote_port_chkready(rport);
|
||||||
|
if (unlikely(scsi_result)) {
|
||||||
|
scpnt->result = scsi_result;
|
||||||
|
zfcp_scsi_dbf_event_result("fail", 4, adapter, scpnt, NULL);
|
||||||
|
scpnt->scsi_done(scpnt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
status = atomic_read(&unit->status);
|
status = atomic_read(&unit->status);
|
||||||
if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) ||
|
if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) ||
|
||||||
!(status & ZFCP_STATUS_COMMON_RUNNING))) {
|
!(status & ZFCP_STATUS_COMMON_RUNNING))) {
|
||||||
@ -473,6 +481,109 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
|
|||||||
rport->dev_loss_tmo = timeout;
|
rport->dev_loss_tmo = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zfcp_scsi_dev_loss_tmo_callbk - Free any reference to rport
|
||||||
|
* @rport: The rport that is about to be deleted.
|
||||||
|
*/
|
||||||
|
static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport)
|
||||||
|
{
|
||||||
|
struct zfcp_port *port = rport->dd_data;
|
||||||
|
|
||||||
|
write_lock_irq(&zfcp_data.config_lock);
|
||||||
|
port->rport = NULL;
|
||||||
|
write_unlock_irq(&zfcp_data.config_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport
|
||||||
|
* @rport: The FC rport where to teminate I/O
|
||||||
|
*
|
||||||
|
* Abort all pending SCSI commands for a port by closing the
|
||||||
|
* port. Using a reopen for avoids a conflict with a shutdown
|
||||||
|
* overwriting a reopen.
|
||||||
|
*/
|
||||||
|
static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
|
||||||
|
{
|
||||||
|
struct zfcp_port *port = rport->dd_data;
|
||||||
|
|
||||||
|
zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zfcp_scsi_rport_register(struct zfcp_port *port)
|
||||||
|
{
|
||||||
|
struct fc_rport_identifiers ids;
|
||||||
|
struct fc_rport *rport;
|
||||||
|
|
||||||
|
ids.node_name = port->wwnn;
|
||||||
|
ids.port_name = port->wwpn;
|
||||||
|
ids.port_id = port->d_id;
|
||||||
|
ids.roles = FC_RPORT_ROLE_FCP_TARGET;
|
||||||
|
|
||||||
|
rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
|
||||||
|
if (!rport) {
|
||||||
|
dev_err(&port->adapter->ccw_device->dev,
|
||||||
|
"Registering port 0x%016Lx failed\n",
|
||||||
|
(unsigned long long)port->wwpn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rport->dd_data = port;
|
||||||
|
rport->maxframe_size = port->maxframe_size;
|
||||||
|
rport->supported_classes = port->supported_classes;
|
||||||
|
port->rport = rport;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zfcp_scsi_rport_block(struct zfcp_port *port)
|
||||||
|
{
|
||||||
|
if (port->rport)
|
||||||
|
fc_remote_port_delete(port->rport);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
|
||||||
|
{
|
||||||
|
zfcp_port_get(port);
|
||||||
|
port->rport_task = RPORT_ADD;
|
||||||
|
|
||||||
|
if (!queue_work(zfcp_data.work_queue, &port->rport_work))
|
||||||
|
zfcp_port_put(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zfcp_scsi_schedule_rport_block(struct zfcp_port *port)
|
||||||
|
{
|
||||||
|
zfcp_port_get(port);
|
||||||
|
port->rport_task = RPORT_DEL;
|
||||||
|
|
||||||
|
if (!queue_work(zfcp_data.work_queue, &port->rport_work))
|
||||||
|
zfcp_port_put(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter)
|
||||||
|
{
|
||||||
|
struct zfcp_port *port;
|
||||||
|
|
||||||
|
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||||
|
zfcp_scsi_schedule_rport_block(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zfcp_scsi_rport_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct zfcp_port *port = container_of(work, struct zfcp_port,
|
||||||
|
rport_work);
|
||||||
|
|
||||||
|
while (port->rport_task) {
|
||||||
|
if (port->rport_task == RPORT_ADD) {
|
||||||
|
port->rport_task = RPORT_NONE;
|
||||||
|
zfcp_scsi_rport_register(port);
|
||||||
|
} else {
|
||||||
|
port->rport_task = RPORT_NONE;
|
||||||
|
zfcp_scsi_rport_block(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zfcp_port_put(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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,
|
||||||
@ -491,6 +602,8 @@ struct fc_function_template zfcp_transport_functions = {
|
|||||||
.reset_fc_host_stats = zfcp_reset_fc_host_stats,
|
.reset_fc_host_stats = zfcp_reset_fc_host_stats,
|
||||||
.set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo,
|
.set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo,
|
||||||
.get_host_port_state = zfcp_get_host_port_state,
|
.get_host_port_state = zfcp_get_host_port_state,
|
||||||
|
.dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk,
|
||||||
|
.terminate_rport_io = zfcp_scsi_terminate_rport_io,
|
||||||
.show_host_port_state = 1,
|
.show_host_port_state = 1,
|
||||||
/* no functions registered for following dynamic attributes but
|
/* no functions registered for following dynamic attributes but
|
||||||
directly set by LLDD */
|
directly set by LLDD */
|
||||||
|
Loading…
Reference in New Issue
Block a user