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