Blame view

drivers/target/target_core_fabric_lib.c 11.7 KB
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
1
2
3
4
5
6
  /*******************************************************************************
   * Filename:  target_core_fabric_lib.c
   *
   * This file contains generic high level protocol identifier and PR
   * handlers for TCM fabric modules
   *
4c76251e8   Nicholas Bellinger   target: Update co...
7
   * (c) Copyright 2010-2013 Datera, Inc.
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   *
   * Nicholas A. Bellinger <nab@linux-iscsi.org>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   *
   ******************************************************************************/
2650d71e2   Christoph Hellwig   target: move tran...
26
27
28
29
  /*
   * See SPC4, section 7.5 "Protocol specific parameters" for details
   * on the formats implemented in this file.
   */
11650b859   Andy Shevchenko   target: remove cu...
30
  #include <linux/kernel.h>
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
31
32
33
  #include <linux/string.h>
  #include <linux/ctype.h>
  #include <linux/spinlock.h>
c53181af8   Paul Gortmaker   drivers/target: A...
34
  #include <linux/export.h>
a85d667e5   Bart Van Assche   target: Use {get,...
35
  #include <asm/unaligned.h>
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
36

6546a02a5   Stephen Rothwell   target: explicitl...
37
  #include <scsi/scsi_proto.h>
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
38
  #include <target/target_core_base.h>
c4795fb20   Christoph Hellwig   target: header re...
39
  #include <target/target_core_fabric.h>
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
40

e26d99aed   Christoph Hellwig   target: reshuffle...
41
  #include "target_core_internal.h"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
42
  #include "target_core_pr.h"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
43

2650d71e2   Christoph Hellwig   target: move tran...
44
45
  static int sas_get_pr_transport_id(
  	struct se_node_acl *nacl,
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
46
47
48
  	int *format_code,
  	unsigned char *buf)
  {
8c35ad202   Mimi Zohar   target: check hex...
49
  	int ret;
11650b859   Andy Shevchenko   target: remove cu...
50

2650d71e2   Christoph Hellwig   target: move tran...
51
52
53
54
55
56
57
  	/* Skip over 'naa. prefix */
  	ret = hex2bin(&buf[4], &nacl->initiatorname[4], 8);
  	if (ret) {
  		pr_debug("%s: invalid hex string
  ", __func__);
  		return ret;
  	}
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
58

c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
59
60
  	return 24;
  }
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
61

2650d71e2   Christoph Hellwig   target: move tran...
62
  static int fc_get_pr_transport_id(
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
63
  	struct se_node_acl *se_nacl,
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
64
65
66
  	int *format_code,
  	unsigned char *buf)
  {
11650b859   Andy Shevchenko   target: remove cu...
67
  	unsigned char *ptr;
8c35ad202   Mimi Zohar   target: check hex...
68
  	int i, ret;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
69
  	u32 off = 8;
8c35ad202   Mimi Zohar   target: check hex...
70

c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
71
  	/*
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
72
73
74
75
  	 * We convert the ASCII formatted N Port name into a binary
  	 * encoded TransportID.
  	 */
  	ptr = &se_nacl->initiatorname[0];
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
76
  	for (i = 0; i < 24; ) {
6708bb27b   Andy Grover   target: Follow up...
77
  		if (!strncmp(&ptr[i], ":", 1)) {
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
78
79
80
  			i++;
  			continue;
  		}
8c35ad202   Mimi Zohar   target: check hex...
81
  		ret = hex2bin(&buf[off++], &ptr[i], 1);
2650d71e2   Christoph Hellwig   target: move tran...
82
83
84
85
86
  		if (ret < 0) {
  			pr_debug("%s: invalid hex string
  ", __func__);
  			return ret;
  		}
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
87
88
89
90
91
92
93
  		i += 2;
  	}
  	/*
  	 * The FC Transport ID is a hardcoded 24-byte length
  	 */
  	return 24;
  }
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
94

2650d71e2   Christoph Hellwig   target: move tran...
95
96
97
98
  static int sbp_get_pr_transport_id(
  	struct se_node_acl *nacl,
  	int *format_code,
  	unsigned char *buf)
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
99
  {
2650d71e2   Christoph Hellwig   target: move tran...
100
  	int ret;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
101

2650d71e2   Christoph Hellwig   target: move tran...
102
103
104
105
106
107
  	ret = hex2bin(&buf[8], nacl->initiatorname, 8);
  	if (ret) {
  		pr_debug("%s: invalid hex string
  ", __func__);
  		return ret;
  	}
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
108

2650d71e2   Christoph Hellwig   target: move tran...
109
  	return 24;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
110
  }
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
111

2650d71e2   Christoph Hellwig   target: move tran...
112
113
114
115
  static int srp_get_pr_transport_id(
  	struct se_node_acl *nacl,
  	int *format_code,
  	unsigned char *buf)
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
116
  {
2650d71e2   Christoph Hellwig   target: move tran...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  	const char *p;
  	unsigned len, count, leading_zero_bytes;
  	int rc;
  
  	p = nacl->initiatorname;
  	if (strncasecmp(p, "0x", 2) == 0)
  		p += 2;
  	len = strlen(p);
  	if (len % 2)
  		return -EINVAL;
  
  	count = min(len / 2, 16U);
  	leading_zero_bytes = 16 - count;
  	memset(buf + 8, 0, leading_zero_bytes);
  	rc = hex2bin(buf + 8 + leading_zero_bytes, p, count);
  	if (rc < 0) {
  		pr_debug("hex2bin failed for %s: %d
  ", __func__, rc);
  		return rc;
  	}
  
  	return 24;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
139
  }
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
140

2650d71e2   Christoph Hellwig   target: move tran...
141
  static int iscsi_get_pr_transport_id(
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
142
143
144
145
146
147
148
149
150
151
  	struct se_node_acl *se_nacl,
  	struct t10_pr_registration *pr_reg,
  	int *format_code,
  	unsigned char *buf)
  {
  	u32 off = 4, padding = 0;
  	u16 len = 0;
  
  	spin_lock_irq(&se_nacl->nacl_sess_lock);
  	/*
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  	 * From spc4r17 Section 7.5.4.6: TransportID for initiator
  	 * ports using SCSI over iSCSI.
  	 *
  	 * The null-terminated, null-padded (see 4.4.2) ISCSI NAME field
  	 * shall contain the iSCSI name of an iSCSI initiator node (see
  	 * RFC 3720). The first ISCSI NAME field byte containing an ASCII
  	 * null character terminates the ISCSI NAME field without regard for
  	 * the specified length of the iSCSI TransportID or the contents of
  	 * the ADDITIONAL LENGTH field.
  	 */
  	len = sprintf(&buf[off], "%s", se_nacl->initiatorname);
  	/*
  	 * Add Extra byte for NULL terminator
  	 */
  	len++;
  	/*
  	 * If there is ISID present with the registration and *format code == 1
  	 * 1, use iSCSI Initiator port TransportID format.
  	 *
  	 * Otherwise use iSCSI Initiator device TransportID format that
  	 * does not contain the ASCII encoded iSCSI Initiator iSID value
  	 * provied by the iSCSi Initiator during the iSCSI login process.
  	 */
  	if ((*format_code == 1) && (pr_reg->isid_present_at_reg)) {
  		/*
  		 * Set FORMAT CODE 01b for iSCSI Initiator port TransportID
  		 * format.
  		 */
  		buf[0] |= 0x40;
  		/*
  		 * From spc4r17 Section 7.5.4.6: TransportID for initiator
  		 * ports using SCSI over iSCSI.  Table 390
  		 *
  		 * The SEPARATOR field shall contain the five ASCII
  		 * characters ",i,0x".
  		 *
  		 * The null-terminated, null-padded ISCSI INITIATOR SESSION ID
  		 * field shall contain the iSCSI initiator session identifier
  		 * (see RFC 3720) in the form of ASCII characters that are the
  		 * hexadecimal digits converted from the binary iSCSI initiator
  		 * session identifier value. The first ISCSI INITIATOR SESSION
  		 * ID field byte containing an ASCII null character
  		 */
  		buf[off+len] = 0x2c; off++; /* ASCII Character: "," */
  		buf[off+len] = 0x69; off++; /* ASCII Character: "i" */
  		buf[off+len] = 0x2c; off++; /* ASCII Character: "," */
  		buf[off+len] = 0x30; off++; /* ASCII Character: "0" */
  		buf[off+len] = 0x78; off++; /* ASCII Character: "x" */
  		len += 5;
  		buf[off+len] = pr_reg->pr_reg_isid[0]; off++;
  		buf[off+len] = pr_reg->pr_reg_isid[1]; off++;
  		buf[off+len] = pr_reg->pr_reg_isid[2]; off++;
  		buf[off+len] = pr_reg->pr_reg_isid[3]; off++;
  		buf[off+len] = pr_reg->pr_reg_isid[4]; off++;
  		buf[off+len] = pr_reg->pr_reg_isid[5]; off++;
  		buf[off+len] = '\0'; off++;
  		len += 7;
  	}
  	spin_unlock_irq(&se_nacl->nacl_sess_lock);
  	/*
  	 * The ADDITIONAL LENGTH field specifies the number of bytes that follow
  	 * in the TransportID. The additional length shall be at least 20 and
  	 * shall be a multiple of four.
  	*/
  	padding = ((-len) & 3);
  	if (padding != 0)
  		len += padding;
a85d667e5   Bart Van Assche   target: Use {get,...
219
  	put_unaligned_be16(len, &buf[2]);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
220
221
222
223
224
225
226
227
  	/*
  	 * Increment value for total payload + header length for
  	 * full status descriptor
  	 */
  	len += 4;
  
  	return len;
  }
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
228

2650d71e2   Christoph Hellwig   target: move tran...
229
  static int iscsi_get_pr_transport_id_len(
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  	struct se_node_acl *se_nacl,
  	struct t10_pr_registration *pr_reg,
  	int *format_code)
  {
  	u32 len = 0, padding = 0;
  
  	spin_lock_irq(&se_nacl->nacl_sess_lock);
  	len = strlen(se_nacl->initiatorname);
  	/*
  	 * Add extra byte for NULL terminator
  	 */
  	len++;
  	/*
  	 * If there is ISID present with the registration, use format code:
  	 * 01b: iSCSI Initiator port TransportID format
  	 *
  	 * If there is not an active iSCSI session, use format code:
  	 * 00b: iSCSI Initiator device TransportID format
  	 */
  	if (pr_reg->isid_present_at_reg) {
35d1efe80   Masanari Iida   target: Fix minor...
250
  		len += 5; /* For ",i,0x" ASCII separator */
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  		len += 7; /* For iSCSI Initiator Session ID + Null terminator */
  		*format_code = 1;
  	} else
  		*format_code = 0;
  	spin_unlock_irq(&se_nacl->nacl_sess_lock);
  	/*
  	 * The ADDITIONAL LENGTH field specifies the number of bytes that follow
  	 * in the TransportID. The additional length shall be at least 20 and
  	 * shall be a multiple of four.
  	 */
  	padding = ((-len) & 3);
  	if (padding != 0)
  		len += padding;
  	/*
  	 * Increment value for total payload + header length for
  	 * full status descriptor
  	 */
  	len += 4;
  
  	return len;
  }
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
272

2650d71e2   Christoph Hellwig   target: move tran...
273
  static char *iscsi_parse_pr_out_transport_id(
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
274
  	struct se_portal_group *se_tpg,
094bb5d76   Rasmus Villemoes   target-core: don'...
275
  	char *buf,
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
  	u32 *out_tid_len,
  	char **port_nexus_ptr)
  {
  	char *p;
  	u32 tid_len, padding;
  	int i;
  	u16 add_len;
  	u8 format_code = (buf[0] & 0xc0);
  	/*
  	 * Check for FORMAT CODE 00b or 01b from spc4r17, section 7.5.4.6:
  	 *
  	 *       TransportID for initiator ports using SCSI over iSCSI,
  	 *       from Table 388 -- iSCSI TransportID formats.
  	 *
  	 *    00b     Initiator port is identified using the world wide unique
  	 *            SCSI device name of the iSCSI initiator
  	 *            device containing the initiator port (see table 389).
  	 *    01b     Initiator port is identified using the world wide unique
  	 *            initiator port identifier (see table 390).10b to 11b
  	 *            Reserved
  	 */
  	if ((format_code != 0x00) && (format_code != 0x40)) {
6708bb27b   Andy Grover   target: Follow up...
298
  		pr_err("Illegal format code: 0x%02x for iSCSI"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
299
300
301
302
303
304
305
306
  			" Initiator Transport ID
  ", format_code);
  		return NULL;
  	}
  	/*
  	 * If the caller wants the TransportID Length, we set that value for the
  	 * entire iSCSI Tarnsport ID now.
  	 */
68edbce4f   Joern Engel   target: fix pr_ou...
307
308
  	if (out_tid_len) {
  		/* The shift works thanks to integer promotion rules */
a85d667e5   Bart Van Assche   target: Use {get,...
309
  		add_len = get_unaligned_be16(&buf[2]);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
310

8359cf43b   Jörn Engel   target: remove us...
311
  		tid_len = strlen(&buf[4]);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
312
313
314
315
316
317
318
  		tid_len += 4; /* Add four bytes for iSCSI Transport ID header */
  		tid_len += 1; /* Add one byte for NULL terminator */
  		padding = ((-tid_len) & 3);
  		if (padding != 0)
  			tid_len += padding;
  
  		if ((add_len + 4) != tid_len) {
6708bb27b   Andy Grover   target: Follow up...
319
  			pr_debug("LIO-Target Extracted add_len: %hu "
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
320
321
322
323
324
325
326
327
  				"does not match calculated tid_len: %u,"
  				" using tid_len instead
  ", add_len+4, tid_len);
  			*out_tid_len = tid_len;
  		} else
  			*out_tid_len = (add_len + 4);
  	}
  	/*
35d1efe80   Masanari Iida   target: Fix minor...
328
  	 * Check for ',i,0x' separator between iSCSI Name and iSCSI Initiator
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
329
330
331
332
  	 * Session ID as defined in Table 390 - iSCSI initiator port TransportID
  	 * format.
  	 */
  	if (format_code == 0x40) {
8359cf43b   Jörn Engel   target: remove us...
333
  		p = strstr(&buf[4], ",i,0x");
6708bb27b   Andy Grover   target: Follow up...
334
  		if (!p) {
35d1efe80   Masanari Iida   target: Fix minor...
335
  			pr_err("Unable to locate \",i,0x\" separator"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
336
337
  				" for Initiator port identifier: %s
  ",
8359cf43b   Jörn Engel   target: remove us...
338
  				&buf[4]);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
339
340
341
  			return NULL;
  		}
  		*p = '\0'; /* Terminate iSCSI Name */
35d1efe80   Masanari Iida   target: Fix minor...
342
  		p += 5; /* Skip over ",i,0x" separator */
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
343
344
345
346
347
  
  		*port_nexus_ptr = p;
  		/*
  		 * Go ahead and do the lower case conversion of the received
  		 * 12 ASCII characters representing the ISID in the TransportID
25985edce   Lucas De Marchi   Fix common misspe...
348
  		 * for comparison against the running iSCSI session's ISID from
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
349
350
351
352
353
354
355
356
357
358
359
  		 * iscsi_target.c:lio_sess_get_initiator_sid()
  		 */
  		for (i = 0; i < 12; i++) {
  			if (isdigit(*p)) {
  				p++;
  				continue;
  			}
  			*p = tolower(*p);
  			p++;
  		}
  	}
094bb5d76   Rasmus Villemoes   target-core: don'...
360
  	return &buf[4];
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
361
  }
2650d71e2   Christoph Hellwig   target: move tran...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  
  int target_get_pr_transport_id_len(struct se_node_acl *nacl,
  		struct t10_pr_registration *pr_reg, int *format_code)
  {
  	switch (nacl->se_tpg->proto_id) {
  	case SCSI_PROTOCOL_FCP:
  	case SCSI_PROTOCOL_SBP:
  	case SCSI_PROTOCOL_SRP:
  	case SCSI_PROTOCOL_SAS:
  		break;
  	case SCSI_PROTOCOL_ISCSI:
  		return iscsi_get_pr_transport_id_len(nacl, pr_reg, format_code);
  	default:
  		pr_err("Unknown proto_id: 0x%02x
  ", nacl->se_tpg->proto_id);
  		return -EINVAL;
  	}
  
  	/*
  	 * Most transports use a fixed length 24 byte identifier.
  	 */
  	*format_code = 0;
  	return 24;
  }
  
  int target_get_pr_transport_id(struct se_node_acl *nacl,
  		struct t10_pr_registration *pr_reg, int *format_code,
  		unsigned char *buf)
  {
  	switch (nacl->se_tpg->proto_id) {
  	case SCSI_PROTOCOL_SAS:
  		return sas_get_pr_transport_id(nacl, format_code, buf);
  	case SCSI_PROTOCOL_SBP:
  		return sbp_get_pr_transport_id(nacl, format_code, buf);
  	case SCSI_PROTOCOL_SRP:
  		return srp_get_pr_transport_id(nacl, format_code, buf);
  	case SCSI_PROTOCOL_FCP:
  		return fc_get_pr_transport_id(nacl, format_code, buf);
  	case SCSI_PROTOCOL_ISCSI:
  		return iscsi_get_pr_transport_id(nacl, pr_reg, format_code,
  				buf);
  	default:
  		pr_err("Unknown proto_id: 0x%02x
  ", nacl->se_tpg->proto_id);
  		return -EINVAL;
  	}
  }
  
  const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg,
094bb5d76   Rasmus Villemoes   target-core: don'...
411
  		char *buf, u32 *out_tid_len, char **port_nexus_ptr)
2650d71e2   Christoph Hellwig   target: move tran...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  {
  	u32 offset;
  
  	switch (tpg->proto_id) {
  	case SCSI_PROTOCOL_SAS:
  		/*
  		 * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID
  		 * for initiator ports using SCSI over SAS Serial SCSI Protocol.
  		 */
  		offset = 4;
  		break;
  	case SCSI_PROTOCOL_SBP:
  	case SCSI_PROTOCOL_SRP:
  	case SCSI_PROTOCOL_FCP:
  		offset = 8;
  		break;
  	case SCSI_PROTOCOL_ISCSI:
  		return iscsi_parse_pr_out_transport_id(tpg, buf, out_tid_len,
  					port_nexus_ptr);
  	default:
  		pr_err("Unknown proto_id: 0x%02x
  ", tpg->proto_id);
  		return NULL;
  	}
  
  	*port_nexus_ptr = NULL;
  	*out_tid_len = 24;
  	return buf + offset;
  }