|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2010 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stddef.h> ! 22: #include <stdint.h> ! 23: #include <stdlib.h> ! 24: #include <string.h> ! 25: #include <errno.h> ! 26: #include <stdio.h> ! 27: #include <assert.h> ! 28: #include <byteswap.h> ! 29: #include <ipxe/refcnt.h> ! 30: #include <ipxe/list.h> ! 31: #include <ipxe/interface.h> ! 32: #include <ipxe/xfer.h> ! 33: #include <ipxe/iobuf.h> ! 34: #include <ipxe/open.h> ! 35: #include <ipxe/process.h> ! 36: #include <ipxe/uri.h> ! 37: #include <ipxe/acpi.h> ! 38: #include <ipxe/scsi.h> ! 39: #include <ipxe/device.h> ! 40: #include <ipxe/edd.h> ! 41: #include <ipxe/fc.h> ! 42: #include <ipxe/fcels.h> ! 43: #include <ipxe/fcp.h> ! 44: ! 45: /** @file ! 46: * ! 47: * Fibre Channel Protocol ! 48: * ! 49: */ ! 50: ! 51: /* Disambiguate the various error causes */ ! 52: #define ERANGE_READ_DATA_ORDERING \ ! 53: __einfo_error ( EINFO_ERANGE_READ_DATA_ORDERING ) ! 54: #define EINFO_ERANGE_READ_DATA_ORDERING \ ! 55: __einfo_uniqify ( EINFO_ERANGE, 0x01, "Read data out of order" ) ! 56: #define ERANGE_READ_DATA_OVERRUN \ ! 57: __einfo_error ( EINFO_ERANGE_READ_DATA_OVERRUN ) ! 58: #define EINFO_ERANGE_READ_DATA_OVERRUN \ ! 59: __einfo_uniqify ( EINFO_ERANGE, 0x02, "Read data overrun" ) ! 60: #define ERANGE_WRITE_DATA_STUCK \ ! 61: __einfo_error ( EINFO_ERANGE_WRITE_DATA_STUCK ) ! 62: #define EINFO_ERANGE_WRITE_DATA_STUCK \ ! 63: __einfo_uniqify ( EINFO_ERANGE, 0x03, "Write data stuck" ) ! 64: #define ERANGE_WRITE_DATA_OVERRUN \ ! 65: __einfo_error ( EINFO_ERANGE_WRITE_DATA_OVERRUN ) ! 66: #define EINFO_ERANGE_WRITE_DATA_OVERRUN \ ! 67: __einfo_uniqify ( EINFO_ERANGE, 0x04, "Write data overrun" ) ! 68: #define ERANGE_DATA_UNDERRUN \ ! 69: __einfo_error ( EINFO_ERANGE_DATA_UNDERRUN ) ! 70: #define EINFO_ERANGE_DATA_UNDERRUN \ ! 71: __einfo_uniqify ( EINFO_ERANGE, 0x05, "Data underrun" ) ! 72: ! 73: /****************************************************************************** ! 74: * ! 75: * PRLI ! 76: * ! 77: ****************************************************************************** ! 78: */ ! 79: ! 80: struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor; ! 81: ! 82: /** ! 83: * Transmit FCP PRLI ! 84: * ! 85: * @v els Fibre Channel ELS transaction ! 86: * @ret rc Return status code ! 87: */ ! 88: static int fcp_prli_tx ( struct fc_els *els ) { ! 89: struct fcp_prli_service_parameters param; ! 90: ! 91: /* Build service parameter page */ ! 92: memset ( ¶m, 0, sizeof ( param ) ); ! 93: param.flags = htonl ( FCP_PRLI_NO_READ_RDY | FCP_PRLI_INITIATOR ); ! 94: ! 95: return fc_els_prli_tx ( els, &fcp_prli_descriptor, ¶m ); ! 96: } ! 97: ! 98: /** ! 99: * Receive FCP PRLI ! 100: * ! 101: * @v els Fibre Channel ELS transaction ! 102: * @v frame ELS frame ! 103: * @v len Length of ELS frame ! 104: * @ret rc Return status code ! 105: */ ! 106: static int fcp_prli_rx ( struct fc_els *els, void *data, size_t len ) { ! 107: return fc_els_prli_rx ( els, &fcp_prli_descriptor, data, len ); ! 108: } ! 109: ! 110: /** ! 111: * Detect FCP PRLI ! 112: * ! 113: * @v els Fibre Channel ELS transaction ! 114: * @v data ELS frame ! 115: * @v len Length of ELS frame ! 116: * @ret rc Return status code ! 117: */ ! 118: static int fcp_prli_detect ( struct fc_els *els, const void *data, ! 119: size_t len ) { ! 120: return fc_els_prli_detect ( els, &fcp_prli_descriptor, data, len ); ! 121: } ! 122: ! 123: /** FCP PRLI ELS handler */ ! 124: struct fc_els_handler fcp_prli_handler __fc_els_handler = { ! 125: .name = "PRLI-FCP", ! 126: .tx = fcp_prli_tx, ! 127: .rx = fcp_prli_rx, ! 128: .detect = fcp_prli_detect, ! 129: }; ! 130: ! 131: /** FCP PRLI descriptor */ ! 132: struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor = { ! 133: .type = FC_TYPE_FCP, ! 134: .param_len = sizeof ( struct fcp_prli_service_parameters ), ! 135: .handler = &fcp_prli_handler, ! 136: }; ! 137: ! 138: /****************************************************************************** ! 139: * ! 140: * FCP devices and commands ! 141: * ! 142: ****************************************************************************** ! 143: */ ! 144: ! 145: /** An FCP device */ ! 146: struct fcp_device { ! 147: /** Reference count */ ! 148: struct refcnt refcnt; ! 149: /** Fibre Channel upper-layer protocol */ ! 150: struct fc_ulp *ulp; ! 151: /** SCSI command issuing interface */ ! 152: struct interface scsi; ! 153: /** List of active commands */ ! 154: struct list_head fcpcmds; ! 155: ! 156: /** Fibre Channel WWN (for boot firmware table) */ ! 157: struct fc_name wwn; ! 158: /** SCSI LUN (for boot firmware table) */ ! 159: struct scsi_lun lun; ! 160: }; ! 161: ! 162: /** An FCP command */ ! 163: struct fcp_command { ! 164: /** Reference count */ ! 165: struct refcnt refcnt; ! 166: /** FCP SCSI device */ ! 167: struct fcp_device *fcpdev; ! 168: /** List of active commands */ ! 169: struct list_head list; ! 170: /** SCSI command interface */ ! 171: struct interface scsi; ! 172: /** Fibre Channel exchange interface */ ! 173: struct interface xchg; ! 174: /** Send process */ ! 175: struct process process; ! 176: /** Send current IU ! 177: * ! 178: * @v fcpcmd FCP command ! 179: * @ret rc Return status code ! 180: */ ! 181: int ( * send ) ( struct fcp_command *fcpcmd ); ! 182: /** SCSI command */ ! 183: struct scsi_cmd command; ! 184: /** Data offset within command */ ! 185: size_t offset; ! 186: /** Length of data remaining to be sent within this IU */ ! 187: size_t remaining; ! 188: /** Exchange ID */ ! 189: uint16_t xchg_id; ! 190: }; ! 191: ! 192: /** ! 193: * Get reference to FCP device ! 194: * ! 195: * @v fcpdev FCP device ! 196: * @ret fcpdev FCP device ! 197: */ ! 198: static inline __attribute__ (( always_inline )) struct fcp_device * ! 199: fcpdev_get ( struct fcp_device *fcpdev ) { ! 200: ref_get ( &fcpdev->refcnt ); ! 201: return fcpdev; ! 202: } ! 203: ! 204: /** ! 205: * Drop reference to FCP device ! 206: * ! 207: * @v fcpdev FCP device ! 208: */ ! 209: static inline __attribute__ (( always_inline )) void ! 210: fcpdev_put ( struct fcp_device *fcpdev ) { ! 211: ref_put ( &fcpdev->refcnt ); ! 212: } ! 213: ! 214: /** ! 215: * Get reference to FCP command ! 216: * ! 217: * @v fcpcmd FCP command ! 218: * @ret fcpcmd FCP command ! 219: */ ! 220: static inline __attribute__ (( always_inline )) struct fcp_command * ! 221: fcpcmd_get ( struct fcp_command *fcpcmd ) { ! 222: ref_get ( &fcpcmd->refcnt ); ! 223: return fcpcmd; ! 224: } ! 225: ! 226: /** ! 227: * Drop reference to FCP command ! 228: * ! 229: * @v fcpcmd FCP command ! 230: */ ! 231: static inline __attribute__ (( always_inline )) void ! 232: fcpcmd_put ( struct fcp_command *fcpcmd ) { ! 233: ref_put ( &fcpcmd->refcnt ); ! 234: } ! 235: ! 236: /** ! 237: * Start FCP command sending ! 238: * ! 239: * @v fcpcmd FCP command ! 240: * @v send Send method ! 241: */ ! 242: static inline __attribute__ (( always_inline )) void ! 243: fcpcmd_start_send ( struct fcp_command *fcpcmd, ! 244: int ( * send ) ( struct fcp_command *fcpcmd ) ) { ! 245: fcpcmd->send = send; ! 246: process_add ( &fcpcmd->process ); ! 247: } ! 248: ! 249: /** ! 250: * Stop FCP command sending ! 251: * ! 252: * @v fcpcmd FCP command ! 253: */ ! 254: static inline __attribute__ (( always_inline )) void ! 255: fcpcmd_stop_send ( struct fcp_command *fcpcmd ) { ! 256: process_del ( &fcpcmd->process ); ! 257: } ! 258: ! 259: /** ! 260: * Free FCP command ! 261: * ! 262: * @v refcnt Reference count ! 263: */ ! 264: static void fcpcmd_free ( struct refcnt *refcnt ) { ! 265: struct fcp_command *fcpcmd = ! 266: container_of ( refcnt, struct fcp_command, refcnt ); ! 267: ! 268: /* Remove from list of commands */ ! 269: list_del ( &fcpcmd->list ); ! 270: fcpdev_put ( fcpcmd->fcpdev ); ! 271: ! 272: /* Free command */ ! 273: free ( fcpcmd ); ! 274: } ! 275: ! 276: /** ! 277: * Close FCP command ! 278: * ! 279: * @v fcpcmd FCP command ! 280: * @v rc Reason for close ! 281: */ ! 282: static void fcpcmd_close ( struct fcp_command *fcpcmd, int rc ) { ! 283: struct fcp_device *fcpdev = fcpcmd->fcpdev; ! 284: ! 285: if ( rc != 0 ) { ! 286: DBGC ( fcpdev, "FCP %p xchg %04x closed: %s\n", ! 287: fcpdev, fcpcmd->xchg_id, strerror ( rc ) ); ! 288: } ! 289: ! 290: /* Stop sending */ ! 291: fcpcmd_stop_send ( fcpcmd ); ! 292: ! 293: /* Shut down interfaces */ ! 294: intf_shutdown ( &fcpcmd->scsi, rc ); ! 295: intf_shutdown ( &fcpcmd->xchg, rc ); ! 296: } ! 297: ! 298: /** ! 299: * Close FCP command in error ! 300: * ! 301: * @v fcpcmd FCP command ! 302: * @v rc Reason for close ! 303: */ ! 304: static void fcpcmd_close_err ( struct fcp_command *fcpcmd, int rc ) { ! 305: if ( rc == 0 ) ! 306: rc = -EPIPE; ! 307: fcpcmd_close ( fcpcmd, rc ); ! 308: } ! 309: ! 310: /** ! 311: * Send FCP command IU ! 312: * ! 313: * @v fcpcmd FCP command ! 314: * @ret rc Return status code ! 315: */ ! 316: static int fcpcmd_send_cmnd ( struct fcp_command *fcpcmd ) { ! 317: struct fcp_device *fcpdev = fcpcmd->fcpdev; ! 318: struct scsi_cmd *command = &fcpcmd->command; ! 319: struct io_buffer *iobuf; ! 320: struct fcp_cmnd *cmnd; ! 321: struct xfer_metadata meta; ! 322: int rc; ! 323: ! 324: /* Sanity check */ ! 325: if ( command->data_in_len && command->data_out_len ) { ! 326: DBGC ( fcpdev, "FCP %p xchg %04x cannot handle bidirectional " ! 327: "command\n", fcpdev, fcpcmd->xchg_id ); ! 328: return -ENOTSUP; ! 329: } ! 330: ! 331: /* Allocate I/O buffer */ ! 332: iobuf = xfer_alloc_iob ( &fcpcmd->xchg, sizeof ( *cmnd ) ); ! 333: if ( ! iobuf ) { ! 334: DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate command IU\n", ! 335: fcpdev, fcpcmd->xchg_id ); ! 336: return -ENOMEM; ! 337: } ! 338: ! 339: /* Construct command IU frame */ ! 340: cmnd = iob_put ( iobuf, sizeof ( *cmnd ) ); ! 341: memset ( cmnd, 0, sizeof ( *cmnd ) ); ! 342: memcpy ( &cmnd->lun, &command->lun, sizeof ( cmnd->lun ) ); ! 343: assert ( ! ( command->data_in_len && command->data_out_len ) ); ! 344: if ( command->data_in_len ) ! 345: cmnd->dirn |= FCP_CMND_RDDATA; ! 346: if ( command->data_out_len ) ! 347: cmnd->dirn |= FCP_CMND_WRDATA; ! 348: memcpy ( &cmnd->cdb, &fcpcmd->command.cdb, sizeof ( cmnd->cdb ) ); ! 349: cmnd->len = htonl ( command->data_in_len + command->data_out_len ); ! 350: memset ( &meta, 0, sizeof ( meta ) ); ! 351: meta.flags = ( XFER_FL_CMD_STAT | XFER_FL_OVER ); ! 352: DBGC2 ( fcpdev, "FCP %p xchg %04x CMND " SCSI_CDB_FORMAT " %04x\n", ! 353: fcpdev, fcpcmd->xchg_id, SCSI_CDB_DATA ( cmnd->cdb ), ! 354: ntohl ( cmnd->len ) ); ! 355: ! 356: /* No further data to send within this IU */ ! 357: fcpcmd_stop_send ( fcpcmd ); ! 358: ! 359: /* Send command IU frame */ ! 360: if ( ( rc = xfer_deliver ( &fcpcmd->xchg, iob_disown ( iobuf ), ! 361: &meta ) ) != 0 ) { ! 362: DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver command IU: " ! 363: "%s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) ); ! 364: return rc; ! 365: } ! 366: ! 367: return 0; ! 368: } ! 369: ! 370: /** ! 371: * Handle FCP read data IU ! 372: * ! 373: * @v fcpcmd FCP command ! 374: * @v iobuf I/O buffer ! 375: * @v meta Data transfer metadata ! 376: * @ret rc Return status code ! 377: */ ! 378: static int fcpcmd_recv_rddata ( struct fcp_command *fcpcmd, ! 379: struct io_buffer *iobuf, ! 380: struct xfer_metadata *meta ) { ! 381: struct fcp_device *fcpdev = fcpcmd->fcpdev; ! 382: struct scsi_cmd *command = &fcpcmd->command; ! 383: size_t offset = meta->offset; ! 384: size_t len = iob_len ( iobuf ); ! 385: int rc; ! 386: ! 387: /* Sanity checks */ ! 388: if ( ! ( meta->flags & XFER_FL_ABS_OFFSET ) ) { ! 389: DBGC ( fcpdev, "FCP %p xchg %04x read data missing offset\n", ! 390: fcpdev, fcpcmd->xchg_id ); ! 391: rc = -ERANGE_READ_DATA_ORDERING; ! 392: goto done; ! 393: } ! 394: if ( offset != fcpcmd->offset ) { ! 395: DBGC ( fcpdev, "FCP %p xchg %04x read data out of order " ! 396: "(expected %zd, received %zd)\n", ! 397: fcpdev, fcpcmd->xchg_id, fcpcmd->offset, offset ); ! 398: rc = -ERANGE_READ_DATA_ORDERING; ! 399: goto done; ! 400: } ! 401: if ( ( offset + len ) > command->data_in_len ) { ! 402: DBGC ( fcpdev, "FCP %p xchg %04x read data overrun (max %zd, " ! 403: "received %zd)\n", fcpdev, fcpcmd->xchg_id, ! 404: command->data_in_len, ( offset + len ) ); ! 405: rc = -ERANGE_READ_DATA_OVERRUN; ! 406: goto done; ! 407: } ! 408: DBGC2 ( fcpdev, "FCP %p xchg %04x RDDATA [%08zx,%08zx)\n", ! 409: fcpdev, fcpcmd->xchg_id, offset, ( offset + len ) ); ! 410: ! 411: /* Copy to user buffer */ ! 412: copy_to_user ( command->data_in, offset, iobuf->data, len ); ! 413: fcpcmd->offset += len; ! 414: assert ( fcpcmd->offset <= command->data_in_len ); ! 415: ! 416: rc = 0; ! 417: done: ! 418: free_iob ( iobuf ); ! 419: return rc; ! 420: } ! 421: ! 422: /** ! 423: * Send FCP write data IU ! 424: * ! 425: * @v fcpcmd FCP command ! 426: * @ret rc Return status code ! 427: */ ! 428: static int fcpcmd_send_wrdata ( struct fcp_command *fcpcmd ) { ! 429: struct fcp_device *fcpdev = fcpcmd->fcpdev; ! 430: struct scsi_cmd *command = &fcpcmd->command; ! 431: struct io_buffer *iobuf; ! 432: struct xfer_metadata meta; ! 433: size_t len; ! 434: int rc; ! 435: ! 436: /* Calculate length to be sent */ ! 437: len = xfer_window ( &fcpcmd->xchg ); ! 438: if ( len > fcpcmd->remaining ) ! 439: len = fcpcmd->remaining; ! 440: ! 441: /* Sanity checks */ ! 442: if ( len == 0 ) { ! 443: DBGC ( fcpdev, "FCP %p xchg %04x write data stuck\n", ! 444: fcpdev, fcpcmd->xchg_id ); ! 445: return -ERANGE_WRITE_DATA_STUCK; ! 446: } ! 447: if ( ( fcpcmd->offset + len ) > command->data_out_len ) { ! 448: DBGC ( fcpdev, "FCP %p xchg %04x write data overrun (max %zd, " ! 449: "requested %zd)\n", fcpdev, fcpcmd->xchg_id, ! 450: command->data_out_len, ( fcpcmd->offset + len ) ); ! 451: return -ERANGE_WRITE_DATA_OVERRUN; ! 452: } ! 453: ! 454: /* Allocate I/O buffer */ ! 455: iobuf = xfer_alloc_iob ( &fcpcmd->xchg, len ); ! 456: if ( ! iobuf ) { ! 457: DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate write data " ! 458: "IU for %zd bytes\n", fcpdev, fcpcmd->xchg_id, len ); ! 459: return -ENOMEM; ! 460: } ! 461: ! 462: /* Construct data IU frame */ ! 463: copy_from_user ( iob_put ( iobuf, len ), command->data_out, ! 464: fcpcmd->offset, len ); ! 465: memset ( &meta, 0, sizeof ( meta ) ); ! 466: meta.flags = ( XFER_FL_RESPONSE | XFER_FL_ABS_OFFSET ); ! 467: meta.offset = fcpcmd->offset; ! 468: DBGC2 ( fcpdev, "FCP %p xchg %04x WRDATA [%08zx,%04zx)\n", ! 469: fcpdev, fcpcmd->xchg_id, fcpcmd->offset, ! 470: ( fcpcmd->offset + iob_len ( iobuf ) ) ); ! 471: ! 472: /* Calculate amount of data remaining to be sent within this IU */ ! 473: assert ( len <= fcpcmd->remaining ); ! 474: fcpcmd->offset += len; ! 475: fcpcmd->remaining -= len; ! 476: assert ( fcpcmd->offset <= command->data_out_len ); ! 477: if ( fcpcmd->remaining == 0 ) { ! 478: fcpcmd_stop_send ( fcpcmd ); ! 479: meta.flags |= XFER_FL_OVER; ! 480: } ! 481: ! 482: /* Send data IU frame */ ! 483: if ( ( rc = xfer_deliver ( &fcpcmd->xchg, iob_disown ( iobuf ), ! 484: &meta ) ) != 0 ) { ! 485: DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver write data " ! 486: "IU: %s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) ); ! 487: return rc; ! 488: } ! 489: ! 490: return 0; ! 491: } ! 492: ! 493: /** ! 494: * Handle FCP transfer ready IU ! 495: * ! 496: * @v fcpcmd FCP command ! 497: * @v iobuf I/O buffer ! 498: * @v meta Data transfer metadata ! 499: * @ret rc Return status code ! 500: */ ! 501: static int fcpcmd_recv_xfer_rdy ( struct fcp_command *fcpcmd, ! 502: struct io_buffer *iobuf, ! 503: struct xfer_metadata *meta __unused ) { ! 504: struct fcp_device *fcpdev = fcpcmd->fcpdev; ! 505: struct fcp_xfer_rdy *xfer_rdy = iobuf->data; ! 506: int rc; ! 507: ! 508: /* Sanity checks */ ! 509: if ( iob_len ( iobuf ) != sizeof ( *xfer_rdy ) ) { ! 510: DBGC ( fcpdev, "FCP %p xchg %04x received invalid transfer " ! 511: "ready IU:\n", fcpdev, fcpcmd->xchg_id ); ! 512: DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) ); ! 513: rc = -EPROTO; ! 514: goto done; ! 515: } ! 516: if ( ntohl ( xfer_rdy->offset ) != fcpcmd->offset ) { ! 517: /* We do not advertise out-of-order delivery */ ! 518: DBGC ( fcpdev, "FCP %p xchg %04x cannot support out-of-order " ! 519: "delivery (expected %zd, requested %d)\n", ! 520: fcpdev, fcpcmd->xchg_id, fcpcmd->offset, ! 521: ntohl ( xfer_rdy->offset ) ); ! 522: rc = -EPROTO; ! 523: goto done; ! 524: } ! 525: DBGC2 ( fcpdev, "FCP %p xchg %04x XFER_RDY [%08x,%08x)\n", ! 526: fcpdev, fcpcmd->xchg_id, ntohl ( xfer_rdy->offset ), ! 527: ( ntohl ( xfer_rdy->offset ) + ntohl ( xfer_rdy->len ) ) ); ! 528: ! 529: /* Start sending requested data */ ! 530: fcpcmd->remaining = ntohl ( xfer_rdy->len ); ! 531: fcpcmd_start_send ( fcpcmd, fcpcmd_send_wrdata ); ! 532: ! 533: rc = 0; ! 534: done: ! 535: free_iob ( iobuf ); ! 536: return rc; ! 537: } ! 538: ! 539: /** ! 540: * Handle FCP response IU ! 541: * ! 542: * @v fcpcmd FCP command ! 543: * @v iobuf I/O buffer ! 544: * @v meta Data transfer metadata ! 545: * @ret rc Return status code ! 546: */ ! 547: static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd, ! 548: struct io_buffer *iobuf, ! 549: struct xfer_metadata *meta __unused ) { ! 550: struct fcp_device *fcpdev = fcpcmd->fcpdev; ! 551: struct scsi_cmd *command = &fcpcmd->command; ! 552: struct fcp_rsp *rsp = iobuf->data; ! 553: struct scsi_sense *sense; ! 554: struct scsi_rsp response; ! 555: int rc; ! 556: ! 557: /* Sanity check */ ! 558: if ( ( iob_len ( iobuf ) < sizeof ( *rsp ) ) || ! 559: ( iob_len ( iobuf ) < ( sizeof ( *rsp ) + ! 560: fcp_rsp_response_data_len ( rsp ) + ! 561: fcp_rsp_sense_data_len ( rsp ) ) ) ) { ! 562: DBGC ( fcpdev, "FCP %p xchg %04x received invalid response " ! 563: "IU:\n", fcpdev, fcpcmd->xchg_id ); ! 564: DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) ); ! 565: rc = -EPROTO; ! 566: goto done; ! 567: } ! 568: DBGC2 ( fcpdev, "FCP %p xchg %04x RSP stat %02x resid %08x flags %02x" ! 569: "%s%s%s%s\n", fcpdev, fcpcmd->xchg_id, rsp->status, ! 570: ntohl ( rsp->residual ), rsp->flags, ! 571: ( ( rsp->flags & FCP_RSP_RESPONSE_LEN_VALID ) ? " resp" : "" ), ! 572: ( ( rsp->flags & FCP_RSP_SENSE_LEN_VALID ) ? " sense" : "" ), ! 573: ( ( rsp->flags & FCP_RSP_RESIDUAL_OVERRUN ) ? " over" : "" ), ! 574: ( ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN ) ? " under" : "" )); ! 575: if ( fcp_rsp_response_data ( rsp ) ) { ! 576: DBGC2 ( fcpdev, "FCP %p xchg %04x response data:\n", ! 577: fcpdev, fcpcmd->xchg_id ); ! 578: DBGC2_HDA ( fcpdev, 0, fcp_rsp_response_data ( rsp ), ! 579: fcp_rsp_response_data_len ( rsp ) ); ! 580: } ! 581: if ( fcp_rsp_sense_data ( rsp ) ) { ! 582: DBGC2 ( fcpdev, "FCP %p xchg %04x sense data:\n", ! 583: fcpdev, fcpcmd->xchg_id ); ! 584: DBGC2_HDA ( fcpdev, 0, fcp_rsp_sense_data ( rsp ), ! 585: fcp_rsp_sense_data_len ( rsp ) ); ! 586: } ! 587: ! 588: /* Check for locally-detected command underrun */ ! 589: if ( ( rsp->status == 0 ) && ! 590: ( fcpcmd->offset != ( command->data_in_len + ! 591: command->data_out_len ) ) ) { ! 592: DBGC ( fcpdev, "FCP %p xchg %04x data underrun (expected %zd, " ! 593: "got %zd)\n", fcpdev, fcpcmd->xchg_id, ! 594: ( command->data_in_len + command->data_out_len ), ! 595: fcpcmd->offset ); ! 596: rc = -ERANGE_DATA_UNDERRUN; ! 597: goto done; ! 598: } ! 599: ! 600: /* Build SCSI response */ ! 601: memset ( &response, 0, sizeof ( response ) ); ! 602: response.status = rsp->status; ! 603: if ( rsp->flags & ( FCP_RSP_RESIDUAL_OVERRUN | ! 604: FCP_RSP_RESIDUAL_UNDERRUN ) ) { ! 605: response.overrun = ntohl ( rsp->residual ); ! 606: if ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN ) ! 607: response.overrun = -response.overrun; ! 608: } ! 609: if ( ( sense = fcp_rsp_sense_data ( rsp ) ) != NULL ) ! 610: memcpy ( &response.sense, sense, sizeof ( response.sense ) ); ! 611: ! 612: /* Free buffer before sending response, to minimise ! 613: * out-of-memory errors. ! 614: */ ! 615: free_iob ( iob_disown ( iobuf ) ); ! 616: ! 617: /* Send SCSI response */ ! 618: scsi_response ( &fcpcmd->scsi, &response ); ! 619: ! 620: /* Terminate command */ ! 621: fcpcmd_close ( fcpcmd, 0 ); ! 622: ! 623: rc = 0; ! 624: done: ! 625: free_iob ( iobuf ); ! 626: return rc; ! 627: } ! 628: ! 629: /** ! 630: * Handle unknown FCP IU ! 631: * ! 632: * @v fcpcmd FCP command ! 633: * @v iobuf I/O buffer ! 634: * @v meta Data transfer metadata ! 635: * @ret rc Return status code ! 636: */ ! 637: static int fcpcmd_recv_unknown ( struct fcp_command *fcpcmd, ! 638: struct io_buffer *iobuf, ! 639: struct xfer_metadata *meta __unused ) { ! 640: struct fcp_device *fcpdev = fcpcmd->fcpdev; ! 641: ! 642: DBGC ( fcpdev, "FCP %p xchg %04x received unknown IU:\n", ! 643: fcpdev, fcpcmd->xchg_id ); ! 644: DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) ); ! 645: free_iob ( iobuf ); ! 646: return -EPROTO; ! 647: } ! 648: ! 649: /** ! 650: * Transmit FCP frame ! 651: * ! 652: * @v process FCP command process ! 653: */ ! 654: static void fcpcmd_step ( struct process *process ) { ! 655: struct fcp_command *fcpcmd = ! 656: container_of ( process, struct fcp_command, process ); ! 657: int rc; ! 658: ! 659: /* Send the current IU */ ! 660: if ( ( rc = fcpcmd->send ( fcpcmd ) ) != 0 ) { ! 661: /* Treat failure as a fatal error */ ! 662: fcpcmd_close ( fcpcmd, rc ); ! 663: } ! 664: } ! 665: ! 666: /** ! 667: * Receive FCP frame ! 668: * ! 669: * @v fcpcmd FCP command ! 670: * @v iobuf I/O buffer ! 671: * @v meta Data transfer metadata ! 672: * @ret rc Return status code ! 673: */ ! 674: static int fcpcmd_deliver ( struct fcp_command *fcpcmd, ! 675: struct io_buffer *iobuf, ! 676: struct xfer_metadata *meta ) { ! 677: int ( * fcpcmd_recv ) ( struct fcp_command *fcpcmd, ! 678: struct io_buffer *iobuf, ! 679: struct xfer_metadata *meta ); ! 680: int rc; ! 681: ! 682: /* Determine handler */ ! 683: switch ( meta->flags & ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) ) { ! 684: case ( XFER_FL_RESPONSE ) : ! 685: fcpcmd_recv = fcpcmd_recv_rddata; ! 686: break; ! 687: case ( XFER_FL_CMD_STAT ) : ! 688: fcpcmd_recv = fcpcmd_recv_xfer_rdy; ! 689: break; ! 690: case ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) : ! 691: fcpcmd_recv = fcpcmd_recv_rsp; ! 692: break; ! 693: default: ! 694: fcpcmd_recv = fcpcmd_recv_unknown; ! 695: break; ! 696: } ! 697: ! 698: /* Handle IU */ ! 699: if ( ( rc = fcpcmd_recv ( fcpcmd, iob_disown ( iobuf ), meta ) ) != 0 ){ ! 700: /* Treat any error as fatal to the command */ ! 701: fcpcmd_close ( fcpcmd, rc ); ! 702: } ! 703: ! 704: return rc; ! 705: } ! 706: ! 707: /** FCP command SCSI interface operations */ ! 708: static struct interface_operation fcpcmd_scsi_op[] = { ! 709: INTF_OP ( intf_close, struct fcp_command *, fcpcmd_close ), ! 710: }; ! 711: ! 712: /** FCP command SCSI interface descriptor */ ! 713: static struct interface_descriptor fcpcmd_scsi_desc = ! 714: INTF_DESC_PASSTHRU ( struct fcp_command, scsi, fcpcmd_scsi_op, xchg ); ! 715: ! 716: /** FCP command Fibre Channel exchange interface operations */ ! 717: static struct interface_operation fcpcmd_xchg_op[] = { ! 718: INTF_OP ( xfer_deliver, struct fcp_command *, fcpcmd_deliver ), ! 719: INTF_OP ( intf_close, struct fcp_command *, fcpcmd_close_err ), ! 720: }; ! 721: ! 722: /** FCP command Fibre Channel exchange interface descriptor */ ! 723: static struct interface_descriptor fcpcmd_xchg_desc = ! 724: INTF_DESC_PASSTHRU ( struct fcp_command, xchg, fcpcmd_xchg_op, scsi ); ! 725: ! 726: /** ! 727: * Issue FCP SCSI command ! 728: * ! 729: * @v fcpdev FCP device ! 730: * @v parent Parent interface ! 731: * @v command SCSI command ! 732: * @ret tag Command tag, or negative error ! 733: */ ! 734: static int fcpdev_scsi_command ( struct fcp_device *fcpdev, ! 735: struct interface *parent, ! 736: struct scsi_cmd *command ) { ! 737: struct fcp_prli_service_parameters *param = fcpdev->ulp->param; ! 738: struct fcp_command *fcpcmd; ! 739: int xchg_id; ! 740: int rc; ! 741: ! 742: /* Check link */ ! 743: if ( ( rc = fcpdev->ulp->link.rc ) != 0 ) { ! 744: DBGC ( fcpdev, "FCP %p could not issue command while link is " ! 745: "down: %s\n", fcpdev, strerror ( rc ) ); ! 746: goto err_link; ! 747: } ! 748: ! 749: /* Check target capability */ ! 750: assert ( param != NULL ); ! 751: assert ( fcpdev->ulp->param_len >= sizeof ( *param ) ); ! 752: if ( ! ( param->flags & htonl ( FCP_PRLI_TARGET ) ) ) { ! 753: DBGC ( fcpdev, "FCP %p could not issue command: not a target\n", ! 754: fcpdev ); ! 755: rc = -ENOTTY; ! 756: goto err_target; ! 757: } ! 758: ! 759: /* Allocate and initialise structure */ ! 760: fcpcmd = zalloc ( sizeof ( *fcpcmd ) ); ! 761: if ( ! fcpcmd ) { ! 762: rc = -ENOMEM; ! 763: goto err_zalloc; ! 764: } ! 765: ref_init ( &fcpcmd->refcnt, fcpcmd_free ); ! 766: intf_init ( &fcpcmd->scsi, &fcpcmd_scsi_desc, &fcpcmd->refcnt ); ! 767: intf_init ( &fcpcmd->xchg, &fcpcmd_xchg_desc, &fcpcmd->refcnt ); ! 768: process_init_stopped ( &fcpcmd->process, fcpcmd_step, &fcpcmd->refcnt ); ! 769: fcpcmd->fcpdev = fcpdev_get ( fcpdev ); ! 770: list_add ( &fcpcmd->list, &fcpdev->fcpcmds ); ! 771: memcpy ( &fcpcmd->command, command, sizeof ( fcpcmd->command ) ); ! 772: ! 773: /* Create new exchange */ ! 774: if ( ( xchg_id = fc_xchg_originate ( &fcpcmd->xchg, ! 775: fcpdev->ulp->peer->port, ! 776: &fcpdev->ulp->peer->port_id, ! 777: FC_TYPE_FCP ) ) < 0 ) { ! 778: rc = xchg_id; ! 779: DBGC ( fcpdev, "FCP %p could not create exchange: %s\n", ! 780: fcpdev, strerror ( rc ) ); ! 781: goto err_xchg_originate; ! 782: } ! 783: fcpcmd->xchg_id = xchg_id; ! 784: ! 785: /* Start sending command IU */ ! 786: fcpcmd_start_send ( fcpcmd, fcpcmd_send_cmnd ); ! 787: ! 788: /* Attach to parent interface, mortalise self, and return */ ! 789: intf_plug_plug ( &fcpcmd->scsi, parent ); ! 790: ref_put ( &fcpcmd->refcnt ); ! 791: return ( FCP_TAG_MAGIC | fcpcmd->xchg_id ); ! 792: ! 793: err_xchg_originate: ! 794: fcpcmd_close ( fcpcmd, rc ); ! 795: ref_put ( &fcpcmd->refcnt ); ! 796: err_zalloc: ! 797: err_target: ! 798: err_link: ! 799: return rc; ! 800: } ! 801: ! 802: /** ! 803: * Close FCP device ! 804: * ! 805: * @v fcpdev FCP device ! 806: * @v rc Reason for close ! 807: */ ! 808: static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) { ! 809: struct fcp_command *fcpcmd; ! 810: struct fcp_command *tmp; ! 811: ! 812: DBGC ( fcpdev, "FCP %p closed: %s\n", fcpdev, strerror ( rc ) ); ! 813: ! 814: /* Shut down interfaces */ ! 815: intf_shutdown ( &fcpdev->scsi, rc ); ! 816: ! 817: /* Shut down any active commands */ ! 818: list_for_each_entry_safe ( fcpcmd, tmp, &fcpdev->fcpcmds, list ) { ! 819: fcpcmd_get ( fcpcmd ); ! 820: fcpcmd_close ( fcpcmd, rc ); ! 821: fcpcmd_put ( fcpcmd ); ! 822: } ! 823: ! 824: /* Drop reference to ULP */ ! 825: if ( fcpdev->ulp ) { ! 826: fc_ulp_decrement ( fcpdev->ulp ); ! 827: fc_ulp_put ( fcpdev->ulp ); ! 828: fcpdev->ulp = NULL; ! 829: } ! 830: } ! 831: ! 832: /** ! 833: * Check FCP device flow-control window ! 834: * ! 835: * @v fcpdev FCP device ! 836: * @ret len Length of window ! 837: */ ! 838: static size_t fcpdev_window ( struct fcp_device *fcpdev ) { ! 839: return ( fc_link_ok ( &fcpdev->ulp->link ) ? ~( ( size_t ) 0 ) : 0 ); ! 840: } ! 841: ! 842: /** ! 843: * Describe FCP device in an ACPI table ! 844: * ! 845: * @v fcpdev FCP device ! 846: * @v acpi ACPI table ! 847: * @v len Length of ACPI table ! 848: * @ret rc Return status code ! 849: */ ! 850: static int fcpdev_acpi_describe ( struct fcp_device *fcpdev, ! 851: struct acpi_description_header *acpi, ! 852: size_t len ) { ! 853: ! 854: DBGC ( fcpdev, "FCP %p cannot yet describe device in an ACPI table\n", ! 855: fcpdev ); ! 856: ( void ) acpi; ! 857: ( void ) len; ! 858: return 0; ! 859: } ! 860: ! 861: /** ! 862: * Describe FCP device using EDD ! 863: * ! 864: * @v fcpdev FCP device ! 865: * @v type EDD interface type ! 866: * @v path EDD device path ! 867: * @ret rc Return status code ! 868: */ ! 869: static int fcpdev_edd_describe ( struct fcp_device *fcpdev, ! 870: struct edd_interface_type *type, ! 871: union edd_device_path *path ) { ! 872: union { ! 873: struct fc_name fc; ! 874: uint64_t u64; ! 875: } wwn; ! 876: union { ! 877: struct scsi_lun scsi; ! 878: uint64_t u64; ! 879: } lun; ! 880: ! 881: type->type = cpu_to_le64 ( EDD_INTF_TYPE_FIBRE ); ! 882: memcpy ( &wwn.fc, &fcpdev->wwn, sizeof ( wwn.fc ) ); ! 883: path->fibre.wwn = be64_to_cpu ( wwn.u64 ); ! 884: memcpy ( &lun.scsi, &fcpdev->lun, sizeof ( lun.scsi ) ); ! 885: path->fibre.lun = be64_to_cpu ( lun.u64 ); ! 886: return 0; ! 887: } ! 888: ! 889: /** ! 890: * Identify device underlying FCP device ! 891: * ! 892: * @v fcpdev FCP device ! 893: * @ret device Underlying device ! 894: */ ! 895: static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) { ! 896: ! 897: /* We know the underlying device only if the link is up; ! 898: * otherwise we don't have a port to examine. ! 899: */ ! 900: if ( ! fc_link_ok ( &fcpdev->ulp->link ) ) { ! 901: DBGC ( fcpdev, "FCP %p doesn't know underlying device " ! 902: "until link is up\n", fcpdev ); ! 903: return NULL; ! 904: } ! 905: ! 906: /* Hand off to port's transport interface */ ! 907: assert ( fcpdev->ulp->peer->port != NULL ); ! 908: return identify_device ( &fcpdev->ulp->peer->port->transport ); ! 909: } ! 910: ! 911: /** FCP device SCSI interface operations */ ! 912: static struct interface_operation fcpdev_scsi_op[] = { ! 913: INTF_OP ( scsi_command, struct fcp_device *, fcpdev_scsi_command ), ! 914: INTF_OP ( xfer_window, struct fcp_device *, fcpdev_window ), ! 915: INTF_OP ( intf_close, struct fcp_device *, fcpdev_close ), ! 916: INTF_OP ( acpi_describe, struct fcp_device *, fcpdev_acpi_describe ), ! 917: INTF_OP ( edd_describe, struct fcp_device *, fcpdev_edd_describe ), ! 918: INTF_OP ( identify_device, struct fcp_device *, ! 919: fcpdev_identify_device ), ! 920: }; ! 921: ! 922: /** FCP device SCSI interface descriptor */ ! 923: static struct interface_descriptor fcpdev_scsi_desc = ! 924: INTF_DESC ( struct fcp_device, scsi, fcpdev_scsi_op ); ! 925: ! 926: /** ! 927: * Open FCP device ! 928: * ! 929: * @v parent Parent interface ! 930: * @v wwn Fibre Channel WWN ! 931: * @v lun SCSI LUN ! 932: * @ret rc Return status code ! 933: */ ! 934: static int fcpdev_open ( struct interface *parent, struct fc_name *wwn, ! 935: struct scsi_lun *lun ) { ! 936: struct fc_ulp *ulp; ! 937: struct fcp_device *fcpdev; ! 938: int rc; ! 939: ! 940: /* Get Fibre Channel ULP interface */ ! 941: ulp = fc_ulp_get_wwn_type ( wwn, FC_TYPE_FCP ); ! 942: if ( ! ulp ) { ! 943: rc = -ENOMEM; ! 944: goto err_ulp_get; ! 945: } ! 946: ! 947: /* Allocate and initialise structure */ ! 948: fcpdev = zalloc ( sizeof ( *fcpdev ) ); ! 949: if ( ! fcpdev ) { ! 950: rc = -ENOMEM; ! 951: goto err_zalloc; ! 952: } ! 953: ref_init ( &fcpdev->refcnt, NULL ); ! 954: intf_init ( &fcpdev->scsi, &fcpdev_scsi_desc, &fcpdev->refcnt ); ! 955: INIT_LIST_HEAD ( &fcpdev->fcpcmds ); ! 956: fcpdev->ulp = fc_ulp_get ( ulp ); ! 957: fc_ulp_increment ( fcpdev->ulp ); ! 958: ! 959: DBGC ( fcpdev, "FCP %p opened for %s\n", fcpdev, fc_ntoa ( wwn ) ); ! 960: ! 961: /* Preserve parameters required for boot firmware table */ ! 962: memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) ); ! 963: memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) ); ! 964: ! 965: /* Attach SCSI device to parent interface */ ! 966: if ( ( rc = scsi_open ( parent, &fcpdev->scsi, lun ) ) != 0 ) { ! 967: DBGC ( fcpdev, "FCP %p could not create SCSI device: %s\n", ! 968: fcpdev, strerror ( rc ) ); ! 969: goto err_scsi_open; ! 970: } ! 971: ! 972: /* Drop temporary reference to ULP */ ! 973: fc_ulp_put ( ulp ); ! 974: ! 975: /* Mortalise self and return */ ! 976: ref_put ( &fcpdev->refcnt ); ! 977: return 0; ! 978: ! 979: err_scsi_open: ! 980: fcpdev_close ( fcpdev, rc ); ! 981: ref_put ( &fcpdev->refcnt ); ! 982: err_zalloc: ! 983: fc_ulp_put ( ulp ); ! 984: err_ulp_get: ! 985: return rc; ! 986: } ! 987: ! 988: /****************************************************************************** ! 989: * ! 990: * FCP URIs ! 991: * ! 992: ****************************************************************************** ! 993: */ ! 994: ! 995: /** ! 996: * Parse FCP URI ! 997: * ! 998: * @v uri URI ! 999: * @ret wwn Fibre Channel WWN ! 1000: * @ret lun SCSI LUN ! 1001: * @ret rc Return status code ! 1002: * ! 1003: * An FCP URI has the form "fcp:<wwn>:<lun>" or "fcp://<wwn>/<lun>" ! 1004: */ ! 1005: static int fcp_parse_uri ( struct uri *uri, struct fc_name *wwn, ! 1006: struct scsi_lun *lun ) { ! 1007: char wwn_buf[ FC_NAME_STRLEN + 1 /* NUL */ ]; ! 1008: const char *wwn_text; ! 1009: const char *lun_text; ! 1010: int rc; ! 1011: ! 1012: /* Extract WWN and LUN texts from URI */ ! 1013: if ( uri->opaque ) { ! 1014: /* "fcp:<wwn>:<lun>" */ ! 1015: if ( snprintf ( wwn_buf, sizeof ( wwn_buf ), "%s", ! 1016: uri->opaque ) < ( FC_NAME_STRLEN + 1 /* : */ ) ) ! 1017: return -EINVAL; ! 1018: if ( uri->opaque[FC_NAME_STRLEN] != ':' ) ! 1019: return -EINVAL; ! 1020: wwn_text = wwn_buf; ! 1021: lun_text = &uri->opaque[FC_NAME_STRLEN + 1]; ! 1022: } else { ! 1023: /* If host exists, path must also exist */ ! 1024: if ( ! ( uri->host && uri->path ) ) ! 1025: return -EINVAL; ! 1026: if ( uri->path[0] != '/' ) ! 1027: return -EINVAL; ! 1028: wwn_text = uri->host; ! 1029: lun_text = ( uri->path + 1 ); ! 1030: } ! 1031: ! 1032: /* Parse WWN */ ! 1033: if ( ( rc = fc_aton ( wwn_text, wwn ) ) != 0 ) ! 1034: return rc; ! 1035: ! 1036: /* Parse LUN */ ! 1037: if ( ( rc = scsi_parse_lun ( lun_text, lun ) ) != 0 ) ! 1038: return rc; ! 1039: ! 1040: return 0; ! 1041: } ! 1042: ! 1043: /** ! 1044: * Open FCP URI ! 1045: * ! 1046: * @v parent Parent interface ! 1047: * @v uri URI ! 1048: * @ret rc Return status code ! 1049: */ ! 1050: static int fcp_open ( struct interface *parent, struct uri *uri ) { ! 1051: struct fc_name wwn; ! 1052: struct scsi_lun lun; ! 1053: int rc; ! 1054: ! 1055: /* Parse URI */ ! 1056: if ( ( rc = fcp_parse_uri ( uri, &wwn, &lun ) ) != 0 ) ! 1057: return rc; ! 1058: ! 1059: /* Open FCP device */ ! 1060: if ( ( rc = fcpdev_open ( parent, &wwn, &lun ) ) != 0 ) ! 1061: return rc; ! 1062: ! 1063: return 0; ! 1064: } ! 1065: ! 1066: /** FCP URI opener */ ! 1067: struct uri_opener fcp_uri_opener __uri_opener = { ! 1068: .scheme = "fcp", ! 1069: .open = fcp_open, ! 1070: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.