mirror of https://github.com/ipxe/ipxe.git
Added generic asynchronous operations code.
Removed data_in_len and data_out_len from ata_command structure; the lengths are implied by the sector count and the presence of the data_in or data_out pointers. Changed AoE code to use subcommands by default, and made aoe_issue() nonblocking (with completion via async_wait()).pull/1/head
parent
73a449e96b
commit
68125bc441
|
@ -37,7 +37,8 @@ static int aoe_command ( struct ata_device *ata,
|
||||||
struct aoe_device *aoedev
|
struct aoe_device *aoedev
|
||||||
= container_of ( ata, struct aoe_device, ata );
|
= container_of ( ata, struct aoe_device, ata );
|
||||||
|
|
||||||
return aoe_issue_split ( &aoedev->aoe, command );
|
aoe_issue ( &aoedev->aoe, command );
|
||||||
|
return async_wait ( &aoedev->aoe.aop );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <byteswap.h>
|
#include <byteswap.h>
|
||||||
#include <gpxe/blockdev.h>
|
#include <gpxe/blockdev.h>
|
||||||
#include <gpxe/ata.h>
|
#include <gpxe/ata.h>
|
||||||
|
@ -73,7 +74,6 @@ static int ata_read ( struct block_device *blockdev, uint64_t block,
|
||||||
command.cb.device |= command.cb.lba.bytes.low_prev;
|
command.cb.device |= command.cb.lba.bytes.low_prev;
|
||||||
command.cb.cmd_stat = ( ata->lba48 ? ATA_CMD_READ_EXT : ATA_CMD_READ );
|
command.cb.cmd_stat = ( ata->lba48 ? ATA_CMD_READ_EXT : ATA_CMD_READ );
|
||||||
command.data_in = buffer;
|
command.data_in = buffer;
|
||||||
command.data_in_len = ( count * blockdev->blksize );
|
|
||||||
return ata_command ( ata, &command );
|
return ata_command ( ata, &command );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,6 @@ static int ata_write ( struct block_device *blockdev, uint64_t block,
|
||||||
command.cb.cmd_stat = ( ata->lba48 ?
|
command.cb.cmd_stat = ( ata->lba48 ?
|
||||||
ATA_CMD_WRITE_EXT : ATA_CMD_WRITE );
|
ATA_CMD_WRITE_EXT : ATA_CMD_WRITE );
|
||||||
command.data_out = buffer;
|
command.data_out = buffer;
|
||||||
command.data_out_len = ( count * blockdev->blksize );
|
|
||||||
return ata_command ( ata, &command );
|
return ata_command ( ata, &command );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,12 +118,12 @@ static int ata_identify ( struct block_device *blockdev ) {
|
||||||
|
|
||||||
/* Issue IDENTIFY */
|
/* Issue IDENTIFY */
|
||||||
memset ( &command, 0, sizeof ( command ) );
|
memset ( &command, 0, sizeof ( command ) );
|
||||||
command.cb.count.native = 1; /* n/a according to spec, but at least
|
command.cb.count.native = 1;
|
||||||
* AoE vblade devices require it. */
|
|
||||||
command.cb.device = ( ata->device | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
|
command.cb.device = ( ata->device | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
|
||||||
command.cb.cmd_stat = ATA_CMD_IDENTIFY;
|
command.cb.cmd_stat = ATA_CMD_IDENTIFY;
|
||||||
command.data_in = virt_to_user ( &identity );
|
command.data_in = virt_to_user ( &identity );
|
||||||
command.data_in_len = sizeof ( identity );
|
linker_assert ( sizeof ( identity ) == ATA_SECTOR_SIZE,
|
||||||
|
__ata_identity_bad_size__ );
|
||||||
if ( ( rc = ata_command ( ata, &command ) ) != 0 )
|
if ( ( rc = ata_command ( ata, &command ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <gpxe/list.h>
|
#include <gpxe/list.h>
|
||||||
#include <gpxe/if_ether.h>
|
#include <gpxe/if_ether.h>
|
||||||
|
#include <gpxe/retry.h>
|
||||||
|
#include <gpxe/async.h>
|
||||||
#include <gpxe/ata.h>
|
#include <gpxe/ata.h>
|
||||||
|
|
||||||
/** An AoE ATA command */
|
/** An AoE ATA command */
|
||||||
|
@ -89,29 +91,31 @@ struct aoe_session {
|
||||||
/** Target MAC address */
|
/** Target MAC address */
|
||||||
uint8_t target[ETH_ALEN];
|
uint8_t target[ETH_ALEN];
|
||||||
|
|
||||||
/** Tag for current command */
|
/** Tag for current AoE command */
|
||||||
uint32_t tag;
|
uint32_t tag;
|
||||||
|
|
||||||
/** Current ATA command */
|
/** Current ATA command */
|
||||||
struct ata_command *command;
|
struct ata_command *command;
|
||||||
/** Status of the command */
|
/** Overall status of current ATA command */
|
||||||
int status;
|
unsigned int status;
|
||||||
/** Byte offset within command's data buffer */
|
/** Byte offset within command's data buffer */
|
||||||
unsigned int command_offset;
|
unsigned int command_offset;
|
||||||
|
/** Asynchronous operation for this command */
|
||||||
|
struct async_operation aop;
|
||||||
|
|
||||||
|
/** Retransmission timer */
|
||||||
|
struct retry_timer timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define AOE_STATUS_ERR_MASK 0x0f /**< Error portion of status code */
|
#define AOE_STATUS_ERR_MASK 0x0f /**< Error portion of status code */
|
||||||
#define AOE_STATUS_PENDING 0x80 /**< Command pending */
|
#define AOE_STATUS_PENDING 0x80 /**< Command pending */
|
||||||
#define AOE_STATUS_UNDERRUN 0x40 /**< Buffer overrun */
|
|
||||||
#define AOE_STATUS_OVERRUN 0x20 /**< Buffer underrun */
|
|
||||||
|
|
||||||
/** Maximum number of sectors per packet */
|
/** Maximum number of sectors per packet */
|
||||||
#define AOE_MAX_COUNT 2
|
#define AOE_MAX_COUNT 2
|
||||||
|
|
||||||
extern void aoe_open ( struct aoe_session *aoe );
|
extern void aoe_open ( struct aoe_session *aoe );
|
||||||
extern void aoe_close ( struct aoe_session *aoe );
|
extern void aoe_close ( struct aoe_session *aoe );
|
||||||
extern int aoe_issue ( struct aoe_session *aoe, struct ata_command *command );
|
extern void aoe_issue ( struct aoe_session *aoe, struct ata_command *command );
|
||||||
extern int aoe_issue_split ( struct aoe_session *aoe,
|
|
||||||
struct ata_command *command );
|
|
||||||
|
|
||||||
/** An AoE device */
|
/** An AoE device */
|
||||||
struct aoe_device {
|
struct aoe_device {
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
#ifndef _GPXE_ASYNC_H
|
||||||
|
#define _GPXE_ASYNC_H
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
*
|
||||||
|
* Asynchronous operations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/** An asynchronous operation */
|
||||||
|
struct async_operation {
|
||||||
|
/** Operation status
|
||||||
|
*
|
||||||
|
* This is an error code as defined in errno.h, plus an offset
|
||||||
|
* of EINPROGRESS. This means that a status value of 0
|
||||||
|
* corresponds to a return status code of -EINPROGRESS,
|
||||||
|
* i.e. that the default state of an asynchronous operation is
|
||||||
|
* "not yet completed".
|
||||||
|
*/
|
||||||
|
int status;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set asynchronous operation status
|
||||||
|
*
|
||||||
|
* @v aop Asynchronous operation
|
||||||
|
* @v rc Return status code
|
||||||
|
*/
|
||||||
|
static inline __attribute__ (( always_inline )) void
|
||||||
|
async_set_status ( struct async_operation *aop, int rc ) {
|
||||||
|
aop->status = ( rc + EINPROGRESS );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get asynchronous operation status
|
||||||
|
*
|
||||||
|
* @v aop Asynchronous operation
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static inline __attribute__ (( always_inline )) int
|
||||||
|
async_status ( struct async_operation *aop ) {
|
||||||
|
return ( aop->status - EINPROGRESS );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag asynchronous operation as complete
|
||||||
|
*
|
||||||
|
* @v aop Asynchronous operation
|
||||||
|
* @v rc Return status code
|
||||||
|
*/
|
||||||
|
static inline __attribute__ (( always_inline )) void
|
||||||
|
async_done ( struct async_operation *aop, int rc ) {
|
||||||
|
assert ( rc != -EINPROGRESS );
|
||||||
|
async_set_status ( aop, rc );
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int async_wait ( struct async_operation *aop );
|
||||||
|
|
||||||
|
#endif /* _GPXE_ASYNC_H */
|
|
@ -139,20 +139,18 @@ struct ata_cb {
|
||||||
struct ata_command {
|
struct ata_command {
|
||||||
/** ATA command block */
|
/** ATA command block */
|
||||||
struct ata_cb cb;
|
struct ata_cb cb;
|
||||||
/** Data-out buffer (may be NULL) */
|
/** Data-out buffer (may be NULL)
|
||||||
|
*
|
||||||
|
* If non-NULL, this buffer must be ata_command::cb::count
|
||||||
|
* sectors in size.
|
||||||
|
*/
|
||||||
userptr_t data_out;
|
userptr_t data_out;
|
||||||
/** Data-out buffer length
|
/** Data-in buffer (may be NULL)
|
||||||
*
|
*
|
||||||
* Must be zero if @c data_out is NULL
|
* If non-NULL, this buffer must be ata_command::cb::count
|
||||||
|
* sectors in size.
|
||||||
*/
|
*/
|
||||||
size_t data_out_len;
|
|
||||||
/** Data-in buffer (may be NULL) */
|
|
||||||
userptr_t data_in;
|
userptr_t data_in;
|
||||||
/** Data-in buffer length
|
|
||||||
*
|
|
||||||
* Must be zero if @c data_in is NULL
|
|
||||||
*/
|
|
||||||
size_t data_in_len;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
170
src/net/aoe.c
170
src/net/aoe.c
|
@ -28,7 +28,7 @@
|
||||||
#include <gpxe/uaccess.h>
|
#include <gpxe/uaccess.h>
|
||||||
#include <gpxe/ata.h>
|
#include <gpxe/ata.h>
|
||||||
#include <gpxe/netdevice.h>
|
#include <gpxe/netdevice.h>
|
||||||
#include <gpxe/process.h>
|
#include <gpxe/async.h>
|
||||||
#include <gpxe/aoe.h>
|
#include <gpxe/aoe.h>
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
@ -42,6 +42,22 @@ struct net_protocol aoe_protocol;
|
||||||
/** List of all AoE sessions */
|
/** List of all AoE sessions */
|
||||||
static LIST_HEAD ( aoe_sessions );
|
static LIST_HEAD ( aoe_sessions );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark current AoE command complete
|
||||||
|
*
|
||||||
|
* @v aoe AoE session
|
||||||
|
* @v rc Return status code
|
||||||
|
*/
|
||||||
|
static void aoe_done ( struct aoe_session *aoe, int rc ) {
|
||||||
|
|
||||||
|
/* Record overall command status */
|
||||||
|
aoe->command->cb.cmd_stat = aoe->status;
|
||||||
|
aoe->command = NULL;
|
||||||
|
|
||||||
|
/* Mark async operation as complete */
|
||||||
|
async_done ( &aoe->aop, rc );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send AoE command
|
* Send AoE command
|
||||||
*
|
*
|
||||||
|
@ -56,10 +72,18 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
|
||||||
struct pk_buff *pkb;
|
struct pk_buff *pkb;
|
||||||
struct aoehdr *aoehdr;
|
struct aoehdr *aoehdr;
|
||||||
struct aoecmd *aoecmd;
|
struct aoecmd *aoecmd;
|
||||||
|
unsigned int count;
|
||||||
|
unsigned int data_out_len;
|
||||||
|
|
||||||
|
/* Calculate count and data_out_len for this subcommand */
|
||||||
|
count = command->cb.count.native;
|
||||||
|
if ( count > AOE_MAX_COUNT )
|
||||||
|
count = AOE_MAX_COUNT;
|
||||||
|
data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 );
|
||||||
|
|
||||||
/* Create outgoing packet buffer */
|
/* Create outgoing packet buffer */
|
||||||
pkb = alloc_pkb ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
|
pkb = alloc_pkb ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
|
||||||
command->data_out_len );
|
data_out_len );
|
||||||
if ( ! pkb )
|
if ( ! pkb )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
pkb->net_protocol = &aoe_protocol;
|
pkb->net_protocol = &aoe_protocol;
|
||||||
|
@ -78,18 +102,17 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
|
||||||
linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ );
|
linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ );
|
||||||
aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
|
aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
|
||||||
( command->cb.device & ATA_DEV_SLAVE ) |
|
( command->cb.device & ATA_DEV_SLAVE ) |
|
||||||
( command->data_out_len ? AOE_FL_WRITE : 0 ) );
|
( data_out_len ? AOE_FL_WRITE : 0 ) );
|
||||||
aoecmd->err_feat = command->cb.err_feat.bytes.cur;
|
aoecmd->err_feat = command->cb.err_feat.bytes.cur;
|
||||||
aoecmd->count = command->cb.count.bytes.cur;
|
aoecmd->count = count;
|
||||||
aoecmd->cmd_stat = command->cb.cmd_stat;
|
aoecmd->cmd_stat = command->cb.cmd_stat;
|
||||||
aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
|
aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
|
||||||
if ( ! command->cb.lba48 )
|
if ( ! command->cb.lba48 )
|
||||||
aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
|
aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
|
||||||
|
|
||||||
/* Fill data payload */
|
/* Fill data payload */
|
||||||
copy_from_user ( pkb_put ( pkb, command->data_out_len ),
|
copy_from_user ( pkb_put ( pkb, data_out_len ), command->data_out,
|
||||||
command->data_out, aoe->command_offset,
|
aoe->command_offset, data_out_len );
|
||||||
command->data_out_len );
|
|
||||||
|
|
||||||
/* Send packet */
|
/* Send packet */
|
||||||
return net_transmit_via ( pkb, aoe->netdev );
|
return net_transmit_via ( pkb, aoe->netdev );
|
||||||
|
@ -106,33 +129,51 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
|
||||||
unsigned int len ) {
|
unsigned int len ) {
|
||||||
struct aoecmd *aoecmd = aoehdr->arg.command;
|
struct aoecmd *aoecmd = aoehdr->arg.command;
|
||||||
struct ata_command *command = aoe->command;
|
struct ata_command *command = aoe->command;
|
||||||
unsigned int data_in_len;
|
unsigned int rx_data_len;
|
||||||
|
unsigned int count;
|
||||||
|
unsigned int data_len;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) )
|
if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) )
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
rx_data_len = ( len - sizeof ( *aoehdr ) - sizeof ( *aoecmd ) );
|
||||||
|
|
||||||
/* Set overall status code */
|
/* Check for fatal errors */
|
||||||
aoe->status = ( ( aoehdr->ver_flags & AOE_FL_ERROR ) ?
|
if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
|
||||||
aoehdr->error : 0 );
|
aoe_done ( aoe, -EIO );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Copy ATA results */
|
/* Calculate count and data_len for this subcommand */
|
||||||
command->cb.err_feat.bytes.cur = aoecmd->err_feat;
|
count = command->cb.count.native;
|
||||||
command->cb.count.bytes.cur = aoecmd->count;
|
if ( count > AOE_MAX_COUNT )
|
||||||
command->cb.cmd_stat = aoecmd->cmd_stat;
|
count = AOE_MAX_COUNT;
|
||||||
command->cb.lba.native = le64_to_cpu ( aoecmd->lba.u64 );
|
data_len = count * ATA_SECTOR_SIZE;
|
||||||
command->cb.lba.bytes.pad = 0;
|
|
||||||
|
/* Merge into overall ATA status */
|
||||||
|
aoe->status |= aoecmd->cmd_stat;
|
||||||
|
|
||||||
/* Copy data payload */
|
/* Copy data payload */
|
||||||
data_in_len = ( len - sizeof ( *aoehdr ) - sizeof ( *aoecmd ) );
|
if ( command->data_in ) {
|
||||||
if ( data_in_len > command->data_in_len ) {
|
if ( rx_data_len > data_len )
|
||||||
data_in_len = command->data_in_len;
|
rx_data_len = data_len;
|
||||||
aoe->status |= AOE_STATUS_OVERRUN;
|
copy_to_user ( command->data_in, aoe->command_offset,
|
||||||
} else if ( data_in_len < command->data_in_len ) {
|
aoecmd->data, rx_data_len );
|
||||||
aoe->status |= AOE_STATUS_UNDERRUN;
|
|
||||||
}
|
}
|
||||||
copy_to_user ( command->data_in, aoe->command_offset,
|
|
||||||
aoecmd->data, data_in_len );
|
/* Update ATA command and offset */
|
||||||
|
aoe->command_offset += data_len;
|
||||||
|
command->cb.lba.native += count;
|
||||||
|
command->cb.count.native -= count;
|
||||||
|
|
||||||
|
/* Check for operation complete */
|
||||||
|
if ( ! command->cb.count.native ) {
|
||||||
|
aoe_done ( aoe, 0 );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transmit next portion of request */
|
||||||
|
aoe_send_command ( aoe );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -229,79 +270,18 @@ void aoe_close ( struct aoe_session *aoe ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kick an AoE session into life
|
* Issue ATA command via an open AoE session
|
||||||
*
|
*
|
||||||
* @v aoe AoE session
|
* @v aoe AoE session
|
||||||
|
* @v command ATA command
|
||||||
*
|
*
|
||||||
* Transmits an AoE request. Call this function to issue a new
|
* Only one command may be issued concurrently per session. This call
|
||||||
* command, or when a retransmission timer expires.
|
* is non-blocking; use async_wait() to wait for the command to
|
||||||
|
* complete.
|
||||||
*/
|
*/
|
||||||
void aoe_kick ( struct aoe_session *aoe ) {
|
void aoe_issue ( struct aoe_session *aoe, struct ata_command *command ) {
|
||||||
|
aoe->command = command;
|
||||||
|
aoe->status = 0;
|
||||||
|
aoe->command_offset = 0;
|
||||||
aoe_send_command ( aoe );
|
aoe_send_command ( aoe );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Issue ATA command via an open AoE session
|
|
||||||
*
|
|
||||||
* @v aoe AoE session
|
|
||||||
* @v command ATA command
|
|
||||||
* @ret rc Return status code
|
|
||||||
*
|
|
||||||
* The ATA command must fit within a single AoE frame (i.e. the sector
|
|
||||||
* count must not exceed AOE_MAX_COUNT).
|
|
||||||
*/
|
|
||||||
int aoe_issue ( struct aoe_session *aoe, struct ata_command *command ) {
|
|
||||||
aoe->command = command;
|
|
||||||
aoe->status = AOE_STATUS_PENDING;
|
|
||||||
|
|
||||||
aoe_kick ( aoe );
|
|
||||||
while ( aoe->status & AOE_STATUS_PENDING ) {
|
|
||||||
step();
|
|
||||||
}
|
|
||||||
aoe->command = NULL;
|
|
||||||
|
|
||||||
return ( ( aoe->status & AOE_STATUS_ERR_MASK ) ? -EIO : 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Issue ATA command via an open AoE session
|
|
||||||
*
|
|
||||||
* @v aoe AoE session
|
|
||||||
* @v command ATA command
|
|
||||||
* @ret rc Return status code
|
|
||||||
*
|
|
||||||
* The ATA command will be split into several smaller ATA commands,
|
|
||||||
* each with a sector count no larger than AOE_MAX_COUNT.
|
|
||||||
*/
|
|
||||||
int aoe_issue_split ( struct aoe_session *aoe, struct ata_command *command ) {
|
|
||||||
struct ata_command subcommand;
|
|
||||||
unsigned int offset;
|
|
||||||
unsigned int count;
|
|
||||||
unsigned int data_len;
|
|
||||||
unsigned int status = 0;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
/* Split ATA command into AoE-sized subcommands */
|
|
||||||
for ( offset = 0; offset < command->cb.count.native; offset += count ){
|
|
||||||
memcpy ( &subcommand, command, sizeof ( subcommand ) );
|
|
||||||
count = ( command->cb.count.native - offset );
|
|
||||||
if ( count > AOE_MAX_COUNT )
|
|
||||||
count = AOE_MAX_COUNT;
|
|
||||||
data_len = count * ATA_SECTOR_SIZE;
|
|
||||||
if ( subcommand.data_in_len )
|
|
||||||
subcommand.data_in_len = data_len;
|
|
||||||
if ( subcommand.data_out_len )
|
|
||||||
subcommand.data_out_len = data_len;
|
|
||||||
aoe->command_offset = ( offset * ATA_SECTOR_SIZE );
|
|
||||||
subcommand.cb.lba.native += offset;
|
|
||||||
subcommand.cb.count.native = count;
|
|
||||||
if ( ( rc = aoe_issue ( aoe, &subcommand ) ) != 0 )
|
|
||||||
goto done;
|
|
||||||
status |= subcommand.cb.cmd_stat;
|
|
||||||
}
|
|
||||||
command->cb.cmd_stat = status;
|
|
||||||
|
|
||||||
done:
|
|
||||||
aoe->command_offset = 0;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue