root/sys/dev/hptmv/command.h
/*-
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Copyright (c) 2004-2005 HighPoint Technologies, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#ifndef _COMMAND_H_
#define _COMMAND_H_

/***************************************************************************
 * Description: Command
 ***************************************************************************/
typedef struct _AtaCommand
{
        LBA_T            Lba;          /* Current Logic Disk command: LBA   */
        USHORT           nSectors;     /* sector count. May great than 0x80 */  
        UCHAR            Command;      /* IDE_COMMAND_READ, _WRITE, _VERIFY */
        UCHAR            QueueTag;
} AtaComm, *PAtaComm;

typedef struct _PassthroughCmd {
        BYTE     bFeaturesReg;     /* feature register */
        BYTE     bSectorCountReg;  /* IDE sector count register. */
        BYTE     bLbaLowReg; /* IDE sector number register. */
        BYTE     bLbaMidReg;       /* IDE low order cylinder value. */
        BYTE     bLbaHighReg;      /* IDE high order cylinder value. */
        BYTE     bDriveHeadReg;    /* IDE drive/head register. */
        BYTE     bCommandReg;      /* Actual IDE command. Checked for validity by driver. */
        BYTE     nSectors;         /* data transfer */
        ADDRESS  pDataBuffer;      /* data buffer */
}
PassthroughCmd;

/* control commands */
#define CTRL_CMD_REBUILD 1
#define CTRL_CMD_VERIFY  2
#define CTRL_CMD_INIT    3

/* 
 * RAID5 rebuild/verify
 *   Rebuild/verify one stripe line.
 *   The caller needn't supply a buffer for rebuild.
 *   RebuildSectors member will be updated if its previous location is the 
 *   begin of this stripe line.
 */
typedef struct _R5ControlCmd {
        LBA_T  StripeLine;   /* _physical_ stripe line on array */
        USHORT Offset;       /* internal use, don't set */
        UCHAR  Command;      /* CTRL_CMD_XXX */
        UCHAR  reserve1;
}
R5ControlCmd, *PR5ControlCmd;

/* 
 * RAID1 rebuild/verify 
 *   Rebuild/verify specified sectors.
 *   The caller must supply a valid buffer and a physical SG table (or a
 *   pfnBuildSgl routine).
 *   For rebuild/initialize, the buffer size should be nSectors<<9;
 *   For verify, the buffer size should be (nSectors*2)<<9.
 *   RebuildSectors member will be updated if its previous value equals Lba.
 */
typedef struct _R1ControlCmd {
        LBA_T  Lba;
        USHORT nSectors;
        UCHAR  Command;      /* CTRL_CMD_XXX */
        UCHAR  reserve1;
        ADDRESS Buffer;  /* buffer logical address */
#ifdef _MACOSX_
        ADDRESS PhysicalAddress;
#endif
}
R1ControlCmd, *PR1ControlCmd;

typedef struct _Command
{
        PVDevice pVDevice;
        union{
                /* Ide Command */
                AtaComm Ide;
                PassthroughCmd Passthrough;
                /* Atapi Command */
                UCHAR Atapi[12];
                /* Control command */
                R5ControlCmd R5Control;
                R1ControlCmd R1Control;
        } uCmd;
        
        USHORT  cf_physical_sg: 1;
        USHORT  cf_data_in: 1;
        USHORT  cf_data_out: 1;
        USHORT  cf_atapi: 1;
        USHORT  cf_ide_passthrough: 1;
        USHORT  cf_control: 1;

        /* return status */
        UCHAR   Result;
        /* retry count */
        UCHAR   RetryCount;

        /* S/G table address, if already prepared */
        FPSCAT_GATH pSgTable;
        
        /* called if pSgTable is invalid. */
        int (* HPTLIBAPI pfnBuildSgl)(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical);
        
        /* called when this command is finished */
        void (* HPTLIBAPI pfnCompletion)(_VBUS_ARG PCommand pCmd);
        
        /* pointer to original command */
        void *pOrgCommand;


        /* scratch data area */
        union {
                struct {
                        LBA_T      StartLBA;
                        UCHAR      FirstMember;    /* the sequence number of the first member */
                        UCHAR      LastMember;     /* the sequence number of the last member */
                        USHORT     LastSectors;    /* the number of sectors for the last member */
                        USHORT     FirstSectors;   /* the number of sectors for the first member */
                        USHORT     FirstOffset;    /* the offset from the StartLBA for the first member */
                        USHORT     AllMemberBlocks;/* the number of sectors for all member */
                        USHORT     WaitInterrupt;  /* bit map the members who wait interrupt */
                        UCHAR      InSameLine;     /* if the start and end on the same line */
                        UCHAR      pad1;
                } array;
                struct {
                        LBA_T      StartLBA;
                        USHORT     FirstSectors;   /* the number of sectors for the first member */
                        USHORT     FirstOffset;    /* the offset from the StartLBA for the first member */
                        USHORT     WaitInterrupt;  /* bit map the members who wait interrupt */
                        USHORT     r5_gap;         /* see raid5.c */
                        UCHAR      ParDiskNo;      /* parity for startLba */
                        UCHAR      BadDiskNo;
                        UCHAR      FirstMember;
                        UCHAR      pad1;
                } r5;
                struct {
                        PCommand pCmd1;
                        PCommand pCmd2;
                } r5split;
#ifdef _RAID5N_
                struct {
                        ULONG dummy[2]; /* uScratch.wait shall be moved out uScratch.
                                                           now just fix it thisway */
                        struct range_lock *range_lock;
                        struct stripe *stripes[5]; 
                        UCHAR nstripes;
                        UCHAR finished_stripes;
                        USHORT pad2;
                        /* for direct-read: */
                        struct {
                                UCHAR  cmds;
                                UCHAR  finished;
                                UCHAR  first;
                                UCHAR  parity;
                                LBA_T  base;
                                USHORT firstoffset;
                                USHORT firstsectors;
                        } dr;
                } r5n2;
#endif
                struct {
                        ULONG WordsLeft;
                        FPSCAT_GATH pPIOSg;
                        void (* HPTLIBAPI pfnOrgDone)(_VBUS_ARG PCommand pCmd);
#ifdef SUPPORT_HPT584
                        UCHAR cmd;
#endif
                } disk;
                struct {
                        PCommand pNext;
                        void (* HPTLIBAPI WaitEntry)(_VBUS_ARG PCommand pCmd);
                } wait;
                
                struct {
                        PVOID prdAddr;
                        ULONG cmd_priv;
                        USHORT responseFlags;
                        UCHAR  bIdeStatus;
                        UCHAR  errorRegister;
                } sata_param;
        } uScratch;
} Command;

/***************************************************************************
 * command return value
 ***************************************************************************/
#define   RETURN_PENDING             0
#define   RETURN_SUCCESS             1
#define   RETURN_BAD_DEVICE          2
#define   RETURN_BAD_PARAMETER       3
#define   RETURN_WRITE_NO_DRQ        4
#define   RETURN_DEVICE_BUSY         5
#define   RETURN_INVALID_REQUEST     6
#define   RETURN_SELECTION_TIMEOUT   7
#define   RETURN_IDE_ERROR           8
#define   RETURN_NEED_LOGICAL_SG     9
#define   RETURN_NEED_PHYSICAL_SG    10
#define   RETURN_RETRY               11
#define   RETURN_DATA_ERROR          12
#define   RETURN_BUS_RESET           13
#define   RETURN_BAD_TRANSFER_LENGTH 14

typedef void (* HPTLIBAPI DPC_PROC)(_VBUS_ARG void *);
typedef struct _dpc_routine {
        DPC_PROC proc;
        void *arg;
}
DPC_ROUTINE;

/*
 * MAX_QUEUE_COMM is defined in platform related compiler.h
 * to specify the maximum requests allowed (for each VBus) from system.
 *
 * Maximum command blocks needed for each VBus:
 *   Each OS command requests 1+MAX_MEMBERS*2 command blocks (RAID1/0 case)
 *   This space is allocated by platform dependent part, either static or 
 *   dynamic, continuous or non-continuous.
 *   The code only needs _vbus_(pFreeCommands) to be set.
 *
 * PendingRoutines[] size:
 *   Each command may invoke CallAfterReturn once.
 *
 * IdleRoutines[] size:
 *   Each command may invoke CallWhenIdle once.
 */
#define MAX_COMMAND_BLOCKS_FOR_EACH_VBUS (MAX_QUEUE_COMM * (1+MAX_MEMBERS*2) + 1)
#define MAX_PENDING_ROUTINES  (MAX_COMMAND_BLOCKS_FOR_EACH_VBUS+1)
#define MAX_IDLE_ROUTINES     (MAX_COMMAND_BLOCKS_FOR_EACH_VBUS+1)

#define mWaitingForIdle(pVBus) ((pVBus)->IdleRoutinesFirst!=(pVBus)->IdleRoutinesLast)

PCommand HPTLIBAPI AllocateCommand(_VBUS_ARG0);
void FASTCALL FreeCommand(_VBUS_ARG PCommand pCmd);

void FASTCALL CallAfterReturn(_VBUS_ARG DPC_PROC proc, void *arg);
void HPTLIBAPI CheckPendingCall(_VBUS_ARG0);
void FASTCALL CallWhenIdle(_VBUS_ARG DPC_PROC proc, void *arg);
void HPTLIBAPI CheckIdleCall(_VBUS_ARG0);

void HPTLIBAPI AddToWaitingList(PCommand *ppList, PCommand pCmd);
void HPTLIBAPI DoWaitingList(_VBUS_ARG PCommand *ppList);

#endif