david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Fix TX state machine and miscellaneous other bits.

This commit is contained in:
Michael Brown 2007-07-09 00:52:45 +01:00
parent ef9fd938d0
commit fabd0f5fec
1 changed files with 72 additions and 40 deletions

View File

@ -924,6 +924,16 @@ static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
iscsi->tx_state = ISCSI_TX_BHS; iscsi->tx_state = ISCSI_TX_BHS;
} }
/**
* Transmit nothing
*
* @v iscsi iSCSI session
* @ret rc Return status code
*/
static int iscsi_tx_nothing ( struct iscsi_session *iscsi __unused ) {
return 0;
}
/** /**
* Transmit basic header segment of an iSCSI PDU * Transmit basic header segment of an iSCSI PDU
* *
@ -953,8 +963,8 @@ static int iscsi_tx_data ( struct iscsi_session *iscsi ) {
case ISCSI_OPCODE_LOGIN_REQUEST: case ISCSI_OPCODE_LOGIN_REQUEST:
return iscsi_tx_login_request ( iscsi ); return iscsi_tx_login_request ( iscsi );
default: default:
assert ( 0 ); /* Nothing to send in other states */
return -EINVAL; return 0;
} }
} }
@ -1014,38 +1024,60 @@ static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
static void iscsi_tx_step ( struct process *process ) { static void iscsi_tx_step ( struct process *process ) {
struct iscsi_session *iscsi = struct iscsi_session *iscsi =
container_of ( process, struct iscsi_session, process ); container_of ( process, struct iscsi_session, process );
int rc = 0; struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
int ( * tx ) ( struct iscsi_session *iscsi );
enum iscsi_tx_state next_state;
size_t tx_len;
int rc;
if ( xfer_window ( &iscsi->socket ) == 0 ) /* Select fragment to transmit */
return; while ( 1 ) {
switch ( iscsi->tx_state ) {
case ISCSI_TX_IDLE:
/* Stop processing */
return;
case ISCSI_TX_BHS:
tx = iscsi_tx_bhs;
tx_len = sizeof ( iscsi->tx_bhs );
next_state = ISCSI_TX_AHS;
break;
case ISCSI_TX_AHS:
tx = iscsi_tx_nothing;
tx_len = 0;
next_state = ISCSI_TX_DATA;
break;
case ISCSI_TX_DATA:
tx = iscsi_tx_data;
tx_len = ISCSI_DATA_LEN ( common->lengths );
next_state = ISCSI_TX_DATA_PADDING;
break;
case ISCSI_TX_DATA_PADDING:
tx = iscsi_tx_data_padding;
tx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
next_state = ISCSI_TX_IDLE;
break;
default:
assert ( 0 );
return;
}
switch ( iscsi->tx_state ) { /* Check for window availability, if needed */
case ISCSI_TX_IDLE: if ( tx_len && ( xfer_window ( &iscsi->socket ) == 0 ) ) {
/* Nothing to send */ /* Cannot transmit at this point; stop processing */
break; return;
case ISCSI_TX_BHS: }
if ( ( rc = iscsi_tx_bhs ( iscsi ) ) != 0 )
break; /* Transmit data */
iscsi->tx_state = ISCSI_TX_AHS; if ( ( rc = tx ( iscsi ) ) != 0 ) {
break; DBGC ( iscsi, "iSCSI %p could not transmit: %s\n",
case ISCSI_TX_AHS: iscsi, strerror ( rc ) );
/* We don't yet have an AHS transmission mechanism */ return;
iscsi->tx_state = ISCSI_TX_DATA; }
break;
case ISCSI_TX_DATA: /* Move to next state */
if ( ( rc = iscsi_tx_data ( iscsi ) ) != 0 ) iscsi->tx_state = next_state;
break; if ( next_state == ISCSI_TX_IDLE )
iscsi->tx_state = ISCSI_TX_DATA_PADDING; iscsi_tx_done ( iscsi );
break;
case ISCSI_TX_DATA_PADDING:
if ( ( rc = iscsi_tx_data_padding ( iscsi ) ) != 0 )
break;
iscsi->tx_state = ISCSI_TX_IDLE;
iscsi_tx_done ( iscsi );
break;
default:
assert ( 0 );
break;
} }
} }
@ -1149,8 +1181,8 @@ static int iscsi_socket_deliver_raw ( struct xfer_interface *socket,
struct iscsi_session *iscsi = struct iscsi_session *iscsi =
container_of ( socket, struct iscsi_session, socket ); container_of ( socket, struct iscsi_session, socket );
struct iscsi_bhs_common *common = &iscsi->rx_bhs.common; struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
int ( *process ) ( struct iscsi_session *iscsi, const void *data, int ( * rx ) ( struct iscsi_session *iscsi, const void *data,
size_t len, size_t remaining ); size_t len, size_t remaining );
enum iscsi_rx_state next_state; enum iscsi_rx_state next_state;
size_t frag_len; size_t frag_len;
size_t remaining; size_t remaining;
@ -1159,22 +1191,22 @@ static int iscsi_socket_deliver_raw ( struct xfer_interface *socket,
while ( 1 ) { while ( 1 ) {
switch ( iscsi->rx_state ) { switch ( iscsi->rx_state ) {
case ISCSI_RX_BHS: case ISCSI_RX_BHS:
process = iscsi_rx_bhs; rx = iscsi_rx_bhs;
iscsi->rx_len = sizeof ( iscsi->rx_bhs ); iscsi->rx_len = sizeof ( iscsi->rx_bhs );
next_state = ISCSI_RX_AHS; next_state = ISCSI_RX_AHS;
break; break;
case ISCSI_RX_AHS: case ISCSI_RX_AHS:
process = iscsi_rx_discard; rx = iscsi_rx_discard;
iscsi->rx_len = 4 * ISCSI_AHS_LEN ( common->lengths ); iscsi->rx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
next_state = ISCSI_RX_DATA; next_state = ISCSI_RX_DATA;
break; break;
case ISCSI_RX_DATA: case ISCSI_RX_DATA:
process = iscsi_rx_data; rx = iscsi_rx_data;
iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths ); iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths );
next_state = ISCSI_RX_DATA_PADDING; next_state = ISCSI_RX_DATA_PADDING;
break; break;
case ISCSI_RX_DATA_PADDING: case ISCSI_RX_DATA_PADDING:
process = iscsi_rx_discard; rx = iscsi_rx_discard;
iscsi->rx_len = ISCSI_DATA_PAD_LEN ( common->lengths ); iscsi->rx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
next_state = ISCSI_RX_BHS; next_state = ISCSI_RX_BHS;
break; break;
@ -1187,8 +1219,7 @@ static int iscsi_socket_deliver_raw ( struct xfer_interface *socket,
if ( frag_len > len ) if ( frag_len > len )
frag_len = len; frag_len = len;
remaining = iscsi->rx_len - iscsi->rx_offset - frag_len; remaining = iscsi->rx_len - iscsi->rx_offset - frag_len;
if ( ( rc = process ( iscsi, data, frag_len, if ( ( rc = rx ( iscsi, data, frag_len, remaining ) ) != 0 ) {
remaining ) ) != 0 ) {
DBGC ( iscsi, "iSCSI %p could not process received " DBGC ( iscsi, "iSCSI %p could not process received "
"data: %s\n", iscsi, strerror ( rc ) ); "data: %s\n", iscsi, strerror ( rc ) );
iscsi_close_connection ( iscsi, rc ); iscsi_close_connection ( iscsi, rc );
@ -1320,6 +1351,7 @@ void iscsi_detach ( struct scsi_device *scsi ) {
struct iscsi_session *iscsi = struct iscsi_session *iscsi =
container_of ( scsi->backend, struct iscsi_session, refcnt ); container_of ( scsi->backend, struct iscsi_session, refcnt );
xfer_nullify ( &iscsi->socket );
iscsi_close_connection ( iscsi, 0 ); iscsi_close_connection ( iscsi, 0 );
process_del ( &iscsi->process ); process_del ( &iscsi->process );
scsi->command = iscsi_detached_command; scsi->command = iscsi_detached_command;