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 <string.h> 35 #include <errno.h> 36 #include <gpxe/scsi.h> 37 #include <gpxe/xfer.h> 38 #include <gpxe/features.h> 39 #include <gpxe/ib_srp.h> 40 #include <gpxe/srp.h> 41 42 /** 43 * @file 44 * 45 * SCSI RDMA Protocol 46 * 47 */ 48 49 FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 ); 50 51 /** Tag to be used for next SRP IU */ 52 static unsigned int srp_tag = 0; 53 54 static void srp_login ( struct srp_device *srp ); 55 static void srp_cmd ( struct srp_device *srp ); 56 57 /** 58 * Mark SRP SCSI command as complete 59 * 60 * @v srp SRP device 61 * @v rc Status code 62 */ 63 static void srp_scsi_done ( struct srp_device *srp, int rc ) { 64 if ( srp->command ) 65 srp->command->rc = rc; 66 srp->command = NULL; 67 } 68 69 /** 70 * Handle SRP session failure 71 * 72 * @v srp SRP device 73 * @v rc Reason for failure 74 */ 75 static void srp_fail ( struct srp_device *srp, int rc ) { 76 77 /* Close underlying socket */ 78 xfer_close ( &srp->socket, rc ); 79 80 /* Clear session state */ 81 srp->state = 0; 82 83 /* If we have reached the retry limit, report the failure */ 84 if ( srp->retry_count >= SRP_MAX_RETRIES ) { 85 srp_scsi_done ( srp, rc ); 86 return; 87 } 88 89 /* Otherwise, increment the retry count and try to reopen the 90 * connection 91 */ 92 srp->retry_count++; 93 srp_login ( srp ); 94 } 95 96 /** 97 * Initiate SRP login 98 * 99 * @v srp SRP device 100 */ 101 static void srp_login ( struct srp_device *srp ) { 102 struct io_buffer *iobuf; 103 struct srp_login_req *login_req; 104 int rc; 105 106 assert ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) ); 107 108 /* Open underlying socket */ 109 if ( ( rc = srp->transport->connect ( srp ) ) != 0 ) { 110 DBGC ( srp, "SRP %p could not open socket: %s\n", 111 srp, strerror ( rc ) ); 112 goto err; 113 } 114 srp->state |= SRP_STATE_SOCKET_OPEN; 115 116 /* Allocate I/O buffer */ 117 iobuf = xfer_alloc_iob ( &srp->socket, sizeof ( *login_req ) ); 118 if ( ! iobuf ) { 119 rc = -ENOMEM; 120 goto err; 121 } 122 123 /* Construct login request IU */ 124 login_req = iob_put ( iobuf, sizeof ( *login_req ) ); 125 memset ( login_req, 0, sizeof ( *login_req ) ); 126 login_req->type = SRP_LOGIN_REQ; 127 login_req->tag.dwords[1] = htonl ( ++srp_tag ); 128 login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN ); 129 login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD; 130 memcpy ( &login_req->port_ids, &srp->port_ids, 131 sizeof ( login_req->port_ids ) ); 132 133 DBGC2 ( srp, "SRP %p TX login request tag %08x%08x\n", 134 srp, ntohl ( login_req->tag.dwords[0] ), 135 ntohl ( login_req->tag.dwords[1] ) ); 136 DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) ); 137 138 /* Send login request IU */ 139 if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) { 140 DBGC ( srp, "SRP %p could not send login request: %s\n", 141 srp, strerror ( rc ) ); 142 goto err; 143 } 144 145 return; 146 147 err: 148 srp_fail ( srp, rc ); 149 } 150 151 /** 152 * Handle SRP login response 153 * 154 * @v srp SRP device 155 * @v iobuf I/O buffer 156 * @ret rc Return status code 157 */ 158 static int srp_login_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) { 159 struct srp_login_rsp *login_rsp = iobuf->data; 160 int rc; 161 162 DBGC2 ( srp, "SRP %p RX login response tag %08x%08x\n", 163 srp, ntohl ( login_rsp->tag.dwords[0] ), 164 ntohl ( login_rsp->tag.dwords[1] ) ); 165 166 /* Sanity check */ 167 if ( iob_len ( iobuf ) < sizeof ( *login_rsp ) ) { 168 DBGC ( srp, "SRP %p RX login response too short (%zd bytes)\n", 169 srp, iob_len ( iobuf ) ); 170 rc = -EINVAL; 171 goto out; 172 } 173 174 DBGC ( srp, "SRP %p logged in\n", srp ); 175 176 /* Mark as logged in */ 177 srp->state |= SRP_STATE_LOGGED_IN; 178 179 /* Reset error counter */ 180 srp->retry_count = 0; 181 182 /* Issue pending command */ 183 srp_cmd ( srp ); 184 185 rc = 0; 186 out: 187 free_iob ( iobuf ); 188 return rc; 189 } 190 191 /** 192 * Handle SRP login rejection 193 * 194 * @v srp SRP device 195 * @v iobuf I/O buffer 196 * @ret rc Return status code 197 */ 198 static int srp_login_rej ( struct srp_device *srp, struct io_buffer *iobuf ) { 199 struct srp_login_rej *login_rej = iobuf->data; 200 int rc; 201 202 DBGC2 ( srp, "SRP %p RX login rejection tag %08x%08x\n", 203 srp, ntohl ( login_rej->tag.dwords[0] ), 204 ntohl ( login_rej->tag.dwords[1] ) ); 205 206 /* Sanity check */ 207 if ( iob_len ( iobuf ) < sizeof ( *login_rej ) ) { 208 DBGC ( srp, "SRP %p RX login rejection too short (%zd " 209 "bytes)\n", srp, iob_len ( iobuf ) ); 210 rc = -EINVAL; 211 goto out; 212 } 213 214 /* Login rejection always indicates an error */ 215 DBGC ( srp, "SRP %p login rejected (reason %08x)\n", 216 srp, ntohl ( login_rej->reason ) ); 217 rc = -EPERM; 218 219 out: 220 free_iob ( iobuf ); 221 return rc; 222 } 223 224 /** 225 * Transmit SRP SCSI command 226 * 227 * @v srp SRP device 228 */ 229 static void srp_cmd ( struct srp_device *srp ) { 230 struct io_buffer *iobuf; 231 struct srp_cmd *cmd; 232 struct srp_memory_descriptor *data_out; 233 struct srp_memory_descriptor *data_in; 234 int rc; 235 236 assert ( srp->state & SRP_STATE_LOGGED_IN ); 237 238 /* Allocate I/O buffer */ 239 iobuf = xfer_alloc_iob ( &srp->socket, SRP_MAX_I_T_IU_LEN ); 240 if ( ! iobuf ) { 241 rc = -ENOMEM; 242 goto err; 243 } 244 245 /* Construct base portion */ 246 cmd = iob_put ( iobuf, sizeof ( *cmd ) ); 247 memset ( cmd, 0, sizeof ( *cmd ) ); 248 cmd->type = SRP_CMD; 249 cmd->tag.dwords[1] = htonl ( ++srp_tag ); 250 cmd->lun = srp->lun; 251 memcpy ( &cmd->cdb, &srp->command->cdb, sizeof ( cmd->cdb ) ); 252 253 /* Construct data-out descriptor, if present */ 254 if ( srp->command->data_out ) { 255 cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT; 256 data_out = iob_put ( iobuf, sizeof ( *data_out ) ); 257 data_out->address = 258 cpu_to_be64 ( user_to_phys ( srp->command->data_out, 0 ) ); 259 data_out->handle = ntohl ( srp->memory_handle ); 260 data_out->len = ntohl ( srp->command->data_out_len ); 261 } 262 263 /* Construct data-in descriptor, if present */ 264 if ( srp->command->data_in ) { 265 cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT; 266 data_in = iob_put ( iobuf, sizeof ( *data_in ) ); 267 data_in->address = 268 cpu_to_be64 ( user_to_phys ( srp->command->data_in, 0 ) ); 269 data_in->handle = ntohl ( srp->memory_handle ); 270 data_in->len = ntohl ( srp->command->data_in_len ); 271 } 272 273 DBGC2 ( srp, "SRP %p TX SCSI command tag %08x%08x\n", srp, 274 ntohl ( cmd->tag.dwords[0] ), ntohl ( cmd->tag.dwords[1] ) ); 275 DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) ); 276 277 /* Send IU */ 278 if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) { 279 DBGC ( srp, "SRP %p could not send command: %s\n", 280 srp, strerror ( rc ) ); 281 goto err; 282 } 283 284 return; 285 286 err: 287 srp_fail ( srp, rc ); 288 } 289 290 /** 291 * Handle SRP SCSI response 292 * 293 * @v srp SRP device 294 * @v iobuf I/O buffer 295 * @ret rc Returns status code 296 */ 297 static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) { 298 struct srp_rsp *rsp = iobuf->data; 299 int rc; 300 301 DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp, 302 ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) ); 303 304 /* Sanity check */ 305 if ( iob_len ( iobuf ) < sizeof ( *rsp ) ) { 306 DBGC ( srp, "SRP %p RX SCSI response too short (%zd bytes)\n", 307 srp, iob_len ( iobuf ) ); 308 rc = -EINVAL; 309 goto out; 310 } 311 312 /* Report SCSI errors */ 313 if ( rsp->status != 0 ) { 314 DBGC ( srp, "SRP %p response status %02x\n", 315 srp, rsp->status ); 316 if ( srp_rsp_sense_data ( rsp ) ) { 317 DBGC ( srp, "SRP %p sense data:\n", srp ); 318 DBGC_HDA ( srp, 0, srp_rsp_sense_data ( rsp ), 319 srp_rsp_sense_data_len ( rsp ) ); 320 } 321 } 322 if ( rsp->valid & ( SRP_RSP_VALID_DOUNDER | SRP_RSP_VALID_DOOVER ) ) { 323 DBGC ( srp, "SRP %p response data-out %srun by %#x bytes\n", 324 srp, ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) 325 ? "under" : "over" ), 326 ntohl ( rsp->data_out_residual_count ) ); 327 } 328 if ( rsp->valid & ( SRP_RSP_VALID_DIUNDER | SRP_RSP_VALID_DIOVER ) ) { 329 DBGC ( srp, "SRP %p response data-in %srun by %#x bytes\n", 330 srp, ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) 331 ? "under" : "over" ), 332 ntohl ( rsp->data_in_residual_count ) ); 333 } 334 srp->command->status = rsp->status; 335 336 /* Mark SCSI command as complete */ 337 srp_scsi_done ( srp, 0 ); 338 339 rc = 0; 340 out: 341 free_iob ( iobuf ); 342 return rc; 343 } 344 345 /** 346 * Handle SRP unrecognised response 347 * 348 * @v srp SRP device 349 * @v iobuf I/O buffer 350 * @ret rc Returns status code 351 */ 352 static int srp_unrecognised ( struct srp_device *srp, 353 struct io_buffer *iobuf ) { 354 struct srp_common *common = iobuf->data; 355 356 DBGC ( srp, "SRP %p RX unrecognised IU tag %08x%08x type %02x\n", 357 srp, ntohl ( common->tag.dwords[0] ), 358 ntohl ( common->tag.dwords[1] ), common->type ); 359 360 free_iob ( iobuf ); 361 return -ENOTSUP; 362 } 363 364 /** 365 * Receive data from underlying socket 366 * 367 * @v xfer Data transfer interface 368 * @v iobuf Datagram I/O buffer 369 * @v meta Data transfer metadata 370 * @ret rc Return status code 371 */ 372 static int srp_xfer_deliver_iob ( struct xfer_interface *xfer, 373 struct io_buffer *iobuf, 374 struct xfer_metadata *meta __unused ) { 375 struct srp_device *srp = 376 container_of ( xfer, struct srp_device, socket ); 377 struct srp_common *common = iobuf->data; 378 int ( * type ) ( struct srp_device *srp, struct io_buffer *iobuf ); 379 int rc; 380 381 /* Determine IU type */ 382 switch ( common->type ) { 383 case SRP_LOGIN_RSP: 384 type = srp_login_rsp; 385 break; 386 case SRP_LOGIN_REJ: 387 type = srp_login_rej; 388 break; 389 case SRP_RSP: 390 type = srp_rsp; 391 break; 392 default: 393 type = srp_unrecognised; 394 break; 395 } 396 397 /* Handle IU */ 398 if ( ( rc = type ( srp, iobuf ) ) != 0 ) 399 goto err; 400 401 return 0; 402 403 err: 404 srp_fail ( srp, rc ); 405 return rc; 406 } 407 408 /** 409 * Underlying socket closed 410 * 411 * @v xfer Data transfer interface 412 * @v rc Reason for close 413 */ 414 static void srp_xfer_close ( struct xfer_interface *xfer, int rc ) { 415 struct srp_device *srp = 416 container_of ( xfer, struct srp_device, socket ); 417 418 DBGC ( srp, "SRP %p socket closed: %s\n", srp, strerror ( rc ) ); 419 420 srp_fail ( srp, rc ); 421 } 422 423 /** SRP data transfer interface operations */ 424 static struct xfer_interface_operations srp_xfer_operations = { 425 .close = srp_xfer_close, 426 .vredirect = ignore_xfer_vredirect, 427 .window = unlimited_xfer_window, 428 .alloc_iob = default_xfer_alloc_iob, 429 .deliver_iob = srp_xfer_deliver_iob, 430 .deliver_raw = xfer_deliver_as_iob, 431 }; 432 433 /** 434 * Issue SCSI command via SRP 435 * 436 * @v scsi SCSI device 437 * @v command SCSI command 438 * @ret rc Return status code 439 */ 440 static int srp_command ( struct scsi_device *scsi, 441 struct scsi_command *command ) { 442 struct srp_device *srp = 443 container_of ( scsi->backend, struct srp_device, refcnt ); 444 445 /* Store SCSI command */ 446 if ( srp->command ) { 447 DBGC ( srp, "SRP %p cannot handle concurrent SCSI commands\n", 448 srp ); 449 return -EBUSY; 450 } 451 srp->command = command; 452 453 /* Log in or issue command as appropriate */ 454 if ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) ) { 455 srp_login ( srp ); 456 } else if ( srp->state & SRP_STATE_LOGGED_IN ) { 457 srp_cmd ( srp ); 458 } else { 459 /* Still waiting for login; do nothing */ 460 } 461 462 return 0; 463 } 464 465 /** 466 * Attach SRP device 467 * 468 * @v scsi SCSI device 469 * @v root_path Root path 470 */ 471 int srp_attach ( struct scsi_device *scsi, const char *root_path ) { 472 struct srp_transport_type *transport; 473 struct srp_device *srp; 474 int rc; 475 476 /* Hard-code an IB SRP back-end for now */ 477 transport = &ib_srp_transport; 478 479 /* Allocate and initialise structure */ 480 srp = zalloc ( sizeof ( *srp ) + transport->priv_len ); 481 if ( ! srp ) { 482 rc = -ENOMEM; 483 goto err_alloc; 484 } 485 xfer_init ( &srp->socket, &srp_xfer_operations, &srp->refcnt ); 486 srp->transport = transport; 487 DBGC ( srp, "SRP %p using %s\n", srp, root_path ); 488 489 /* Parse root path */ 490 if ( ( rc = transport->parse_root_path ( srp, root_path ) ) != 0 ) { 491 DBGC ( srp, "SRP %p could not parse root path: %s\n", 492 srp, strerror ( rc ) ); 493 goto err_parse_root_path; 494 } 495 496 /* Attach parent interface, mortalise self, and return */ 497 scsi->backend = ref_get ( &srp->refcnt ); 498 scsi->command = srp_command; 499 ref_put ( &srp->refcnt ); 500 return 0; 501 502 err_parse_root_path: 503 ref_put ( &srp->refcnt ); 504 err_alloc: 505 return rc; 506 } 507 508 /** 509 * Detach SRP device 510 * 511 * @v scsi SCSI device 512 */ 513 void srp_detach ( struct scsi_device *scsi ) { 514 struct srp_device *srp = 515 container_of ( scsi->backend, struct srp_device, refcnt ); 516 517 /* Close socket */ 518 xfer_nullify ( &srp->socket ); 519 xfer_close ( &srp->socket, 0 ); 520 scsi->command = scsi_detached_command; 521 ref_put ( scsi->backend ); 522 scsi->backend = NULL; 523 } 524