diff options
author | RajithaY <rajithax.yerrumsetty@intel.com> | 2017-04-25 03:31:15 -0700 |
---|---|---|
committer | Rajitha Yerrumchetty <rajithax.yerrumsetty@intel.com> | 2017-05-22 06:48:08 +0000 |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/roms/ipxe/src/net/fcp.c | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/roms/ipxe/src/net/fcp.c')
-rw-r--r-- | qemu/roms/ipxe/src/net/fcp.c | 1096 |
1 files changed, 0 insertions, 1096 deletions
diff --git a/qemu/roms/ipxe/src/net/fcp.c b/qemu/roms/ipxe/src/net/fcp.c deleted file mode 100644 index 930bf7dd4..000000000 --- a/qemu/roms/ipxe/src/net/fcp.c +++ /dev/null @@ -1,1096 +0,0 @@ -/* - * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * You can also choose to distribute this program under the terms of - * the Unmodified Binary Distribution Licence (as given in the file - * COPYING.UBDL), provided that you have satisfied its requirements. - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include <stddef.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <stdio.h> -#include <assert.h> -#include <byteswap.h> -#include <ipxe/refcnt.h> -#include <ipxe/list.h> -#include <ipxe/interface.h> -#include <ipxe/xfer.h> -#include <ipxe/iobuf.h> -#include <ipxe/open.h> -#include <ipxe/process.h> -#include <ipxe/uri.h> -#include <ipxe/acpi.h> -#include <ipxe/scsi.h> -#include <ipxe/device.h> -#include <ipxe/edd.h> -#include <ipxe/fc.h> -#include <ipxe/fcels.h> -#include <ipxe/fcp.h> - -/** @file - * - * Fibre Channel Protocol - * - */ - -/* Disambiguate the various error causes */ -#define ERANGE_READ_DATA_ORDERING \ - __einfo_error ( EINFO_ERANGE_READ_DATA_ORDERING ) -#define EINFO_ERANGE_READ_DATA_ORDERING \ - __einfo_uniqify ( EINFO_ERANGE, 0x01, "Read data out of order" ) -#define ERANGE_READ_DATA_OVERRUN \ - __einfo_error ( EINFO_ERANGE_READ_DATA_OVERRUN ) -#define EINFO_ERANGE_READ_DATA_OVERRUN \ - __einfo_uniqify ( EINFO_ERANGE, 0x02, "Read data overrun" ) -#define ERANGE_WRITE_DATA_STUCK \ - __einfo_error ( EINFO_ERANGE_WRITE_DATA_STUCK ) -#define EINFO_ERANGE_WRITE_DATA_STUCK \ - __einfo_uniqify ( EINFO_ERANGE, 0x03, "Write data stuck" ) -#define ERANGE_WRITE_DATA_OVERRUN \ - __einfo_error ( EINFO_ERANGE_WRITE_DATA_OVERRUN ) -#define EINFO_ERANGE_WRITE_DATA_OVERRUN \ - __einfo_uniqify ( EINFO_ERANGE, 0x04, "Write data overrun" ) -#define ERANGE_DATA_UNDERRUN \ - __einfo_error ( EINFO_ERANGE_DATA_UNDERRUN ) -#define EINFO_ERANGE_DATA_UNDERRUN \ - __einfo_uniqify ( EINFO_ERANGE, 0x05, "Data underrun" ) - -/****************************************************************************** - * - * PRLI - * - ****************************************************************************** - */ - -struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor; - -/** - * Transmit FCP PRLI - * - * @v els Fibre Channel ELS transaction - * @ret rc Return status code - */ -static int fcp_prli_tx ( struct fc_els *els ) { - struct fcp_prli_service_parameters param; - - /* Build service parameter page */ - memset ( ¶m, 0, sizeof ( param ) ); - param.flags = htonl ( FCP_PRLI_NO_READ_RDY | FCP_PRLI_INITIATOR ); - - return fc_els_prli_tx ( els, &fcp_prli_descriptor, ¶m ); -} - -/** - * Receive FCP PRLI - * - * @v els Fibre Channel ELS transaction - * @v frame ELS frame - * @v len Length of ELS frame - * @ret rc Return status code - */ -static int fcp_prli_rx ( struct fc_els *els, void *data, size_t len ) { - return fc_els_prli_rx ( els, &fcp_prli_descriptor, data, len ); -} - -/** - * Detect FCP PRLI - * - * @v els Fibre Channel ELS transaction - * @v data ELS frame - * @v len Length of ELS frame - * @ret rc Return status code - */ -static int fcp_prli_detect ( struct fc_els *els, const void *data, - size_t len ) { - return fc_els_prli_detect ( els, &fcp_prli_descriptor, data, len ); -} - -/** FCP PRLI ELS handler */ -struct fc_els_handler fcp_prli_handler __fc_els_handler = { - .name = "PRLI-FCP", - .tx = fcp_prli_tx, - .rx = fcp_prli_rx, - .detect = fcp_prli_detect, -}; - -/** FCP PRLI descriptor */ -struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor = { - .type = FC_TYPE_FCP, - .param_len = sizeof ( struct fcp_prli_service_parameters ), - .handler = &fcp_prli_handler, -}; - -/****************************************************************************** - * - * FCP devices and commands - * - ****************************************************************************** - */ - -/** An FCP device */ -struct fcp_device { - /** Reference count */ - struct refcnt refcnt; - /** Fibre Channel upper-layer protocol user */ - struct fc_ulp_user user; - /** SCSI command issuing interface */ - struct interface scsi; - /** List of active commands */ - struct list_head fcpcmds; - - /** Fibre Channel WWN (for boot firmware table) */ - struct fc_name wwn; - /** SCSI LUN (for boot firmware table) */ - struct scsi_lun lun; -}; - -/** An FCP command */ -struct fcp_command { - /** Reference count */ - struct refcnt refcnt; - /** FCP SCSI device */ - struct fcp_device *fcpdev; - /** List of active commands */ - struct list_head list; - /** SCSI command interface */ - struct interface scsi; - /** Fibre Channel exchange interface */ - struct interface xchg; - /** Send process */ - struct process process; - /** Send current IU - * - * @v fcpcmd FCP command - * @ret rc Return status code - */ - int ( * send ) ( struct fcp_command *fcpcmd ); - /** SCSI command */ - struct scsi_cmd command; - /** Data offset within command */ - size_t offset; - /** Length of data remaining to be sent within this IU */ - size_t remaining; - /** Exchange ID */ - uint16_t xchg_id; -}; - -/** - * Get reference to FCP device - * - * @v fcpdev FCP device - * @ret fcpdev FCP device - */ -static inline __attribute__ (( always_inline )) struct fcp_device * -fcpdev_get ( struct fcp_device *fcpdev ) { - ref_get ( &fcpdev->refcnt ); - return fcpdev; -} - -/** - * Drop reference to FCP device - * - * @v fcpdev FCP device - */ -static inline __attribute__ (( always_inline )) void -fcpdev_put ( struct fcp_device *fcpdev ) { - ref_put ( &fcpdev->refcnt ); -} - -/** - * Get reference to FCP command - * - * @v fcpcmd FCP command - * @ret fcpcmd FCP command - */ -static inline __attribute__ (( always_inline )) struct fcp_command * -fcpcmd_get ( struct fcp_command *fcpcmd ) { - ref_get ( &fcpcmd->refcnt ); - return fcpcmd; -} - -/** - * Drop reference to FCP command - * - * @v fcpcmd FCP command - */ -static inline __attribute__ (( always_inline )) void -fcpcmd_put ( struct fcp_command *fcpcmd ) { - ref_put ( &fcpcmd->refcnt ); -} - -/** - * Start FCP command sending - * - * @v fcpcmd FCP command - * @v send Send method - */ -static inline __attribute__ (( always_inline )) void -fcpcmd_start_send ( struct fcp_command *fcpcmd, - int ( * send ) ( struct fcp_command *fcpcmd ) ) { - fcpcmd->send = send; - process_add ( &fcpcmd->process ); -} - -/** - * Stop FCP command sending - * - * @v fcpcmd FCP command - */ -static inline __attribute__ (( always_inline )) void -fcpcmd_stop_send ( struct fcp_command *fcpcmd ) { - process_del ( &fcpcmd->process ); -} - -/** - * Free FCP command - * - * @v refcnt Reference count - */ -static void fcpcmd_free ( struct refcnt *refcnt ) { - struct fcp_command *fcpcmd = - container_of ( refcnt, struct fcp_command, refcnt ); - - /* Remove from list of commands */ - list_del ( &fcpcmd->list ); - fcpdev_put ( fcpcmd->fcpdev ); - - /* Free command */ - free ( fcpcmd ); -} - -/** - * Close FCP command - * - * @v fcpcmd FCP command - * @v rc Reason for close - */ -static void fcpcmd_close ( struct fcp_command *fcpcmd, int rc ) { - struct fcp_device *fcpdev = fcpcmd->fcpdev; - - if ( rc != 0 ) { - DBGC ( fcpdev, "FCP %p xchg %04x closed: %s\n", - fcpdev, fcpcmd->xchg_id, strerror ( rc ) ); - } - - /* Stop sending */ - fcpcmd_stop_send ( fcpcmd ); - - /* Shut down interfaces */ - intf_shutdown ( &fcpcmd->scsi, rc ); - intf_shutdown ( &fcpcmd->xchg, rc ); -} - -/** - * Close FCP command in error - * - * @v fcpcmd FCP command - * @v rc Reason for close - */ -static void fcpcmd_close_err ( struct fcp_command *fcpcmd, int rc ) { - if ( rc == 0 ) - rc = -EPIPE; - fcpcmd_close ( fcpcmd, rc ); -} - -/** - * Send FCP command IU - * - * @v fcpcmd FCP command - * @ret rc Return status code - */ -static int fcpcmd_send_cmnd ( struct fcp_command *fcpcmd ) { - struct fcp_device *fcpdev = fcpcmd->fcpdev; - struct scsi_cmd *command = &fcpcmd->command; - struct io_buffer *iobuf; - struct fcp_cmnd *cmnd; - struct xfer_metadata meta; - int rc; - - /* Sanity check */ - if ( command->data_in_len && command->data_out_len ) { - DBGC ( fcpdev, "FCP %p xchg %04x cannot handle bidirectional " - "command\n", fcpdev, fcpcmd->xchg_id ); - return -ENOTSUP; - } - - /* Allocate I/O buffer */ - iobuf = xfer_alloc_iob ( &fcpcmd->xchg, sizeof ( *cmnd ) ); - if ( ! iobuf ) { - DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate command IU\n", - fcpdev, fcpcmd->xchg_id ); - return -ENOMEM; - } - - /* Construct command IU frame */ - cmnd = iob_put ( iobuf, sizeof ( *cmnd ) ); - memset ( cmnd, 0, sizeof ( *cmnd ) ); - memcpy ( &cmnd->lun, &command->lun, sizeof ( cmnd->lun ) ); - assert ( ! ( command->data_in_len && command->data_out_len ) ); - if ( command->data_in_len ) - cmnd->dirn |= FCP_CMND_RDDATA; - if ( command->data_out_len ) - cmnd->dirn |= FCP_CMND_WRDATA; - memcpy ( &cmnd->cdb, &fcpcmd->command.cdb, sizeof ( cmnd->cdb ) ); - cmnd->len = htonl ( command->data_in_len + command->data_out_len ); - memset ( &meta, 0, sizeof ( meta ) ); - meta.flags = ( XFER_FL_CMD_STAT | XFER_FL_OVER ); - DBGC2 ( fcpdev, "FCP %p xchg %04x CMND " SCSI_CDB_FORMAT " %04x\n", - fcpdev, fcpcmd->xchg_id, SCSI_CDB_DATA ( cmnd->cdb ), - ntohl ( cmnd->len ) ); - - /* No further data to send within this IU */ - fcpcmd_stop_send ( fcpcmd ); - - /* Send command IU frame */ - if ( ( rc = xfer_deliver ( &fcpcmd->xchg, iob_disown ( iobuf ), - &meta ) ) != 0 ) { - DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver command IU: " - "%s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Handle FCP read data IU - * - * @v fcpcmd FCP command - * @v iobuf I/O buffer - * @v meta Data transfer metadata - * @ret rc Return status code - */ -static int fcpcmd_recv_rddata ( struct fcp_command *fcpcmd, - struct io_buffer *iobuf, - struct xfer_metadata *meta ) { - struct fcp_device *fcpdev = fcpcmd->fcpdev; - struct scsi_cmd *command = &fcpcmd->command; - size_t offset = meta->offset; - size_t len = iob_len ( iobuf ); - int rc; - - /* Sanity checks */ - if ( ! ( meta->flags & XFER_FL_ABS_OFFSET ) ) { - DBGC ( fcpdev, "FCP %p xchg %04x read data missing offset\n", - fcpdev, fcpcmd->xchg_id ); - rc = -ERANGE_READ_DATA_ORDERING; - goto done; - } - if ( offset != fcpcmd->offset ) { - DBGC ( fcpdev, "FCP %p xchg %04x read data out of order " - "(expected %zd, received %zd)\n", - fcpdev, fcpcmd->xchg_id, fcpcmd->offset, offset ); - rc = -ERANGE_READ_DATA_ORDERING; - goto done; - } - if ( ( offset + len ) > command->data_in_len ) { - DBGC ( fcpdev, "FCP %p xchg %04x read data overrun (max %zd, " - "received %zd)\n", fcpdev, fcpcmd->xchg_id, - command->data_in_len, ( offset + len ) ); - rc = -ERANGE_READ_DATA_OVERRUN; - goto done; - } - DBGC2 ( fcpdev, "FCP %p xchg %04x RDDATA [%08zx,%08zx)\n", - fcpdev, fcpcmd->xchg_id, offset, ( offset + len ) ); - - /* Copy to user buffer */ - copy_to_user ( command->data_in, offset, iobuf->data, len ); - fcpcmd->offset += len; - assert ( fcpcmd->offset <= command->data_in_len ); - - rc = 0; - done: - free_iob ( iobuf ); - return rc; -} - -/** - * Send FCP write data IU - * - * @v fcpcmd FCP command - * @ret rc Return status code - */ -static int fcpcmd_send_wrdata ( struct fcp_command *fcpcmd ) { - struct fcp_device *fcpdev = fcpcmd->fcpdev; - struct scsi_cmd *command = &fcpcmd->command; - struct io_buffer *iobuf; - struct xfer_metadata meta; - size_t len; - int rc; - - /* Calculate length to be sent */ - len = xfer_window ( &fcpcmd->xchg ); - if ( len > fcpcmd->remaining ) - len = fcpcmd->remaining; - - /* Sanity checks */ - if ( len == 0 ) { - DBGC ( fcpdev, "FCP %p xchg %04x write data stuck\n", - fcpdev, fcpcmd->xchg_id ); - return -ERANGE_WRITE_DATA_STUCK; - } - if ( ( fcpcmd->offset + len ) > command->data_out_len ) { - DBGC ( fcpdev, "FCP %p xchg %04x write data overrun (max %zd, " - "requested %zd)\n", fcpdev, fcpcmd->xchg_id, - command->data_out_len, ( fcpcmd->offset + len ) ); - return -ERANGE_WRITE_DATA_OVERRUN; - } - - /* Allocate I/O buffer */ - iobuf = xfer_alloc_iob ( &fcpcmd->xchg, len ); - if ( ! iobuf ) { - DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate write data " - "IU for %zd bytes\n", fcpdev, fcpcmd->xchg_id, len ); - return -ENOMEM; - } - - /* Construct data IU frame */ - copy_from_user ( iob_put ( iobuf, len ), command->data_out, - fcpcmd->offset, len ); - memset ( &meta, 0, sizeof ( meta ) ); - meta.flags = ( XFER_FL_RESPONSE | XFER_FL_ABS_OFFSET ); - meta.offset = fcpcmd->offset; - DBGC2 ( fcpdev, "FCP %p xchg %04x WRDATA [%08zx,%04zx)\n", - fcpdev, fcpcmd->xchg_id, fcpcmd->offset, - ( fcpcmd->offset + iob_len ( iobuf ) ) ); - - /* Calculate amount of data remaining to be sent within this IU */ - assert ( len <= fcpcmd->remaining ); - fcpcmd->offset += len; - fcpcmd->remaining -= len; - assert ( fcpcmd->offset <= command->data_out_len ); - if ( fcpcmd->remaining == 0 ) { - fcpcmd_stop_send ( fcpcmd ); - meta.flags |= XFER_FL_OVER; - } - - /* Send data IU frame */ - if ( ( rc = xfer_deliver ( &fcpcmd->xchg, iob_disown ( iobuf ), - &meta ) ) != 0 ) { - DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver write data " - "IU: %s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Handle FCP transfer ready IU - * - * @v fcpcmd FCP command - * @v iobuf I/O buffer - * @v meta Data transfer metadata - * @ret rc Return status code - */ -static int fcpcmd_recv_xfer_rdy ( struct fcp_command *fcpcmd, - struct io_buffer *iobuf, - struct xfer_metadata *meta __unused ) { - struct fcp_device *fcpdev = fcpcmd->fcpdev; - struct fcp_xfer_rdy *xfer_rdy = iobuf->data; - int rc; - - /* Sanity checks */ - if ( iob_len ( iobuf ) != sizeof ( *xfer_rdy ) ) { - DBGC ( fcpdev, "FCP %p xchg %04x received invalid transfer " - "ready IU:\n", fcpdev, fcpcmd->xchg_id ); - DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) ); - rc = -EPROTO; - goto done; - } - if ( ntohl ( xfer_rdy->offset ) != fcpcmd->offset ) { - /* We do not advertise out-of-order delivery */ - DBGC ( fcpdev, "FCP %p xchg %04x cannot support out-of-order " - "delivery (expected %zd, requested %d)\n", - fcpdev, fcpcmd->xchg_id, fcpcmd->offset, - ntohl ( xfer_rdy->offset ) ); - rc = -EPROTO; - goto done; - } - DBGC2 ( fcpdev, "FCP %p xchg %04x XFER_RDY [%08x,%08x)\n", - fcpdev, fcpcmd->xchg_id, ntohl ( xfer_rdy->offset ), - ( ntohl ( xfer_rdy->offset ) + ntohl ( xfer_rdy->len ) ) ); - - /* Start sending requested data */ - fcpcmd->remaining = ntohl ( xfer_rdy->len ); - fcpcmd_start_send ( fcpcmd, fcpcmd_send_wrdata ); - - rc = 0; - done: - free_iob ( iobuf ); - return rc; -} - -/** - * Handle FCP response IU - * - * @v fcpcmd FCP command - * @v iobuf I/O buffer - * @v meta Data transfer metadata - * @ret rc Return status code - */ -static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd, - struct io_buffer *iobuf, - struct xfer_metadata *meta __unused ) { - struct fcp_device *fcpdev = fcpcmd->fcpdev; - struct scsi_cmd *command = &fcpcmd->command; - struct fcp_rsp *rsp = iobuf->data; - struct scsi_rsp response; - int rc; - - /* Sanity check */ - if ( ( iob_len ( iobuf ) < sizeof ( *rsp ) ) || - ( iob_len ( iobuf ) < ( sizeof ( *rsp ) + - fcp_rsp_response_data_len ( rsp ) + - fcp_rsp_sense_data_len ( rsp ) ) ) ) { - DBGC ( fcpdev, "FCP %p xchg %04x received invalid response " - "IU:\n", fcpdev, fcpcmd->xchg_id ); - DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) ); - rc = -EPROTO; - goto done; - } - DBGC2 ( fcpdev, "FCP %p xchg %04x RSP stat %02x resid %08x flags %02x" - "%s%s%s%s\n", fcpdev, fcpcmd->xchg_id, rsp->status, - ntohl ( rsp->residual ), rsp->flags, - ( ( rsp->flags & FCP_RSP_RESPONSE_LEN_VALID ) ? " resp" : "" ), - ( ( rsp->flags & FCP_RSP_SENSE_LEN_VALID ) ? " sense" : "" ), - ( ( rsp->flags & FCP_RSP_RESIDUAL_OVERRUN ) ? " over" : "" ), - ( ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN ) ? " under" : "" )); - if ( fcp_rsp_response_data ( rsp ) ) { - DBGC2 ( fcpdev, "FCP %p xchg %04x response data:\n", - fcpdev, fcpcmd->xchg_id ); - DBGC2_HDA ( fcpdev, 0, fcp_rsp_response_data ( rsp ), - fcp_rsp_response_data_len ( rsp ) ); - } - if ( fcp_rsp_sense_data ( rsp ) ) { - DBGC2 ( fcpdev, "FCP %p xchg %04x sense data:\n", - fcpdev, fcpcmd->xchg_id ); - DBGC2_HDA ( fcpdev, 0, fcp_rsp_sense_data ( rsp ), - fcp_rsp_sense_data_len ( rsp ) ); - } - - /* Check for locally-detected command underrun */ - if ( ( rsp->status == 0 ) && - ( fcpcmd->offset != ( command->data_in_len + - command->data_out_len ) ) ) { - DBGC ( fcpdev, "FCP %p xchg %04x data underrun (expected %zd, " - "got %zd)\n", fcpdev, fcpcmd->xchg_id, - ( command->data_in_len + command->data_out_len ), - fcpcmd->offset ); - rc = -ERANGE_DATA_UNDERRUN; - goto done; - } - - /* Build SCSI response */ - memset ( &response, 0, sizeof ( response ) ); - response.status = rsp->status; - if ( rsp->flags & ( FCP_RSP_RESIDUAL_OVERRUN | - FCP_RSP_RESIDUAL_UNDERRUN ) ) { - response.overrun = ntohl ( rsp->residual ); - if ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN ) - response.overrun = -response.overrun; - } - scsi_parse_sense ( fcp_rsp_sense_data ( rsp ), - fcp_rsp_sense_data_len ( rsp ), &response.sense ); - - /* Free buffer before sending response, to minimise - * out-of-memory errors. - */ - free_iob ( iob_disown ( iobuf ) ); - - /* Send SCSI response */ - scsi_response ( &fcpcmd->scsi, &response ); - - /* Terminate command */ - fcpcmd_close ( fcpcmd, 0 ); - - rc = 0; - done: - free_iob ( iobuf ); - return rc; -} - -/** - * Handle unknown FCP IU - * - * @v fcpcmd FCP command - * @v iobuf I/O buffer - * @v meta Data transfer metadata - * @ret rc Return status code - */ -static int fcpcmd_recv_unknown ( struct fcp_command *fcpcmd, - struct io_buffer *iobuf, - struct xfer_metadata *meta __unused ) { - struct fcp_device *fcpdev = fcpcmd->fcpdev; - - DBGC ( fcpdev, "FCP %p xchg %04x received unknown IU:\n", - fcpdev, fcpcmd->xchg_id ); - DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) ); - free_iob ( iobuf ); - return -EPROTO; -} - -/** - * Transmit FCP frame - * - * @v fcpcmd FCP command - */ -static void fcpcmd_step ( struct fcp_command *fcpcmd ) { - int rc; - - /* Send the current IU */ - if ( ( rc = fcpcmd->send ( fcpcmd ) ) != 0 ) { - /* Treat failure as a fatal error */ - fcpcmd_close ( fcpcmd, rc ); - } -} - -/** - * Receive FCP frame - * - * @v fcpcmd FCP command - * @v iobuf I/O buffer - * @v meta Data transfer metadata - * @ret rc Return status code - */ -static int fcpcmd_deliver ( struct fcp_command *fcpcmd, - struct io_buffer *iobuf, - struct xfer_metadata *meta ) { - int ( * fcpcmd_recv ) ( struct fcp_command *fcpcmd, - struct io_buffer *iobuf, - struct xfer_metadata *meta ); - int rc; - - /* Determine handler */ - switch ( meta->flags & ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) ) { - case ( XFER_FL_RESPONSE ) : - fcpcmd_recv = fcpcmd_recv_rddata; - break; - case ( XFER_FL_CMD_STAT ) : - fcpcmd_recv = fcpcmd_recv_xfer_rdy; - break; - case ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) : - fcpcmd_recv = fcpcmd_recv_rsp; - break; - default: - fcpcmd_recv = fcpcmd_recv_unknown; - break; - } - - /* Handle IU */ - if ( ( rc = fcpcmd_recv ( fcpcmd, iob_disown ( iobuf ), meta ) ) != 0 ){ - /* Treat any error as fatal to the command */ - fcpcmd_close ( fcpcmd, rc ); - } - - return rc; -} - -/** FCP command SCSI interface operations */ -static struct interface_operation fcpcmd_scsi_op[] = { - INTF_OP ( intf_close, struct fcp_command *, fcpcmd_close ), -}; - -/** FCP command SCSI interface descriptor */ -static struct interface_descriptor fcpcmd_scsi_desc = - INTF_DESC_PASSTHRU ( struct fcp_command, scsi, fcpcmd_scsi_op, xchg ); - -/** FCP command Fibre Channel exchange interface operations */ -static struct interface_operation fcpcmd_xchg_op[] = { - INTF_OP ( xfer_deliver, struct fcp_command *, fcpcmd_deliver ), - INTF_OP ( intf_close, struct fcp_command *, fcpcmd_close_err ), -}; - -/** FCP command Fibre Channel exchange interface descriptor */ -static struct interface_descriptor fcpcmd_xchg_desc = - INTF_DESC_PASSTHRU ( struct fcp_command, xchg, fcpcmd_xchg_op, scsi ); - -/** FCP command process descriptor */ -static struct process_descriptor fcpcmd_process_desc = - PROC_DESC ( struct fcp_command, process, fcpcmd_step ); - -/** - * Issue FCP SCSI command - * - * @v fcpdev FCP device - * @v parent Parent interface - * @v command SCSI command - * @ret tag Command tag, or negative error - */ -static int fcpdev_scsi_command ( struct fcp_device *fcpdev, - struct interface *parent, - struct scsi_cmd *command ) { - struct fcp_prli_service_parameters *param = fcpdev->user.ulp->param; - struct fcp_command *fcpcmd; - int xchg_id; - int rc; - - /* Check link */ - if ( ( rc = fcpdev->user.ulp->link.rc ) != 0 ) { - DBGC ( fcpdev, "FCP %p could not issue command while link is " - "down: %s\n", fcpdev, strerror ( rc ) ); - goto err_link; - } - - /* Check target capability */ - assert ( param != NULL ); - assert ( fcpdev->user.ulp->param_len >= sizeof ( *param ) ); - if ( ! ( param->flags & htonl ( FCP_PRLI_TARGET ) ) ) { - DBGC ( fcpdev, "FCP %p could not issue command: not a target\n", - fcpdev ); - rc = -ENOTTY; - goto err_target; - } - - /* Allocate and initialise structure */ - fcpcmd = zalloc ( sizeof ( *fcpcmd ) ); - if ( ! fcpcmd ) { - rc = -ENOMEM; - goto err_zalloc; - } - ref_init ( &fcpcmd->refcnt, fcpcmd_free ); - intf_init ( &fcpcmd->scsi, &fcpcmd_scsi_desc, &fcpcmd->refcnt ); - intf_init ( &fcpcmd->xchg, &fcpcmd_xchg_desc, &fcpcmd->refcnt ); - process_init_stopped ( &fcpcmd->process, &fcpcmd_process_desc, - &fcpcmd->refcnt ); - fcpcmd->fcpdev = fcpdev_get ( fcpdev ); - list_add ( &fcpcmd->list, &fcpdev->fcpcmds ); - memcpy ( &fcpcmd->command, command, sizeof ( fcpcmd->command ) ); - - /* Create new exchange */ - if ( ( xchg_id = fc_xchg_originate ( &fcpcmd->xchg, - fcpdev->user.ulp->peer->port, - &fcpdev->user.ulp->peer->port_id, - FC_TYPE_FCP ) ) < 0 ) { - rc = xchg_id; - DBGC ( fcpdev, "FCP %p could not create exchange: %s\n", - fcpdev, strerror ( rc ) ); - goto err_xchg_originate; - } - fcpcmd->xchg_id = xchg_id; - - /* Start sending command IU */ - fcpcmd_start_send ( fcpcmd, fcpcmd_send_cmnd ); - - /* Attach to parent interface, mortalise self, and return */ - intf_plug_plug ( &fcpcmd->scsi, parent ); - ref_put ( &fcpcmd->refcnt ); - return ( FCP_TAG_MAGIC | fcpcmd->xchg_id ); - - err_xchg_originate: - fcpcmd_close ( fcpcmd, rc ); - ref_put ( &fcpcmd->refcnt ); - err_zalloc: - err_target: - err_link: - return rc; -} - -/** - * Close FCP device - * - * @v fcpdev FCP device - * @v rc Reason for close - */ -static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) { - struct fcp_command *fcpcmd; - struct fcp_command *tmp; - - DBGC ( fcpdev, "FCP %p closed: %s\n", fcpdev, strerror ( rc ) ); - - /* Shut down interfaces */ - intf_shutdown ( &fcpdev->scsi, rc ); - - /* Shut down any active commands */ - list_for_each_entry_safe ( fcpcmd, tmp, &fcpdev->fcpcmds, list ) { - fcpcmd_get ( fcpcmd ); - fcpcmd_close ( fcpcmd, rc ); - fcpcmd_put ( fcpcmd ); - } - - /* Drop reference to ULP */ - fc_ulp_detach ( &fcpdev->user ); -} - -/** - * Check FCP device flow-control window - * - * @v fcpdev FCP device - * @ret len Length of window - */ -static size_t fcpdev_window ( struct fcp_device *fcpdev ) { - return ( fc_link_ok ( &fcpdev->user.ulp->link ) ? - ~( ( size_t ) 0 ) : 0 ); -} - -/** - * Describe FCP device in an ACPI table - * - * @v fcpdev FCP device - * @v acpi ACPI table - * @v len Length of ACPI table - * @ret rc Return status code - */ -static int fcpdev_acpi_describe ( struct fcp_device *fcpdev, - struct acpi_description_header *acpi, - size_t len ) { - - DBGC ( fcpdev, "FCP %p cannot yet describe device in an ACPI table\n", - fcpdev ); - ( void ) acpi; - ( void ) len; - return 0; -} - -/** - * Describe FCP device using EDD - * - * @v fcpdev FCP device - * @v type EDD interface type - * @v path EDD device path - * @ret rc Return status code - */ -static int fcpdev_edd_describe ( struct fcp_device *fcpdev, - struct edd_interface_type *type, - union edd_device_path *path ) { - union { - struct fc_name fc; - uint64_t u64; - } wwn; - union { - struct scsi_lun scsi; - uint64_t u64; - } lun; - - type->type = cpu_to_le64 ( EDD_INTF_TYPE_FIBRE ); - memcpy ( &wwn.fc, &fcpdev->wwn, sizeof ( wwn.fc ) ); - path->fibre.wwn = be64_to_cpu ( wwn.u64 ); - memcpy ( &lun.scsi, &fcpdev->lun, sizeof ( lun.scsi ) ); - path->fibre.lun = be64_to_cpu ( lun.u64 ); - return 0; -} - -/** - * Identify device underlying FCP device - * - * @v fcpdev FCP device - * @ret device Underlying device - */ -static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) { - - /* We know the underlying device only if the link is up; - * otherwise we don't have a port to examine. - */ - if ( ! fc_link_ok ( &fcpdev->user.ulp->link ) ) { - DBGC ( fcpdev, "FCP %p doesn't know underlying device " - "until link is up\n", fcpdev ); - return NULL; - } - - /* Hand off to port's transport interface */ - assert ( fcpdev->user.ulp->peer->port != NULL ); - return identify_device ( &fcpdev->user.ulp->peer->port->transport ); -} - -/** FCP device SCSI interface operations */ -static struct interface_operation fcpdev_scsi_op[] = { - INTF_OP ( scsi_command, struct fcp_device *, fcpdev_scsi_command ), - INTF_OP ( xfer_window, struct fcp_device *, fcpdev_window ), - INTF_OP ( intf_close, struct fcp_device *, fcpdev_close ), - INTF_OP ( acpi_describe, struct fcp_device *, fcpdev_acpi_describe ), - INTF_OP ( edd_describe, struct fcp_device *, fcpdev_edd_describe ), - INTF_OP ( identify_device, struct fcp_device *, - fcpdev_identify_device ), -}; - -/** FCP device SCSI interface descriptor */ -static struct interface_descriptor fcpdev_scsi_desc = - INTF_DESC ( struct fcp_device, scsi, fcpdev_scsi_op ); - -/** - * Examine FCP ULP link state - * - * @v user Fibre Channel upper-layer protocol user - */ -static void fcpdev_examine ( struct fc_ulp_user *user ) { - struct fcp_device *fcpdev = - container_of ( user, struct fcp_device, user ); - - if ( fc_link_ok ( &fcpdev->user.ulp->link ) ) { - DBGC ( fcpdev, "FCP %p link is up\n", fcpdev ); - } else { - DBGC ( fcpdev, "FCP %p link is down: %s\n", - fcpdev, strerror ( fcpdev->user.ulp->link.rc ) ); - } - - /* Notify SCSI layer of window change */ - xfer_window_changed ( &fcpdev->scsi ); -} - -/** - * Open FCP device - * - * @v parent Parent interface - * @v wwn Fibre Channel WWN - * @v lun SCSI LUN - * @ret rc Return status code - */ -static int fcpdev_open ( struct interface *parent, struct fc_name *wwn, - struct scsi_lun *lun ) { - struct fc_ulp *ulp; - struct fcp_device *fcpdev; - int rc; - - /* Get Fibre Channel ULP interface */ - ulp = fc_ulp_get_wwn_type ( wwn, FC_TYPE_FCP ); - if ( ! ulp ) { - rc = -ENOMEM; - goto err_ulp_get; - } - - /* Allocate and initialise structure */ - fcpdev = zalloc ( sizeof ( *fcpdev ) ); - if ( ! fcpdev ) { - rc = -ENOMEM; - goto err_zalloc; - } - ref_init ( &fcpdev->refcnt, NULL ); - intf_init ( &fcpdev->scsi, &fcpdev_scsi_desc, &fcpdev->refcnt ); - INIT_LIST_HEAD ( &fcpdev->fcpcmds ); - fc_ulp_user_init ( &fcpdev->user, fcpdev_examine, &fcpdev->refcnt ); - - DBGC ( fcpdev, "FCP %p opened for %s\n", fcpdev, fc_ntoa ( wwn ) ); - - /* Attach to Fibre Channel ULP */ - fc_ulp_attach ( ulp, &fcpdev->user ); - - /* Preserve parameters required for boot firmware table */ - memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) ); - memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) ); - - /* Attach SCSI device to parent interface */ - if ( ( rc = scsi_open ( parent, &fcpdev->scsi, lun ) ) != 0 ) { - DBGC ( fcpdev, "FCP %p could not create SCSI device: %s\n", - fcpdev, strerror ( rc ) ); - goto err_scsi_open; - } - - /* Drop temporary reference to ULP */ - fc_ulp_put ( ulp ); - - /* Mortalise self and return */ - ref_put ( &fcpdev->refcnt ); - return 0; - - err_scsi_open: - fcpdev_close ( fcpdev, rc ); - ref_put ( &fcpdev->refcnt ); - err_zalloc: - fc_ulp_put ( ulp ); - err_ulp_get: - return rc; -} - -/****************************************************************************** - * - * FCP URIs - * - ****************************************************************************** - */ - -/** - * Parse FCP URI - * - * @v uri URI - * @ret wwn Fibre Channel WWN - * @ret lun SCSI LUN - * @ret rc Return status code - * - * An FCP URI has the form "fcp:<wwn>:<lun>" or "fcp://<wwn>/<lun>" - */ -static int fcp_parse_uri ( struct uri *uri, struct fc_name *wwn, - struct scsi_lun *lun ) { - char wwn_buf[ FC_NAME_STRLEN + 1 /* NUL */ ]; - const char *wwn_text; - const char *lun_text; - int rc; - - /* Extract WWN and LUN texts from URI */ - if ( uri->opaque ) { - /* "fcp:<wwn>:<lun>" */ - if ( snprintf ( wwn_buf, sizeof ( wwn_buf ), "%s", - uri->opaque ) < ( FC_NAME_STRLEN + 1 /* : */ ) ) - return -EINVAL; - if ( uri->opaque[FC_NAME_STRLEN] != ':' ) - return -EINVAL; - wwn_text = wwn_buf; - lun_text = &uri->opaque[FC_NAME_STRLEN + 1]; - } else { - /* If host exists, path must also exist */ - if ( ! ( uri->host && uri->path ) ) - return -EINVAL; - if ( uri->path[0] != '/' ) - return -EINVAL; - wwn_text = uri->host; - lun_text = ( uri->path + 1 ); - } - - /* Parse WWN */ - if ( ( rc = fc_aton ( wwn_text, wwn ) ) != 0 ) - return rc; - - /* Parse LUN */ - if ( ( rc = scsi_parse_lun ( lun_text, lun ) ) != 0 ) - return rc; - - return 0; -} - -/** - * Open FCP URI - * - * @v parent Parent interface - * @v uri URI - * @ret rc Return status code - */ -static int fcp_open ( struct interface *parent, struct uri *uri ) { - struct fc_name wwn; - struct scsi_lun lun; - int rc; - - /* Parse URI */ - if ( ( rc = fcp_parse_uri ( uri, &wwn, &lun ) ) != 0 ) - return rc; - - /* Open FCP device */ - if ( ( rc = fcpdev_open ( parent, &wwn, &lun ) ) != 0 ) - return rc; - - return 0; -} - -/** FCP URI opener */ -struct uri_opener fcp_uri_opener __uri_opener = { - .scheme = "fcp", - .open = fcp_open, -}; |