cregit-Linux how code gets into the kernel

Release 4.11 drivers/scsi/scsi_transport_fc.c

Directory: drivers/scsi
/*
 *  FiberChannel transport specific attributes exported to sysfs.
 *
 *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  ========
 *
 *  Copyright (C) 2004-2007   James Smart, Emulex Corporation
 *    Rewrite for host, target, device, and remote port attributes,
 *    statistics, and service functions...
 *    Add vports, etc
 *
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/bsg-lib.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_cmnd.h>
#include <net/netlink.h>
#include <scsi/scsi_netlink_fc.h>
#include <scsi/scsi_bsg_fc.h>
#include "scsi_priv.h"

static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
static void fc_vport_sched_delete(struct work_struct *work);
static int fc_vport_setup(struct Scsi_Host *shost, int channel,
	struct device *pdev, struct fc_vport_identifiers  *ids,
	struct fc_vport **vport);
static int fc_bsg_hostadd(struct Scsi_Host *, struct fc_host_attrs *);
static int fc_bsg_rportadd(struct Scsi_Host *, struct fc_rport *);
static void fc_bsg_remove(struct request_queue *);
static void fc_bsg_goose_queue(struct fc_rport *);

/*
 * Module Parameters
 */

/*
 * dev_loss_tmo: the default number of seconds that the FC transport
 *   should insulate the loss of a remote port.
 *   The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT.
 */

static unsigned int fc_dev_loss_tmo = 60;		
/* seconds */

module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(dev_loss_tmo,
		 "Maximum number of seconds that the FC transport should"
		 " insulate the loss of a remote port. Once this value is"
		 " exceeded, the scsi target is removed. Value should be"
		 " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if"
		 " fast_io_fail_tmo is not set.");

/*
 * Redefine so that we can have same named attributes in the
 * sdev/starget/host objects.
 */

#define FC_DEVICE_ATTR(_prefix,_name,_mode,_show,_store)		\
struct device_attribute device_attr_##_prefix##_##_name =       \
        __ATTR(_name,_mode,_show,_store)


#define fc_enum_name_search(title, table_type, table)			\
static const char *get_fc_##title##_name(enum table_type table_key)     \
{                                                                       \
        int i;                                                          \
        char *name = NULL;                                              \
                                                                        \
        for (i = 0; i < ARRAY_SIZE(table); i++) {                       \
                if (table[i].value == table_key) {                      \
                        name = table[i].name;                           \
                        break;                                          \
                }                                                       \
        }                                                               \
        return name;                                                    \
}


#define fc_enum_name_match(title, table_type, table)			\
static int get_fc_##title##_match(const char *table_key,                \
                enum table_type *value)                                 \
{                                                                       \
        int i;                                                          \
                                                                        \
        for (i = 0; i < ARRAY_SIZE(table); i++) {                       \
                if (strncmp(table_key, table[i].name,                   \
                                table[i].matchlen) == 0) {              \
                        *value = table[i].value;                        \
                        return 0; /* success */				\
                }                                                       \
        }                                                               \
        return 1; /* failure */						\
}


/* Convert fc_port_type values to ascii string name */
static struct {
	
enum fc_port_type	value;
	
char			*name;
} 
fc_port_type_names[] = {
	{ FC_PORTTYPE_UNKNOWN,		"Unknown" },
	{ FC_PORTTYPE_OTHER,		"Other" },
	{ FC_PORTTYPE_NOTPRESENT,	"Not Present" },
	{ FC_PORTTYPE_NPORT,	"NPort (fabric via point-to-point)" },
	{ FC_PORTTYPE_NLPORT,	"NLPort (fabric via loop)" },
	{ FC_PORTTYPE_LPORT,	"LPort (private loop)" },
	{ FC_PORTTYPE_PTP,	"Point-To-Point (direct nport connection)" },
	{ FC_PORTTYPE_NPIV,		"NPIV VPORT" },
};
fc_enum_name_search(port_type, fc_port_type, fc_port_type_names)

#define FC_PORTTYPE_MAX_NAMELEN		50

/* Reuse fc_port_type enum function for vport_type */

#define get_fc_vport_type_name get_fc_port_type_name


/* Convert fc_host_event_code values to ascii string name */
static const struct {
	
enum fc_host_event_code		value;
	
char				*name;
} 
fc_host_event_code_names[] = {
	{ FCH_EVT_LIP,			"lip" },
	{ FCH_EVT_LINKUP,		"link_up" },
	{ FCH_EVT_LINKDOWN,		"link_down" },
	{ FCH_EVT_LIPRESET,		"lip_reset" },
	{ FCH_EVT_RSCN,			"rscn" },
	{ FCH_EVT_ADAPTER_CHANGE,	"adapter_chg" },
	{ FCH_EVT_PORT_UNKNOWN,		"port_unknown" },
	{ FCH_EVT_PORT_ONLINE,		"port_online" },
	{ FCH_EVT_PORT_OFFLINE,		"port_offline" },
	{ FCH_EVT_PORT_FABRIC,		"port_fabric" },
	{ FCH_EVT_LINK_UNKNOWN,		"link_unknown" },
	{ FCH_EVT_VENDOR_UNIQUE,	"vendor_unique" },
};
fc_enum_name_search(host_event_code, fc_host_event_code,
		fc_host_event_code_names)

#define FC_HOST_EVENT_CODE_MAX_NAMELEN	30


/* Convert fc_port_state values to ascii string name */
static struct {
	
enum fc_port_state	value;
	
char			*name;
} 
fc_port_state_names[] = {
	{ FC_PORTSTATE_UNKNOWN,		"Unknown" },
	{ FC_PORTSTATE_NOTPRESENT,	"Not Present" },
	{ FC_PORTSTATE_ONLINE,		"Online" },
	{ FC_PORTSTATE_OFFLINE,		"Offline" },
	{ FC_PORTSTATE_BLOCKED,		"Blocked" },
	{ FC_PORTSTATE_BYPASSED,	"Bypassed" },
	{ FC_PORTSTATE_DIAGNOSTICS,	"Diagnostics" },
	{ FC_PORTSTATE_LINKDOWN,	"Linkdown" },
	{ FC_PORTSTATE_ERROR,		"Error" },
	{ FC_PORTSTATE_LOOPBACK,	"Loopback" },
	{ FC_PORTSTATE_DELETED,		"Deleted" },
};
fc_enum_name_search(port_state, fc_port_state, fc_port_state_names)

#define FC_PORTSTATE_MAX_NAMELEN	20


/* Convert fc_vport_state values to ascii string name */
static struct {
	
enum fc_vport_state	value;
	
char			*name;
} 
fc_vport_state_names[] = {
	{ FC_VPORT_UNKNOWN,		"Unknown" },
	{ FC_VPORT_ACTIVE,		"Active" },
	{ FC_VPORT_DISABLED,		"Disabled" },
	{ FC_VPORT_LINKDOWN,		"Linkdown" },
	{ FC_VPORT_INITIALIZING,	"Initializing" },
	{ FC_VPORT_NO_FABRIC_SUPP,	"No Fabric Support" },
	{ FC_VPORT_NO_FABRIC_RSCS,	"No Fabric Resources" },
	{ FC_VPORT_FABRIC_LOGOUT,	"Fabric Logout" },
	{ FC_VPORT_FABRIC_REJ_WWN,	"Fabric Rejected WWN" },
	{ FC_VPORT_FAILED,		"VPort Failed" },
};
fc_enum_name_search(vport_state, fc_vport_state, fc_vport_state_names)

#define FC_VPORTSTATE_MAX_NAMELEN	24

/* Reuse fc_vport_state enum function for vport_last_state */

#define get_fc_vport_last_state_name get_fc_vport_state_name


/* Convert fc_tgtid_binding_type values to ascii string name */
static const struct {
	
enum fc_tgtid_binding_type	value;
	
char				*name;
	
int				matchlen;
} 
fc_tgtid_binding_type_names[] = {
	{ FC_TGTID_BIND_NONE, "none", 4 },
	{ FC_TGTID_BIND_BY_WWPN, "wwpn (World Wide Port Name)", 4 },
	{ FC_TGTID_BIND_BY_WWNN, "wwnn (World Wide Node Name)", 4 },
	{ FC_TGTID_BIND_BY_ID, "port_id (FC Address)", 7 },
};
fc_enum_name_search(tgtid_bind_type, fc_tgtid_binding_type,
		fc_tgtid_binding_type_names)
fc_enum_name_match(tgtid_bind_type, fc_tgtid_binding_type,
		fc_tgtid_binding_type_names)

#define FC_BINDTYPE_MAX_NAMELEN	30



#define fc_bitfield_name_search(title, table)			\
static ssize_t                                                  \
get_fc_##title##_names(u32 table_key, char *buf)                \
{                                                               \
        char *prefix = "";                                      \
        ssize_t len = 0;                                        \
        int i;                                                  \
                                                                \
        for (i = 0; i < ARRAY_SIZE(table); i++) {               \
                if (table[i].value & table_key) {               \
                        len += sprintf(buf + len, "%s%s",       \
                                prefix, table[i].name);         \
                        prefix = ", ";                          \
                }                                               \
        }                                                       \
        len += sprintf(buf + len, "\n");                        \
        return len;                                             \
}


/* Convert FC_COS bit values to ascii string name */
static const struct {
	
u32 			value;
	
char			*name;
} 
fc_cos_names[] = {
	{ FC_COS_CLASS1,	"Class 1" },
	{ FC_COS_CLASS2,	"Class 2" },
	{ FC_COS_CLASS3,	"Class 3" },
	{ FC_COS_CLASS4,	"Class 4" },
	{ FC_COS_CLASS6,	"Class 6" },
};
fc_bitfield_name_search(cos, fc_cos_names)


/* Convert FC_PORTSPEED bit values to ascii string name */
static const struct {
	
u32 			value;
	
char			*name;
} 
fc_port_speed_names[] = {
	{ FC_PORTSPEED_1GBIT,		"1 Gbit" },
	{ FC_PORTSPEED_2GBIT,		"2 Gbit" },
	{ FC_PORTSPEED_4GBIT,		"4 Gbit" },
	{ FC_PORTSPEED_10GBIT,		"10 Gbit" },
	{ FC_PORTSPEED_8GBIT,		"8 Gbit" },
	{ FC_PORTSPEED_16GBIT,		"16 Gbit" },
	{ FC_PORTSPEED_32GBIT,		"32 Gbit" },
	{ FC_PORTSPEED_20GBIT,		"20 Gbit" },
	{ FC_PORTSPEED_40GBIT,		"40 Gbit" },
	{ FC_PORTSPEED_50GBIT,		"50 Gbit" },
	{ FC_PORTSPEED_100GBIT,		"100 Gbit" },
	{ FC_PORTSPEED_25GBIT,		"25 Gbit" },
	{ FC_PORTSPEED_NOT_NEGOTIATED,	"Not Negotiated" },
};
fc_bitfield_name_search(port_speed, fc_port_speed_names)



static int show_fc_fc4s (char *buf, u8 *fc4_list) { int i, len=0; for (i = 0; i < FC_FC4_LIST_SIZE; i++, fc4_list++) len += sprintf(buf + len , "0x%02x ", *fc4_list); len += sprintf(buf + len, "\n"); return len; }

Contributors

PersonTokensPropCommitsCommitProp
James Bottomley6295.38%266.67%
James Smart34.62%133.33%
Total65100.00%3100.00%

/* Convert FC_PORT_ROLE bit values to ascii string name */ static const struct { u32 value; char *name; } fc_port_role_names[] = { { FC_PORT_ROLE_FCP_TARGET, "FCP Target" }, { FC_PORT_ROLE_FCP_INITIATOR, "FCP Initiator" }, { FC_PORT_ROLE_IP_PORT, "IP Port" }, }; fc_bitfield_name_search(port_roles, fc_port_role_names) /* * Define roles that are specific to port_id. Values are relative to ROLE_MASK. */ #define FC_WELLKNOWN_PORTID_MASK 0xfffff0 #define FC_WELLKNOWN_ROLE_MASK 0x00000f #define FC_FPORT_PORTID 0x00000e #define FC_FABCTLR_PORTID 0x00000d #define FC_DIRSRVR_PORTID 0x00000c #define FC_TIMESRVR_PORTID 0x00000b #define FC_MGMTSRVR_PORTID 0x00000a static void fc_timeout_deleted_rport(struct work_struct *work); static void fc_timeout_fail_rport_io(struct work_struct *work); static void fc_scsi_scan_rport(struct work_struct *work); /* * Attribute counts pre object type... * Increase these values if you add attributes */ #define FC_STARGET_NUM_ATTRS 3 #define FC_RPORT_NUM_ATTRS 10 #define FC_VPORT_NUM_ATTRS 9 #define FC_HOST_NUM_ATTRS 29 struct fc_internal { struct scsi_transport_template t; struct fc_function_template *f; /* * For attributes : each object has : * An array of the actual attributes structures * An array of null-terminated pointers to the attribute * structures - used for mid-layer interaction. * * The attribute containers for the starget and host are are * part of the midlayer. As the remote port is specific to the * fc transport, we must provide the attribute container. */ struct device_attribute private_starget_attrs[ FC_STARGET_NUM_ATTRS]; struct device_attribute *starget_attrs[FC_STARGET_NUM_ATTRS + 1]; struct device_attribute private_host_attrs[FC_HOST_NUM_ATTRS]; struct device_attribute *host_attrs[FC_HOST_NUM_ATTRS + 1]; struct transport_container rport_attr_cont; struct device_attribute private_rport_attrs[FC_RPORT_NUM_ATTRS]; struct device_attribute *rport_attrs[FC_RPORT_NUM_ATTRS + 1]; struct transport_container vport_attr_cont; struct device_attribute private_vport_attrs[FC_VPORT_NUM_ATTRS]; struct device_attribute *vport_attrs[FC_VPORT_NUM_ATTRS + 1]; }; #define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t)
static int fc_target_setup(struct transport_container *tc, struct device *dev, struct device *cdev) { struct scsi_target *starget = to_scsi_target(dev); struct fc_rport *rport = starget_to_rport(starget); /* * if parent is remote port, use values from remote port. * Otherwise, this host uses the fc_transport, but not the * remote port interface. As such, initialize to known non-values. */ if (rport) { fc_starget_node_name(starget) = rport->node_name; fc_starget_port_name(starget) = rport->port_name; fc_starget_port_id(starget) = rport->port_id; } else { fc_starget_node_name(starget) = -1; fc_starget_port_name(starget) = -1; fc_starget_port_id(starget) = -1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
James Bottomley10499.05%480.00%
Tony Jones10.95%120.00%
Total105100.00%5100.00%

static DECLARE_TRANSPORT_CLASS(fc_transport_class, "fc_transport", fc_target_setup, NULL, NULL);
static int fc_host_setup(struct transport_container *tc, struct device *dev, struct device *cdev) { struct Scsi_Host *shost = dev_to_shost(dev); struct fc_host_attrs *fc_host = shost_to_fc_host(shost); /* * Set default values easily detected by the midlayer as * failure cases. The scsi lldd is responsible for initializing * all transport attributes to valid values per host. */ fc_host->node_name = -1; fc_host->port_name = -1; fc_host->permanent_port_name = -1; fc_host->supported_classes = FC_COS_UNSPECIFIED; memset(fc_host->supported_fc4s, 0, sizeof(fc_host->supported_fc4s)); fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN; fc_host->maxframe_size = -1; fc_host->max_npiv_vports = 0; memset(fc_host->serial_number, 0, sizeof(fc_host->serial_number)); memset(fc_host->manufacturer, 0, sizeof(fc_host->manufacturer)); memset(fc_host->model, 0, sizeof(fc_host->model)); memset(fc_host->model_description, 0, sizeof(fc_host->model_description)); memset(fc_host->hardware_version, 0, sizeof(fc_host->hardware_version)); memset(fc_host->driver_version, 0, sizeof(fc_host->driver_version)); memset(fc_host->firmware_version, 0, sizeof(fc_host->firmware_version)); memset(fc_host->optionrom_version, 0, sizeof(fc_host->optionrom_version)); fc_host->port_id = -1; fc_host->port_type = FC_PORTTYPE_UNKNOWN; fc_host->port_state = FC_PORTSTATE_UNKNOWN; memset(fc_host->active_fc4s, 0, sizeof(fc_host->active_fc4s)); fc_host->speed = FC_PORTSPEED_UNKNOWN; fc_host->fabric_name = -1; memset(fc_host->symbolic_name, 0, sizeof(fc_host->symbolic_name)); memset(fc_host->system_hostname, 0, sizeof(fc_host->system_hostname)); fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN; INIT_LIST_HEAD(&fc_host->rports); INIT_LIST_HEAD(&fc_host->rport_bindings); INIT_LIST_HEAD(&fc_host->vports); fc_host->next_rport_number = 0; fc_host->next_target_id = 0; fc_host->next_vport_number = 0; fc_host->npiv_vports_inuse = 0; snprintf(fc_host->work_q_name, sizeof(fc_host->work_q_name), "fc_wq_%d", shost->host_no); fc_host->work_q = alloc_workqueue("%s", 0, 0, fc_host->work_q_name); if (!fc_host->work_q) return -ENOMEM; fc_host->dev_loss_tmo = fc_dev_loss_tmo; snprintf(fc_host->devloss_work_q_name, sizeof(fc_host->devloss_work_q_name), "fc_dl_%d", shost->host_no); fc_host->devloss_work_q = alloc_workqueue("%s", 0, 0, fc_host->devloss_work_q_name); if (!fc_host->devloss_work_q) { destroy_workqueue(fc_host->work_q); fc_host->work_q = NULL; return -ENOMEM; } fc_bsg_hostadd(shost, fc_host); /* ignore any bsg add error - we just can't do sgio */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
James Smart22345.14%633.33%
James Bottomley11623.48%527.78%
Neerav Parikh11222.67%15.56%
Kay Sievers122.43%15.56%
Nithin Nayak Sujir102.02%15.56%
Kees Cook102.02%15.56%
Mike Christie61.21%15.56%
Andreas Herrmann40.81%15.56%
Tony Jones10.20%15.56%
Total494100.00%18100.00%


static int fc_host_remove(struct transport_container *tc, struct device *dev, struct device *cdev) { struct Scsi_Host *shost = dev_to_shost(dev); struct fc_host_attrs *fc_host = shost_to_fc_host(shost); fc_bsg_remove(fc_host->rqst_q); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
James Smart4792.16%133.33%
James Bottomley47.84%266.67%
Total51100.00%3100.00%

static DECLARE_TRANSPORT_CLASS(fc_host_class, "fc_host", fc_host_setup, fc_host_remove, NULL); /* * Setup and Remove actions for remote ports are handled * in the service functions below. */ static DECLARE_TRANSPORT_CLASS(fc_rport_class, "fc_remote_ports", NULL, NULL, NULL); /* * Setup and Remove actions for virtual ports are handled * in the service functions below. */ static DECLARE_TRANSPORT_CLASS(fc_vport_class, "fc_vports", NULL, NULL, NULL); /* * Netlink Infrastructure */ static atomic_t fc_event_seq; /** * fc_get_event_number - Obtain the next sequential FC event number * * Notes: * We could have inlined this, but it would have required fc_event_seq to * be exposed. For now, live with the subroutine call. * Atomic used to avoid lock/unlock... */
u32 fc_get_event_number(void) { return atomic_add_return(1, &fc_event_seq); }

Contributors

PersonTokensPropCommitsCommitProp
James Smart16100.00%1100.00%
Total16100.00%1100.00%

EXPORT_SYMBOL(fc_get_event_number); /** * fc_host_post_event - called to post an even on an fc_host. * @shost: host the event occurred on * @event_number: fc event number obtained from get_fc_event_number() * @event_code: fc_host event being posted * @event_data: 32bits of data for the event being posted * * Notes: * This routine assumes no locks are held on entry. */
void fc_host_post_event(struct Scsi_Host *shost, u32 event_number, enum fc_host_event_code event_code, u32 event_data) { struct sk_buff *skb; struct nlmsghdr *nlh; struct fc_nl_event *event; const char *name; u32 len; int err; if (!scsi_nl_sock) { err = -ENOENT; goto send_fail; } len = FC_NL_MSGALIGN(sizeof(*event)); skb = nlmsg_new(len, GFP_KERNEL); if (!skb) { err = -ENOBUFS; goto send_fail; } nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, len, 0); if (!nlh) { err = -ENOBUFS; goto send_fail_skb; } event = nlmsg_data(nlh); INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, FC_NL_ASYNC_EVENT, len); event->seconds = get_seconds(); event->vendor_id = 0; event->host_no = shost->host_no; event->event_datalen = sizeof(u32); /* bytes */ event->event_num = event_number; event->event_code = event_code; event->event_data = event_data; nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, GFP_KERNEL); return; send_fail_skb: kfree_skb(skb); send_fail: name = get_fc_host_event_code_name(event_code); printk(KERN_WARNING "%s: Dropped Event : host %d %s data 0x%08x - err %d\n", __func__, shost->host_no, (name) ? name : "<unknown>", event_data, err); return; }

Contributors

PersonTokensPropCommitsCommitProp
James Smart24697.23%125.00%
Hong Zhi Guo41.58%125.00%
James Bottomley20.79%125.00%
Harvey Harrison10.40%125.00%
Total253100.00%4100.00%

EXPORT_SYMBOL(fc_host_post_event); /** * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host * @shost: host the event occurred on * @event_number: fc event number obtained from get_fc_event_number() * @data_len: amount, in bytes, of vendor unique data * @data_buf: pointer to vendor unique data * @vendor_id: Vendor id * * Notes: * This routine assumes no locks are held on entry. */
void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, u32 data_len, char * data_buf, u64 vendor_id) { struct sk_buff *skb; struct nlmsghdr *nlh; struct fc_nl_event *event; u32 len; int err; if (!scsi_nl_sock) { err = -ENOENT; goto send_vendor_fail; } len = FC_NL_MSGALIGN(sizeof(*event) + data_len); skb = nlmsg_new(len, GFP_KERNEL); if (!skb) { err = -ENOBUFS; goto send_vendor_fail; } nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, len, 0); if (!nlh) { err = -ENOBUFS; goto send_vendor_fail_skb; } event = nlmsg_data(nlh); INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, FC_NL_ASYNC_EVENT, len); event->seconds = get_seconds(); event->vendor_id = vendor_id; event->host_no = shost->host_no; event->event_datalen = data_len; /* bytes */ event->event_num = event_number; event->event_code = FCH_EVT_VENDOR_UNIQUE; memcpy(&event->event_data, data_buf, data_len); nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, GFP_KERNEL); return; send_vendor_fail_skb: kfree_skb(skb); send_vendor_fail: printk(KERN_WARNING "%s: Dropped Event : host %d vendor_unique - err %d\n", __func__, shost->host_no, err); return; }

Contributors

PersonTokensPropCommitsCommitProp
James Smart23297.07%240.00%
Hong Zhi Guo41.67%120.00%
James Bottomley20.84%120.00%
Harvey Harrison10.42%120.00%
Total239100.00%5100.00%

EXPORT_SYMBOL(fc_host_post_vendor_event);
static __init int fc_transport_init(void) { int error; atomic_set(&fc_event_seq, 0); error = transport_class_register(&fc_host_class); if (error) return error; error = transport_class_register(&fc_vport_class); if (error) goto unreg_host_class; error = transport_class_register(&fc_rport_class); if (error) goto unreg_vport_class; error = transport_class_register(&fc_transport_class); if (error) goto unreg_rport_class; return 0; unreg_rport_class: transport_class_unregister(&fc_rport_class); unreg_vport_class: transport_class_unregister(&fc_vport_class); unreg_host_class: transport_class_unregister(&fc_host_class); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Mike Christie4440.00%116.67%
James Bottomley4238.18%350.00%
James Smart2421.82%233.33%
Total110100.00%6100.00%


static void __exit fc_transport_exit(void) { transport_class_unregister(&fc_transport_class); transport_class_unregister(&fc_rport_class); transport_class_unregister(&fc_host_class); transport_class_unregister(&fc_vport_class); }

Contributors

PersonTokensPropCommitsCommitProp
James Bottomley2781.82%375.00%
James Smart618.18%125.00%
Total33100.00%4100.00%

/* * FC Remote Port Attribute Management */ #define fc_rport_show_function(field, format_string, sz, cast) \ static ssize_t \ show_fc_rport_##field (struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct fc_rport *rport = transport_class_to_rport(dev); \ struct Scsi_Host *shost = rport_to_shost(rport); \ struct fc_internal *i = to_fc_internal(shost->transportt); \ if ((i->f->get_rport_##field) && \ !((rport->port_state == FC_PORTSTATE_BLOCKED) || \ (rport->port_state == FC_PORTSTATE_DELETED) || \ (rport->port_state == FC_PORTSTATE_NOTPRESENT))) \ i->f->get_rport_##field(rport); \ return snprintf(buf, sz, format_string, cast rport->field); \ } #define fc_rport_store_function(field) \ static ssize_t \ store_fc_rport_##field(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ int val; \ struct fc_rport *rport = transport_class_to_rport(dev); \ struct Scsi_Host *shost = rport_to_shost(rport); \ struct fc_internal *i = to_fc_internal(shost->transportt); \ char *cp; \ if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ (rport->port_state == FC_PORTSTATE_DELETED) || \ (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ return -EBUSY; \ val = simple_strtoul(buf, &cp, 0); \ if (*cp && (*cp != '\n')) \ return -EINVAL; \ i->f->set_rport_##field(rport, val); \ return count; \ } #define fc_rport_rd_attr(field, format_string, sz) \ fc_rport_show_function(field, format_string, sz, ) \ static FC_DEVICE_ATTR(rport, field, S_IRUGO, \ show_fc_rport_##field, NULL) #define fc_rport_rd_attr_cast(field, format_string, sz, cast) \ fc_rport_show_function(field, format_string, sz, (cast)) \ static FC_DEVICE_ATTR(rport, field, S_IRUGO, \ show_fc_rport_##field, NULL) #define fc_rport_rw_attr(field, format_string, sz) \ fc_rport_show_function(field, format_string, sz, ) \ fc_rport_store_function(field) \ static FC_DEVICE_ATTR(rport, field, S_IRUGO | S_IWUSR, \ show_fc_rport_##field, \ store_fc_rport_##field) #define fc_private_rport_show_function(field, format_string, sz, cast) \ static ssize_t \ show_fc_rport_##field (struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct fc_rport *rport = transport_class_to_rport(dev); \ return snprintf(buf, sz, format_string, cast rport->field); \ } #define fc_private_rport_rd_attr(field, format_string, sz) \ fc_private_rport_show_function(field, format_string, sz, ) \ static FC_DEVICE_ATTR(rport, field, S_IRUGO, \ show_fc_rport_##field, NULL) #define fc_private_rport_rd_attr_cast(field, format_string, sz, cast) \ fc_private_rport_show_function(field, format_string, sz, (cast)) \ static FC_DEVICE_ATTR(rport, field, S_IRUGO, \ show_fc_rport_##field, NULL) #define fc_private_rport_rd_enum_attr(title, maxlen) \ static ssize_t \ show_fc_rport_##title (struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct fc_rport *rport = transport_class_to_rport(dev); \ const char *name; \ name = get_fc_##title##_name(rport->title); \ if (!name) \ return -EINVAL; \ return snprintf(buf, maxlen, "%s\n", name); \ } \ static FC_DEVICE_ATTR(rport, title, S_IRUGO, \ show_fc_rport_##title, NULL) #define SETUP_RPORT_ATTRIBUTE_RD(field) \ i->private_rport_attrs[count] = device_attr_rport_##field; \ i->private_rport_attrs[count].attr.mode = S_IRUGO; \ i->private_rport_attrs[count].store = NULL; \ i->rport_attrs[count] = &i->private_rport_attrs[count]; \ if (i->f->show_rport_##field) \ count++ #define SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(field) \ i->private_rport_attrs[count] = device_attr_rport_##field; \ i->private_rport_attrs[count].attr.mode = S_IRUGO; \ i->private_rport_attrs[count].store = NULL; \ i->rport_attrs[count] = &i->private_rport_attrs[count]; \ count++ #define SETUP_RPORT_ATTRIBUTE_RW(field) \ i->private_rport_attrs[count] = device_attr_rport_##field; \ if (!i->f->set_rport_##field) { \ i->private_rport_attrs[count].attr.mode = S_IRUGO; \ i->private_rport_attrs[count].store = NULL; \ } \ i->rport_attrs[count] = &i->private_rport_attrs[count]; \ if (i->f->show_rport_##field) \ count++ #define SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(field) \ { \ i->private_rport_attrs[count] = device_attr_rport_##field; \ i->rport_attrs[count] = &i->private_rport_attrs[count]; \ count++; \ } /* The FC Transport Remote Port Attributes: */ /* Fixed Remote Port Attributes */ fc_private_rport_rd_attr(maxframe_size, "%u bytes\n", 20);
static ssize_t show_fc_rport_supported_classes (struct device *dev, struct device_attribute *attr, char *buf) { struct fc_rport *rport = transport_class_to_rport(dev); if (rport->supported_classes == FC_COS_UNSPECIFIED) return snprintf(buf, 20, "unspecified\n"); return get_fc_cos_names(rport->supported_classes, buf); }

Contributors

PersonTokensPropCommitsCommitProp
James Bottomley4475.86%466.67%
Tony Jones813.79%116.67%
James Smart610.34%116.67%
Total58100.00%6100.00%

static FC_DEVICE_ATTR(rport, supported_classes, S_IRUGO, show_fc_rport_supported_classes, NULL); /* Dynamic Remote Port Attributes */ /* * dev_loss_tmo attribute */
static int fc_str_to_dev_loss(const char *buf, unsigned long *val) { char *cp; *val = simple_strtoul(buf, &cp, 0); if ((*cp && (*cp != '\n')) || (*val < 0)) return -EINVAL; /* * Check for overflow; dev_loss_tmo is u32 */ if (*val > UINT_MAX) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Mike Christie6284.93%133.33%
James Smart912.33%133.33%
Hannes Reinecke22.74%133.33%
Total73100.00%3100.00%


static int fc_rport_set_dev_loss_tmo(struct fc_rport *rport, unsigned long val) { struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); if ((rport->port_state == FC_PORTSTATE_BLOCKED) || (rport->port_state == FC_PORTSTATE_DELETED) || (rport->port_state == FC_PORTSTATE_NOTPRESENT)) return -EBUSY; /* * Check for overflow; dev_loss_tmo is u32 */ if (val > UINT_MAX) return -EINVAL; /* * If fast_io_fail is off we have to cap * dev_loss_tmo at SCSI_DEVICE_BLOCK_MAX_TIMEOUT */ if (