scsi_transport_fc.c
来自「linux 内核源代码」· C语言 代码 · 共 2,128 行 · 第 1/5 页
C
2,128 行
/* * 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 <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 <linux/netlink.h>#include <net/netlink.h>#include <scsi/scsi_netlink_fc.h>#include "scsi_priv.h"#include "scsi_transport_fc_internal.h"static int fc_queue_work(struct Scsi_Host *, struct work_struct *);static void fc_vport_sched_delete(struct work_struct *work);/* * This is a temporary carrier for creating a vport. It will eventually * be replaced by a real message definition for sgio or netlink. * * fc_vport_identifiers: This set of data contains all elements * to uniquely identify and instantiate a FC virtual port. * * Notes: * symbolic_name: The driver is to append the symbolic_name string data * to the symbolic_node_name data that it generates by default. * the resulting combination should then be registered with the switch. * It is expected that things like Xen may stuff a VM title into * this field. */struct fc_vport_identifiers { u64 node_name; u64 port_name; u32 roles; bool disable; enum fc_port_type vport_type; /* only FC_PORTTYPE_NPIV allowed */ char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];};static int fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev, struct fc_vport_identifiers *ids, struct fc_vport **vport);/* * Redefine so that we can have same named attributes in the * sdev/starget/host objects. */#define FC_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \struct class_device_attribute class_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_NOT_NEGOTIATED, "Not Negotiated" },};fc_bitfield_name_search(port_speed, fc_port_speed_names)static intshow_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;}/* 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 0x00000astatic 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 21struct 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 class_device_attribute private_starget_attrs[ FC_STARGET_NUM_ATTRS]; struct class_device_attribute *starget_attrs[FC_STARGET_NUM_ATTRS + 1]; struct class_device_attribute private_host_attrs[FC_HOST_NUM_ATTRS]; struct class_device_attribute *host_attrs[FC_HOST_NUM_ATTRS + 1]; struct transport_container rport_attr_cont; struct class_device_attribute private_rport_attrs[FC_RPORT_NUM_ATTRS]; struct class_device_attribute *rport_attrs[FC_RPORT_NUM_ATTRS + 1]; struct transport_container vport_attr_cont; struct class_device_attribute private_vport_attrs[FC_VPORT_NUM_ATTRS]; struct class_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 class_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;}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 class_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)); 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, KOBJ_NAME_LEN, "fc_wq_%d", shost->host_no); fc_host->work_q = create_singlethread_workqueue( fc_host->work_q_name); if (!fc_host->work_q) return -ENOMEM;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?