* @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 ) );
}
/** 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 {
};
extern int init_iscsidev ( struct iscsi_device *iscsidev );
+extern void fini_iscsidev ( struct iscsi_device *iscsidev );
#endif /* _GPXE_ISCSI_H */
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
/* 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 );
}
}
/* 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 )
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;
}
default:
DBG ( "iSCSI %p got invalid response flags %02x\n",
iscsi, response->flags );
- iscsi_close ( iscsi, -EIO );
+ iscsi_done ( iscsi, -EIO );
return;
}
}
*/
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 );
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;
+}