• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
ib_srp_parse_byte_string(const char * rp_comp,uint8_t * bytes,unsigned int size_flags)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  */
ib_srp_parse_integer(const char * rp_comp,int default_value)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  */
ib_srp_parse_literal(const char * rp_comp __unused,struct ib_srp_root_path * rp __unused)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  */
ib_srp_parse_sgid(const char * rp_comp,struct ib_srp_root_path * rp)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  */
ib_srp_parse_initiator_id_ext(const char * rp_comp,struct ib_srp_root_path * rp)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  */
ib_srp_parse_initiator_hca_guid(const char * rp_comp,struct ib_srp_root_path * rp)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  */
ib_srp_parse_dgid(const char * rp_comp,struct ib_srp_root_path * rp)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  */
ib_srp_parse_pkey(const char * rp_comp,struct ib_srp_root_path * rp)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_DEFAULT ) ) < 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  */
ib_srp_parse_service_id(const char * rp_comp,struct ib_srp_root_path * rp)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  */
ib_srp_parse_lun(const char * rp_comp,struct ib_srp_root_path * rp)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  */
ib_srp_parse_target_id_ext(const char * rp_comp,struct ib_srp_root_path * rp)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  */
ib_srp_parse_target_ioc_guid(const char * rp_comp,struct ib_srp_root_path * rp)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  */
ib_srp_parse_root_path(struct srp_device * srp,const char * rp_string)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  */
ib_srp_connect(struct srp_device * srp)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 };
407