brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · cb8db25 Raw
269 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 3#include <linux/module.h>4#include <linux/moduleparam.h>5#include <linux/init.h>6#include <linux/slab.h>7#include <linux/types.h>8#include <linux/configfs.h>9#include <scsi/scsi.h>10#include <scsi/scsi_tcq.h>11#include <scsi/scsi_host.h>12#include <scsi/scsi_device.h>13#include <scsi/scsi_cmnd.h>14 15#include <target/target_core_base.h>16#include <target/target_core_fabric.h>17 18#include "tcm_remote.h"19 20static inline struct tcm_remote_tpg *remote_tpg(struct se_portal_group *se_tpg)21{22	return container_of(se_tpg, struct tcm_remote_tpg, remote_se_tpg);23}24 25static char *tcm_remote_get_endpoint_wwn(struct se_portal_group *se_tpg)26{27	/*28	 * Return the passed NAA identifier for the Target Port29	 */30	return &remote_tpg(se_tpg)->remote_hba->remote_wwn_address[0];31}32 33static u16 tcm_remote_get_tag(struct se_portal_group *se_tpg)34{35	/*36	 * This Tag is used when forming SCSI Name identifier in EVPD=1 0x8337	 * to represent the SCSI Target Port.38	 */39	return remote_tpg(se_tpg)->remote_tpgt;40}41 42static int tcm_remote_dummy_cmd_fn(struct se_cmd *se_cmd)43{44	return 0;45}46 47static void tcm_remote_dummy_cmd_void_fn(struct se_cmd *se_cmd)48{49 50}51 52static char *tcm_remote_dump_proto_id(struct tcm_remote_hba *remote_hba)53{54	switch (remote_hba->remote_proto_id) {55	case SCSI_PROTOCOL_SAS:56		return "SAS";57	case SCSI_PROTOCOL_SRP:58		return "SRP";59	case SCSI_PROTOCOL_FCP:60		return "FCP";61	case SCSI_PROTOCOL_ISCSI:62		return "iSCSI";63	default:64		break;65	}66 67	return "Unknown";68}69 70static int tcm_remote_port_link(71	struct se_portal_group *se_tpg,72	struct se_lun *lun)73{74	pr_debug("TCM_Remote_ConfigFS: Port Link LUN %lld Successful\n",75		 lun->unpacked_lun);76	return 0;77}78 79static void tcm_remote_port_unlink(80	struct se_portal_group *se_tpg,81	struct se_lun *lun)82{83	pr_debug("TCM_Remote_ConfigFS: Port Unlink LUN %lld Successful\n",84		 lun->unpacked_lun);85}86 87static struct se_portal_group *tcm_remote_make_tpg(88	struct se_wwn *wwn,89	const char *name)90{91	struct tcm_remote_hba *remote_hba = container_of(wwn,92			struct tcm_remote_hba, remote_hba_wwn);93	struct tcm_remote_tpg *remote_tpg;94	unsigned long tpgt;95	int ret;96 97	if (strstr(name, "tpgt_") != name) {98		pr_err("Unable to locate \"tpgt_#\" directory group\n");99		return ERR_PTR(-EINVAL);100	}101	if (kstrtoul(name + 5, 10, &tpgt))102		return ERR_PTR(-EINVAL);103 104	if (tpgt >= TL_TPGS_PER_HBA) {105		pr_err("Passed tpgt: %lu exceeds TL_TPGS_PER_HBA: %u\n",106		       tpgt, TL_TPGS_PER_HBA);107		return ERR_PTR(-EINVAL);108	}109	remote_tpg = &remote_hba->remote_hba_tpgs[tpgt];110	remote_tpg->remote_hba = remote_hba;111	remote_tpg->remote_tpgt = tpgt;112	/*113	 * Register the remote_tpg as a emulated TCM Target Endpoint114	 */115	ret = core_tpg_register(wwn, &remote_tpg->remote_se_tpg,116				remote_hba->remote_proto_id);117	if (ret < 0)118		return ERR_PTR(-ENOMEM);119 120	pr_debug("TCM_Remote_ConfigFS: Allocated Emulated %s Target Port %s,t,0x%04lx\n",121		 tcm_remote_dump_proto_id(remote_hba),122		 config_item_name(&wwn->wwn_group.cg_item), tpgt);123	return &remote_tpg->remote_se_tpg;124}125 126static void tcm_remote_drop_tpg(struct se_portal_group *se_tpg)127{128	struct se_wwn *wwn = se_tpg->se_tpg_wwn;129	struct tcm_remote_tpg *remote_tpg = container_of(se_tpg,130				struct tcm_remote_tpg, remote_se_tpg);131	struct tcm_remote_hba *remote_hba;132	unsigned short tpgt;133 134	remote_hba = remote_tpg->remote_hba;135	tpgt = remote_tpg->remote_tpgt;136 137	/*138	 * Deregister the remote_tpg as a emulated TCM Target Endpoint139	 */140	core_tpg_deregister(se_tpg);141 142	remote_tpg->remote_hba = NULL;143	remote_tpg->remote_tpgt = 0;144 145	pr_debug("TCM_Remote_ConfigFS: Deallocated Emulated %s Target Port %s,t,0x%04x\n",146		 tcm_remote_dump_proto_id(remote_hba),147		 config_item_name(&wwn->wwn_group.cg_item), tpgt);148}149 150static struct se_wwn *tcm_remote_make_wwn(151	struct target_fabric_configfs *tf,152	struct config_group *group,153	const char *name)154{155	struct tcm_remote_hba *remote_hba;156	char *ptr;157	int ret, off = 0;158 159	remote_hba = kzalloc(sizeof(*remote_hba), GFP_KERNEL);160	if (!remote_hba)161		return ERR_PTR(-ENOMEM);162 163	/*164	 * Determine the emulated Protocol Identifier and Target Port Name165	 * based on the incoming configfs directory name.166	 */167	ptr = strstr(name, "naa.");168	if (ptr) {169		remote_hba->remote_proto_id = SCSI_PROTOCOL_SAS;170		goto check_len;171	}172	ptr = strstr(name, "fc.");173	if (ptr) {174		remote_hba->remote_proto_id = SCSI_PROTOCOL_FCP;175		off = 3; /* Skip over "fc." */176		goto check_len;177	}178	ptr = strstr(name, "0x");179	if (ptr) {180		remote_hba->remote_proto_id = SCSI_PROTOCOL_SRP;181		off = 2; /* Skip over "0x" */182		goto check_len;183	}184	ptr = strstr(name, "iqn.");185	if (!ptr) {186		pr_err("Unable to locate prefix for emulated Target Port: %s\n",187		       name);188		ret = -EINVAL;189		goto out;190	}191	remote_hba->remote_proto_id = SCSI_PROTOCOL_ISCSI;192 193check_len:194	if (strlen(name) >= TL_WWN_ADDR_LEN) {195		pr_err("Emulated NAA %s Address: %s, exceeds max: %d\n",196		       name, tcm_remote_dump_proto_id(remote_hba), TL_WWN_ADDR_LEN);197		ret = -EINVAL;198		goto out;199	}200	snprintf(&remote_hba->remote_wwn_address[0], TL_WWN_ADDR_LEN, "%s", &name[off]);201 202	pr_debug("TCM_Remote_ConfigFS: Allocated emulated Target %s Address: %s\n",203		 tcm_remote_dump_proto_id(remote_hba), name);204	return &remote_hba->remote_hba_wwn;205out:206	kfree(remote_hba);207	return ERR_PTR(ret);208}209 210static void tcm_remote_drop_wwn(struct se_wwn *wwn)211{212	struct tcm_remote_hba *remote_hba = container_of(wwn,213				struct tcm_remote_hba, remote_hba_wwn);214 215	pr_debug("TCM_Remote_ConfigFS: Deallocating emulated Target %s Address: %s\n",216		 tcm_remote_dump_proto_id(remote_hba),217		 remote_hba->remote_wwn_address);218	kfree(remote_hba);219}220 221static ssize_t tcm_remote_wwn_version_show(struct config_item *item, char *page)222{223	return sprintf(page, "TCM Remote Fabric module %s\n", TCM_REMOTE_VERSION);224}225 226CONFIGFS_ATTR_RO(tcm_remote_wwn_, version);227 228static struct configfs_attribute *tcm_remote_wwn_attrs[] = {229	&tcm_remote_wwn_attr_version,230	NULL,231};232 233static const struct target_core_fabric_ops remote_ops = {234	.module				= THIS_MODULE,235	.fabric_name			= "remote",236	.tpg_get_wwn			= tcm_remote_get_endpoint_wwn,237	.tpg_get_tag			= tcm_remote_get_tag,238	.check_stop_free		= tcm_remote_dummy_cmd_fn,239	.release_cmd			= tcm_remote_dummy_cmd_void_fn,240	.write_pending			= tcm_remote_dummy_cmd_fn,241	.queue_data_in			= tcm_remote_dummy_cmd_fn,242	.queue_status			= tcm_remote_dummy_cmd_fn,243	.queue_tm_rsp			= tcm_remote_dummy_cmd_void_fn,244	.aborted_task			= tcm_remote_dummy_cmd_void_fn,245	.fabric_make_wwn		= tcm_remote_make_wwn,246	.fabric_drop_wwn		= tcm_remote_drop_wwn,247	.fabric_make_tpg		= tcm_remote_make_tpg,248	.fabric_drop_tpg		= tcm_remote_drop_tpg,249	.fabric_post_link		= tcm_remote_port_link,250	.fabric_pre_unlink		= tcm_remote_port_unlink,251	.tfc_wwn_attrs			= tcm_remote_wwn_attrs,252};253 254static int __init tcm_remote_fabric_init(void)255{256	return target_register_template(&remote_ops);257}258 259static void __exit tcm_remote_fabric_exit(void)260{261	target_unregister_template(&remote_ops);262}263 264MODULE_DESCRIPTION("TCM virtual remote target");265MODULE_AUTHOR("Dmitry Bogdanov <d.bogdanov@yadro.com>");266MODULE_LICENSE("GPL");267module_init(tcm_remote_fabric_init);268module_exit(tcm_remote_fabric_exit);269