Browse Source

[infiniband] Add support for SRP over Infiniband

SRP is the SCSI RDMA Protocol.  It allows for a method of SAN booting
whereby the target is responsible for reading and writing data using
Remote DMA directly to the initiator's memory.  The software initiator
merely sends and receives SCSI commands; it never has to touch the
actual data.
tags/v0.9.8
Michael Brown 15 years ago
parent
commit
0c30dc6bc5

+ 63
- 0
src/arch/i386/interface/pcbios/ib_srpboot.c View File

@@ -0,0 +1,63 @@
1
+#include <stdint.h>
2
+#include <string.h>
3
+#include <stdlib.h>
4
+#include <stdio.h>
5
+#include <errno.h>
6
+#include <gpxe/sanboot.h>
7
+#include <int13.h>
8
+#include <gpxe/srp.h>
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+static int ib_srpboot ( const char *root_path ) {
13
+	struct scsi_device *scsi;
14
+	struct int13_drive *drive;
15
+	int rc;
16
+
17
+	scsi = zalloc ( sizeof ( *scsi ) );
18
+	if ( ! scsi ) {
19
+		rc = -ENOMEM;
20
+		goto err_alloc_scsi;
21
+	}
22
+	drive = zalloc ( sizeof ( *drive ) );
23
+	if ( ! drive ) {
24
+		rc = -ENOMEM;
25
+		goto err_alloc_drive;
26
+	}
27
+
28
+	if ( ( rc = srp_attach ( scsi, root_path ) ) != 0 ) {
29
+		printf ( "Could not attach IB_SRP device: %s\n",
30
+			 strerror ( rc ) );
31
+		goto err_attach;
32
+	}
33
+	if ( ( rc = init_scsidev ( scsi ) ) != 0 ) {
34
+		printf ( "Could not initialise IB_SRP device: %s\n",
35
+			 strerror ( rc ) );
36
+		goto err_init;
37
+	}
38
+
39
+	drive->blockdev = &scsi->blockdev;
40
+
41
+	register_int13_drive ( drive );
42
+	printf ( "Registered as BIOS drive %#02x\n", drive->drive );
43
+	printf ( "Booting from BIOS drive %#02x\n", drive->drive );
44
+	rc = int13_boot ( drive->drive );
45
+	printf ( "Boot failed\n" );
46
+
47
+	printf ( "Unregistering BIOS drive %#02x\n", drive->drive );
48
+	unregister_int13_drive ( drive );
49
+
50
+ err_init:
51
+	srp_detach ( scsi );
52
+ err_attach:
53
+	free ( drive );
54
+ err_alloc_drive:
55
+	free ( scsi );
56
+ err_alloc_scsi:
57
+	return rc;
58
+}
59
+
60
+struct sanboot_protocol ib_srp_sanboot_protocol __sanboot_protocol = {
61
+	.prefix = "ib_srp:",
62
+	.boot = ib_srpboot,
63
+};

+ 1
- 0
src/config/general.h View File

@@ -62,6 +62,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
62 62
 
63 63
 //#undef	SANBOOT_PROTO_ISCSI	/* iSCSI protocol */
64 64
 //#undef	SANBOOT_PROTO_AOE	/* AoE protocol */
65
+//#undef	SANBOOT_PROTO_IB_SRP	/* Infiniband SCSI RDMA protocol */
65 66
 
66 67
 /*
67 68
  * Name resolution modules

+ 3
- 0
src/core/config.c View File

@@ -109,6 +109,9 @@ REQUIRE_OBJECT ( iscsiboot );
109 109
 #ifdef SANBOOT_PROTO_AOE
110 110
 REQUIRE_OBJECT ( aoeboot );
111 111
 #endif
112
+#ifdef SANBOOT_PROTO_IB_SRP
113
+REQUIRE_OBJECT ( ib_srpboot );
114
+#endif
112 115
 
113 116
 /*
114 117
  * Drag in all requested resolvers

+ 530
- 0
src/drivers/block/srp.c View File

@@ -0,0 +1,530 @@
1
+/*
2
+ * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions
7
+ * are met:
8
+ *
9
+ *   Redistributions of source code must retain the above copyright
10
+ *   notice, this list of conditions and the following disclaimer.
11
+ *
12
+ *   Redistributions in binary form must reproduce the above copyright
13
+ *   notice, this list of conditions and the following disclaimer in
14
+ *   the documentation and/or other materials provided with the
15
+ *   distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+FILE_LICENCE ( BSD2 );
32
+
33
+#include <stdlib.h>
34
+#include <string.h>
35
+#include <errno.h>
36
+#include <gpxe/scsi.h>
37
+#include <gpxe/xfer.h>
38
+#include <gpxe/features.h>
39
+#include <gpxe/ib_srp.h>
40
+#include <gpxe/srp.h>
41
+
42
+/**
43
+ * @file
44
+ *
45
+ * SCSI RDMA Protocol
46
+ *
47
+ */
48
+
49
+FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
50
+
51
+/** Tag to be used for next SRP IU */
52
+static unsigned int srp_tag = 0;
53
+
54
+static void srp_login ( struct srp_device *srp );
55
+static void srp_cmd ( struct srp_device *srp );
56
+
57
+/**
58
+ * Mark SRP SCSI command as complete
59
+ *
60
+ * @v srp		SRP device
61
+ * @v rc		Status code
62
+ */
63
+static void srp_scsi_done ( struct srp_device *srp, int rc ) {
64
+	if ( srp->command )
65
+		srp->command->rc = rc;
66
+	srp->command = NULL;
67
+}
68
+
69
+/**
70
+ * Handle SRP session failure
71
+ *
72
+ * @v srp		SRP device
73
+ * @v rc 		Reason for failure
74
+ */
75
+static void srp_fail ( struct srp_device *srp, int rc ) {
76
+
77
+	/* Close underlying socket */
78
+	xfer_close ( &srp->socket, rc );
79
+
80
+	/* Clear session state */
81
+	srp->state = 0;
82
+
83
+	/* Increment retry count */
84
+	srp->retry_count++;
85
+
86
+	/* If we have reached the retry limit, permanently abort the
87
+	 * session.
88
+	 */
89
+	if ( srp->retry_count >= SRP_MAX_RETRIES ) {
90
+		srp->instant_rc = rc;
91
+		srp_scsi_done ( srp, rc );
92
+		return;
93
+	}
94
+
95
+	/* Otherwise, try to reopen the connection */
96
+	srp_login ( srp );
97
+}
98
+
99
+/**
100
+ * Initiate SRP login
101
+ *
102
+ * @v srp		SRP device
103
+ */
104
+static void srp_login ( struct srp_device *srp ) {
105
+	struct io_buffer *iobuf;
106
+	struct srp_login_req *login_req;
107
+	int rc;
108
+
109
+	assert ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) );
110
+
111
+	/* Open underlying socket */
112
+	if ( ( rc = srp->transport->connect ( srp ) ) != 0 ) {
113
+		DBGC ( srp, "SRP %p could not open socket: %s\n",
114
+		       srp, strerror ( rc ) );
115
+		goto err;
116
+	}
117
+	srp->state |= SRP_STATE_SOCKET_OPEN;
118
+
119
+	/* Allocate I/O buffer */
120
+	iobuf = xfer_alloc_iob ( &srp->socket, sizeof ( *login_req ) );
121
+	if ( ! iobuf ) {
122
+		rc = -ENOMEM;
123
+		goto err;
124
+	}
125
+
126
+	/* Construct login request IU */
127
+	login_req = iob_put ( iobuf, sizeof ( *login_req ) );
128
+	memset ( login_req, 0, sizeof ( *login_req ) );
129
+	login_req->type = SRP_LOGIN_REQ;
130
+	login_req->tag.dwords[1] = htonl ( ++srp_tag );
131
+	login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
132
+	login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
133
+	memcpy ( &login_req->port_ids, &srp->port_ids,
134
+		 sizeof ( login_req->port_ids ) );
135
+
136
+	DBGC2 ( srp, "SRP %p TX login request tag %08x%08x\n",
137
+		srp, ntohl ( login_req->tag.dwords[0] ),
138
+		ntohl ( login_req->tag.dwords[1] ) );
139
+	DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
140
+
141
+	/* Send login request IU */
142
+	if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
143
+		DBGC ( srp, "SRP %p could not send login request: %s\n",
144
+		       srp, strerror ( rc ) );
145
+		goto err;
146
+	}
147
+
148
+	return;
149
+
150
+ err:
151
+	srp_fail ( srp, rc );
152
+}
153
+
154
+/**
155
+ * Handle SRP login response
156
+ *
157
+ * @v srp		SRP device
158
+ * @v iobuf		I/O buffer
159
+ * @ret rc		Return status code
160
+ */
161
+static int srp_login_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
162
+	struct srp_login_rsp *login_rsp = iobuf->data;
163
+	int rc;
164
+
165
+	DBGC2 ( srp, "SRP %p RX login response tag %08x%08x\n",
166
+		srp, ntohl ( login_rsp->tag.dwords[0] ),
167
+		ntohl ( login_rsp->tag.dwords[1] ) );
168
+
169
+	/* Sanity check */
170
+	if ( iob_len ( iobuf ) < sizeof ( *login_rsp ) ) {
171
+		DBGC ( srp, "SRP %p RX login response too short (%zd bytes)\n",
172
+		       srp, iob_len ( iobuf ) );
173
+		rc = -EINVAL;
174
+		goto out;
175
+	}
176
+
177
+	DBGC ( srp, "SRP %p logged in\n", srp );
178
+
179
+	/* Mark as logged in */
180
+	srp->state |= SRP_STATE_LOGGED_IN;
181
+
182
+	/* Reset error counter */
183
+	srp->retry_count = 0;
184
+
185
+	/* Issue pending command */
186
+	srp_cmd ( srp );
187
+
188
+	rc = 0;
189
+ out:
190
+	free_iob ( iobuf );
191
+	return rc;
192
+}
193
+
194
+/**
195
+ * Handle SRP login rejection
196
+ *
197
+ * @v srp		SRP device
198
+ * @v iobuf		I/O buffer
199
+ * @ret rc		Return status code
200
+ */
201
+static int srp_login_rej ( struct srp_device *srp, struct io_buffer *iobuf ) {
202
+	struct srp_login_rej *login_rej = iobuf->data;
203
+	int rc;
204
+
205
+	DBGC2 ( srp, "SRP %p RX login rejection tag %08x%08x\n",
206
+		srp, ntohl ( login_rej->tag.dwords[0] ),
207
+		ntohl ( login_rej->tag.dwords[1] ) );
208
+
209
+	/* Sanity check */
210
+	if ( iob_len ( iobuf ) < sizeof ( *login_rej ) ) {
211
+		DBGC ( srp, "SRP %p RX login rejection too short (%zd "
212
+		       "bytes)\n", srp, iob_len ( iobuf ) );
213
+		rc = -EINVAL;
214
+		goto out;
215
+	}
216
+
217
+	/* Login rejection always indicates an error */
218
+	DBGC ( srp, "SRP %p login rejected (reason %08x)\n",
219
+	       srp, ntohl ( login_rej->reason ) );
220
+	rc = -EPERM;
221
+
222
+ out:
223
+	free_iob ( iobuf );
224
+	return rc;
225
+}
226
+
227
+/**
228
+ * Transmit SRP SCSI command
229
+ *
230
+ * @v srp		SRP device
231
+ */
232
+static void srp_cmd ( struct srp_device *srp ) {
233
+	struct io_buffer *iobuf;
234
+	struct srp_cmd *cmd;
235
+	struct srp_memory_descriptor *data_out;
236
+	struct srp_memory_descriptor *data_in;
237
+	int rc;
238
+
239
+	assert ( srp->state & SRP_STATE_LOGGED_IN );
240
+
241
+	/* Allocate I/O buffer */
242
+	iobuf = xfer_alloc_iob ( &srp->socket, SRP_MAX_I_T_IU_LEN );
243
+	if ( ! iobuf ) {
244
+		rc = -ENOMEM;
245
+		goto err;
246
+	}
247
+
248
+	/* Construct base portion */
249
+	cmd = iob_put ( iobuf, sizeof ( *cmd ) );
250
+	memset ( cmd, 0, sizeof ( *cmd ) );
251
+	cmd->type = SRP_CMD;
252
+	cmd->tag.dwords[1] = htonl ( ++srp_tag );
253
+	cmd->lun = srp->lun;
254
+	memcpy ( &cmd->cdb, &srp->command->cdb, sizeof ( cmd->cdb ) );
255
+
256
+	/* Construct data-out descriptor, if present */
257
+	if ( srp->command->data_out ) {
258
+		cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
259
+		data_out = iob_put ( iobuf, sizeof ( *data_out ) );
260
+		data_out->address =
261
+		    cpu_to_be64 ( user_to_phys ( srp->command->data_out, 0 ) );
262
+		data_out->handle = ntohl ( srp->memory_handle );
263
+		data_out->len = ntohl ( srp->command->data_out_len );
264
+	}
265
+
266
+	/* Construct data-in descriptor, if present */
267
+	if ( srp->command->data_in ) {
268
+		cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
269
+		data_in = iob_put ( iobuf, sizeof ( *data_in ) );
270
+		data_in->address =
271
+		     cpu_to_be64 ( user_to_phys ( srp->command->data_in, 0 ) );
272
+		data_in->handle = ntohl ( srp->memory_handle );
273
+		data_in->len = ntohl ( srp->command->data_in_len );
274
+	}
275
+
276
+	DBGC2 ( srp, "SRP %p TX SCSI command tag %08x%08x\n", srp,
277
+		ntohl ( cmd->tag.dwords[0] ), ntohl ( cmd->tag.dwords[1] ) );
278
+	DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
279
+
280
+	/* Send IU */
281
+	if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
282
+		DBGC ( srp, "SRP %p could not send command: %s\n",
283
+		       srp, strerror ( rc ) );
284
+		goto err;
285
+	}
286
+
287
+	return;
288
+
289
+ err:
290
+	srp_fail ( srp, rc );
291
+}
292
+
293
+/**
294
+ * Handle SRP SCSI response
295
+ *
296
+ * @v srp		SRP device
297
+ * @v iobuf		I/O buffer
298
+ * @ret rc		Returns status code
299
+ */
300
+static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
301
+	struct srp_rsp *rsp = iobuf->data;
302
+	int rc;
303
+
304
+	DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp,
305
+		ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) );
306
+
307
+	/* Sanity check */
308
+	if ( iob_len ( iobuf ) < sizeof ( *rsp ) ) {
309
+		DBGC ( srp, "SRP %p RX SCSI response too short (%zd bytes)\n",
310
+		       srp, iob_len ( iobuf ) );
311
+		rc = -EINVAL;
312
+		goto out;
313
+	}
314
+
315
+	/* Report SCSI errors */
316
+	if ( rsp->status != 0 ) {
317
+		DBGC ( srp, "SRP %p response status %02x\n",
318
+		       srp, rsp->status );
319
+		if ( srp_rsp_sense_data ( rsp ) ) {
320
+			DBGC ( srp, "SRP %p sense data:\n", srp );
321
+			DBGC_HDA ( srp, 0, srp_rsp_sense_data ( rsp ),
322
+				   srp_rsp_sense_data_len ( rsp ) );
323
+		}
324
+	}
325
+	if ( rsp->valid & ( SRP_RSP_VALID_DOUNDER | SRP_RSP_VALID_DOOVER ) ) {
326
+		DBGC ( srp, "SRP %p response data-out %srun by %#x bytes\n",
327
+		       srp, ( ( rsp->valid & SRP_RSP_VALID_DOUNDER )
328
+			      ? "under" : "over" ),
329
+		       ntohl ( rsp->data_out_residual_count ) );
330
+	}
331
+	if ( rsp->valid & ( SRP_RSP_VALID_DIUNDER | SRP_RSP_VALID_DIOVER ) ) {
332
+		DBGC ( srp, "SRP %p response data-in %srun by %#x bytes\n",
333
+		       srp, ( ( rsp->valid & SRP_RSP_VALID_DIUNDER )
334
+			      ? "under" : "over" ),
335
+		       ntohl ( rsp->data_in_residual_count ) );
336
+	}
337
+	srp->command->status = rsp->status;
338
+
339
+	/* Mark SCSI command as complete */
340
+	srp_scsi_done ( srp, 0 );
341
+
342
+	rc = 0;
343
+ out:
344
+	free_iob ( iobuf );
345
+	return rc;
346
+}
347
+
348
+/**
349
+ * Handle SRP unrecognised response
350
+ *
351
+ * @v srp		SRP device
352
+ * @v iobuf		I/O buffer
353
+ * @ret rc		Returns status code
354
+ */
355
+static int srp_unrecognised ( struct srp_device *srp,
356
+			      struct io_buffer *iobuf ) {
357
+	struct srp_common *common = iobuf->data;
358
+
359
+	DBGC ( srp, "SRP %p RX unrecognised IU tag %08x%08x type %02x\n",
360
+	       srp, ntohl ( common->tag.dwords[0] ),
361
+	       ntohl ( common->tag.dwords[1] ), common->type );
362
+
363
+	free_iob ( iobuf );
364
+	return -ENOTSUP;
365
+}
366
+
367
+/**
368
+ * Receive data from underlying socket
369
+ *
370
+ * @v xfer		Data transfer interface
371
+ * @v iobuf		Datagram I/O buffer
372
+ * @v meta		Data transfer metadata
373
+ * @ret rc		Return status code
374
+ */
375
+static int srp_xfer_deliver_iob ( struct xfer_interface *xfer,
376
+				  struct io_buffer *iobuf,
377
+				  struct xfer_metadata *meta __unused ) {
378
+	struct srp_device *srp =
379
+		container_of ( xfer, struct srp_device, socket );
380
+	struct srp_common *common = iobuf->data;
381
+	int ( * type ) ( struct srp_device *srp, struct io_buffer *iobuf );
382
+	int rc;
383
+
384
+	/* Determine IU type */
385
+	switch ( common->type ) {
386
+	case SRP_LOGIN_RSP:
387
+		type = srp_login_rsp;
388
+		break;
389
+	case SRP_LOGIN_REJ:
390
+		type = srp_login_rej;
391
+		break;
392
+	case SRP_RSP:
393
+		type = srp_rsp;
394
+		break;
395
+	default:
396
+		type = srp_unrecognised;
397
+		break;
398
+	}
399
+
400
+	/* Handle IU */
401
+	if ( ( rc = type ( srp, iobuf ) ) != 0 )
402
+		goto err;
403
+
404
+	return 0;
405
+
406
+ err:
407
+	srp_fail ( srp, rc );
408
+	return rc;
409
+}
410
+
411
+/**
412
+ * Underlying socket closed
413
+ *
414
+ * @v xfer		Data transfer interface
415
+ * @v rc		Reason for close
416
+ */
417
+static void srp_xfer_close ( struct xfer_interface *xfer, int rc ) {
418
+	struct srp_device *srp =
419
+		container_of ( xfer, struct srp_device, socket );
420
+
421
+	DBGC ( srp, "SRP %p socket closed: %s\n", srp, strerror ( rc ) );
422
+
423
+	srp_fail ( srp, rc );
424
+}
425
+
426
+/** SRP data transfer interface operations */
427
+static struct xfer_interface_operations srp_xfer_operations = {
428
+	.close		= srp_xfer_close,
429
+	.vredirect	= ignore_xfer_vredirect,
430
+	.window		= unlimited_xfer_window,
431
+	.alloc_iob	= default_xfer_alloc_iob,
432
+	.deliver_iob	= srp_xfer_deliver_iob,
433
+	.deliver_raw	= xfer_deliver_as_iob,
434
+};
435
+
436
+/**
437
+ * Issue SCSI command via SRP
438
+ *
439
+ * @v scsi		SCSI device
440
+ * @v command		SCSI command
441
+ * @ret rc		Return status code
442
+ */
443
+static int srp_command ( struct scsi_device *scsi,
444
+			 struct scsi_command *command ) {
445
+	struct srp_device *srp =
446
+		container_of ( scsi->backend, struct srp_device, refcnt );
447
+
448
+	/* Return instant failure, if we have already aborted the session */
449
+	if ( srp->instant_rc )
450
+		return srp->instant_rc;
451
+
452
+	/* Store SCSI command */
453
+	if ( srp->command ) {
454
+		DBGC ( srp, "SRP %p cannot handle concurrent SCSI commands\n",
455
+		       srp );
456
+		return -EBUSY;
457
+	}
458
+	srp->command = command;
459
+
460
+	/* Log in or issue command as appropriate */
461
+	if ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) ) {
462
+		srp_login ( srp );
463
+	} else if ( srp->state & SRP_STATE_LOGGED_IN ) {
464
+		srp_cmd ( srp );
465
+	} else {
466
+		/* Still waiting for login; do nothing */
467
+	}
468
+
469
+	return 0;
470
+}
471
+
472
+/**
473
+ * Attach SRP device
474
+ *
475
+ * @v scsi		SCSI device
476
+ * @v root_path		Root path
477
+ */
478
+int srp_attach ( struct scsi_device *scsi, const char *root_path ) {
479
+	struct srp_transport_type *transport;
480
+	struct srp_device *srp;
481
+	int rc;
482
+
483
+	/* Hard-code an IB SRP back-end for now */
484
+	transport = &ib_srp_transport;
485
+
486
+	/* Allocate and initialise structure */
487
+	srp = zalloc ( sizeof ( *srp ) + transport->priv_len );
488
+	if ( ! srp ) {
489
+		rc = -ENOMEM;
490
+		goto err_alloc;
491
+	}
492
+	xfer_init ( &srp->socket, &srp_xfer_operations, &srp->refcnt );
493
+	srp->transport = transport;
494
+	DBGC ( srp, "SRP %p using %s\n", srp, root_path );
495
+
496
+	/* Parse root path */
497
+	if ( ( rc = transport->parse_root_path ( srp, root_path ) ) != 0 ) {
498
+		DBGC ( srp, "SRP %p could not parse root path: %s\n",
499
+		       srp, strerror ( rc ) );
500
+		goto err_parse_root_path;
501
+	}
502
+
503
+	/* Attach parent interface, mortalise self, and return */
504
+	scsi->backend = ref_get ( &srp->refcnt );
505
+	scsi->command = srp_command;
506
+	ref_put ( &srp->refcnt );
507
+	return 0;
508
+
509
+ err_parse_root_path:
510
+	ref_put ( &srp->refcnt );
511
+ err_alloc:
512
+	return rc;
513
+}
514
+
515
+/**
516
+ * Detach SRP device
517
+ *
518
+ * @v scsi		SCSI device
519
+ */
520
+void srp_detach ( struct scsi_device *scsi ) {
521
+	struct srp_device *srp =
522
+		container_of ( scsi->backend, struct srp_device, refcnt );
523
+
524
+	/* Close socket */
525
+	xfer_nullify ( &srp->socket );
526
+	xfer_close ( &srp->socket, 0 );
527
+	scsi->command = scsi_detached_command;
528
+	ref_put ( scsi->backend );
529
+	scsi->backend = NULL;
530
+}

+ 3
- 0
src/include/gpxe/errfile.h View File

@@ -119,6 +119,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
119 119
 #define ERRFILE_hermon		     ( ERRFILE_DRIVER | 0x00720000 )
120 120
 #define ERRFILE_linda		     ( ERRFILE_DRIVER | 0x00730000 )
121 121
 #define ERRFILE_ata		     ( ERRFILE_DRIVER | 0x00740000 )
122
+#define ERRFILE_srp		     ( ERRFILE_DRIVER | 0x00750000 )
122 123
 
123 124
 #define ERRFILE_aoe			( ERRFILE_NET | 0x00000000 )
124 125
 #define ERRFILE_arp			( ERRFILE_NET | 0x00010000 )
@@ -154,6 +155,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
154 155
 #define ERRFILE_net80211		( ERRFILE_NET | 0x001f0000 )
155 156
 #define ERRFILE_ib_mi			( ERRFILE_NET | 0x00200000 )
156 157
 #define ERRFILE_ib_cmrc			( ERRFILE_NET | 0x00210000 )
158
+#define ERRFILE_ib_srp			( ERRFILE_NET | 0x00220000 )
157 159
 
158 160
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
159 161
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )
@@ -186,6 +188,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
186 188
 #define ERRFILE_pxemenu		      ( ERRFILE_OTHER | 0x00150000 )
187 189
 #define ERRFILE_x509		      ( ERRFILE_OTHER | 0x00160000 )
188 190
 #define ERRFILE_login_ui	      ( ERRFILE_OTHER | 0x00170000 )
191
+#define ERRFILE_ib_srpboot	      ( ERRFILE_OTHER | 0x00180000 )
189 192
 
190 193
 /** @} */
191 194
 

+ 1
- 0
src/include/gpxe/features.h View File

@@ -44,6 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
44 44
 #define DHCP_EB_FEATURE_BZIMAGE		0x18 /**< bzImage format */
45 45
 #define DHCP_EB_FEATURE_MULTIBOOT	0x19 /**< Multiboot format */
46 46
 #define DHCP_EB_FEATURE_SLAM		0x1a /**< SLAM protocol */
47
+#define DHCP_EB_FEATURE_SRP		0x1b /**< SRP protocol */
47 48
 #define DHCP_EB_FEATURE_NBI		0x20 /**< NBI format */
48 49
 #define DHCP_EB_FEATURE_PXE		0x21 /**< PXE format */
49 50
 #define DHCP_EB_FEATURE_ELF		0x22 /**< ELF format */

+ 79
- 0
src/include/gpxe/ib_srp.h View File

@@ -0,0 +1,79 @@
1
+#ifndef _GPXE_IB_SRP_H
2
+#define _GPXE_IB_SRP_H
3
+
4
+/** @file
5
+ *
6
+ * SCSI RDMA Protocol over Infiniband
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( BSD2 );
11
+
12
+#include <stdint.h>
13
+#include <gpxe/infiniband.h>
14
+#include <gpxe/srp.h>
15
+
16
+/** SRP initiator port identifier for Infiniband */
17
+struct ib_srp_initiator_port_id {
18
+	/** Identifier extension */
19
+	struct ib_gid_half id_ext;
20
+	/** IB channel adapter GUID */
21
+	struct ib_gid_half hca_guid;
22
+} __attribute__ (( packed ));
23
+
24
+/** SRP target port identifier for Infiniband */
25
+struct ib_srp_target_port_id {
26
+	/** Identifier extension */
27
+	struct ib_gid_half id_ext;
28
+	/** I/O controller GUID */
29
+	struct ib_gid_half ioc_guid;
30
+} __attribute__ (( packed ));
31
+
32
+/**
33
+ * Get Infiniband-specific initiator port ID
34
+ *
35
+ * @v port_ids		SRP port IDs
36
+ * @ret initiator_port_id  Infiniband-specific initiator port ID
37
+ */
38
+static inline __always_inline struct ib_srp_initiator_port_id *
39
+ib_srp_initiator_port_id ( struct srp_port_ids *port_ids ) {
40
+	return ( ( struct ib_srp_initiator_port_id * ) &port_ids->initiator );
41
+}
42
+
43
+/**
44
+ * Get Infiniband-specific target port ID
45
+ *
46
+ * @v port_ids		SRP port IDs
47
+ * @ret target_port_id	Infiniband-specific target port ID
48
+ */
49
+static inline __always_inline struct ib_srp_target_port_id *
50
+ib_srp_target_port_id ( struct srp_port_ids *port_ids ) {
51
+	return ( ( struct ib_srp_target_port_id * ) &port_ids->target );
52
+}
53
+
54
+/** Infiniband-specific SRP parameters */
55
+struct ib_srp_parameters {
56
+	/** Source GID */
57
+	struct ib_gid sgid;
58
+	/** Destination GID */
59
+	struct ib_gid dgid;
60
+	/** Service ID */
61
+	struct ib_gid_half service_id;
62
+	/** Partition key */
63
+	uint16_t pkey;
64
+};
65
+
66
+/**
67
+ * Get Infiniband-specific transport parameters
68
+ *
69
+ * @v srp		SRP device
70
+ * @ret ib_params	Infiniband-specific transport parameters
71
+ */
72
+static inline __always_inline struct ib_srp_parameters *
73
+ib_srp_params ( struct srp_device *srp ) {
74
+	return srp_transport_priv ( srp );
75
+}
76
+
77
+extern struct srp_transport_type ib_srp_transport;
78
+
79
+#endif /* _GPXE_IB_SRP_H */

+ 874
- 0
src/include/gpxe/srp.h View File

@@ -0,0 +1,874 @@
1
+#ifndef _GPXE_SRP_H
2
+#define _GPXE_SRP_H
3
+
4
+/** @file
5
+ *
6
+ * SCSI RDMA Protocol
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( BSD2 );
11
+
12
+#include <stdint.h>
13
+#include <byteswap.h>
14
+#include <gpxe/iobuf.h>
15
+#include <gpxe/xfer.h>
16
+#include <gpxe/scsi.h>
17
+
18
+/*****************************************************************************
19
+ *
20
+ * Common fields
21
+ *
22
+ *****************************************************************************
23
+ */
24
+
25
+/** An SRP information unit tag */
26
+struct srp_tag {
27
+	uint32_t dwords[2];
28
+} __attribute__ (( packed ));
29
+
30
+/** An SRP port ID */
31
+struct srp_port_id {
32
+	uint8_t bytes[16];
33
+} __attribute__ (( packed ));
34
+
35
+/** An SRP port ID pair */
36
+struct srp_port_ids {
37
+	/** Initiator port ID */
38
+	struct srp_port_id initiator;
39
+	/** Target port ID */
40
+	struct srp_port_id target;
41
+} __attribute__ (( packed ));
42
+
43
+/** SRP information unit common fields */
44
+struct srp_common {
45
+	/** Information unit type */
46
+	uint8_t type;
47
+	/** Reserved */
48
+	uint8_t reserved0[7];
49
+	/** Tag */
50
+	struct srp_tag tag;
51
+} __attribute__ (( packed ));
52
+
53
+/*****************************************************************************
54
+ *
55
+ * Login request
56
+ *
57
+ *****************************************************************************
58
+ */
59
+
60
+/** An SRP login request information unit */
61
+struct srp_login_req {
62
+	/** Information unit type
63
+	 *
64
+	 * This must be @c SRP_LOGIN_REQ
65
+	 */
66
+	uint8_t type;
67
+	/** Reserved */
68
+	uint8_t reserved0[7];
69
+	/** Tag */
70
+	struct srp_tag tag;
71
+	/** Requested maximum initiator to target IU length */
72
+	uint32_t max_i_t_iu_len;
73
+	/** Reserved */
74
+	uint8_t reserved1[4];
75
+	/** Required buffer formats
76
+	 *
77
+	 * This is the bitwise OR of one or more @c
78
+	 * SRP_LOGIN_REQ_FMT_XXX constants.
79
+	 */
80
+	uint16_t required_buffer_formats;
81
+	/** Flags
82
+	 *
83
+	 * This is the bitwise OR of zero or more @c
84
+	 * SRP_LOGIN_REQ_FLAG_XXX and @c SRP_LOGIN_REQ_MCA_XXX
85
+	 * constants.
86
+	 */
87
+	uint8_t flags;
88
+	/** Reserved */
89
+	uint8_t reserved2[5];
90
+	/** Initiator and target port identifiers */
91
+	struct srp_port_ids port_ids;
92
+} __attribute__ (( packed ));
93
+
94
+/** Type of an SRP login request */
95
+#define SRP_LOGIN_REQ 0x00
96
+
97
+/** Require indirect data buffer descriptor format */
98
+#define SRP_LOGIN_REQ_FMT_IDBD 0x04
99
+
100
+/** Require direct data buffer descriptor format */
101
+#define SRP_LOGIN_REQ_FMT_DDBD 0x02
102
+
103
+/** Use solicited notification for asynchronous events */
104
+#define SRP_LOGIN_REQ_FLAG_AESOLNT 0x40
105
+
106
+/** Use solicited notification for credit request */
107
+#define SRP_LOGIN_REQ_FLAG_CRSOLNT 0x20
108
+
109
+/** Use solicited notification for logouts */
110
+#define SRP_LOGIN_REQ_FLAG_LOSOLNT 0x10
111
+
112
+/** Multi-channel action mask */
113
+#define SRP_LOGIN_REQ_MCA_MASK 0x03
114
+
115
+/** Single RDMA channel operation */
116
+#define SRP_LOGIN_REQ_MCA_SINGLE_CHANNEL 0x00
117
+
118
+/** Multiple independent RDMA channel operation */
119
+#define SRP_LOGIN_REQ_MCA_MULTIPLE_CHANNELS 0x01
120
+
121
+/*****************************************************************************
122
+ *
123
+ * Login response
124
+ *
125
+ *****************************************************************************
126
+ */
127
+
128
+/** An SRP login response */
129
+struct srp_login_rsp {
130
+	/** Information unit type
131
+	 *
132
+	 * This must be @c SRP_LOGIN_RSP
133
+	 */
134
+	uint8_t type;
135
+	/** Reserved */
136
+	uint8_t reserved0[3];
137
+	/** Request limit delta */
138
+	uint32_t request_limit_delta;
139
+	/** Tag */
140
+	struct srp_tag tag;
141
+	/** Maximum initiator to target IU length */
142
+	uint32_t max_i_t_iu_len;
143
+	/** Maximum target to initiator IU length */
144
+	uint32_t max_t_i_iu_len;
145
+	/** Supported buffer formats
146
+	 *
147
+	 * This is the bitwise OR of one or more @c
148
+	 * SRP_LOGIN_RSP_FMT_XXX constants.
149
+	 */
150
+	uint16_t supported_buffer_formats;
151
+	/** Flags
152
+	 *
153
+	 * This is the bitwise OR of zero or more @c
154
+	 * SRP_LOGIN_RSP_FLAG_XXX and @c SRP_LOGIN_RSP_MCR_XXX
155
+	 * constants.
156
+	 */
157
+	uint8_t flags;
158
+	/** Reserved */
159
+	uint8_t reserved1[25];
160
+} __attribute__ (( packed ));
161
+
162
+/** Type of an SRP login response */
163
+#define SRP_LOGIN_RSP 0xc0
164
+
165
+/** Indirect data buffer descriptor format supported */
166
+#define SRP_LOGIN_RSP_FMT_IDBD 0x04
167
+
168
+/** Direct data buffer descriptor format supported */
169
+#define SRP_LOGIN_RSP_FMT_DDBD 0x02
170
+
171
+/** Solicited notification is supported */
172
+#define SRP_LOGIN_RSP_FLAG_SOLNTSUP 0x10
173
+
174
+/** Multi-channel result mask */
175
+#define SRP_LOGIN_RSP_MCR_MASK 0x03
176
+
177
+/** No existing RDMA channels were associated with the same I_T nexus */
178
+#define SRP_LOGIN_RSP_MCR_NO_EXISTING_CHANNELS 0x00
179
+
180
+/** One or more existing RDMA channels were terminated */
181
+#define SRP_LOGIN_RSP_MCR_EXISTING_CHANNELS_TERMINATED 0x01
182
+
183
+/** One or more existing RDMA channels continue to operate independently */
184
+#define SRP_LOGIN_RSP_MCR_EXISTING_CHANNELS_CONTINUE 0x02
185
+
186
+/*****************************************************************************
187
+ *
188
+ * Login rejection
189
+ *
190
+ *****************************************************************************
191
+ */
192
+
193
+/** An SRP login rejection */
194
+struct srp_login_rej {
195
+	/** Information unit type
196
+	 *
197
+	 * This must be @c SRP_LOGIN_REJ
198
+	 */
199
+	uint8_t type;
200
+	/** Reserved */
201
+	uint8_t reserved0[3];
202
+	/** Reason
203
+	 *
204
+	 * This is a @c SRP_LOGIN_REJ_REASON_XXX constant.
205
+	 */
206
+	uint32_t reason;
207
+	/** Tag */
208
+	struct srp_tag tag;
209
+	/** Reserved */
210
+	uint8_t reserved1[8];
211
+	/** Supported buffer formats
212
+	 *
213
+	 * This is the bitwise OR of one or more @c
214
+	 * SRP_LOGIN_REJ_FMT_XXX constants.
215
+	 */
216
+	uint16_t supported_buffer_formats;
217
+	/** Reserved */
218
+	uint8_t reserved2[6];
219
+} __attribute__ (( packed ));
220
+
221
+/** Type of an SRP login rejection */
222
+#define SRP_LOGIN_REJ 0xc2
223
+
224
+/** Unable to establish RDMA channel, no reason specified */
225
+#define SRP_LOGIN_REJ_REASON_UNKNOWN 0x00010000UL
226
+
227
+/** Insufficient RDMA channel resources */
228
+#define SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES 0x00010001UL
229
+
230
+/** Requested maximum initiator to target IU length value too large */
231
+#define SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN 0x00010002UL
232
+
233
+/** Unable to associate RDMA channel with specified I_T nexus */
234
+#define SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE 0x00010003UL
235
+
236
+/** One or more requested data buffer descriptor formats are not supported */
237
+#define SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT 0x00010004UL
238
+
239
+/** SRP target port does not support multiple RDMA channels per I_T nexus */
240
+#define SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS 0x00010005UL
241
+
242
+/** RDMA channel limit reached for this initiator */
243
+#define SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS 0x00010006UL
244
+
245
+/** Indirect data buffer descriptor format supported */
246
+#define SRP_LOGIN_REJ_FMT_IDBD 0x04
247
+
248
+/** Direct data buffer descriptor format supported */
249
+#define SRP_LOGIN_REJ_FMT_DDBD 0x02
250
+
251
+/*****************************************************************************
252
+ *
253
+ * Initiator logout
254
+ *
255
+ *****************************************************************************
256
+ */
257
+
258
+/** An SRP initiator logout request */
259
+struct srp_i_logout {
260
+	/** Information unit type
261
+	 *
262
+	 * This must be @c SRP_I_LOGOUT
263
+	 */
264
+	uint8_t type;
265
+	/** Reserved */
266
+	uint8_t reserved0[7];
267
+	/** Tag */
268
+	struct srp_tag tag;
269
+} __attribute__ (( packed ));
270
+
271
+/** Type of an SRP initiator logout request */
272
+#define SRP_I_LOGOUT 0x03
273
+
274
+/*****************************************************************************
275
+ *
276
+ * Target logout
277
+ *
278
+ *****************************************************************************
279
+ */
280
+
281
+/** An SRP target logout request */
282
+struct srp_t_logout {
283
+	/** Information unit type
284
+	 *
285
+	 * This must be @c SRP_T_LOGOUT
286
+	 */
287
+	uint8_t type;
288
+	/** Flags
289
+	 *
290
+	 * This is the bitwise OR of zero or more @c
291
+	 * SRP_T_LOGOUT_FLAG_XXX constants.
292
+	 */
293
+	uint8_t flags;
294
+	/** Reserved */
295
+	uint8_t reserved0[2];
296
+	/** Reason
297
+	 *
298
+	 * This is a @c SRP_T_LOGOUT_REASON_XXX constant.
299
+	 */
300
+	uint32_t reason;
301
+	/** Tag */
302
+	struct srp_tag tag;
303
+} __attribute__ (( packed ));
304
+
305
+/** Type of an SRP target logout request */
306
+#define SRP_T_LOGOUT 0x80
307
+
308
+/** The initiator specified solicited notification of logouts */
309
+#define SRP_T_LOGOUT_FLAG_SOLNT 0x01
310
+
311
+/** No reason specified */
312
+#define SRP_T_LOGOUT_REASON_UNKNOWN 0x00000000UL
313
+
314
+/** Inactive RDMA channel (reclaiming resources) */
315
+#define SRP_T_LOGOUT_REASON_INACTIVE 0x00000001UL
316
+
317
+/** Invalid information unit type code received by SRP target port */
318
+#define SRP_T_LOGOUT_REASON_INVALID_TYPE 0x00000002UL
319
+
320
+/** SRP initiator port sent response with no corresponding request */
321
+#define SRP_T_LOGOUT_REASON_SPURIOUS_RESPONSE 0x00000003UL
322
+
323
+/** RDMA channel disconnected due to multi-channel action code in new login */
324
+#define SRP_T_LOGOUT_REASON_MCA 0x00000004UL
325
+
326
+/** Unsuppported format code value specified in data-out buffer descriptor */
327
+#define SRP_T_LOGOUT_UNSUPPORTED_DATA_OUT_FORMAT 0x00000005UL
328
+
329
+/** Unsuppported format code value specified in data-in buffer descriptor */
330
+#define SRP_T_LOGOUT_UNSUPPORTED_DATA_IN_FORMAT 0x00000006UL
331
+
332
+/** Invalid length for IU type */
333
+#define SRP_T_LOGOUT_INVALID_IU_LEN 0x00000008UL
334
+
335
+/*****************************************************************************
336
+ *
337
+ * Task management
338
+ *
339
+ *****************************************************************************
340
+ */
341
+
342
+/** An SRP task management request */
343
+struct srp_tsk_mgmt {
344
+	/** Information unit type
345
+	 *
346
+	 * This must be @c SRP_TSK_MGMT
347
+	 */
348
+	uint8_t type;
349
+	/** Flags
350
+	 *
351
+	 * This is the bitwise OR of zero or more
352
+	 * @c SRP_TSK_MGMT_FLAG_XXX constants.
353
+	 */
354
+	uint8_t flags;
355
+	/** Reserved */
356
+	uint8_t reserved0[6];
357
+	/** Tag */
358
+	struct srp_tag tag;
359
+	/** Reserved */
360
+	uint8_t reserved1[4];
361
+	/** Logical unit number */
362
+	struct scsi_lun lun;
363
+	/** Reserved */
364
+	uint8_t reserved2[2];
365
+	/** Task management function
366
+	 *
367
+	 * This is a @c SRP_TASK_MGMT_FUNC_XXX constant
368
+	 */
369
+	uint8_t function;
370
+	/** Reserved */
371
+	uint8_t reserved3[1];
372
+	/** Tag of task to be managed */
373
+	struct srp_tag managed_tag;
374
+	/** Reserved */
375
+	uint8_t reserved4[8];
376
+} __attribute__ (( packed ));
377
+
378
+/** Type of an SRP task management request */
379
+#define SRP_TSK_MGMT 0x01
380
+
381
+/** Use solicited notification for unsuccessful completions */
382
+#define SRP_TSK_MGMT_FLAG_UCSOLNT 0x04
383
+
384
+/** Use solicited notification for successful completions */
385
+#define SRP_TSK_MGMT_FLAG_SCSOLNT 0x02
386
+
387
+/** The task manager shall perform an ABORT TASK function */
388
+#define SRP_TSK_MGMT_FUNC_ABORT_TASK 0x01
389
+
390
+/** The task manager shall perform an ABORT TASK SET function */
391
+#define SRP_TSK_MGMT_FUNC_ABORT_TASK_SET 0x02
392
+
393
+/** The task manager shall perform a CLEAR TASK SET function */
394
+#define SRP_TSK_MGMT_FUNC_CLEAR_TASK_SET 0x04
395
+
396
+/** The task manager shall perform a LOGICAL UNIT RESET function */
397
+#define SRP_TSK_MGMT_FUNC_LOGICAL_UNIT_RESET 0x08
398
+
399
+/** The task manager shall perform a CLEAR ACA function */
400
+#define SRP_TSK_MGMT_FUNC_CLEAR_ACA 0x40
401
+
402
+/*****************************************************************************
403
+ *
404
+ * SCSI command
405
+ *
406
+ *****************************************************************************
407
+ */
408
+
409
+/** An SRP SCSI command */
410
+struct srp_cmd {
411
+	/** Information unit type
412
+	 *
413
+	 * This must be @c SRP_CMD
414
+	 */
415
+	uint8_t type;
416
+	/** Flags
417
+	 *
418
+	 * This is the bitwise OR of zero or more @c SRP_CMD_FLAG_XXX
419
+	 * constants.
420
+	 */
421
+	uint8_t flags;
422
+	/** Reserved */
423
+	uint8_t reserved0[3];
424
+	/** Data buffer descriptor formats
425
+	 *
426
+	 * This is the bitwise OR of one @c SRP_CMD_DO_FMT_XXX and one @c
427
+	 * SRP_CMD_DI_FMT_XXX constant.
428
+	 */
429
+	uint8_t data_buffer_formats;
430
+	/** Data-out buffer descriptor count */
431
+	uint8_t data_out_buffer_count;
432
+	/** Data-in buffer descriptor count */
433
+	uint8_t data_in_buffer_count;
434
+	/** Tag */
435
+	struct srp_tag tag;
436
+	/** Reserved */
437
+	uint8_t reserved1[4];
438
+	/** Logical unit number */
439
+	struct scsi_lun lun;
440
+	/** Reserved */
441
+	uint8_t reserved2[1];
442
+	/** Task attribute
443
+	 *
444
+	 * This is a @c SRP_CMD_TASK_ATTR_XXX constant.
445
+	 */
446
+	uint8_t task_attr;
447
+	/** Reserved */
448
+	uint8_t reserved3[1];
449
+	/** Additional CDB length */
450
+	uint8_t additional_cdb_len;
451
+	/** Command data block */
452
+	union scsi_cdb cdb;
453
+} __attribute__ (( packed ));
454
+
455
+/** Type of an SRP SCSI command */
456
+#define SRP_CMD 0x02
457
+
458
+/** Use solicited notification for unsuccessful completions */
459
+#define SRP_CMD_FLAG_UCSOLNT 0x04
460
+
461
+/** Use solicited notification for successful completions */
462
+#define SRP_CMD_FLAG_SCSOLNT 0x02
463
+
464
+/** Data-out buffer format mask */
465
+#define SRP_CMD_DO_FMT_MASK 0xf0
466
+
467
+/** Direct data-out buffer format */
468
+#define SRP_CMD_DO_FMT_DIRECT 0x10
469
+
470
+/** Indirect data-out buffer format */
471
+#define SRP_CMD_DO_FMT_INDIRECT 0x20
472
+
473
+/** Data-in buffer format mask */
474
+#define SRP_CMD_DI_FMT_MASK 0x0f
475
+
476
+/** Direct data-in buffer format */
477
+#define SRP_CMD_DI_FMT_DIRECT 0x01
478
+
479
+/** Indirect data-in buffer format */
480
+#define SRP_CMD_DI_FMT_INDIRECT 0x02
481
+
482
+/** Use the rules for a simple task attribute */
483
+#define SRP_CMD_TASK_ATTR_SIMPLE 0x00
484
+
485
+/** Use the rules for a head of queue task attribute */
486
+#define SRP_CMD_TASK_ATTR_QUEUE_HEAD 0x01
487
+
488
+/** Use the rules for an ordered task attribute */
489
+#define SRP_CMD_TASK_ATTR_ORDERED 0x02
490
+
491
+/** Use the rules for an automatic contingent allegiance task attribute */
492
+#define SRP_CMD_TASK_ATTR_AUTOMATIC_CONTINGENT_ALLEGIANCE 0x08
493
+
494
+/** An SRP memory descriptor */
495
+struct srp_memory_descriptor {
496
+	/** Virtual address */
497
+	uint64_t address;
498
+	/** Memory handle */
499
+	uint32_t handle;
500
+	/** Data length */
501
+	uint32_t len;
502
+} __attribute__ (( packed ));
503
+
504
+/*****************************************************************************
505
+ *
506
+ * SCSI response
507
+ *
508
+ *****************************************************************************
509
+ */
510
+
511
+/** An SRP SCSI response */
512
+struct srp_rsp {
513
+	/** Information unit type
514
+	 *
515
+	 * This must be @c SRP_RSP
516
+	 */
517
+	uint8_t type;
518
+	/** Flags
519
+	 *
520
+	 * This is the bitwise OR of zero or more @c SRP_RSP_FLAG_XXX
521
+	 * constants.
522
+	 */
523
+	uint8_t flags;
524
+	/** Reserved */
525
+	uint8_t reserved0[2];
526
+	/** Request limit delta */
527
+	uint32_t request_limit_delta;
528
+	/** Tag */
529
+	struct srp_tag tag;
530
+	/** Reserved */
531
+	uint8_t reserved1[2];
532
+	/** Valid fields
533
+	 *
534
+	 * This is the bitwise OR of zero or more @c SRP_RSP_VALID_XXX
535
+	 * constants.
536
+	 */
537
+	uint8_t valid;
538
+	/** Status
539
+	 *
540
+	 * This is the SCSI status code.
541
+	 */
542
+	uint8_t status;
543
+	/** Data-out residual count */
544
+	uint32_t data_out_residual_count;
545
+	/** Data-in residual count */
546
+	uint32_t data_in_residual_count;
547
+	/** Sense data list length */
548
+	uint32_t sense_data_len;
549
+	/** Response data list length */
550
+	uint32_t response_data_len;
551
+} __attribute__ (( packed ));
552
+
553
+/** Type of an SRP SCSI response */
554
+#define SRP_RSP 0xc1
555
+
556
+/** The initiator specified solicited notification of this response */
557
+#define SRP_RSP_FLAG_SOLNT 0x01
558
+
559
+/** Data-in residual count field is valid and represents an underflow */
560
+#define SRP_RSP_VALID_DIUNDER 0x20
561
+
562
+/** Data-in residual count field is valid and represents an overflow */
563
+#define SRP_RSP_VALID_DIOVER 0x10
564
+
565
+/** Data-out residual count field is valid and represents an underflow */
566
+#define SRP_RSP_VALID_DOUNDER 0x08
567
+
568
+/** Data-out residual count field is valid and represents an overflow */
569
+#define SRP_RSP_VALID_DOOVER 0x04
570
+
571
+/** Sense data list length field is valid */
572
+#define SRP_RSP_VALID_SNSVALID 0x02
573
+
574
+/** Response data list length field is valid */
575
+#define SRP_RSP_VALID_RSPVALID 0x01
576
+
577
+/**
578
+ * Get response data portion of SCSI response
579
+ *
580
+ * @v rsp			SCSI response
581
+ * @ret response_data		Response data, or NULL if not present
582
+ */
583
+static inline void * srp_rsp_response_data ( struct srp_rsp *rsp ) {
584
+	return ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ?
585
+		 ( ( ( void * ) rsp ) + sizeof ( *rsp ) ) : NULL );
586
+}
587
+
588
+/**
589
+ * Get length of response data portion of SCSI response
590
+ *
591
+ * @v rsp			SCSI response
592
+ * @ret response_data_len	Response data length
593
+ */
594
+static inline size_t srp_rsp_response_data_len ( struct srp_rsp *rsp ) {
595
+	return ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ?
596
+		 ntohl ( rsp->response_data_len ) : 0 );
597
+}
598
+
599
+/**
600
+ * Get sense data portion of SCSI response
601
+ *
602
+ * @v rsp			SCSI response
603
+ * @ret sense_data		Sense data, or NULL if not present
604
+ */
605
+static inline void * srp_rsp_sense_data ( struct srp_rsp *rsp ) {
606
+	return ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ?
607
+		 ( ( ( void * ) rsp ) + sizeof ( *rsp ) +
608
+		   srp_rsp_response_data_len ( rsp ) ) : NULL );
609
+}
610
+
611
+/**
612
+ * Get length of sense data portion of SCSI response
613
+ *
614
+ * @v rsp			SCSI response
615
+ * @ret sense_data_len		Sense data length
616
+ */
617
+static inline size_t srp_rsp_sense_data_len ( struct srp_rsp *rsp ) {
618
+	return ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ?
619
+		 ntohl ( rsp->sense_data_len ) : 0 );
620
+}
621
+
622
+/*****************************************************************************
623
+ *
624
+ * Credit request
625
+ *
626
+ *****************************************************************************
627
+ */
628
+
629
+/** An SRP credit request */
630
+struct srp_cred_req {
631
+	/** Information unit type
632
+	 *
633
+	 * This must be @c SRP_CRED_REQ
634
+	 */
635
+	uint8_t type;
636
+	/** Flags
637
+	 *
638
+	 * This is the bitwise OR of zero or more
639
+	 * @c SRP_CRED_REQ_FLAG_XXX constants.
640
+	 */
641
+	uint8_t flags;
642
+	/** Reserved */
643
+	uint8_t reserved0[2];
644
+	/** Request limit delta */
645
+	uint32_t request_limit_delta;
646
+	/** Tag */
647
+	struct srp_tag tag;
648
+} __attribute__ (( packed ));
649
+
650
+/** Type of an SRP credit request */
651
+#define SRP_CRED_REQ 0x81
652
+
653
+/** The initiator specified solicited notification of credit requests */
654
+#define SRP_CRED_REQ_FLAG_SOLNT 0x01
655
+
656
+/*****************************************************************************
657
+ *
658
+ * Credit response
659
+ *
660
+ *****************************************************************************
661
+ */
662
+
663
+/** An SRP credit response */
664
+struct srp_cred_rsp {
665
+	/** Information unit type
666
+	 *
667
+	 * This must be @c SRP_CRED_RSP
668
+	 */
669
+	uint8_t type;
670
+	/** Reserved */
671
+	uint8_t reserved0[7];
672
+	/** Tag */
673
+	struct srp_tag tag;
674
+} __attribute__ (( packed ));
675
+
676
+/** Type of an SRP credit response */
677
+#define SRP_CRED_RSP 0x41
678
+
679
+/*****************************************************************************
680
+ *
681
+ * Asynchronous event request
682
+ *
683
+ *****************************************************************************
684
+ */
685
+
686
+/** An SRP asynchronous event request */
687
+struct srp_aer_req {
688
+	/** Information unit type
689
+	 *
690
+	 * This must be @c SRP_AER_REQ
691
+	 */
692
+	uint8_t type;
693
+	/** Flags
694
+	 *
695
+	 * This is the bitwise OR of zero or more @c
696
+	 * SRP_AER_REQ_FLAG_XXX constants.
697
+	 */
698
+	uint8_t flags;
699
+	/** Reserved */
700
+	uint8_t reserved0[2];
701
+	/** Request limit delta */
702
+	uint32_t request_limit_delta;
703
+	/** Tag */
704
+	struct srp_tag tag;
705
+	/** Reserved */
706
+	uint8_t reserved1[4];
707
+	/** Logical unit number */
708
+	struct scsi_lun lun;
709
+	/** Sense data list length */
710
+	uint32_t sense_data_len;
711
+	/** Reserved */
712
+	uint8_t reserved2[4];
713
+} __attribute__ (( packed ));
714
+
715
+/** Type of an SRP asynchronous event request */
716
+#define SRP_AER_REQ 0x82
717
+
718
+/** The initiator specified solicited notification of asynchronous events */
719
+#define SRP_AER_REQ_FLAG_SOLNT 0x01
720
+
721
+/**
722
+ * Get sense data portion of asynchronous event request
723
+ *
724
+ * @v aer_req			SRP asynchronous event request
725
+ * @ret sense_data		Sense data
726
+ */
727
+static inline __always_inline void *
728
+srp_aer_req_sense_data ( struct srp_aer_req *aer_req ) {
729
+	return ( ( ( void * ) aer_req ) + sizeof ( *aer_req ) );
730
+}
731
+
732
+/**
733
+ * Get length of sense data portion of asynchronous event request
734
+ *
735
+ * @v aer_req			SRP asynchronous event request
736
+ * @ret sense_data_len		Sense data length
737
+ */
738
+static inline __always_inline size_t
739
+srp_aer_req_sense_data_len ( struct srp_aer_req *aer_req ) {
740
+	return ( ntohl ( aer_req->sense_data_len ) );
741
+}
742
+
743
+/*****************************************************************************
744
+ *
745
+ * Asynchronous event response
746
+ *
747
+ *****************************************************************************
748
+ */
749
+
750
+/** An SRP asynchronous event response */
751
+struct srp_aer_rsp {
752
+	/** Information unit type
753
+	 *
754
+	 * This must be @c SRP_AER_RSP
755
+	 */
756
+	uint8_t type;
757
+	/** Reserved */
758
+	uint8_t reserved0[7];
759
+	/** Tag */
760
+	struct srp_tag tag;
761
+} __attribute__ (( packed ));
762
+
763
+/** Type of an SRP asynchronous event response */
764
+#define SRP_AER_RSP 0x42
765
+
766
+/*****************************************************************************
767
+ *
768
+ * Information units
769
+ *
770
+ *****************************************************************************
771
+ */
772
+
773
+/** Maximum length of any initiator-to-target IU that we will send
774
+ *
775
+ * The longest IU is a SRP_CMD with no additional CDB and two direct
776
+ * data buffer descriptors, which comes to 80 bytes.
777
+ */
778
+#define SRP_MAX_I_T_IU_LEN 80
779
+
780
+/*****************************************************************************
781
+ *
782
+ * SRP device
783
+ *
784
+ *****************************************************************************
785
+ */
786
+
787
+struct srp_device;
788
+
789
+/** An SRP transport type */
790
+struct srp_transport_type {
791
+	/** Length of transport private data */
792
+	size_t priv_len;
793
+	/** Parse root path
794
+	 *
795
+	 * @v srp		SRP device
796
+	 * @v root_path		Root path
797
+	 * @ret 		Return status code
798
+	 */
799
+	int ( * parse_root_path ) ( struct srp_device *srp,
800
+				    const char *root_path );
801
+	/** Connect SRP session
802
+	 *
803
+	 * @v srp		SRP device
804
+	 * @ret rc		Return status code
805
+	 *
806
+	 * This method should open the underlying socket.
807
+	 */
808
+	int ( * connect ) ( struct srp_device *srp );
809
+};
810
+
811
+/** An SRP device */
812
+struct srp_device {
813
+	/** Reference count */
814
+	struct refcnt refcnt;
815
+
816
+	/** Initiator and target port IDs */
817
+	struct srp_port_ids port_ids;
818
+	/** Logical unit number */
819
+	struct scsi_lun lun;
820
+	/** Memory handle */
821
+	uint32_t memory_handle;
822
+
823
+	/** Current state
824
+	 *
825
+	 * This is the bitwise-OR of zero or more @c SRP_STATE_XXX
826
+	 * flags.
827
+	 */
828
+	unsigned int state;
829
+	/** Retry counter */
830
+	unsigned int retry_count;
831
+	/** Instant return status code
832
+	 *
833
+	 * Used to avoid retrying the connection on every new SCSI
834
+	 * command after the retry count has been exceeded.
835
+	 */
836
+	int instant_rc;
837
+	/** Current SCSI command */
838
+	struct scsi_command *command;
839
+
840
+	/** Underlying data transfer interface */
841
+	struct xfer_interface socket;
842
+
843
+	/** Transport type */
844
+	struct srp_transport_type *transport;
845
+	/** Transport private data */
846
+	char transport_priv[0];
847
+};
848
+
849
+/**
850
+ * Get SRP transport private data
851
+ *
852
+ * @v srp		SRP device
853
+ * @ret priv		SRP transport private data
854
+ */
855
+static inline __always_inline void *
856
+srp_transport_priv ( struct srp_device *srp ) {
857
+	return ( ( void * ) srp->transport_priv );
858
+}
859
+
860
+/** SRP state flags */
861
+enum srp_state {
862
+	/** Underlying socket is open */
863
+	SRP_STATE_SOCKET_OPEN = 0x0001,
864
+	/** Session is logged in */
865
+	SRP_STATE_LOGGED_IN = 0x0002,
866
+};
867
+
868
+/** Maximum number of SRP retry attempts */
869
+#define SRP_MAX_RETRIES 3
870
+
871
+extern int srp_attach ( struct scsi_device *scsi, const char *root_path );
872
+extern void srp_detach ( struct scsi_device *scsi );
873
+
874
+#endif /* _GPXE_SRP_H */

+ 406
- 0
src/net/infiniband/ib_srp.c View File

@@ -0,0 +1,406 @@
1
+/*
2
+ * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions
7
+ * are met:
8
+ *
9
+ *   Redistributions of source code must retain the above copyright
10
+ *   notice, this list of conditions and the following disclaimer.
11
+ *
12
+ *   Redistributions in binary form must reproduce the above copyright
13
+ *   notice, this list of conditions and the following disclaimer in
14
+ *   the documentation and/or other materials provided with the
15
+ *   distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+FILE_LICENCE ( BSD2 );
32
+
33
+#include <stdlib.h>
34
+#include <errno.h>
35
+#include <gpxe/srp.h>
36
+#include <gpxe/infiniband.h>
37
+#include <gpxe/ib_cmrc.h>
38
+#include <gpxe/ib_srp.h>
39
+
40
+/**
41
+ * @file
42
+ *
43
+ * SCSI RDMA Protocol over Infiniband
44
+ *
45
+ */
46
+
47
+/* Disambiguate the various possible EINVALs */
48
+#define EINVAL_BYTE_STRING_LEN ( EINVAL | EUNIQ_01 )
49
+#define EINVAL_BYTE_STRING ( EINVAL | EUNIQ_02 )
50
+#define EINVAL_INTEGER ( EINVAL | EUNIQ_03 )
51
+#define EINVAL_RP_TOO_SHORT ( EINVAL | EUNIQ_04 )
52
+
53
+/** IB SRP parse flags */
54
+enum ib_srp_parse_flags {
55
+	IB_SRP_PARSE_REQUIRED = 0x0000,
56
+	IB_SRP_PARSE_OPTIONAL = 0x8000,
57
+	IB_SRP_PARSE_FLAG_MASK = 0xf000,
58
+};
59
+
60
+/** IB SRP root path parameters */
61
+struct ib_srp_root_path {
62
+	/** SCSI LUN */
63
+	struct scsi_lun *lun;
64
+	/** SRP port IDs */
65
+	struct srp_port_ids *port_ids;
66
+	/** IB SRP parameters */
67
+	struct ib_srp_parameters *ib;
68
+};
69
+
70
+/**
71
+ * Parse IB SRP root path byte-string value
72
+ *
73
+ * @v rp_comp		Root path component string
74
+ * @v default_value	Default value to use if component string is empty
75
+ * @ret value		Value
76
+ */
77
+static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
78
+				      unsigned int size_flags ) {
79
+	size_t size = ( size_flags & ~IB_SRP_PARSE_FLAG_MASK );
80
+	size_t rp_comp_len = strlen ( rp_comp );
81
+	char buf[3];
82
+	char *buf_end;
83
+
84
+	/* Allow optional components to be empty */
85
+	if ( ( rp_comp_len == 0 ) &&
86
+	     ( size_flags & IB_SRP_PARSE_OPTIONAL ) )
87
+		return 0;
88
+
89
+	/* Check string length */
90
+	if ( rp_comp_len != ( 2 * size ) )
91
+		return -EINVAL_BYTE_STRING_LEN;
92
+
93
+	/* Parse byte string */
94
+	for ( ; size ; size--, rp_comp += 2, bytes++ ) {
95
+		memcpy ( buf, rp_comp, 2 );
96
+		buf[2] = '\0';
97
+		*bytes = strtoul ( buf, &buf_end, 16 );
98
+		if ( buf_end != &buf[2] )
99
+			return -EINVAL_BYTE_STRING;
100
+	}
101
+	return 0;
102
+}
103
+
104
+/**
105
+ * Parse IB SRP root path integer value
106
+ *
107
+ * @v rp_comp		Root path component string
108
+ * @v default_value	Default value to use if component string is empty
109
+ * @ret value		Value
110
+ */
111
+static int ib_srp_parse_integer ( const char *rp_comp, int default_value ) {
112
+	int value;
113
+	char *end;
114
+
115
+	value = strtoul ( rp_comp, &end, 16 );
116
+	if ( *end )
117
+		return -EINVAL_INTEGER;
118
+
119
+	if ( end == rp_comp )
120
+		return default_value;
121
+
122
+	return value;
123
+}
124
+
125
+/**
126
+ * Parse IB SRP root path literal component
127
+ *
128
+ * @v rp_comp		Root path component string
129
+ * @v rp		IB SRP root path
130
+ * @ret rc		Return status code
131
+ */
132
+static int ib_srp_parse_literal ( const char *rp_comp __unused,
133
+				  struct ib_srp_root_path *rp __unused ) {
134
+	/* Ignore */
135
+	return 0;
136
+}
137
+
138
+/**
139
+ * Parse IB SRP root path source GID
140
+ *
141
+ * @v rp_comp		Root path component string
142
+ * @v rp		IB SRP root path
143
+ * @ret rc		Return status code
144
+ */
145
+static int ib_srp_parse_sgid ( const char *rp_comp,
146
+			       struct ib_srp_root_path *rp ) {
147
+	struct ib_device *ibdev;
148
+
149
+	/* Default to the GID of the last opened Infiniband device */
150
+	if ( ( ibdev = last_opened_ibdev() ) != NULL )
151
+		memcpy ( &rp->ib->sgid, &ibdev->gid, sizeof ( rp->ib->sgid ) );
152
+
153
+	return ib_srp_parse_byte_string ( rp_comp, rp->ib->sgid.u.bytes,
154
+					  ( sizeof ( rp->ib->sgid ) |
155
+					    IB_SRP_PARSE_OPTIONAL ) );
156
+}
157
+
158
+/**
159
+ * Parse IB SRP root path initiator identifier extension
160
+ *
161
+ * @v rp_comp		Root path component string
162
+ * @v rp		IB SRP root path
163
+ * @ret rc		Return status code
164
+ */
165
+static int ib_srp_parse_initiator_id_ext ( const char *rp_comp,
166
+					   struct ib_srp_root_path *rp ) {
167
+	struct ib_srp_initiator_port_id *port_id =
168
+		ib_srp_initiator_port_id ( rp->port_ids );
169
+
170
+	return ib_srp_parse_byte_string ( rp_comp, port_id->id_ext.u.bytes,
171
+					  ( sizeof ( port_id->id_ext ) |
172
+					    IB_SRP_PARSE_OPTIONAL ) );
173
+}
174
+
175
+/**
176
+ * Parse IB SRP root path initiator HCA GUID
177
+ *
178
+ * @v rp_comp		Root path component string
179
+ * @v rp		IB SRP root path
180
+ * @ret rc		Return status code
181
+ */
182
+static int ib_srp_parse_initiator_hca_guid ( const char *rp_comp,
183
+					     struct ib_srp_root_path *rp ) {
184
+	struct ib_srp_initiator_port_id *port_id =
185
+		ib_srp_initiator_port_id ( rp->port_ids );
186
+
187
+	/* Default to the GUID portion of the source GID */
188
+	memcpy ( &port_id->hca_guid, &rp->ib->sgid.u.half[1],
189
+		 sizeof ( port_id->hca_guid ) );
190
+
191
+	return ib_srp_parse_byte_string ( rp_comp, port_id->hca_guid.u.bytes,
192
+					  ( sizeof ( port_id->hca_guid ) |
193
+					    IB_SRP_PARSE_OPTIONAL ) );
194
+}
195
+
196
+/**
197
+ * Parse IB SRP root path destination GID
198
+ *
199
+ * @v rp_comp		Root path component string
200
+ * @v rp		IB SRP root path
201
+ * @ret rc		Return status code
202
+ */
203
+static int ib_srp_parse_dgid ( const char *rp_comp,
204
+			       struct ib_srp_root_path *rp ) {
205
+	return ib_srp_parse_byte_string ( rp_comp, rp->ib->dgid.u.bytes,
206
+					  ( sizeof ( rp->ib->dgid ) |
207
+					    IB_SRP_PARSE_REQUIRED ) );
208
+}
209
+
210
+/**
211
+ * Parse IB SRP root path partition key
212
+ *
213
+ * @v rp_comp		Root path component string
214
+ * @v rp		IB SRP root path
215
+ * @ret rc		Return status code
216
+ */
217
+static int ib_srp_parse_pkey ( const char *rp_comp,
218
+			       struct ib_srp_root_path *rp ) {
219
+	int pkey;
220
+
221
+	if ( ( pkey = ib_srp_parse_integer ( rp_comp, IB_PKEY_NONE ) ) < 0 )
222
+		return pkey;
223
+	rp->ib->pkey = pkey;
224
+	return 0;
225
+}
226
+
227
+/**
228
+ * Parse IB SRP root path service ID
229
+ *
230
+ * @v rp_comp		Root path component string
231
+ * @v rp		IB SRP root path
232
+ * @ret rc		Return status code
233
+ */
234
+static int ib_srp_parse_service_id ( const char *rp_comp,
235
+				     struct ib_srp_root_path *rp ) {
236
+	return ib_srp_parse_byte_string ( rp_comp, rp->ib->service_id.u.bytes,
237
+					  ( sizeof ( rp->ib->service_id ) |
238
+					    IB_SRP_PARSE_REQUIRED ) );
239
+}
240
+
241
+/**
242
+ * Parse IB SRP root path LUN
243
+ *
244
+ * @v rp_comp		Root path component string
245
+ * @v rp		IB SRP root path
246
+ * @ret rc		Return status code
247
+ */
248
+static int ib_srp_parse_lun ( const char *rp_comp,
249
+			      struct ib_srp_root_path *rp ) {
250
+	return scsi_parse_lun ( rp_comp, rp->lun );
251
+}
252
+
253
+/**
254
+ * Parse IB SRP root path target identifier extension
255
+ *
256
+ * @v rp_comp		Root path component string
257
+ * @v rp		IB SRP root path
258
+ * @ret rc		Return status code
259
+ */
260
+static int ib_srp_parse_target_id_ext ( const char *rp_comp,
261
+					struct ib_srp_root_path *rp ) {
262
+	struct ib_srp_target_port_id *port_id =
263
+		ib_srp_target_port_id ( rp->port_ids );
264
+
265
+	return ib_srp_parse_byte_string ( rp_comp, port_id->id_ext.u.bytes,
266
+					  ( sizeof ( port_id->id_ext ) |
267
+					    IB_SRP_PARSE_REQUIRED ) );
268
+}
269
+
270
+/**
271
+ * Parse IB SRP root path target I/O controller GUID
272
+ *
273
+ * @v rp_comp		Root path component string
274
+ * @v rp		IB SRP root path
275
+ * @ret rc		Return status code
276
+ */
277
+static int ib_srp_parse_target_ioc_guid ( const char *rp_comp,
278
+					  struct ib_srp_root_path *rp ) {
279
+	struct ib_srp_target_port_id *port_id =
280
+		ib_srp_target_port_id ( rp->port_ids );
281
+
282
+	return ib_srp_parse_byte_string ( rp_comp, port_id->ioc_guid.u.bytes,
283
+					  ( sizeof ( port_id->ioc_guid ) |
284
+					    IB_SRP_PARSE_REQUIRED ) );
285
+}
286
+
287
+/** IB SRP root path component parser */
288
+struct ib_srp_root_path_parser {
289
+	/**
290
+	 * Parse IB SRP root path component
291
+	 *
292
+	 * @v rp_comp		Root path component string
293
+	 * @v rp		IB SRP root path
294
+	 * @ret rc		Return status code
295
+	 */
296
+	int ( * parse ) ( const char *rp_comp, struct ib_srp_root_path *rp );
297
+};
298
+
299
+/** IB SRP root path components */
300
+static struct ib_srp_root_path_parser ib_srp_rp_parser[] = {
301
+	{ ib_srp_parse_literal },
302
+	{ ib_srp_parse_sgid },
303
+	{ ib_srp_parse_initiator_id_ext },
304
+	{ ib_srp_parse_initiator_hca_guid },
305
+	{ ib_srp_parse_dgid },
306
+	{ ib_srp_parse_pkey },
307
+	{ ib_srp_parse_service_id },
308
+	{ ib_srp_parse_lun },
309
+	{ ib_srp_parse_target_id_ext },
310
+	{ ib_srp_parse_target_ioc_guid },
311
+};
312
+
313
+/** Number of IB SRP root path components */
314
+#define IB_SRP_NUM_RP_COMPONENTS \
315
+	( sizeof ( ib_srp_rp_parser ) / sizeof ( ib_srp_rp_parser[0] ) )
316
+
317
+/**
318
+ * Parse IB SRP root path
319
+ *
320
+ * @v srp		SRP device
321
+ * @v rp_string		Root path
322
+ * @ret rc		Return status code
323
+ */
324
+static int ib_srp_parse_root_path ( struct srp_device *srp,
325
+				    const char *rp_string ) {
326
+	struct ib_srp_parameters *ib_params = ib_srp_params ( srp );
327
+	struct ib_srp_root_path rp = {
328
+		.lun = &srp->lun,
329
+		.port_ids = &srp->port_ids,
330
+		.ib = ib_params,
331
+	};
332
+	char rp_string_copy[ strlen ( rp_string ) + 1 ];
333
+	char *rp_comp[IB_SRP_NUM_RP_COMPONENTS];
334
+	char *rp_string_tmp = rp_string_copy;
335
+	unsigned int i = 0;
336
+	int rc;
337
+
338
+	/* Split root path into component parts */
339
+	strcpy ( rp_string_copy, rp_string );
340
+	while ( 1 ) {
341
+		rp_comp[i++] = rp_string_tmp;
342
+		if ( i == IB_SRP_NUM_RP_COMPONENTS )
343
+			break;
344
+		for ( ; *rp_string_tmp != ':' ; rp_string_tmp++ ) {
345
+			if ( ! *rp_string_tmp ) {
346
+				DBGC ( srp, "SRP %p root path \"%s\" too "
347
+				       "short\n", srp, rp_string );
348
+				return -EINVAL_RP_TOO_SHORT;
349
+			}
350
+		}
351
+		*(rp_string_tmp++) = '\0';
352
+	}
353
+
354
+	/* Parse root path components */
355
+	for ( i = 0 ; i < IB_SRP_NUM_RP_COMPONENTS ; i++ ) {
356
+		if ( ( rc = ib_srp_rp_parser[i].parse ( rp_comp[i],
357
+							&rp ) ) != 0 ) {
358
+			DBGC ( srp, "SRP %p could not parse \"%s\" in root "
359
+			       "path \"%s\": %s\n", srp, rp_comp[i],
360
+			       rp_string, strerror ( rc ) );
361
+			return rc;
362
+		}
363
+	}
364
+
365
+	return 0;
366
+}
367
+
368
+/**
369
+ * Connect IB SRP session
370
+ *
371
+ * @v srp		SRP device
372
+ * @ret rc		Return status code
373
+ */
374
+static int ib_srp_connect ( struct srp_device *srp ) {
375
+	struct ib_srp_parameters *ib_params = ib_srp_params ( srp );
376
+	struct ib_device *ibdev;
377
+	int rc;
378
+
379
+	/* Identify Infiniband device */
380
+	ibdev = find_ibdev ( &ib_params->sgid );
381
+	if ( ! ibdev ) {
382
+		DBGC ( srp, "SRP %p could not identify Infiniband device\n",
383
+		       srp );
384
+		return -ENODEV;
385
+	}
386
+
387
+	/* Configure remaining SRP parameters */
388
+	srp->memory_handle = ibdev->rdma_key;
389
+
390
+	/* Open CMRC socket */
391
+	if ( ( rc = ib_cmrc_open ( &srp->socket, ibdev, &ib_params->dgid,
392
+				   &ib_params->service_id ) ) != 0 ) {
393
+		DBGC ( srp, "SRP %p could not open CMRC socket: %s\n",
394
+		       srp, strerror ( rc ) );
395
+		return rc;
396
+	}
397
+
398
+	return 0;
399
+}
400
+
401
+/** IB SRP transport type */
402
+struct srp_transport_type ib_srp_transport = {
403
+	.priv_len = sizeof ( struct ib_srp_parameters ),
404
+	.parse_root_path = ib_srp_parse_root_path,
405
+	.connect = ib_srp_connect,
406
+};

Loading…
Cancel
Save