// SPDX-License-Identifier: MPL-2.0
//
// Do NOT modify or remove this copyright and license
//
// Copyright (c) 2012-2026 Seagate Technology LLC and/or its Affiliates, All Rights Reserved
//
// This software is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// ******************************************************************************************
//
// \file sector_repair.h
// \brief This file defines the functions related to sector repair. This file also contians functions for creating
// uncorrectables on the drive since these functions are useful for testing repairs

#pragma once

#include "operations_Common.h"

#if defined(__cplusplus)
extern "C"
{
#endif

    typedef enum eRepairStatusEnum
    {
        NOT_REPAIRED,
        REPAIR_FAILED,
        REPAIRED,
        REPAIR_NOT_REQUIRED,
        UNABLE_TO_REPAIR_ACCESS_DENIED, // This can happen if the OS blocks our commands to the LBA we are trying to
                                        // repair. Saw this happen on Win10, when a secondary drive with a Win10
                                        // installation on it had errors, we could not repair them. - TJE
    } eRepairStatus;

    typedef struct s_errorLBA
    {
        uint64_t      errorAddress;
        eRepairStatus repairStatus;
    } errorLBA, *ptrErrorLBA;

    typedef const errorLBA* constPtrErrorLBA;

    static M_INLINE void safe_free_error_lba(errorLBA* M_NULLABLE* M_NULLABLE errlba)
    {
        safe_free_core(M_REINTERPRET_CAST(void**, errlba));
    }

    //-----------------------------------------------------------------------------
    //
    //  repair_LBA()
    //
    //! \brief   Description:  This function takes an LBA, then aligns it to the beginning of a physical block, then
    //! issues a write to the full physical block to repair the whole physical block. By doing this, reallocations are
    //! minimized.
    //
    //  Entry:
    //!   \param[in] device = file descriptor
    //!   \param[in] LBA = the LBA to repair
    //!   \param[in] forcePassthroughCommand = boolean value to force sending a SAT passthrough command to repair the
    //!   LBA instead of a SCSI command. This value is ignored on non-ATA devices. \param[in]
    //!   automaticWriteReallocationEnabled = when set to true, will perform write reallocation. If set to false,
    //!   reassign blocks command will be used (ATA translation will be run on ATA drives). Ignored when
    //!   forcePassthroughCommand is set \param[in] automaticReadReallocationEnabled = when set to true, will attempt
    //!   read reallocation before attempting write reallocation or using the reassign blocks command. Ignored when
    //!   forcePassthroughCommand is set
    //!
    //  Exit:
    //!   \return SUCCESS on successful completion, FAILURE = fail
    //
    //-----------------------------------------------------------------------------
    M_PARAM_RO(1)
    M_PARAM_RW(2)
    OPENSEA_OPERATIONS_API eReturnValues repair_LBA(const tDevice* M_NONNULL device,
                                                    ptrErrorLBA M_NONNULL    LBA,
                                                    bool                     forcePassthroughCommand,
                                                    bool                     automaticWriteReallocationEnabled,
                                                    bool                     automaticReadReallocationEnabled);

    //-----------------------------------------------------------------------------
    //
    //  print_LBA_Error_List()
    //
    //! \brief   Description:  This function takes a list of LBAs with errors and their current repair status and prints
    //! it to the screen.
    //
    //  Entry:
    //!   \param[in] LBAs = pointer to the list of LBAs in the ERROR LBA struct type to read and print to the screen
    //!   \param[in] numberOfErrors = this is the number of items in the list to print (list length)
    //!
    //  Exit:
    //
    //-----------------------------------------------------------------------------
    M_PARAM_RO(1)
    OPENSEA_OPERATIONS_API void print_LBA_Error_List(constPtrErrorLBA M_NONNULL LBAs, uint16_t numberOfErrors);

    M_PARAM_RO(1)
    M_PARAM_WO(2)
    M_PARAM_WO(3)
    OPENSEA_OPERATIONS_API eReturnValues
    get_Automatic_Reallocation_Support(const tDevice* M_NONNULL device,
                                       bool* M_NONNULL          automaticWriteReallocationEnabled,
                                       bool* M_NONNULL          automaticReadReallocationEnabled);

    // Use this call to determine if you've already logged an error in the list so that you don't log it again
    M_PARAM_RO(1)
    OPENSEA_OPERATIONS_API
    bool is_LBA_Already_In_The_List(ptrErrorLBA M_NONNULL LBAList, uint32_t numberOfLBAsInTheList, uint64_t lba);

    // Use this call to sort the list of Error LBAs. This will also remove any duplicates it finds and adjust the value
    // of numberOfLBAsInTheList
    M_PARAM_RW(1)
    M_PARAM_RW(2)
    OPENSEA_OPERATIONS_API
    void sort_Error_LBA_List(ptrErrorLBA M_NONNULL LBAList, uint32_t* M_NONNULL numberOfLBAsInTheList);

    M_PARAM_RO(1)
    OPENSEA_OPERATIONS_API uint32_t find_LBA_Entry_In_List(ptrErrorLBA M_NONNULL LBAList,
                                                           uint32_t              numberOfLBAsInTheList,
                                                           uint64_t lba); // returns UINT32_MAX if not found

    M_PARAM_RO(1)
    M_PARAM_RW(2)
    OPENSEA_OPERATIONS_API
    eReturnValues reallocate_LBAs(const tDevice* M_NONNULL device,
                                  ptrErrorLBA M_NONNULL    lbaList,
                                  uint32_t                 lbaListLength);

#if defined(__cplusplus)
}
#endif
