linux/drivers/scsi/bfa/rport_api.c
Jing Huang c507341713 [SCSI] bfa: fix rport speed setting
When a rport goes offline, its speed setting was not reset. Subsequently, if
the rport was not deleted due to it coming back online within rport del
timeout, previously discovered speed would continue to show up. The fix is to
reset the speed when processing rport offline transition.

In rport attributes, rport's with unknown speed were indicated as TRL
enforced.  The right thing do to would be to use TRL default speed to
determine if TRL is enforced, when TRL is enabled.

Signed-off-by: Jing Huang <huangj@brocade.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
2010-07-27 12:04:10 -05:00

185 lines
4.3 KiB
C

/*
* Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
* All rights reserved
* www.brocade.com
*
* Linux driver for Brocade Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
* published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <bfa.h>
#include <bfa_svc.h>
#include "fcs_vport.h"
#include "fcs_lport.h"
#include "fcs_rport.h"
#include "fcs_trcmod.h"
BFA_TRC_FILE(FCS, RPORT_API);
/**
* rport_api.c Remote port implementation.
*/
/**
* fcs_rport_api FCS rport API.
*/
/**
* Direct API to add a target by port wwn. This interface is used, for
* example, by bios when target pwwn is known from boot lun configuration.
*/
bfa_status_t
bfa_fcs_rport_add(struct bfa_fcs_port_s *port, wwn_t *pwwn,
struct bfa_fcs_rport_s *rport,
struct bfad_rport_s *rport_drv)
{
bfa_trc(port->fcs, *pwwn);
return BFA_STATUS_OK;
}
/**
* Direct API to remove a target and its associated resources. This
* interface is used, for example, by vmware driver to remove target
* ports from the target list for a VM.
*/
bfa_status_t
bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport_in)
{
struct bfa_fcs_rport_s *rport;
bfa_trc(rport_in->fcs, rport_in->pwwn);
rport = bfa_fcs_port_get_rport_by_pwwn(rport_in->port, rport_in->pwwn);
if (rport == NULL) {
/*
* TBD Error handling
*/
bfa_trc(rport_in->fcs, rport_in->pid);
return BFA_STATUS_UNKNOWN_RWWN;
}
/*
* TBD if this remote port is online, send a logo
*/
return BFA_STATUS_OK;
}
/**
* Remote device status for display/debug.
*/
void
bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
struct bfa_rport_attr_s *rport_attr)
{
struct bfa_rport_qos_attr_s qos_attr;
struct bfa_fcs_port_s *port = rport->port;
enum bfa_pport_speed rport_speed = rport->rpf.rpsc_speed;
bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s));
rport_attr->pid = rport->pid;
rport_attr->pwwn = rport->pwwn;
rport_attr->nwwn = rport->nwwn;
rport_attr->cos_supported = rport->fc_cos;
rport_attr->df_sz = rport->maxfrsize;
rport_attr->state = bfa_fcs_rport_get_state(rport);
rport_attr->fc_cos = rport->fc_cos;
rport_attr->cisc = rport->cisc;
rport_attr->scsi_function = rport->scsi_function;
rport_attr->curr_speed = rport->rpf.rpsc_speed;
rport_attr->assigned_speed = rport->rpf.assigned_speed;
bfa_rport_get_qos_attr(rport->bfa_rport, &qos_attr);
rport_attr->qos_attr = qos_attr;
rport_attr->trl_enforced = BFA_FALSE;
if (bfa_fcport_is_ratelim(port->fcs->bfa)) {
if (rport_speed == BFA_PPORT_SPEED_UNKNOWN) {
/* Use default ratelim speed setting */
rport_speed =
bfa_fcport_get_ratelim_speed(rport->fcs->bfa);
}
if (rport_speed < bfa_fcs_port_get_rport_max_speed(port))
rport_attr->trl_enforced = BFA_TRUE;
}
/*
* TODO
* rport->symname
*/
}
/**
* Per remote device statistics.
*/
void
bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport,
struct bfa_rport_stats_s *stats)
{
*stats = rport->stats;
}
void
bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport)
{
bfa_os_memset((char *)&rport->stats, 0,
sizeof(struct bfa_rport_stats_s));
}
struct bfa_fcs_rport_s *
bfa_fcs_rport_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn)
{
struct bfa_fcs_rport_s *rport;
rport = bfa_fcs_port_get_rport_by_pwwn(port, rpwwn);
if (rport == NULL) {
/*
* TBD Error handling
*/
}
return rport;
}
struct bfa_fcs_rport_s *
bfa_fcs_rport_lookup_by_nwwn(struct bfa_fcs_port_s *port, wwn_t rnwwn)
{
struct bfa_fcs_rport_s *rport;
rport = bfa_fcs_port_get_rport_by_nwwn(port, rnwwn);
if (rport == NULL) {
/*
* TBD Error handling
*/
}
return rport;
}
/*
* This API is to set the Rport's speed. Should be used when RPSC is not
* supported by the rport.
*/
void
bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport,
enum bfa_pport_speed speed)
{
rport->rpf.assigned_speed = speed;
/* Set this speed in f/w only if the RPSC speed is not available */
if (rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN)
bfa_rport_speed(rport->bfa_rport, speed);
}