mirror of https://github.com/ipxe/ipxe.git
Fix TX state machine and miscellaneous other bits.
parent
ef9fd938d0
commit
fabd0f5fec
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue