|
|
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 <string.h> ! 35: #include <errno.h> ! 36: #include <ipxe/scsi.h> ! 37: #include <ipxe/xfer.h> ! 38: #include <ipxe/features.h> ! 39: #include <ipxe/srp.h> ! 40: ! 41: /** ! 42: * @file ! 43: * ! 44: * SCSI RDMA Protocol ! 45: * ! 46: */ ! 47: ! 48: FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 ); ! 49: ! 50: /** Maximum length of any initiator-to-target IU that we will send ! 51: * ! 52: * The longest IU is a SRP_CMD with no additional CDB and two direct ! 53: * data buffer descriptors, which comes to 80 bytes. ! 54: */ ! 55: #define SRP_MAX_I_T_IU_LEN 80 ! 56: ! 57: /* Error numbers generated by SRP login rejection */ ! 58: #define EINFO_SRP_LOGIN_REJ( reason, desc ) \ ! 59: __einfo_uniqify ( EINFO_EPERM, ( (reason) & 0x0f ), desc ) ! 60: #define EPERM_UNKNOWN \ ! 61: __einfo_error ( EINFO_EPERM_UNKNOWN ) ! 62: #define EINFO_EPERM_UNKNOWN EINFO_SRP_LOGIN_REJ ( \ ! 63: SRP_LOGIN_REJ_REASON_UNKNOWN, \ ! 64: "Unable to establish RDMA channel, no reason specified" ) ! 65: #define EPERM_INSUFFICIENT_RESOURCES \ ! 66: __einfo_error ( EINFO_EPERM_INSUFFICIENT_RESOURCES ) ! 67: #define EINFO_EPERM_INSUFFICIENT_RESOURCES EINFO_SRP_LOGIN_REJ ( \ ! 68: SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES, \ ! 69: "Insufficient RDMA channel resources" ) ! 70: #define EPERM_BAD_MAX_I_T_IU_LEN \ ! 71: __einfo_error ( EINFO_EPERM_BAD_MAX_I_T_IU_LEN ) ! 72: #define EINFO_EPERM_BAD_MAX_I_T_IU_LEN EINFO_SRP_LOGIN_REJ ( \ ! 73: SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN, \ ! 74: "Requested maximum initiator to target IU length value too large" ) ! 75: #define EPERM_CANNOT_ASSOCIATE \ ! 76: __einfo_error ( EINFO_EPERM_CANNOT_ASSOCIATE ) ! 77: #define EINFO_EPERM_CANNOT_ASSOCIATE EINFO_SRP_LOGIN_REJ ( \ ! 78: SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE, \ ! 79: "Unable to associate RDMA channel with specified I_T nexus" ) ! 80: #define EPERM_UNSUPPORTED_BUFFER_FORMAT \ ! 81: __einfo_error ( EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT ) ! 82: #define EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT EINFO_SRP_LOGIN_REJ ( \ ! 83: SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT, \ ! 84: "One or more requested data buffer descriptor formats not supported" ) ! 85: #define EPERM_NO_MULTIPLE_CHANNELS \ ! 86: __einfo_error ( EINFO_EPERM_NO_MULTIPLE_CHANNELS ) ! 87: #define EINFO_EPERM_NO_MULTIPLE_CHANNELS EINFO_SRP_LOGIN_REJ ( \ ! 88: SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS, \ ! 89: "SRP target does not support multiple RDMA channels per I_T nexus" ) ! 90: #define EPERM_NO_MORE_CHANNELS \ ! 91: __einfo_error ( EINFO_EPERM_NO_MORE_CHANNELS ) ! 92: #define EINFO_EPERM_NO_MORE_CHANNELS EINFO_SRP_LOGIN_REJ ( \ ! 93: SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS, \ ! 94: "RDMA channel limit reached for this initiator" ) ! 95: #define EPERM_LOGIN_REJ( reason_nibble ) \ ! 96: EUNIQ ( EPERM, (reason_nibble), EPERM_UNKNOWN, \ ! 97: EPERM_INSUFFICIENT_RESOURCES, EPERM_BAD_MAX_I_T_IU_LEN, \ ! 98: EPERM_CANNOT_ASSOCIATE, EPERM_UNSUPPORTED_BUFFER_FORMAT, \ ! 99: EPERM_NO_MULTIPLE_CHANNELS, EPERM_NO_MORE_CHANNELS ) ! 100: ! 101: /** An SRP device */ ! 102: struct srp_device { ! 103: /** Reference count */ ! 104: struct refcnt refcnt; ! 105: ! 106: /** SCSI command issuing interface */ ! 107: struct interface scsi; ! 108: /** Underlying data transfer interface */ ! 109: struct interface socket; ! 110: ! 111: /** RDMA memory handle */ ! 112: uint32_t memory_handle; ! 113: /** Login completed successfully */ ! 114: int logged_in; ! 115: ! 116: /** Initiator port ID (for boot firmware table) */ ! 117: union srp_port_id initiator; ! 118: /** Target port ID (for boot firmware table) */ ! 119: union srp_port_id target; ! 120: /** SCSI LUN (for boot firmware table) */ ! 121: struct scsi_lun lun; ! 122: ! 123: /** List of active commands */ ! 124: struct list_head commands; ! 125: }; ! 126: ! 127: /** An SRP command */ ! 128: struct srp_command { ! 129: /** Reference count */ ! 130: struct refcnt refcnt; ! 131: /** SRP device */ ! 132: struct srp_device *srpdev; ! 133: /** List of active commands */ ! 134: struct list_head list; ! 135: ! 136: /** SCSI command interface */ ! 137: struct interface scsi; ! 138: /** Command tag */ ! 139: uint32_t tag; ! 140: }; ! 141: ! 142: /** ! 143: * Get reference to SRP device ! 144: * ! 145: * @v srpdev SRP device ! 146: * @ret srpdev SRP device ! 147: */ ! 148: static inline __attribute__ (( always_inline )) struct srp_device * ! 149: srpdev_get ( struct srp_device *srpdev ) { ! 150: ref_get ( &srpdev->refcnt ); ! 151: return srpdev; ! 152: } ! 153: ! 154: /** ! 155: * Drop reference to SRP device ! 156: * ! 157: * @v srpdev SRP device ! 158: */ ! 159: static inline __attribute__ (( always_inline )) void ! 160: srpdev_put ( struct srp_device *srpdev ) { ! 161: ref_put ( &srpdev->refcnt ); ! 162: } ! 163: ! 164: /** ! 165: * Get reference to SRP command ! 166: * ! 167: * @v srpcmd SRP command ! 168: * @ret srpcmd SRP command ! 169: */ ! 170: static inline __attribute__ (( always_inline )) struct srp_command * ! 171: srpcmd_get ( struct srp_command *srpcmd ) { ! 172: ref_get ( &srpcmd->refcnt ); ! 173: return srpcmd; ! 174: } ! 175: ! 176: /** ! 177: * Drop reference to SRP command ! 178: * ! 179: * @v srpcmd SRP command ! 180: */ ! 181: static inline __attribute__ (( always_inline )) void ! 182: srpcmd_put ( struct srp_command *srpcmd ) { ! 183: ref_put ( &srpcmd->refcnt ); ! 184: } ! 185: ! 186: /** ! 187: * Free SRP command ! 188: * ! 189: * @v refcnt Reference count ! 190: */ ! 191: static void srpcmd_free ( struct refcnt *refcnt ) { ! 192: struct srp_command *srpcmd = ! 193: container_of ( refcnt, struct srp_command, refcnt ); ! 194: ! 195: assert ( list_empty ( &srpcmd->list ) ); ! 196: ! 197: srpdev_put ( srpcmd->srpdev ); ! 198: free ( srpcmd ); ! 199: } ! 200: ! 201: /** ! 202: * Close SRP command ! 203: * ! 204: * @v srpcmd SRP command ! 205: * @v rc Reason for close ! 206: */ ! 207: static void srpcmd_close ( struct srp_command *srpcmd, int rc ) { ! 208: struct srp_device *srpdev = srpcmd->srpdev; ! 209: ! 210: if ( rc != 0 ) { ! 211: DBGC ( srpdev, "SRP %p tag %08x closed: %s\n", ! 212: srpdev, srpcmd->tag, strerror ( rc ) ); ! 213: } ! 214: ! 215: /* Remove from list of commands */ ! 216: if ( ! list_empty ( &srpcmd->list ) ) { ! 217: list_del ( &srpcmd->list ); ! 218: INIT_LIST_HEAD ( &srpcmd->list ); ! 219: srpcmd_put ( srpcmd ); ! 220: } ! 221: ! 222: /* Shut down interfaces */ ! 223: intf_shutdown ( &srpcmd->scsi, rc ); ! 224: } ! 225: ! 226: /** ! 227: * Close SRP device ! 228: * ! 229: * @v srpdev SRP device ! 230: * @v rc Reason for close ! 231: */ ! 232: static void srpdev_close ( struct srp_device *srpdev, int rc ) { ! 233: struct srp_command *srpcmd; ! 234: struct srp_command *tmp; ! 235: ! 236: if ( rc != 0 ) { ! 237: DBGC ( srpdev, "SRP %p closed: %s\n", ! 238: srpdev, strerror ( rc ) ); ! 239: } ! 240: ! 241: /* Shut down interfaces */ ! 242: intf_shutdown ( &srpdev->socket, rc ); ! 243: intf_shutdown ( &srpdev->scsi, rc ); ! 244: ! 245: /* Shut down any active commands */ ! 246: list_for_each_entry_safe ( srpcmd, tmp, &srpdev->commands, list ) { ! 247: srpcmd_get ( srpcmd ); ! 248: srpcmd_close ( srpcmd, rc ); ! 249: srpcmd_put ( srpcmd ); ! 250: } ! 251: } ! 252: ! 253: /** ! 254: * Identify SRP command by tag ! 255: * ! 256: * @v srpdev SRP device ! 257: * @v tag Command tag ! 258: * @ret srpcmd SRP command, or NULL ! 259: */ ! 260: static struct srp_command * srp_find_tag ( struct srp_device *srpdev, ! 261: uint32_t tag ) { ! 262: struct srp_command *srpcmd; ! 263: ! 264: list_for_each_entry ( srpcmd, &srpdev->commands, list ) { ! 265: if ( srpcmd->tag == tag ) ! 266: return srpcmd; ! 267: } ! 268: return NULL; ! 269: } ! 270: ! 271: /** ! 272: * Choose an SRP command tag ! 273: * ! 274: * @v srpdev SRP device ! 275: * @ret tag New tag, or negative error ! 276: */ ! 277: static int srp_new_tag ( struct srp_device *srpdev ) { ! 278: static uint16_t tag_idx; ! 279: unsigned int i; ! 280: ! 281: for ( i = 0 ; i < 65536 ; i++ ) { ! 282: tag_idx++; ! 283: if ( srp_find_tag ( srpdev, tag_idx ) == NULL ) ! 284: return tag_idx; ! 285: } ! 286: return -EADDRINUSE; ! 287: } ! 288: ! 289: /** ! 290: * Transmit SRP login request ! 291: * ! 292: * @v srpdev SRP device ! 293: * @v initiator Initiator port ID ! 294: * @v target Target port ID ! 295: * @v tag Command tag ! 296: * @ret rc Return status code ! 297: */ ! 298: static int srp_login ( struct srp_device *srpdev, union srp_port_id *initiator, ! 299: union srp_port_id *target, uint32_t tag ) { ! 300: struct io_buffer *iobuf; ! 301: struct srp_login_req *login_req; ! 302: int rc; ! 303: ! 304: /* Allocate I/O buffer */ ! 305: iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) ); ! 306: if ( ! iobuf ) ! 307: return -ENOMEM; ! 308: ! 309: /* Construct login request IU */ ! 310: login_req = iob_put ( iobuf, sizeof ( *login_req ) ); ! 311: memset ( login_req, 0, sizeof ( *login_req ) ); ! 312: login_req->type = SRP_LOGIN_REQ; ! 313: login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC ); ! 314: login_req->tag.dwords[1] = htonl ( tag ); ! 315: login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN ); ! 316: login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD; ! 317: memcpy ( &login_req->initiator, initiator, ! 318: sizeof ( login_req->initiator ) ); ! 319: memcpy ( &login_req->target, target, sizeof ( login_req->target ) ); ! 320: ! 321: DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag ); ! 322: DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) ); ! 323: ! 324: /* Send login request IU */ ! 325: if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) { ! 326: DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: " ! 327: "%s\n", srpdev, tag, strerror ( rc ) ); ! 328: return rc; ! 329: } ! 330: ! 331: return 0; ! 332: } ! 333: ! 334: /** ! 335: * Receive SRP login response ! 336: * ! 337: * @v srpdev SRP device ! 338: * @v data SRP IU ! 339: * @v len Length of SRP IU ! 340: * @ret rc Return status code ! 341: */ ! 342: static int srp_login_rsp ( struct srp_device *srpdev, ! 343: const void *data, size_t len ) { ! 344: const struct srp_login_rsp *login_rsp = data; ! 345: ! 346: /* Sanity check */ ! 347: if ( len < sizeof ( *login_rsp ) ) { ! 348: DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n", ! 349: srpdev, len ); ! 350: return -EINVAL; ! 351: } ! 352: DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n", ! 353: srpdev, ntohl ( login_rsp->tag.dwords[1] ) ); ! 354: DBGC_HDA ( srpdev, 0, data, len ); ! 355: ! 356: /* Mark as logged in */ ! 357: srpdev->logged_in = 1; ! 358: DBGC ( srpdev, "SRP %p logged in\n", srpdev ); ! 359: ! 360: /* Notify of window change */ ! 361: xfer_window_changed ( &srpdev->scsi ); ! 362: ! 363: return 0; ! 364: } ! 365: ! 366: /** ! 367: * Receive SRP login rejection ! 368: * ! 369: * @v srpdev SRP device ! 370: * @v data SRP IU ! 371: * @v len Length of SRP IU ! 372: * @ret rc Return status code ! 373: */ ! 374: static int srp_login_rej ( struct srp_device *srpdev, ! 375: const void *data, size_t len ) { ! 376: const struct srp_login_rej *login_rej = data; ! 377: uint32_t reason; ! 378: ! 379: /* Sanity check */ ! 380: if ( len < sizeof ( *login_rej ) ) { ! 381: DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n", ! 382: srpdev, len ); ! 383: return -EINVAL; ! 384: } ! 385: reason = ntohl ( login_rej->reason ); ! 386: DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n", ! 387: srpdev, ntohl ( login_rej->tag.dwords[1] ), reason ); ! 388: DBGC_HDA ( srpdev, 0, data, len ); ! 389: ! 390: /* Login rejection always indicates an error */ ! 391: return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason ) ? ! 392: -EPERM_LOGIN_REJ ( reason ) : -EACCES ); ! 393: } ! 394: ! 395: /** ! 396: * Transmit SRP SCSI command ! 397: * ! 398: * @v srpdev SRP device ! 399: * @v command SCSI command ! 400: * @v tag Command tag ! 401: * @ret rc Return status code ! 402: */ ! 403: static int srp_cmd ( struct srp_device *srpdev, ! 404: struct scsi_cmd *command, ! 405: uint32_t tag ) { ! 406: struct io_buffer *iobuf; ! 407: struct srp_cmd *cmd; ! 408: struct srp_memory_descriptor *data_out; ! 409: struct srp_memory_descriptor *data_in; ! 410: int rc; ! 411: ! 412: /* Sanity check */ ! 413: if ( ! srpdev->logged_in ) { ! 414: DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before " ! 415: "login completes\n", srpdev, tag ); ! 416: return -EBUSY; ! 417: } ! 418: ! 419: /* Allocate I/O buffer */ ! 420: iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN ); ! 421: if ( ! iobuf ) ! 422: return -ENOMEM; ! 423: ! 424: /* Construct base portion */ ! 425: cmd = iob_put ( iobuf, sizeof ( *cmd ) ); ! 426: memset ( cmd, 0, sizeof ( *cmd ) ); ! 427: cmd->type = SRP_CMD; ! 428: cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC ); ! 429: cmd->tag.dwords[1] = htonl ( tag ); ! 430: memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) ); ! 431: memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) ); ! 432: ! 433: /* Construct data-out descriptor, if present */ ! 434: if ( command->data_out ) { ! 435: cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT; ! 436: data_out = iob_put ( iobuf, sizeof ( *data_out ) ); ! 437: data_out->address = ! 438: cpu_to_be64 ( user_to_phys ( command->data_out, 0 ) ); ! 439: data_out->handle = ntohl ( srpdev->memory_handle ); ! 440: data_out->len = ntohl ( command->data_out_len ); ! 441: } ! 442: ! 443: /* Construct data-in descriptor, if present */ ! 444: if ( command->data_in ) { ! 445: cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT; ! 446: data_in = iob_put ( iobuf, sizeof ( *data_in ) ); ! 447: data_in->address = ! 448: cpu_to_be64 ( user_to_phys ( command->data_in, 0 ) ); ! 449: data_in->handle = ntohl ( srpdev->memory_handle ); ! 450: data_in->len = ntohl ( command->data_in_len ); ! 451: } ! 452: ! 453: DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n", ! 454: srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) ); ! 455: ! 456: /* Send IU */ ! 457: if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) { ! 458: DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n", ! 459: srpdev, tag, strerror ( rc ) ); ! 460: return rc; ! 461: } ! 462: ! 463: return 0; ! 464: } ! 465: ! 466: /** ! 467: * Receive SRP SCSI response ! 468: * ! 469: * @v srpdev SRP device ! 470: * @v data SRP IU ! 471: * @v len Length of SRP IU ! 472: * @ret rc Returns status code ! 473: */ ! 474: static int srp_rsp ( struct srp_device *srpdev, ! 475: const void *data, size_t len ) { ! 476: const struct srp_rsp *rsp = data; ! 477: struct srp_command *srpcmd; ! 478: struct scsi_rsp response; ! 479: const void *sense; ! 480: ssize_t data_out_residual_count; ! 481: ssize_t data_in_residual_count; ! 482: ! 483: /* Sanity check */ ! 484: if ( len < sizeof ( *rsp ) ) { ! 485: DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n", ! 486: srpdev, len ); ! 487: return -EINVAL; ! 488: } ! 489: DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires " ! 490: "%08x valid %02x%s%s%s%s%s%s\n", ! 491: srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status, ! 492: ntohl ( rsp->data_out_residual_count ), ! 493: ntohl ( rsp->data_in_residual_count ), rsp->valid, ! 494: ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ), ! 495: ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ), ! 496: ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ), ! 497: ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ), ! 498: ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ), ! 499: ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) ); ! 500: ! 501: /* Identify command by tag */ ! 502: srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) ); ! 503: if ( ! srpcmd ) { ! 504: DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n", ! 505: srpdev, ntohl ( rsp->tag.dwords[1] ) ); ! 506: return -ENOENT; ! 507: } ! 508: ! 509: /* Hold command reference for remainder of function */ ! 510: srpcmd_get ( srpcmd ); ! 511: ! 512: /* Build SCSI response */ ! 513: memset ( &response, 0, sizeof ( response ) ); ! 514: response.status = rsp->status; ! 515: data_out_residual_count = ntohl ( rsp->data_out_residual_count ); ! 516: data_in_residual_count = ntohl ( rsp->data_in_residual_count ); ! 517: if ( rsp->valid & SRP_RSP_VALID_DOOVER ) { ! 518: response.overrun = data_out_residual_count; ! 519: } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) { ! 520: response.overrun = -(data_out_residual_count); ! 521: } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) { ! 522: response.overrun = data_in_residual_count; ! 523: } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) { ! 524: response.overrun = -(data_in_residual_count); ! 525: } ! 526: sense = srp_rsp_sense_data ( rsp ); ! 527: if ( sense ) ! 528: memcpy ( &response.sense, sense, sizeof ( response.sense ) ); ! 529: ! 530: /* Report SCSI response */ ! 531: scsi_response ( &srpcmd->scsi, &response ); ! 532: ! 533: /* Close SCSI command */ ! 534: srpcmd_close ( srpcmd, 0 ); ! 535: ! 536: /* Drop temporary command reference */ ! 537: srpcmd_put ( srpcmd ); ! 538: ! 539: return 0; ! 540: } ! 541: ! 542: /** ! 543: * Receive SRP unrecognised response IU ! 544: * ! 545: * @v srpdev SRP device ! 546: * @v data SRP IU ! 547: * @v len Length of SRP IU ! 548: * @ret rc Returns status code ! 549: */ ! 550: static int srp_unrecognised ( struct srp_device *srpdev, ! 551: const void *data, size_t len ) { ! 552: const struct srp_common *common = data; ! 553: ! 554: DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n", ! 555: srpdev, ntohl ( common->tag.dwords[1] ), common->type ); ! 556: DBGC_HDA ( srpdev, 0, data, len ); ! 557: ! 558: return -ENOTSUP; ! 559: } ! 560: ! 561: /** SRP command SCSI interface operations */ ! 562: static struct interface_operation srpcmd_scsi_op[] = { ! 563: INTF_OP ( intf_close, struct srp_command *, srpcmd_close ), ! 564: }; ! 565: ! 566: /** SRP command SCSI interface descriptor */ ! 567: static struct interface_descriptor srpcmd_scsi_desc = ! 568: INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op ); ! 569: ! 570: /** ! 571: * Issue SRP SCSI command ! 572: * ! 573: * @v srpdev SRP device ! 574: * @v parent Parent interface ! 575: * @v command SCSI command ! 576: * @ret tag Command tag, or negative error ! 577: */ ! 578: static int srpdev_scsi_command ( struct srp_device *srpdev, ! 579: struct interface *parent, ! 580: struct scsi_cmd *command ) { ! 581: struct srp_command *srpcmd; ! 582: int tag; ! 583: int rc; ! 584: ! 585: /* Allocate command tag */ ! 586: tag = srp_new_tag ( srpdev ); ! 587: if ( tag < 0 ) { ! 588: rc = tag; ! 589: goto err_tag; ! 590: } ! 591: ! 592: /* Allocate and initialise structure */ ! 593: srpcmd = zalloc ( sizeof ( *srpcmd ) ); ! 594: if ( ! srpcmd ) { ! 595: rc = -ENOMEM; ! 596: goto err_zalloc; ! 597: } ! 598: ref_init ( &srpcmd->refcnt, srpcmd_free ); ! 599: intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt ); ! 600: srpcmd->srpdev = srpdev_get ( srpdev ); ! 601: list_add ( &srpcmd->list, &srpdev->commands ); ! 602: srpcmd->tag = tag; ! 603: ! 604: /* Send command IU */ ! 605: if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 ) ! 606: goto err_cmd; ! 607: ! 608: /* Attach to parent interface, leave reference with command ! 609: * list, and return. ! 610: */ ! 611: intf_plug_plug ( &srpcmd->scsi, parent ); ! 612: return srpcmd->tag; ! 613: ! 614: err_cmd: ! 615: srpcmd_close ( srpcmd, rc ); ! 616: err_zalloc: ! 617: err_tag: ! 618: return rc; ! 619: } ! 620: ! 621: /** ! 622: * Receive data from SRP socket ! 623: * ! 624: * @v srpdev SRP device ! 625: * @v iobuf Datagram I/O buffer ! 626: * @v meta Data transfer metadata ! 627: * @ret rc Return status code ! 628: */ ! 629: static int srpdev_deliver ( struct srp_device *srpdev, ! 630: struct io_buffer *iobuf, ! 631: struct xfer_metadata *meta __unused ) { ! 632: struct srp_common *common = iobuf->data; ! 633: int ( * type ) ( struct srp_device *srp, const void *data, size_t len ); ! 634: int rc; ! 635: ! 636: /* Sanity check */ ! 637: if ( iob_len ( iobuf ) < sizeof ( *common ) ) { ! 638: DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n", ! 639: srpdev, iob_len ( iobuf ) ); ! 640: rc = -EINVAL; ! 641: goto err; ! 642: } ! 643: ! 644: /* Determine IU type */ ! 645: switch ( common->type ) { ! 646: case SRP_LOGIN_RSP: ! 647: type = srp_login_rsp; ! 648: break; ! 649: case SRP_LOGIN_REJ: ! 650: type = srp_login_rej; ! 651: break; ! 652: case SRP_RSP: ! 653: type = srp_rsp; ! 654: break; ! 655: default: ! 656: type = srp_unrecognised; ! 657: break; ! 658: } ! 659: ! 660: /* Handle IU */ ! 661: if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 ) ! 662: goto err; ! 663: ! 664: free_iob ( iobuf ); ! 665: return 0; ! 666: ! 667: err: ! 668: DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n", ! 669: srpdev, strerror ( rc ) ); ! 670: DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) ); ! 671: free_iob ( iobuf ); ! 672: srpdev_close ( srpdev, rc ); ! 673: return rc; ! 674: } ! 675: ! 676: /** ! 677: * Check SRP device flow-control window ! 678: * ! 679: * @v srpdev SRP device ! 680: * @ret len Length of window ! 681: */ ! 682: static size_t srpdev_window ( struct srp_device *srpdev ) { ! 683: return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 ); ! 684: } ! 685: ! 686: /** ! 687: * A (transport-independent) sBFT created by iPXE ! 688: */ ! 689: struct ipxe_sbft { ! 690: /** The table header */ ! 691: struct sbft_table table; ! 692: /** The SCSI subtable */ ! 693: struct sbft_scsi_subtable scsi; ! 694: /** The SRP subtable */ ! 695: struct sbft_srp_subtable srp; ! 696: } __attribute__ (( packed, aligned ( 16 ) )); ! 697: ! 698: /** ! 699: * Describe SRP device in an ACPI table ! 700: * ! 701: * @v srpdev SRP device ! 702: * @v acpi ACPI table ! 703: * @v len Length of ACPI table ! 704: * @ret rc Return status code ! 705: */ ! 706: static int srpdev_describe ( struct srp_device *srpdev, ! 707: struct acpi_description_header *acpi, ! 708: size_t len ) { ! 709: struct ipxe_sbft *sbft = ! 710: container_of ( acpi, struct ipxe_sbft, table.acpi ); ! 711: int rc; ! 712: ! 713: /* Sanity check */ ! 714: if ( len < sizeof ( *sbft ) ) ! 715: return -ENOBUFS; ! 716: ! 717: /* Populate table */ ! 718: sbft->table.acpi.signature = cpu_to_le32 ( SBFT_SIG ); ! 719: sbft->table.acpi.length = cpu_to_le32 ( sizeof ( *sbft ) ); ! 720: sbft->table.acpi.revision = 1; ! 721: sbft->table.scsi_offset = ! 722: cpu_to_le16 ( offsetof ( typeof ( *sbft ), scsi ) ); ! 723: memcpy ( &sbft->scsi.lun, &srpdev->lun, sizeof ( sbft->scsi.lun ) ); ! 724: sbft->table.srp_offset = ! 725: cpu_to_le16 ( offsetof ( typeof ( *sbft ), srp ) ); ! 726: memcpy ( &sbft->srp.initiator, &srpdev->initiator, ! 727: sizeof ( sbft->srp.initiator ) ); ! 728: memcpy ( &sbft->srp.target, &srpdev->target, ! 729: sizeof ( sbft->srp.target ) ); ! 730: ! 731: /* Ask transport layer to describe transport-specific portions */ ! 732: if ( ( rc = acpi_describe ( &srpdev->socket, acpi, len ) ) != 0 ) { ! 733: DBGC ( srpdev, "SRP %p cannot describe transport layer: %s\n", ! 734: srpdev, strerror ( rc ) ); ! 735: return rc; ! 736: } ! 737: ! 738: return 0; ! 739: } ! 740: ! 741: /** SRP device socket interface operations */ ! 742: static struct interface_operation srpdev_socket_op[] = { ! 743: INTF_OP ( xfer_deliver, struct srp_device *, srpdev_deliver ), ! 744: INTF_OP ( intf_close, struct srp_device *, srpdev_close ), ! 745: }; ! 746: ! 747: /** SRP device socket interface descriptor */ ! 748: static struct interface_descriptor srpdev_socket_desc = ! 749: INTF_DESC_PASSTHRU ( struct srp_device, socket, srpdev_socket_op, ! 750: scsi ); ! 751: ! 752: /** SRP device SCSI interface operations */ ! 753: static struct interface_operation srpdev_scsi_op[] = { ! 754: INTF_OP ( scsi_command, struct srp_device *, srpdev_scsi_command ), ! 755: INTF_OP ( xfer_window, struct srp_device *, srpdev_window ), ! 756: INTF_OP ( intf_close, struct srp_device *, srpdev_close ), ! 757: INTF_OP ( acpi_describe, struct srp_device *, srpdev_describe ), ! 758: }; ! 759: ! 760: /** SRP device SCSI interface descriptor */ ! 761: static struct interface_descriptor srpdev_scsi_desc = ! 762: INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket ); ! 763: ! 764: /** ! 765: * Open SRP device ! 766: * ! 767: * @v block Block control interface ! 768: * @v socket Socket interface ! 769: * @v initiator Initiator port ID ! 770: * @v target Target port ID ! 771: * @v memory_handle RDMA memory handle ! 772: * @v lun SCSI LUN ! 773: * @ret rc Return status code ! 774: */ ! 775: int srp_open ( struct interface *block, struct interface *socket, ! 776: union srp_port_id *initiator, union srp_port_id *target, ! 777: uint32_t memory_handle, struct scsi_lun *lun ) { ! 778: struct srp_device *srpdev; ! 779: int tag; ! 780: int rc; ! 781: ! 782: /* Allocate and initialise structure */ ! 783: srpdev = zalloc ( sizeof ( *srpdev ) ); ! 784: if ( ! srpdev ) { ! 785: rc = -ENOMEM; ! 786: goto err_zalloc; ! 787: } ! 788: ref_init ( &srpdev->refcnt, NULL ); ! 789: intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt ); ! 790: intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt ); ! 791: INIT_LIST_HEAD ( &srpdev->commands ); ! 792: srpdev->memory_handle = memory_handle; ! 793: DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev, ! 794: ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ), ! 795: ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ), ! 796: ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ), ! 797: ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) ); ! 798: ! 799: /* Preserve parameters required for boot firmware table */ ! 800: memcpy ( &srpdev->initiator, initiator, sizeof ( srpdev->initiator ) ); ! 801: memcpy ( &srpdev->target, target, sizeof ( srpdev->target ) ); ! 802: memcpy ( &srpdev->lun, lun, sizeof ( srpdev->lun ) ); ! 803: ! 804: /* Attach to socket interface and initiate login */ ! 805: intf_plug_plug ( &srpdev->socket, socket ); ! 806: tag = srp_new_tag ( srpdev ); ! 807: assert ( tag >= 0 ); /* Cannot fail when no commands in progress */ ! 808: if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 ) ! 809: goto err_login; ! 810: ! 811: /* Attach SCSI device to parent interface */ ! 812: if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) { ! 813: DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n", ! 814: srpdev, strerror ( rc ) ); ! 815: goto err_scsi_open; ! 816: } ! 817: ! 818: /* Mortalise self and return */ ! 819: ref_put ( &srpdev->refcnt ); ! 820: return 0; ! 821: ! 822: err_scsi_open: ! 823: err_login: ! 824: srpdev_close ( srpdev, rc ); ! 825: ref_put ( &srpdev->refcnt ); ! 826: err_zalloc: ! 827: return rc; ! 828: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.