1 // SPDX-License-Identifier: GPL-2.0-or-later
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>
10 #include <scsi/scsi_tcq.h>
11 #include <scsi/scsi_host.h>
12 #include <scsi/scsi_device.h>
13 #include <scsi/scsi_cmnd.h>
15 #include <target/target_core_base.h>
16 #include <target/target_core_fabric.h>
18 #include "tcm_remote.h"
20 static inline struct tcm_remote_tpg
*remote_tpg(struct se_portal_group
*se_tpg
)
22 return container_of(se_tpg
, struct tcm_remote_tpg
, remote_se_tpg
);
25 static char *tcm_remote_get_endpoint_wwn(struct se_portal_group
*se_tpg
)
28 * Return the passed NAA identifier for the Target Port
30 return &remote_tpg(se_tpg
)->remote_hba
->remote_wwn_address
[0];
33 static u16
tcm_remote_get_tag(struct se_portal_group
*se_tpg
)
36 * This Tag is used when forming SCSI Name identifier in EVPD=1 0x83
37 * to represent the SCSI Target Port.
39 return remote_tpg(se_tpg
)->remote_tpgt
;
42 static int tcm_remote_dummy_cmd_fn(struct se_cmd
*se_cmd
)
47 static void tcm_remote_dummy_cmd_void_fn(struct se_cmd
*se_cmd
)
52 static char *tcm_remote_dump_proto_id(struct tcm_remote_hba
*remote_hba
)
54 switch (remote_hba
->remote_proto_id
) {
55 case SCSI_PROTOCOL_SAS
:
57 case SCSI_PROTOCOL_SRP
:
59 case SCSI_PROTOCOL_FCP
:
61 case SCSI_PROTOCOL_ISCSI
:
70 static int tcm_remote_port_link(
71 struct se_portal_group
*se_tpg
,
74 pr_debug("TCM_Remote_ConfigFS: Port Link LUN %lld Successful\n",
79 static void tcm_remote_port_unlink(
80 struct se_portal_group
*se_tpg
,
83 pr_debug("TCM_Remote_ConfigFS: Port Unlink LUN %lld Successful\n",
87 static struct se_portal_group
*tcm_remote_make_tpg(
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
;
97 if (strstr(name
, "tpgt_") != name
) {
98 pr_err("Unable to locate \"tpgt_#\" directory group\n");
99 return ERR_PTR(-EINVAL
);
101 if (kstrtoul(name
+ 5, 10, &tpgt
))
102 return ERR_PTR(-EINVAL
);
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
);
109 remote_tpg
= &remote_hba
->remote_hba_tpgs
[tpgt
];
110 remote_tpg
->remote_hba
= remote_hba
;
111 remote_tpg
->remote_tpgt
= tpgt
;
113 * Register the remote_tpg as a emulated TCM Target Endpoint
115 ret
= core_tpg_register(wwn
, &remote_tpg
->remote_se_tpg
,
116 remote_hba
->remote_proto_id
);
118 return ERR_PTR(-ENOMEM
);
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
;
126 static void tcm_remote_drop_tpg(struct se_portal_group
*se_tpg
)
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
;
134 remote_hba
= remote_tpg
->remote_hba
;
135 tpgt
= remote_tpg
->remote_tpgt
;
138 * Deregister the remote_tpg as a emulated TCM Target Endpoint
140 core_tpg_deregister(se_tpg
);
142 remote_tpg
->remote_hba
= NULL
;
143 remote_tpg
->remote_tpgt
= 0;
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
);
150 static struct se_wwn
*tcm_remote_make_wwn(
151 struct target_fabric_configfs
*tf
,
152 struct config_group
*group
,
155 struct tcm_remote_hba
*remote_hba
;
159 remote_hba
= kzalloc(sizeof(*remote_hba
), GFP_KERNEL
);
161 return ERR_PTR(-ENOMEM
);
164 * Determine the emulated Protocol Identifier and Target Port Name
165 * based on the incoming configfs directory name.
167 ptr
= strstr(name
, "naa.");
169 remote_hba
->remote_proto_id
= SCSI_PROTOCOL_SAS
;
172 ptr
= strstr(name
, "fc.");
174 remote_hba
->remote_proto_id
= SCSI_PROTOCOL_FCP
;
175 off
= 3; /* Skip over "fc." */
178 ptr
= strstr(name
, "0x");
180 remote_hba
->remote_proto_id
= SCSI_PROTOCOL_SRP
;
181 off
= 2; /* Skip over "0x" */
184 ptr
= strstr(name
, "iqn.");
186 pr_err("Unable to locate prefix for emulated Target Port: %s\n",
191 remote_hba
->remote_proto_id
= SCSI_PROTOCOL_ISCSI
;
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
);
200 snprintf(&remote_hba
->remote_wwn_address
[0], TL_WWN_ADDR_LEN
, "%s", &name
[off
]);
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
;
210 static void tcm_remote_drop_wwn(struct se_wwn
*wwn
)
212 struct tcm_remote_hba
*remote_hba
= container_of(wwn
,
213 struct tcm_remote_hba
, remote_hba_wwn
);
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
);
221 static ssize_t
tcm_remote_wwn_version_show(struct config_item
*item
, char *page
)
223 return sprintf(page
, "TCM Remote Fabric module %s\n", TCM_REMOTE_VERSION
);
226 CONFIGFS_ATTR_RO(tcm_remote_wwn_
, version
);
228 static struct configfs_attribute
*tcm_remote_wwn_attrs
[] = {
229 &tcm_remote_wwn_attr_version
,
233 static 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
,
254 static int __init
tcm_remote_fabric_init(void)
256 return target_register_template(&remote_ops
);
259 static void __exit
tcm_remote_fabric_exit(void)
261 target_unregister_template(&remote_ops
);
264 MODULE_DESCRIPTION("TCM virtual remote target");
265 MODULE_AUTHOR("Dmitry Bogdanov <d.bogdanov@yadro.com>");
266 MODULE_LICENSE("GPL");
267 module_init(tcm_remote_fabric_init
);
268 module_exit(tcm_remote_fabric_exit
);