0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <linux/kernel.h>
0020 #include <linux/string.h>
0021 #include <linux/ctype.h>
0022 #include <linux/spinlock.h>
0023 #include <linux/export.h>
0024 #include <asm/unaligned.h>
0025
0026 #include <scsi/scsi_proto.h>
0027
0028 #include <target/target_core_base.h>
0029 #include <target/target_core_fabric.h>
0030
0031 #include "target_core_internal.h"
0032 #include "target_core_pr.h"
0033
0034
0035 static int sas_get_pr_transport_id(
0036 struct se_node_acl *nacl,
0037 int *format_code,
0038 unsigned char *buf)
0039 {
0040 int ret;
0041
0042
0043 ret = hex2bin(&buf[4], &nacl->initiatorname[4], 8);
0044 if (ret) {
0045 pr_debug("%s: invalid hex string\n", __func__);
0046 return ret;
0047 }
0048
0049 return 24;
0050 }
0051
0052 static int fc_get_pr_transport_id(
0053 struct se_node_acl *se_nacl,
0054 int *format_code,
0055 unsigned char *buf)
0056 {
0057 unsigned char *ptr;
0058 int i, ret;
0059 u32 off = 8;
0060
0061
0062
0063
0064
0065 ptr = &se_nacl->initiatorname[0];
0066 for (i = 0; i < 23; ) {
0067 if (!strncmp(&ptr[i], ":", 1)) {
0068 i++;
0069 continue;
0070 }
0071 ret = hex2bin(&buf[off++], &ptr[i], 1);
0072 if (ret < 0) {
0073 pr_debug("%s: invalid hex string\n", __func__);
0074 return ret;
0075 }
0076 i += 2;
0077 }
0078
0079
0080
0081 return 24;
0082 }
0083
0084 static int sbp_get_pr_transport_id(
0085 struct se_node_acl *nacl,
0086 int *format_code,
0087 unsigned char *buf)
0088 {
0089 int ret;
0090
0091 ret = hex2bin(&buf[8], nacl->initiatorname, 8);
0092 if (ret) {
0093 pr_debug("%s: invalid hex string\n", __func__);
0094 return ret;
0095 }
0096
0097 return 24;
0098 }
0099
0100 static int srp_get_pr_transport_id(
0101 struct se_node_acl *nacl,
0102 int *format_code,
0103 unsigned char *buf)
0104 {
0105 const char *p;
0106 unsigned len, count, leading_zero_bytes;
0107 int rc;
0108
0109 p = nacl->initiatorname;
0110 if (strncasecmp(p, "0x", 2) == 0)
0111 p += 2;
0112 len = strlen(p);
0113 if (len % 2)
0114 return -EINVAL;
0115
0116 count = min(len / 2, 16U);
0117 leading_zero_bytes = 16 - count;
0118 memset(buf + 8, 0, leading_zero_bytes);
0119 rc = hex2bin(buf + 8 + leading_zero_bytes, p, count);
0120 if (rc < 0) {
0121 pr_debug("hex2bin failed for %s: %d\n", p, rc);
0122 return rc;
0123 }
0124
0125 return 24;
0126 }
0127
0128 static int iscsi_get_pr_transport_id(
0129 struct se_node_acl *se_nacl,
0130 struct t10_pr_registration *pr_reg,
0131 int *format_code,
0132 unsigned char *buf)
0133 {
0134 u32 off = 4, padding = 0;
0135 int isid_len;
0136 u16 len = 0;
0137
0138 spin_lock_irq(&se_nacl->nacl_sess_lock);
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154 len = sprintf(&buf[off], "%s", se_nacl->initiatorname);
0155 off += len;
0156 if ((*format_code == 1) && (pr_reg->isid_present_at_reg)) {
0157
0158
0159
0160
0161 buf[0] |= 0x40;
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183 buf[off++] = 0x2c;
0184 buf[off++] = 0x69;
0185 buf[off++] = 0x2c;
0186 buf[off++] = 0x30;
0187 buf[off++] = 0x78;
0188 len += 5;
0189
0190 isid_len = sprintf(buf + off, "%s", pr_reg->pr_reg_isid);
0191 off += isid_len;
0192 len += isid_len;
0193 }
0194 buf[off] = '\0';
0195 len += 1;
0196 spin_unlock_irq(&se_nacl->nacl_sess_lock);
0197
0198
0199
0200
0201
0202 padding = ((-len) & 3);
0203 if (padding != 0)
0204 len += padding;
0205
0206 put_unaligned_be16(len, &buf[2]);
0207
0208
0209
0210
0211 len += 4;
0212
0213 return len;
0214 }
0215
0216 static int iscsi_get_pr_transport_id_len(
0217 struct se_node_acl *se_nacl,
0218 struct t10_pr_registration *pr_reg,
0219 int *format_code)
0220 {
0221 u32 len = 0, padding = 0;
0222
0223 spin_lock_irq(&se_nacl->nacl_sess_lock);
0224 len = strlen(se_nacl->initiatorname);
0225
0226
0227
0228 len++;
0229
0230
0231
0232
0233
0234
0235
0236 if (pr_reg->isid_present_at_reg) {
0237 len += 5;
0238 len += strlen(pr_reg->pr_reg_isid);
0239 *format_code = 1;
0240 } else
0241 *format_code = 0;
0242 spin_unlock_irq(&se_nacl->nacl_sess_lock);
0243
0244
0245
0246
0247
0248 padding = ((-len) & 3);
0249 if (padding != 0)
0250 len += padding;
0251
0252
0253
0254
0255 len += 4;
0256
0257 return len;
0258 }
0259
0260 static char *iscsi_parse_pr_out_transport_id(
0261 struct se_portal_group *se_tpg,
0262 char *buf,
0263 u32 *out_tid_len,
0264 char **port_nexus_ptr)
0265 {
0266 char *p;
0267 int i;
0268 u8 format_code = (buf[0] & 0xc0);
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282 if ((format_code != 0x00) && (format_code != 0x40)) {
0283 pr_err("Illegal format code: 0x%02x for iSCSI"
0284 " Initiator Transport ID\n", format_code);
0285 return NULL;
0286 }
0287
0288
0289
0290
0291 if (out_tid_len) {
0292
0293 *out_tid_len = get_unaligned_be16(&buf[2]);
0294
0295 *out_tid_len += 4;
0296 }
0297
0298
0299
0300
0301
0302
0303 if (format_code == 0x40) {
0304 p = strstr(&buf[4], ",i,0x");
0305 if (!p) {
0306 pr_err("Unable to locate \",i,0x\" separator"
0307 " for Initiator port identifier: %s\n",
0308 &buf[4]);
0309 return NULL;
0310 }
0311 *p = '\0';
0312 p += 5;
0313
0314 *port_nexus_ptr = p;
0315
0316
0317
0318
0319
0320
0321 for (i = 0; i < 12; i++) {
0322
0323
0324
0325
0326
0327
0328
0329 if (*p == '\0')
0330 break;
0331
0332 if (isdigit(*p)) {
0333 p++;
0334 continue;
0335 }
0336 *p = tolower(*p);
0337 p++;
0338 }
0339 } else
0340 *port_nexus_ptr = NULL;
0341
0342 return &buf[4];
0343 }
0344
0345 int target_get_pr_transport_id_len(struct se_node_acl *nacl,
0346 struct t10_pr_registration *pr_reg, int *format_code)
0347 {
0348 switch (nacl->se_tpg->proto_id) {
0349 case SCSI_PROTOCOL_FCP:
0350 case SCSI_PROTOCOL_SBP:
0351 case SCSI_PROTOCOL_SRP:
0352 case SCSI_PROTOCOL_SAS:
0353 break;
0354 case SCSI_PROTOCOL_ISCSI:
0355 return iscsi_get_pr_transport_id_len(nacl, pr_reg, format_code);
0356 default:
0357 pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id);
0358 return -EINVAL;
0359 }
0360
0361
0362
0363
0364 *format_code = 0;
0365 return 24;
0366 }
0367
0368 int target_get_pr_transport_id(struct se_node_acl *nacl,
0369 struct t10_pr_registration *pr_reg, int *format_code,
0370 unsigned char *buf)
0371 {
0372 switch (nacl->se_tpg->proto_id) {
0373 case SCSI_PROTOCOL_SAS:
0374 return sas_get_pr_transport_id(nacl, format_code, buf);
0375 case SCSI_PROTOCOL_SBP:
0376 return sbp_get_pr_transport_id(nacl, format_code, buf);
0377 case SCSI_PROTOCOL_SRP:
0378 return srp_get_pr_transport_id(nacl, format_code, buf);
0379 case SCSI_PROTOCOL_FCP:
0380 return fc_get_pr_transport_id(nacl, format_code, buf);
0381 case SCSI_PROTOCOL_ISCSI:
0382 return iscsi_get_pr_transport_id(nacl, pr_reg, format_code,
0383 buf);
0384 default:
0385 pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id);
0386 return -EINVAL;
0387 }
0388 }
0389
0390 const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg,
0391 char *buf, u32 *out_tid_len, char **port_nexus_ptr)
0392 {
0393 u32 offset;
0394
0395 switch (tpg->proto_id) {
0396 case SCSI_PROTOCOL_SAS:
0397
0398
0399
0400
0401 offset = 4;
0402 break;
0403 case SCSI_PROTOCOL_SBP:
0404 case SCSI_PROTOCOL_SRP:
0405 case SCSI_PROTOCOL_FCP:
0406 offset = 8;
0407 break;
0408 case SCSI_PROTOCOL_ISCSI:
0409 return iscsi_parse_pr_out_transport_id(tpg, buf, out_tid_len,
0410 port_nexus_ptr);
0411 default:
0412 pr_err("Unknown proto_id: 0x%02x\n", tpg->proto_id);
0413 return NULL;
0414 }
0415
0416 *port_nexus_ptr = NULL;
0417 *out_tid_len = 24;
0418 return buf + offset;
0419 }