diff --git a/src/core/quiesce.c b/src/core/quiesce.c new file mode 100644 index 00000000..5d2a919d --- /dev/null +++ b/src/core/quiesce.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * @file + * + * Quiesce system + * + */ + +#include + +/** Quiesce system */ +void quiesce ( void ) { + struct quiescer *quiescer; + + /* Call all quiescers */ + for_each_table_entry ( quiescer, QUIESCERS ) { + quiescer->quiesce(); + } +} + +/** Unquiesce system */ +void unquiesce ( void ) { + struct quiescer *quiescer; + + /* Call all quiescers */ + for_each_table_entry ( quiescer, QUIESCERS ) { + quiescer->unquiesce(); + } +} diff --git a/src/core/sanboot.c b/src/core/sanboot.c index 1fd63490..cabc4843 100644 --- a/src/core/sanboot.c +++ b/src/core/sanboot.c @@ -41,6 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include /** @@ -365,6 +366,9 @@ int sandev_reopen ( struct san_device *sandev ) { struct san_path *sanpath; int rc; + /* Unquiesce system */ + unquiesce(); + /* Close any outstanding command and restart interfaces */ sandev_restart ( sandev, -ECONNRESET ); assert ( sandev->active == NULL ); @@ -503,6 +507,9 @@ sandev_command ( struct san_device *sandev, /* Sanity check */ assert ( ! timer_running ( &sandev->timer ) ); + /* Unquiesce system */ + unquiesce(); + /* (Re)try command */ do { @@ -654,6 +661,14 @@ int sandev_write ( struct san_device *sandev, uint64_t lba, if ( ( rc = sandev_rw ( sandev, lba, count, buffer, block_write ) ) != 0 ) return rc; + /* Quiesce system. This is a heuristic designed to ensure + * that the system is quiesced before Windows starts up, since + * a Windows SAN boot will typically write a status flag to + * the disk as its last action before transferring control to + * the native drivers. + */ + quiesce(); + return 0; } diff --git a/src/include/ipxe/quiesce.h b/src/include/ipxe/quiesce.h new file mode 100644 index 00000000..00b530b8 --- /dev/null +++ b/src/include/ipxe/quiesce.h @@ -0,0 +1,31 @@ +#ifndef _IPXE_QUIESCE_H +#define _IPXE_QUIESCE_H + +/** @file + * + * Quiesce system + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** A quiescer */ +struct quiescer { + /** Quiesce system */ + void ( * quiesce ) ( void ); + /** Unquiesce system */ + void ( * unquiesce ) ( void ); +}; + +/** Quiescer table */ +#define QUIESCERS __table ( struct quiescer, "quiescers" ) + +/** Declare a quiescer */ +#define __quiescer __table_entry ( QUIESCERS, 01 ) + +extern void quiesce ( void ); +extern void unquiesce ( void ); + +#endif /* _IPXE_QUIESCE_H */