commit 4e076e90cf429456701a2e06ba93c08e1967628c Author: Maksym Sadovnychyy Date: Thu Oct 31 19:42:40 2024 +0100 (feature): init diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7fa7210 --- /dev/null +++ b/.gitignore @@ -0,0 +1,262 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs +.directory + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d85e884 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,47 @@ +# Contributing to MaksIT.LTO.Backup + +Thank you for your interest in contributing to the MaksIT.LTO.Backup project! Whether you're submitting a bug report, suggesting a new feature, or improving the code, your efforts are greatly appreciated. Below are some guidelines to help make the process smooth and effective. + +## Getting Started + +1. **Fork the Repository**: Start by forking this repository to your GitHub account. +2. **Clone Your Fork**: Clone the fork to your local machine to begin making changes. + ```bash + git clone https://github.com/your-username/MaksIT.LTO.Backup.git + ``` +3. **Install Dependencies**: Ensure .NET8 or higher is installed on your system. +4. **Prepare Configurations**: Check the `README.md` for details on setting up `configuration.json` in the application directory. +5. **Run and Test**: Before submitting changes, ensure the application builds and functions correctly. Run all relevant tests and add new ones if needed. + +## Reporting Issues + +When reporting an issue, please include: +- Detailed steps to reproduce the issue. +- Your operating system and .NET version. +- Any relevant logs or error messages. + +If the issue is specific to a particular LTO version that you cannot test, please consider either: +- **Providing Funding**: Donations to cover hardware expenses can help expand compatibility. Contributions can be made via: + + + Buy Me A Coffee + + +- **Sponsoring Hardware**: If you're facing compatibility issues with a specific LTO generation, you can sponsor by directly purchasing the relevant LTO drive and tapes for testing. Contact me for shipping details if you're interested in sponsoring hardware. + +## Code Contribution + +### Guidelines + +1. **Pull Request**: Open a pull request (PR) with a clear description of your changes. If the PR is linked to an issue, reference it in the description. +2. **Code Style**: Follow existing code conventions and formatting. Keep your changes focused and avoid unnecessary code refactoring. +3. **Documentation**: Ensure any new methods, classes, or configurations are fully documented. +4. **Testing**: Test your changes thoroughly and add relevant tests where possible. + +## Contact + +If you have any questions or need further assistance, feel free to reach out: + +- **Email**: [maksym.sadovnychyy@gmail.com](mailto:maksym.sadovnychyy@gmail.com) + +Thank you for considering contributing, and feel free to reach out if you have questions! Your support helps make MaksIT.LTO.Backup better for everyone. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..7f5c368 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,325 @@ +The GNU General Public License (GPL-2.0) +Version 2, June 1991 +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to +most of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software is +covered by the GNU Library General Public License instead.) You can apply +it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. +Our General Public Licenses are designed to make sure that you have the +freedom to distribute copies of free software (and charge for this service +if you wish), that you receive source code or can get it if you want it, +that you can change the software or use pieces of it in new free programs; +and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or +for a fee, you must give the recipients all the rights that you have. +You must make sure that they, too, receive or can get the source code. +And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. +If the software is modified by someone else and passed on, we want its +recipients to know that what they have is not the original, so that any +problems introduced by others will not reflect on the +original authors' reputations. + +Finally, any free program is threatened constantly by software patents. +We wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program proprietary. +To prevent this, we have made it clear that any patent must be licensed for +everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution +and modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms +of this General Public License. The "Program", below, refers to any such +program or work, and a "work based on the Program" means either the Program +or any derivative work under copyright law: that is to say, a work containing +the Program or a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is included +without limitation in the term "modification".) +Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running the Program +is not restricted, and the output from the Program is covered only if its +contents constitute a work based on the Program (independent of having been +made by running the Program). Whether that is true depends on +what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this +License and to the absence of any warranty; and give any other recipients +of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, +thus forming a work based on the Program, and copy and distribute such +modifications or work under the terms of Section 1 above, provided that you +also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in whole + or in part contains or is derived from the Program or any part thereof, + to be licensed as a whole at no charge to all third parties under + the terms of this License. + + c) If the modified program normally reads commands interactively when run, + you must cause it, when started running for such interactive use in the + most ordinary way, to print or display an announcement including an + appropriate copyright notice and a notice that there is no warranty + (or else, saying that you provide a warranty) and that users may + redistribute the program under these conditions, and telling the user how + to view a copy of this License. (Exception: if the Program itself is + interactive but does not normally print such an announcement, your work + based on the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Program, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part +regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective +works based on the Program. + +In addition, mere aggregation of another work not based on the Program with +the Program (or with a work based on the Program) on a volume of a storage +or distribution medium does not bring the other work under +the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 above + on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three years, to + give any third party, for a charge no more than your cost of physically + performing source distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Sections 1 and 2 above on a medium customarily used + for software interchange; or, + + c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed only + for noncommercial distribution and only if you received the program in + object code or executable form with such an offer, in accord + with Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all +the source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and +installation of the executable. However, as a special exception, the source +code distributed need not include anything that is normally distributed +(in either source or binary form) with the major components (compiler, kernel, +and so on) of the operating system on which the executable runs, unless that +component itself accompanies the executable. + +If distribution of executable or object code is made by offering access to +copy from a designated place, then offering equivalent access to copy the +source code from the same place counts as distribution of the source code, +even though third parties are not compelled to copy the source +along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as +expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. +However, nothing else grants you permission to modify or distribute the +Program or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Program +(or any work based on the Program), you indicate your acceptance of this +License to do so, and all its terms and conditions for copying, distributing +or modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), +the recipient automatically receives a license from the original licensor +to copy, distribute or modify the Program subject to these terms +and conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from +the conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Program at all. +For example, if a patent license would not permit royalty-free redistribution +of the Program by all those who receive copies directly or indirectly +through you, then the only way you could satisfy both it and this License +would be to refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system, which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of +that system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee +cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original +copyright holder who places the Program under this License may add an explicit +geographical distribution limitation excluding those countries, so that +distribution is permitted only in or among countries not thus excluded. +In such case, this License incorporates the limitation as if written +in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the +General Public License from time to time. Such new versions will be similar +in spirit to the present version, but may differ in detail to address +new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and conditions +either of that version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published +by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing +and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE +PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, +YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL +ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively convey the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + MaksIT.LTO.Backup - Simple LTO backup cli utility for Windows + Copyright (C) 2024 Maksym Sadovnychyy (MAKS-IT) + + 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 + (at your option) 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., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when +it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author Gnomovision + comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is + free software, and you are welcome to redistribute it under certain + conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + signature of Ty Coon, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Library General +Public License instead of this License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..776a030 --- /dev/null +++ b/README.md @@ -0,0 +1,95 @@ +# MaksIT.LTO.Backup + +A C# application designed to facilitate backup and restore operations to an LTO tape drive. This application enables seamless management of backups by handling file organization, descriptor creation, and efficient tape handling processes for loading, writing, and restoring data. + +## Features + +- **Load and Eject Tape**: Safely loads and unloads the tape using `TapeDeviceHandler`. +- **Backup Operation**: Allows users to create a descriptor file for organizing file metadata and backs up files to the LTO tape in structured blocks. +- **Restore Operation**: Reads data from the tape and restores files to a specified directory, reconstructing original file structure. +- **Customizable Block Sizes**: Supports multiple LTO generations, allowing customization of block sizes based on the tape generation (e.g., LTO-6). +- **File Descriptor Management**: Metadata is organized for each file, including file paths, sizes, creation, and modification times. +- **Zero-Filled End Blocks**: Marks the end of a backup with zero-filled blocks to assist with reading and integrity checks. + +## Requirements + +- .NET8 or higher +- JSON configuration files: `configuration.json` and `descriptor.json` (auto-generated) +- LTO Tape Drive and compatible drivers + +## Setup + +1. Clone the repository: + ```bash + git clone https://github.com/your-username/MaksIT.LTO.Backup.git + ``` +2. Ensure `.NET Core` is installed on your system. +3. Prepare a `configuration.json` file in the application directory with the following structure: + ```json + { + "TapePath": "YourTapePath", + "Backups": [ + { + "Name": "BackupName", + "Barcode": "123456", + "Source": "path/to/source", + "Destination": "path/to/destination", + "LTOGen": "LTO6" + } + ] + } + ``` + +## Usage + +### Running the Application + +Execute the application by navigating to the project directory and running: +```bash +dotnet run +``` + +### Application Menu + +Upon running, the following options will be presented: + +1. **Load Tape**: Loads the tape into the drive. +2. **Backup**: Prompts the user to select a backup task from the configured list and initiates the backup process. +3. **Restore**: Restores a previously backed-up directory from the tape. +4. **Eject Tape**: Ejects the tape from the drive safely. +5. **Exit**: Exits the application. + +### Code Overview + +- **Application Class**: Main class handling backup and restore functionalities. Provides methods like `LoadTape`, `EjectTape`, `Backup`, `Restore`, `CreateDescriptor`, `WriteFilesToTape`, and `FindDescriptor`. +- **TapeDeviceHandler**: Controls tape device operations such as setting positions, writing data, and reading data. +- **BackupDescriptor**: Organizes metadata for backed-up files. Used to log details about each file block on tape. + +### Sample Configuration + +Below is an example configuration setup for an LTO-6 tape generation backup operation: + +```json +{ + "TapePath": "\\\\.\\Tape0", + "Backups": [ + { + "Name": "Monthly Backup", + "Barcode": "MB12345", + "Source": "/path/to/source", + "Destination": "/path/to/restore", + "LTOGen": "LTO6" + } + ] +} +``` + +### Error Handling + +Errors during backup or restore are caught and logged to the console. Ensure that your `TapeDeviceHandler` is correctly configured and that the tape drive is accessible. + +## License + +This project is licensed under the terms of the GPLv2. See the [LICENSE](./LICENSE) file for full details. + +© Maksym Sadovnychyy (MAKS-IT) 2024 diff --git a/docs/ntddstor.h b/docs/ntddstor.h new file mode 100644 index 0000000..2fc5163 --- /dev/null +++ b/docs/ntddstor.h @@ -0,0 +1,4949 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntddstor.h + +Abstract: + + This is the include file that defines all common constants and types + accessing the storage class drivers + +--*/ + +#include + + + +#pragma region Desktop Family or OneCore Family +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + +// +// Interface GUIDs +// +// need these GUIDs outside conditional includes so that user can +// #include in precompiled header +// #include in a single source file +// #include in that source file a second time to instantiate the GUIDs +// +#ifdef DEFINE_GUID +// +// Make sure FAR is defined... +// +#ifndef FAR +#ifdef _WIN32 +#define FAR +#else +#define FAR _far +#endif +#endif + +// begin_wioctlguids + +#ifndef __WRAPPED__ +#define __WRAPPED__ +#endif + +DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_CDROM, 0x53f56308L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_PARTITION, 0x53f5630aL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_TAPE, 0x53f5630bL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_WRITEONCEDISK, 0x53f5630cL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_VOLUME, 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_MEDIUMCHANGER, 0x53f56310L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_FLOPPY, 0x53f56311L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_CDCHANGER, 0x53f56312L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT, 0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_VMLUN, 0x6f416619L, 0x9f29, 0x42a5, 0xb2, 0x0b, 0x37, 0xe2, 0x19, 0xca, 0x02, 0xb0); +DEFINE_GUID(GUID_DEVINTERFACE_SES, 0x1790c9ecL, 0x47d5, 0x4df3, 0xb5, 0xaf, 0x9a, 0xdf, 0x3c, 0xf2, 0x3e, 0x48); + +#define WDI_STORAGE_PREDICT_FAILURE_DPS_GUID {0xe9f2d03aL, 0x747c, 0x41c2, {0xbb, 0x9a, 0x02, 0xc6, 0x2b, 0x6d, 0x5f, 0xcb}}; + +// +// Interfaces to discover devices that are +// not reported through conventional APIs +// + +DEFINE_GUID(GUID_DEVINTERFACE_SERVICE_VOLUME, 0x6ead3d82L, 0x25ec, 0x46bc, 0xb7, 0xfd, 0xc1, 0xf0, 0xdf, 0x8f, 0x50, 0x37); +DEFINE_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME, 0x7f108a28L, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62); + +// +// Interface to register for RPMB commands +// + +DEFINE_GUID(GUID_DEVINTERFACE_UNIFIED_ACCESS_RPMB, 0x27447c21L, 0xbcc3, 0x4d07, 0xa0, 0x5b, 0xa3, 0x39, 0x5b, 0xb4, 0xee, 0xe7); + +// end_wioctlguids + +// begin_wioctlobsoleteguids + +#ifndef __WRAPPED__ +#define __WRAPPED__ +#endif + +#define DiskClassGuid GUID_DEVINTERFACE_DISK +#define CdRomClassGuid GUID_DEVINTERFACE_CDROM +#define PartitionClassGuid GUID_DEVINTERFACE_PARTITION +#define TapeClassGuid GUID_DEVINTERFACE_TAPE +#define WriteOnceDiskClassGuid GUID_DEVINTERFACE_WRITEONCEDISK +#define VolumeClassGuid GUID_DEVINTERFACE_VOLUME +#define MediumChangerClassGuid GUID_DEVINTERFACE_MEDIUMCHANGER +#define FloppyClassGuid GUID_DEVINTERFACE_FLOPPY +#define CdChangerClassGuid GUID_DEVINTERFACE_CDCHANGER +#define StoragePortClassGuid GUID_DEVINTERFACE_STORAGEPORT + +#define HiddenVolumeClassGuid GUID_DEVINTERFACE_HIDDEN_VOLUME + +// end_wioctlobsoleteguids + +// begin_tcioctlguids + +#ifndef __WRAPPED__ +#define __WRAPPED__ +#endif + +// +// GUID, identifying crash dump section, containing device information or driver information. These GUIDs are used both to identify secondary dump section in the crashdump +// and in IOCTL to identify why section is requested by the user mode application +// + +// /* d8e2592f-1aab-4d56-a746-1f7585df40f4 */ +DEFINE_GUID(GUID_DEVICEDUMP_STORAGE_DEVICE, 0xd8e2592f,0x1aab,0x4d56,0xa7, 0x46, 0x1f, 0x75, 0x85, 0xdf, 0x40, 0xf4); + +// /* da82441d-7142-4bc1-b844-0807c5a4b67f */ +DEFINE_GUID(GUID_DEVICEDUMP_DRIVER_STORAGE_PORT, 0xda82441d,0x7142,0x4bc1,0xb8, 0x44, 0x08, 0x07, 0xc5, 0xa4, 0xb6, 0x7f); + +// end_tcioctlguids + + + + +#endif + +// +// Interface DEVPROPKEY +// +// need these DEVPROPKEYs outside conditional includes so that user can +// #include in precompiled header +// #include in a single source file +// #include in that source file a second time to instantiate the DEVPROPKEYs +// +#ifdef DEFINE_DEVPROPKEY + +// begin_wioctldevpropkeys + +#ifndef __WRAPPED__ +#define __WRAPPED__ +#endif + +// +// Properties associated with the volume interface. +// + +DEFINE_DEVPROPKEY(DEVPKEY_Storage_Portable, 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 2); // DEVPROP_TYPE_BOOLEAN +DEFINE_DEVPROPKEY(DEVPKEY_Storage_Removable_Media, 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 3); // DEVPROP_TYPE_BOOLEAN +DEFINE_DEVPROPKEY(DEVPKEY_Storage_System_Critical, 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 4); // DEVPROP_TYPE_BOOLEAN +DEFINE_DEVPROPKEY(DEVPKEY_Storage_Disk_Number, 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 5); // DEVPROP_TYPE_UINT32 +DEFINE_DEVPROPKEY(DEVPKEY_Storage_Partition_Number, 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 6); // DEVPROP_TYPE_UINT32 +DEFINE_DEVPROPKEY(DEVPKEY_Storage_Mbr_Type, 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 7); // DEVPROP_TYPE_BYTE +DEFINE_DEVPROPKEY(DEVPKEY_Storage_Gpt_Type, 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 8); // DEVPROP_TYPE_GUID +DEFINE_DEVPROPKEY(DEVPKEY_Storage_Gpt_Name, 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 9); // DEVPROP_TYPE_STRING +// end_wioctldevpropkeys + +#endif + +// begin_winioctl + +#ifndef __WRAPPED__ +#define __WRAPPED__ +#endif + +#ifndef _NTDDSTOR_H_ +#define _NTDDSTOR_H_ + +#if defined __cplusplus && !defined __ALT_GENERATOR__ +extern "C" { +#endif + +#if _MSC_VER >= 1200 +#pragma warning(push) +#pragma warning(disable:4820) // padding added after data member +#endif + +// +// IoControlCode values for storage devices +// + +#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE + +// +// The following device control codes are common for all class drivers. They +// should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE +// common codes +// + +#define IOCTL_STORAGE_CHECK_VERIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_RESERVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RELEASE CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_FIND_NEW_DEVICES CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_STORAGE_EJECTION_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MCN_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_STORAGE_GET_MEDIA_TYPES CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0304, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0305, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_SET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0306, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_BREAK_RESERVATION CTL_CODE(IOCTL_STORAGE_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_PERSISTENT_RESERVE_IN CTL_CODE(IOCTL_STORAGE_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_PERSISTENT_RESERVE_OUT CTL_CODE(IOCTL_STORAGE_BASE, 0x0407, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// This IOCTL includes the same information as IOCTL_STORAGE_GET_DEVICE_NUMBER, plus the device GUID. +// +#define IOCTL_STORAGE_GET_DEVICE_NUMBER_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0421, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +#define IOCTL_STORAGE_PREDICT_FAILURE CTL_CODE(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG CTL_CODE(IOCTL_STORAGE_BASE, 0x0441, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// This IOCTL retrieves reliability counters for a device. +// +#define IOCTL_STORAGE_GET_COUNTERS CTL_CODE(IOCTL_STORAGE_BASE, 0x442, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_STORAGE_READ_CAPACITY CTL_CODE(IOCTL_STORAGE_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// IOCTLs 0x0463 to 0x0468 reserved for dependent disk support. +// + + +// +// IOCTLs 0x0470 to 0x047f reserved for device and stack telemetry interfaces +// + +#define IOCTL_STORAGE_GET_DEVICE_TELEMETRY CTL_CODE(IOCTL_STORAGE_BASE, 0x0470, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_STORAGE_DEVICE_TELEMETRY_NOTIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0471, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_STORAGE_DEVICE_TELEMETRY_QUERY_CAPS CTL_CODE(IOCTL_STORAGE_BASE, 0x0472, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_STORAGE_GET_DEVICE_TELEMETRY_RAW CTL_CODE(IOCTL_STORAGE_BASE, 0x0473, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + + +#define IOCTL_STORAGE_SET_TEMPERATURE_THRESHOLD CTL_CODE(IOCTL_STORAGE_BASE, 0x0480, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_STORAGE_PROTOCOL_COMMAND CTL_CODE(IOCTL_STORAGE_BASE, 0x04F0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES CTL_CODE(IOCTL_STORAGE_BASE, 0x0501, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define IOCTL_STORAGE_GET_LB_PROVISIONING_MAP_RESOURCES CTL_CODE(IOCTL_STORAGE_BASE, 0x0502, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// IOCTLs 0x0503 to 0x0580 reserved for Enhanced Storage devices. +// + +// +// This IOCTL offloads the erasure process to the storage device. There is no guarantee as to the successful +// deletion or recoverability of the data on the storage device after command completion. This IOCTL is limited +// to data disks in regular Windows. In WinPE, this IOCTL is supported for both boot and data disks. +// +// Initial implementation requires no input and returns no output other than status. Callers should first +// call FSCTL_LOCK_VOLUME before calling this ioctl to flush out cached data in upper layers. No waiting of +// outstanding request completion is done before issuing the command to the device. +// +#define IOCTL_STORAGE_REINITIALIZE_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0590, METHOD_BUFFERED, FILE_WRITE_ACCESS) + + +// +// IOCTLs for bandwidth contracts on storage devices +// (Move this to ntddsfio if we decide to use a new base) +// + +#define IOCTL_STORAGE_GET_BC_PROPERTIES CTL_CODE(IOCTL_STORAGE_BASE, 0x0600, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_ALLOCATE_BC_STREAM CTL_CODE(IOCTL_STORAGE_BASE, 0x0601, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_STORAGE_FREE_BC_STREAM CTL_CODE(IOCTL_STORAGE_BASE, 0x0602, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTL to check for priority support +// +#define IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT CTL_CODE(IOCTL_STORAGE_BASE, 0x0620, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTL for data integrity check support +// + +#define IOCTL_STORAGE_START_DATA_INTEGRITY_CHECK CTL_CODE(IOCTL_STORAGE_BASE, 0x0621, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_STORAGE_STOP_DATA_INTEGRITY_CHECK CTL_CODE(IOCTL_STORAGE_BASE, 0x0622, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// These ioctl codes are obsolete. They are defined here to avoid resuing them +// and to allow class drivers to respond to them more easily. +// + +#define OBSOLETE_IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define OBSOLETE_IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTLs 0x0643 to 0x0655 reserved for VHD disk support. +// + + +// +// IOCTLs for firmware upgrade on storage devices +// + +#define IOCTL_STORAGE_FIRMWARE_GET_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0700, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_FIRMWARE_DOWNLOAD CTL_CODE(IOCTL_STORAGE_BASE, 0x0701, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_STORAGE_FIRMWARE_ACTIVATE CTL_CODE(IOCTL_STORAGE_BASE, 0x0702, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + + +// +// IOCTL to support Idle Power Management, including Device Wake +// +#define IOCTL_STORAGE_ENABLE_IDLE_POWER CTL_CODE(IOCTL_STORAGE_BASE, 0x0720, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_IDLE_POWERUP_REASON CTL_CODE(IOCTL_STORAGE_BASE, 0x0721, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTLs to allow class drivers to acquire and release active references on +// a unit. These should only be used if the class driver previously sent a +// successful IOCTL_STORAGE_ENABLE_IDLE_POWER request to the port driver. +// +#define IOCTL_STORAGE_POWER_ACTIVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0722, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_POWER_IDLE CTL_CODE(IOCTL_STORAGE_BASE, 0x0723, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// This IOCTL indicates that the physical device has triggered some sort of event. +// +#define IOCTL_STORAGE_EVENT_NOTIFICATION CTL_CODE(IOCTL_STORAGE_BASE, 0x0724, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTL to specify a power cap for a storage device. +// +#define IOCTL_STORAGE_DEVICE_POWER_CAP CTL_CODE(IOCTL_STORAGE_BASE, 0x0725, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTL to send commands to the RPMB for a storage device. +// +#define IOCTL_STORAGE_RPMB_COMMAND CTL_CODE(IOCTL_STORAGE_BASE, 0x0726, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTL to manage attributes for storage devices +// +#define IOCTL_STORAGE_ATTRIBUTE_MANAGEMENT CTL_CODE(IOCTL_STORAGE_BASE, 0x0727, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTL_STORAGE_DIAGNOSTIC IOCTL to query diagnostic data from the storage driver stack +// +#define IOCTL_STORAGE_DIAGNOSTIC CTL_CODE(IOCTL_STORAGE_BASE, 0x0728, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTLs for storage device depopulation support. +// + +// +// IOCTL_STORAGE_GET_PHYSICAL_ELEMENT_STATUS IOCTL to query physical element status from device. +// +#define IOCTL_STORAGE_GET_PHYSICAL_ELEMENT_STATUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0729, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTL_STORAGE_REMOVE_ELEMENT_AND_TRUNCATE IOCTL to remove and truncate element from device. +// +#define IOCTL_STORAGE_REMOVE_ELEMENT_AND_TRUNCATE CTL_CODE(IOCTL_STORAGE_BASE, 0x0730, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// Note: Function code values of less than 0x800 are reserved for Microsoft. Values of 0x800 and higher can be used by vendors. +// So do not use function code of 0x800 and higher to define new IOCTLs in this file. +// + + +// +// IOCTL_STORAGE_GET_HOTPLUG_INFO +// + +typedef struct _STORAGE_HOTPLUG_INFO { + ULONG Size; // version + BOOLEAN MediaRemovable; // ie. zip, jaz, cdrom, mo, etc. vs hdd + BOOLEAN MediaHotplug; // ie. does the device succeed a lock even though its not lockable media? + BOOLEAN DeviceHotplug; // ie. 1394, USB, etc. + BOOLEAN WriteCacheEnableOverride; // This field should not be relied upon because it is no longer used +} STORAGE_HOTPLUG_INFO, *PSTORAGE_HOTPLUG_INFO; + +// +// IOCTL_STORAGE_GET_DEVICE_NUMBER +// +// input - none +// +// output - STORAGE_DEVICE_NUMBER structure +// The values in the STORAGE_DEVICE_NUMBER structure are guaranteed +// to remain unchanged until the system is rebooted. They are not +// guaranteed to be persistant across boots. +// + +typedef struct _STORAGE_DEVICE_NUMBER { + + // + // The FILE_DEVICE_XXX type for this device. + // + + DEVICE_TYPE DeviceType; + + // + // The number of this device + // + + ULONG DeviceNumber; + + // + // If the device is partitionable, the partition number of the device. + // Otherwise -1 + // + + ULONG PartitionNumber; +} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER; + +typedef struct _STORAGE_DEVICE_NUMBERS { + + ULONG NumberOfDevices; + + STORAGE_DEVICE_NUMBER Devices[ANYSIZE_ARRAY]; + +} STORAGE_DEVICE_NUMBERS, *PSTORAGE_DEVICE_NUMBERS; + +// +// IOCTL_STORAGE_GET_DEVICE_NUMBER_EX +// +// input - none +// +// output - STORAGE_DEVICE_NUMBER_EX structure +// + +// +// Possible flags that can be set in Flags field of +// STORAGE_DEVICE_NUMBER_EX structure defined below +// + +// +// This flag indicates that deviceguid is randomly created because a deviceguid conflict was observed +// +#define STORAGE_DEVICE_FLAGS_RANDOM_DEVICEGUID_REASON_CONFLICT 0x1 + +// +// This flag indicates that deviceguid is randomly created because the HW ID was not available +// +#define STORAGE_DEVICE_FLAGS_RANDOM_DEVICEGUID_REASON_NOHWID 0x2 + +// +// This flag indicates that deviceguid is created from the scsi page83 data. +// If this flag is not set this implies it's created from serial number or is randomly generated. +// +#define STORAGE_DEVICE_FLAGS_PAGE_83_DEVICEGUID 0x4 + +typedef struct _STORAGE_DEVICE_NUMBER_EX { + + // + // Sizeof(STORAGE_DEVICE_NUMBER_EX). + // + + ULONG Version; + + // + // Total size of the structure, including any additional data. Currently + // this will always be the same as sizeof(STORAGE_DEVICE_NUMBER_EX). + // + + ULONG Size; + + // + // Flags - this shall be a combination of STORAGE_DEVICE_FLAGS_XXX flags + // that gives more information about the members of this structure. + // + + ULONG Flags; + + // + // The FILE_DEVICE_XXX type for this device. This IOCTL is only + // supported for disk devices. + // + + DEVICE_TYPE DeviceType; + + // + // The number of this device. + // + + ULONG DeviceNumber; + + // + // A globally-unique identification number for this device. + // A GUID of {0} indicates that a GUID could not be generated. The GUID + // is based on hardware information that doesn't change with firmware updates + // (for instance, serial number can be used to form the GUID, but not the firmware + // revision). The device GUID remains the same across reboots. + // + // In general, if a device exposes a globally unique identifier, the storage driver + // will use that identifier to form the GUID. Otherwise, the storage driver will combine + // the device's vendor ID, product ID and serial number to create the GUID. + // + // If a storage driver detects two devices with the same hardware information (which is + // an indication of a problem with the device), the driver will generate a random GUID for + // one of the two devices. When handling IOCTL_STORAGE_GET_DEVICE_NUMBER_EX for the device + // with the random GUID, the driver will add STORAGE_DEVICE_FLAGS_RANDOM_DEVICEGUID_REASON_CONFLICT + // to the Flags member of this structure. + // + // If a storage device does not provide any identifying information, the driver will generate a random + // GUID and add STORAGE_DEVICE_FLAGS_RANDOM_DEVICEGUID_REASON_NOHWID to the Flags member of this structure. + // + // A random GUID is not persisted and will not be the same after a reboot. + // + + GUID DeviceGuid; + + // + // If the device is partitionable, the partition number of the device. + // Otherwise -1. + // + + ULONG PartitionNumber; +} STORAGE_DEVICE_NUMBER_EX, *PSTORAGE_DEVICE_NUMBER_EX; + + +// +// Define the structures for scsi resets +// + +typedef struct _STORAGE_BUS_RESET_REQUEST { + UCHAR PathId; +} STORAGE_BUS_RESET_REQUEST, *PSTORAGE_BUS_RESET_REQUEST; + +// +// Break reservation is sent to the Adapter/FDO with the given lun information. +// + +typedef struct STORAGE_BREAK_RESERVATION_REQUEST { + ULONG Length; + UCHAR _unused; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +} STORAGE_BREAK_RESERVATION_REQUEST, *PSTORAGE_BREAK_RESERVATION_REQUEST; + + +// +// IOCTL_STORAGE_MEDIA_REMOVAL disables the mechanism +// on a storage device that ejects media. This function +// may or may not be supported on storage devices that +// support removable media. +// +// TRUE means prevent media from being removed. +// FALSE means allow media removal. +// + +typedef struct _PREVENT_MEDIA_REMOVAL { + BOOLEAN PreventMediaRemoval; +} PREVENT_MEDIA_REMOVAL, *PPREVENT_MEDIA_REMOVAL; + + + +// +// This is the format of TARGET_DEVICE_CUSTOM_NOTIFICATION.CustomDataBuffer +// passed to applications by the classpnp autorun code (via IoReportTargetDeviceChangeAsynchronous). +// +typedef struct _CLASS_MEDIA_CHANGE_CONTEXT { + ULONG MediaChangeCount; + ULONG NewState; // see MEDIA_CHANGE_DETECTION_STATE enum in classpnp.h in DDK +} CLASS_MEDIA_CHANGE_CONTEXT, *PCLASS_MEDIA_CHANGE_CONTEXT; + + +// begin_ntminitape + +#ifndef __WRAPPED__ +#define __WRAPPED__ +#endif + +typedef struct _TAPE_STATISTICS { + ULONG Version; + ULONG Flags; + LARGE_INTEGER RecoveredWrites; + LARGE_INTEGER UnrecoveredWrites; + LARGE_INTEGER RecoveredReads; + LARGE_INTEGER UnrecoveredReads; + UCHAR CompressionRatioReads; + UCHAR CompressionRatioWrites; +} TAPE_STATISTICS, *PTAPE_STATISTICS; + +#define RECOVERED_WRITES_VALID 0x00000001 +#define UNRECOVERED_WRITES_VALID 0x00000002 +#define RECOVERED_READS_VALID 0x00000004 +#define UNRECOVERED_READS_VALID 0x00000008 +#define WRITE_COMPRESSION_INFO_VALID 0x00000010 +#define READ_COMPRESSION_INFO_VALID 0x00000020 + +typedef struct _TAPE_GET_STATISTICS { + ULONG Operation; +} TAPE_GET_STATISTICS, *PTAPE_GET_STATISTICS; + +#define TAPE_RETURN_STATISTICS 0L +#define TAPE_RETURN_ENV_INFO 1L +#define TAPE_RESET_STATISTICS 2L + +// +// IOCTL_STORAGE_GET_MEDIA_TYPES_EX will return an array of DEVICE_MEDIA_INFO +// structures, one per supported type, embedded in the GET_MEDIA_TYPES struct. +// + +typedef enum _STORAGE_MEDIA_TYPE { + // + // Following are defined in ntdddisk.h in the MEDIA_TYPE enum + // + // Unknown, // Format is unknown + // F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector + // F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector + // F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector + // F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector + // F3_720_512, // 3.5", 720KB, 512 bytes/sector + // F5_360_512, // 5.25", 360KB, 512 bytes/sector + // F5_320_512, // 5.25", 320KB, 512 bytes/sector + // F5_320_1024, // 5.25", 320KB, 1024 bytes/sector + // F5_180_512, // 5.25", 180KB, 512 bytes/sector + // F5_160_512, // 5.25", 160KB, 512 bytes/sector + // RemovableMedia, // Removable media other than floppy + // FixedMedia, // Fixed hard disk media + // F3_120M_512, // 3.5", 120M Floppy + // F3_640_512, // 3.5" , 640KB, 512 bytes/sector + // F5_640_512, // 5.25", 640KB, 512 bytes/sector + // F5_720_512, // 5.25", 720KB, 512 bytes/sector + // F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector + // F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector + // F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector + // F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector + // F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector + // F8_256_128, // 8", 256KB, 128 bytes/sector + // F3_200Mb_512, // 3.5", 200M Floppy (HiFD) + // + + DDS_4mm = 0x20, // Tape - DAT DDS1,2,... (all vendors) + MiniQic, // Tape - miniQIC Tape + Travan, // Tape - Travan TR-1,2,3,... + QIC, // Tape - QIC + MP_8mm, // Tape - 8mm Exabyte Metal Particle + AME_8mm, // Tape - 8mm Exabyte Advanced Metal Evap + AIT1_8mm, // Tape - 8mm Sony AIT + DLT, // Tape - DLT Compact IIIxt, IV + NCTP, // Tape - Philips NCTP + IBM_3480, // Tape - IBM 3480 + IBM_3490E, // Tape - IBM 3490E + IBM_Magstar_3590, // Tape - IBM Magstar 3590 + IBM_Magstar_MP, // Tape - IBM Magstar MP + STK_DATA_D3, // Tape - STK Data D3 + SONY_DTF, // Tape - Sony DTF + DV_6mm, // Tape - 6mm Digital Video + DMI, // Tape - Exabyte DMI and compatibles + SONY_D2, // Tape - Sony D2S and D2L + CLEANER_CARTRIDGE, // Cleaner - All Drive types that support Drive Cleaners + CD_ROM, // Opt_Disk - CD + CD_R, // Opt_Disk - CD-Recordable (Write Once) + CD_RW, // Opt_Disk - CD-Rewriteable + DVD_ROM, // Opt_Disk - DVD-ROM + DVD_R, // Opt_Disk - DVD-Recordable (Write Once) + DVD_RW, // Opt_Disk - DVD-Rewriteable + MO_3_RW, // Opt_Disk - 3.5" Rewriteable MO Disk + MO_5_WO, // Opt_Disk - MO 5.25" Write Once + MO_5_RW, // Opt_Disk - MO 5.25" Rewriteable (not LIMDOW) + MO_5_LIMDOW, // Opt_Disk - MO 5.25" Rewriteable (LIMDOW) + PC_5_WO, // Opt_Disk - Phase Change 5.25" Write Once Optical + PC_5_RW, // Opt_Disk - Phase Change 5.25" Rewriteable + PD_5_RW, // Opt_Disk - PhaseChange Dual Rewriteable + ABL_5_WO, // Opt_Disk - Ablative 5.25" Write Once Optical + PINNACLE_APEX_5_RW, // Opt_Disk - Pinnacle Apex 4.6GB Rewriteable Optical + SONY_12_WO, // Opt_Disk - Sony 12" Write Once + PHILIPS_12_WO, // Opt_Disk - Philips/LMS 12" Write Once + HITACHI_12_WO, // Opt_Disk - Hitachi 12" Write Once + CYGNET_12_WO, // Opt_Disk - Cygnet/ATG 12" Write Once + KODAK_14_WO, // Opt_Disk - Kodak 14" Write Once + MO_NFR_525, // Opt_Disk - Near Field Recording (Terastor) + NIKON_12_RW, // Opt_Disk - Nikon 12" Rewriteable + IOMEGA_ZIP, // Mag_Disk - Iomega Zip + IOMEGA_JAZ, // Mag_Disk - Iomega Jaz + SYQUEST_EZ135, // Mag_Disk - Syquest EZ135 + SYQUEST_EZFLYER, // Mag_Disk - Syquest EzFlyer + SYQUEST_SYJET, // Mag_Disk - Syquest SyJet + AVATAR_F2, // Mag_Disk - 2.5" Floppy + MP2_8mm, // Tape - 8mm Hitachi + DST_S, // Ampex DST Small Tapes + DST_M, // Ampex DST Medium Tapes + DST_L, // Ampex DST Large Tapes + VXATape_1, // Ecrix 8mm Tape + VXATape_2, // Ecrix 8mm Tape +#if (NTDDI_VERSION < NTDDI_WINXP) + STK_EAGLE, // STK Eagle +#else + STK_9840, // STK 9840 +#endif + LTO_Ultrium, // IBM, HP, Seagate LTO Ultrium + LTO_Accelis, // IBM, HP, Seagate LTO Accelis + DVD_RAM, // Opt_Disk - DVD-RAM + AIT_8mm, // AIT2 or higher + ADR_1, // OnStream ADR Mediatypes + ADR_2, + STK_9940, // STK 9940 + SAIT, // SAIT Tapes + VXATape // VXA (Ecrix 8mm) Tape +}STORAGE_MEDIA_TYPE, *PSTORAGE_MEDIA_TYPE; + +#define MEDIA_ERASEABLE 0x00000001 +#define MEDIA_WRITE_ONCE 0x00000002 +#define MEDIA_READ_ONLY 0x00000004 +#define MEDIA_READ_WRITE 0x00000008 + +#define MEDIA_WRITE_PROTECTED 0x00000100 +#define MEDIA_CURRENTLY_MOUNTED 0x80000000 + +// +// Define the different storage bus types +// Bus types below 128 (0x80) are reserved for Microsoft use +// + +typedef enum __WRAPPED__ _STORAGE_BUS_TYPE { + BusTypeUnknown = 0x00, + BusTypeScsi, + BusTypeAtapi, + BusTypeAta, + BusType1394, + BusTypeSsa, + BusTypeFibre, + BusTypeUsb, + BusTypeRAID, + BusTypeiScsi, + BusTypeSas, + BusTypeSata, + BusTypeSd, + BusTypeMmc, + BusTypeVirtual, + BusTypeFileBackedVirtual, + BusTypeSpaces, + BusTypeNvme, + BusTypeSCM, + BusTypeUfs, + BusTypeMax, + BusTypeMaxReserved = 0x7F +} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE; + +// +// Macro to identify which bus types +// support shared storage +// + +#define SupportsDeviceSharing( BusType ) ( \ + (BusType == BusTypeScsi) || \ + (BusType == BusTypeFibre) || \ + (BusType == BusTypeiScsi) || \ + (BusType == BusTypeSas) || \ + (BusType == BusTypeSpaces) ) + +typedef struct _DEVICE_MEDIA_INFO { + union { + struct { + LARGE_INTEGER Cylinders; + STORAGE_MEDIA_TYPE MediaType; + ULONG TracksPerCylinder; + ULONG SectorsPerTrack; + ULONG BytesPerSector; + ULONG NumberMediaSides; + ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. + } DiskInfo; + + struct { + LARGE_INTEGER Cylinders; + STORAGE_MEDIA_TYPE MediaType; + ULONG TracksPerCylinder; + ULONG SectorsPerTrack; + ULONG BytesPerSector; + ULONG NumberMediaSides; + ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. + } RemovableDiskInfo; + + struct { + STORAGE_MEDIA_TYPE MediaType; + ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. + ULONG CurrentBlockSize; + STORAGE_BUS_TYPE BusType; + + // + // Bus specific information describing the medium supported. + // + + union { + struct { + UCHAR MediumType; + UCHAR DensityCode; + } ScsiInformation; + } BusSpecificData; + + } TapeInfo; + } DeviceSpecific; +} DEVICE_MEDIA_INFO, *PDEVICE_MEDIA_INFO; + +typedef struct _GET_MEDIA_TYPES { + ULONG DeviceType; // FILE_DEVICE_XXX values + ULONG MediaInfoCount; + DEVICE_MEDIA_INFO MediaInfo[1]; +} GET_MEDIA_TYPES, *PGET_MEDIA_TYPES; + + +// +// IOCTL_STORAGE_PREDICT_FAILURE +// +// input - none +// +// output - STORAGE_PREDICT_FAILURE structure +// PredictFailure returns zero if no failure predicted and non zero +// if a failure is predicted. +// +// VendorSpecific returns 512 bytes of vendor specific information +// if a failure is predicted +// +typedef struct _STORAGE_PREDICT_FAILURE +{ + ULONG PredictFailure; + UCHAR VendorSpecific[512]; +} STORAGE_PREDICT_FAILURE, *PSTORAGE_PREDICT_FAILURE; + + +// +// IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG +// +// Input - STORAGE_FAILURE_PREDICTION_CONFIG structure. +// If the sender wants to enable or disable failure prediction then +// the sender should set the "Set" field to TRUE. +// Output - STORAGE_FAILURE_PREDICTION_CONFIG structure. +// If successful, the "Enabled" field will indicate if failure +// prediction is currently enabled or not. +// +typedef struct _STORAGE_FAILURE_PREDICTION_CONFIG { + ULONG Version; // Set to 1 for Blue. + ULONG Size; + BOOLEAN Set; // TRUE if the sender wants to enable/disable failure prediction. + BOOLEAN Enabled; + USHORT Reserved; +} STORAGE_FAILURE_PREDICTION_CONFIG, *PSTORAGE_FAILURE_PREDICTION_CONFIG; + +#define STORAGE_FAILURE_PREDICTION_CONFIG_V1 1 + +// end_ntminitape + +// +// Property Query Structures +// + +// +// IOCTL_STORAGE_QUERY_PROPERTY +// +// Input Buffer: +// a STORAGE_PROPERTY_QUERY structure which describes what type of query +// is being done, what property is being queried for, and any additional +// parameters which a particular property query requires. +// +// Output Buffer: +// Contains a buffer to place the results of the query into. Since all +// property descriptors can be cast into a STORAGE_DESCRIPTOR_HEADER, +// the IOCTL can be called once with a small buffer then again using +// a buffer as large as the header reports is necessary. +// + + +// +// Types of queries +// + +typedef enum _STORAGE_QUERY_TYPE { + PropertyStandardQuery = 0, // Retrieves the descriptor + PropertyExistsQuery, // Used to test whether the descriptor is supported + PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the descriptor + PropertyQueryMaxDefined // use to validate the value +} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE; + +// +// define some initial property id's +// + +typedef enum __WRAPPED__ _STORAGE_PROPERTY_ID { + StorageDeviceProperty = 0, + StorageAdapterProperty, + StorageDeviceIdProperty, + StorageDeviceUniqueIdProperty, // See storduid.h for details + StorageDeviceWriteCacheProperty, + StorageMiniportProperty, + StorageAccessAlignmentProperty, + StorageDeviceSeekPenaltyProperty, + StorageDeviceTrimProperty, + StorageDeviceWriteAggregationProperty, + StorageDeviceDeviceTelemetryProperty, + StorageDeviceLBProvisioningProperty, + StorageDevicePowerProperty, + StorageDeviceCopyOffloadProperty, + StorageDeviceResiliencyProperty, + StorageDeviceMediumProductType, + StorageAdapterRpmbProperty, + StorageAdapterCryptoProperty, +// end_winioctl + StorageDeviceTieringProperty, + StorageDeviceFaultDomainProperty, + StorageDeviceClusportProperty, +// begin_winioctl + StorageDeviceIoCapabilityProperty = 48, + StorageAdapterProtocolSpecificProperty, + StorageDeviceProtocolSpecificProperty, + StorageAdapterTemperatureProperty, + StorageDeviceTemperatureProperty, + StorageAdapterPhysicalTopologyProperty, + StorageDevicePhysicalTopologyProperty, + StorageDeviceAttributesProperty, + StorageDeviceManagementStatus, + StorageAdapterSerialNumberProperty, + StorageDeviceLocationProperty, + StorageDeviceNumaProperty, + StorageDeviceZonedDeviceProperty, + StorageDeviceUnsafeShutdownCount +} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID; + +// +// Query structure - additional parameters for specific queries can follow +// the header +// + +typedef struct _STORAGE_PROPERTY_QUERY { + + // + // ID of the property being retrieved + // + + STORAGE_PROPERTY_ID PropertyId; + + // + // Flags indicating the type of query being performed + // + + STORAGE_QUERY_TYPE QueryType; + + // + // Space for additional parameters if necessary + // + + UCHAR AdditionalParameters[1]; + +} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY; + +// +// Standard property descriptor header. All property pages should use this +// as their first element or should contain these two elements +// + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_DESCRIPTOR_HEADER { + + __WRAPPED__ + ULONG Version; + + __WRAPPED__ + ULONG Size; + +} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER; + +// +// Device property descriptor - this is really just a rehash of the inquiry +// data retrieved from a scsi device +// +// This may only be retrieved from a target device. Sending this to the bus +// will result in an error +// + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_DEVICE_DESCRIPTOR { + + // + // Sizeof(STORAGE_DEVICE_DESCRIPTOR) + // + + __WRAPPED__ + ULONG Version; + + // + // Total size of the descriptor, including the space for additional + // data and id strings + // + + __WRAPPED__ + ULONG Size; + + // + // The SCSI-2 device type + // + + __WRAPPED__ + UCHAR DeviceType; + + // + // The SCSI-2 device type modifier (if any) - this may be zero + // + + __WRAPPED__ + UCHAR DeviceTypeModifier; + + // + // Flag indicating whether the device's media (if any) is removable. This + // field should be ignored for media-less devices + // + + __WRAPPED__ + BOOLEAN RemovableMedia; + + // + // Flag indicating whether the device can support mulitple outstanding + // commands. The actual synchronization in this case is the responsibility + // of the port driver. + // + + __WRAPPED__ + BOOLEAN CommandQueueing; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // vendor id string. For devices with no such ID this will be zero + // + + __WRAPPED__ + ULONG VendorIdOffset; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // product id string. For devices with no such ID this will be zero + // + + __WRAPPED__ + ULONG ProductIdOffset; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // product revision string. For devices with no such string this will be + // zero + // + + __WRAPPED__ + ULONG ProductRevisionOffset; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // serial number. For devices with no serial number this will be zero + // + + __WRAPPED__ + ULONG SerialNumberOffset; + + // + // Contains the bus type (as defined above) of the device. It should be + // used to interpret the raw device properties at the end of this structure + // (if any) + // + + __WRAPPED__ + STORAGE_BUS_TYPE BusType; + + // + // The number of bytes of bus-specific data which have been appended to + // this descriptor + // + + __WRAPPED__ + ULONG RawPropertiesLength; + + // + // Place holder for the first byte of the bus specific property data + // + + __WRAPPED__ + UCHAR RawDeviceProperties[1]; + +} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR; + + +// +// Adapter properties +// +// This descriptor can be retrieved from a target device object of from the +// device object for the bus. Retrieving from the target device object will +// forward the request to the underlying bus +// + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_ADAPTER_DESCRIPTOR { + + __WRAPPED__ + ULONG Version; + + __WRAPPED__ + ULONG Size; + + __WRAPPED__ + ULONG MaximumTransferLength; + + __WRAPPED__ + ULONG MaximumPhysicalPages; + + __WRAPPED__ + ULONG AlignmentMask; + + __WRAPPED__ + BOOLEAN AdapterUsesPio; + + __WRAPPED__ + BOOLEAN AdapterScansDown; + + __WRAPPED__ + BOOLEAN CommandQueueing; + + __WRAPPED__ + BOOLEAN AcceleratedTransfer; + +#if (NTDDI_VERSION < NTDDI_WINXP) + BOOLEAN BusType; +#else + __WRAPPED__ + UCHAR BusType; +#endif + + __WRAPPED__ + USHORT BusMajorVersion; + + __WRAPPED__ + USHORT BusMinorVersion; + +#if (NTDDI_VERSION >= NTDDI_WIN8) + + __WRAPPED__ + UCHAR SrbType; + + __WRAPPED__ + UCHAR AddressType; +#endif + +} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR; + + +#if (NTDDI_VERSION >= NTDDI_WIN8) + +#define NO_SRBTYPE_ADAPTER_DESCRIPTOR_SIZE \ + UFIELD_OFFSET(STORAGE_ADAPTER_DESCRIPTOR, SrbType) + +#if !defined(SRB_TYPE_SCSI_REQUEST_BLOCK) +#define SRB_TYPE_SCSI_REQUEST_BLOCK 0 +#endif + +#if !defined(SRB_TYPE_STORAGE_REQUEST_BLOCK) +#define SRB_TYPE_STORAGE_REQUEST_BLOCK 1 +#endif + +#if !defined(STORAGE_ADDRESS_TYPE_BTL8) +#define STORAGE_ADDRESS_TYPE_BTL8 0 +#endif + +#endif // (NTDDI_VERSION >= NTDDI_WIN8) + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR { + + // + // Sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) + // + + __WRAPPED__ + ULONG Version; + + // + // Total size of the descriptor, including the space for additional + // data and id strings + // + + __WRAPPED__ + ULONG Size; + + // + // The number of bytes in a cache line of the device + // + + __WRAPPED__ + ULONG BytesPerCacheLine; + + // + // The address offset neccessary for proper cache access alignment in bytes + // + + __WRAPPED__ + ULONG BytesOffsetForCacheAlignment; + + // + // The number of bytes in a physical sector of the device + // + + __WRAPPED__ + ULONG BytesPerLogicalSector; + + // + // The number of bytes in an addressable logical sector (LBA)of the device + // + + __WRAPPED__ + ULONG BytesPerPhysicalSector; + + // + // The address offset neccessary for proper sector access alignment in bytes + // + + __WRAPPED__ + ULONG BytesOffsetForSectorAlignment; + +} STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR, *PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR; + +typedef _Struct_size_bytes_(Size) struct _STORAGE_MEDIUM_PRODUCT_TYPE_DESCRIPTOR { + + // + // Sizeof(STORAGE_MEDIUM_PRODUCT_TYPE_DESCRIPTOR) + // + + ULONG Version; + + // + // Total size of the descriptor, including the space for additional data + // + + ULONG Size; + + // + // Product type of the supporting storage medium + // + + ULONG MediumProductType; + +} STORAGE_MEDIUM_PRODUCT_TYPE_DESCRIPTOR, *PSTORAGE_MEDIUM_PRODUCT_TYPE_DESCRIPTOR; + + +typedef enum __WRAPPED__ _STORAGE_PORT_CODE_SET { + StoragePortCodeSetReserved = 0, + StoragePortCodeSetStorport = 1, + StoragePortCodeSetSCSIport = 2, + StoragePortCodeSetSpaceport = 3, + StoragePortCodeSetATAport = 4, + StoragePortCodeSetUSBport = 5, + StoragePortCodeSetSBP2port = 6, + StoragePortCodeSetSDport = 7 +} STORAGE_PORT_CODE_SET, *PSTORAGE_PORT_CODE_SET; + +#if (NTDDI_VERSION >= NTDDI_WIN8) +#define STORAGE_MINIPORT_DESCRIPTOR_V1_SIZE RTL_SIZEOF_THROUGH_FIELD(STORAGE_MINIPORT_DESCRIPTOR, IoTimeoutValue) +#endif + +typedef struct __WRAPPED__ _STORAGE_MINIPORT_DESCRIPTOR { + + __WRAPPED__ + ULONG Version; + + __WRAPPED__ + ULONG Size; + + __WRAPPED__ + STORAGE_PORT_CODE_SET Portdriver; + + __WRAPPED__ + BOOLEAN LUNResetSupported; + + __WRAPPED__ + BOOLEAN TargetResetSupported; + +#if (NTDDI_VERSION >= NTDDI_WIN8) + __WRAPPED__ + USHORT IoTimeoutValue; +#endif + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) + __WRAPPED__ + BOOLEAN ExtraIoInfoSupported; + + __WRAPPED__ + UCHAR Reserved0[3]; + + __WRAPPED__ + ULONG Reserved1; +#endif + +} STORAGE_MINIPORT_DESCRIPTOR, *PSTORAGE_MINIPORT_DESCRIPTOR; + +// +// Storage identification descriptor. +// The definitions here are based on the SCSI/SBP vital product data +// device identifier page. +// + +typedef enum __WRAPPED__ _STORAGE_IDENTIFIER_CODE_SET { + StorageIdCodeSetReserved = 0, + StorageIdCodeSetBinary = 1, + StorageIdCodeSetAscii = 2, + StorageIdCodeSetUtf8 = 3 +} STORAGE_IDENTIFIER_CODE_SET, *PSTORAGE_IDENTIFIER_CODE_SET; + +typedef enum __WRAPPED__ _STORAGE_IDENTIFIER_TYPE { + StorageIdTypeVendorSpecific = 0, + StorageIdTypeVendorId = 1, + StorageIdTypeEUI64 = 2, + StorageIdTypeFCPHName = 3, + StorageIdTypePortRelative = 4, + StorageIdTypeTargetPortGroup = 5, + StorageIdTypeLogicalUnitGroup = 6, + StorageIdTypeMD5LogicalUnitIdentifier = 7, + StorageIdTypeScsiNameString = 8 +} STORAGE_IDENTIFIER_TYPE, *PSTORAGE_IDENTIFIER_TYPE; + +// Mislabeled above but need to keep it for backwards compatibility +#define StorageIdTypeNAA StorageIdTypeFCPHName + +// NAA formats (Used with StorageIdTypeNAA) +typedef enum __WRAPPED__ _STORAGE_ID_NAA_FORMAT { + StorageIdNAAFormatIEEEExtended = 2, + StorageIdNAAFormatIEEERegistered = 3, + StorageIdNAAFormatIEEEERegisteredExtended = 5 +} STORAGE_ID_NAA_FORMAT, *PSTORAGE_ID_NAA_FORMAT; + +typedef enum __WRAPPED__ _STORAGE_ASSOCIATION_TYPE { + StorageIdAssocDevice = 0, + StorageIdAssocPort = 1, + StorageIdAssocTarget = 2 +} STORAGE_ASSOCIATION_TYPE, *PSTORAGE_ASSOCIATION_TYPE; + +typedef struct __WRAPPED__ _STORAGE_IDENTIFIER { + + __WRAPPED__ + STORAGE_IDENTIFIER_CODE_SET CodeSet; + + __WRAPPED__ + STORAGE_IDENTIFIER_TYPE Type; + + __WRAPPED__ + USHORT IdentifierSize; + + __WRAPPED__ + USHORT NextOffset; + + // + // Add new fields here since existing code depends on + // the above layout not changing. + // + + __WRAPPED__ + STORAGE_ASSOCIATION_TYPE Association; + + // + // The identifier is a variable length array of bytes. + // + + __WRAPPED__ + UCHAR Identifier[1]; + +} STORAGE_IDENTIFIER, *PSTORAGE_IDENTIFIER; + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_DEVICE_ID_DESCRIPTOR { + + __WRAPPED__ + ULONG Version; + + __WRAPPED__ + ULONG Size; + + // + // The number of identifiers reported by the device. + // + + __WRAPPED__ + ULONG NumberOfIdentifiers; + + // + // The following field is actually a variable length array of identification + // descriptors. Unfortunately there's no C notation for an array of + // variable length structures so we're forced to just pretend. + // + + __WRAPPED__ + UCHAR Identifiers[1]; + +} STORAGE_DEVICE_ID_DESCRIPTOR, *PSTORAGE_DEVICE_ID_DESCRIPTOR; + +// output buffer for StorageDeviceSeekPenaltyProperty & PropertyStandardQuery +typedef struct __WRAPPED__ _DEVICE_SEEK_PENALTY_DESCRIPTOR { + + __WRAPPED__ + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + __WRAPPED__ + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + __WRAPPED__ + BOOLEAN IncursSeekPenalty; +} DEVICE_SEEK_PENALTY_DESCRIPTOR, *PDEVICE_SEEK_PENALTY_DESCRIPTOR; + +// output buffer for StorageDeviceWriteAggregationProperty & PropertyStandardQuery +typedef struct _DEVICE_WRITE_AGGREGATION_DESCRIPTOR { + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + BOOLEAN BenefitsFromWriteAggregation; +} DEVICE_WRITE_AGGREGATION_DESCRIPTOR, *PDEVICE_WRITE_AGGREGATION_DESCRIPTOR; + +// output buffer for StorageDeviceTrimProperty & PropertyStandardQuery +typedef struct __WRAPPED__ _DEVICE_TRIM_DESCRIPTOR { + + __WRAPPED__ + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + __WRAPPED__ + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + __WRAPPED__ + BOOLEAN TrimEnabled; + +} DEVICE_TRIM_DESCRIPTOR, *PDEVICE_TRIM_DESCRIPTOR; + +#pragma warning(push) +#pragma warning(disable:4214) // bit fields other than int +// +// Output buffer for StorageDeviceLBProvisioningProperty & PropertyStandardQuery +// +typedef struct __WRAPPED__ _DEVICE_LB_PROVISIONING_DESCRIPTOR { + __WRAPPED__ + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + __WRAPPED__ + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + __WRAPPED__ + UCHAR ThinProvisioningEnabled : 1; + + __WRAPPED__ + UCHAR ThinProvisioningReadZeros : 1; + + __WRAPPED__ + UCHAR AnchorSupported : 3; + + __WRAPPED__ + UCHAR UnmapGranularityAlignmentValid : 1; + + __WRAPPED__ + UCHAR Reserved0 : 2; + + __WRAPPED__ + UCHAR Reserved1[7]; + + __WRAPPED__ + ULONGLONG OptimalUnmapGranularity; // Granularity in bytes. + + __WRAPPED__ + ULONGLONG UnmapGranularityAlignment; // Granularity alignment in bytes. + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) + + __WRAPPED__ + ULONG MaxUnmapLbaCount; // Max LBAs that can be unmapped in a single UNMAP command, in logical blocks. + + __WRAPPED__ + ULONG MaxUnmapBlockDescriptorCount; // Max number of descriptors allowed in a single UNMAP command. + +#endif +} DEVICE_LB_PROVISIONING_DESCRIPTOR, *PDEVICE_LB_PROVISIONING_DESCRIPTOR; + +#define DEVICE_LB_PROVISIONING_DESCRIPTOR_V1_SIZE RTL_SIZEOF_THROUGH_FIELD(DEVICE_LB_PROVISIONING_DESCRIPTOR, UnmapGranularityAlignment) + +// +// IOCTL_STORAGE_GET_LB_PROVISIONING_MAP_RESOURCES +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type STORAGE_LB_PROVISIONING_MAP_RESOURCES +// + +typedef struct _STORAGE_LB_PROVISIONING_MAP_RESOURCES { + ULONG Size; + ULONG Version; + UCHAR AvailableMappingResourcesValid : 1; + UCHAR UsedMappingResourcesValid : 1; + UCHAR Reserved0 : 6; + UCHAR Reserved1[3]; + UCHAR AvailableMappingResourcesScope : 2; // See LOG_PAGE_LBP_RESOURCE_SCOPE_* definitions in scsi.h for scope values. + UCHAR UsedMappingResourcesScope : 2; + UCHAR Reserved2 : 4; + UCHAR Reserved3[3]; + ULONGLONG AvailableMappingResources; // Available LBA mapping resources, in bytes. + ULONGLONG UsedMappingResources; // Used LBA mapping resources, in bytes. +} STORAGE_LB_PROVISIONING_MAP_RESOURCES, *PSTORAGE_LB_PROVISIONING_MAP_RESOURCES; + +#pragma warning(pop) + +// output buffer for StorageDevicePowerProperty & PropertyStandardQuery +typedef struct _DEVICE_POWER_DESCRIPTOR { + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + BOOLEAN DeviceAttentionSupported; // The device supports "device attention". + BOOLEAN AsynchronousNotificationSupported; // The device supports asynchronous notifications, delivered via IOCTL_STORAGE_EVENT_NOTIFICATION. + BOOLEAN IdlePowerManagementEnabled; // The device has been registered for runtime idle power management. + BOOLEAN D3ColdEnabled; // The device will be powered off when put into D3. + BOOLEAN D3ColdSupported; // The platform supports D3Cold for this device. + BOOLEAN NoVerifyDuringIdlePower; // Device require no verification during idle power transitions. + UCHAR Reserved[2]; + ULONG IdleTimeoutInMS; // The idle timeout value in milliseconds. Only valid if IdlePowerManagementEnabled == TRUE. +} DEVICE_POWER_DESCRIPTOR, *PDEVICE_POWER_DESCRIPTOR; + +// +// Output buffer for StorageDeviceCopyOffloadProperty & PropertyStandardQuery +// +typedef struct _DEVICE_COPY_OFFLOAD_DESCRIPTOR { + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + ULONG MaximumTokenLifetime; + ULONG DefaultTokenLifetime; + ULONGLONG MaximumTransferSize; + ULONGLONG OptimalTransferCount; + ULONG MaximumDataDescriptors; + ULONG MaximumTransferLengthPerDescriptor; + ULONG OptimalTransferLengthPerDescriptor; + USHORT OptimalTransferLengthGranularity; + UCHAR Reserved[2]; +} DEVICE_COPY_OFFLOAD_DESCRIPTOR, *PDEVICE_COPY_OFFLOAD_DESCRIPTOR; + +// +// Output buffer for StorageDeviceResiliencyProperty & PropertyStandardQuery +// + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_DEVICE_RESILIENCY_DESCRIPTOR { + + // + // Size of this structure serves + // as the version + // + + __WRAPPED__ + ULONG Version; + + // + // Size of this structure plus + // all the variable sized fields + // + + __WRAPPED__ + ULONG Size; + + // + // Friendly name associated with + // this descriptor + // + + __WRAPPED__ + ULONG NameOffset; + + // + // Number of logical copies of + // data that are available + // + + __WRAPPED__ + ULONG NumberOfLogicalCopies; + + // + // Number of complete copies of + // data that are stored + // + + __WRAPPED__ + ULONG NumberOfPhysicalCopies; + + // + // Number of disks that can fail + // without leading to data loss + // + + __WRAPPED__ + ULONG PhysicalDiskRedundancy; + + // + // Number of columns associated + // with this descriptor + // + + __WRAPPED__ + ULONG NumberOfColumns; + + // + // Stripe width associated with + // this descriptor, in bytes + // + + __WRAPPED__ + ULONG Interleave; + +} STORAGE_DEVICE_RESILIENCY_DESCRIPTOR, *PSTORAGE_DEVICE_RESILIENCY_DESCRIPTOR; + +// +// Output buffer for StorageAdapterRpmbProperty & PropertyStandardQuery +// + +typedef enum _STORAGE_RPMB_FRAME_TYPE { + + StorageRpmbFrameTypeUnknown = 0, + StorageRpmbFrameTypeStandard, + StorageRpmbFrameTypeMax, + +} STORAGE_RPMB_FRAME_TYPE, *PSTORAGE_RPMB_FRAME_TYPE; + +#define STORAGE_RPMB_DESCRIPTOR_VERSION_1 1 + +#define STORAGE_RPMB_MINIMUM_RELIABLE_WRITE_SIZE 512 + +typedef struct _STORAGE_RPMB_DESCRIPTOR { + + // + // Keep compatible with STORAGE_DESCRIPTOR_HEADER + // Shall be set to STORAGE_RPMB_DESCRIPTOR_VERSION_1 + // + + ULONG Version; + + // + // Keep compatible with STORAGE_DESCRIPTOR_HEADER + // Shall be set to sizeof(STORAGE_RPMB_DESCRIPTOR) + // + + ULONG Size; + + // + // The size of the RPMB, in bytes. + // + // 0 if not supported, RPMB size in bytes otherwise + // + + ULONG SizeInBytes; + + // + // The maximum amount of data supported in one transaction + // in bytes. + // + // 0 if not supported, minimum 512 bytes + // + + ULONG MaxReliableWriteSizeInBytes; + + // + // To support different RPMB frame formats, specify which + // frame format the payload will be in so the port driver + // can take the appropriate action + // + + STORAGE_RPMB_FRAME_TYPE FrameFormat; + +} STORAGE_RPMB_DESCRIPTOR, *PSTORAGE_RPMB_DESCRIPTOR; + +// +// Output buffer for StorageAdapterCryptoProperty & PropertyStandardQuery +// + +typedef enum _STORAGE_CRYPTO_ALGORITHM_ID { + + StorageCryptoAlgorithmUnknown = 0, + StorageCryptoAlgorithmXTSAES = 1, + StorageCryptoAlgorithmBitlockerAESCBC, + StorageCryptoAlgorithmAESECB, + StorageCryptoAlgorithmESSIVAESCBC, + StorageCryptoAlgorithmMax + +} STORAGE_CRYPTO_ALGORITHM_ID, *PSTORAGE_CRYPTO_ALGORITHM_ID; + +typedef enum _STORAGE_CRYPTO_KEY_SIZE { + + StorageCryptoKeySizeUnknown = 0, + StorageCryptoKeySize128Bits = 1, + StorageCryptoKeySize192Bits, + StorageCryptoKeySize256Bits, + StorageCryptoKeySize512Bits + +} STORAGE_CRYPTO_KEY_SIZE, *PSTORAGE_CRYPTO_KEY_SIZE; + +#define STORAGE_CRYPTO_CAPABILITY_VERSION_1 1 + +typedef struct _STORAGE_CRYPTO_CAPABILITY { + + // + // To enable versioning of this structure. This shall bet set + // to STORAGE_CRYPTO_CAPABILITY_VERSION_1 + // + + ULONG Version; + + // + // Size of this structure. This shall be set to + // sizeof(STORAGE_CRYPTO_CAPABILITY) + // + + ULONG Size; + + // + // The index for this crypto capability + // + + ULONG CryptoCapabilityIndex; + + // + // Supported algorithm for this crypto capability + // + + STORAGE_CRYPTO_ALGORITHM_ID AlgorithmId; + + // + // The supported key size for this algorithm + // + + STORAGE_CRYPTO_KEY_SIZE KeySize; + + // + // Bitmask for the supported sizes of encryptable data blocks. When bit + // j is set (j=0...7), a data unit size of 512*2^j bytes is supported. + // Bit 0 represents 512 bytes, 1 represents 1 KB, bit 7 represents 64 KB + // + + ULONG DataUnitSizeBitmask; + +} STORAGE_CRYPTO_CAPABILITY, *PSTORAGE_CRYPTO_CAPABILITY; + +#define STORAGE_CRYPTO_DESCRIPTOR_VERSION_1 1 + +typedef struct _STORAGE_CRYPTO_DESCRIPTOR { + + // + // Keep compatible with STORAGE_DESCRIPTOR_HEADER + // Shall be set to STORAGE_CRYPTO_DESCRIPTOR_VERSION_1 + // + + ULONG Version; + + // + // Keep compatible with STORAGE_DESCRIPTOR_HEADER + // Shall be set to sizeof(STORAGE_CRYPTO_DESCRIPTOR) + // + + ULONG Size; + + // + // The number of keys the crypto engine in the adapter supports + // + + ULONG NumKeysSupported; + + // + // The number of crypto capability entries. This outlines the + // crypto configurations the adapter supports + // + + ULONG NumCryptoCapabilities; + + // + // Array of Crypto Capabilities + // + + _Field_size_(NumCryptoCapabilities) STORAGE_CRYPTO_CAPABILITY CryptoCapabilities[ANYSIZE_ARRAY]; + +} STORAGE_CRYPTO_DESCRIPTOR, *PSTORAGE_CRYPTO_DESCRIPTOR; + +// end_winioctl +// begin_winioctl + +// +// The STORAGE_TIER is an identifier for the storage tier relative to the volume/LUN. +// The storage tier ID for a particular volume has no relationship to the storage tier +// ID with the same value on a different volume. +// + +#define STORAGE_TIER_NAME_LENGTH (256) +#define STORAGE_TIER_DESCRIPTION_LENGTH (512) + +#define STORAGE_TIER_FLAG_NO_SEEK_PENALTY (0x00020000) +#define STORAGE_TIER_FLAG_WRITE_BACK_CACHE (0x00200000) +#define STORAGE_TIER_FLAG_READ_CACHE (0x00400000) +#define STORAGE_TIER_FLAG_PARITY (0x00800000) +#define STORAGE_TIER_FLAG_SMR (0x01000000) + +typedef enum _STORAGE_TIER_MEDIA_TYPE { + + StorageTierMediaTypeUnspecified = 0, + StorageTierMediaTypeDisk = 1, + StorageTierMediaTypeSsd = 2, + StorageTierMediaTypeScm = 4, + StorageTierMediaTypeMax + +} STORAGE_TIER_MEDIA_TYPE, *PSTORAGE_TIER_MEDIA_TYPE; + +typedef enum _STORAGE_TIER_CLASS { + + StorageTierClassUnspecified = 0, + StorageTierClassCapacity, + StorageTierClassPerformance, + StorageTierClassMax + +} STORAGE_TIER_CLASS, *PSTORAGE_TIER_CLASS; + +typedef struct _STORAGE_TIER { + + // + // Tier ID + // + + GUID Id; + + // + // Name for the tier + // + + WCHAR Name[STORAGE_TIER_NAME_LENGTH]; + + // + // Note for the tier + // + + WCHAR Description[STORAGE_TIER_NAME_LENGTH]; + + // + // Flags: STORAGE_TIER_FLAG_xxx + // + + ULONGLONG Flags; + + // + // Provisioned capacity of the tier + // + + ULONGLONG ProvisionedCapacity; + + // + // Media type of the tier + // + + STORAGE_TIER_MEDIA_TYPE MediaType; + + // + // Classification of the tier + // + + STORAGE_TIER_CLASS Class; + +} STORAGE_TIER, *PSTORAGE_TIER; + +// +// The response returns a single structure of STORAGE_DEVICE_TIERING_DESCRIPTOR that has +// all the tiers for this disk. +// + +typedef _Struct_size_bytes_(Size) struct _STORAGE_DEVICE_TIERING_DESCRIPTOR { + + // + // Size of this structure serves + // as the version + // + + ULONG Version; + + // + // Size of this structure plus + // all the variable sized fields + // + + ULONG Size; + + // + // Flags. The upper USHORT of these flags is reserved for file system use as + // this structure is returned slightly tweaked in FSCTL_QUERY_STORAGE_CLASSES_OUTPUT. + // + + ULONG Flags; + + // + // The total number of available tiers for this disk + // + + ULONG TotalNumberOfTiers; + + // + // The number of tiers that fit in the output + // + + ULONG NumberOfTiersReturned; + + // + // Detailed info on the storage tiers. + // + + _Field_size_(NumberOfTiersReturned) STORAGE_TIER Tiers[ANYSIZE_ARRAY]; + +} STORAGE_DEVICE_TIERING_DESCRIPTOR, *PSTORAGE_DEVICE_TIERING_DESCRIPTOR; + +// +// Output buffer for StorageDeviceFaultDomainProperty & PropertyStandardQuery +// + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_DEVICE_FAULT_DOMAIN_DESCRIPTOR { + + // + // Size of this structure serves + // as the version + // + + __WRAPPED__ + ULONG Version; + + // + // Size of this structure plus + // all the variable sized fields + // + + __WRAPPED__ + ULONG Size; + + // + // Number of fault domains + // + + __WRAPPED__ + ULONG NumberOfFaultDomains; + + // + // Fault domain ids + // + + _Field_size_(NumberOfFaultDomains) + __WRAPPED__ + GUID FaultDomainIds[ANYSIZE_ARRAY]; + +} STORAGE_DEVICE_FAULT_DOMAIN_DESCRIPTOR, *PSTORAGE_DEVICE_FAULT_DOMAIN_DESCRIPTOR; + +// +// Parameters for StorageAdapterProtocolSpecificProperty (or StorageDeviceProtocolSpecificProperty) & PropertyStandardQuery +// + +// +// Define the different storage command protocols that used between software and hardware. +// e.g. command protocol software uses to communicate with hardware. +// Protocol types below 128 (0x80) are reserved for Microsoft use. +// +typedef enum _STORAGE_PROTOCOL_TYPE { + ProtocolTypeUnknown = 0x00, + ProtocolTypeScsi, + ProtocolTypeAta, + ProtocolTypeNvme, + ProtocolTypeSd, + ProtocolTypeUfs, + ProtocolTypeProprietary = 0x7E, + ProtocolTypeMaxReserved = 0x7F +} STORAGE_PROTOCOL_TYPE, *PSTORAGE_PROTOCOL_TYPE; + + +typedef enum _STORAGE_PROTOCOL_NVME_DATA_TYPE { + NVMeDataTypeUnknown = 0, + NVMeDataTypeIdentify, // Retrieved by command - IDENTIFY CONTROLLER or IDENTIFY NAMESPACE + NVMeDataTypeLogPage, // Retrieved by command - GET LOG PAGE + NVMeDataTypeFeature, // Retrieved by command - GET FEATURES +} STORAGE_PROTOCOL_NVME_DATA_TYPE, *PSTORAGE_PROTOCOL_NVME_DATA_TYPE; + +typedef enum _STORAGE_PROTOCOL_ATA_DATA_TYPE { + AtaDataTypeUnknown = 0, + AtaDataTypeIdentify, // Retrieved by command - IDENTIFY DEVICE + AtaDataTypeLogPage, // Retrieved by command - READ LOG EXT +} STORAGE_PROTOCOL_ATA_DATA_TYPE, *PSTORAGE_PROTOCOL_ATA_DATA_TYPE; + +typedef enum _STORAGE_PROTOCOL_UFS_DATA_TYPE { + UfsDataTypeUnknown = 0, + UfsDataTypeQueryDescriptor, // Retrieved by command - QUERY UPIU + UfsDataTypeMax, +} STORAGE_PROTOCOL_UFS_DATA_TYPE, *PSTORAGE_PROTOCOL_UFS_DATA_TYPE; + +// +// Protocol Data should follow this data structure in the same buffer. +// The offset of Protocol Data from the beginning of this data structure +// is reported in data field - "ProtocolDataOffset". +// +typedef struct _STORAGE_PROTOCOL_SPECIFIC_DATA { + + STORAGE_PROTOCOL_TYPE ProtocolType; + ULONG DataType; // The value will be protocol specific, as defined in STORAGE_PROTOCOL_NVME_DATA_TYPE or STORAGE_PROTOCOL_ATA_DATA_TYPE. + + ULONG ProtocolDataRequestValue; + ULONG ProtocolDataRequestSubValue; + + ULONG ProtocolDataOffset; // The offset of data buffer is from beginning of this data structure. + ULONG ProtocolDataLength; + + ULONG FixedProtocolReturnData; // This is returned data, especially from NVMe feature data that doesn't need separate device data transfer. + ULONG Reserved[3]; + +} STORAGE_PROTOCOL_SPECIFIC_DATA, *PSTORAGE_PROTOCOL_SPECIFIC_DATA; + +// +// Input parameters for StorageAdapterProtocolSpecificProperty (or StorageDeviceProtocolSpecificProperty) & PropertyStandardQuery +// will be data structure STORAGE_PROPERTY_QUERY, where the data field "AdditionalParameters" is a buffer +// in format of STORAGE_PROTOCOL_SPECIFIC_DATA. +// + +// +// Out parameters for StorageAdapterProtocolSpecificProperty (or StorageDeviceProtocolSpecificProperty) & PropertyStandardQuery +// +typedef struct _STORAGE_PROTOCOL_DATA_DESCRIPTOR { + + ULONG Version; + ULONG Size; + + STORAGE_PROTOCOL_SPECIFIC_DATA ProtocolSpecificData; + +} STORAGE_PROTOCOL_DATA_DESCRIPTOR, *PSTORAGE_PROTOCOL_DATA_DESCRIPTOR; + +// +// Parameters for StorageAdapterTemperatureProperty (or StorageDeviceTemperatureProperty) & PropertyStandardQuery +// + + +// +// Input parameters for StorageAdapterTemperatureProperty (or StorageDeviceTemperatureProperty) & PropertyStandardQuery +// uses data structure STORAGE_PROPERTY_QUERY. +// + +// +// Out parameters for StorageAdapterTemperatureProperty (or StorageDeviceTemperatureProperty) & PropertyStandardQuery +// For temperature/threshold data fields, the smallest value of SHORT type - 0x8000 indicates the value is not reported. +// +#define STORAGE_TEMPERATURE_VALUE_NOT_REPORTED 0x8000 + +typedef struct _STORAGE_TEMPERATURE_INFO { + + USHORT Index; // Starts from 0. Index 0 may indicate a composite value. + SHORT Temperature; // Signed value; in Celsius. + SHORT OverThreshold; // Signed value; in Celsius. + SHORT UnderThreshold; // Signed value; in Celsius. + + BOOLEAN OverThresholdChangable; // Can the threshold value being changed by using IOCTL_STORAGE_SET_TEMPERATURE_THRESHOLD. + BOOLEAN UnderThresholdChangable; // Can the threshold value being changed by using IOCTL_STORAGE_SET_TEMPERATURE_THRESHOLD. + BOOLEAN EventGenerated; // Indicates that notification will be generated when temperature cross threshold. + UCHAR Reserved0; + ULONG Reserved1; + +} STORAGE_TEMPERATURE_INFO, *PSTORAGE_TEMPERATURE_INFO; + +typedef struct _STORAGE_TEMPERATURE_DATA_DESCRIPTOR { + + ULONG Version; + ULONG Size; + + // + // Indicates the maximum temperature in degrees Celsius that may prevent continued normal operation, + // possibility of data loss, automatic device shutdown, extreme performance throttling, or permanent damage. + // + SHORT CriticalTemperature; // Signed value; in Celsius. + + // + // Indicates the maximum temperature in degrees Celsius at which the device is capable of + // operating continuously without degrading operation or reliability. + // + SHORT WarningTemperature; // Signed value; in Celsius. + + USHORT InfoCount; // Some devices may report more than one temperature information as there can be multiple sensors implemented. + + UCHAR Reserved0[2]; + + ULONG Reserved1[2]; + + STORAGE_TEMPERATURE_INFO TemperatureInfo[ANYSIZE_ARRAY]; + +} STORAGE_TEMPERATURE_DATA_DESCRIPTOR, *PSTORAGE_TEMPERATURE_DATA_DESCRIPTOR; + + +// +// Input parameters for IOCTL_STORAGE_SET_TEMPERATURE_THRESHOLD +// + +// +// Indicate the target of the request other than the device handle/object itself. +// This is used in "Flags" field of data structures. +// +#define STORAGE_TEMPERATURE_THRESHOLD_FLAG_ADAPTER_REQUEST 0x0001 + +typedef struct _STORAGE_TEMPERATURE_THRESHOLD { + + ULONG Version; + ULONG Size; + + USHORT Flags; + USHORT Index; + + SHORT Threshold; // Signed value; in Celsius. + BOOLEAN OverThreshold; // If TRUE, set the OverThreshold value; Otherwise, set the UnderThreshold value. + UCHAR Reserved; + +} STORAGE_TEMPERATURE_THRESHOLD, *PSTORAGE_TEMPERATURE_THRESHOLD; + +// +// Parameters for StorageAdapterPhysicalTopologyProperty (or StorageDevicePhysicalTopologyProperty) & PropertyStandardQuery +// + + +// +// Input parameters for StorageAdapterPhysicalTopologyProperty (or StorageDevicePhysicalTopologyProperty) & PropertyStandardQuery +// uses data structure STORAGE_PROPERTY_QUERY. +// + +// +// Out parameters for StorageAdapterPhysicalTopologyProperty (or StorageDevicePhysicalTopologyProperty) & PropertyStandardQuery +// uses data structure STORAGE_PHYSICAL_TOPOLOGY_DESCRIPTOR +// + +// +// Multiple roles are allowed for a single device. +// +#define STORAGE_COMPONENT_ROLE_CACHE 0x00000001 +#define STORAGE_COMPONENT_ROLE_TIERING 0x00000002 +#define STORAGE_COMPONENT_ROLE_DATA 0x00000004 + + +typedef enum _STORAGE_DEVICE_FORM_FACTOR { + FormFactorUnknown = 0, + + FormFactor3_5, // 3.5 inch nominal form factor + FormFactor2_5, // 2.5 inch nominal form factor + FormFactor1_8, // 1.8 inch nominal form factor + FormFactor1_8Less, // Less than 1.8 inch nominal form factor + + FormFactorEmbedded, // Embedded on board. + FormFactorMemoryCard, // Memory card such as SD, CF. + FormFactormSata, // mSATA + FormFactorM_2, // M.2 + FormFactorPCIeBoard, // PCIe card plug into slot. + FormFactorDimm, // DIMM Slot + +} STORAGE_DEVICE_FORM_FACTOR, *PSTORAGE_DEVICE_FORM_FACTOR; + + +typedef enum _STORAGE_COMPONENT_HEALTH_STATUS { + HealthStatusUnknown = 0, + HealthStatusNormal, + HealthStatusThrottled, + HealthStatusWarning, + HealthStatusDisabled, + HealthStatusFailed, +} STORAGE_COMPONENT_HEALTH_STATUS, *PSTORAGE_COMPONENT_HEALTH_STATUS; + +#pragma warning(push) +#pragma warning(disable:4201) // nameless struct/unions + +typedef union _STORAGE_SPEC_VERSION { + + struct { + union { + struct { + UCHAR SubMinor; + UCHAR Minor; + } DUMMYSTRUCTNAME; + + USHORT AsUshort; + + } MinorVersion; + + USHORT MajorVersion; + } DUMMYSTRUCTNAME; + + ULONG AsUlong; + +} STORAGE_SPEC_VERSION, *PSTORAGE_SPEC_VERSION; + +#pragma warning(pop) + + +typedef struct _STORAGE_PHYSICAL_DEVICE_DATA { + + ULONG DeviceId; + ULONG Role; // Value(s) of bitmask from STORAGE_COMPONENT_ROLE_xxx + + STORAGE_COMPONENT_HEALTH_STATUS HealthStatus; + STORAGE_PROTOCOL_TYPE CommandProtocol; + STORAGE_SPEC_VERSION SpecVersion; // Supported storage spec version. For example: SBC 3, SATA 3.2, NVMe 1.2 + STORAGE_DEVICE_FORM_FACTOR FormFactor; + + UCHAR Vendor[8]; + UCHAR Model[40]; + UCHAR FirmwareRevision[16]; + + ULONGLONG Capacity; // in unit of Kilo-Bytes (1024 bytes). + + UCHAR PhysicalLocation[32]; // Reserved for future. + + ULONG Reserved[2]; + +} STORAGE_PHYSICAL_DEVICE_DATA, *PSTORAGE_PHYSICAL_DEVICE_DATA; + + +typedef struct _STORAGE_PHYSICAL_ADAPTER_DATA { + + ULONG AdapterId; + STORAGE_COMPONENT_HEALTH_STATUS HealthStatus; + STORAGE_PROTOCOL_TYPE CommandProtocol; + STORAGE_SPEC_VERSION SpecVersion; // Supported storage spec version. For example: AHCI 1.3.1 + + UCHAR Vendor[8]; + UCHAR Model[40]; + UCHAR FirmwareRevision[16]; + + UCHAR PhysicalLocation[32]; // Reserve for future. + + BOOLEAN ExpanderConnected; + UCHAR Reserved0[3]; + ULONG Reserved1[3]; + +} STORAGE_PHYSICAL_ADAPTER_DATA, *PSTORAGE_PHYSICAL_ADAPTER_DATA; + + +typedef struct _STORAGE_PHYSICAL_NODE_DATA { + + ULONG NodeId; + + ULONG AdapterCount; // 0 or 1 + ULONG AdapterDataLength; + ULONG AdapterDataOffset; // Offset from beginning of this data structure. The buffer contains an array of STORAGE_PHYSICAL_ADAPTER_DATA. + + ULONG DeviceCount; // >= 1 + ULONG DeviceDataLength; + ULONG DeviceDataOffset; // Offset from beginning of this data structure. The buffer contains an array of STORAGE_PHYSICAL_DEVICE_DATA. + + ULONG Reserved[3]; + +} STORAGE_PHYSICAL_NODE_DATA, *PSTORAGE_PHYSICAL_NODE_DATA; + + +typedef struct _STORAGE_PHYSICAL_TOPOLOGY_DESCRIPTOR { + + ULONG Version; // sizeof(STORAGE_PHYSICAL_TOPOLOGY_DESCRIPTOR) + ULONG Size; // Total size of the data. Should be >= sizeof(STORAGE_PHYSICAL_TOPOLOGY_DESCRIPTOR) + + ULONG NodeCount; + ULONG Reserved; + + STORAGE_PHYSICAL_NODE_DATA Node[ANYSIZE_ARRAY]; + +} STORAGE_PHYSICAL_TOPOLOGY_DESCRIPTOR, *PSTORAGE_PHYSICAL_TOPOLOGY_DESCRIPTOR; + + +// +// Output buffer for StorageDeviceIoCapabilityProperty & PropertyStandardQuery +// + +typedef _Struct_size_bytes_(Size) struct _STORAGE_DEVICE_IO_CAPABILITY_DESCRIPTOR { + + // + // Size of this structure serves + // as the version + // + + ULONG Version; + + // + // Size of this structure + // + + ULONG Size; + + // + // LUN max outstanding IO count + // + + ULONG LunMaxIoCount; + + // + // Adapter max outstanding IO count + // + + ULONG AdapterMaxIoCount; + +} STORAGE_DEVICE_IO_CAPABILITY_DESCRIPTOR, *PSTORAGE_DEVICE_IO_CAPABILITY_DESCRIPTOR; + +// +// Output buffer for StorageDeviceAttributesProperty & PropertyStandardQuery +// + +typedef _Struct_size_bytes_(Size) struct _STORAGE_DEVICE_ATTRIBUTES_DESCRIPTOR { + + // + // Size of this structure serves + // as the version + // + + ULONG Version; + + // + // Size of this structure + // + + ULONG Size; + + // + // Attributes (bit flags) + // + + ULONG64 Attributes; + +} STORAGE_DEVICE_ATTRIBUTES_DESCRIPTOR, *PSTORAGE_DEVICE_ATTRIBUTES_DESCRIPTOR; + +// +// Storage Device Attributes Flags +// + +#define STORAGE_ATTRIBUTE_BYTE_ADDRESSABLE_IO 0x01 +#define STORAGE_ATTRIBUTE_BLOCK_IO 0x02 +#define STORAGE_ATTRIBUTE_DYNAMIC_PERSISTENCE 0x04 +#define STORAGE_ATTRIBUTE_VOLATILE 0x08 +#define STORAGE_ATTRIBUTE_ASYNC_EVENT_NOTIFICATION 0x10 +#define STORAGE_ATTRIBUTE_PERF_SIZE_INDEPENDENT 0x20 + +// +// Constants for StorageDeviceManagementStatus +// + +typedef enum _STORAGE_DISK_HEALTH_STATUS { + DiskHealthUnknown = 0, + DiskHealthUnhealthy, + DiskHealthWarning, + DiskHealthHealthy, + DiskHealthMax +} STORAGE_DISK_HEALTH_STATUS, *PSTORAGE_DISK_HEALTH_STATUS; + +// +// Operational States +// +typedef enum _STORAGE_DISK_OPERATIONAL_STATUS { + DiskOpStatusNone = 0, + DiskOpStatusUnknown, + DiskOpStatusOk, + DiskOpStatusPredictingFailure, + DiskOpStatusInService, + DiskOpStatusHardwareError, + DiskOpStatusNotUsable, + DiskOpStatusTransientError, + DiskOpStatusMissing, +} STORAGE_DISK_OPERATIONAL_STATUS, *PSTORAGE_DISK_OPERATIONAL_STATUS; + +// +// Operational Reasons +// +typedef enum _STORAGE_OPERATIONAL_STATUS_REASON { + DiskOpReasonUnknown = 0, + DiskOpReasonScsiSenseCode, + DiskOpReasonMedia, + DiskOpReasonIo, + DiskOpReasonThresholdExceeded, + DiskOpReasonLostData, + DiskOpReasonEnergySource, + DiskOpReasonConfiguration, + DiskOpReasonDeviceController, + DiskOpReasonMediaController, + DiskOpReasonComponent, + DiskOpReasonNVDIMM_N, + DiskOpReasonBackgroundOperation, + DiskOpReasonInvalidFirmware, + DiskOpReasonHealthCheck, + DiskOpReasonLostDataPersistence, + DiskOpReasonDisabledByPlatform, + DiskOpReasonLostWritePersistence, + DiskOpReasonDataPersistenceLossImminent, + DiskOpReasonWritePersistenceLossImminent, + DiskOpReasonMax +} STORAGE_OPERATIONAL_STATUS_REASON, *PSTORAGE_OPERATIONAL_STATUS_REASON; + +typedef struct _STORAGE_OPERATIONAL_REASON { + ULONG Version; + ULONG Size; + STORAGE_OPERATIONAL_STATUS_REASON Reason; + + union { + + // + // This is the format if Reason == DiskOpReasonScsiSenseCode. + // + struct { + UCHAR SenseKey; + UCHAR ASC; + UCHAR ASCQ; + UCHAR Reserved; + } ScsiSenseKey; + + // + // This is the format if Reason == DiskOpReasonNVDIMM_N. + // + struct { + UCHAR CriticalHealth; + UCHAR ModuleHealth[2]; + UCHAR ErrorThresholdStatus; + } NVDIMM_N; + + ULONG AsUlong; + } RawBytes; +} STORAGE_OPERATIONAL_REASON, *PSTORAGE_OPERATIONAL_REASON; + +// +// Output buffer for StorageDeviceManagementStatus & PropertyStandardQuery +// + +#define STORAGE_DEVICE_MAX_OPERATIONAL_STATUS 16 + +typedef struct _STORAGE_DEVICE_MANAGEMENT_STATUS { + + // + // Sizeof() of this structure serves + // as the version. + // + + ULONG Version; + + // + // The total size of the structure, including operational status reasons + // that didn't fit in the caller's array. Callers should use this field to learn + // how big the input buffer should be to contain all the available information. + // + + ULONG Size; + + // + // Health status. + // + + STORAGE_DISK_HEALTH_STATUS Health; + + // + // The number of operational status returned. + // + + ULONG NumberOfOperationalStatus; + + // + // The number of additional reasons returned. + // + + ULONG NumberOfAdditionalReasons; + + // + // Operational statuses. The primary operational status is the first element + // in the array. There are NumberOfOperationalStatus valid elements in the array. + // + + STORAGE_DISK_OPERATIONAL_STATUS OperationalStatus[STORAGE_DEVICE_MAX_OPERATIONAL_STATUS]; + + // + // Additional reasons. There are NumberOfAdditionalReasons valid elements in the array. + // + + STORAGE_OPERATIONAL_REASON AdditionalReasons[ANYSIZE_ARRAY]; + +} STORAGE_DEVICE_MANAGEMENT_STATUS, *PSTORAGE_DEVICE_MANAGEMENT_STATUS; + +// +// Parameter for StorageAdapterSerialNumberProperty. +// +// Use this to get the serial number of the storage adapter. Note that not all +// controllers and host controller interfaces may provide a serial number for +// the adapter. If the serial number is malformed or cannot be obtained this +// query will fail. +// +// The serial number can have a maximum of 128 Unicode characters, including +// the trailing NULL character. +// + +#define STORAGE_ADAPTER_SERIAL_NUMBER_V1_MAX_LENGTH (128) + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_ADAPTER_SERIAL_NUMBER { + + __WRAPPED__ + ULONG Version; + + __WRAPPED__ + ULONG Size; + + // + // NULL-terminated Unicode string of the adapter's serial number. + // + + __WRAPPED__ + WCHAR SerialNumber[STORAGE_ADAPTER_SERIAL_NUMBER_V1_MAX_LENGTH]; + +} STORAGE_ADAPTER_SERIAL_NUMBER, *PSTORAGE_ADAPTER_SERIAL_NUMBER; + +#define STORAGE_ADAPTER_SERIAL_NUMBER_V1_VERSION (sizeof(STORAGE_ADAPTER_SERIAL_NUMBER)) +#define STORAGE_ADAPTER_SERIAL_NUMBER_V1_SIZE (sizeof(STORAGE_ADAPTER_SERIAL_NUMBER)) + +// +// Output buffer for StorageDeviceZonedDeviceProperty & PropertyStandardQuery +// + +typedef enum __WRAPPED__ _STORAGE_ZONED_DEVICE_TYPES { + ZonedDeviceTypeUnknown = 0, + ZonedDeviceTypeHostManaged, + ZonedDeviceTypeHostAware, + ZonedDeviceTypeDeviceManaged, +} STORAGE_ZONED_DEVICE_TYPES, *PSTORAGE_ZONED_DEVICE_TYPES; + +typedef enum __WRAPPED__ _STORAGE_ZONE_TYPES { + ZoneTypeUnknown = 0, + ZoneTypeConventional = 1, + ZoneTypeSequentialWriteRequired = 2, + ZoneTypeSequentialWritePreferred = 3, + ZoneTypeMax +} STORAGE_ZONE_TYPES, *PSTORAGE_ZONE_TYPES; + +typedef struct __WRAPPED__ _STORAGE_ZONE_GROUP { + + __WRAPPED__ + ULONG ZoneCount; // Count of zones in this group. + + __WRAPPED__ + STORAGE_ZONE_TYPES ZoneType; + + __WRAPPED__ + ULONGLONG ZoneSize; // In Bytes + +} STORAGE_ZONE_GROUP, *PSTORAGE_ZONE_GROUP; + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_ZONED_DEVICE_DESCRIPTOR { + + // + // Size of this structure serves as the version + // + + __WRAPPED__ + ULONG Version; + + // + // Size of buffer. The returned value indicates how big the buffer should be + // to store complete data. + // + + __WRAPPED__ + ULONG Size; + + // + // Zoned device type + // + + __WRAPPED__ + STORAGE_ZONED_DEVICE_TYPES DeviceType; + + // + // Total zone count + // + + __WRAPPED__ + ULONG ZoneCount; + + // + // Zone Attributes + // + + union { + struct { + + ULONG MaxOpenZoneCount; + + BOOLEAN UnrestrictedRead; + + UCHAR Reserved[3]; + + } SequentialRequiredZone; // Host managed device only + + struct { + + ULONG OptimalOpenZoneCount; + + ULONG Reserved; + + } SequentialPreferredZone; // Host aware device only + + } ZoneAttributes; + + // + // Zone Layout Information, to provide a picture about locations of different type of zones on disk. + // The zone layout starts from the first zone, and groups together zones with same type and size. + // + + __WRAPPED__ + ULONG ZoneGroupCount; + + __WRAPPED__ + STORAGE_ZONE_GROUP ZoneGroup[ANYSIZE_ARRAY]; + +} STORAGE_ZONED_DEVICE_DESCRIPTOR, *PSTORAGE_ZONED_DEVICE_DESCRIPTOR; + + +// +// Output buffer for StorageDeviceLocationProperty & PropertyStandardQuery +// + +#pragma warning(push) +#pragma warning(disable:4201) // nameless struct/unions +typedef struct __WRAPPED__ _DEVICE_LOCATION { + + __WRAPPED__ + ULONG Socket; + + __WRAPPED__ + ULONG Slot; + + __WRAPPED__ + ULONG Adapter; + + __WRAPPED__ + ULONG Port; + + union { + + struct { + + ULONG Channel; + + ULONG Device; + + } DUMMYSTRUCTNAME; + + struct { + + ULONG Target; + + ULONG Lun; + + } DUMMYSTRUCTNAME2; + + } DUMMYUNIONNAME; + +} DEVICE_LOCATION, *PDEVICE_LOCATION; +#pragma warning(pop) + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_DEVICE_LOCATION_DESCRIPTOR { + + __WRAPPED__ + ULONG Version; + + __WRAPPED__ + ULONG Size; + + __WRAPPED__ + DEVICE_LOCATION Location; + + __WRAPPED__ + ULONG StringOffset; + +} STORAGE_DEVICE_LOCATION_DESCRIPTOR, *PSTORAGE_DEVICE_LOCATION_DESCRIPTOR; + +// +// Output buffer for StorageDeviceNumaProperty. +// +// If the query for this property is successful, then the caller should +// validate the NumaNode field before using it to optimize any operations. +// That is, the caller should ensure the NumaNode value is less than or equal +// to the system's highest NUMA node value and the NumaNode value is not equal +// to STORAGE_DEVICE_NUMA_NODE_UNKNOWN. +// +typedef struct _STORAGE_DEVICE_NUMA_PROPERTY { + ULONG Version; + ULONG Size; + ULONG NumaNode; +} STORAGE_DEVICE_NUMA_PROPERTY, *PSTORAGE_DEVICE_NUMA_PROPERTY; + +#define STORAGE_DEVICE_NUMA_NODE_UNKNOWN MAXULONG + +// +// Output buffer for StorageDeviceUnsafeShutdownCount. +// +// On persistent memory devices, the unsafe shutdown count is the number of times +// the logical persistent memory disk was shut down in a way that might have caused +// data loss. +// +typedef struct _STORAGE_DEVICE_UNSAFE_SHUTDOWN_COUNT { + ULONG Version; + ULONG Size; + ULONG UnsafeShutdownCount; +} STORAGE_DEVICE_UNSAFE_SHUTDOWN_COUNT, *PSTORAGE_DEVICE_UNSAFE_SHUTDOWN_COUNT; + +// +// IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES +// +// Input Buffer: +// Structure of type DEVICE_MANAGE_DATA_SET_ATTRIBUTES +// +// Output Buffer: +// If a particular action uses an output buffer, it will be a structure +// of type DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT optionally followed +// by a structure specific to that action. +// +// Actions that use an output buffer are listed below, along with their +// corresponding structure: +// +// - DeviceDsmAction_OffloadRead: STORAGE_OFFLOAD_READ_OUTPUT +// - DeviceDsmAction_OffloadWrite: STORAGE_OFFLOAD_WRITE_OUTPUT +// - DeviceDsmAction_Allocation: DEVICE_DATA_SET_LB_PROVISIONING_STATE +// - DeviceDsmAction_Scrub: DEVICE_DATA_SET_SCRUB_OUTPUT +// - DeviceDsmAction_GetPhysicalAddresses: DEVICE_DSM_PHYSICAL_ADDRESSES_OUTPUT +// - DeviceDsmAction_ReportZones: STORAGE_DEVICE_ZONE_INFORMATION +// - DeviceDsmAction_GetRangeErrorInfo: DEVICE_DSM_RANGE_ERROR_INFO +// + +// +// This flag, when OR'd into an action indicates that the given action is +// non-destructive. If this flag is set then storage stack components which +// do not understand the action should forward the given request +// + +#define DeviceDsmActionFlag_NonDestructive 0x80000000 + +#define IsDsmActionNonDestructive(_Action) ((BOOLEAN)((_Action & DeviceDsmActionFlag_NonDestructive) != 0)) + +// +// Defines the various actions +// + +typedef ULONG DEVICE_DATA_MANAGEMENT_SET_ACTION; + + #define DeviceDsmAction_None 0 + #define DeviceDsmAction_Trim 1 + #define DeviceDsmAction_Notification ( 2 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_OffloadRead ( 3 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_OffloadWrite 4 + #define DeviceDsmAction_Allocation ( 5 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_Repair ( 6 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_Scrub ( 7 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_DrtQuery ( 8 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_DrtClear ( 9 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_DrtDisable (10 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_TieringQuery (11 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_Map (12 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_RegenerateParity (13 | DeviceDsmActionFlag_NonDestructive) + + #define DeviceDsmAction_NvCache_Change_Priority (14 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_NvCache_Evict (15 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_TopologyIdQuery (16 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_GetPhysicalAddresses (17 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_ScopeRegen (18 | DeviceDsmActionFlag_NonDestructive) + + #define DeviceDsmAction_ReportZones (19 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_OpenZone (20 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_FinishZone (21 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_CloseZone (22 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_ResetWritePointer (23) + + #define DeviceDsmAction_GetRangeErrorInfo (24 | DeviceDsmActionFlag_NonDestructive) + #define DeviceDsmAction_WriteZeroes (25) + +// +// Flags that are global across all actions +// These are in the low 16bits of the flags fields +// + +#define DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE 0x00000001 // If set, the DataSetRanges fields should be 0 + + +// +// Flags that are specific to a given verb. +// These are in the high 16bits of the flags field +// + +// +// DeviceDsmAction_Trim specific flags +// + +#define DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED 0x80000000 // If SET, the described ranges are not allocated by a file system + +// +// DeviceDsmAction_Allocation specific flags +// + +// +// If set, the device should only return slabs that are eligible for consolidation. +// +#define DEVICE_DSM_FLAG_ALLOCATION_CONSOLIDATEABLE_ONLY 0x40000000 + +// +// DeviceDsmAction_Scrub specific flags +// + +#define DEVICE_DSM_FLAG_SCRUB_SKIP_IN_SYNC 0x10000000 +#define DEVICE_DSM_FLAG_SCRUB_OUTPUT_PARITY_EXTENT 0x20000000 + +// +// DeviceDsmAction_Repair specific flags +// + +#define DEVICE_DSM_FLAG_REPAIR_OUTPUT_PARITY_EXTENT 0x20000000 + +// +// If set, 128-bit Topology ID is present in the next 8-byte aligned offset +// after RepairCopies field of DEVICE_DATA_SET_REPAIR_PARAMETERS +// + +#define DEVICE_DSM_FLAG_REPAIR_INPUT_TOPOLOGY_ID_PRESENT 0x40000000 + + +// +// DeviceDsmAction_GetPhysicalAddresses specific flags +// + +// +// If set, the device will always return 0 in the TotalNumberOfRanges field. +// A caller that doesn't need to know the total number of ranges should set +// this flag as a performance optimization, because the device might +// incur some cost calculating the total number of ranges. +// +#define DEVICE_DSM_FLAG_PHYSICAL_ADDRESSES_OMIT_TOTAL_RANGES 0x10000000 + +// +// Structure used to describe the list of ranges to process +// + +typedef struct _DEVICE_DATA_SET_RANGE { + LONGLONG StartingOffset; //in bytes, must allign to sector + ULONGLONG LengthInBytes; // multiple of sector size. +} DEVICE_DATA_SET_RANGE, *PDEVICE_DATA_SET_RANGE; + +// +// input structure for IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES +// 1. Value ofParameterBlockOffset or ParameterBlockLength is 0 indicates that Parameter Block does not exist. +// 2. Value of DataSetRangesOffset or DataSetRangesLength is 0 indicates that DataSetRanges Block does not exist. +// If DataSetRanges Block exists, it contains contiguous DEVICE_DATA_SET_RANGE structures. +// 3. The total size of buffer should be at least: +// sizeof (DEVICE_MANAGE_DATA_SET_ATTRIBUTES) + ParameterBlockLength + DataSetRangesLength +// +typedef struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES { + ULONG Size; // Size of structure DEVICE_MANAGE_DATA_SET_ATTRIBUTES + DEVICE_DATA_MANAGEMENT_SET_ACTION Action; + + ULONG Flags; // Global flags across all actions + + ULONG ParameterBlockOffset; // must be alligned to corresponding structure allignment + ULONG ParameterBlockLength; // 0 means Parameter Block does not exist. + + ULONG DataSetRangesOffset; // must be alligned to DEVICE_DATA_SET_RANGE structure allignment. + ULONG DataSetRangesLength; // 0 means DataSetRanges Block does not exist. + +} DEVICE_MANAGE_DATA_SET_ATTRIBUTES, *PDEVICE_MANAGE_DATA_SET_ATTRIBUTES; + +// +// This defines the parameter block for the DeviceDsmAction_Notification +// action +// + +typedef struct _DEVICE_DSM_NOTIFICATION_PARAMETERS { + + ULONG Size; // Size of this structure + + ULONG Flags; // Flags specific to the notify operation + + ULONG NumFileTypeIDs; // Count of how many file type ID's are given + + GUID FileTypeID[1]; // Identifier for the type of file being notified + +} DEVICE_DSM_NOTIFICATION_PARAMETERS, *PDEVICE_DSM_NOTIFICATION_PARAMETERS; + +// +// DEVICE_DSM_NOTIFICATION_PARAMETERS flag definitions +// + +#define DEVICE_DSM_NOTIFY_FLAG_BEGIN 0x00000001 // The given LBA range is being used as defined by the FileID +#define DEVICE_DSM_NOTIFY_FLAG_END 0x00000002 // The given LBA range is no longer being used as defined by the FileID + +// +// Parameter Block for the DeviceDsmAction_NvCache_Change_Priority action. +// +typedef struct _DEVICE_DSM_NVCACHE_CHANGE_PRIORITY_PARAMETERS { + ULONG Size; // Size of this structure + + UCHAR TargetPriority; // Target priority + + UCHAR Reserved[3]; +} DEVICE_DSM_NVCACHE_CHANGE_PRIORITY_PARAMETERS, *PDEVICE_DSM_NVCACHE_CHANGE_PRIORITY_PARAMETERS; + + +// +// Parameter structure definitions for copy offload actions +// + +// +// Offload copy interface operates in 2 steps : offload read and offload write. +// +// Input for OffloadRead action is set of extends in DSM structure +// Output parameter of an OffloadRead is a token, returned by the target which will uniquely identify a "point in time" snapshot of extends taken by the target. +// Format of the token is opaque to Windows and is specific to the target. +// +// Note: we arbitrarily limit token length to 512. SCSI interface to OffloadCopy will (may) enable negotiable size. If/when we want to have variable size +// tokens we will need to create a new action +// +#define STORAGE_OFFLOAD_MAX_TOKEN_LENGTH 512 // Keep as ULONG multiple +#define STORAGE_OFFLOAD_TOKEN_ID_LENGTH 0x1F8 +#define STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA 0xFFFF0001 + +#pragma warning(push) +#pragma warning(disable:4201) // nameless struct/unions +typedef struct _STORAGE_OFFLOAD_TOKEN { + UCHAR TokenType[4]; + UCHAR Reserved[2]; + UCHAR TokenIdLength[2]; + union { + struct { + UCHAR Reserved2[STORAGE_OFFLOAD_TOKEN_ID_LENGTH]; + } StorageOffloadZeroDataToken; + UCHAR Token[STORAGE_OFFLOAD_TOKEN_ID_LENGTH]; + } DUMMYUNIONNAME; +} STORAGE_OFFLOAD_TOKEN, *PSTORAGE_OFFLOAD_TOKEN; +#pragma warning(pop) + +#define MAKE_ZERO_TOKEN(T) ( \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenType[0] = 0xFF, \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenType[1] = 0xFF, \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenType[2] = 0x00, \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenType[3] = 0x01, \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenIdLength[0] = 0x01, \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenIdLength[1] = 0xF8 \ +) + +#define IS_ZERO_TOKEN(T) ( \ + (((PSTORAGE_OFFLOAD_TOKEN)T)->TokenType[0] == 0xFF && \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenType[1] == 0xFF && \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenType[2] == 0x00 && \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenType[3] == 0x01 && \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenIdLength[0] == 0x01 && \ + ((PSTORAGE_OFFLOAD_TOKEN)T)->TokenIdLength[1] == 0xF8) \ +) + +typedef struct _DEVICE_DSM_OFFLOAD_READ_PARAMETERS { + ULONG Flags; // no flags defined yet + ULONG TimeToLive; // token TTL in milli-seconds as requested by initiator (TODO: Do we need it exposed to interface caller?) + ULONG Reserved[2]; // reserved for future use +} DEVICE_DSM_OFFLOAD_READ_PARAMETERS, *PDEVICE_DSM_OFFLOAD_READ_PARAMETERS; + +typedef struct _DEVICE_DSM_OFFLOAD_WRITE_PARAMETERS { + ULONG Flags; // no flags defined yet + ULONG Reserved; // reserved for future usage + ULONGLONG TokenOffset; // The starting offset to copy from "snapshot" bound to the token + STORAGE_OFFLOAD_TOKEN Token; // the token +} DEVICE_DSM_OFFLOAD_WRITE_PARAMETERS, *PDEVICE_DSM_OFFLOAD_WRITE_PARAMETERS; + +// +// DSM parameters block structure for DeviceDsmAction_Repair +// + +#define GET_REPAIR_TOPOLOGY_ID(R) \ + RtlOffsetToPointer( R, \ + ALIGN_UP_BY( FIELD_OFFSET( DEVICE_DATA_SET_REPAIR_PARAMETERS, RepairCopies ) + \ + sizeof( ULONG ) * R->NumberOfRepairCopies, \ + 8 ) ) + +typedef struct _DEVICE_DATA_SET_REPAIR_PARAMETERS { + + ULONG NumberOfRepairCopies; // The number of copies that will be repaired. + ULONG SourceCopy; // The copy number of the source copy. + ULONG RepairCopies[ANYSIZE_ARRAY]; // The copy numbers of all the copies that will be repaired. + + // UCHAR TopologyId[16]; // 128-bit topology ID when DEVICE_DSM_FLAG_REPAIR_INPUT_TOPOLOGY_ID_PRESENT + // in 8-byte aligned offset from the start of the DEVICE_DSM_FLAG_REPAIR_INPUT_TOPOLOGY_ID_PRESENT structure + +} DEVICE_DATA_SET_REPAIR_PARAMETERS, *PDEVICE_DATA_SET_REPAIR_PARAMETERS; + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) + +// +// Parameters block for DeviceDsmAction_Allocation +// +typedef struct _DEVICE_DATA_SET_LBP_STATE_PARAMETERS { + ULONG Version; // Version of this structure. + ULONG Size; // Size of this structure. + ULONG Flags; // No flags defined yet. + + // + // Version of DEVICE_DATA_SET_LB_PROVISIONING_STATE to return, one of: + // - DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V1 + // - DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V2 + // + ULONG OutputVersion; +} DEVICE_DATA_SET_LBP_STATE_PARAMETERS, *PDEVICE_DATA_SET_LBP_STATE_PARAMETERS; + +#define DEVICE_DATA_SET_LBP_STATE_PARAMETERS_VERSION_V1 1 + +#endif + +// +// DSM output structure for bi-directional actions. +// +// Output parameter block is located in resultant buffer at the offset contained in OutputBlockOffset field. Offset is calculated from the beginning of the buffer, +// and callee will align it according to the requirement of the action specific structure template. +// Thus future extended bi-directional actions won't require revision of ntddstor.h +// +// Example: for OffloadRead action in order to get a pointer to the output structure caller shall do +// +// PSTORAGE_OFFLOAD_READ_OUTPUT pReadOut = (PSTORAGE_OFFLOAD_READ_OUTPUT) ((UCHAR *)pOutputBuffer + ((PDEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT)pOutputBuffer)->OutputBlockOffset) +// + +typedef struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT { + + ULONG Size; // Size of the structure + + DEVICE_DATA_MANAGEMENT_SET_ACTION Action; // Action requested and performed + + ULONG Flags; // Common output flags for DSM actions + ULONG OperationStatus; // Operation status , used for offload actions (placeholder for richer semantic, like PENDING) + ULONG ExtendedError; // Extended error information (Windows or driver extended error) + ULONG TargetDetailedError; // Target specific error , used for offload actions (SCSI sense code) + ULONG ReservedStatus; // Reserved field + + ULONG OutputBlockOffset; // Action specific must be alligned to corresponding structure allignment. + ULONG OutputBlockLength; // 0 means Output Parameter Block does not exist. + +} DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT, *PDEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT; + +// +// DSM output structure for DeviceDsmAction_Allocation +// + +typedef struct _DEVICE_DATA_SET_LB_PROVISIONING_STATE { + + ULONG Size; // The size of this structure, including the bitmap, in bytes. + ULONG Version; // The version of this structure. + ULONGLONG SlabSizeInBytes; // The byte size of a slab + ULONG SlabOffsetDeltaInBytes; // The delta from the given offset in bytes. + ULONG SlabAllocationBitMapBitCount; // The number of relevant bits in the bitmap. + ULONG SlabAllocationBitMapLength; // The number of ULONGS in the bitmap array. + ULONG SlabAllocationBitMap[ANYSIZE_ARRAY]; // Slab allocation bitmap, 1 = mapped, 0 = unmapped. + +} DEVICE_DATA_SET_LB_PROVISIONING_STATE, *PDEVICE_DATA_SET_LB_PROVISIONING_STATE; + +#define DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V1 (sizeof(DEVICE_DATA_SET_LB_PROVISIONING_STATE)) + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) + +typedef struct _DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2 { + + ULONG Size; // The size of this structure, including the bitmap, in bytes. + ULONG Version; // The version of this structure. + ULONGLONG SlabSizeInBytes; // The byte size of a slab + ULONGLONG SlabOffsetDeltaInBytes; // The delta from the given offset in bytes. + ULONG SlabAllocationBitMapBitCount; // The number of relevant bits in the bitmap. + ULONG SlabAllocationBitMapLength; // The number of ULONGS in the bitmap array. + ULONG SlabAllocationBitMap[ANYSIZE_ARRAY]; // Slab allocation bitmap, 1 = mapped, 0 = unmapped. + +} DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2, *PDEVICE_DATA_SET_LB_PROVISIONING_STATE_V2; + +#define DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V2 (sizeof(DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2)) + +#endif + +typedef struct _STORAGE_OFFLOAD_READ_OUTPUT { + + ULONG OffloadReadFlags; // Outbound flags + ULONG Reserved; + ULONGLONG LengthProtected; // The length of the snapshot by token. Must be from the lowest StartingOffset + ULONG TokenLength; // Length of the token in bytes. + STORAGE_OFFLOAD_TOKEN Token; // The token created on success. + +} STORAGE_OFFLOAD_READ_OUTPUT, *PSTORAGE_OFFLOAD_READ_OUTPUT; + +// +// STORAGE_OFFLOAD_READ_OUTPUT flag definitions +// + +#define STORAGE_OFFLOAD_READ_RANGE_TRUNCATED (0x0001) + +typedef struct _STORAGE_OFFLOAD_WRITE_OUTPUT { + + ULONG OffloadWriteFlags; // Out flags + ULONG Reserved; // reserved for future usage + ULONGLONG LengthCopied; // Out parameter : The length of content copied from the "snapshot" from the start + +} STORAGE_OFFLOAD_WRITE_OUTPUT, *PSTORAGE_OFFLOAD_WRITE_OUTPUT; + +// +// STORAGE_OFFLOAD_WRITE_OUTPUT flag definitions - used in OffloadWriteFlags mask +// + +#define STORAGE_OFFLOAD_WRITE_RANGE_TRUNCATED (0x0001) // Write performed, but on a truncated range +#define STORAGE_OFFLOAD_TOKEN_INVALID (0x0002) // Token specified in offload write operation is invalid. + +// +// DSM output structure for DeviceDsmAction_Scrub +// + +typedef struct _DEVICE_DATA_SET_SCRUB_OUTPUT { + + ULONGLONG BytesProcessed; // Number of bytes that were actually processed + ULONGLONG BytesRepaired; // Number of bytes that were out of sync and fixed + ULONGLONG BytesFailed; // Number of bytes that could not be read or fixed + +} DEVICE_DATA_SET_SCRUB_OUTPUT, *PDEVICE_DATA_SET_SCRUB_OUTPUT; + +// +// DSM output structure for DeviceDsmAction_Scrub +// +// ParityExtent is valid only if DEVICE_DSM_FLAG_SCRUB_OUTPUT_PARITY_EXTENT is set +// in DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT Flags +// + +typedef struct _DEVICE_DATA_SET_SCRUB_EX_OUTPUT { + + ULONGLONG BytesProcessed; // Number of bytes that were actually processed + ULONGLONG BytesRepaired; // Number of bytes that were out of sync and fixed + ULONGLONG BytesFailed; // Number of bytes that could not be read or fixed + + DEVICE_DATA_SET_RANGE ParityExtent; // Parity extent for stripe regeneration + +} DEVICE_DATA_SET_SCRUB_EX_OUTPUT, *PDEVICE_DATA_SET_SCRUB_EX_OUTPUT; + +// +// DSM output structure for DeviceDsmAction_Repair +// +// ParityExtent is valid only if DEVICE_DSM_FLAG_REPAIR_OUTPUT_PARITY_EXTENT is set +// in DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT Flags +// + +typedef struct _DEVICE_DATA_SET_REPAIR_OUTPUT { + + DEVICE_DATA_SET_RANGE ParityExtent; // Parity extent for stripe regeneration + +} DEVICE_DATA_SET_REPAIR_OUTPUT, *PDEVICE_DATA_SET_REPAIR_OUTPUT; + +// +// DSM input structure for DeviceDsmAction_TieringQuery. +// +// This IOCTL returns the storage tier regions from the storage +// stack for a particular LUN or volume. +// + +typedef struct _DEVICE_DSM_TIERING_QUERY_INPUT { + + ULONG Version; // The version of this structure. + ULONG Size; // The size of this structure in bytes. + + ULONG Flags; // Reserved for future use. + + ULONG NumberOfTierIds; // Number of entries in TierIds, 0 for all for volume + GUID TierIds[ANYSIZE_ARRAY]; // Storage tiers to return information for + +} DEVICE_DSM_TIERING_QUERY_INPUT, *PDEVICE_DSM_TIERING_QUERY_INPUT; + +// +// DSM output structures for DeviceDsmAction_TieringQuery. +// + +typedef struct _STORAGE_TIER_REGION { + + GUID TierId; // Tier ID + + ULONGLONG Offset; // offset of region in bytes + ULONGLONG Length; // length of region in bytes + +} STORAGE_TIER_REGION, *PSTORAGE_TIER_REGION; + +// +// The DeviceDsmAction_TieringQuery DSM response returns a single one of these that include +// multiple STORAGE_TIER_REGION records, one for each region. +// + +typedef struct _DEVICE_DSM_TIERING_QUERY_OUTPUT { + + ULONG Version; // The version of this structure. + ULONG Size; // The size of this structure in bytes. + + ULONG Flags; // Reserved for future use. + ULONG Reserved; // Reserved for future use. + + ULONGLONG Alignment; // in bytes, must align to slab boundary. + + ULONG TotalNumberOfRegions; // Total number of available regions. + ULONG NumberOfRegionsReturned; // Number of regions that fit in the output. + + _Field_size_(NumberOfRegionsReturned) STORAGE_TIER_REGION Regions[ANYSIZE_ARRAY]; // Detailed info on the regions. + +} DEVICE_DSM_TIERING_QUERY_OUTPUT, *PDEVICE_DSM_TIERING_QUERY_OUTPUT; + +typedef struct _DEVICE_DATA_SET_TOPOLOGY_ID_QUERY_OUTPUT { + + // + // Number of bytes that TopologyId describes from the start of an input range + // + + ULONGLONG TopologyRangeBytes; + + // + // First topology ID described by the TopologyRangeBytes + // + + UCHAR TopologyId[16]; + +} DEVICE_DATA_SET_TOPOLOGY_ID_QUERY_OUTPUT, *PDEVICE_DATA_SET_TOPOLOGY_ID_QUERY_OUTPUT; + + +// +// DSM output structure for DeviceDsmAction_GetPhysicalAddresses +// + +// +// Structure used to describe a range corresponding to a Byte Addressable +// Storage device. +// + +typedef struct _DEVICE_STORAGE_ADDRESS_RANGE { + LONGLONG StartAddress; // Starting system physical address + ULONGLONG LengthInBytes; // Size of the range +} DEVICE_STORAGE_ADDRESS_RANGE, *PDEVICE_STORAGE_ADDRESS_RANGE; + +#define DEVICE_DSM_PHYSICAL_ADDRESSES_OUTPUT_VERSION_V1 1 + +typedef struct _DEVICE_DSM_PHYSICAL_ADDRESSES_OUTPUT { + + ULONG Version; // The version of this structure. + + ULONG Flags; // Additional information about the output. + + ULONG TotalNumberOfRanges; // The number of ranges that would be necessary to fulfill the request. + // By looking at this field, the caller can know how big the output + // buffer needs to be. The device always sets this field to 0 if + // the DEVICE_DSM_FLAG_PHYSICAL_ADDRESSES_OMIT_TOTAL_RANGES flag is set + // in the input buffer. + + ULONG NumberOfRangesReturned; // Number of entries in Ranges. If the buffer provided by the caller + // isn't large enough to hold all the requested ranges, the device + // returns STATUS_BUFFER_OVERFLOW in IoStatus.Status. + + DEVICE_STORAGE_ADDRESS_RANGE Ranges[ANYSIZE_ARRAY]; + +} DEVICE_DSM_PHYSICAL_ADDRESSES_OUTPUT, *PDEVICE_DSM_PHYSICAL_ADDRESSES_OUTPUT; + +// +// Parameter Block for the DeviceDsmAction_ReportZones action. +// +// Input parameter is with data structure DEVICE_MANAGE_DATA_SET_ATTRIBUTES, +// following in memory by a DEVICE_DSM_REPORT_ZONES_PARAMETERS. +// If DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE flag is not set, a single range DEVICE_DATA_SET_RANGE should also follow +// with StartingOffset aligned at the zone boundary. +// If DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE is specified, it indicates that caller wants zones information for whole disk. +// + +typedef enum _STORAGE_ZONE_CONDITION { + + ZoneConditionConventional = 0x00, + ZoneConditionEmpty = 0x01, + ZoneConditionImplicitlyOpened = 0x02, + ZoneConditionExplicitlyOpened = 0x03, + ZoneConditionClosed = 0x04, + + ZoneConditionReadOnly = 0x0D, + ZoneConditionFull = 0x0E, + ZoneConditionOffline = 0x0F, + +} STORAGE_ZONE_CONDITION, *PSTORAGE_ZONE_CONDITION; + +typedef struct _DEVICE_DSM_REPORT_ZONES_PARAMETERS { + ULONG Size; // Size of this structure + + UCHAR ReportOption; // Report Zone options + UCHAR Partial; // Partial bit effects calculation of Zone List Length + + UCHAR Reserved[2]; +} DEVICE_DSM_REPORT_ZONES_PARAMETERS, *PDEVICE_DSM_REPORT_ZONES_PARAMETERS; + +// +// Output buffer for the DeviceDsmAction_ReportZones action. +// output buffer consists of data structure DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT, +// following with DEVICE_DSM_REPORT_ZONES_DATA. +// + +typedef enum _STORAGE_ZONES_ATTRIBUTES { + + ZonesAttributeTypeAndLengthMayDifferent = 0, + ZonesAttributeTypeSameLengthSame = 1, + ZonesAttributeTypeSameLastZoneLengthDifferent = 2, + ZonesAttributeTypeMayDifferentLengthSame = 3, + +} STORAGE_ZONES_ATTRIBUTES, *PSTORAGE_ZONES_ATTRIBUTES; + +typedef struct _STORAGE_ZONE_DESCRIPTOR { + + ULONG Size; // size of this structure. + + STORAGE_ZONE_TYPES ZoneType; + STORAGE_ZONE_CONDITION ZoneCondition; + + BOOLEAN ResetWritePointerRecommend; + UCHAR Reserved0[3]; + + ULONGLONG ZoneSize; // in bytes + ULONGLONG WritePointerOffset; // write pointer offset, in bytes, from the beginning of the zone + +} STORAGE_ZONE_DESCRIPTOR, *PSTORAGE_ZONE_DESCRIPTOR; + +typedef struct _DEVICE_DSM_REPORT_ZONES_DATA { + + ULONG Size; // Size of this structure + + ULONG ZoneCount; + STORAGE_ZONES_ATTRIBUTES Attributes; + + ULONG Reserved0; + + _Field_size_(ZoneCount) STORAGE_ZONE_DESCRIPTOR ZoneDescriptors[ANYSIZE_ARRAY]; + +} DEVICE_DSM_REPORT_ZONES_DATA, *PDEVICE_DSM_REPORT_ZONES_DATA; + +// +// Parameters for DeviceDsmAction_OpenZones, DeviceDsmAction_FinishZones and DeviceDsmAction_CloseZones action. +// +// Input parameter is with data structure DEVICE_MANAGE_DATA_SET_ATTRIBUTES, following by DEVICE_DATA_SET_RANGE(s). +// DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE can be used to indicate operation applies to all applicable zones. +// Output parameter: None. +// + +// +// Parameters for DeviceDsmAction_ResetWritePointer action. +// +// Input parameter is with data structure DEVICE_MANAGE_DATA_SET_ATTRIBUTES, optionally following by DEVICE_DATA_SET_RANGE(s). +// DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE can be used to indicate reseting writer pointer for all opened/closed/full zones. +// Output parameter: None. +// + + +// +// DSM output structure for DeviceDsmAction_GetRangeErrorInfo +// +#pragma warning(push) +#pragma warning(disable:4201) // nameless struct/unions +#pragma warning(disable:4214) // bit fields other than int + +// +// This structure describes a range of a disk which can be either good or bad. Bad +// ranges should not be accessed. +// +typedef struct _DEVICE_STORAGE_RANGE_ATTRIBUTES { + ULONGLONG LengthInBytes; // Size of the range, in bytes. This is a multiple of the sector size. + + union { + ULONG AllFlags; + + struct { + ULONG IsRangeBad : 1; // If 1, the range is bad. Otherwise, the range is good. + }; + }; + + ULONG Reserved; // Reserved for future use. + +} DEVICE_STORAGE_RANGE_ATTRIBUTES, *PDEVICE_STORAGE_RANGE_ATTRIBUTES; + +#pragma warning(pop) + +#define DEVICE_DSM_RANGE_ERROR_INFO_VERSION_V1 1 + +// +// Flags for DEVICE_DSM_RANGE_ERROR_INFO. +// + +// +// When this flag is set, there are no errors in any of the input ranges. +// +#define DEVICE_STORAGE_NO_ERRORS 0x1 + +typedef struct _DEVICE_DSM_RANGE_ERROR_INFO { + + ULONG Version; // The version of this structure. + + ULONG Flags; // Additional information about the output. + + ULONG TotalNumberOfRanges; // The number of ranges that would be necessary to fulfill the request. + // By looking at this field, the caller can know how big the output + // buffer needs to be. + + ULONG NumberOfRangesReturned; // Number of entries in Ranges. If the buffer provided by the caller + // isn't large enough to hold all the requested ranges, the device + // returns STATUS_BUFFER_OVERFLOW in IoStatus.Status. + + DEVICE_STORAGE_RANGE_ATTRIBUTES Ranges[ANYSIZE_ARRAY]; // The output ranges, which inform the caller about which regions of the requested + // ranges are good or bad. The elements of this array are sorted so that their order + // corresponds to the order of the input ranges. For example, if the first input + // range was broken into 3 output ranges, those will be the first 3 ranges in the array. + // The caller can learn which output ranges correspond to an input range by keeping track + // of the length of the output ranges. + + +} DEVICE_DSM_RANGE_ERROR_INFO, *PDEVICE_DSM_RANGE_ERROR_INFO; + + +// +// There are some well known GUIDS for certain types of files. They are +// defined in NTIFS.H +// + +// +// IOCTL_STORAGE_GET_BC_PROPERTIES +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type STORAGE_GET_BC_PROPERTIES_OUTPUT +// + +typedef struct _STORAGE_GET_BC_PROPERTIES_OUTPUT { + + // + // Specifies the maximum number of requests + // that can be scheduled per period of time + // + ULONG MaximumRequestsPerPeriod; + + // + // Specifies the minimum period that the + // device uses when scheduling requests + // + ULONG MinimumPeriod; + + // + // Specifies the maximum transfer size supported + // for bandwidth contracts on this device. To + // achieve the highest level of performance, all + // requests should be of this size + // + ULONGLONG MaximumRequestSize; + + // + // Specifies the estimated time taken to + // perform an Io operstion. This field + // is for informational purposes only + // + ULONG EstimatedTimePerRequest; + + // + // Specifies the number of requests that should be + // kept outstanding. This helps keep the device + // device busy and thus obtain maximum throughput. + // This will only be filled in if the target file + // has an outstanding contract. + // + ULONG NumOutStandingRequests; + + // + // Specifies the required size of requests in this + // stream. This will only be filled in if the + // target file has an outstanding contract. + // + ULONGLONG RequestSize; + +} STORAGE_GET_BC_PROPERTIES_OUTPUT, *PSTORAGE_GET_BC_PROPERTIES_OUTPUT; + + +// +// IOCTL_STORAGE_ALLOCATE_BC_STREAM +// +// Input Buffer: +// Structure of type STORAGE_ALLOCATE_BC_STREAM_INPUT +// +// Output Buffer: +// Structure of type STORAGE_ALLOCATE_BC_STREAM_OUTPUT +// + + +// +// Current version +// +#define IOCTL_STORAGE_BC_VERSION 1 + +typedef struct _STORAGE_ALLOCATE_BC_STREAM_INPUT { + + // + // Specifies the corresponding structure version + // + ULONG Version; + + // + // Specifies the number of requests that + // need to complete per period of time + // + ULONG RequestsPerPeriod; + + // + // Specifies the period of time wherein the + // above number of requests must complete + // + ULONG Period; + + // + // Indicates whether failures + // should be retried or not + // + BOOLEAN RetryFailures; + + // + // Indicates whether reqests that will miss + // their deadline should be discarded or not + // + BOOLEAN Discardable; + + // + // Helps align the following field + // + BOOLEAN Reserved1[2]; + + // + // Indicates whether the Io will be + // comprised of reads, writes or both + // + ULONG AccessType; + + // + // Indicates whether the Io to the + // file will be sequential or random + // + ULONG AccessMode; + +} STORAGE_ALLOCATE_BC_STREAM_INPUT, *PSTORAGE_ALLOCATE_BC_STREAM_INPUT; + +typedef struct _STORAGE_ALLOCATE_BC_STREAM_OUTPUT { + + // + // Specifies the required size + // of requests in this stream + // + ULONGLONG RequestSize; + + // + // Specifies the number of requests that should be + // kept outstanding. This helps keep the device + // device busy and thus obtain maximum throughput + // + ULONG NumOutStandingRequests; + +} STORAGE_ALLOCATE_BC_STREAM_OUTPUT, *PSTORAGE_ALLOCATE_BC_STREAM_OUTPUT; + + +// +// IOCTL_STORAGE_FREE_BC_STREAM +// +// Input Buffer: +// None +// +// Output Buffer: +// None +// + +// +// IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT +// +// Input Buffer : +// None +// Output Buffer : +// Structure of type STORAGE_PRIORITY_HINT_SUPPORT +// + +#define STORAGE_PRIORITY_HINT_SUPPORTED 0x0001 + +typedef struct _STORAGE_PRIORITY_HINT_SUPPORT { + ULONG SupportFlags; +} STORAGE_PRIORITY_HINT_SUPPORT, *PSTORAGE_PRIORITY_HINT_SUPPORT; + +// +// IOCTL_STORAGE_DIAGNOSTIC +// +// Input Buffer : +// STORAGE_DIAGNOSTIC_REQUEST +// Output Buffer : +// STORAGE_DIAGNOSTIC_DATA +// + +typedef enum _STORAGE_DIAGNOSTIC_LEVEL { + StorageDiagnosticLevelDefault = 0, + StorageDiagnosticLevelMax +} STORAGE_DIAGNOSTIC_LEVEL, *PSTORAGE_DIAGNOSTIC_LEVEL; + +typedef enum _STORAGE_DIAGNOSTIC_TARGET_TYPE { + + StorageDiagnosticTargetTypeUndefined = 0, + StorageDiagnosticTargetTypePort, + StorageDiagnosticTargetTypeMiniport, + StorageDiagnosticTargetTypeHbaFirmware, + StorageDiagnosticTargetTypeMax + +} STORAGE_DIAGNOSTIC_TARGET_TYPE, *PSTORAGE_DIAGNOSTIC_TARGET_TYPE; + +// +// STORAGE_DIAGNOSTIC_REQUEST +// + +typedef struct _STORAGE_DIAGNOSTIC_REQUEST { + + // Size of this structure. + ULONG Version; + + // Whole size of the structure and the associated data buffer. + // (In case adding variable-sized buffer in future.) + ULONG Size; + + // Reserved for future use. + ULONG Reserved; + + // Request target type. See definitions for STORAGE_DIAGNOSTIC_TARGET_TYPE. + STORAGE_DIAGNOSTIC_TARGET_TYPE TargetType; + + // Diagnostic level. See definitions for STORAGE_DIAGNOSTIC_LEVEL. + STORAGE_DIAGNOSTIC_LEVEL Level; + +} STORAGE_DIAGNOSTIC_REQUEST, *PSTORAGE_DIAGNOSTIC_REQUEST; + +// +// STORAGE_DIAGNOSTIC_DATA +// + +typedef struct _STORAGE_DIAGNOSTIC_DATA { + + // Size of this structure. + ULONG Version; + + // Whole size of the structure and the associated data buffer. + ULONG Size; + + // GUID of diagnostic data provider. + GUID ProviderId; + + // If the request failed because of buffer too small, this field should be filled with the required buffer + // size for DiagnosticDataBuffer needed by provider; + // if the request is successful, it should be filled with returned buffer size of DiagnosticDataBuffer; + // it should be cleared to zero for other cases. + ULONG BufferSize; + + // Reserved for future use. + ULONG Reserved; + + // Diagnostic data buffer. + _Field_size_(BufferSize) UCHAR DiagnosticDataBuffer[ANYSIZE_ARRAY]; + +} STORAGE_DIAGNOSTIC_DATA, *PSTORAGE_DIAGNOSTIC_DATA; + +// +// IOCTL_STORAGE_GET_PHYSICAL_ELEMENT_STATUS +// +// Input: +// PHYSICAL_ELEMENT_STATUS_REQUEST +// Output: +// PHYSICAL_ELEMENT_STATUS +// + +typedef struct _PHYSICAL_ELEMENT_STATUS_REQUEST { + + ULONG Version; + ULONG Size; + + ULONG StartingElement; + UCHAR Filter; + UCHAR ReportType; + UCHAR Reserved[2]; + +} PHYSICAL_ELEMENT_STATUS_REQUEST, *PPHYSICAL_ELEMENT_STATUS_REQUEST; + +typedef struct _PHYSICAL_ELEMENT_STATUS_DESCRIPTOR { + + ULONG Version; + ULONG Size; + + ULONG ElementIdentifier; + UCHAR PhysicalElementType; + UCHAR PhysicalElementHealth; + UCHAR Reserved1[2]; + + // In unit of LBA. + ULONGLONG AssociatedCapacity; + + ULONG Reserved2[4]; + +} PHYSICAL_ELEMENT_STATUS_DESCRIPTOR, *PPHYSICAL_ELEMENT_STATUS_DESCRIPTOR; + +typedef struct _PHYSICAL_ELEMENT_STATUS { + + ULONG Version; + ULONG Size; + + ULONG DescriptorCount; + ULONG ReturnedDescriptorCount; + + ULONG ElementIdentifierBeingDepoped; + ULONG Reserved; + + PHYSICAL_ELEMENT_STATUS_DESCRIPTOR Descriptors[ANYSIZE_ARRAY]; + +} PHYSICAL_ELEMENT_STATUS, *PPHYSICAL_ELEMENT_STATUS; + +// +// IOCTL_STORAGE_REMOVE_ELEMENT_AND_TRUNCATE +// +// Input: +// REMOVE_ELEMENT_AND_TRUNCATE_REQUEST +// + +typedef struct _REMOVE_ELEMENT_AND_TRUNCATE_REQUEST { + + ULONG Version; + ULONG Size; + + // In unit of LBA. + ULONGLONG RequestCapacity; + + ULONG ElementIdentifier; + ULONG Reserved; + +} REMOVE_ELEMENT_AND_TRUNCATE_REQUEST, *PREMOVE_ELEMENT_AND_TRUNCATE_REQUEST; + + +#pragma warning(push) +#pragma warning(disable:4200) + +#if defined(_MSC_EXTENSIONS) + +typedef struct _STORAGE_MEDIA_SERIAL_NUMBER_DATA { + + USHORT Reserved; + + // + // the SerialNumberLength will be set to zero + // if the command is supported and the media + // does not have a valid serial number. + // + + USHORT SerialNumberLength; + + // + // the following data is binary, and is not guaranteed + // to be NULL terminated. this is an excercise for the + // caller. + // + +#if !defined(__midl) + UCHAR SerialNumber[0]; +#endif + +} STORAGE_MEDIA_SERIAL_NUMBER_DATA, *PSTORAGE_MEDIA_SERIAL_NUMBER_DATA; + +#endif /* _MSC_EXTENSIONS */ + +typedef _Struct_size_bytes_(Size) struct _STORAGE_READ_CAPACITY { + + // + // The version number, size of the STORAGE_READ_CAPACITY structure + // + ULONG Version; + + // + // The size of the date returned, size of the STORAGE_READ_CAPACITY structure + // + ULONG Size; + + // + // Number of bytes per block + // + + ULONG BlockLength; + + // + // Total number of blocks in the disk + // This will have the last LBA + 1 + // + + LARGE_INTEGER NumberOfBlocks; + + // + // Disk size in bytes + // + + LARGE_INTEGER DiskLength; + +} STORAGE_READ_CAPACITY, *PSTORAGE_READ_CAPACITY; + +#pragma warning(pop) + +// +// Device write cache property +// +// This property provides the write cache information +// about the target device. +// + +typedef enum __WRAPPED__ _WRITE_CACHE_TYPE { + WriteCacheTypeUnknown, + WriteCacheTypeNone, + WriteCacheTypeWriteBack, + WriteCacheTypeWriteThrough +} WRITE_CACHE_TYPE; + +typedef enum __WRAPPED__ _WRITE_CACHE_ENABLE { + WriteCacheEnableUnknown, + WriteCacheDisabled, + WriteCacheEnabled +} WRITE_CACHE_ENABLE; + +typedef enum __WRAPPED__ _WRITE_CACHE_CHANGE { + WriteCacheChangeUnknown, + WriteCacheNotChangeable, + WriteCacheChangeable +} WRITE_CACHE_CHANGE; + +typedef enum __WRAPPED__ _WRITE_THROUGH { + WriteThroughUnknown, + WriteThroughNotSupported, + WriteThroughSupported +} WRITE_THROUGH; + +typedef _Struct_size_bytes_(Size) struct __WRAPPED__ _STORAGE_WRITE_CACHE_PROPERTY { + + // + // The version number + // Size of STORAGE_WRITE_CACHE_PROPERTY structure + // + + __WRAPPED__ + ULONG Version; + + // + // The size of the date returned + // Size of STORAGE_WRITE_CACHE_PROPERTY structure + // + + __WRAPPED__ + ULONG Size; + + // + // Current write cache type + // + + __WRAPPED__ + WRITE_CACHE_TYPE WriteCacheType; + + // + // Current write cache value + // + + __WRAPPED__ + WRITE_CACHE_ENABLE WriteCacheEnabled; + + // + // Device write cache change capability + // + + __WRAPPED__ + WRITE_CACHE_CHANGE WriteCacheChangeable; + + // + // Device write through support capability + // + + __WRAPPED__ + WRITE_THROUGH WriteThroughSupported; + + // + // Device flush cache capability + // + + __WRAPPED__ + BOOLEAN FlushCacheSupported; + + // + // User selected power protection option through registry + // + + __WRAPPED__ + BOOLEAN UserDefinedPowerProtection; + + // + // Device has battery backup for write cache + // + + __WRAPPED__ + BOOLEAN NVCacheEnabled; + +} STORAGE_WRITE_CACHE_PROPERTY, *PSTORAGE_WRITE_CACHE_PROPERTY; + +#pragma warning(push) +#pragma warning(disable:4200) // array[0] +#pragma warning(disable:4201) // nameless struct/unions +#pragma warning(disable:4214) // bit fields other than int + + +#if defined(_MSC_EXTENSIONS) + +typedef struct _PERSISTENT_RESERVE_COMMAND { + + ULONG Version; + ULONG Size; + + union { + + struct { + + // + // Persistent Reserve service action. + // + + UCHAR ServiceAction : 5; + UCHAR Reserved1 : 3; + + // + // Number of bytes allocated for returned parameter list. + // + + USHORT AllocationLength; + + } PR_IN; + + struct { + + // + // Persistent Reserve service action. + // + + UCHAR ServiceAction : 5; + UCHAR Reserved1 : 3; + + // + // Persistent Reserve type and scope. + // + + UCHAR Type : 4; + UCHAR Scope : 4; + + // + // Space for additional PR Out parameters. + // + +#if !defined(__midl) + UCHAR ParameterList[0]; +#endif + + } PR_OUT; + } DUMMYUNIONNAME; + +} PERSISTENT_RESERVE_COMMAND, *PPERSISTENT_RESERVE_COMMAND; + +#endif /* _MSC_EXTENSIONS */ +#pragma warning(pop) + +// +// Device telemetry definitions +// +// Structures and interfaces dealing with acquistion of device and driver internal telemetry. +// + +// For variable size fields we use byte array, defined with zero length in structure template. Length of the field is stored as a separate field. +// No more than one variable size field is allowed in one structure and it is always placed last. + +#pragma warning(push) + + +// +// Persistent data structures are versioned and "sized" by adding structure version field and structure size field +// +#define DEVICEDUMP_STRUCTURE_VERSION_V1 1 + +// +// Max size of the identification string +// +#define DEVICEDUMP_MAX_IDSTRING 32 // Keep proportional to sizeof (ULONG) +#define MAX_FW_BUCKET_ID_LENGTH 132 // 128 (ACS specification + 1 for zero termination + 3 to align on ULONG) + + +// +// Global telemetry collection parameters in the registry +// +#define STORAGE_CRASH_TELEMETRY_REGKEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl\\StorageTelemetry" +#define STORAGE_DEVICE_TELEMETRY_REGKEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Storage\\StorageTelemetry" + +// +// Reasons for telemetry collection +// +typedef enum _DEVICEDUMP_COLLECTION_TYPE { + TCCollectionBugCheck = 1, // 1 + TCCollectionApplicationRequested, // 2 (Host Initiated - HITC) + TCCollectionDeviceRequested // 3 (Device initiated - DITC) +} DEVICEDUMP_COLLECTION_TYPEIDE_NOTIFICATION_TYPE, *PDEVICEDUMP_COLLECTION_TYPE; + +// +// Flags for the device dump section +// +#define DDUMP_FLAG_DATA_READ_FROM_DEVICE 0x0001 + +// +// Firmware issue IDs (similar to bug check reasons) +// +#define FW_ISSUEID_NO_ISSUE 0x00000000 +#define FW_ISSUEID_UNKNOWN 0xFFFFFFFF + +// +#include // Structures are packed on a byte boundary , because parsers may run on separate machines and different OS flavors + +// +// Device dump section contains common device dump header, followed by set of relative pointers to sub sections +// Each relative pointer contain size in bytes of the subsection and starting offset from the beginning of the section +// +// Layout of the device dump section is as +// +// HEADER - common descriptor +// PUBLIC DATA - publicly accessible data (eg SMART structures) +// RESRICTED DATA - restricted access data (eg encrypted with Microsoft and IHV public keys) +// PRIVATE DATA - private device data +// +// All fields in the section definition are used cross platform => types used are platform neutral +// + +// +// Relative descript or of a subsection, contains size of the subsection and relative offset (0 is the start of the section) +// +typedef struct _DEVICEDUMP_SUBSECTION_POINTER { + ULONG dwSize; // Size (in bytes) of the subsection + ULONG dwFlags; // Parameter flags for the subsection + ULONG dwOffset; // Offset (in bytes) of the subsection block from the start of the buffer +} DEVICEDUMP_SUBSECTION_POINTER,*PDEVICEDUMP_SUBSECTION_POINTER; + +// +// Data structure tagging fields (version and size) +// +typedef struct _DEVICEDUMP_STRUCTURE_VERSION { + // + // Header signature, useful for identifying the structure when reading the dump + // + ULONG dwSignature; + + // + // Version of the template + // + ULONG dwVersion; + + // + // Size of the parent structure in bytes + // + ULONG dwSize; + +} DEVICEDUMP_STRUCTURE_VERSION, *PDEVICEDUMP_STRUCTURE_VERSION; + +// +// Device data header for the secondary data (in crashdump) section , holding device dump information. +// +typedef struct _DEVICEDUMP_SECTION_HEADER { + // + // GUID, identifying device dump section. Same GUID as used in registering for SecondaryData callback, stored here for live telemetry interface consistency + // + GUID guidDeviceDataId; + + // + // Device identification fields. + // These fields together should uniquely identify the device firmware image. + + // + // ID value, common for storage device vendors. This ID will be used by !analyze to create a vendor ID for WinQual. + // + // + // Unique identifier assigned to the organization responsible for device quality (firmware quality). In most cases this is OUID (IEEE) or WorldWideName of the device vendor + // + UCHAR sOrganizationID[16]; + + // + // Firmware revision as indicated in IDENITFY or INQUIRY structures + // + ULONG dwFirmwareRevision; + + // + // Device model number (keep the length of the field proportional to sizeof (ULONG)) + // + UCHAR sModelNumber[DEVICEDUMP_MAX_IDSTRING]; + + // + // Vendor specific device cookie, identifying process and manufacturing parameters. Opaque to the OS and applications. + // + UCHAR szDeviceManufacturingID[DEVICEDUMP_MAX_IDSTRING]; // Keep the length of the field proportional to sizeof (ULONG) + + // + // Sourcing indicator flag - used to detect if data was emulated from other structures or obtained directly from the firmware using log command + // Set to 1 if public data was filled in using data from the device telemetry log + // Set to 0 if the device doesn't support the command and the driver filled in as best it could + // + ULONG dwFlags; + + // + // Version of private data as indicated by the firmware.Initially always 0 to specify Private only unspecified data + // + ULONG bRestrictedPrivateDataVersion; + + // + // Issue identifier (hash value) generated by the firmware. Reflects state of the device firmware and used for cross device type/vendor queries. + // We will rely on standardized namespace of issue IDs and good will of firmware developers to taxonomize + // + ULONG dwFirmwareIssueId; //currently unused + + // + // Firmware bucket ID - long string, opague to Windows , but useful to create unique bucket in concatenation with device identification data + // + UCHAR szIssueDescriptionString[MAX_FW_BUCKET_ID_LENGTH]; // zero terminated + +} DEVICEDUMP_SECTION_HEADER, *PDEVICEDUMP_SECTION_HEADER; + +// +// Public subsection header - subsection is holding data, describing device state and accessible to everybody. +// + +#define TC_PUBLIC_DEVICEDUMP_CONTENT_SMART 0x01 +#define TC_PUBLIC_DEVICEDUMP_CONTENT_GPLOG 0x02 + +// +// Maximum number of log pages collected into the public section +#define TC_PUBLIC_DEVICEDUMP_CONTENT_GPLOG_MAX 16 + +// Maximum length of the description of the collected pages (filled by the miniport) +#define TC_DEVICEDUMP_SUBSECTION_DESC_LENGTH 16 + +// +// Standard types of collected pages +// +#define TC_PUBLIC_DATA_TYPE_ATAGP "ATAGPLogPages" +#define TC_PUBLIC_DATA_TYPE_ATASMART "ATASMARTPages" + +// +// Public data is tagged with the table of "log descriptors". Each descriptor has LogAddress and number of pages. +// Specific meaning, assigned to the descriptor, is relative to the command set used. +// + +typedef struct _GP_LOG_PAGE_DESCRIPTOR { + USHORT LogAddress; + USHORT LogSectors; +} GP_LOG_PAGE_DESCRIPTOR,*PGP_LOG_PAGE_DESCRIPTOR; + +typedef struct _DEVICEDUMP_PUBLIC_SUBSECTION { + ULONG dwFlags; + GP_LOG_PAGE_DESCRIPTOR GPLogTable[TC_PUBLIC_DEVICEDUMP_CONTENT_GPLOG_MAX]; + CHAR szDescription[TC_DEVICEDUMP_SUBSECTION_DESC_LENGTH]; // Zero terminated + UCHAR bData[ANYSIZE_ARRAY]; // Data byte array ANYSIZE_ARRAY +} DEVICEDUMP_PUBLIC_SUBSECTION, *PDEVICEDUMP_PUBLIC_SUBSECTION; + +// +// Restricted subsection header - subsection is holding data, describing device state and accessible only to Microsoft and a device vendor +// +typedef struct _DEVICEDUMP_RESTRICTED_SUBSECTION { + + UCHAR bData[ANYSIZE_ARRAY]; // Data byte array (ANYSIZE_ARRAY) + +} DEVICEDUMP_RESTRICTED_SUBSECTION, *PDEVICEDUMP_RESTRICTED_SUBSECTION; + +// +// Private subsection header - subsection is holding data, describing device state and accessible only to a device vendor +// +typedef struct _DEVICEDUMP_PRIVATE_SUBSECTION { + + ULONG dwFlags; + GP_LOG_PAGE_DESCRIPTOR GPLogId; + + UCHAR bData[ANYSIZE_ARRAY]; // Data byte array (ANYSIZE_ARRAY) + +} DEVICEDUMP_PRIVATE_SUBSECTION, *PDEVICEDUMP_PRIVATE_SUBSECTION; + +// +// Descriptor of the storage device dump section +// +typedef _Struct_size_bytes_(Descriptor.dwSize) struct _DEVICEDUMP_STORAGEDEVICE_DATA { + + // + // Common descriptor (signature,version of the structure) + // + DEVICEDUMP_STRUCTURE_VERSION Descriptor; + + // + // Header - set of fields, describing dump section and device (not requiring protocol communication) + // + DEVICEDUMP_SECTION_HEADER SectionHeader; + + // + // Size of the whole section buffer, in bytes , including header and sum total of all the variable sized sub sections + // + ULONG dwBufferSize; + + // + // Reason for collecting telemetry + // + ULONG dwReasonForCollection; + + // + // "Pointers" to individual sub-sections. Sub sections are filled with the information, obtained from the device + // + DEVICEDUMP_SUBSECTION_POINTER PublicData; + DEVICEDUMP_SUBSECTION_POINTER RestrictedData; + DEVICEDUMP_SUBSECTION_POINTER PrivateData; + +} DEVICEDUMP_STORAGEDEVICE_DATA, *PDEVICEDUMP_STORAGEDEVICE_DATA; + + +// +// Driver dump section contains common device driver context information: +// - circular buffer of the IO requests as visible by the lower edge of the driver +// (in case of storage that would be an interface to the controller stack or controller itself) +// +// All fields in the section definition are used cross platform => types used are platform neutral +// + +// +// Format of the single record for publicly accessible driver state table +// + +#define CDB_SIZE 16 +#define TELEMETRY_COMMAND_SIZE 16 + +#define TCRecordStorportSrbFunction Command[0] + +typedef struct _DEVICEDUMP_STORAGESTACK_PUBLIC_STATE_RECORD { + // The CDB for this request. variable sized CDBs are truncated. + UCHAR Cdb[CDB_SIZE]; + + // The actual command for this request. + UCHAR Command[TELEMETRY_COMMAND_SIZE]; + + // the time when driver received the request + ULONGLONG StartTime; + + // the system time when the request was completed + ULONGLONG EndTime; + + // Status value () + ULONG OperationStatus; + + // Error value (eg error reg for ATAPort, SCSI error for storport) + ULONG OperationError; + + // Stack specific information + union { + struct { + ULONG dwReserved; + } ExternalStack; + + struct { + ULONG dwAtaPortSpecific; + } AtaPort; + + struct { + ULONG SrbTag ; + } StorPort; + + } StackSpecific; + +} DEVICEDUMP_STORAGESTACK_PUBLIC_STATE_RECORD,*PDEVICEDUMP_STORAGESTACK_PUBLIC_STATE_RECORD; + + +typedef _Struct_size_bytes_(Descriptor.dwSize) struct _DEVICEDUMP_STORAGESTACK_PUBLIC_DUMP { + + // + // Common descriptor (signature,version of the structure) + // + DEVICEDUMP_STRUCTURE_VERSION Descriptor; + + // + // Reason for collecting telemetry + // + ULONG dwReasonForCollection; + + // + // Driver stack and instance + // + UCHAR cDriverName[16]; + + // + // Standardized log of IO requests issued to the target, starting with number of records. + // Log is circular, order is not guaranteed + // + ULONG uiNumRecords; + + DEVICEDUMP_STORAGESTACK_PUBLIC_STATE_RECORD RecordArray[ANYSIZE_ARRAY]; //ANYSIZE_ARRAY + +} DEVICEDUMP_STORAGESTACK_PUBLIC_DUMP,*PDEVICEDUMP_STORAGESTACK_PUBLIC_DUMP; + +// End of the packed structure group +#include + + +// +// Telemetry information block descriptor - bit flags in DumpCapabilities field +// + +#define DEVICEDUMP_CAP_PRIVATE_SECTION 0x00000001 // Target supports private data +#define DEVICEDUMP_CAP_RESTRICTED_SECTION 0x00000002 // Target supports restricted data + + + +#pragma warning(push) +#pragma warning(disable:4214) // bit fields other than int + +// +// IOCTL_STORAGE_ENABLE_IDLE_POWER +// +// Input Buffer: +// A STORAGE_IDLE_POWER structure specifying the idle power management +// properties of the device. +// +// Output Buffer: +// None. +// +typedef struct _STORAGE_IDLE_POWER { + ULONG Version; // Structure version, should be set to 1 for Win8. + ULONG Size; // Size of this structure in bytes. + ULONG WakeCapableHint : 1; // Storage device supports wake from low power states. + ULONG D3ColdSupported : 1; // Storage device supports D3Cold + ULONG Reserved : 30; + ULONG D3IdleTimeout; // Idle time in msec before storage device is transitioned to D3 (max of ~49.7 days). +} STORAGE_IDLE_POWER, *PSTORAGE_IDLE_POWER; + +#pragma warning(pop) + +// +// IOCTL_STORAGE_GET_IDLE_POWERUP_REASON +// +// Input Buffer: +// None. +// +// Output Buffer: +// A STORAGE_IDLE_POWERUP_REASON structure specifying what caused the power up. +// +typedef enum _STORAGE_POWERUP_REASON_TYPE { + StoragePowerupUnknown = 0, + StoragePowerupIO, + StoragePowerupDeviceAttention +} STORAGE_POWERUP_REASON_TYPE, *PSTORAGE_POWERUP_REASON_TYPE; + +typedef struct _STORAGE_IDLE_POWERUP_REASON { + ULONG Version; // Structure version, should be set to 1 for Win8. + ULONG Size; // Size of this structure in bytes. + STORAGE_POWERUP_REASON_TYPE PowerupReason; // The reason for the power up (see above). +} STORAGE_IDLE_POWERUP_REASON, *PSTORAGE_IDLE_POWERUP_REASON; + +#define STORAGE_IDLE_POWERUP_REASON_VERSION_V1 1 + +// +// IOCTL_STORAGE_DEVICE_POWER_CAP +// +// This IOCTL specifies a maximum *operational* power consumption level for a +// storage device. +// The storage stack will do its best to transition the device to a power state +// that will not exceed the given maximum. However, this depends on what the +// device supports. The actual maximum may be less than or greater than the +// desired maximum. +// +// Input buffer: +// A STORAGE_DEVICE_POWER_CAP structure. +// * The Units field specifies the units of the MaxPower field. It can be +// either a percentage (0-100%) or an absolute value in milliwatts. +// * The MaxPower field is used to set the desired maximum power consumption +// value for the storage device. +// +// Output buffer: +// On success, the output buffer will contain a STORAGE_DEVICE_POWER_CAP +// structure. +// * The Units field will continue to specify the units of the MaxPower field +// and will match the value from the input buffer. +// * The MaxPower field will contain the value of the actual maximum +// power consumption level of the device. This may be equal to, less than, +// or greater than the desired cap, depending on what the device supports. +// +typedef enum _STORAGE_DEVICE_POWER_CAP_UNITS { + StorageDevicePowerCapUnitsPercent, + StorageDevicePowerCapUnitsMilliwatts +} STORAGE_DEVICE_POWER_CAP_UNITS, *PSTORAGE_DEVICE_POWER_CAP_UNITS; + +typedef struct _STORAGE_DEVICE_POWER_CAP { + ULONG Version; + ULONG Size; + STORAGE_DEVICE_POWER_CAP_UNITS Units; + ULONGLONG MaxPower; +} STORAGE_DEVICE_POWER_CAP, *PSTORAGE_DEVICE_POWER_CAP; + +#define STORAGE_DEVICE_POWER_CAP_VERSION_V1 1 + +// +// IOCTL_STORAGE_RPMB_COMMAND +// +// This IOCTL sends an RPMB command to the underlying storage device. +// +// Input buffer: +// An array of STORAGE_RPMB_DATA_FRAME structures +// * The number of frames included can be calculated by InputBufferLength / sizeof(STORAGE_RPMB_DATA_FRAME) +// +// Output buffer: +// An array of STORAGE_RPMB_DATA_FRAME structures +// * The number of frames included can be calculated by OutputBufferLength / sizeof(STORAGE_RPMB_DATA_FRAME) +// + +// Ensure we are byte aligned +#pragma pack(push) +#pragma pack(1) + +// +// This is the RPMB data frame used to compose all RPMB requests and responses. +// +// This corresponds to StorageRpmbFrameTypeStandard +// + +typedef struct _STORAGE_RPMB_DATA_FRAME { + + // + // Reserved + // + UCHAR Stuff[196]; + + // + // Either the key to be programmed or the MAC authenticating this frame or series of frames + // + UCHAR KeyOrMAC[32]; + + // + // The data input or output + // + UCHAR Data[256]; + + // + // Random 128-bit number generated by host + // + UCHAR Nonce[16]; + + // + // 32-bit counter + // + UCHAR WriteCounter[4]; + + // + // The half-sector address to operate on + // + UCHAR Address[2]; + + // + // The count of half-sector blocks to read/write + // + UCHAR BlockCount[2]; + + // + // The result of the operation + // + UCHAR OperationResult[2]; + + // + // The type of request or response + // + UCHAR RequestOrResponseType[2]; + +} STORAGE_RPMB_DATA_FRAME, *PSTORAGE_RPMB_DATA_FRAME; + +// +// RPMB RequestOrResponseType Values +// + +typedef enum _STORAGE_RPMB_COMMAND_TYPE { + StorRpmbProgramAuthKey = 0x00000001, + StorRpmbQueryWriteCounter = 0x00000002, + StorRpmbAuthenticatedWrite = 0x00000003, + StorRpmbAuthenticatedRead = 0x00000004, + StorRpmbReadResultRequest = 0x00000005, + StorRpmbAuthenticatedDeviceConfigWrite = 0x00000006, + StorRpmbAuthenticatedDeviceConfigRead = 0x00000007, +} STORAGE_RPMB_COMMAND_TYPE, *PSTORAGE_RPMB_COMMAND_TYPE; + +#pragma pack(pop) + +// +// IOCTL_STORAGE_EVENT_NOTIFICATION +// +// Input Buffer: +// A STORAGE_EVENT_NOTIFICATION structure specifying the event(s) that occurred. +// +// Output Buffer: +// None +// +typedef struct _STORAGE_EVENT_NOTIFICATION { + ULONG Version; // Structure version, should be set to 1 for Win8. + ULONG Size; // Size of this structure in bytes. + ULONGLONG Events; // Bitmask of event(s) that occurred. +} STORAGE_EVENT_NOTIFICATION, *PSTORAGE_EVENT_NOTIFICATION; + +#define STORAGE_EVENT_NOTIFICATION_VERSION_V1 1 + +#define STORAGE_EVENT_MEDIA_STATUS 0x0000000000000001 +#define STORAGE_EVENT_DEVICE_STATUS 0x0000000000000002 +#define STORAGE_EVENT_DEVICE_OPERATION 0x0000000000000004 + +#define STORAGE_EVENT_ALL (STORAGE_EVENT_MEDIA_STATUS | STORAGE_EVENT_DEVICE_STATUS | STORAGE_EVENT_DEVICE_OPERATION) + +#pragma warning(pop) + + +#define READ_COPY_NUMBER_KEY 0x52434e00 // 'RCN' + +#define IsKeyReadCopyNumber(_k) (((_k) & 0xFFFFFF00) == READ_COPY_NUMBER_KEY) + +#define ReadCopyNumberToKey(_c) (READ_COPY_NUMBER_KEY | (UCHAR)(_c)) +#define ReadCopyNumberFromKey(_k) (UCHAR)((_k) & 0x000000FF) + + +// +// IOCTL_STORAGE_GET_COUNTERS +// +// This IOCTL retrieves reliability counters for a storage device. +// +// The caller can find out the required output buffer size by simply sending +// down a single STORAGE_COUNTERS structure. STATUS_BUFFER_OVERFLOW will be +// returned and the Size field in the STORAGE_COUNTERS structure will contain +// the total size of the required output buffer. +// +// When the output buffer is sufficiently large, STATUS_SUCCESS will be +// returned and the output buffer will contain a STORAGE_COUNTERS structure +// followed by an array of STORAGE_COUNTER structures. +// +// Input Buffer: +// STORAGE_COUNTERS with the Version field set appropriately. +// +// Output Buffer: +// When successful, a STORAGE_COUNTERS structure with the Counters array +// filled out. NumberOfCounters will indicate the number of elements in +// the Counters array. +// See above for more details. +// + +typedef enum _STORAGE_COUNTER_TYPE { + + StorageCounterTypeUnknown = 0, + + StorageCounterTypeTemperatureCelsius, + StorageCounterTypeTemperatureCelsiusMax, + StorageCounterTypeReadErrorsTotal, + StorageCounterTypeReadErrorsCorrected, + StorageCounterTypeReadErrorsUncorrected, + StorageCounterTypeWriteErrorsTotal, + StorageCounterTypeWriteErrorsCorrected, + StorageCounterTypeWriteErrorsUncorrected, + StorageCounterTypeManufactureDate, + StorageCounterTypeStartStopCycleCount, + StorageCounterTypeStartStopCycleCountMax, + StorageCounterTypeLoadUnloadCycleCount, + StorageCounterTypeLoadUnloadCycleCountMax, + StorageCounterTypeWearPercentage, + StorageCounterTypeWearPercentageWarning, + StorageCounterTypeWearPercentageMax, + StorageCounterTypePowerOnHours, + StorageCounterTypeReadLatency100NSMax, + StorageCounterTypeWriteLatency100NSMax, + StorageCounterTypeFlushLatency100NSMax, + + StorageCounterTypeMax + +} STORAGE_COUNTER_TYPE, *PSTORAGE_COUNTER_TYPE; + +typedef struct _STORAGE_COUNTER { + + STORAGE_COUNTER_TYPE Type; + + union { + + struct { + // + // Week is the number of the week in the year, 1-52. + // + ULONG Week; + + // + // Year is the last two digits of the year, e.g. 2016 is simply "16". + // + ULONG Year; + } ManufactureDate; + + ULONGLONG AsUlonglong; + } Value; + +} STORAGE_COUNTER, *PSTORAGE_COUNTER; + +typedef _Struct_size_bytes_(Size) struct _STORAGE_COUNTERS { + + // + // Size of this structure serves as the version. + // + ULONG Version; + + // + // Total size of this structure plus all the variable-sized fields. + // + ULONG Size; + + ULONG NumberOfCounters; + + _Field_size_(NumberOfCounters) STORAGE_COUNTER Counters[ANYSIZE_ARRAY]; + +} STORAGE_COUNTERS, *PSTORAGE_COUNTERS; + +#define STORAGE_COUNTERS_VERSION_V1 sizeof(STORAGE_COUNTERS) + +// +// Parameter and data structure for firmware upgrade IOCTLs +// IOCTL_STORAGE_FIRMWARE_GET_INFO, IOCTL_STORAGE_FIRMWARE_DOWNLOAD, IOCTL_STORAGE_FIRMWARE_ACTIVATE +// + +// +// Indicate the target of the request other than the device handle/object itself. +// This is used in "Flags" field of data structures for firmware upgrade request. +// +#define STORAGE_HW_FIRMWARE_REQUEST_FLAG_CONTROLLER 0x00000001 + +// +// Indicate that current FW image segment is the last one. +// +#define STORAGE_HW_FIRMWARE_REQUEST_FLAG_LAST_SEGMENT 0x00000002 + +// +// Indicate that current FW image segment is the first one. +// +#define STORAGE_HW_FIRMWARE_REQUEST_FLAG_FIRST_SEGMENT 0x00000004 + +// +// Indicate that the existing firmware in slot should be activated. +// Only valid for IOCTL_STORAGE_FIRMWARE_ACTIVATE. +// +#define STORAGE_HW_FIRMWARE_REQUEST_FLAG_SWITCH_TO_EXISTING_FIRMWARE 0x80000000 + +// +// Input parameter for IOCTL_STORAGE_FIRMWARE_GET_INFO +// +typedef struct _STORAGE_HW_FIRMWARE_INFO_QUERY { + ULONG Version; // sizeof(STORAGE_FIRMWARE_INFO_QUERY) + ULONG Size; // Whole size of the buffer (in case this data structure being extended to be variable length) + ULONG Flags; + ULONG Reserved; +} STORAGE_HW_FIRMWARE_INFO_QUERY, *PSTORAGE_HW_FIRMWARE_INFO_QUERY; + +// +// Output parameter for IOCTL_STORAGE_FIRMWARE_GET_INFO +// The total size of returned data is for Firmware Info is: +// sizeof(STORAGE_HW_FIRMWARE_INFO) + sizeof(STORAGE_HW_FIRMWARE_SLOT_INFO) * (SlotCount - 1). +// If the buffer is not big enough, callee should set the required length in "Size" field of STORAGE_HW_FIRMWARE_INFO, +// + +// +// Following value maybe used in "PendingActiveSlot" field indicating there is no firmware pending to activate. +// +#define STORAGE_HW_FIRMWARE_INVALID_SLOT 0xFF + +#pragma warning(push) +#pragma warning(disable:4214) // bit fields other than int + +#define STORAGE_HW_FIRMWARE_REVISION_LENGTH 16 + +typedef struct __WRAPPED__ _STORAGE_HW_FIRMWARE_SLOT_INFO { + + __WRAPPED__ + ULONG Version; // sizeof(STORAGE_HW_FIRMWARE_SLOT_INFO) + + __WRAPPED__ + ULONG Size; // size the data contained in STORAGE_HW_FIRMWARE_SLOT_INFO. + + __WRAPPED__ + UCHAR SlotNumber; + + __WRAPPED__ + UCHAR ReadOnly : 1; + + __WRAPPED__ + UCHAR Reserved0 : 7; + + __WRAPPED__ + UCHAR Reserved1[6]; + + __WRAPPED__ + UCHAR Revision[STORAGE_HW_FIRMWARE_REVISION_LENGTH]; + +} STORAGE_HW_FIRMWARE_SLOT_INFO, *PSTORAGE_HW_FIRMWARE_SLOT_INFO; + +typedef struct __WRAPPED__ _STORAGE_HW_FIRMWARE_INFO { + + __WRAPPED__ + ULONG Version; // sizeof(STORAGE_HW_FIRMWARE_INFO) + + __WRAPPED__ + ULONG Size; // size of the whole buffer including slot[] + + __WRAPPED__ + UCHAR SupportUpgrade : 1; + + __WRAPPED__ + UCHAR Reserved0 : 7; + + __WRAPPED__ + UCHAR SlotCount; + + __WRAPPED__ + UCHAR ActiveSlot; + + __WRAPPED__ + UCHAR PendingActivateSlot; + + __WRAPPED__ + BOOLEAN FirmwareShared; // The firmware applies to both device and adapter. For example: PCIe SSD. + + __WRAPPED__ + UCHAR Reserved[3]; + + __WRAPPED__ + ULONG ImagePayloadAlignment; // Number of bytes. Max: PAGE_SIZE. The transfer size should be multiple of this unit size. Some protocol requires at least sector size. 0 means the value is not valid. + + __WRAPPED__ + ULONG ImagePayloadMaxSize; // for a single command. + + __WRAPPED__ + STORAGE_HW_FIRMWARE_SLOT_INFO Slot[ANYSIZE_ARRAY]; + +} STORAGE_HW_FIRMWARE_INFO, *PSTORAGE_HW_FIRMWARE_INFO; +#pragma warning(pop) + + +// +// Input parameter for IOCTL_STORAGE_FIRMWARE_DOWNLOAD +// +#pragma warning(push) +#pragma warning(disable:4200) + +typedef struct _STORAGE_HW_FIRMWARE_DOWNLOAD { + + ULONG Version; // sizeof(STORAGE_HW_FIRMWARE_DOWNLOAD) + ULONG Size; // size of the whole buffer include "ImageBuffer" + + ULONG Flags; + UCHAR Slot; // Slot number that firmware image will be downloaded into. + UCHAR Reserved[3]; + + ULONGLONG Offset; // Image file offset, should be aligned to "ImagePayloadAlignment" value from STORAGE_FIRMWARE_INFO. + ULONGLONG BufferSize; // should be multiple of "ImagePayloadAlignment" value from STORAGE_FIRMWARE_INFO. + + UCHAR ImageBuffer[ANYSIZE_ARRAY]; // firmware image file. + +} STORAGE_HW_FIRMWARE_DOWNLOAD, *PSTORAGE_HW_FIRMWARE_DOWNLOAD; + +typedef struct _STORAGE_HW_FIRMWARE_DOWNLOAD_V2 { + + ULONG Version; // sizeof(STORAGE_HW_FIRMWARE_DOWNLOAD_V2) + ULONG Size; // size of the whole buffer include "ImageBuffer" + + ULONG Flags; + UCHAR Slot; // Slot number that firmware image will be downloaded into. + UCHAR Reserved[3]; + + ULONGLONG Offset; // Image file offset, should be aligned to "ImagePayloadAlignment" value from STORAGE_FIRMWARE_INFO. + ULONGLONG BufferSize; // should be multiple of "ImagePayloadAlignment" value from STORAGE_FIRMWARE_INFO. + + ULONG ImageSize; // Firmware Image size. + ULONG Reserved2; + + UCHAR ImageBuffer[ANYSIZE_ARRAY]; // firmware image file. + +} STORAGE_HW_FIRMWARE_DOWNLOAD_V2, *PSTORAGE_HW_FIRMWARE_DOWNLOAD_V2; + +#pragma warning(pop) + +// +// Input parameter for IOCTL_STORAGE_FIRMWARE_ACTIVATE +// +typedef struct _STORAGE_HW_FIRMWARE_ACTIVATE { + + ULONG Version; + ULONG Size; + + ULONG Flags; + UCHAR Slot; // Slot with firmware image to be activated. + UCHAR Reserved0[3]; + +} STORAGE_HW_FIRMWARE_ACTIVATE, *PSTORAGE_HW_FIRMWARE_ACTIVATE; + +// +// Parameter for IOCTL_STORAGE_PROTOCOL_COMMAND +// Buffer layout: [Error Info Buffer] [Data-to-Device Buffer] [Data-from-Device Buffer] +// +#define STORAGE_PROTOCOL_STRUCTURE_VERSION 0x1 + +typedef struct _STORAGE_PROTOCOL_COMMAND { + + ULONG Version; // STORAGE_PROTOCOL_STRUCTURE_VERSION + ULONG Length; // sizeof(STORAGE_PROTOCOL_COMMAND) + + STORAGE_PROTOCOL_TYPE ProtocolType; + ULONG Flags; // Flags for the request + + ULONG ReturnStatus; // return value + ULONG ErrorCode; // return value, optional + + ULONG CommandLength; // non-zero value should be set by caller + ULONG ErrorInfoLength; // optional, can be zero + ULONG DataToDeviceTransferLength; // optional, can be zero. Used by WRITE type of request. + ULONG DataFromDeviceTransferLength; // optional, can be zero. Used by READ type of request. + + ULONG TimeOutValue; // in unit of seconds + + ULONG ErrorInfoOffset; // offsets need to be pointer aligned + ULONG DataToDeviceBufferOffset; // offsets need to be pointer aligned + ULONG DataFromDeviceBufferOffset; // offsets need to be pointer aligned + + ULONG CommandSpecific; // optional information passed along with Command. + ULONG Reserved0; + + ULONG FixedProtocolReturnData; // return data, optional. Some protocol, such as NVMe, may return a small amount data (DWORD0 from completion queue entry) without the need of separate device data transfer. + ULONG Reserved1[3]; + + _Field_size_bytes_full_(CommandLength) UCHAR Command[ANYSIZE_ARRAY]; + +} STORAGE_PROTOCOL_COMMAND, *PSTORAGE_PROTOCOL_COMMAND; + +// +// Bit-mask values for STORAGE_PROTOCOL_COMMAND - "Flags" field. +// +#define STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST 0x80000000 // Flag indicates the request targeting to adapter instead of device. + +// +// Status values for STORAGE_PROTOCOL_COMMAND - "ReturnStatus" field. +// +#define STORAGE_PROTOCOL_STATUS_PENDING 0x0 +#define STORAGE_PROTOCOL_STATUS_SUCCESS 0x1 +#define STORAGE_PROTOCOL_STATUS_ERROR 0x2 +#define STORAGE_PROTOCOL_STATUS_INVALID_REQUEST 0x3 +#define STORAGE_PROTOCOL_STATUS_NO_DEVICE 0x4 +#define STORAGE_PROTOCOL_STATUS_BUSY 0x5 +#define STORAGE_PROTOCOL_STATUS_DATA_OVERRUN 0x6 +#define STORAGE_PROTOCOL_STATUS_INSUFFICIENT_RESOURCES 0x7 + +#define STORAGE_PROTOCOL_STATUS_NOT_SUPPORTED 0xFF + +// +// Command Length for Storage Protocols. +// +#define STORAGE_PROTOCOL_COMMAND_LENGTH_NVME 0x40 // NVMe commands are always 64 bytes. + +// +// Command Specific Information for Storage Protocols - "CommandSpecific" field. +// +#define STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND 0x01 +#define STORAGE_PROTOCOL_SPECIFIC_NVME_NVM_COMMAND 0x02 + +// +// Additional notes when STORAGE_PROTOCOL_TYPE is ProtocolTypeNvme: +// 1. When flag STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST is set, or the request is sent through adapter, namespace Id from "Command" field is used; +// otherwise, the underneath driver should determine namespace Id from the device that receives the command. +// 2. When a command fails, the "ErrorCode" field contains value from NVMe Completion Queue Entry - DW3 - Status Field. +// 3. "CommandLength" field must have value of 64. e.g. STORAGE_PROTOCOL_COMMAND_LENGTH_NVME. +// 4. "CommandSpecific" field must have value of either STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND, or STORAGE_PROTOCOL_SPECIFIC_NVME_NVM_COMMAND. +// 5. When a command succeeds, field "FixedProtocolReturnData" may contain value from NVMe Completion Queue Entry - DW0. +// + +// +// IOCTL_STORAGE_ATTRIBUTE_MANAGEMENT +// +// This IOCTL manages an attribute +// for a storage device. +// +// When a driver receives this IOCTL it should first +// let any lower drivers process the IOCTL. +// The driver can override the completion status +// from the lower driver layers, if needed. +// For example when driver can provide +// the required functionality after +// doing "Action" on "Attribute", without any support +// from lower drivers, it can choose to ignore failure +// from lower driver layers, complete the "Action" +// and return success. +// +// Input Buffer: +// STORAGE_ATTRIBUTE_MGMT +// +// Output Buffer: +// None. +// + +// +// Valid Management Actions allowed +// on the Attribute +// +typedef enum _STORAGE_ATTRIBUTE_MGMT_ACTION { + StorAttributeMgmt_ClearAttribute = 0, + StorAttributeMgmt_SetAttribute = 1, + StorAttributeMgmt_ResetAttribute = 2 +} STORAGE_ATTRIBUTE_MGMT_ACTION, *PSTORAGE_ATTRIBUTE_MGMT_ACTION; + +// +// Valid Storage Device Attributes +// + +// +// Reserved for future usage. +// +#define STORATTRIBUTE_NONE 0 + +// +// When this attribute is reset, a driver reverts to its +// default state. The definition of default state is specific +// to each individual driver. +// +// Supported actions: Reset. +// +#define STORATTRIBUTE_MANAGEMENT_STATE 1 + +typedef struct _STORAGE_ATTRIBUTE_MGMT { + + // + // Size of this structure serves + // as the version. + // + ULONG Version; + + // + // Size of this structure plus + // all the variable sized fields. + // + ULONG Size; + + // + // Indicates what action is requested. + // + STORAGE_ATTRIBUTE_MGMT_ACTION Action; + + // + // The attribute on which specified "Action" + // needs to be taken. + // + ULONG Attribute; + +} STORAGE_ATTRIBUTE_MGMT, *PSTORAGE_ATTRIBUTE_MGMT; + +#if _MSC_VER >= 1200 +#pragma warning(pop) +#endif + +#if defined __cplusplus && !defined __ALT_GENERATOR__ +} +#endif + + +#endif // _NTDDSTOR_H_ +// end_winioctl + + +#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */ +#pragma endregion + diff --git a/docs/ntddtape.h b/docs/ntddtape.h new file mode 100644 index 0000000..d770fc8 --- /dev/null +++ b/docs/ntddtape.h @@ -0,0 +1,368 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntddtape.h + +Abstract: + + This is the include file that defines all constants and types for + accessing the Tape device. + +--*/ + +#ifndef _NTDDTAPE_ +#define _NTDDTAPE_ + +#if _MSC_VER > 1000 +#pragma once +#endif +#include + +#if _MSC_VER >= 1200 +#pragma warning(push) +#pragma warning(disable:4820) /* padding added after data member */ +#endif + +#pragma region Desktop Family or OneCore Family +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + + +#ifdef __cplusplus +extern "C" { +#endif + +// +// Device Name - this string is the name of the device. It is the name +// that should be passed to NtOpenFile when accessing the device. +// +// Note: For devices that support multiple units, it should be suffixed +// with the Ascii representation of the unit number. +// + +#define DD_TAPE_DEVICE_NAME "\\Device\\Tape" + + +// +// NtDeviceIoControlFile IoControlCode values for this device. +// +// Warning: Remember that the low two bits of the code specify how the +// buffers are passed to the driver! +// + +#define IOCTL_TAPE_BASE FILE_DEVICE_TAPE + +#define IOCTL_TAPE_ERASE CTL_CODE(IOCTL_TAPE_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_TAPE_PREPARE CTL_CODE(IOCTL_TAPE_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_WRITE_MARKS CTL_CODE(IOCTL_TAPE_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_TAPE_GET_POSITION CTL_CODE(IOCTL_TAPE_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_SET_POSITION CTL_CODE(IOCTL_TAPE_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_GET_DRIVE_PARAMS CTL_CODE(IOCTL_TAPE_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_SET_DRIVE_PARAMS CTL_CODE(IOCTL_TAPE_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_TAPE_GET_MEDIA_PARAMS CTL_CODE(IOCTL_TAPE_BASE, 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_SET_MEDIA_PARAMS CTL_CODE(IOCTL_TAPE_BASE, 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_GET_STATUS CTL_CODE(IOCTL_TAPE_BASE, 0x0009, METHOD_BUFFERED, FILE_READ_ACCESS ) +#define IOCTL_TAPE_CREATE_PARTITION CTL_CODE(IOCTL_TAPE_BASE, 0x000a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// The following device control codes are common for all class drivers. The +// functions codes defined here must match all of the other class drivers. +// +// Warning: these codes will be replaced in the future with the IOCTL_STORAGE +// codes included below +// + +#define IOCTL_TAPE_MEDIA_REMOVAL CTL_CODE(IOCTL_TAPE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_EJECT_MEDIA CTL_CODE(IOCTL_TAPE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_LOAD_MEDIA CTL_CODE(IOCTL_TAPE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_RESERVE CTL_CODE(IOCTL_TAPE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_RELEASE CTL_CODE(IOCTL_TAPE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) + +#if (NTDDI_VERSION < NTDDI_WS03) +#define IOCTL_TAPE_CHECK_VERIFY CTL_CODE(IOCTL_TAPE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_FIND_NEW_DEVICES CTL_CODE(IOCTL_DISK_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) +#endif +// +// The following file contains the IOCTL_STORAGE class ioctls +// + +#include + +// begin_winnt begin_ntminitape + +#ifndef _NTDDTAPE_WINNT_ +#define _NTDDTAPE_WINNT_ + +// +// IOCTL_TAPE_ERASE definitions +// + +#define TAPE_ERASE_SHORT 0L +#define TAPE_ERASE_LONG 1L + +typedef struct _TAPE_ERASE { + ULONG Type; + BOOLEAN Immediate; +} TAPE_ERASE, *PTAPE_ERASE; + +// +// IOCTL_TAPE_PREPARE definitions +// + +#define TAPE_LOAD 0L +#define TAPE_UNLOAD 1L +#define TAPE_TENSION 2L +#define TAPE_LOCK 3L +#define TAPE_UNLOCK 4L +#define TAPE_FORMAT 5L + +typedef struct _TAPE_PREPARE { + ULONG Operation; + BOOLEAN Immediate; +} TAPE_PREPARE, *PTAPE_PREPARE; + +// +// IOCTL_TAPE_WRITE_MARKS definitions +// + +#define TAPE_SETMARKS 0L +#define TAPE_FILEMARKS 1L +#define TAPE_SHORT_FILEMARKS 2L +#define TAPE_LONG_FILEMARKS 3L + +typedef struct _TAPE_WRITE_MARKS { + ULONG Type; + ULONG Count; + BOOLEAN Immediate; +} TAPE_WRITE_MARKS, *PTAPE_WRITE_MARKS; + +// +// IOCTL_TAPE_GET_POSITION definitions +// + +#define TAPE_ABSOLUTE_POSITION 0L +#define TAPE_LOGICAL_POSITION 1L +#define TAPE_PSEUDO_LOGICAL_POSITION 2L + +typedef struct _TAPE_GET_POSITION { + ULONG Type; + ULONG Partition; + LARGE_INTEGER Offset; +} TAPE_GET_POSITION, *PTAPE_GET_POSITION; + +// +// IOCTL_TAPE_SET_POSITION definitions +// + +#define TAPE_REWIND 0L +#define TAPE_ABSOLUTE_BLOCK 1L +#define TAPE_LOGICAL_BLOCK 2L +#define TAPE_PSEUDO_LOGICAL_BLOCK 3L +#define TAPE_SPACE_END_OF_DATA 4L +#define TAPE_SPACE_RELATIVE_BLOCKS 5L +#define TAPE_SPACE_FILEMARKS 6L +#define TAPE_SPACE_SEQUENTIAL_FMKS 7L +#define TAPE_SPACE_SETMARKS 8L +#define TAPE_SPACE_SEQUENTIAL_SMKS 9L + +typedef struct _TAPE_SET_POSITION { + ULONG Method; + ULONG Partition; + LARGE_INTEGER Offset; + BOOLEAN Immediate; +} TAPE_SET_POSITION, *PTAPE_SET_POSITION; + +// +// IOCTL_TAPE_GET_DRIVE_PARAMS definitions +// + +// +// Definitions for FeaturesLow parameter +// + +#define TAPE_DRIVE_FIXED 0x00000001 +#define TAPE_DRIVE_SELECT 0x00000002 +#define TAPE_DRIVE_INITIATOR 0x00000004 + +#define TAPE_DRIVE_ERASE_SHORT 0x00000010 +#define TAPE_DRIVE_ERASE_LONG 0x00000020 +#define TAPE_DRIVE_ERASE_BOP_ONLY 0x00000040 +#define TAPE_DRIVE_ERASE_IMMEDIATE 0x00000080 + +#define TAPE_DRIVE_TAPE_CAPACITY 0x00000100 +#define TAPE_DRIVE_TAPE_REMAINING 0x00000200 +#define TAPE_DRIVE_FIXED_BLOCK 0x00000400 +#define TAPE_DRIVE_VARIABLE_BLOCK 0x00000800 + +#define TAPE_DRIVE_WRITE_PROTECT 0x00001000 +#define TAPE_DRIVE_EOT_WZ_SIZE 0x00002000 + +#define TAPE_DRIVE_ECC 0x00010000 +#define TAPE_DRIVE_COMPRESSION 0x00020000 +#define TAPE_DRIVE_PADDING 0x00040000 +#define TAPE_DRIVE_REPORT_SMKS 0x00080000 + +#define TAPE_DRIVE_GET_ABSOLUTE_BLK 0x00100000 +#define TAPE_DRIVE_GET_LOGICAL_BLK 0x00200000 +#define TAPE_DRIVE_SET_EOT_WZ_SIZE 0x00400000 + +#define TAPE_DRIVE_EJECT_MEDIA 0x01000000 +#define TAPE_DRIVE_CLEAN_REQUESTS 0x02000000 +#define TAPE_DRIVE_SET_CMP_BOP_ONLY 0x04000000 + +#define TAPE_DRIVE_RESERVED_BIT 0x80000000 //don't use this bit! +// //can't be a low features bit! +// //reserved; high features only + +// +// Definitions for FeaturesHigh parameter +// + +#define TAPE_DRIVE_LOAD_UNLOAD 0x80000001 +#define TAPE_DRIVE_TENSION 0x80000002 +#define TAPE_DRIVE_LOCK_UNLOCK 0x80000004 +#define TAPE_DRIVE_REWIND_IMMEDIATE 0x80000008 + +#define TAPE_DRIVE_SET_BLOCK_SIZE 0x80000010 +#define TAPE_DRIVE_LOAD_UNLD_IMMED 0x80000020 +#define TAPE_DRIVE_TENSION_IMMED 0x80000040 +#define TAPE_DRIVE_LOCK_UNLK_IMMED 0x80000080 + +#define TAPE_DRIVE_SET_ECC 0x80000100 +#define TAPE_DRIVE_SET_COMPRESSION 0x80000200 +#define TAPE_DRIVE_SET_PADDING 0x80000400 +#define TAPE_DRIVE_SET_REPORT_SMKS 0x80000800 + +#define TAPE_DRIVE_ABSOLUTE_BLK 0x80001000 +#define TAPE_DRIVE_ABS_BLK_IMMED 0x80002000 +#define TAPE_DRIVE_LOGICAL_BLK 0x80004000 +#define TAPE_DRIVE_LOG_BLK_IMMED 0x80008000 + +#define TAPE_DRIVE_END_OF_DATA 0x80010000 +#define TAPE_DRIVE_RELATIVE_BLKS 0x80020000 +#define TAPE_DRIVE_FILEMARKS 0x80040000 +#define TAPE_DRIVE_SEQUENTIAL_FMKS 0x80080000 + +#define TAPE_DRIVE_SETMARKS 0x80100000 +#define TAPE_DRIVE_SEQUENTIAL_SMKS 0x80200000 +#define TAPE_DRIVE_REVERSE_POSITION 0x80400000 +#define TAPE_DRIVE_SPACE_IMMEDIATE 0x80800000 + +#define TAPE_DRIVE_WRITE_SETMARKS 0x81000000 +#define TAPE_DRIVE_WRITE_FILEMARKS 0x82000000 +#define TAPE_DRIVE_WRITE_SHORT_FMKS 0x84000000 +#define TAPE_DRIVE_WRITE_LONG_FMKS 0x88000000 + +#define TAPE_DRIVE_WRITE_MARK_IMMED 0x90000000 +#define TAPE_DRIVE_FORMAT 0xA0000000 +#define TAPE_DRIVE_FORMAT_IMMEDIATE 0xC0000000 +#define TAPE_DRIVE_HIGH_FEATURES 0x80000000 //mask for high features flag + +typedef struct _TAPE_GET_DRIVE_PARAMETERS { + BOOLEAN ECC; + BOOLEAN Compression; + BOOLEAN DataPadding; + BOOLEAN ReportSetmarks; + ULONG DefaultBlockSize; + ULONG MaximumBlockSize; + ULONG MinimumBlockSize; + ULONG MaximumPartitionCount; + ULONG FeaturesLow; + ULONG FeaturesHigh; + ULONG EOTWarningZoneSize; +} TAPE_GET_DRIVE_PARAMETERS, *PTAPE_GET_DRIVE_PARAMETERS; + +// +// IOCTL_TAPE_SET_DRIVE_PARAMETERS definitions +// + +typedef struct _TAPE_SET_DRIVE_PARAMETERS { + BOOLEAN ECC; + BOOLEAN Compression; + BOOLEAN DataPadding; + BOOLEAN ReportSetmarks; + ULONG EOTWarningZoneSize; +} TAPE_SET_DRIVE_PARAMETERS, *PTAPE_SET_DRIVE_PARAMETERS; + +// +// IOCTL_TAPE_GET_MEDIA_PARAMETERS definitions +// + +typedef struct _TAPE_GET_MEDIA_PARAMETERS { + LARGE_INTEGER Capacity; + LARGE_INTEGER Remaining; + ULONG BlockSize; + ULONG PartitionCount; + BOOLEAN WriteProtected; +} TAPE_GET_MEDIA_PARAMETERS, *PTAPE_GET_MEDIA_PARAMETERS; + +// +// IOCTL_TAPE_SET_MEDIA_PARAMETERS definitions +// + +typedef struct _TAPE_SET_MEDIA_PARAMETERS { + ULONG BlockSize; +} TAPE_SET_MEDIA_PARAMETERS, *PTAPE_SET_MEDIA_PARAMETERS; + +// +// IOCTL_TAPE_CREATE_PARTITION definitions +// + +#define TAPE_FIXED_PARTITIONS 0L +#define TAPE_SELECT_PARTITIONS 1L +#define TAPE_INITIATOR_PARTITIONS 2L + +typedef struct _TAPE_CREATE_PARTITION { + ULONG Method; + ULONG Count; + ULONG Size; +} TAPE_CREATE_PARTITION, *PTAPE_CREATE_PARTITION; + + +// +// WMI Methods +// +#define TAPE_QUERY_DRIVE_PARAMETERS 0L +#define TAPE_QUERY_MEDIA_CAPACITY 1L +#define TAPE_CHECK_FOR_DRIVE_PROBLEM 2L +#define TAPE_QUERY_IO_ERROR_DATA 3L +#define TAPE_QUERY_DEVICE_ERROR_DATA 4L + +typedef struct _TAPE_WMI_OPERATIONS { + ULONG Method; + ULONG DataBufferSize; + PVOID DataBuffer; +} TAPE_WMI_OPERATIONS, *PTAPE_WMI_OPERATIONS; + +// +// Type of drive errors +// +typedef enum _TAPE_DRIVE_PROBLEM_TYPE { + TapeDriveProblemNone, TapeDriveReadWriteWarning, + TapeDriveReadWriteError, TapeDriveReadWarning, + TapeDriveWriteWarning, TapeDriveReadError, + TapeDriveWriteError, TapeDriveHardwareError, + TapeDriveUnsupportedMedia, TapeDriveScsiConnectionError, + TapeDriveTimetoClean, TapeDriveCleanDriveNow, + TapeDriveMediaLifeExpired, TapeDriveSnappedTape +} TAPE_DRIVE_PROBLEM_TYPE; + +#endif +// end_winnt end_ntminitape + +#ifdef __cplusplus +} +#endif + + +#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */ +#pragma endregion + +#if _MSC_VER >= 1200 +#pragma warning(pop) +#endif + +#endif // _NTDDTAPE_ + diff --git a/src/MaksIT.LTO.Backup.sln b/src/MaksIT.LTO.Backup.sln new file mode 100644 index 0000000..9d1b64f --- /dev/null +++ b/src/MaksIT.LTO.Backup.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaksIT.LTO.Backup", "MaksIT.LTO.Backup\MaksIT.LTO.Backup.csproj", "{8E6B7295-1579-4FF7-914C-7CF6CD5C67C9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaksIT.LTO.Core", "MaksIT.LTO.Core\MaksIT.LTO.Core.csproj", "{EA1BAEAB-248C-47D6-85B7-C2C0CDC9FCAF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8E6B7295-1579-4FF7-914C-7CF6CD5C67C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E6B7295-1579-4FF7-914C-7CF6CD5C67C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E6B7295-1579-4FF7-914C-7CF6CD5C67C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E6B7295-1579-4FF7-914C-7CF6CD5C67C9}.Release|Any CPU.Build.0 = Release|Any CPU + {EA1BAEAB-248C-47D6-85B7-C2C0CDC9FCAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA1BAEAB-248C-47D6-85B7-C2C0CDC9FCAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA1BAEAB-248C-47D6-85B7-C2C0CDC9FCAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA1BAEAB-248C-47D6-85B7-C2C0CDC9FCAF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D228D2F6-B38A-412B-870E-0B579D8203D6} + EndGlobalSection +EndGlobal diff --git a/src/MaksIT.LTO.Backup/Application.cs b/src/MaksIT.LTO.Backup/Application.cs new file mode 100644 index 0000000..e5e2480 --- /dev/null +++ b/src/MaksIT.LTO.Backup/Application.cs @@ -0,0 +1,432 @@ +using System.Text; +using System.Text.Json; +using System.Diagnostics.CodeAnalysis; + +using MaksIT.LTO.Core; +using MaksIT.LTO.Backup.Entities; + +namespace MaksIT.LTO.Backup; +public class Application { + + private const string _descriptoFileName = "descriptor.json"; + private const string _configurationFileName = "configuration.json"; + + private readonly string appPath = AppDomain.CurrentDomain.BaseDirectory; + private readonly string _tapePath; + private readonly string _descriptorFilePath; + + private Configuration _configuration; + + public Application() { + _descriptorFilePath = Path.Combine(appPath, _descriptoFileName); + LoadConfiguration(); + + _tapePath = _configuration.TapePath; + } + + [MemberNotNull(nameof(_configuration))] + public void LoadConfiguration() { + var configFilePath = Path.Combine(appPath, _configurationFileName); + var configuration = JsonSerializer.Deserialize(File.ReadAllText(configFilePath)); + if (configuration == null) + throw new InvalidOperationException("Failed to deserialize configuration."); + + _configuration = configuration; + } + + public void LoadTape() { + using var handler = new TapeDeviceHandler(_tapePath); + LoadTape(handler); + } + + public void LoadTape(TapeDeviceHandler handler) { + handler.Prepare(TapeDeviceHandler.TAPE_LOAD); + Thread.Sleep(2000); + + Console.WriteLine("Tape loaded."); + } + + public void EjectTape() { + using var handler = new TapeDeviceHandler(_tapePath); + EjectTape(handler); + } + + public void EjectTape(TapeDeviceHandler handler) { + handler.Prepare(TapeDeviceHandler.TAPE_UNLOAD); + Thread.Sleep(2000); + + Console.WriteLine("Tape ejected."); + } + + public void CreateDescriptor(string directoryPath, string descriptorFilePath, uint blockSize) { + var files = Directory.GetFiles(directoryPath, "*.*", SearchOption.AllDirectories); + + // Define list to hold file descriptors + var descriptor = new List(); + uint currentTapeBlock = 0; + + foreach (var filePath in files) { + var fileInfo = new FileInfo(filePath); + var relativePath = Path.GetRelativePath(directoryPath, filePath); + var numberOfBlocks = (uint)((fileInfo.Length + blockSize - 1) / blockSize); + + // Optional: Calculate a simple hash for file integrity (e.g., MD5) + using var md5 = System.Security.Cryptography.MD5.Create(); + using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); + using var bufferedStream = new BufferedStream(fileStream, (int)blockSize); + + byte[] buffer = new byte[blockSize]; + int bytesRead; + while ((bytesRead = bufferedStream.Read(buffer, 0, buffer.Length)) > 0) { + md5.TransformBlock(buffer, 0, bytesRead, null, 0); + } + md5.TransformFinalBlock(Array.Empty(), 0, 0); + string fileHash = BitConverter.ToString(md5.Hash).Replace("-", "").ToLower(); + + descriptor.Add(new FileDescriptor { + StartBlock = currentTapeBlock, // Position of the file on the tape + NumberOfBlocks = numberOfBlocks, // Number of blocks used by the file + FilePath = relativePath, + FileSize = fileInfo.Length, + CreationTime = fileInfo.CreationTime, + LastModifiedTime = fileInfo.LastWriteTime, + FileHash = fileHash + }); + + currentTapeBlock += numberOfBlocks; + } + + // Convert descriptor list to JSON and include BlockSize + string descriptorJson = JsonSerializer.Serialize(new BackupDescriptor { + BlockSize = blockSize, + Files = descriptor + }); + + File.WriteAllText(descriptorFilePath, descriptorJson); + } + + private void ZeroFillBlocks(TapeDeviceHandler handler, int blocks, uint blockSize) { + Console.WriteLine($"Writing {blocks} zero-filled blocks to tape."); + Console.WriteLine($"Block Size: {blockSize}."); + + for (int i = 0; i < blocks; i++) { + handler.WriteData(new byte[blockSize]); + Thread.Sleep(100); + } + } + + public void WriteFilesToTape(string directoryPath, string descriptorFilePath, uint blockSize) { + Console.WriteLine($"Writing files to tape from: {directoryPath}."); + Console.WriteLine($"Block Size: {blockSize}."); + + using var handler = new TapeDeviceHandler(_tapePath); + + LoadTape(handler); + + handler.SetMediaParams(blockSize); + + handler.SetPosition(TapeDeviceHandler.TAPE_REWIND); + Thread.Sleep(2000); + + handler.Prepare(TapeDeviceHandler.TAPE_TENSION); + Thread.Sleep(2000); + + handler.Prepare(TapeDeviceHandler.TAPE_LOCK); + Thread.Sleep(2000); + + handler.WaitForTapeReady(); + + // Read descriptor from file system + string descriptorJson = File.ReadAllText(descriptorFilePath); + var descriptor = JsonSerializer.Deserialize(descriptorJson); + + if (descriptor == null) { + throw new InvalidOperationException("Failed to deserialize descriptor."); + } + + var currentTapeBlock = (descriptorJson.Length + blockSize - 1) / blockSize; + + foreach (var file in descriptor.Files) { + var filePath = Path.Combine(directoryPath, file.FilePath); + using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); + using var bufferedStream = new BufferedStream(fileStream, (int)blockSize); + + byte[] buffer = new byte[blockSize]; + int bytesRead; + for (var i = 0; i < file.NumberOfBlocks; i++) { + bytesRead = bufferedStream.Read(buffer, 0, buffer.Length); + if (bytesRead < buffer.Length) { + // Zero-fill the remaining part of the buffer if the last block is smaller than blockSize + Array.Clear(buffer, bytesRead, buffer.Length - bytesRead); + } + handler.WriteData(buffer); + currentTapeBlock++; + Thread.Sleep(100); // Small delay between blocks + } + } + + + // write mark to indicate end of files + handler.WriteMarks(TapeDeviceHandler.TAPE_FILEMARKS, 1); + + // write descriptor to tape + var descriptorData = Encoding.UTF8.GetBytes(descriptorJson); + var descriptorBlocks = (descriptorData.Length + blockSize - 1) / blockSize; + for (int i = 0; i < descriptorBlocks; i++) { + var startIndex = i * blockSize; + var length = Math.Min(blockSize, descriptorData.Length - startIndex); + byte[] block = new byte[blockSize]; // Initialized with zeros by default + Array.Copy(descriptorData, startIndex, block, 0, length); + handler.WriteData(block); + currentTapeBlock++; + Thread.Sleep(100); // Small delay between blocks + } + + // write 3 0 filled blocks to indicate end of backup + ZeroFillBlocks(handler, 3, blockSize); + + handler.Prepare(TapeDeviceHandler.TAPE_UNLOCK); + Thread.Sleep(2000); + handler.SetPosition(TapeDeviceHandler.TAPE_REWIND); + Thread.Sleep(2000); + } + + public BackupDescriptor? FindDescriptor(uint blockSize) { + Console.WriteLine("Searching for descriptor on tape..."); + Console.WriteLine($"Block Size: {blockSize}."); + + using var handler = new TapeDeviceHandler(_tapePath); + + LoadTape(handler); + + handler.SetMediaParams(blockSize); + + handler.SetPosition(TapeDeviceHandler.TAPE_REWIND); + Thread.Sleep(2000); + + handler.SetPosition(TapeDeviceHandler.TAPE_SPACE_FILEMARKS, 0, 1); + Thread.Sleep(2000); + + handler.WaitForTapeReady(); + + // Read data from tape until 3 zero-filled blocks are found + var buffer = new List(); + byte[] data; + var zeroBlocks = 0; + do { + data = handler.ReadData(blockSize); + buffer.AddRange(data); + if (data.All(b => b == 0)) { + zeroBlocks++; + } + else { + zeroBlocks = 0; + } + } while (zeroBlocks < 3); + + // Remove the last 3 zero-filled blocks from the buffer + var totalZeroBlocksSize = (int)(3 * blockSize); + if (buffer.Count >= totalZeroBlocksSize) { + buffer.RemoveRange(buffer.Count - totalZeroBlocksSize, totalZeroBlocksSize); + } + + // Convert buffer to byte array + var byteArray = buffer.ToArray(); + + // Convert byte array to string and trim ending zeros + var json = Encoding.UTF8.GetString(byteArray).TrimEnd('\0'); + + try { + var descriptor = JsonSerializer.Deserialize(json); + if (descriptor != null) { + Console.WriteLine("Descriptor read successfully."); + return descriptor; + } + } + catch (JsonException ex) { + Console.WriteLine($"Failed to parse descriptor JSON: {ex.Message}"); + } + + + handler.Prepare(TapeDeviceHandler.TAPE_UNLOCK); + Thread.Sleep(2000); + handler.SetPosition(TapeDeviceHandler.TAPE_REWIND); + Thread.Sleep(2000); + + return null; + } + + public void RestoreDirectory(BackupDescriptor descriptor, string restoreDirectoryPath) { + Console.WriteLine("Restoring files to directory: " + restoreDirectoryPath); + Console.WriteLine("Block Size: " + descriptor.BlockSize); + + using var handler = new TapeDeviceHandler(_tapePath); + + LoadTape(handler); + + handler.SetMediaParams(descriptor.BlockSize); + + handler.SetPosition(TapeDeviceHandler.TAPE_REWIND); + Thread.Sleep(2000); + + handler.WaitForTapeReady(); + + foreach (var file in descriptor.Files) { + // Set position to the start block of the file + handler.SetPosition(TapeDeviceHandler.TAPE_ABSOLUTE_BLOCK, 0, file.StartBlock); + Thread.Sleep(2000); + + var filePath = Path.Combine(restoreDirectoryPath, file.FilePath); + var directoryPath = Path.GetDirectoryName(filePath); + if (directoryPath != null) { + Directory.CreateDirectory(directoryPath); + } + + using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write)) { + var buffer = new byte[descriptor.BlockSize]; + + for (var i = 0; i < file.NumberOfBlocks; i++) { + var bytesRead = handler.ReadData(buffer, 0, buffer.Length); + if (bytesRead < buffer.Length) { + // Zero-fill the remaining part of the buffer if the last block is smaller than blockSize + Array.Clear(buffer, bytesRead, buffer.Length - bytesRead); + } + + var bytesToWrite = (i == file.NumberOfBlocks - 1) ? (int)(file.FileSize % descriptor.BlockSize) : buffer.Length; + fileStream.Write(buffer, 0, bytesToWrite); + } + } + + // check md5 checksum of restored file with the one in descriptor + using (var md5 = System.Security.Cryptography.MD5.Create()) { + using (var fileStreamRead = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { + var fileHash = md5.ComputeHash(fileStreamRead); + var fileHashString = BitConverter.ToString(fileHash).Replace("-", "").ToLower(); + + if (fileHashString != file.FileHash) { + Console.WriteLine($"Checksum mismatch for file: {filePath}"); + } + else { + Console.WriteLine($"Restored file: {filePath}"); + } + } + } + } + + handler.SetPosition(TapeDeviceHandler.TAPE_REWIND); + Thread.Sleep(2000); + } + + public int CheckMediaSize(string ltoGen) { + var descriptor = JsonSerializer.Deserialize(File.ReadAllText(_descriptorFilePath)); + if (descriptor == null) { + Console.WriteLine("Failed to read descriptor."); + return 1; + } + + var totalBlocks = (ulong)descriptor.Files.Sum(f => f.NumberOfBlocks); + + const ulong fileMarkBlocks = 1; + const ulong terminalBlocks = 3; + + var descriptorSize = new FileInfo(_descriptoFileName).Length; + ulong descriptorSizeBlocks = (ulong)Math.Ceiling((double)descriptorSize / descriptor.BlockSize); + + totalBlocks += fileMarkBlocks + descriptorSizeBlocks + terminalBlocks; + + var maxBlocks = LTOBlockSizes.GetMaxBlocks(ltoGen); + if (totalBlocks > maxBlocks) { + Console.WriteLine("Backup will not fit on tape. Please use a larger tape."); + return 1; + } + else { + Console.WriteLine("Backup will fit on tape."); + } + + return 0; + } + + public void Backup() { + while (true) { + Console.WriteLine("\nSelect a backup to perform:"); + for (int i = 0; i < _configuration.Backups.Count; i++) { + var backupInt = _configuration.Backups[i]; + Console.WriteLine($"{i + 1}. Backup Name: {backupInt.Name}, Bar code {backupInt.Barcode}, Source: {backupInt.Source}, Destination: {backupInt.Destination}"); + } + + Console.Write("Enter your choice (or '0' to go back): "); + var choice = Console.ReadLine(); + + if (choice == "0") { + return; // Go back to the main menu + } + + if (!int.TryParse(choice, out int index) || index < 1 || index > _configuration.Backups.Count) { + Console.WriteLine("Invalid choice. Please try again."); + continue; + } + + var backup = _configuration.Backups[index - 1]; + + uint blockSize = LTOBlockSizes.GetBlockSize(backup.LTOGen); + + // Step 1: Create Descriptor and Write to File System + CreateDescriptor(backup.Source, _descriptorFilePath, blockSize); + + // Step 2: calculate if files in descriptor will fit on tape + var checkMediaSizeResult = CheckMediaSize(backup.LTOGen); + if (checkMediaSizeResult != 0) + return; + + // Step 3: Write Files to Tape + WriteFilesToTape(backup.Source, _descriptorFilePath, blockSize); + + File.Delete(_descriptorFilePath); + Console.WriteLine("Backup completed."); + return; // Go back to the main menu after completing the backup + } + } + + public void Restore() { + while (true) { + Console.WriteLine("\nSelect a backup to restore:"); + for (int i = 0; i < _configuration.Backups.Count; i++) { + var backupInt = _configuration.Backups[i]; + Console.WriteLine($"{i + 1}. Backup Name: {backupInt.Name}, Bar code {backupInt.Barcode}, Source: {backupInt.Source}, Destination: {backupInt.Destination}"); + } + + Console.Write("Enter your choice (or '0' to go back): "); + var choice = Console.ReadLine(); + + if (choice == "0") { + return; // Go back to the main menu + } + + if (!int.TryParse(choice, out int index) || index < 1 || index > _configuration.Backups.Count) { + Console.WriteLine("Invalid choice. Please try again."); + continue; + } + + var backup = _configuration.Backups[index - 1]; + + uint blockSize = LTOBlockSizes.GetBlockSize(backup.LTOGen); + + var descriptor = FindDescriptor(blockSize); + if (descriptor != null) { + var json = JsonSerializer.Serialize(descriptor, new JsonSerializerOptions { WriteIndented = true }); + Console.WriteLine(json); + } + + if (descriptor == null) { + Console.WriteLine("Descriptor not found on tape."); + return; + } + + // Step 3: Test restore from tape + RestoreDirectory(descriptor, backup.Destination); + Console.WriteLine("Restore completed."); + return; // Go back to the main menu after completing the restore + } + } +} + diff --git a/src/MaksIT.LTO.Backup/Configuration.cs b/src/MaksIT.LTO.Backup/Configuration.cs new file mode 100644 index 0000000..140e3f0 --- /dev/null +++ b/src/MaksIT.LTO.Backup/Configuration.cs @@ -0,0 +1,14 @@ +namespace MaksIT.LTO.Backup; + +public class BackupItem { + public required string Name { get; set; } + public required string Barcode { get; set; } + public required string Source { get; set; } + public required string Destination { get; set; } + public required string LTOGen { get; set; } +} + +public class Configuration { + public required string TapePath { get; set; } + public required List Backups { get; set; } +} diff --git a/src/MaksIT.LTO.Backup/Entities/BackupDescriptor.cs b/src/MaksIT.LTO.Backup/Entities/BackupDescriptor.cs new file mode 100644 index 0000000..c1d4f89 --- /dev/null +++ b/src/MaksIT.LTO.Backup/Entities/BackupDescriptor.cs @@ -0,0 +1,8 @@ + + +namespace MaksIT.LTO.Backup.Entities; +public class BackupDescriptor { + public uint ReservedBlocks { get; set; } + public uint BlockSize { get; set; } + public List Files { get; set; } = new List(); +} diff --git a/src/MaksIT.LTO.Backup/Entities/FileDescriptor.cs b/src/MaksIT.LTO.Backup/Entities/FileDescriptor.cs new file mode 100644 index 0000000..6977ba7 --- /dev/null +++ b/src/MaksIT.LTO.Backup/Entities/FileDescriptor.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MaksIT.LTO.Backup.Entities; +public class FileDescriptor { + public required string FilePath { get; set; } + public long StartBlock { get; set; } + public uint NumberOfBlocks { get; set; } + public long FileSize { get; set; } + public DateTime CreationTime { get; set; } + public DateTime LastModifiedTime { get; set; } + public required string FileHash { get; set; } +} diff --git a/src/MaksIT.LTO.Backup/MaksIT.LTO.Backup.csproj b/src/MaksIT.LTO.Backup/MaksIT.LTO.Backup.csproj new file mode 100644 index 0000000..4de6d32 --- /dev/null +++ b/src/MaksIT.LTO.Backup/MaksIT.LTO.Backup.csproj @@ -0,0 +1,20 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + PreserveNewest + + + + diff --git a/src/MaksIT.LTO.Backup/Program.cs b/src/MaksIT.LTO.Backup/Program.cs new file mode 100644 index 0000000..52f9cc5 --- /dev/null +++ b/src/MaksIT.LTO.Backup/Program.cs @@ -0,0 +1,58 @@ +namespace MaksIT.LTO.Backup; + +class Program { + + public static void Main() { + + var app = new Application(); + + Console.OutputEncoding = System.Text.Encoding.UTF8; + + while (true) { + // Console.Clear(); + Console.WriteLine("MaksIT.LTO.Backup v0.0.1"); + Console.WriteLine("© Maksym Sadovnychyy (MAKS-IT) 2024"); + + Console.WriteLine("\nSelect an action:"); + Console.WriteLine("1. Load tape"); + Console.WriteLine("2. Backup"); + Console.WriteLine("3. Restore"); + Console.WriteLine("4. Eject tape"); + Console.WriteLine("5. Reload configurations"); + Console.WriteLine("6. Exit"); + Console.Write("Enter your choice: "); + + var choice = Console.ReadLine(); + + try { + switch (choice) { + case "1": + app.LoadTape(); + break; + case "2": + app.Backup(); + break; + case "3": + app.Restore(); + break; + case "4": + app.EjectTape(); + break; + + case "5": + app.LoadConfiguration(); + break; + case "6": + Console.WriteLine("Exiting..."); + return; + default: + Console.WriteLine("Invalid choice. Please try again."); + break; + } + } + catch (Exception ex) { + Console.WriteLine($"An error occurred: {ex.Message}"); + } + } + } +} diff --git a/src/MaksIT.LTO.Backup/configuration.json b/src/MaksIT.LTO.Backup/configuration.json new file mode 100644 index 0000000..15dfe46 --- /dev/null +++ b/src/MaksIT.LTO.Backup/configuration.json @@ -0,0 +1,19 @@ +{ + "TapePath": "\\\\.\\Tape0", + "Backups": [ + { + "Name": "Test", + "Barcode": "", + "Source": "F:\\LTO\\Backup", + "Destination": "F:\\LTO\\Restore", + "LTOGen": "LTO5" + }, + { + "Name": "Drivers", + "Barcode": "", + "Source": "D:\\Drivers", + "Destination": "F:\\LTO\\Restore", + "LTOGen": "LTO5" + } + ] +} \ No newline at end of file diff --git a/src/MaksIT.LTO.Core/LTOBlockSizes.cs b/src/MaksIT.LTO.Core/LTOBlockSizes.cs new file mode 100644 index 0000000..7261c2b --- /dev/null +++ b/src/MaksIT.LTO.Core/LTOBlockSizes.cs @@ -0,0 +1,60 @@ + +namespace MaksIT.LTO.Core; + +public static class LTOBlockSizes { + public const uint LTO1 = 65536; // 64 KB + public const uint LTO2 = 65536; // 64 KB + public const uint LTO3 = 131072; // 128 KB + public const uint LTO4 = 131072; // 128 KB + public const uint LTO5 = 262144; // 256 KB + public const uint LTO6 = 262144; // 256 KB + public const uint LTO7 = 524288; // 512 KB + public const uint LTO8 = 524288; // 512 KB + public const uint LTO9 = 1048576; // 1 MB + + // Dictionary to store the total capacity for each LTO generation (in bytes) + private static readonly Dictionary TapeCapacities = new Dictionary + { + { "LTO1", 100UL * 1024 * 1024 * 1024 }, // 100 GB + { "LTO2", 200UL * 1024 * 1024 * 1024 }, // 200 GB + { "LTO3", 400UL * 1024 * 1024 * 1024 }, // 400 GB + { "LTO4", 800UL * 1024 * 1024 * 1024 }, // 800 GB + { "LTO5", 1500UL * 1024 * 1024 * 1024 }, // 1.5 TB + { "LTO6", 2500UL * 1024 * 1024 * 1024 }, // 2.5 TB + { "LTO7", 6000UL * 1024 * 1024 * 1024 }, // 6 TB + { "LTO8", 12000UL * 1024 * 1024 * 1024 },// 12 TB + { "LTO9", 18000UL * 1024 * 1024 * 1024 } // 18 TB + }; + + // Method to get the block size for a given LTO generation + // Method to get the block size for a given LTO generation + public static uint GetBlockSize(string ltoGen) { + return ltoGen switch { + "LTO1" => LTO1, + "LTO2" => LTO2, + "LTO3" => LTO3, + "LTO4" => LTO4, + "LTO5" => LTO5, + "LTO6" => LTO6, + "LTO7" => LTO7, + "LTO8" => LTO8, + "LTO9" => LTO9, + _ => throw new ArgumentException("Invalid LTO generation") + }; + } + + // Method to get the total capacity for a given LTO generation + public static ulong GetTapeCapacity(string ltoGen) { + if (TapeCapacities.TryGetValue(ltoGen, out var capacity)) { + return capacity; + } + throw new ArgumentException("Invalid LTO generation"); + } + + // Method to calculate the maximum number of blocks that can be written on the tape + public static ulong GetMaxBlocks(string ltoGen) { + var blockSize = GetBlockSize(ltoGen); + var tapeCapacity = GetTapeCapacity(ltoGen); + return tapeCapacity / blockSize; + } +} diff --git a/src/MaksIT.LTO.Core/MaksIT.LTO.Core.csproj b/src/MaksIT.LTO.Core/MaksIT.LTO.Core.csproj new file mode 100644 index 0000000..c8734fc --- /dev/null +++ b/src/MaksIT.LTO.Core/MaksIT.LTO.Core.csproj @@ -0,0 +1,10 @@ + + + + net8.0 + enable + enable + NTDDI_VERSION_05010000;NTDDI_WINXP_05010000 + + + diff --git a/src/MaksIT.LTO.Core/TapeDeviceHandler.cs b/src/MaksIT.LTO.Core/TapeDeviceHandler.cs new file mode 100644 index 0000000..149fe21 --- /dev/null +++ b/src/MaksIT.LTO.Core/TapeDeviceHandler.cs @@ -0,0 +1,169 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +// https://github.com/tpn/winsdk-10 + +namespace MaksIT.LTO.Core; + +public partial class TapeDeviceHandler : IDisposable { + private string _tapeDevicePath; + private SafeFileHandle _tapeHandle; + + + + private const uint GENERIC_READ = 0x80000000; + private const uint GENERIC_WRITE = 0x40000000; + private const uint OPEN_EXISTING = 3; + + // Define IOCTL base + private const uint FILE_DEVICE_TAPE = 0x0000001F; + private const uint FILE_DEVICE_MASS_STORAGE = 0x0000002D; + + // Define access rights + private const uint FILE_ANY_ACCESS = 0x0000; // any access + private const uint FILE_READ_ACCESS = 0x0001; // file & pipe + private const uint FILE_WRITE_ACCESS = 0x0002; // file & pipe + + // Define method + private const uint METHOD_BUFFERED = 0; + + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern SafeFileHandle CreateFile( + string lpFileName, + uint dwDesiredAccess, + uint dwShareMode, + IntPtr lpSecurityAttributes, + uint dwCreationDisposition, + uint dwFlagsAndAttributes, + IntPtr hTemplateFile); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool DeviceIoControl( + SafeFileHandle hDevice, + uint dwIoControlCode, + IntPtr lpInBuffer, + uint nInBufferSize, + IntPtr lpOutBuffer, + uint nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool WriteFile( + SafeFileHandle hFile, + IntPtr lpBuffer, + uint nNumberOfBytesToWrite, + out uint lpNumberOfBytesWritten, + IntPtr lpOverlapped); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool ReadFile( + SafeFileHandle hFile, + IntPtr lpBuffer, + uint nNumberOfBytesToRead, + out uint lpNumberOfBytesRead, + IntPtr lpOverlapped); + + public TapeDeviceHandler(string tapeDevicePath) { + _tapeDevicePath = tapeDevicePath; + OpenTapeDevice(GENERIC_READ | GENERIC_WRITE); + } + + [MemberNotNull(nameof(_tapeHandle))] + private void OpenTapeDevice(uint desiredAccess) { + _tapeHandle?.Dispose(); + _tapeHandle = CreateFile(_tapeDevicePath, desiredAccess, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); + if (_tapeHandle.IsInvalid) { + throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); + } + } + + + public void WriteData(byte[] data) { + IntPtr unmanagedPointer = Marshal.AllocHGlobal(data.Length); + try { + Marshal.Copy(data, 0, unmanagedPointer, data.Length); + bool result = WriteFile(_tapeHandle, unmanagedPointer, (uint)data.Length, out uint bytesWritten, IntPtr.Zero); + + if (result) { + Console.WriteLine("Write Data: Success"); + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Write Data: Failed with error code {error}"); + } + } + finally { + Marshal.FreeHGlobal(unmanagedPointer); + } + } + + public byte[] ReadData(uint length) { + byte[] data = new byte[length]; + IntPtr unmanagedPointer = Marshal.AllocHGlobal((int)length); + try { + bool result = ReadFile(_tapeHandle, unmanagedPointer, length, out uint bytesRead, IntPtr.Zero); + + if (result) { + Marshal.Copy(unmanagedPointer, data, 0, (int)length); + Console.WriteLine("Read Data: Success"); + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Read Data: Failed with error code {error}"); + } + } + finally { + Marshal.FreeHGlobal(unmanagedPointer); + } + return data; + } + + public int ReadData(byte[] buffer, int offset, int length) { + IntPtr unmanagedPointer = Marshal.AllocHGlobal(length); + try { + bool result = ReadFile(_tapeHandle, unmanagedPointer, (uint)length, out uint bytesRead, IntPtr.Zero); + + if (result) { + Marshal.Copy(unmanagedPointer, buffer, offset, (int)bytesRead); + Console.WriteLine("Read Data: Success"); + return (int)bytesRead; + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Read Data: Failed with error code {error}"); + return 0; + } + } + finally { + Marshal.FreeHGlobal(unmanagedPointer); + } + } + + public void WaitForTapeReady() { + bool isReady = false; + while (!isReady) { + Console.WriteLine("Checking if tape is ready..."); + int errorCode = GetStatus(); + if (errorCode == 0) // Assuming 0 means success/ready + { + isReady = true; + Console.WriteLine("Tape is ready."); + } + else { + Console.WriteLine($"Tape not ready, status code: {errorCode}. Retrying..."); + Thread.Sleep(1000); // Wait 1 second before checking again + } + } + } + + + + + public void Dispose() { + _tapeHandle?.Dispose(); + } +} diff --git a/src/MaksIT.LTO.Core/TapeDeviceHandlerNtdstor.cs b/src/MaksIT.LTO.Core/TapeDeviceHandlerNtdstor.cs new file mode 100644 index 0000000..68b76f4 --- /dev/null +++ b/src/MaksIT.LTO.Core/TapeDeviceHandlerNtdstor.cs @@ -0,0 +1,811 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +namespace MaksIT.LTO.Core; + +public partial class TapeDeviceHandler : IDisposable +{ + + #region Storage IOCTL Commands from ntddstor.h + + // + // The following device control codes are common for all class drivers. They + // should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE + // common codes + // + private const uint IOCTL_STORAGE_CHECK_VERIFY = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0200 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_CHECK_VERIFY2 = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0200 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_MEDIA_REMOVAL = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0201 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_EJECT_MEDIA = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0202 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_LOAD_MEDIA = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0203 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_LOAD_MEDIA2 = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0203 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_RESERVE = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0204 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_RELEASE = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0205 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_FIND_NEW_DEVICES = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0206 << 2) | METHOD_BUFFERED; + + private const uint IOCTL_STORAGE_EJECTION_CONTROL = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0250 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_MCN_CONTROL = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0251 << 2) | METHOD_BUFFERED; + + private const uint IOCTL_STORAGE_GET_MEDIA_TYPES = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0300 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_GET_MEDIA_TYPES_EX = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0301 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0304 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_GET_HOTPLUG_INFO = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0305 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_SET_HOTPLUG_INFO = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0306 << 2) | METHOD_BUFFERED; + + private const uint IOCTL_STORAGE_RESET_BUS = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0400 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_RESET_DEVICE = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0401 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_BREAK_RESERVATION = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0405 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_PERSISTENT_RESERVE_IN = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0406 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_PERSISTENT_RESERVE_OUT = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0407 << 2) | METHOD_BUFFERED; + + // + // This IOCTL includes the same information as IOCTL_STORAGE_GET_DEVICE_NUMBER, plus the device GUID. + // + private const uint IOCTL_STORAGE_GET_DEVICE_NUMBER = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0420 << 2) | METHOD_BUFFERED; + + + private const uint IOCTL_STORAGE_PREDICT_FAILURE = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0440 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0441 << 2) | METHOD_BUFFERED; + + // + // This IOCTL retrieves reliability counters for a device. + // + private const uint IOCTL_STORAGE_GET_COUNTERS = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x442 << 2) | METHOD_BUFFERED; + + private const uint IOCTL_STORAGE_READ_CAPACITY = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0450 << 2) | METHOD_BUFFERED; + + // + // IOCTLs 0x0463 to 0x0468 reserved for dependent disk support. + // + + // + // IOCTLs 0x0470 to 0x047f reserved for device and stack telemetry interfaces + // + + private const uint IOCTL_STORAGE_GET_DEVICE_TELEMETRY = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0470 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_DEVICE_TELEMETRY_NOTIFY = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0471 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_DEVICE_TELEMETRY_QUERY_CAPS = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0472 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_GET_DEVICE_TELEMETRY_RAW = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0473 << 2) | METHOD_BUFFERED; + + private const uint IOCTL_STORAGE_SET_TEMPERATURE_THRESHOLD = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0480 << 2) | METHOD_BUFFERED; + + private const uint IOCTL_STORAGE_PROTOCOL_COMMAND = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x04F0 << 2) | METHOD_BUFFERED; + + private const uint IOCTL_STORAGE_QUERY_PROPERTY = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0500 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_WRITE_ACCESS << 14) | (0x0501 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_GET_LB_PROVISIONING_MAP_RESOURCES = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0502 << 2) | METHOD_BUFFERED; + + // + // IOCTLs 0x0503 to 0x0580 reserved for Enhanced Storage devices. + // + + // + // This IOCTL offloads the erasure process to the storage device. There is no guarantee as to the successful + // deletion or recoverability of the data on the storage device after command completion. This IOCTL is limited + // to data disks in regular Windows. In WinPE, this IOCTL is supported for both boot and data disks. + // + // Initial implementation requires no input and returns no output other than status. Callers should first + // call FSCTL_LOCK_VOLUME before calling this ioctl to flush out cached data in upper layers. No waiting of + // outstanding request completion is done before issuing the command to the device. + // + private const uint IOCTL_STORAGE_REINITIALIZE_MEDIA = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_WRITE_ACCESS << 14) | (0x0503 << 2) | METHOD_BUFFERED; + + // + // IOCTLs for bandwidth contracts on storage devices + // (Move this to ntddsfio if we decide to use a new base) + // + + private const uint IOCTL_STORAGE_GET_BC_PROPERTIES = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_READ_ACCESS << 14) | (0x0600 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_ALLOCATE_BC_STREAM = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0601 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_FREE_BC_STREAM = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0602 << 2) | METHOD_BUFFERED; + + // + // IOCTL to check for priority support + // + private const uint IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0620 << 2) | METHOD_BUFFERED; + + // + // IOCTL for data integrity check support + // + + private const uint IOCTL_STORAGE_START_DATA_INTEGRITY_CHECK = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0621 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_STOP_DATA_INTEGRITY_CHECK = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0622 << 2) | METHOD_BUFFERED; + + // + // These ioctl codes are obsolete. They are defined here to avoid resuing them + // and to allow class drivers to respond to them more easily. + // + + private const uint OBSOLETE_IOCTL_STORAGE_RESET_BUS = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0400 << 2) | METHOD_BUFFERED; + private const uint OBSOLETE_IOCTL_STORAGE_RESET_DEVICE = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0401 << 2) | METHOD_BUFFERED; + + // + // IOCTLs 0x0643 to 0x0655 reserved for VHD disk support. + // + + + // + // IOCTLs for firmware upgrade on storage devices + // + + private const uint IOCTL_STORAGE_FIRMWARE_GET_INFO = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0700 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_FIRMWARE_DOWNLOAD = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0701 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_FIRMWARE_ACTIVATE = (FILE_DEVICE_MASS_STORAGE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0702 << 2) | METHOD_BUFFERED; + + // + // IOCTL to support Idle Power Management, including Device Wake + // + private const uint IOCTL_STORAGE_ENABLE_IDLE_POWER = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0720 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_GET_IDLE_POWERUP_REASON = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0721 << 2) | METHOD_BUFFERED; + + // + // IOCTLs to allow class drivers to acquire and release active references on + // a unit. These should only be used if the class driver previously sent a + // successful IOCTL_STORAGE_ENABLE_IDLE_POWER request to the port driver. + // + private const uint IOCTL_STORAGE_POWER_ACTIVE = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0722 << 2) | METHOD_BUFFERED; + private const uint IOCTL_STORAGE_POWER_IDLE = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0723 << 2) | METHOD_BUFFERED; + + // + // This IOCTL indicates that the physical device has triggered some sort of event. + // + private const uint IOCTL_STORAGE_EVENT_NOTIFICATION = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0724 << 2) | METHOD_BUFFERED; + + // + // IOCTL to specify a power cap for a storage device. + // + private const uint IOCTL_STORAGE_DEVICE_POWER_CAP = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0725 << 2) | METHOD_BUFFERED; + + // + // IOCTL to send commands to the RPMB for a storage device. + // + private const uint IOCTL_STORAGE_RPMB_COMMAND = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0726 << 2) | METHOD_BUFFERED; + + // + // IOCTL to manage attributes for storage devices + // + private const uint IOCTL_STORAGE_ATTRIBUTE_MANAGEMENT = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0727 << 2) | METHOD_BUFFERED; + + // + // IOCTL_STORAGE_DIAGNOSTIC IOCTL to query diagnostic data from the storage driver stack + // + private const uint IOCTL_STORAGE_DIAGNOSTIC = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0728 << 2) | METHOD_BUFFERED; + + // + // IOCTLs for storage device depopulation support. + // + + // + // IOCTL_STORAGE_GET_PHYSICAL_ELEMENT_STATUS IOCTL to query physical element status from device. + // + private const uint IOCTL_STORAGE_GET_PHYSICAL_ELEMENT_STATUS = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0729 << 2) | METHOD_BUFFERED; + + // + // IOCTL_STORAGE_SET_PHYSICAL_ELEMENT_STATUS IOCTL to set physical element status on device. + // + private const uint IOCTL_STORAGE_REMOVE_ELEMENT_AND_TRUNCATE = (FILE_DEVICE_MASS_STORAGE << 16) | (FILE_ANY_ACCESS << 14) | (0x0730 << 2) | METHOD_BUFFERED; + + #endregion + + #region Storage IOCTL Structures from ntddstor.h + + // + // Note: Function code values of less than 0x800 are reserved for Microsoft. Values of 0x800 and higher can be used by vendors. + // So do not use function code of 0x800 and higher to define new IOCTLs in this file. + // + + + // + // IOCTL_STORAGE_GET_HOTPLUG_INFO + // + + [StructLayout(LayoutKind.Sequential)] + public struct STORAGE_HOTPLUG_INFO + { + public uint Size; // version + public bool MediaRemovable; // ie. zip, jaz, cdrom, mo, etc. vs hdd + public bool MediaHotplug; // ie. does the device succeed a lock even though its not lockable media? + public bool DeviceHotplug; // ie. 1394, USB, etc. + public bool WriteCacheEnableOverride; // This field should not be relied upon because it is no longer used + } + + // + // IOCTL_STORAGE_GET_DEVICE_NUMBER + // + // input - none + // + // output - STORAGE_DEVICE_NUMBER structure + // The values in the STORAGE_DEVICE_NUMBER structure are guaranteed + // to remain unchanged until the system is rebooted. They are not + // guaranteed to be persistant across boots. + + [StructLayout(LayoutKind.Sequential)] + public struct STORAGE_DEVICE_NUMBER + { + // + // The FILE_DEVICE_XXX type for this device. + // + + public uint DeviceType; + + // + // The number of this device + // + + public uint DeviceNumber; + + // + // If the device is partitionable, the partition number of the device. + // Otherwise -1 + // + + public uint PartitionNumber; + } + + [StructLayout(LayoutKind.Sequential)] + public struct _STORAGE_DEVICE_NUMBERS + { + public uint NumberOfDeviceNumbers; + public STORAGE_DEVICE_NUMBER DeviceNumber; + } + + // + // IOCTL_STORAGE_GET_DEVICE_NUMBER_EX + // + // input - none + // + // output - STORAGE_DEVICE_NUMBER_EX structure + // + + // + // Possible flags that can be set in Flags field of + // STORAGE_DEVICE_NUMBER_EX structure defined below + // + + // + // This flag indicates that deviceguid is randomly created because a deviceguid conflict was observed + // + public const uint STORAGE_DEVICE_FLAGS_RANDOM_DEVICEGUID = 0x1; + + // + // This flag indicates that deviceguid is randomly created because the HW ID was not available + // + public const uint STORAGE_DEVICE_FLAGS_DEFAULT_DEVICEGUID = 0x2; + + // + // This flag indicates that deviceguid is created from the scsi page83 data. + // If this flag is not set this implies it's created from serial number or is randomly generated. + // + public const uint STORAGE_DEVICE_FLAGS_DEVICEGUID_FROM_PAGE83 = 0x4; + + [StructLayout(LayoutKind.Sequential)] + public struct STORAGE_DEVICE_NUMBER_EX + { + // + // Sizeof(STORAGE_DEVICE_NUMBER_EX). + // + public uint Version; + + // + // Total size of the structure, including any additional data. Currently + // this will always be the same as sizeof(STORAGE_DEVICE_NUMBER_EX). + // + public uint Size; + + // + // Flags for the device + // + + public uint Flags; + + // + // The FILE_DEVICE_XXX type for this device. + // + + public uint DeviceType; + + // + // The number of this device + // + + public uint DeviceNumber; + + // + // A globally-unique identification number for this device. + // A GUID of {0} indicates that a GUID could not be generated. The GUID + // is based on hardware information that doesn't change with firmware updates + // (for instance, serial number can be used to form the GUID, but not the firmware + // revision). The device GUID remains the same across reboots. + // + // In general, if a device exposes a globally unique identifier, the storage driver + // will use that identifier to form the GUID. Otherwise, the storage driver will combine + // the device's vendor ID, product ID and serial number to create the GUID. + // + // If a storage driver detects two devices with the same hardware information (which is + // an indication of a problem with the device), the driver will generate a random GUID for + // one of the two devices. When handling IOCTL_STORAGE_GET_DEVICE_NUMBER_EX for the device + // with the random GUID, the driver will add STORAGE_DEVICE_FLAGS_RANDOM_DEVICEGUID_REASON_CONFLICT + // to the Flags member of this structure. + // + // If a storage device does not provide any identifying information, the driver will generate a random + // GUID and add STORAGE_DEVICE_FLAGS_RANDOM_DEVICEGUID_REASON_NOHWID to the Flags member of this structure. + // + // A random GUID is not persisted and will not be the same after a reboot. + // + + public Guid DeviceGuid; + + + // + // If the device is partitionable, the partition number of the device. + // Otherwise -1 + // + + public uint PartitionNumber; + } + + // + // Define the structures for scsi resets + // + + [StructLayout(LayoutKind.Sequential)] + public struct STORAGE_BUS_RESET_REQUEST + { + public byte PathId; + } + + // + // Break reservation is sent to the Adapter/FDO with the given lun information. + // + + [StructLayout(LayoutKind.Sequential)] + public struct STORAGE_BREAK_RESERVATION_REQUEST + { + public uint Length; + public byte _unused; + + public byte PathId; + + public byte TargetId; + + public byte Lun; + } + + // + // IOCTL_STORAGE_MEDIA_REMOVAL disables the mechanism + // on a storage device that ejects media. This function + // may or may not be supported on storage devices that + // support removable media. + // + // TRUE means prevent media from being removed. + // FALSE means allow media removal. + // + + [StructLayout(LayoutKind.Sequential)] + public struct PREVENT_MEDIA_REMOVAL + { + public bool PreventMediaRemoval; + } + + // + // This is the format of TARGET_DEVICE_CUSTOM_NOTIFICATION.CustomDataBuffer + // passed to applications by the classpnp autorun code (via IoReportTargetDeviceChangeAsynchronous). + // + + [StructLayout(LayoutKind.Sequential)] + public struct CLASS_MEDIA_CHANGE_CONTEXT { + public uint MediaChangeCount; + public uint NewState; + } + + // begin_ntminitape + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_STATISTICS + { + public uint Version; + public uint Flags; + public ulong RecoveredWriteOperations; + public ulong UnrecoveredWriteOperations; + public ulong RecoveredReadOperations; + public ulong UnrecoveredReadOperations; + public byte CompressionRatioRead; + public byte CompressionRatioWrite; + } + + public uint RECOVERED_WRITES_VALID = 0x00000001; + public uint UNRECOVERED_WRITES_VALID = 0x00000002; + public uint RECOVERED_READS_VALID = 0x00000004; + public uint UNRECOVERED_READS_VALID = 0x00000008; + public uint WRITE_COMPRESSION_INFO_VALID = 0x00000010; + public uint READ_COMPRESSION_INFO_VALID = 0x00000020; + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_GET_STATISTICS + { + public uint Operation; + } + + public uint TAPE_RETURN_STATISTICS = 0; + public uint TAPE_RETURN_ENV_INFO = 1; + public uint TAPE_RESET_STATISTICS = 2; + + // + // IOCTL_STORAGE_GET_MEDIA_TYPES_EX will return an array of DEVICE_MEDIA_INFO + // structures, one per supported type, embedded in the GET_MEDIA_TYPES struct. + // + + public enum STORAGE_MEDIA_TYPE + { + // Unknown, // Format is unknown + // F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector + // F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector + // F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector + // F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector + // F3_720_512, // 3.5", 720KB, 512 bytes/sector + // F5_360_512, // 5.25", 360KB, 512 bytes/sector + // F5_320_512, // 5.25", 320KB, 512 bytes/sector + // F5_320_1024, // 5.25", 320KB, 1024 bytes/sector + // F5_180_512, // 5.25", 180KB, 512 bytes/sector + // F5_160_512, // 5.25", 160KB, 512 bytes/sector + // RemovableMedia, // Removable media other than floppy + // FixedMedia, // Fixed hard disk media + // F3_120M_512, // 3.5", 120M Floppy + // F3_640_512, // 3.5" , 640KB, 512 bytes/sector + // F5_640_512, // 5.25", 640KB, 512 bytes/sector + // F5_720_512, // 5.25", 720KB, 512 bytes/sector + // F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector + // F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector + // F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector + // F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector + // F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector + // F8_256_128, // 8", 256KB, 128 bytes/sector + // F3_200Mb_512, // 3.5", 200M Floppy (HiFD) + + DDS_4mm = 0x20, // Tape - DAT DDS1,2,... (all vendors) + MiniQic, // Tape - miniQIC Tape + Travan, // Tape - Travan TR-1,2,3,... + QIC, // Tape - QIC + MP_8mm, // Tape - 8mm Exabyte Metal Particle + AME_8mm, // Tape - 8mm Exabyte Advanced Metal Evap + AIT1_8mm, // Tape - 8mm Sony AIT + DLT, // Tape - DLT Compact IIIxt, IV + NCTP, // Tape - Philips NCTP + IBM_3480, // Tape - IBM 3480 + IBM_3490E, // Tape - IBM 3490E + IBM_Magstar_3590, // Tape - IBM Magstar 3590 + IBM_Magstar_MP, // Tape - IBM Magstar MP + STK_DATA_D3, // Tape - STK Data D3 + SONY_DTF, // Tape - Sony DTF + DV_6mm, // Tape - 6mm Digital Video + DMI, // Tape - Exabyte DMI and compatibles + SONY_D2, // Tape - Sony D2S and D2L + CLEANER_CARTRIDGE, // Cleaner - All Drive types that support Drive Cleaners + CD_ROM, // Opt_Disk - CD + CD_R, // Opt_Disk - CD-Recordable (Write Once) + CD_RW, // Opt_Disk - CD-Rewriteable + DVD_ROM, // Opt_Disk - DVD-ROM + DVD_R, // Opt_Disk - DVD-Recordable (Write Once) + DVD_RW, // Opt_Disk - DVD-Rewriteable + MO_3_RW, // Opt_Disk - 3.5" Rewriteable MO Disk + MO_5_WO, // Opt_Disk - MO 5.25" Write Once + MO_5_RW, // Opt_Disk - MO 5.25" Rewriteable (not LIMDOW) + MO_5_LIMDOW, // Opt_Disk - MO 5.25" Rewriteable (LIMDOW) + PC_5_WO, // Opt_Disk - Phase Change 5.25" Write Once Optical + PC_5_RW, // Opt_Disk - Phase Change 5.25" Rewriteable + PD_5_RW, // Opt_Disk - PhaseChange Dual Rewriteable + ABL_5_WO, // Opt_Disk - Ablative 5.25" Write Once Optical + PINNACLE_APEX_5_RW, // Opt_Disk - Pinnacle Apex 4.6GB Rewriteable Optical + SONY_12_WO, // Opt_Disk - Sony 12" Write Once + PHILIPS_12_WO, // Opt_Disk - Philips/LMS 12" Write Once + HITACHI_12_WO, // Opt_Disk - Hitachi 12" Write Once + CYGNET_12_WO, // Opt_Disk - Cygnet/ATG 12" Write Once + KODAK_14_WO, // Opt_Disk - Kodak 14" Write Once + MO_NFR_525, // Opt_Disk - Near Field Recording (Terastor) + NIKON_12_RW, // Opt_Disk - Nikon 12" Rewriteable + IOMEGA_ZIP, // Mag_Disk - Iomega Zip + IOMEGA_JAZ, // Mag_Disk - Iomega Jaz + SYQUEST_EZ135, // Mag_Disk - Syquest EZ135 + SYQUEST_EZFLYER, // Mag_Disk - Syquest EzFlyer + SYQUEST_SYJET, // Mag_Disk - Syquest SyJet + AVATAR_F2, // Mag_Disk - 2.5" Floppy + MP2_8mm, // Tape - 8mm Hitachi + DST_S, // Ampex DST Small Tapes + DST_M, // Ampex DST Medium Tapes + DST_L, // Ampex DST Large Tapes + VXATape_1, // Ecrix 8mm Tape + VXATape_2, // Ecrix 8mm Tape + #if NTDDI_VERSION_05010000 + STK_EAGLE, // STK Eagle + #elif NTDDI_WINXP_05010000 + STK_9840, // STK 9840 + #endif + LTO_Ultrium, // IBM, HP, Seagate LTO Ultrium + LTO_Accelis, // IBM, HP, Seagate LTO Accelis + DVD_RAM, // Opt_Disk - DVD-RAM + AIT_8mm, // AIT2 or higher + ADR_1, // OnStream ADR Mediatypes + ADR_2, + STK_9940, // STK 9940 + SAIT, // SAIT Tapes + VXATape // VXA (Ecrix 8mm) Tape + } + + public const uint MEDIA_ERASEABLE = 0x00000001; + public const uint MEDIA_WRITE_ONCE = 0x00000002; + public const uint MEDIA_READ_ONLY = 0x00000004; + public const uint MEDIA_READ_WRITE = 0x00000008; + + public const uint MEDIA_WRITE_PROTECTED = 0x00000100; + public const uint MEDIA_CURRENTLY_MOUNTED = 0x80000000; + + // + // Define the different storage bus types + // Bus types below 128 (0x80) are reserved for Microsoft use + // + + public enum STORAGE_BUS_TYPE + { + BusTypeUnknown = 0x00, + BusTypeScsi, + BusTypeAtapi, + BusTypeAta, + BusType1394, + BusTypeSsa, + BusTypeFibre, + BusTypeUsb, + BusTypeRAID, + BusTypeiSCSI, + BusTypeSas, + BusTypeSata, + BusTypeSd, + BusTypeMmc, + BusTypeVirtual, + BusTypeFileBackedVirtual, + BusTypeSpaces, + BusTypeNvme, + BusTypeSCM, + BusTypeUfs, + BusTypeMax, + BusTypeMaxReserved = 0x7F + } + + + // + // Macro to identify which bus types + // support shared storage + // + + + public static bool SupportsDeviceSharing(STORAGE_BUS_TYPE busType) + { + return busType == STORAGE_BUS_TYPE.BusTypeScsi || + busType == STORAGE_BUS_TYPE.BusTypeFibre || + busType == STORAGE_BUS_TYPE.BusTypeiSCSI || + busType == STORAGE_BUS_TYPE.BusTypeSas || + busType == STORAGE_BUS_TYPE.BusTypeSpaces; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DEVICE_MEDIA_INFO + { + [StructLayout(LayoutKind.Sequential)] + public struct DiskInfoStruct + { + public long Cylinders; // LARGE_INTEGER + public STORAGE_MEDIA_TYPE MediaType; + public uint TracksPerCylinder; + public uint SectorsPerTrack; + public uint BytesPerSector; + public uint NumberMediaSides; + public uint MediaCharacteristics; // Bitmask of MEDIA_XXX values. + } + + [StructLayout(LayoutKind.Sequential)] + public struct RemovableDiskInfoStruct + { + public long Cylinders; // LARGE_INTEGER + public STORAGE_MEDIA_TYPE MediaType; + public uint TracksPerCylinder; + public uint SectorsPerTrack; + public uint BytesPerSector; + public uint NumberMediaSides; + public uint MediaCharacteristics; // Bitmask of MEDIA_XXX values. + } + + [StructLayout(LayoutKind.Sequential)] + public struct TapeInfoStruct + { + public STORAGE_MEDIA_TYPE MediaType; + public uint MediaCharacteristics; // Bitmask of MEDIA_XXX values. + public uint CurrentBlockSize; + public STORAGE_BUS_TYPE BusType; + + [StructLayout(LayoutKind.Sequential)] + public struct ScsiInformationStruct + { + public byte MediumType; + public byte DensityCode; + } + + [StructLayout(LayoutKind.Explicit)] + public struct BusSpecificDataUnion + { + [FieldOffset(0)] + public ScsiInformationStruct ScsiInformation; + } + + public BusSpecificDataUnion BusSpecificData; + } + + [StructLayout(LayoutKind.Explicit)] + public struct DeviceSpecificUnion + { + [FieldOffset(0)] + public DiskInfoStruct DiskInfo; + + [FieldOffset(0)] + public RemovableDiskInfoStruct RemovableDiskInfo; + + [FieldOffset(0)] + public TapeInfoStruct TapeInfo; + } + + public DeviceSpecificUnion DeviceSpecific; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GET_MEDIA_TYPES + { + public uint DeviceType; // FILE_DEVICE_XXX values + public uint MediaInfoCount; + public DEVICE_MEDIA_INFO MediaInfo; + } + + // + // IOCTL_STORAGE_PREDICT_FAILURE + // + // input - none + // + // output - STORAGE_PREDICT_FAILURE structure + // PredictFailure returns zero if no failure predicted and non zero + // if a failure is predicted. + // + // VendorSpecific returns 512 bytes of vendor specific information + // if a failure is predicted + // + + [StructLayout(LayoutKind.Sequential)] + public struct STORAGE_PREDICT_FAILURE + { + public uint PredictFailure; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] + public byte[] VendorSpecific; + } + + // + // IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG + // + // Input - STORAGE_FAILURE_PREDICTION_CONFIG structure. + // If the sender wants to enable or disable failure prediction then + // the sender should set the "Set" field to TRUE. + // Output - STORAGE_FAILURE_PREDICTION_CONFIG structure. + // If successful, the "Enabled" field will indicate if failure + // prediction is currently enabled or not. + // + + [StructLayout(LayoutKind.Sequential)] + public struct STORAGE_FAILURE_PREDICTION_CONFIG + { + public uint Version; // ULONG in C++ is equivalent to uint in C# + public uint Size; // ULONG in C++ is equivalent to uint in C# + public byte Set; // BOOLEAN in C++ is equivalent to byte in C# + public byte Enabled; // BOOLEAN in C++ is equivalent to byte in C# + public ushort Reserved; // USHORT in C++ is equivalent to ushort in C# + } + + public const uint STORAGE_FAILURE_PREDICTION_CONFIG_V1 = 1; + + // end_ntminitape + + // + // Property Query Structures + // + + // + // IOCTL_STORAGE_QUERY_PROPERTY + // + // Input Buffer: + // a STORAGE_PROPERTY_QUERY structure which describes what type of query + // is being done, what property is being queried for, and any additional + // parameters which a particular property query requires. + // + // Output Buffer: + // Contains a buffer to place the results of the query into. Since all + // property descriptors can be cast into a STORAGE_DESCRIPTOR_HEADER, + // the IOCTL can be called once with a small buffer then again using + // a buffer as large as the header reports is necessary. + // + + + // + // Types of queries + // + + public enum STORAGE_QUERY_TYPE + { + PropertyStandardQuery = 0, // Retrieves the descriptor + PropertyExistsQuery, // Used to test whether the descriptor is supported + PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the descriptor + PropertyQueryMaxDefined // use to validate the value + } + + // + // define some initial property id's + // + + public enum STORAGE_PROPERTY_ID + { + StorageDeviceProperty = 0, + StorageAdapterProperty, + StorageDeviceIdProperty, + StorageDeviceUniqueIdProperty, // See storduid.h for details + StorageDeviceWriteCacheProperty, + StorageMiniportProperty, + StorageAccessAlignmentProperty, + StorageDeviceSeekPenaltyProperty, + StorageDeviceTrimProperty, + StorageDeviceWriteAggregationProperty, + StorageDeviceDeviceTelemetryProperty, + StorageDeviceLBProvisioningProperty, + StorageDevicePowerProperty, + StorageDeviceCopyOffloadProperty, + StorageDeviceResiliencyProperty, + StorageDeviceMediumProductType, + StorageAdapterRpmbProperty, + StorageAdapterCryptoProperty, + // end_winioctl + StorageDeviceTieringProperty, + StorageDeviceFaultDomainProperty, + StorageDeviceClusportProperty, + // begin_winioctl + StorageDeviceIoCapabilityProperty = 48, + StorageAdapterProtocolSpecificProperty, + StorageDeviceProtocolSpecificProperty, + StorageAdapterTemperatureProperty, + StorageDeviceTemperatureProperty, + StorageAdapterPhysicalTopologyProperty, + StorageDevicePhysicalTopologyProperty, + StorageDeviceAttributesProperty, + StorageDeviceManagementStatus, + StorageAdapterSerialNumberProperty, + StorageDeviceLocationProperty, + StorageDeviceNumaProperty, + StorageDeviceZonedDeviceProperty, + StorageDeviceUnsafeShutdownCount + } + + // + // Query structure - additional parameters for specific queries can follow + // the header + // + + [StructLayout(LayoutKind.Sequential)] + public struct STORAGE_PROPERTY_QUERY + { + public STORAGE_PROPERTY_ID PropertyId; + public STORAGE_QUERY_TYPE QueryType; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public byte[] AdditionalParameters; + } + + + #endregion + + #region Storage IOCTL Methods from ntddstor.h + + #endregion +} diff --git a/src/MaksIT.LTO.Core/TapeDeviceHandlerNtdtape.cs b/src/MaksIT.LTO.Core/TapeDeviceHandlerNtdtape.cs new file mode 100644 index 0000000..66a312d --- /dev/null +++ b/src/MaksIT.LTO.Core/TapeDeviceHandlerNtdtape.cs @@ -0,0 +1,673 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +namespace MaksIT.LTO.Core; + +public partial class TapeDeviceHandler : IDisposable { + + #region Tape IOCTL Commands from ntddtape.h + + // + // NtDeviceIoControlFile IoControlCode values for this device. + // + // Warning: Remember that the low two bits of the code specify how the + // buffers are passed to the driver! + // + + private const uint IOCTL_TAPE_ERASE = (FILE_DEVICE_TAPE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0000 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_PREPARE = (FILE_DEVICE_TAPE << 16) | ((FILE_READ_ACCESS) << 14) | (0x0001 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_WRITE_MARKS = (FILE_DEVICE_TAPE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0002 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_GET_POSITION = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0003 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_SET_POSITION = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0004 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_GET_DRIVE_PARAMS = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0005 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_SET_DRIVE_PARAMS = (FILE_DEVICE_TAPE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x0006 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_GET_MEDIA_PARAMS = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0007 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_SET_MEDIA_PARAMS = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0008 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_GET_STATUS = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0009 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_CREATE_PARTITION = (FILE_DEVICE_TAPE << 16) | ((FILE_READ_ACCESS | FILE_WRITE_ACCESS) << 14) | (0x000A << 2) | METHOD_BUFFERED; + + // + // The following device control codes are common for all class drivers. The + // functions codes defined here must match all of the other class drivers. + // + // Warning: these codes will be replaced in the future with the IOCTL_STORAGE + // codes included below + // + + private const uint IOCTL_TAPE_MEDIA_REMOVAL = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0201 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_EJECT_MEDIA = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0202 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_LOAD_MEDIA = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0203 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_RESERVE = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0204 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_RELEASE = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0205 << 2) | METHOD_BUFFERED; + + private const uint IOCTL_TAPE_CHECK_VERIFY = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0200 << 2) | METHOD_BUFFERED; + private const uint IOCTL_TAPE_FIND_NEW_DEVICES = (FILE_DEVICE_TAPE << 16) | (FILE_READ_ACCESS << 14) | (0x0206 << 2) | METHOD_BUFFERED; + + #endregion + + #region Tape IOCTL Structures from ntddtape.h + + // + // IOCTL_TAPE_ERASE definitions + // + + public const uint TAPE_ERASE_SHORT = 0; + public const uint TAPE_ERASE_LONG = 1; + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_ERASE { + public uint Type; // ULONG in C is equivalent to uint in C# + public byte Immediate; // BOOLEAN in C is typically a byte in C# + } + + // + // IOCTL_TAPE_PREPARE definitions + // + + public const uint TAPE_LOAD = 0; + public const uint TAPE_UNLOAD = 1; + public const uint TAPE_TENSION = 2; + public const uint TAPE_LOCK = 3; + public const uint TAPE_UNLOCK = 4; + public const uint TAPE_FORMAT = 5; + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_PREPARE { + public uint Operation; // ULONG in C is equivalent to uint in C# + public byte Immediate; // BOOLEAN in C is typically a byte in C# + } + + // + // IOCTL_TAPE_WRITE_MARKS definitions + // + + public const uint TAPE_SETMARKS = 0; + public const uint TAPE_FILEMARKS = 1; + public const uint TAPE_SHORT_FILEMARKS = 2; + public const uint TAPE_LONG_FILEMARKS = 3; + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_WRITE_MARKS { + public uint Type; // ULONG in C is equivalent to uint in C# + public uint Count; // ULONG in C is equivalent to uint in C# + public byte Immediate; // BOOLEAN in C is typically a byte in C# + } + + // + // IOCTL_TAPE_SET_POSITION definitions + // + + public const uint TAPE_ABSOLUTE_POSITION = 0; + public const uint TAPE_LOGICAL_POSITION = 1; + public const uint TAPE_PSEUDO_LOGICAL_POSITION = 2; + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_GET_POSITION { + public uint Type; + public uint Partition; + public uint OffsetLow; + public uint OffsetHigh; + } + + // + // IOCTL_TAPE_SET_POSITION definitions + // + + public const uint TAPE_REWIND = 0; + public const uint TAPE_ABSOLUTE_BLOCK = 1; + public const uint TAPE_LOGICAL_BLOCK = 2; + public const uint TAPE_PSEUDO_LOGICAL_BLOCK = 3; + public const uint TAPE_SPACE_END_OF_DATA = 4; + public const uint TAPE_SPACE_RELATIVE_BLOCKS = 5; + public const uint TAPE_SPACE_FILEMARKS = 6; + public const uint TAPE_SPACE_SEQUENTIAL_FMKS = 7; + public const uint TAPE_SPACE_SETMARKS = 8; + public const uint TAPE_SPACE_SEQUENTIAL_SMKS = 9; + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_SET_POSITION { + public uint Method; + public uint Partition; + public long Offset; + public byte Immediate; + } + + // + // IOCTL_TAPE_GET_DRIVE_PARAMS definitions + // + + // + // Definitions for FeaturesLow parameter + // + + public const uint TAPE_DRIVE_FIXED = 0x00000001; + public const uint TAPE_DRIVE_SELECT = 0x00000002; + public const uint TAPE_DRIVE_INITIATOR = 0x00000004; + + public const uint TAPE_DRIVE_ERASE_SHORT = 0x00000010; + public const uint TAPE_DRIVE_ERASE_LONG = 0x00000020; + public const uint TAPE_DRIVE_ERASE_BOP_ONLY = 0x00000040; + public const uint TAPE_DRIVE_ERASE_IMMEDIATE = 0x00000080; + + public const uint TAPE_DRIVE_TAPE_CAPACITY = 0x00000100; + public const uint TAPE_DRIVE_TAPE_REMAINING = 0x00000200; + public const uint TAPE_DRIVE_FIXED_BLOCK = 0x00000400; + public const uint TAPE_DRIVE_VARIABLE_BLOCK = 0x00000800; + + public const uint TAPE_DRIVE_WRITE_PROTECT = 0x00001000; + public const uint TAPE_DRIVE_EOT_WZ_SIZE = 0x00002000; + + public const uint TAPE_DRIVE_ECC = 0x00010000; + public const uint TAPE_DRIVE_COMPRESSION = 0x00020000; + public const uint TAPE_DRIVE_PADDING = 0x00040000; + public const uint TAPE_DRIVE_REPORT_SMKS = 0x00080000; + + public const uint TAPE_DRIVE_GET_ABSOLUTE_BLK = 0x00100000; + public const uint TAPE_DRIVE_GET_LOGICAL_BLK = 0x00200000; + public const uint TAPE_DRIVE_SET_EOT_WZ_SIZE = 0x00400000; + + public const uint TAPE_DRIVE_EJECT_MEDIA = 0x01000000; //don't use this bit! + // //can't be a low features bit! + // //reserved; high features only + + // + // Definitions for FeaturesHigh parameter + // + + public const uint TAPE_DRIVE_LOAD_UNLOAD = 0x80000001; + public const uint TAPE_DRIVE_TENSION = 0x80000002; + public const uint TAPE_DRIVE_LOCK_UNLOCK = 0x80000004; + public const uint TAPE_DRIVE_REWIND_IMMEDIATE = 0x80000008; + + public const uint TAPE_DRIVE_SET_BLOCK_SIZE = 0x80000010; + public const uint TAPE_DRIVE_LOAD_UNLD_IMMED = 0x80000040; + public const uint TAPE_DRIVE_TENSION_IMMED = 0x80000080; + public const uint TAPE_DRIVE_LOCK_UNLK_IMMED = 0x80000100; + + public const uint TAPE_DRIVE_SET_ECC = 0x80000200; + public const uint TAPE_DRIVE_SET_COMPRESSION = 0x80000400; + public const uint TAPE_DRIVE_SET_PADDING = 0x80000800; + public const uint TAPE_DRIVE_SET_REPORT_SMKS = 0x80001000; + + public const uint TAPE_DRIVE_ABSOLUTE_BLK = 0x80002000; + public const uint TAPE_DRIVE_ABS_BLK_IMMED = 0x80004000; + public const uint TAPE_DRIVE_LOGICAL_BLK = 0x80008000; + public const uint TAPE_DRIVE_LOG_BLK_IMMED = 0x80010000; + + public const uint TAPE_DRIVE_END_OF_DATA = 0x80020000; + public const uint TAPE_DRIVE_RELATIVE_BLKS = 0x80040000; + public const uint TAPE_DRIVE_FILEMARKS = 0x80080000; + public const uint TAPE_DRIVE_SEQUENTIAL_FMKS = 0x80100000; + + public const uint TAPE_DRIVE_SETMARKS = 0x80200000; + public const uint TAPE_DRIVE_SEQUENTIAL_SMKS = 0x80400000; + public const uint TAPE_DRIVE_REVERSE_POSITION = 0x80800000; + public const uint TAPE_DRIVE_SPACE_IMMEDIATE = 0x81000000; + + public const uint TAPE_DRIVE_WRITE_SETMARKS = 0x82000000; + public const uint TAPE_DRIVE_WRITE_FILEMARKS = 0x84000000; + public const uint TAPE_DRIVE_WRITE_SHORT_FMKS = 0x88000000; + public const uint TAPE_DRIVE_WRITE_LONG_FMKS = 0x90000000; + + public const uint TAPE_DRIVE_WRITE_MARK_IMMED = 0xA0000000; + public const uint TAPE_DRIVE_FORMAT = 0xC0000000; + public const uint TAPE_DRIVE_FORMAT_IMMEDIATE = 0x80000000; + public const uint TAPE_DRIVE_HIGH_FEATURES = 0x80000000; //mask for high features flag + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_GET_DRIVE_PARAMETERS { + public uint ECC; + public uint Compression; + public uint DataPadding; + public uint ReportSetmarks; + public uint DefaultBlockSize; + public uint MaximumBlockSize; + public uint MinimumBlockSize; + public uint MaximumPartitionCount; + public uint FeaturesLow; + public uint FeaturesHigh; + public uint EOTWarningZoneSize; + } + + // + // IOCTL_TAPE_SET_DRIVE_PARAMETERS definitions + // + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_SET_DRIVE_PARAMETERS { + public uint ECC; + public uint Compression; + public uint DataPadding; + public uint ReportSetmarks; + public uint EOTWarningZoneSize; + } + + // + // IOCTL_TAPE_GET_MEDIA_PARAMETERS definitions + // + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_GET_MEDIA_PARAMETERS { + public uint Capacity; + public uint Remaining; + public uint BlockSize; + public uint PartitionCount; + public byte WriteProtected; + } + + // + // IOCTL_TAPE_SET_MEDIA_PARAMETERS definitions + // + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_SET_MEDIA_PARAMETERS { + public uint BlockSize; + } + + // + // IOCTL_TAPE_CREATE_PARTITION definitions + // + + public const uint TAPE_FIXED_PARTITIONS = 0; + public const uint TAPE_SELECT_PARTITIONS = 1; + public const uint TAPE_INITIATOR_PARTITIONS = 2; + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_CREATE_PARTITION { + public uint Method; + public uint Count; + public uint Size; + } + + // + // WMI Methods + // + + public const uint TAPE_QUERY_DRIVE_PARAMETERS = 0; + public const uint TAPE_QUERY_MEDIA_CAPACITY = 1; + public const uint TAPE_CHECK_FOR_DRIVE_PROBLEM = 2; + public const uint TAPE_QUERY_IO_ERROR_DATA = 3; + public const uint TAPE_QUERY_DEVICE_ERROR_DATA = 4; + + [StructLayout(LayoutKind.Sequential)] + public struct TAPE_WMI_OPERATIONS { + public uint Method; + public uint DataBufferSize; + public IntPtr DataBuffer; + } + + // + // Type of drive errors + // + + public enum TAPE_DRIVE_PROBLEM_TYPE { + TapeDriveProblemNone, + TapeDriveReadWriteWarning, + TapeDriveReadWriteError, + TapeDriveReadWarning, + TapeDriveWriteWarning, + TapeDriveReadError, + TapeDriveWriteError, + TapeDriveHardwareError, + TapeDriveUnsupportedMedia, + TapeDriveScsiConnectionError, + TapeDriveTimetoClean, + TapeDriveCleanDriveNow, + TapeDriveMediaLifeExpired, + TapeDriveSnappedTape + } + #endregion + + #region Tape IOCTL Methods from ntddtape.h + + /// + /// Erase the tape + /// + /// The type of erase operation. Valid values are and . + public void Erase(uint type) { + TAPE_ERASE erase = new TAPE_ERASE { + Type = type, + Immediate = 0 + }; + + IntPtr inBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(erase)); + + try { + Marshal.StructureToPtr(erase, inBuffer, false); + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_ERASE, inBuffer, (uint)Marshal.SizeOf(erase), IntPtr.Zero, 0, out uint bytesReturned, IntPtr.Zero); + + if (result) { + Console.WriteLine($"Erase Tape ({type}): Success"); + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Erase Tape: Failed with error code {error}"); + } + } + finally { + Marshal.FreeHGlobal(inBuffer); + } + } + + /// + /// Prepare the tape for a specific operation + /// + /// The type of prepare operation. Valid values are , , and . + public void Prepare(uint operation) { + TAPE_PREPARE prepare = new TAPE_PREPARE { + Operation = operation, + Immediate = 0 + }; + + IntPtr inBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(prepare)); + + try { + Marshal.StructureToPtr(prepare, inBuffer, false); + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_PREPARE, inBuffer, (uint)Marshal.SizeOf(prepare), IntPtr.Zero, 0, out uint bytesReturned, IntPtr.Zero); + + if (result) { + Console.WriteLine($"Prepare Tape ({operation}): Success"); + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Prepare Tape: Failed with error code {error}"); + } + } + finally { + Marshal.FreeHGlobal(inBuffer); + } + } + + /// + /// Write tape marks + /// The type of marks to write. Valid values are , , and . + /// The number of marks to write. + public void WriteMarks(uint type, uint count) { + TAPE_WRITE_MARKS marks = new TAPE_WRITE_MARKS { + Type = type, + Count = count, + Immediate = 0 + }; + + IntPtr inBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(marks)); + + try { + Marshal.StructureToPtr(marks, inBuffer, false); + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_WRITE_MARKS, inBuffer, (uint)Marshal.SizeOf(marks), IntPtr.Zero, 0, out uint bytesReturned, IntPtr.Zero); + + if (result) { + Console.WriteLine("Write Marks: Success"); + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Write Marks: Failed with error code {error}"); + } + } + finally { + Marshal.FreeHGlobal(inBuffer); + } + } + + + public class TapePosition { + public uint? MethodType { get; set; } + public uint? Partition { get; set; } + public uint? OffsetLow { get; set; } + public uint? OffsetHigh { get; set; } + public int? Error { get; set; } + } + + + /// + /// Get the current tape position + /// + /// The type of position to get. Valid values are , and . + /// The partition number. + /// The low offset value. + /// The high offset value. + /// The tape position . + public TapePosition GetPosition(uint type, uint partition = 0, uint offsetLow = 0, uint offsetHigh = 0) { + TAPE_GET_POSITION position = new TAPE_GET_POSITION { + Type = 0, + Partition = partition, + OffsetLow = offsetLow, + OffsetHigh = offsetHigh + }; + + IntPtr outBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(position)); + + try { + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_GET_POSITION, IntPtr.Zero, 0, outBuffer, (uint)Marshal.SizeOf(position), out uint bytesReturned, IntPtr.Zero); + + if (result) { + position = Marshal.PtrToStructure(outBuffer); + Console.WriteLine("Get Position: Success"); + Console.WriteLine($"Type: {position.Type}"); + Console.WriteLine($"Partition: {position.Partition}"); + Console.WriteLine($"OffsetLow: {position.OffsetLow}"); + Console.WriteLine($"OffsetHigh: {position.OffsetHigh}"); + + return new TapePosition { + MethodType = position.Type, + Partition = position.Partition, + OffsetLow = position.OffsetLow, + OffsetHigh = position.OffsetHigh + }; + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Get Position: Failed with error code {error}"); + + return new TapePosition { + Error = error + }; + } + } + finally { + Marshal.FreeHGlobal(outBuffer); + } + } + + /// + /// Set the tape position + /// + /// The method to use for setting the position. Valid values are , , , , , , , , and . + /// The partition number. + /// The offset value. + public void SetPosition(uint method, uint partition = 0, long offset = 0) { + TAPE_SET_POSITION position = new TAPE_SET_POSITION { + Method = method, + Partition = partition, + Offset = offset, + Immediate = 0 + }; + + IntPtr inBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(position)); + try { + Marshal.StructureToPtr(position, inBuffer, false); + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_SET_POSITION, inBuffer, (uint)Marshal.SizeOf(position), IntPtr.Zero, 0, out uint bytesReturned, IntPtr.Zero); + + if (result) { + Console.WriteLine($"Set Position ({method}): Success"); + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Set Position ({method}): Failed with error code {error}"); + } + } + finally { + Marshal.FreeHGlobal(inBuffer); + } + } + + /// + /// Get the drive parameters + /// + /// The maximum block size supported by the drive. + /// The minimum block size supported by the drive. + public void GetDriveParameters(out uint minBlockSize, out uint maxBlockSize) { + TAPE_GET_DRIVE_PARAMETERS driveParams = new TAPE_GET_DRIVE_PARAMETERS { + ECC = 0, + Compression = 0, + DataPadding = 0, + ReportSetmarks = 0, + DefaultBlockSize = 0, + MaximumBlockSize = 0, + MinimumBlockSize = 0, + MaximumPartitionCount = 0, + FeaturesLow = 0, + FeaturesHigh = 0, + EOTWarningZoneSize = 0 + }; + + IntPtr outBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(driveParams)); + try { + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_GET_DRIVE_PARAMS, IntPtr.Zero, 0, outBuffer, (uint)Marshal.SizeOf(driveParams), out uint bytesReturned, IntPtr.Zero); + + if (result) { + driveParams = Marshal.PtrToStructure(outBuffer); + minBlockSize = driveParams.MinimumBlockSize; + maxBlockSize = driveParams.MaximumBlockSize; + Console.WriteLine($"Drive Parameters: MinBlockSize = {minBlockSize}, MaxBlockSize = {maxBlockSize}"); + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Get Drive Parameters Failed with error code {error}"); + minBlockSize = 0; + maxBlockSize = 0; + } + } + finally { + Marshal.FreeHGlobal(outBuffer); + } + } + + /// + /// Set the drive parameters + /// + /// The error correction code (ECC) setting. + /// The compression setting. + /// The data padding setting. + /// The report setmarks setting. + /// The end-of-tape (EOT) warning zone size setting. + public void SetDriveParams(uint ecc, uint compression = 0, uint dataPadding = 0, uint reportSetmarks = 0, uint eotWarningZoneSize = 0) { + TAPE_SET_DRIVE_PARAMETERS driveParams = new TAPE_SET_DRIVE_PARAMETERS { + ECC = ecc, + Compression = compression, + DataPadding = dataPadding, + ReportSetmarks = reportSetmarks, + EOTWarningZoneSize = eotWarningZoneSize + }; + + IntPtr inBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(driveParams)); + + try { + Marshal.StructureToPtr(driveParams, inBuffer, false); + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_SET_DRIVE_PARAMS, inBuffer, (uint)Marshal.SizeOf(driveParams), IntPtr.Zero, 0, out uint bytesReturned, IntPtr.Zero); + + if (result) { + Console.WriteLine("Set Drive Params: Success"); + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Set Drive Params Failed with error code {error}"); + } + } + finally { + Marshal.FreeHGlobal(inBuffer); + } + } + + public void GetMediaParams(uint capacity = 0, uint remaining = 0, uint blockSize = 0, uint partitionCount = 0, byte writeProtected = 0) { + TAPE_GET_MEDIA_PARAMETERS mediaParams = new TAPE_GET_MEDIA_PARAMETERS { + Capacity = 0, + Remaining = 0, + BlockSize = 0, + PartitionCount = 0, + WriteProtected = 0 + }; + + IntPtr outBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(mediaParams)); + + try { + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_GET_MEDIA_PARAMS, IntPtr.Zero, 0, outBuffer, (uint)Marshal.SizeOf(mediaParams), out uint bytesReturned, IntPtr.Zero); + + if (result) { + mediaParams = Marshal.PtrToStructure(outBuffer); + Console.WriteLine("Get Media Params: Success"); + Console.WriteLine($"Capacity: {mediaParams.Capacity}"); + Console.WriteLine($"Remaining: {mediaParams.Remaining}"); + Console.WriteLine($"BlockSize: {mediaParams.BlockSize}"); + Console.WriteLine($"PartitionCount: {mediaParams.PartitionCount}"); + Console.WriteLine($"WriteProtected: {mediaParams.WriteProtected}"); + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Get Media Params Failed with error code {error}"); + } + } + finally { + Marshal.FreeHGlobal(outBuffer); + } + } + + public void SetMediaParams(uint blockSize) { + TAPE_SET_MEDIA_PARAMETERS mediaParams = new TAPE_SET_MEDIA_PARAMETERS { + BlockSize = blockSize + }; + + IntPtr inBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(mediaParams)); + + try { + Marshal.StructureToPtr(mediaParams, inBuffer, false); + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_SET_MEDIA_PARAMS, inBuffer, (uint)Marshal.SizeOf(mediaParams), IntPtr.Zero, 0, out uint bytesReturned, IntPtr.Zero); + + if (!result) { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Set Block Size Failed with error code {error}"); + } + else { + Console.WriteLine($"Set Block Size ({blockSize}): Success"); + } + } + finally { + Marshal.FreeHGlobal(inBuffer); + } + } + + public int GetStatus() { + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_GET_STATUS, IntPtr.Zero, 0, IntPtr.Zero, 0, out uint bytesReturned, IntPtr.Zero); + + if (result) { + Console.WriteLine("Get Status: Success"); + } + else { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Get Status: Failed with error code {error}"); + + return error; + } + + return 0; + } + + public void CreatePartition(uint method = 0, uint count = 0, uint size = 0) { + TAPE_CREATE_PARTITION partition = new TAPE_CREATE_PARTITION { + Method = 0, + Count = 1, + Size = 0 + }; + + bool result = DeviceIoControl(_tapeHandle, IOCTL_TAPE_CREATE_PARTITION, IntPtr.Zero, 0, IntPtr.Zero, 0, out uint bytesReturned, IntPtr.Zero); + + if (!result) { + int error = Marshal.GetLastWin32Error(); + Console.WriteLine($"Create Partition: Failed with error code {error}"); + } + else { + Console.WriteLine("Create Partition: Success"); + } + } + #endregion +} \ No newline at end of file diff --git a/src/MaksIT.LTO.Core/WindowsVersions.cs b/src/MaksIT.LTO.Core/WindowsVersions.cs new file mode 100644 index 0000000..dff6680 --- /dev/null +++ b/src/MaksIT.LTO.Core/WindowsVersions.cs @@ -0,0 +1,15 @@ +namespace MaksIT.LTO.Core; + +public static class WindowsVersions +{ + public const uint NTDDI_WINXP = 0x05010000; // Windows XP + public const uint NTDDI_WINXPSP2 = 0x05010200; // Windows XP SP2 + public const uint NTDDI_WINXPSP3 = 0x05010300; // Windows XP SP3 + public const uint NTDDI_VISTA = 0x06000000; // Windows Vista + public const uint NTDDI_VISTASP1 = 0x06000100; // Windows Vista SP1 + public const uint NTDDI_VISTASP2 = 0x06000200; // Windows Vista SP2 + public const uint NTDDI_WIN7 = 0x06010000; // Windows 7 + public const uint NTDDI_WIN8 = 0x06020000; // Windows 8 + public const uint NTDDI_WINBLUE = 0x06030000; // Windows 8.1 + public const uint NTDDI_WIN10 = 0x0A000000; // Windows 10 +} \ No newline at end of file