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