1 /* 2 * Copyright (C) 2009 Fen Systems Ltd <mbrown (at) 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_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 */ 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 }; 407