/** Command for LBA48-capable devices */
uint8_t cmd_lba48;
/**
- * Calculate data-in buffer
+ * Initialise data-in buffer
*
* @v atacmd ATA command
+ * @v xferbuf Data transfer buffer
* @v buffer Available buffer
* @v len Available buffer length
- * @ret data_in Data-in buffer
- * @ret data_in_len Data-in buffer length
*/
- void ( * data_in ) ( struct ata_command *atacmd, void *buffer,
- size_t len, void **data_in,
- size_t *data_in_len );
+ void ( * data_in ) ( struct ata_command *atacmd,
+ struct xfer_buffer *xferbuf,
+ void *buffer, size_t len );
/**
- * Calculate data-out buffer
- *
+ * Initialise data-out buffer
*
* @v atacmd ATA command
+ * @v xferbuf Data transfer buffer
* @v buffer Available buffer
* @v len Available buffer length
- * @ret data_out Data-out buffer
- * @ret data_out_len Data-out buffer length
*/
- void ( * data_out ) ( struct ata_command *atacmd, void *buffer,
- size_t len, void **data_out,
- size_t *data_out_len );
+ void ( * data_out ) ( struct ata_command *atacmd,
+ struct xfer_buffer *xferbuf,
+ void *buffer, size_t len );
/**
* Handle ATA command completion
*
* Use provided data buffer for ATA command
*
* @v atacmd ATA command
+ * @v xferbuf Data transfer buffer
* @v buffer Available buffer
* @v len Available buffer length
- * @ret data Data buffer
- * @ret data_len Data buffer length
*/
static void atacmd_data_buffer ( struct ata_command *atacmd __unused,
- void *buffer, size_t len,
- void **data, size_t *data_len ) {
- *data = buffer;
- *data_len = len;
+ struct xfer_buffer *xferbuf,
+ void *buffer, size_t len ) {
+ xferbuf_fixed_init ( xferbuf, buffer, len );
}
/**
* Use no data buffer for ATA command
*
* @v atacmd ATA command
+ * @v xferbuf Data transfer buffer
* @v buffer Available buffer
* @v len Available buffer length
- * @ret data Data buffer
- * @ret data_len Data buffer length
*/
static void atacmd_data_none ( struct ata_command *atacmd __unused,
- void *buffer __unused, size_t len __unused,
- void **data __unused,
- size_t *data_len __unused ) {
- /* Nothing to do */
+ struct xfer_buffer *xferbuf,
+ void *buffer __unused, size_t len __unused ) {
+ xferbuf_void_init ( xferbuf );
}
/**
* Use private data buffer for ATA command
*
* @v atacmd ATA command
+ * @v xferbuf Data transfer buffer
* @v buffer Available buffer
* @v len Available buffer length
- * @ret data Data buffer
- * @ret data_len Data buffer length
*/
static void atacmd_data_priv ( struct ata_command *atacmd,
- void *buffer __unused, size_t len __unused,
- void **data, size_t *data_len ) {
- *data = atacmd_priv ( atacmd );
- *data_len = atacmd->type->priv_len;
+ struct xfer_buffer *xferbuf,
+ void *buffer __unused, size_t len __unused ) {
+
+ xferbuf_fixed_init ( xferbuf, atacmd_priv ( atacmd ),
+ atacmd->type->priv_len );
}
/** ATA READ command type */
command.cb.device |= command.cb.lba.bytes.low_prev;
command.cb.cmd_stat =
( atadev->lba48 ? type->cmd_lba48 : type->cmd_lba );
- type->data_in ( atacmd, buffer, len,
- &command.data_in, &command.data_in_len );
- type->data_out ( atacmd, buffer, len,
- &command.data_out, &command.data_out_len );
+ type->data_in ( atacmd, &command.data_in, buffer, len );
+ type->data_out ( atacmd, &command.data_out, buffer, len );
/* Issue command */
if ( ( tag = ata_command ( &atadev->ata, &atacmd->ata,
* @v aoecmd AoE command
* @v data Command IU
* @v len Length of command IU
+ * @ret rc Return status code
*/
- void ( * cmd ) ( struct aoe_command *aoecmd, void *data, size_t len );
+ int ( * cmd ) ( struct aoe_command *aoecmd, void *data, size_t len );
/**
* Handle AoE response IU
*
/* Create outgoing I/O buffer */
cmd_len = aoecmd->type->cmd_len ( aoecmd );
iobuf = alloc_iob ( MAX_LL_HEADER_LEN + cmd_len );
- if ( ! iobuf )
- return -ENOMEM;
+ if ( ! iobuf ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
aoehdr = iob_put ( iobuf, cmd_len );
aoehdr->major = htons ( aoedev->major );
aoehdr->minor = aoedev->minor;
aoehdr->tag = htonl ( aoecmd->tag );
- aoecmd->type->cmd ( aoecmd, iobuf->data, iob_len ( iobuf ) );
+ if ( ( rc = aoecmd->type->cmd ( aoecmd, iobuf->data,
+ iob_len ( iobuf ) ) ) != 0 ) {
+ goto err_cmd;
+ }
/* Send packet */
- if ( ( rc = net_tx ( iobuf, netdev, &aoe_protocol, aoedev->target,
- netdev->ll_addr ) ) != 0 ) {
+ if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &aoe_protocol,
+ aoedev->target, netdev->ll_addr ) ) != 0 ) {
DBGC ( aoedev, "AoE %s/%08x could not transmit: %s\n",
aoedev_name ( aoedev ), aoecmd->tag,
strerror ( rc ) );
- return rc;
+ goto err_tx;
}
return 0;
+
+ err_tx:
+ err_cmd:
+ free_iob ( iobuf );
+ err_alloc:
+ return rc;
}
/**
struct ata_cmd *command = &aoecmd->command;
return ( sizeof ( struct aoehdr ) + sizeof ( struct aoeata ) +
- command->data_out_len );
+ command->data_out.len );
}
/**
* @v aoecmd AoE command
* @v data Command IU
* @v len Length of command IU
+ * @ret rc Return status code
*/
-static void aoecmd_ata_cmd ( struct aoe_command *aoecmd,
- void *data, size_t len ) {
+static int aoecmd_ata_cmd ( struct aoe_command *aoecmd,
+ void *data, size_t len ) {
struct aoe_device *aoedev = aoecmd->aoedev;
struct ata_cmd *command = &aoecmd->command;
struct aoehdr *aoehdr = data;
struct aoeata *aoeata = &aoehdr->payload[0].ata;
+ int rc;
/* Sanity check */
static_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE );
assert ( len == ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) +
- command->data_out_len ) );
+ command->data_out.len ) );
/* Build IU */
aoehdr->command = AOE_CMD_ATA;
memset ( aoeata, 0, sizeof ( *aoeata ) );
aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
( command->cb.device & ATA_DEV_SLAVE ) |
- ( command->data_out_len ? AOE_FL_WRITE : 0 ) );
+ ( command->data_out.len ? AOE_FL_WRITE : 0 ) );
aoeata->err_feat = command->cb.err_feat.bytes.cur;
aoeata->count = command->cb.count.native;
aoeata->cmd_stat = command->cb.cmd_stat;
if ( ! command->cb.lba48 )
aoeata->lba.bytes[3] |=
( command->cb.device & ATA_DEV_MASK );
- memcpy ( aoeata->data, command->data_out, command->data_out_len );
-
DBGC2 ( aoedev, "AoE %s/%08x ATA cmd %02x:%02x:%02x:%02x:%08llx",
aoedev_name ( aoedev ), aoecmd->tag, aoeata->aflags,
aoeata->err_feat, aoeata->count, aoeata->cmd_stat,
aoeata->lba.u64 );
- if ( command->data_out_len )
- DBGC2 ( aoedev, " out %04zx", command->data_out_len );
- if ( command->data_in_len )
- DBGC2 ( aoedev, " in %04zx", command->data_in_len );
+ if ( command->data_out.len )
+ DBGC2 ( aoedev, " out %04zx", command->data_out.len );
+ if ( command->data_in.len )
+ DBGC2 ( aoedev, " in %04zx", command->data_in.len );
DBGC2 ( aoedev, "\n" );
+
+ /* Copy data-out (if any) to command IU */
+ if ( ( rc = xferbuf_read ( &command->data_out, 0, aoeata->data,
+ command->data_out.len ) ) != 0 ) {
+ DBGC ( aoedev, "AoE %s/%08x could not read data-out: %s\n",
+ aoedev_name ( aoedev ), aoecmd->tag, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
}
/**
const struct aoehdr *aoehdr = data;
const struct aoeata *aoeata = &aoehdr->payload[0].ata;
size_t data_len;
+ int rc;
/* Sanity check */
if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) ) ) {
/* Check data-in length is sufficient. (There may be trailing
* garbage due to Ethernet minimum-frame-size padding.)
*/
- if ( data_len < command->data_in_len ) {
+ if ( data_len < command->data_in.len ) {
DBGC ( aoedev, "AoE %s/%08x data-in underrun (received %zd, "
"expected %zd)\n", aoedev_name ( aoedev ), aoecmd->tag,
- data_len, command->data_in_len );
+ data_len, command->data_in.len );
return -ERANGE;
}
/* Copy out data payload */
- memcpy ( command->data_in, aoeata->data, command->data_in_len );
+ if ( ( rc = xferbuf_write ( &command->data_in, 0, aoeata->data,
+ command->data_in.len ) ) != 0 ) {
+ DBGC ( aoedev, "AoE %s/%08x could not write data-in: %s\n",
+ aoedev_name ( aoedev ), aoecmd->tag, strerror ( rc ) );
+ return rc;
+ }
return 0;
}
* @v aoecmd AoE command
* @v data Command IU
* @v len Length of command IU
+ * @ret rc Return status code
*/
-static void aoecmd_cfg_cmd ( struct aoe_command *aoecmd,
- void *data, size_t len ) {
+static int aoecmd_cfg_cmd ( struct aoe_command *aoecmd,
+ void *data, size_t len ) {
struct aoe_device *aoedev = aoecmd->aoedev;
struct aoehdr *aoehdr = data;
struct aoecfg *aoecfg = &aoehdr->payload[0].cfg;
/* Build IU */
aoehdr->command = AOE_CMD_CONFIG;
memset ( aoecfg, 0, sizeof ( *aoecfg ) );
-
DBGC ( aoedev, "AoE %s/%08x CONFIG cmd\n",
aoedev_name ( aoedev ), aoecmd->tag );
+
+ return 0;
}
/**