|
|
1.1 root 1: /*
2: * Copyright (C) 2009 Fen Systems Ltd <[email protected]>.
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 <ipxe/interface.h>
36: #include <ipxe/uri.h>
37: #include <ipxe/open.h>
38: #include <ipxe/base16.h>
39: #include <ipxe/acpi.h>
40: #include <ipxe/srp.h>
41: #include <ipxe/infiniband.h>
42: #include <ipxe/ib_cmrc.h>
43: #include <ipxe/ib_srp.h>
44:
45: /**
46: * @file
47: *
48: * SCSI RDMA Protocol over Infiniband
49: *
50: */
51:
52: /* Disambiguate the various possible EINVALs */
53: #define EINVAL_BYTE_STRING_LEN __einfo_error ( EINFO_EINVAL_BYTE_STRING_LEN )
54: #define EINFO_EINVAL_BYTE_STRING_LEN __einfo_uniqify \
55: ( EINFO_EINVAL, 0x01, "Invalid byte string length" )
56: #define EINVAL_INTEGER __einfo_error ( EINFO_EINVAL_INTEGER )
57: #define EINFO_EINVAL_INTEGER __einfo_uniqify \
58: ( EINFO_EINVAL, 0x03, "Invalid integer" )
59: #define EINVAL_RP_TOO_SHORT __einfo_error ( EINFO_EINVAL_RP_TOO_SHORT )
60: #define EINFO_EINVAL_RP_TOO_SHORT __einfo_uniqify \
61: ( EINFO_EINVAL, 0x04, "Root path too short" )
62:
63: /******************************************************************************
64: *
65: * IB SRP devices
66: *
67: ******************************************************************************
68: */
69:
70: /** An Infiniband SRP device */
71: struct ib_srp_device {
72: /** Reference count */
73: struct refcnt refcnt;
74:
75: /** SRP transport interface */
76: struct interface srp;
77: /** CMRC interface */
78: struct interface cmrc;
79:
80: /** Infiniband device */
81: struct ib_device *ibdev;
82:
83: /** Destination GID (for boot firmware table) */
84: union ib_gid dgid;
85: /** Service ID (for boot firmware table) */
86: union ib_guid service_id;
87: };
88:
89: /**
90: * Free IB SRP device
91: *
92: * @v refcnt Reference count
93: */
94: static void ib_srp_free ( struct refcnt *refcnt ) {
95: struct ib_srp_device *ib_srp =
96: container_of ( refcnt, struct ib_srp_device, refcnt );
97:
98: ibdev_put ( ib_srp->ibdev );
99: free ( ib_srp );
100: }
101:
102: /**
103: * Close IB SRP device
104: *
105: * @v ib_srp IB SRP device
106: * @v rc Reason for close
107: */
108: static void ib_srp_close ( struct ib_srp_device *ib_srp, int rc ) {
109:
110: /* Shut down interfaces */
111: intf_shutdown ( &ib_srp->cmrc, rc );
112: intf_shutdown ( &ib_srp->srp, rc );
113: }
114:
115: /**
116: * Describe IB SRP device in an ACPI table
117: *
118: * @v srpdev SRP device
119: * @v acpi ACPI table
120: * @v len Length of ACPI table
121: * @ret rc Return status code
122: */
123: static int ib_srp_describe ( struct ib_srp_device *ib_srp,
124: struct acpi_description_header *acpi,
125: size_t len ) {
126: struct ib_device *ibdev = ib_srp->ibdev;
127: struct sbft_table *sbft =
128: container_of ( acpi, struct sbft_table, acpi );
129: struct sbft_ib_subtable *ib_sbft;
130: size_t used;
131:
132: /* Sanity check */
133: if ( acpi->signature != SBFT_SIG )
134: return -EINVAL;
135:
136: /* Append IB subtable to existing table */
137: used = le32_to_cpu ( sbft->acpi.length );
138: sbft->ib_offset = cpu_to_le16 ( used );
139: ib_sbft = ( ( ( void * ) sbft ) + used );
140: used += sizeof ( *ib_sbft );
141: if ( used > len )
142: return -ENOBUFS;
143: sbft->acpi.length = cpu_to_le32 ( used );
144:
145: /* Populate subtable */
146: memcpy ( &ib_sbft->sgid, &ibdev->gid, sizeof ( ib_sbft->sgid ) );
147: memcpy ( &ib_sbft->dgid, &ib_srp->dgid, sizeof ( ib_sbft->dgid ) );
148: memcpy ( &ib_sbft->service_id, &ib_srp->service_id,
149: sizeof ( ib_sbft->service_id ) );
150: ib_sbft->pkey = cpu_to_le16 ( ibdev->pkey );
151:
152: return 0;
153: }
154:
155: /** IB SRP CMRC interface operations */
156: static struct interface_operation ib_srp_cmrc_op[] = {
157: INTF_OP ( intf_close, struct ib_srp_device *, ib_srp_close ),
158: };
159:
160: /** IB SRP CMRC interface descriptor */
161: static struct interface_descriptor ib_srp_cmrc_desc =
162: INTF_DESC_PASSTHRU ( struct ib_srp_device, cmrc, ib_srp_cmrc_op, srp );
163:
164: /** IB SRP SRP interface operations */
165: static struct interface_operation ib_srp_srp_op[] = {
166: INTF_OP ( acpi_describe, struct ib_srp_device *, ib_srp_describe ),
167: INTF_OP ( intf_close, struct ib_srp_device *, ib_srp_close ),
168: };
169:
170: /** IB SRP SRP interface descriptor */
171: static struct interface_descriptor ib_srp_srp_desc =
172: INTF_DESC_PASSTHRU ( struct ib_srp_device, srp, ib_srp_srp_op, cmrc );
173:
174: /**
175: * Open IB SRP device
176: *
177: * @v block Block control interface
178: * @v ibdev Infiniband device
179: * @v dgid Destination GID
180: * @v service_id Service ID
181: * @v initiator Initiator port ID
182: * @v target Target port ID
183: * @v lun SCSI LUN
184: * @ret rc Return status code
185: */
186: static int ib_srp_open ( struct interface *block, struct ib_device *ibdev,
187: union ib_gid *dgid, union ib_guid *service_id,
188: union srp_port_id *initiator,
189: union srp_port_id *target, struct scsi_lun *lun ) {
190: struct ib_srp_device *ib_srp;
191: int rc;
192:
193: /* Allocate and initialise structure */
194: ib_srp = zalloc ( sizeof ( *ib_srp ) );
195: if ( ! ib_srp ) {
196: rc = -ENOMEM;
197: goto err_zalloc;
198: }
199: ref_init ( &ib_srp->refcnt, ib_srp_free );
200: intf_init ( &ib_srp->srp, &ib_srp_srp_desc, &ib_srp->refcnt );
201: intf_init ( &ib_srp->cmrc, &ib_srp_cmrc_desc, &ib_srp->refcnt );
202: ib_srp->ibdev = ibdev_get ( ibdev );
203: DBGC ( ib_srp, "IBSRP %p for " IB_GID_FMT " " IB_GUID_FMT "\n",
204: ib_srp, IB_GID_ARGS ( dgid ), IB_GUID_ARGS ( service_id ) );
205:
206: /* Preserve parameters required for boot firmware table */
207: memcpy ( &ib_srp->dgid, dgid, sizeof ( ib_srp->dgid ) );
208: memcpy ( &ib_srp->service_id, service_id,
209: sizeof ( ib_srp->service_id ) );
210:
211: /* Open CMRC socket */
212: if ( ( rc = ib_cmrc_open ( &ib_srp->cmrc, ibdev, dgid,
213: service_id ) ) != 0 ) {
214: DBGC ( ib_srp, "IBSRP %p could not open CMRC socket: %s\n",
215: ib_srp, strerror ( rc ) );
216: goto err_cmrc_open;
217: }
218:
219: /* Attach SRP device to parent interface */
220: if ( ( rc = srp_open ( block, &ib_srp->srp, initiator, target,
221: ibdev->rdma_key, lun ) ) != 0 ) {
222: DBGC ( ib_srp, "IBSRP %p could not create SRP device: %s\n",
223: ib_srp, strerror ( rc ) );
224: goto err_srp_open;
225: }
226:
227: /* Mortalise self and return */
228: ref_put ( &ib_srp->refcnt );
229: return 0;
230:
231: err_srp_open:
232: err_cmrc_open:
233: ib_srp_close ( ib_srp, rc );
234: ref_put ( &ib_srp->refcnt );
235: err_zalloc:
236: return rc;
237: }
238:
239: /******************************************************************************
240: *
241: * IB SRP URIs
242: *
243: ******************************************************************************
244: */
245:
246: /** IB SRP parse flags */
247: enum ib_srp_parse_flags {
248: IB_SRP_PARSE_REQUIRED = 0x0000,
249: IB_SRP_PARSE_OPTIONAL = 0x8000,
250: IB_SRP_PARSE_FLAG_MASK = 0xf000,
251: };
252:
253: /** IB SRP root path parameters */
254: struct ib_srp_root_path {
255: /** Source GID */
256: union ib_gid sgid;
257: /** Initiator port ID */
258: union ib_srp_initiator_port_id initiator;
259: /** Destination GID */
260: union ib_gid dgid;
261: /** Partition key */
262: uint16_t pkey;
263: /** Service ID */
264: union ib_guid service_id;
265: /** SCSI LUN */
266: struct scsi_lun lun;
267: /** Target port ID */
268: union ib_srp_target_port_id target;
269: };
270:
271: /**
272: * Parse IB SRP root path byte-string value
273: *
274: * @v rp_comp Root path component string
275: * @v default_value Default value to use if component string is empty
276: * @ret value Value
277: */
278: static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
279: unsigned int size_flags ) {
280: size_t size = ( size_flags & ~IB_SRP_PARSE_FLAG_MASK );
281: size_t rp_comp_len = strlen ( rp_comp );
282: int decoded_size;
283:
284: /* Allow optional components to be empty */
285: if ( ( rp_comp_len == 0 ) &&
286: ( size_flags & IB_SRP_PARSE_OPTIONAL ) )
287: return 0;
288:
289: /* Check string length */
290: if ( rp_comp_len != ( 2 * size ) )
291: return -EINVAL_BYTE_STRING_LEN;
292:
293: /* Parse byte string */
294: decoded_size = base16_decode ( rp_comp, bytes );
295: if ( decoded_size < 0 )
296: return decoded_size;
297:
298: return 0;
299: }
300:
301: /**
302: * Parse IB SRP root path integer value
303: *
304: * @v rp_comp Root path component string
305: * @v default_value Default value to use if component string is empty
306: * @ret value Value
307: */
308: static int ib_srp_parse_integer ( const char *rp_comp, int default_value ) {
309: int value;
310: char *end;
311:
312: value = strtoul ( rp_comp, &end, 16 );
313: if ( *end )
314: return -EINVAL_INTEGER;
315:
316: if ( end == rp_comp )
317: return default_value;
318:
319: return value;
320: }
321:
322: /**
323: * Parse IB SRP root path source GID
324: *
325: * @v rp_comp Root path component string
326: * @v rp IB SRP root path
327: * @ret rc Return status code
328: */
329: static int ib_srp_parse_sgid ( const char *rp_comp,
330: struct ib_srp_root_path *rp ) {
331: struct ib_device *ibdev;
332:
333: /* Default to the GID of the last opened Infiniband device */
334: if ( ( ibdev = last_opened_ibdev() ) != NULL )
335: memcpy ( &rp->sgid, &ibdev->gid, sizeof ( rp->sgid ) );
336:
337: return ib_srp_parse_byte_string ( rp_comp, rp->sgid.bytes,
338: ( sizeof ( rp->sgid ) |
339: IB_SRP_PARSE_OPTIONAL ) );
340: }
341:
342: /**
343: * Parse IB SRP root path initiator identifier extension
344: *
345: * @v rp_comp Root path component string
346: * @v rp IB SRP root path
347: * @ret rc Return status code
348: */
349: static int ib_srp_parse_initiator_id_ext ( const char *rp_comp,
350: struct ib_srp_root_path *rp ) {
351: union ib_srp_initiator_port_id *port_id = &rp->initiator;
352:
353: return ib_srp_parse_byte_string ( rp_comp, port_id->ib.id_ext.bytes,
354: ( sizeof ( port_id->ib.id_ext ) |
355: IB_SRP_PARSE_OPTIONAL ) );
356: }
357:
358: /**
359: * Parse IB SRP root path initiator HCA GUID
360: *
361: * @v rp_comp Root path component string
362: * @v rp IB SRP root path
363: * @ret rc Return status code
364: */
365: static int ib_srp_parse_initiator_hca_guid ( const char *rp_comp,
366: struct ib_srp_root_path *rp ) {
367: union ib_srp_initiator_port_id *port_id = &rp->initiator;
368:
369: /* Default to the GUID portion of the source GID */
370: memcpy ( &port_id->ib.hca_guid, &rp->sgid.s.guid,
371: sizeof ( port_id->ib.hca_guid ) );
372:
373: return ib_srp_parse_byte_string ( rp_comp, port_id->ib.hca_guid.bytes,
374: ( sizeof ( port_id->ib.hca_guid ) |
375: IB_SRP_PARSE_OPTIONAL ) );
376: }
377:
378: /**
379: * Parse IB SRP root path destination GID
380: *
381: * @v rp_comp Root path component string
382: * @v rp IB SRP root path
383: * @ret rc Return status code
384: */
385: static int ib_srp_parse_dgid ( const char *rp_comp,
386: struct ib_srp_root_path *rp ) {
387: return ib_srp_parse_byte_string ( rp_comp, rp->dgid.bytes,
388: ( sizeof ( rp->dgid ) |
389: IB_SRP_PARSE_REQUIRED ) );
390: }
391:
392: /**
393: * Parse IB SRP root path partition key
394: *
395: * @v rp_comp Root path component string
396: * @v rp IB SRP root path
397: * @ret rc Return status code
398: */
399: static int ib_srp_parse_pkey ( const char *rp_comp,
400: struct ib_srp_root_path *rp ) {
401: int pkey;
402:
403: if ( ( pkey = ib_srp_parse_integer ( rp_comp, IB_PKEY_DEFAULT ) ) < 0 )
404: return pkey;
405: rp->pkey = pkey;
406: return 0;
407: }
408:
409: /**
410: * Parse IB SRP root path service ID
411: *
412: * @v rp_comp Root path component string
413: * @v rp IB SRP root path
414: * @ret rc Return status code
415: */
416: static int ib_srp_parse_service_id ( const char *rp_comp,
417: struct ib_srp_root_path *rp ) {
418: return ib_srp_parse_byte_string ( rp_comp, rp->service_id.bytes,
419: ( sizeof ( rp->service_id ) |
420: IB_SRP_PARSE_REQUIRED ) );
421: }
422:
423: /**
424: * Parse IB SRP root path LUN
425: *
426: * @v rp_comp Root path component string
427: * @v rp IB SRP root path
428: * @ret rc Return status code
429: */
430: static int ib_srp_parse_lun ( const char *rp_comp,
431: struct ib_srp_root_path *rp ) {
432: return scsi_parse_lun ( rp_comp, &rp->lun );
433: }
434:
435: /**
436: * Parse IB SRP root path target identifier extension
437: *
438: * @v rp_comp Root path component string
439: * @v rp IB SRP root path
440: * @ret rc Return status code
441: */
442: static int ib_srp_parse_target_id_ext ( const char *rp_comp,
443: struct ib_srp_root_path *rp ) {
444: union ib_srp_target_port_id *port_id = &rp->target;
445:
446: return ib_srp_parse_byte_string ( rp_comp, port_id->ib.id_ext.bytes,
447: ( sizeof ( port_id->ib.id_ext ) |
448: IB_SRP_PARSE_REQUIRED ) );
449: }
450:
451: /**
452: * Parse IB SRP root path target I/O controller GUID
453: *
454: * @v rp_comp Root path component string
455: * @v rp IB SRP root path
456: * @ret rc Return status code
457: */
458: static int ib_srp_parse_target_ioc_guid ( const char *rp_comp,
459: struct ib_srp_root_path *rp ) {
460: union ib_srp_target_port_id *port_id = &rp->target;
461:
462: return ib_srp_parse_byte_string ( rp_comp, port_id->ib.ioc_guid.bytes,
463: ( sizeof ( port_id->ib.ioc_guid ) |
464: IB_SRP_PARSE_REQUIRED ) );
465: }
466:
467: /** IB SRP root path component parser */
468: struct ib_srp_root_path_parser {
469: /**
470: * Parse IB SRP root path component
471: *
472: * @v rp_comp Root path component string
473: * @v rp IB SRP root path
474: * @ret rc Return status code
475: */
476: int ( * parse ) ( const char *rp_comp, struct ib_srp_root_path *rp );
477: };
478:
479: /** IB SRP root path components */
480: static struct ib_srp_root_path_parser ib_srp_rp_parser[] = {
481: { ib_srp_parse_sgid },
482: { ib_srp_parse_initiator_id_ext },
483: { ib_srp_parse_initiator_hca_guid },
484: { ib_srp_parse_dgid },
485: { ib_srp_parse_pkey },
486: { ib_srp_parse_service_id },
487: { ib_srp_parse_lun },
488: { ib_srp_parse_target_id_ext },
489: { ib_srp_parse_target_ioc_guid },
490: };
491:
492: /** Number of IB SRP root path components */
493: #define IB_SRP_NUM_RP_COMPONENTS \
494: ( sizeof ( ib_srp_rp_parser ) / sizeof ( ib_srp_rp_parser[0] ) )
495:
496: /**
497: * Parse IB SRP root path
498: *
499: * @v rp_string Root path string
500: * @v rp IB SRP root path
501: * @ret rc Return status code
502: */
503: static int ib_srp_parse_root_path ( const char *rp_string,
504: struct ib_srp_root_path *rp ) {
505: struct ib_srp_root_path_parser *parser;
506: char rp_string_copy[ strlen ( rp_string ) + 1 ];
507: char *rp_comp[IB_SRP_NUM_RP_COMPONENTS];
508: char *rp_string_tmp = rp_string_copy;
509: unsigned int i = 0;
510: int rc;
511:
512: /* Split root path into component parts */
513: strcpy ( rp_string_copy, rp_string );
514: while ( 1 ) {
515: rp_comp[i++] = rp_string_tmp;
516: if ( i == IB_SRP_NUM_RP_COMPONENTS )
517: break;
518: for ( ; *rp_string_tmp != ':' ; rp_string_tmp++ ) {
519: if ( ! *rp_string_tmp ) {
520: DBG ( "IBSRP root path \"%s\" too short\n",
521: rp_string );
522: return -EINVAL_RP_TOO_SHORT;
523: }
524: }
525: *(rp_string_tmp++) = '\0';
526: }
527:
528: /* Parse root path components */
529: for ( i = 0 ; i < IB_SRP_NUM_RP_COMPONENTS ; i++ ) {
530: parser = &ib_srp_rp_parser[i];
531: if ( ( rc = parser->parse ( rp_comp[i], rp ) ) != 0 ) {
532: DBG ( "IBSRP could not parse \"%s\" in root path "
533: "\"%s\": %s\n", rp_comp[i], rp_string,
534: strerror ( rc ) );
535: return rc;
536: }
537: }
538:
539: return 0;
540: }
541:
542: /**
543: * Open IB SRP URI
544: *
545: * @v parent Parent interface
546: * @v uri URI
547: * @ret rc Return status code
548: */
549: static int ib_srp_open_uri ( struct interface *parent, struct uri *uri ) {
550: struct ib_srp_root_path rp;
551: struct ib_device *ibdev;
552: int rc;
553:
554: /* Parse URI */
555: if ( ! uri->opaque )
556: return -EINVAL;
557: memset ( &rp, 0, sizeof ( rp ) );
558: if ( ( rc = ib_srp_parse_root_path ( uri->opaque, &rp ) ) != 0 )
559: return rc;
560:
561: /* Identify Infiniband device */
562: ibdev = find_ibdev ( &rp.sgid );
563: if ( ! ibdev ) {
564: DBG ( "IBSRP could not identify Infiniband device\n" );
565: return -ENODEV;
566: }
567:
568: /* Open IB SRP device */
569: if ( ( rc = ib_srp_open ( parent, ibdev, &rp.dgid, &rp.service_id,
570: &rp.initiator.srp, &rp.target.srp,
571: &rp.lun ) ) != 0 )
572: return rc;
573:
574: return 0;
575: }
576:
577: /** IB SRP URI opener */
578: struct uri_opener ib_srp_uri_opener __uri_opener = {
579: .scheme = "ib_srp",
580: .open = ib_srp_open_uri,
581: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.