You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ib_srp.c 16KB

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