mirror of
https://github.com/ipxe/ipxe
synced 2026-06-29 00:07:28 +03:00
[scsi] Use data-transfer buffers for data-in and data-out
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -422,6 +422,8 @@ static int scsicmd_command ( struct scsi_command *scsicmd ) {
|
||||
/* Construct command */
|
||||
memset ( &command, 0, sizeof ( command ) );
|
||||
memcpy ( &command.lun, &scsidev->lun, sizeof ( command.lun ) );
|
||||
xferbuf_void_init ( &command.data_in );
|
||||
xferbuf_void_init ( &command.data_out );
|
||||
scsicmd->type->cmd ( scsicmd, &command );
|
||||
|
||||
/* Issue command */
|
||||
@@ -517,8 +519,8 @@ static void scsicmd_read_cmd ( struct scsi_command *scsicmd,
|
||||
command->cdb.read10.lba = cpu_to_be32 ( scsicmd->lba );
|
||||
command->cdb.read10.len = cpu_to_be16 ( scsicmd->count );
|
||||
}
|
||||
command->data_in = scsicmd->buffer;
|
||||
command->data_in_len = scsicmd->len;
|
||||
xferbuf_fixed_init ( &command->data_in, scsicmd->buffer,
|
||||
scsicmd->len );
|
||||
}
|
||||
|
||||
/** SCSI READ command type */
|
||||
@@ -548,8 +550,8 @@ static void scsicmd_write_cmd ( struct scsi_command *scsicmd,
|
||||
command->cdb.write10.lba = cpu_to_be32 ( scsicmd->lba );
|
||||
command->cdb.write10.len = cpu_to_be16 ( scsicmd->count );
|
||||
}
|
||||
command->data_out = scsicmd->buffer;
|
||||
command->data_out_len = scsicmd->len;
|
||||
xferbuf_fixed_init ( &command->data_out, scsicmd->buffer,
|
||||
scsicmd->len );
|
||||
}
|
||||
|
||||
/** SCSI WRITE command type */
|
||||
@@ -592,13 +594,13 @@ static void scsicmd_read_capacity_cmd ( struct scsi_command *scsicmd,
|
||||
readcap16->service_action =
|
||||
SCSI_SERVICE_ACTION_READ_CAPACITY_16;
|
||||
readcap16->len = cpu_to_be32 ( sizeof ( *capacity16 ) );
|
||||
command->data_in = capacity16;
|
||||
command->data_in_len = sizeof ( *capacity16 );
|
||||
xferbuf_fixed_init ( &command->data_in, capacity16,
|
||||
sizeof ( *capacity16 ) );
|
||||
} else {
|
||||
/* Use READ CAPACITY (10) */
|
||||
readcap10->opcode = SCSI_OPCODE_READ_CAPACITY_10;
|
||||
command->data_in = capacity10;
|
||||
command->data_in_len = sizeof ( *capacity10 );
|
||||
xferbuf_fixed_init ( &command->data_in, capacity10,
|
||||
sizeof ( *capacity10 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -424,23 +424,23 @@ static int srp_cmd ( struct srp_device *srpdev,
|
||||
memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );
|
||||
|
||||
/* Construct data-out descriptor, if present */
|
||||
if ( command->data_out ) {
|
||||
if ( command->data_out.len ) {
|
||||
cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
|
||||
data_out = iob_put ( iobuf, sizeof ( *data_out ) );
|
||||
data_out->address =
|
||||
cpu_to_be64 ( virt_to_phys ( command->data_out ) );
|
||||
cpu_to_be64 ( virt_to_phys ( command->data_out.data ) );
|
||||
data_out->handle = ntohl ( srpdev->memory_handle );
|
||||
data_out->len = ntohl ( command->data_out_len );
|
||||
data_out->len = ntohl ( command->data_out.len );
|
||||
}
|
||||
|
||||
/* Construct data-in descriptor, if present */
|
||||
if ( command->data_in ) {
|
||||
if ( command->data_in.len ) {
|
||||
cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
|
||||
data_in = iob_put ( iobuf, sizeof ( *data_in ) );
|
||||
data_in->address =
|
||||
cpu_to_be64 ( virt_to_phys ( command->data_in ) );
|
||||
cpu_to_be64 ( virt_to_phys ( command->data_in.data ) );
|
||||
data_in->handle = ntohl ( srpdev->memory_handle );
|
||||
data_in->len = ntohl ( command->data_in_len );
|
||||
data_in->len = ntohl ( command->data_in.len );
|
||||
}
|
||||
|
||||
DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
|
||||
|
||||
+27
-22
@@ -154,7 +154,7 @@ static int usbblk_out_command ( struct usbblk_device *usbblk ) {
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( cmd->tag );
|
||||
assert ( ! ( cmd->scsi.data_in_len && cmd->scsi.data_out_len ) );
|
||||
assert ( ! ( cmd->scsi.data_in.len && cmd->scsi.data_out.len ) );
|
||||
|
||||
/* Allocate I/O buffer */
|
||||
iobuf = alloc_iob ( sizeof ( *wrapper ) );
|
||||
@@ -168,10 +168,10 @@ static int usbblk_out_command ( struct usbblk_device *usbblk ) {
|
||||
memset ( wrapper, 0, sizeof ( *wrapper ) );
|
||||
wrapper->signature = cpu_to_le32 ( USBBLK_COMMAND_SIGNATURE );
|
||||
wrapper->tag = cmd->tag; /* non-endian */
|
||||
if ( cmd->scsi.data_out_len ) {
|
||||
wrapper->len = cpu_to_le32 ( cmd->scsi.data_out_len );
|
||||
if ( cmd->scsi.data_out.len ) {
|
||||
wrapper->len = cpu_to_le32 ( cmd->scsi.data_out.len );
|
||||
} else {
|
||||
wrapper->len = cpu_to_le32 ( cmd->scsi.data_in_len );
|
||||
wrapper->len = cpu_to_le32 ( cmd->scsi.data_in.len );
|
||||
wrapper->flags = USB_DIR_IN;
|
||||
}
|
||||
wrapper->lun = ntohs ( cmd->scsi.lun.u16[0] );
|
||||
@@ -207,9 +207,9 @@ static int usbblk_out_data ( struct usbblk_device *usbblk ) {
|
||||
|
||||
/* Calculate length */
|
||||
assert ( cmd->tag );
|
||||
assert ( cmd->scsi.data_out != NULL );
|
||||
assert ( cmd->offset < cmd->scsi.data_out_len );
|
||||
len = ( cmd->scsi.data_out_len - cmd->offset );
|
||||
assert ( cmd->scsi.data_out.len != 0 );
|
||||
assert ( cmd->offset < cmd->scsi.data_out.len );
|
||||
len = ( cmd->scsi.data_out.len - cmd->offset );
|
||||
if ( len > USBBLK_MAX_LEN )
|
||||
len = USBBLK_MAX_LEN;
|
||||
assert ( ( len % usbblk->out.mtu ) == 0 );
|
||||
@@ -222,8 +222,9 @@ static int usbblk_out_data ( struct usbblk_device *usbblk ) {
|
||||
}
|
||||
|
||||
/* Populate I/O buffer */
|
||||
memcpy ( iob_put ( iobuf, len ),
|
||||
( cmd->scsi.data_out + cmd->offset ), len );
|
||||
if ( ( rc = xferbuf_read ( &cmd->scsi.data_out, cmd->offset,
|
||||
iob_put ( iobuf, len ), len ) ) != 0 )
|
||||
goto err_read;
|
||||
|
||||
/* Send data */
|
||||
if ( ( rc = usb_stream ( &usbblk->out, iobuf, 0 ) ) != 0 ) {
|
||||
@@ -238,6 +239,7 @@ static int usbblk_out_data ( struct usbblk_device *usbblk ) {
|
||||
return 0;
|
||||
|
||||
err_stream:
|
||||
err_read:
|
||||
free_iob ( iobuf );
|
||||
err_alloc:
|
||||
return rc;
|
||||
@@ -257,7 +259,7 @@ static int usbblk_out_refill ( struct usbblk_device *usbblk ) {
|
||||
assert ( cmd->tag );
|
||||
|
||||
/* Refill endpoint */
|
||||
while ( ( cmd->offset < cmd->scsi.data_out_len ) &&
|
||||
while ( ( cmd->offset < cmd->scsi.data_out.len ) &&
|
||||
( usbblk->out.fill < USBBLK_MAX_FILL ) ) {
|
||||
if ( ( rc = usbblk_out_data ( usbblk ) ) != 0 )
|
||||
return rc;
|
||||
@@ -294,7 +296,7 @@ static void usbblk_out_complete ( struct usb_endpoint *ep,
|
||||
}
|
||||
|
||||
/* Trigger refill process, if applicable */
|
||||
if ( cmd->offset < cmd->scsi.data_out_len )
|
||||
if ( cmd->offset < cmd->scsi.data_out.len )
|
||||
process_add ( &usbblk->process );
|
||||
|
||||
drop:
|
||||
@@ -331,15 +333,18 @@ static struct usb_endpoint_driver_operations usbblk_out_operations = {
|
||||
static int usbblk_in_data ( struct usbblk_device *usbblk, const void *data,
|
||||
size_t len ) {
|
||||
struct usbblk_command *cmd = &usbblk->cmd;
|
||||
int rc;
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( cmd->tag );
|
||||
assert ( cmd->scsi.data_in != NULL );
|
||||
assert ( cmd->offset <= cmd->scsi.data_in_len );
|
||||
assert ( len <= ( cmd->scsi.data_in_len - cmd->offset ) );
|
||||
assert ( cmd->scsi.data_in.len != 0 );
|
||||
assert ( cmd->offset <= cmd->scsi.data_in.len );
|
||||
assert ( len <= ( cmd->scsi.data_in.len - cmd->offset ) );
|
||||
|
||||
/* Store data */
|
||||
memcpy ( ( cmd->scsi.data_in + cmd->offset ), data, len );
|
||||
if ( ( rc = xferbuf_write ( &cmd->scsi.data_in, cmd->offset,
|
||||
data, len ) ) != 0 )
|
||||
return rc;
|
||||
cmd->offset += len;
|
||||
|
||||
return 0;
|
||||
@@ -426,9 +431,9 @@ static int usbblk_in_refill ( struct usbblk_device *usbblk ) {
|
||||
|
||||
/* Calculate maximum required refill */
|
||||
remaining = sizeof ( *stat );
|
||||
if ( cmd->scsi.data_in_len ) {
|
||||
assert ( cmd->offset <= cmd->scsi.data_in_len );
|
||||
remaining += ( cmd->scsi.data_in_len - cmd->offset );
|
||||
if ( cmd->scsi.data_in.len ) {
|
||||
assert ( cmd->offset <= cmd->scsi.data_in.len );
|
||||
remaining += ( cmd->scsi.data_in.len - cmd->offset );
|
||||
}
|
||||
max = ( ( remaining + USBBLK_MAX_LEN - 1 ) / USBBLK_MAX_LEN );
|
||||
|
||||
@@ -472,9 +477,9 @@ static void usbblk_in_complete ( struct usb_endpoint *ep,
|
||||
process_add ( &usbblk->process );
|
||||
|
||||
/* Handle data portion, if any */
|
||||
if ( cmd->scsi.data_in_len ) {
|
||||
assert ( cmd->offset <= cmd->scsi.data_in_len );
|
||||
remaining = ( cmd->scsi.data_in_len - cmd->offset );
|
||||
if ( cmd->scsi.data_in.len ) {
|
||||
assert ( cmd->offset <= cmd->scsi.data_in.len );
|
||||
remaining = ( cmd->scsi.data_in.len - cmd->offset );
|
||||
len = iob_len ( iobuf );
|
||||
if ( len > remaining )
|
||||
len = remaining;
|
||||
@@ -591,7 +596,7 @@ static int usbblk_start ( struct usbblk_device *usbblk,
|
||||
}
|
||||
|
||||
/* Refuse bidirectional commands */
|
||||
if ( scsicmd->data_in_len && scsicmd->data_out_len ) {
|
||||
if ( scsicmd->data_in.len && scsicmd->data_out.len ) {
|
||||
rc = -EOPNOTSUPP;
|
||||
DBGC ( usbblk, "USBBLK %s cannot support bidirectional "
|
||||
"commands\n", usbblk->func->name );
|
||||
|
||||
+5
-14
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/interface.h>
|
||||
#include <ipxe/xferbuf.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
@@ -251,20 +252,10 @@ struct scsi_cmd {
|
||||
struct scsi_lun lun;
|
||||
/** CDB for this command */
|
||||
union scsi_cdb cdb;
|
||||
/** Data-out buffer (may be NULL) */
|
||||
void *data_out;
|
||||
/** Data-out buffer length
|
||||
*
|
||||
* Must be zero if @c data_out is NULL
|
||||
*/
|
||||
size_t data_out_len;
|
||||
/** Data-in buffer (may be NULL) */
|
||||
void *data_in;
|
||||
/** Data-in buffer length
|
||||
*
|
||||
* Must be zero if @c data_in is NULL
|
||||
*/
|
||||
size_t data_in_len;
|
||||
/** Data-out buffer */
|
||||
struct xfer_buffer data_out;
|
||||
/** Data-in buffer */
|
||||
struct xfer_buffer data_in;
|
||||
};
|
||||
|
||||
/** SCSI fixed-format sense data */
|
||||
|
||||
+31
-29
@@ -326,7 +326,7 @@ static int fcpcmd_send_cmnd ( struct fcp_command *fcpcmd ) {
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
if ( command->data_in_len && command->data_out_len ) {
|
||||
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;
|
||||
@@ -344,13 +344,13 @@ static int fcpcmd_send_cmnd ( struct fcp_command *fcpcmd ) {
|
||||
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 )
|
||||
assert ( ! ( command->data_in.len && command->data_out.len ) );
|
||||
if ( command->data_in.len )
|
||||
cmnd->dirn |= FCP_CMND_RDDATA;
|
||||
if ( command->data_out_len )
|
||||
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 );
|
||||
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",
|
||||
@@ -402,20 +402,18 @@ static int fcpcmd_recv_rddata ( struct fcp_command *fcpcmd,
|
||||
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 */
|
||||
memcpy ( ( command->data_in + offset ), iobuf->data, len );
|
||||
if ( ( rc = xferbuf_write ( &command->data_in, offset,
|
||||
iobuf->data, len ) ) != 0 ) {
|
||||
DBGC ( fcpdev, "FCP %p xchg %04x buffer overrun: %s\n",
|
||||
fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
|
||||
goto done;
|
||||
}
|
||||
fcpcmd->offset += len;
|
||||
assert ( fcpcmd->offset <= command->data_in_len );
|
||||
assert ( fcpcmd->offset <= command->data_in.len );
|
||||
|
||||
rc = 0;
|
||||
done:
|
||||
@@ -446,13 +444,8 @@ static int fcpcmd_send_wrdata ( struct fcp_command *fcpcmd ) {
|
||||
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;
|
||||
rc = -ERANGE_WRITE_DATA_STUCK;
|
||||
goto err_sanity;
|
||||
}
|
||||
|
||||
/* Allocate I/O buffer */
|
||||
@@ -460,12 +453,14 @@ static int fcpcmd_send_wrdata ( struct fcp_command *fcpcmd ) {
|
||||
if ( ! iobuf ) {
|
||||
DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate write data "
|
||||
"IU for %zd bytes\n", fcpdev, fcpcmd->xchg_id, len );
|
||||
return -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Construct data IU frame */
|
||||
memcpy ( iob_put ( iobuf, len ),
|
||||
( command->data_out + fcpcmd->offset ), len );
|
||||
if ( ( rc = xferbuf_read ( &command->data_out, fcpcmd->offset,
|
||||
iob_put ( iobuf, len ), len ) ) != 0 )
|
||||
goto err_read;
|
||||
memset ( &meta, 0, sizeof ( meta ) );
|
||||
meta.flags = ( XFER_FL_RESPONSE | XFER_FL_ABS_OFFSET );
|
||||
meta.offset = fcpcmd->offset;
|
||||
@@ -477,7 +472,7 @@ static int fcpcmd_send_wrdata ( struct fcp_command *fcpcmd ) {
|
||||
assert ( len <= fcpcmd->remaining );
|
||||
fcpcmd->offset += len;
|
||||
fcpcmd->remaining -= len;
|
||||
assert ( fcpcmd->offset <= command->data_out_len );
|
||||
assert ( fcpcmd->offset <= command->data_out.len );
|
||||
if ( fcpcmd->remaining == 0 ) {
|
||||
fcpcmd_stop_send ( fcpcmd );
|
||||
meta.flags |= XFER_FL_OVER;
|
||||
@@ -488,10 +483,17 @@ static int fcpcmd_send_wrdata ( struct fcp_command *fcpcmd ) {
|
||||
&meta ) ) != 0 ) {
|
||||
DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver write data "
|
||||
"IU: %s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
|
||||
return rc;
|
||||
goto err_deliver;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_deliver:
|
||||
err_read:
|
||||
free_iob ( iobuf );
|
||||
err_alloc:
|
||||
err_sanity:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -590,11 +592,11 @@ static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd,
|
||||
|
||||
/* Check for locally-detected command underrun */
|
||||
if ( ( rsp->status == 0 ) &&
|
||||
( fcpcmd->offset != ( command->data_in_len +
|
||||
command->data_out_len ) ) ) {
|
||||
( 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 ),
|
||||
( command->data_in.len + command->data_out.len ),
|
||||
fcpcmd->offset );
|
||||
rc = -ERANGE_DATA_UNDERRUN;
|
||||
goto done;
|
||||
|
||||
+41
-23
@@ -377,32 +377,32 @@ static void iscsi_scsi_done ( struct iscsi_session *iscsi, int rc,
|
||||
static void iscsi_start_command ( struct iscsi_session *iscsi ) {
|
||||
struct iscsi_bhs_scsi_command *command = &iscsi->tx_bhs.scsi_command;
|
||||
|
||||
assert ( ! ( iscsi->command->data_in && iscsi->command->data_out ) );
|
||||
assert ( ! ( iscsi->command->data_in.len &&
|
||||
iscsi->command->data_out.len ) );
|
||||
|
||||
/* Construct BHS and initiate transmission */
|
||||
iscsi_start_tx ( iscsi );
|
||||
command->opcode = ISCSI_OPCODE_SCSI_COMMAND;
|
||||
command->flags = ( ISCSI_FLAG_FINAL |
|
||||
ISCSI_COMMAND_ATTR_SIMPLE );
|
||||
if ( iscsi->command->data_in )
|
||||
if ( iscsi->command->data_in.len )
|
||||
command->flags |= ISCSI_COMMAND_FLAG_READ;
|
||||
if ( iscsi->command->data_out )
|
||||
if ( iscsi->command->data_out.len )
|
||||
command->flags |= ISCSI_COMMAND_FLAG_WRITE;
|
||||
/* lengths left as zero */
|
||||
memcpy ( &command->lun, &iscsi->command->lun,
|
||||
sizeof ( command->lun ) );
|
||||
command->itt = htonl ( iscsi->itt );
|
||||
command->exp_len = htonl ( iscsi->command->data_in_len |
|
||||
iscsi->command->data_out_len );
|
||||
command->exp_len = htonl ( iscsi->command->data_in.len |
|
||||
iscsi->command->data_out.len );
|
||||
command->cmdsn = htonl ( iscsi->cmdsn );
|
||||
command->expstatsn = htonl ( iscsi->statsn + 1 );
|
||||
memcpy ( &command->cdb, &iscsi->command->cdb, sizeof ( command->cdb ));
|
||||
DBGC2 ( iscsi, "iSCSI %p start " SCSI_CDB_FORMAT " %s %#zx\n",
|
||||
iscsi, SCSI_CDB_DATA ( command->cdb ),
|
||||
( iscsi->command->data_in ? "in" : "out" ),
|
||||
( iscsi->command->data_in ?
|
||||
iscsi->command->data_in_len :
|
||||
iscsi->command->data_out_len ) );
|
||||
( iscsi->command->data_in.len ? "in" : "out" ),
|
||||
( iscsi->command->data_in.len +
|
||||
iscsi->command->data_out.len ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -472,13 +472,14 @@ static int iscsi_rx_data_in ( struct iscsi_session *iscsi,
|
||||
size_t remaining ) {
|
||||
struct iscsi_bhs_data_in *data_in = &iscsi->rx_bhs.data_in;
|
||||
unsigned long offset;
|
||||
int rc;
|
||||
|
||||
/* Copy data to data-in buffer */
|
||||
offset = ntohl ( data_in->offset ) + iscsi->rx_offset;
|
||||
assert ( iscsi->command != NULL );
|
||||
assert ( iscsi->command->data_in );
|
||||
assert ( ( offset + len ) <= iscsi->command->data_in_len );
|
||||
memcpy ( ( iscsi->command->data_in + offset ), data, len );
|
||||
if ( ( rc = xferbuf_write ( &iscsi->command->data_in, offset,
|
||||
data, len ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Wait for whole SCSI response to arrive */
|
||||
if ( remaining )
|
||||
@@ -486,7 +487,7 @@ static int iscsi_rx_data_in ( struct iscsi_session *iscsi,
|
||||
|
||||
/* Mark as completed if status is present */
|
||||
if ( data_in->flags & ISCSI_DATA_FLAG_STATUS ) {
|
||||
assert ( ( offset + len ) == iscsi->command->data_in_len );
|
||||
assert ( ( offset + len ) == iscsi->command->data_in.len );
|
||||
assert ( data_in->flags & ISCSI_FLAG_FINAL );
|
||||
/* iSCSI cannot return an error status via a data-in */
|
||||
iscsi_scsi_done ( iscsi, 0, NULL );
|
||||
@@ -585,24 +586,41 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
|
||||
unsigned long offset;
|
||||
size_t len;
|
||||
size_t pad_len;
|
||||
int rc;
|
||||
|
||||
/* Calculate offset and lengths */
|
||||
offset = ntohl ( data_out->offset );
|
||||
len = ISCSI_DATA_LEN ( data_out->lengths );
|
||||
pad_len = ISCSI_DATA_PAD_LEN ( data_out->lengths );
|
||||
|
||||
assert ( iscsi->command != NULL );
|
||||
assert ( iscsi->command->data_out );
|
||||
assert ( ( offset + len ) <= iscsi->command->data_out_len );
|
||||
|
||||
/* Allocate I/O buffer */
|
||||
iobuf = xfer_alloc_iob ( &iscsi->socket, ( len + pad_len ) );
|
||||
if ( ! iobuf )
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy ( iob_put ( iobuf, len ),
|
||||
( iscsi->command->data_out + offset ), len );
|
||||
if ( ! iobuf ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Copy data to I/O buffer */
|
||||
assert ( iscsi->command != NULL );
|
||||
if ( ( rc = xferbuf_read ( &iscsi->command->data_out, offset,
|
||||
iob_put ( iobuf, len ), len ) ) != 0 ) {
|
||||
goto err_read;
|
||||
}
|
||||
memset ( iob_put ( iobuf, pad_len ), 0, pad_len );
|
||||
|
||||
return xfer_deliver_iob ( &iscsi->socket, iobuf );
|
||||
/* Deliver I/O buffer */
|
||||
if ( ( rc = xfer_deliver_iob ( &iscsi->socket,
|
||||
iob_disown ( iobuf ) ) ) != 0 ) {
|
||||
goto err_deliver;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_deliver:
|
||||
err_read:
|
||||
free_iob ( iobuf );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user