brintos

brintos / linux-shallow public Read only

0
0
Text · 28.0 KiB · 0609ca6 Raw
1043 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright(c) 2011 - 2012 Intel Corporation. All rights reserved.4 *5 * Maintained at www.Open-FCoE.org6 */7 8#include <linux/module.h>9#include <linux/types.h>10#include <linux/kernel.h>11#include <linux/etherdevice.h>12#include <linux/ctype.h>13#include <linux/string.h>14 15#include <scsi/fcoe_sysfs.h>16#include <scsi/libfcoe.h>17 18/*19 * OK to include local libfcoe.h for debug_logging, but cannot include20 * <scsi/libfcoe.h> otherwise non-netdev based fcoe solutions would have21 * have to include more than fcoe_sysfs.h.22 */23#include "libfcoe.h"24 25static atomic_t ctlr_num;26static atomic_t fcf_num;27 28/*29 * fcoe_fcf_dev_loss_tmo: the default number of seconds that fcoe sysfs30 * should insulate the loss of a fcf.31 */32static unsigned int fcoe_fcf_dev_loss_tmo = 1800;  /* seconds */33 34module_param_named(fcf_dev_loss_tmo, fcoe_fcf_dev_loss_tmo,35		   uint, S_IRUGO|S_IWUSR);36MODULE_PARM_DESC(fcf_dev_loss_tmo,37		 "Maximum number of seconds that libfcoe should"38		 " insulate the loss of a fcf. Once this value is"39		 " exceeded, the fcf is removed.");40 41/*42 * These are used by the fcoe_*_show_function routines, they43 * are intentionally placed in the .c file as they're not intended44 * for use throughout the code.45 */46#define fcoe_ctlr_id(x)				\47	((x)->id)48#define fcoe_ctlr_work_q(x)			\49	((x)->work_q)50#define fcoe_ctlr_devloss_work_q(x)		\51	((x)->devloss_work_q)52#define fcoe_ctlr_mode(x)			\53	((x)->mode)54#define fcoe_ctlr_fcf_dev_loss_tmo(x)		\55	((x)->fcf_dev_loss_tmo)56#define fcoe_ctlr_link_fail(x)			\57	((x)->lesb.lesb_link_fail)58#define fcoe_ctlr_vlink_fail(x)			\59	((x)->lesb.lesb_vlink_fail)60#define fcoe_ctlr_miss_fka(x)			\61	((x)->lesb.lesb_miss_fka)62#define fcoe_ctlr_symb_err(x)			\63	((x)->lesb.lesb_symb_err)64#define fcoe_ctlr_err_block(x)			\65	((x)->lesb.lesb_err_block)66#define fcoe_ctlr_fcs_error(x)			\67	((x)->lesb.lesb_fcs_error)68#define fcoe_ctlr_enabled(x)			\69	((x)->enabled)70#define fcoe_fcf_state(x)			\71	((x)->state)72#define fcoe_fcf_fabric_name(x)			\73	((x)->fabric_name)74#define fcoe_fcf_switch_name(x)			\75	((x)->switch_name)76#define fcoe_fcf_fc_map(x)			\77	((x)->fc_map)78#define fcoe_fcf_vfid(x)			\79	((x)->vfid)80#define fcoe_fcf_mac(x)				\81	((x)->mac)82#define fcoe_fcf_priority(x)			\83	((x)->priority)84#define fcoe_fcf_fka_period(x)			\85	((x)->fka_period)86#define fcoe_fcf_dev_loss_tmo(x)		\87	((x)->dev_loss_tmo)88#define fcoe_fcf_selected(x)			\89	((x)->selected)90#define fcoe_fcf_vlan_id(x)			\91	((x)->vlan_id)92 93/*94 * dev_loss_tmo attribute95 */96static int fcoe_str_to_dev_loss(const char *buf, unsigned long *val)97{98	int ret;99 100	ret = kstrtoul(buf, 0, val);101	if (ret)102		return -EINVAL;103	/*104	 * Check for overflow; dev_loss_tmo is u32105	 */106	if (*val > UINT_MAX)107		return -EINVAL;108 109	return 0;110}111 112static int fcoe_fcf_set_dev_loss_tmo(struct fcoe_fcf_device *fcf,113				     unsigned long val)114{115	if ((fcf->state == FCOE_FCF_STATE_UNKNOWN) ||116	    (fcf->state == FCOE_FCF_STATE_DISCONNECTED) ||117	    (fcf->state == FCOE_FCF_STATE_DELETED))118		return -EBUSY;119	/*120	 * Check for overflow; dev_loss_tmo is u32121	 */122	if (val > UINT_MAX)123		return -EINVAL;124 125	fcoe_fcf_dev_loss_tmo(fcf) = val;126	return 0;127}128 129#define FCOE_DEVICE_ATTR(_prefix, _name, _mode, _show, _store)	\130struct device_attribute device_attr_fcoe_##_prefix##_##_name =	\131	__ATTR(_name, _mode, _show, _store)132 133#define fcoe_ctlr_show_function(field, format_string, sz, cast)	\134static ssize_t show_fcoe_ctlr_device_##field(struct device *dev, \135					    struct device_attribute *attr, \136					    char *buf)			\137{									\138	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);		\139	if (ctlr->f->get_fcoe_ctlr_##field)				\140		ctlr->f->get_fcoe_ctlr_##field(ctlr);			\141	return snprintf(buf, sz, format_string,				\142			cast fcoe_ctlr_##field(ctlr));			\143}144 145#define fcoe_fcf_show_function(field, format_string, sz, cast)	\146static ssize_t show_fcoe_fcf_device_##field(struct device *dev,	\147					   struct device_attribute *attr, \148					   char *buf)			\149{									\150	struct fcoe_fcf_device *fcf = dev_to_fcf(dev);			\151	struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);	\152	if (ctlr->f->get_fcoe_fcf_##field)				\153		ctlr->f->get_fcoe_fcf_##field(fcf);			\154	return snprintf(buf, sz, format_string,				\155			cast fcoe_fcf_##field(fcf));			\156}157 158#define fcoe_ctlr_private_show_function(field, format_string, sz, cast)	\159static ssize_t show_fcoe_ctlr_device_##field(struct device *dev, \160					    struct device_attribute *attr, \161					    char *buf)			\162{									\163	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);		\164	return snprintf(buf, sz, format_string, cast fcoe_ctlr_##field(ctlr)); \165}166 167#define fcoe_fcf_private_show_function(field, format_string, sz, cast)	\168static ssize_t show_fcoe_fcf_device_##field(struct device *dev,	\169					   struct device_attribute *attr, \170					   char *buf)			\171{								\172	struct fcoe_fcf_device *fcf = dev_to_fcf(dev);			\173	return snprintf(buf, sz, format_string, cast fcoe_fcf_##field(fcf)); \174}175 176#define fcoe_ctlr_private_rd_attr(field, format_string, sz)		\177	fcoe_ctlr_private_show_function(field, format_string, sz, )	\178	static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO,			\179				show_fcoe_ctlr_device_##field, NULL)180 181#define fcoe_ctlr_rd_attr(field, format_string, sz)			\182	fcoe_ctlr_show_function(field, format_string, sz, )		\183	static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO,			\184				show_fcoe_ctlr_device_##field, NULL)185 186#define fcoe_fcf_rd_attr(field, format_string, sz)			\187	fcoe_fcf_show_function(field, format_string, sz, )		\188	static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO,			\189				show_fcoe_fcf_device_##field, NULL)190 191#define fcoe_fcf_private_rd_attr(field, format_string, sz)		\192	fcoe_fcf_private_show_function(field, format_string, sz, )	\193	static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO,			\194				show_fcoe_fcf_device_##field, NULL)195 196#define fcoe_ctlr_private_rd_attr_cast(field, format_string, sz, cast)	\197	fcoe_ctlr_private_show_function(field, format_string, sz, (cast)) \198	static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO,			\199				show_fcoe_ctlr_device_##field, NULL)200 201#define fcoe_fcf_private_rd_attr_cast(field, format_string, sz, cast)	\202	fcoe_fcf_private_show_function(field, format_string, sz, (cast)) \203	static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO,			\204				show_fcoe_fcf_device_##field, NULL)205 206#define fcoe_enum_name_search(title, table_type, table)			\207static const char *get_fcoe_##title##_name(enum table_type table_key)	\208{									\209	if (table_key < 0 || table_key >= ARRAY_SIZE(table))		\210		return NULL;						\211	return table[table_key];					\212}213 214static const char * const fip_conn_type_names[] = {215	[ FIP_CONN_TYPE_UNKNOWN ] = "Unknown",216	[ FIP_CONN_TYPE_FABRIC ]  = "Fabric",217	[ FIP_CONN_TYPE_VN2VN ]   = "VN2VN",218};219fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names)220 221static char *fcf_state_names[] = {222	[ FCOE_FCF_STATE_UNKNOWN ]      = "Unknown",223	[ FCOE_FCF_STATE_DISCONNECTED ] = "Disconnected",224	[ FCOE_FCF_STATE_CONNECTED ]    = "Connected",225};226fcoe_enum_name_search(fcf_state, fcf_state, fcf_state_names)227#define FCOE_FCF_STATE_MAX_NAMELEN 50228 229static ssize_t show_fcf_state(struct device *dev,230			      struct device_attribute *attr,231			      char *buf)232{233	struct fcoe_fcf_device *fcf = dev_to_fcf(dev);234	const char *name;235	name = get_fcoe_fcf_state_name(fcf->state);236	if (!name)237		return -EINVAL;238	return snprintf(buf, FCOE_FCF_STATE_MAX_NAMELEN, "%s\n", name);239}240static FCOE_DEVICE_ATTR(fcf, state, S_IRUGO, show_fcf_state, NULL);241 242#define FCOE_MAX_MODENAME_LEN 20243static ssize_t show_ctlr_mode(struct device *dev,244			      struct device_attribute *attr,245			      char *buf)246{247	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);248	const char *name;249 250	name = get_fcoe_ctlr_mode_name(ctlr->mode);251	if (!name)252		return -EINVAL;253	return snprintf(buf, FCOE_MAX_MODENAME_LEN,254			"%s\n", name);255}256 257static ssize_t store_ctlr_mode(struct device *dev,258			       struct device_attribute *attr,259			       const char *buf, size_t count)260{261	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);262	int res;263 264	if (count > FCOE_MAX_MODENAME_LEN)265		return -EINVAL;266 267 268	switch (ctlr->enabled) {269	case FCOE_CTLR_ENABLED:270		LIBFCOE_SYSFS_DBG(ctlr, "Cannot change mode when enabled.\n");271		return -EBUSY;272	case FCOE_CTLR_DISABLED:273		if (!ctlr->f->set_fcoe_ctlr_mode) {274			LIBFCOE_SYSFS_DBG(ctlr,275					  "Mode change not supported by LLD.\n");276			return -ENOTSUPP;277		}278 279		res = sysfs_match_string(fip_conn_type_names, buf);280		if (res < 0 || res == FIP_CONN_TYPE_UNKNOWN) {281			LIBFCOE_SYSFS_DBG(ctlr, "Unknown mode %s provided.\n",282					  buf);283			return -EINVAL;284		}285		ctlr->mode = res;286 287		ctlr->f->set_fcoe_ctlr_mode(ctlr);288		LIBFCOE_SYSFS_DBG(ctlr, "Mode changed to %s.\n", buf);289 290		return count;291	case FCOE_CTLR_UNUSED:292	default:293		LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported.\n");294		return -ENOTSUPP;295	}296}297 298static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO | S_IWUSR,299			show_ctlr_mode, store_ctlr_mode);300 301static ssize_t store_ctlr_enabled(struct device *dev,302				  struct device_attribute *attr,303				  const char *buf, size_t count)304{305	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);306	bool enabled;307	int rc;308 309	if (*buf == '1')310		enabled = true;311	else if (*buf == '0')312		enabled = false;313	else314		return -EINVAL;315 316	switch (ctlr->enabled) {317	case FCOE_CTLR_ENABLED:318		if (enabled)319			return count;320		ctlr->enabled = FCOE_CTLR_DISABLED;321		break;322	case FCOE_CTLR_DISABLED:323		if (!enabled)324			return count;325		ctlr->enabled = FCOE_CTLR_ENABLED;326		break;327	case FCOE_CTLR_UNUSED:328		return -ENOTSUPP;329	}330 331	rc = ctlr->f->set_fcoe_ctlr_enabled(ctlr);332	if (rc)333		return rc;334 335	return count;336}337 338static char *ctlr_enabled_state_names[] = {339	[ FCOE_CTLR_ENABLED ]  = "1",340	[ FCOE_CTLR_DISABLED ] = "0",341};342fcoe_enum_name_search(ctlr_enabled_state, ctlr_enabled_state,343		      ctlr_enabled_state_names)344#define FCOE_CTLR_ENABLED_MAX_NAMELEN 50345 346static ssize_t show_ctlr_enabled_state(struct device *dev,347				       struct device_attribute *attr,348				       char *buf)349{350	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);351	const char *name;352 353	name = get_fcoe_ctlr_enabled_state_name(ctlr->enabled);354	if (!name)355		return -EINVAL;356	return snprintf(buf, FCOE_CTLR_ENABLED_MAX_NAMELEN,357			"%s\n", name);358}359 360static FCOE_DEVICE_ATTR(ctlr, enabled, S_IRUGO | S_IWUSR,361			show_ctlr_enabled_state,362			store_ctlr_enabled);363 364static ssize_t store_ctlr_fip_resp(struct device *dev,365			      struct device_attribute *attr,366			      const char *buf, size_t count)367{368	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);369	struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr);370 371	mutex_lock(&fip->ctlr_mutex);372	if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) {373		if (buf[0] == '1') {374			fip->fip_resp = 1;375			mutex_unlock(&fip->ctlr_mutex);376			return count;377		}378		if (buf[0] == '0') {379			fip->fip_resp = 0;380			mutex_unlock(&fip->ctlr_mutex);381			return count;382		}383	}384	mutex_unlock(&fip->ctlr_mutex);385	return -EINVAL;386}387 388static ssize_t show_ctlr_fip_resp(struct device *dev,389				  struct device_attribute *attr,390				  char *buf)391{392	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);393	struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr);394 395	return sprintf(buf, "%d\n", fip->fip_resp ? 1 : 0);396}397 398static FCOE_DEVICE_ATTR(ctlr, fip_vlan_responder, S_IRUGO | S_IWUSR,399			show_ctlr_fip_resp,400			store_ctlr_fip_resp);401 402static ssize_t403fcoe_ctlr_var_store(u32 *var, const char *buf, size_t count)404{405	int err;406	unsigned long v;407 408	err = kstrtoul(buf, 10, &v);409	if (err || v > UINT_MAX)410		return -EINVAL;411 412	*var = v;413 414	return count;415}416 417static ssize_t store_ctlr_r_a_tov(struct device *dev,418				  struct device_attribute *attr,419				  const char *buf, size_t count)420{421	struct fcoe_ctlr_device *ctlr_dev = dev_to_ctlr(dev);422	struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);423 424	if (ctlr_dev->enabled == FCOE_CTLR_ENABLED)425		return -EBUSY;426	if (ctlr_dev->enabled == FCOE_CTLR_DISABLED)427		return fcoe_ctlr_var_store(&ctlr->lp->r_a_tov, buf, count);428	return -ENOTSUPP;429}430 431static ssize_t show_ctlr_r_a_tov(struct device *dev,432				 struct device_attribute *attr,433				 char *buf)434{435	struct fcoe_ctlr_device *ctlr_dev = dev_to_ctlr(dev);436	struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);437 438	return sprintf(buf, "%d\n", ctlr->lp->r_a_tov);439}440 441static FCOE_DEVICE_ATTR(ctlr, r_a_tov, S_IRUGO | S_IWUSR,442			show_ctlr_r_a_tov, store_ctlr_r_a_tov);443 444static ssize_t store_ctlr_e_d_tov(struct device *dev,445				  struct device_attribute *attr,446				  const char *buf, size_t count)447{448	struct fcoe_ctlr_device *ctlr_dev = dev_to_ctlr(dev);449	struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);450 451	if (ctlr_dev->enabled == FCOE_CTLR_ENABLED)452		return -EBUSY;453	if (ctlr_dev->enabled == FCOE_CTLR_DISABLED)454		return fcoe_ctlr_var_store(&ctlr->lp->e_d_tov, buf, count);455	return -ENOTSUPP;456}457 458static ssize_t show_ctlr_e_d_tov(struct device *dev,459				 struct device_attribute *attr,460				 char *buf)461{462	struct fcoe_ctlr_device *ctlr_dev = dev_to_ctlr(dev);463	struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);464 465	return sprintf(buf, "%d\n", ctlr->lp->e_d_tov);466}467 468static FCOE_DEVICE_ATTR(ctlr, e_d_tov, S_IRUGO | S_IWUSR,469			show_ctlr_e_d_tov, store_ctlr_e_d_tov);470 471static ssize_t472store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev,473					 struct device_attribute *attr,474					 const char *buf, size_t count)475{476	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);477	struct fcoe_fcf_device *fcf;478	unsigned long val;479	int rc;480 481	rc = fcoe_str_to_dev_loss(buf, &val);482	if (rc)483		return rc;484 485	fcoe_ctlr_fcf_dev_loss_tmo(ctlr) = val;486	mutex_lock(&ctlr->lock);487	list_for_each_entry(fcf, &ctlr->fcfs, peers)488		fcoe_fcf_set_dev_loss_tmo(fcf, val);489	mutex_unlock(&ctlr->lock);490	return count;491}492fcoe_ctlr_private_show_function(fcf_dev_loss_tmo, "%d\n", 20, );493static FCOE_DEVICE_ATTR(ctlr, fcf_dev_loss_tmo, S_IRUGO | S_IWUSR,494			show_fcoe_ctlr_device_fcf_dev_loss_tmo,495			store_private_fcoe_ctlr_fcf_dev_loss_tmo);496 497/* Link Error Status Block (LESB) */498fcoe_ctlr_rd_attr(link_fail, "%u\n", 20);499fcoe_ctlr_rd_attr(vlink_fail, "%u\n", 20);500fcoe_ctlr_rd_attr(miss_fka, "%u\n", 20);501fcoe_ctlr_rd_attr(symb_err, "%u\n", 20);502fcoe_ctlr_rd_attr(err_block, "%u\n", 20);503fcoe_ctlr_rd_attr(fcs_error, "%u\n", 20);504 505fcoe_fcf_private_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long);506fcoe_fcf_private_rd_attr_cast(switch_name, "0x%llx\n", 20, unsigned long long);507fcoe_fcf_private_rd_attr(priority, "%u\n", 20);508fcoe_fcf_private_rd_attr(fc_map, "0x%x\n", 20);509fcoe_fcf_private_rd_attr(vfid, "%u\n", 20);510fcoe_fcf_private_rd_attr(mac, "%pM\n", 20);511fcoe_fcf_private_rd_attr(fka_period, "%u\n", 20);512fcoe_fcf_rd_attr(selected, "%u\n", 20);513fcoe_fcf_rd_attr(vlan_id, "%u\n", 20);514 515fcoe_fcf_private_show_function(dev_loss_tmo, "%d\n", 20, )516static ssize_t517store_fcoe_fcf_dev_loss_tmo(struct device *dev, struct device_attribute *attr,518			    const char *buf, size_t count)519{520	struct fcoe_fcf_device *fcf = dev_to_fcf(dev);521	unsigned long val;522	int rc;523 524	rc = fcoe_str_to_dev_loss(buf, &val);525	if (rc)526		return rc;527 528	rc = fcoe_fcf_set_dev_loss_tmo(fcf, val);529	if (rc)530		return rc;531	return count;532}533static FCOE_DEVICE_ATTR(fcf, dev_loss_tmo, S_IRUGO | S_IWUSR,534			show_fcoe_fcf_device_dev_loss_tmo,535			store_fcoe_fcf_dev_loss_tmo);536 537static struct attribute *fcoe_ctlr_lesb_attrs[] = {538	&device_attr_fcoe_ctlr_link_fail.attr,539	&device_attr_fcoe_ctlr_vlink_fail.attr,540	&device_attr_fcoe_ctlr_miss_fka.attr,541	&device_attr_fcoe_ctlr_symb_err.attr,542	&device_attr_fcoe_ctlr_err_block.attr,543	&device_attr_fcoe_ctlr_fcs_error.attr,544	NULL,545};546 547static struct attribute_group fcoe_ctlr_lesb_attr_group = {548	.name = "lesb",549	.attrs = fcoe_ctlr_lesb_attrs,550};551 552static struct attribute *fcoe_ctlr_attrs[] = {553	&device_attr_fcoe_ctlr_fip_vlan_responder.attr,554	&device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr,555	&device_attr_fcoe_ctlr_r_a_tov.attr,556	&device_attr_fcoe_ctlr_e_d_tov.attr,557	&device_attr_fcoe_ctlr_enabled.attr,558	&device_attr_fcoe_ctlr_mode.attr,559	NULL,560};561 562static struct attribute_group fcoe_ctlr_attr_group = {563	.attrs = fcoe_ctlr_attrs,564};565 566static const struct attribute_group *fcoe_ctlr_attr_groups[] = {567	&fcoe_ctlr_attr_group,568	&fcoe_ctlr_lesb_attr_group,569	NULL,570};571 572static struct attribute *fcoe_fcf_attrs[] = {573	&device_attr_fcoe_fcf_fabric_name.attr,574	&device_attr_fcoe_fcf_switch_name.attr,575	&device_attr_fcoe_fcf_dev_loss_tmo.attr,576	&device_attr_fcoe_fcf_fc_map.attr,577	&device_attr_fcoe_fcf_vfid.attr,578	&device_attr_fcoe_fcf_mac.attr,579	&device_attr_fcoe_fcf_priority.attr,580	&device_attr_fcoe_fcf_fka_period.attr,581	&device_attr_fcoe_fcf_state.attr,582	&device_attr_fcoe_fcf_selected.attr,583	&device_attr_fcoe_fcf_vlan_id.attr,584	NULL585};586 587static struct attribute_group fcoe_fcf_attr_group = {588	.attrs = fcoe_fcf_attrs,589};590 591static const struct attribute_group *fcoe_fcf_attr_groups[] = {592	&fcoe_fcf_attr_group,593	NULL,594};595 596static const struct bus_type fcoe_bus_type;597 598static int fcoe_bus_match(struct device *dev,599			  const struct device_driver *drv)600{601	if (dev->bus == &fcoe_bus_type)602		return 1;603	return 0;604}605 606/**607 * fcoe_ctlr_device_release() - Release the FIP ctlr memory608 * @dev: Pointer to the FIP ctlr's embedded device609 *610 * Called when the last FIP ctlr reference is released.611 */612static void fcoe_ctlr_device_release(struct device *dev)613{614	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);615	kfree(ctlr);616}617 618/**619 * fcoe_fcf_device_release() - Release the FIP fcf memory620 * @dev: Pointer to the fcf's embedded device621 *622 * Called when the last FIP fcf reference is released.623 */624static void fcoe_fcf_device_release(struct device *dev)625{626	struct fcoe_fcf_device *fcf = dev_to_fcf(dev);627	kfree(fcf);628}629 630static const struct device_type fcoe_ctlr_device_type = {631	.name = "fcoe_ctlr",632	.groups = fcoe_ctlr_attr_groups,633	.release = fcoe_ctlr_device_release,634};635 636static const struct device_type fcoe_fcf_device_type = {637	.name = "fcoe_fcf",638	.groups = fcoe_fcf_attr_groups,639	.release = fcoe_fcf_device_release,640};641 642static ssize_t ctlr_create_store(const struct bus_type *bus, const char *buf,643				 size_t count)644{645	return fcoe_ctlr_create_store(buf, count);646}647static BUS_ATTR_WO(ctlr_create);648 649static ssize_t ctlr_destroy_store(const struct bus_type *bus, const char *buf,650				  size_t count)651{652	return fcoe_ctlr_destroy_store(buf, count);653}654static BUS_ATTR_WO(ctlr_destroy);655 656static struct attribute *fcoe_bus_attrs[] = {657	&bus_attr_ctlr_create.attr,658	&bus_attr_ctlr_destroy.attr,659	NULL,660};661ATTRIBUTE_GROUPS(fcoe_bus);662 663static const struct bus_type fcoe_bus_type = {664	.name = "fcoe",665	.match = &fcoe_bus_match,666	.bus_groups = fcoe_bus_groups,667};668 669/**670 * fcoe_ctlr_device_flush_work() - Flush a FIP ctlr's workqueue671 * @ctlr: Pointer to the FIP ctlr whose workqueue is to be flushed672 */673static void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr)674{675	if (!fcoe_ctlr_work_q(ctlr)) {676		printk(KERN_ERR677		       "ERROR: FIP Ctlr '%d' attempted to flush work, "678		       "when no workqueue created.\n", ctlr->id);679		dump_stack();680		return;681	}682 683	flush_workqueue(fcoe_ctlr_work_q(ctlr));684}685 686/**687 * fcoe_ctlr_device_queue_work() - Schedule work for a FIP ctlr's workqueue688 * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue689 * @work:   Work to queue for execution690 *691 * Return value:692 *	1 on success / 0 already queued / < 0 for error693 */694static int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr,695				       struct work_struct *work)696{697	if (unlikely(!fcoe_ctlr_work_q(ctlr))) {698		printk(KERN_ERR699		       "ERROR: FIP Ctlr '%d' attempted to queue work, "700		       "when no workqueue created.\n", ctlr->id);701		dump_stack();702 703		return -EINVAL;704	}705 706	return queue_work(fcoe_ctlr_work_q(ctlr), work);707}708 709/**710 * fcoe_ctlr_device_flush_devloss() - Flush a FIP ctlr's devloss workqueue711 * @ctlr: Pointer to FIP ctlr whose workqueue is to be flushed712 */713static void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr)714{715	if (!fcoe_ctlr_devloss_work_q(ctlr)) {716		printk(KERN_ERR717		       "ERROR: FIP Ctlr '%d' attempted to flush work, "718		       "when no workqueue created.\n", ctlr->id);719		dump_stack();720		return;721	}722 723	flush_workqueue(fcoe_ctlr_devloss_work_q(ctlr));724}725 726/**727 * fcoe_ctlr_device_queue_devloss_work() - Schedule work for a FIP ctlr's devloss workqueue728 * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue729 * @work:   Work to queue for execution730 * @delay:  jiffies to delay the work queuing731 *732 * Return value:733 *	1 on success / 0 already queued / < 0 for error734 */735static int fcoe_ctlr_device_queue_devloss_work(struct fcoe_ctlr_device *ctlr,736					       struct delayed_work *work,737					       unsigned long delay)738{739	if (unlikely(!fcoe_ctlr_devloss_work_q(ctlr))) {740		printk(KERN_ERR741		       "ERROR: FIP Ctlr '%d' attempted to queue work, "742		       "when no workqueue created.\n", ctlr->id);743		dump_stack();744 745		return -EINVAL;746	}747 748	return queue_delayed_work(fcoe_ctlr_devloss_work_q(ctlr), work, delay);749}750 751static int fcoe_fcf_device_match(struct fcoe_fcf_device *new,752				 struct fcoe_fcf_device *old)753{754	if (new->switch_name == old->switch_name &&755	    new->fabric_name == old->fabric_name &&756	    new->fc_map == old->fc_map &&757	    ether_addr_equal(new->mac, old->mac))758		return 1;759	return 0;760}761 762/**763 * fcoe_ctlr_device_add() - Add a FIP ctlr to sysfs764 * @parent:    The parent device to which the fcoe_ctlr instance765 *             should be attached766 * @f:         The LLD's FCoE sysfs function template pointer767 * @priv_size: Size to be allocated with the fcoe_ctlr_device for the LLD768 *769 * This routine allocates a FIP ctlr object with some additional memory770 * for the LLD. The FIP ctlr is initialized, added to sysfs and then771 * attributes are added to it.772 */773struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent,774				    struct fcoe_sysfs_function_template *f,775				    int priv_size)776{777	struct fcoe_ctlr_device *ctlr;778	int error = 0;779 780	ctlr = kzalloc(sizeof(struct fcoe_ctlr_device) + priv_size,781		       GFP_KERNEL);782	if (!ctlr)783		goto out;784 785	ctlr->id = atomic_inc_return(&ctlr_num) - 1;786	ctlr->f = f;787	ctlr->mode = FIP_CONN_TYPE_FABRIC;788	INIT_LIST_HEAD(&ctlr->fcfs);789	mutex_init(&ctlr->lock);790	ctlr->dev.parent = parent;791	ctlr->dev.bus = &fcoe_bus_type;792	ctlr->dev.type = &fcoe_ctlr_device_type;793 794	ctlr->fcf_dev_loss_tmo = fcoe_fcf_dev_loss_tmo;795 796	ctlr->work_q = alloc_ordered_workqueue("ctlr_wq_%d", WQ_MEM_RECLAIM,797					       ctlr->id);798	if (!ctlr->work_q)799		goto out_del;800 801	ctlr->devloss_work_q = alloc_ordered_workqueue("ctlr_dl_wq_%d",802						       WQ_MEM_RECLAIM,803						       ctlr->id);804	if (!ctlr->devloss_work_q)805		goto out_del_q;806 807	dev_set_name(&ctlr->dev, "ctlr_%d", ctlr->id);808	error = device_register(&ctlr->dev);809	if (error) {810		destroy_workqueue(ctlr->devloss_work_q);811		destroy_workqueue(ctlr->work_q);812		put_device(&ctlr->dev);813		return NULL;814	}815 816	return ctlr;817 818out_del_q:819	destroy_workqueue(ctlr->work_q);820	ctlr->work_q = NULL;821out_del:822	kfree(ctlr);823out:824	return NULL;825}826EXPORT_SYMBOL_GPL(fcoe_ctlr_device_add);827 828/**829 * fcoe_ctlr_device_delete() - Delete a FIP ctlr and its subtree from sysfs830 * @ctlr: A pointer to the ctlr to be deleted831 *832 * Deletes a FIP ctlr and any fcfs attached833 * to it. Deleting fcfs will cause their childen834 * to be deleted as well.835 *836 * The ctlr is detached from sysfs and it's resources837 * are freed (work q), but the memory is not freed838 * until its last reference is released.839 *840 * This routine expects no locks to be held before841 * calling.842 *843 * TODO: Currently there are no callbacks to clean up LLD data844 * for a fcoe_fcf_device. LLDs must keep this in mind as they need845 * to clean up each of their LLD data for all fcoe_fcf_device before846 * calling fcoe_ctlr_device_delete.847 */848void fcoe_ctlr_device_delete(struct fcoe_ctlr_device *ctlr)849{850	struct fcoe_fcf_device *fcf, *next;851	/* Remove any attached fcfs */852	mutex_lock(&ctlr->lock);853	list_for_each_entry_safe(fcf, next,854				 &ctlr->fcfs, peers) {855		list_del(&fcf->peers);856		fcf->state = FCOE_FCF_STATE_DELETED;857		fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work);858	}859	mutex_unlock(&ctlr->lock);860 861	fcoe_ctlr_device_flush_work(ctlr);862 863	destroy_workqueue(ctlr->devloss_work_q);864	ctlr->devloss_work_q = NULL;865	destroy_workqueue(ctlr->work_q);866	ctlr->work_q = NULL;867 868	device_unregister(&ctlr->dev);869}870EXPORT_SYMBOL_GPL(fcoe_ctlr_device_delete);871 872/**873 * fcoe_fcf_device_final_delete() - Final delete routine874 * @work: The FIP fcf's embedded work struct875 *876 * It is expected that the fcf has been removed from877 * the FIP ctlr's list before calling this routine.878 */879static void fcoe_fcf_device_final_delete(struct work_struct *work)880{881	struct fcoe_fcf_device *fcf =882		container_of(work, struct fcoe_fcf_device, delete_work);883	struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);884 885	/*886	 * Cancel any outstanding timers. These should really exist887	 * only when rmmod'ing the LLDD and we're asking for888	 * immediate termination of the rports889	 */890	if (!cancel_delayed_work(&fcf->dev_loss_work))891		fcoe_ctlr_device_flush_devloss(ctlr);892 893	device_unregister(&fcf->dev);894}895 896/**897 * fip_timeout_deleted_fcf() - Delete a fcf when the devloss timer fires898 * @work: The FIP fcf's embedded work struct899 *900 * Removes the fcf from the FIP ctlr's list of fcfs and901 * queues the final deletion.902 */903static void fip_timeout_deleted_fcf(struct work_struct *work)904{905	struct fcoe_fcf_device *fcf =906		container_of(work, struct fcoe_fcf_device, dev_loss_work.work);907	struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);908 909	mutex_lock(&ctlr->lock);910 911	/*912	 * If the fcf is deleted or reconnected before the timer913	 * fires the devloss queue will be flushed, but the state will914	 * either be CONNECTED or DELETED. If that is the case we915	 * cancel deleting the fcf.916	 */917	if (fcf->state != FCOE_FCF_STATE_DISCONNECTED)918		goto out;919 920	dev_printk(KERN_ERR, &fcf->dev,921		   "FIP fcf connection time out: removing fcf\n");922 923	list_del(&fcf->peers);924	fcf->state = FCOE_FCF_STATE_DELETED;925	fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work);926 927out:928	mutex_unlock(&ctlr->lock);929}930 931/**932 * fcoe_fcf_device_delete() - Delete a FIP fcf933 * @fcf: Pointer to the fcf which is to be deleted934 *935 * Queues the FIP fcf on the devloss workqueue936 *937 * Expects the ctlr_attrs mutex to be held for fcf938 * state change.939 */940void fcoe_fcf_device_delete(struct fcoe_fcf_device *fcf)941{942	struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);943	int timeout = fcf->dev_loss_tmo;944 945	if (fcf->state != FCOE_FCF_STATE_CONNECTED)946		return;947 948	fcf->state = FCOE_FCF_STATE_DISCONNECTED;949 950	/*951	 * FCF will only be re-connected by the LLD calling952	 * fcoe_fcf_device_add, and it should be setting up953	 * priv then.954	 */955	fcf->priv = NULL;956 957	fcoe_ctlr_device_queue_devloss_work(ctlr, &fcf->dev_loss_work,958					   timeout * HZ);959}960EXPORT_SYMBOL_GPL(fcoe_fcf_device_delete);961 962/**963 * fcoe_fcf_device_add() - Add a FCoE sysfs fcoe_fcf_device to the system964 * @ctlr:    The fcoe_ctlr_device that will be the fcoe_fcf_device parent965 * @new_fcf: A temporary FCF used for lookups on the current list of fcfs966 *967 * Expects to be called with the ctlr->lock held968 */969struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *ctlr,970					    struct fcoe_fcf_device *new_fcf)971{972	struct fcoe_fcf_device *fcf;973	int error = 0;974 975	list_for_each_entry(fcf, &ctlr->fcfs, peers) {976		if (fcoe_fcf_device_match(new_fcf, fcf)) {977			if (fcf->state == FCOE_FCF_STATE_CONNECTED)978				return fcf;979 980			fcf->state = FCOE_FCF_STATE_CONNECTED;981 982			if (!cancel_delayed_work(&fcf->dev_loss_work))983				fcoe_ctlr_device_flush_devloss(ctlr);984 985			return fcf;986		}987	}988 989	fcf = kzalloc(sizeof(struct fcoe_fcf_device), GFP_ATOMIC);990	if (unlikely(!fcf))991		goto out;992 993	INIT_WORK(&fcf->delete_work, fcoe_fcf_device_final_delete);994	INIT_DELAYED_WORK(&fcf->dev_loss_work, fip_timeout_deleted_fcf);995 996	fcf->dev.parent = &ctlr->dev;997	fcf->dev.bus = &fcoe_bus_type;998	fcf->dev.type = &fcoe_fcf_device_type;999	fcf->id = atomic_inc_return(&fcf_num) - 1;1000	fcf->state = FCOE_FCF_STATE_UNKNOWN;1001 1002	fcf->dev_loss_tmo = ctlr->fcf_dev_loss_tmo;1003 1004	dev_set_name(&fcf->dev, "fcf_%d", fcf->id);1005 1006	fcf->fabric_name = new_fcf->fabric_name;1007	fcf->switch_name = new_fcf->switch_name;1008	fcf->fc_map = new_fcf->fc_map;1009	fcf->vfid = new_fcf->vfid;1010	memcpy(fcf->mac, new_fcf->mac, ETH_ALEN);1011	fcf->priority = new_fcf->priority;1012	fcf->fka_period = new_fcf->fka_period;1013	fcf->selected = new_fcf->selected;1014 1015	error = device_register(&fcf->dev);1016	if (error) {1017		put_device(&fcf->dev);1018		goto out;1019	}1020 1021	fcf->state = FCOE_FCF_STATE_CONNECTED;1022	list_add_tail(&fcf->peers, &ctlr->fcfs);1023 1024	return fcf;1025 1026out:1027	return NULL;1028}1029EXPORT_SYMBOL_GPL(fcoe_fcf_device_add);1030 1031int __init fcoe_sysfs_setup(void)1032{1033	atomic_set(&ctlr_num, 0);1034	atomic_set(&fcf_num, 0);1035 1036	return bus_register(&fcoe_bus_type);1037}1038 1039void __exit fcoe_sysfs_teardown(void)1040{1041	bus_unregister(&fcoe_bus_type);1042}1043