Add ability to shut down iSCSI connection
authorMichael Brown <mcb30@etherboot.org>
Thu, 21 Dec 2006 17:17:47 +0000 (17:17 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 21 Dec 2006 17:17:47 +0000 (17:17 +0000)
src/drivers/scsi/iscsidev.c
src/include/gpxe/iscsi.h
src/net/tcp/iscsi.c
src/tests/iscsiboot.c

index 8f1b243..9ee625c 100644 (file)
@@ -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 ) );
 }
index 2961a96..635fe26 100644 (file)
@@ -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 */
index 665b976..59b8819 100644 (file)
@@ -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;
+}
index 21a1b58..f7cf8b7 100644 (file)
@@ -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;
 }