From ab242a760d66064ff14b83daaa2eef0a895c8d2b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 21 Dec 2006 17:17:47 +0000 Subject: [PATCH] Add ability to shut down iSCSI connection --- src/drivers/scsi/iscsidev.c | 17 +++++++++++++- src/include/gpxe/iscsi.h | 5 ++++ src/net/tcp/iscsi.c | 47 ++++++++++++++++++++----------------- src/tests/iscsiboot.c | 4 +++- 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/drivers/scsi/iscsidev.c b/src/drivers/scsi/iscsidev.c index 8f1b2435..9ee625c4 100644 --- a/src/drivers/scsi/iscsidev.c +++ b/src/drivers/scsi/iscsidev.c @@ -46,7 +46,22 @@ static int iscsi_command ( struct scsi_device *scsi, * @v iscsidev iSCSI device */ int init_iscsidev ( struct iscsi_device *iscsidev ) { + int rc; + iscsidev->scsi.command = iscsi_command; iscsidev->scsi.lun = iscsidev->iscsi.lun; - return init_scsidev ( &iscsidev->scsi ); + rc = init_scsidev ( &iscsidev->scsi ); + if ( rc != 0 ) { + fini_iscsidev ( iscsidev ); + } + return rc; +} + +/** + * Shut down iSCSI device + * + * @v iscsidev iSCSI device + */ +void fini_iscsidev ( struct iscsi_device *iscsidev ) { + async_wait ( iscsi_shutdown ( &iscsidev->iscsi ) ); } diff --git a/src/include/gpxe/iscsi.h b/src/include/gpxe/iscsi.h index 2961a96c..635fe269 100644 --- a/src/include/gpxe/iscsi.h +++ b/src/include/gpxe/iscsi.h @@ -626,11 +626,15 @@ struct iscsi_session { /** Mask for all iSCSI "needs to send" flags */ #define ISCSI_STATUS_STRINGS_MASK 0xff00 +/** iSCSI session is closing down */ +#define ISCSI_STATUS_CLOSING 0x00010000 + /** Maximum number of retries at connecting */ #define ISCSI_MAX_RETRIES 2 extern struct async_operation * iscsi_issue ( struct iscsi_session *iscsi, struct scsi_command *command ); +extern struct async_operation * iscsi_shutdown ( struct iscsi_session *iscsi ); /** An iSCSI device */ struct iscsi_device { @@ -641,5 +645,6 @@ struct iscsi_device { }; extern int init_iscsidev ( struct iscsi_device *iscsidev ); +extern void fini_iscsidev ( struct iscsi_device *iscsidev ); #endif /* _GPXE_ISCSI_H */ diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index 665b9765..59b8819a 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -104,24 +104,6 @@ static void iscsi_done ( struct iscsi_session *iscsi, int rc ) { async_done ( &iscsi->aop, rc ); } -/** - * Mark iSCSI operation as complete, and close TCP connection - * - * @v iscsi iSCSI session - * @v rc Return status code - */ -static void iscsi_close ( struct iscsi_session *iscsi, int rc ) { - - /* Clear session status */ - iscsi->status = 0; - - /* Close TCP connection */ - tcp_close ( &iscsi->tcp ); - - /* Mark iSCSI operation as complete */ - iscsi_done ( iscsi, rc ); -} - /**************************************************************************** * * iSCSI SCSI command issuing @@ -564,7 +546,7 @@ static void iscsi_handle_chap_a_value ( struct iscsi_session *iscsi, /* Prepare for CHAP with MD5 */ if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) { DBG ( "iSCSI %p could not initialise CHAP\n", iscsi ); - iscsi_close ( iscsi, rc ); + iscsi_done ( iscsi, rc ); } } @@ -722,7 +704,7 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data, /* Buffer up the PDU data */ if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) { DBG ( "iSCSI %p could not buffer login response\n", iscsi ); - iscsi_close ( iscsi, rc ); + iscsi_done ( iscsi, rc ); return; } if ( remaining ) @@ -747,7 +729,7 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data, if ( response->status_class != 0 ) { printf ( "iSCSI login failure: class %02x detail %02x\n", response->status_class, response->status_detail ); - iscsi_close ( iscsi, -EPERM ); + iscsi_done ( iscsi, -EPERM ); return; } @@ -765,7 +747,7 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data, default: DBG ( "iSCSI %p got invalid response flags %02x\n", iscsi, response->flags ); - iscsi_close ( iscsi, -EIO ); + iscsi_done ( iscsi, -EIO ); return; } } @@ -1122,10 +1104,17 @@ static void iscsi_newdata ( struct tcp_connection *conn, void *data, */ static void iscsi_closed ( struct tcp_connection *conn, int status ) { struct iscsi_session *iscsi = tcp_to_iscsi ( conn ); + int session_status = iscsi->status; /* Clear session status */ iscsi->status = 0; + /* If we are deliberately closing down, exit cleanly */ + if ( session_status & ISCSI_STATUS_CLOSING ) { + iscsi_done ( iscsi, status ); + return; + } + /* Retry connection if within the retry limit, otherwise fail */ if ( ++iscsi->retry_count <= ISCSI_MAX_RETRIES ) { DBG ( "iSCSI %p retrying connection\n", iscsi ); @@ -1192,3 +1181,17 @@ struct async_operation * iscsi_issue ( struct iscsi_session *iscsi, return &iscsi->aop; } + +/** + * Close down iSCSI session + * + * @v iscsi iSCSI session + * @ret aop Asynchronous operation + */ +struct async_operation * iscsi_shutdown ( struct iscsi_session *iscsi ) { + if ( iscsi->status ) { + iscsi->status |= ISCSI_STATUS_CLOSING; + tcp_close ( &iscsi->tcp ); + } + return &iscsi->aop; +} diff --git a/src/tests/iscsiboot.c b/src/tests/iscsiboot.c index 21a1b58e..f7cf8b74 100644 --- a/src/tests/iscsiboot.c +++ b/src/tests/iscsiboot.c @@ -32,7 +32,7 @@ int test_iscsiboot ( const char *initiator_iqn, printf ( "Initialising %s\n", target_iqn ); if ( ( rc = init_iscsidev ( &test_iscsidev ) ) != 0 ) { printf ( "Could not reach %s: %s\n", target_iqn, - strerror ( errno ) ); + strerror ( rc ) ); return rc; } ibft_fill_data ( netdev, initiator_iqn, target, target_iqn ); @@ -49,5 +49,7 @@ int test_iscsiboot ( const char *initiator_iqn, printf ( "Unregistering BIOS drive %#02x\n", drive.drive ); unregister_int13_drive ( &drive ); + fini_iscsidev ( &test_iscsidev ); + return rc; }