1 // SPDX-License-Identifier: GPL-2.0-or-later 2 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 20 static 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 25 static char *tcm_remote_get_endpoint_wwn(struct se_portal_group *se_tpg) 26 { 27 /* 28 * Return the passed NAA identifier for the Target Port 29 */ 30 return &remote_tpg(se_tpg)->remote_hba->remote_wwn_address[0]; 31 } 32 33 static 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 0x83 37 * to represent the SCSI Target Port. 38 */ 39 return remote_tpg(se_tpg)->remote_tpgt; 40 } 41 42 static int tcm_remote_dummy_cmd_fn(struct se_cmd *se_cmd) 43 { 44 return 0; 45 } 46 47 static void tcm_remote_dummy_cmd_void_fn(struct se_cmd *se_cmd) 48 { 49 50 } 51 52 static 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 70 static 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 79 static 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 87 static 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 Endpoint 114 */ 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 126 static 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 Endpoint 139 */ 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 150 static 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 Name 165 * 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 193 check_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; 205 out: 206 kfree(remote_hba); 207 return ERR_PTR(ret); 208 } 209 210 static 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 221 static 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 226 CONFIGFS_ATTR_RO(tcm_remote_wwn_, version); 227 228 static struct configfs_attribute *tcm_remote_wwn_attrs[] = { 229 &tcm_remote_wwn_attr_version, 230 NULL, 231 }; 232 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, 252 }; 253 254 static int __init tcm_remote_fabric_init(void) 255 { 256 return target_register_template(&remote_ops); 257 } 258 259 static void __exit tcm_remote_fabric_exit(void) 260 { 261 target_unregister_template(&remote_ops); 262 } 263 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); 269