root/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h
/*
 * Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
 * Copyright 2008, Marcus Overhagen.
 * Copyright 2004-2010, Axel Dörfler, axeld@pinc-software.de.
 * Copyright 2002-2003, Thomas Kurschel.
 *
 * Distributed under the terms of the MIT License.
 */
#ifndef ATA_PRIVATE_H
#define ATA_PRIVATE_H


#include <ata_types.h>
#include <bus/ATA.h>
#include <bus/SCSI.h>
#include <condition_variable.h>
#include <device_manager.h>
#include <lock.h>
#include <new>
#include <safemode.h>
#include <scsi_cmds.h>
#include <stdio.h>
#include <string.h>
#include <util/AutoLock.h>

#include "ATACommands.h"
#include "ATAInfoBlock.h"
#include "ATATracing.h"


#define ATA_MAX_DMA_FAILURES            3
#define ATA_STANDARD_TIMEOUT            10 * 1000 * 1000
#define ATA_RELEASE_TIMEOUT                     10 * 1000 * 1000
#define ATA_SIGNATURE_ATA                       0x0000
#define ATA_SIGNATURE_ATAPI                     0xeb14
#define ATA_SIGNATURE_SATA                      0xc33c
#define ATA_SIM_MODULE_NAME                     "bus_managers/ata/sim/driver_v1"
#define ATA_CHANNEL_ID_GENERATOR        "ide/channel_id"
#define ATA_CHANNEL_ID_ITEM                     "ide/channel_id"

enum {
        ATA_DEVICE_READY_REQUIRED       = 0x01,
        ATA_IS_WRITE                            = 0x02,
        ATA_DMA_TRANSFER                        = 0x04,
        ATA_CHECK_ERROR_BIT                     = 0x08,
        ATA_WAIT_FINISH                         = 0x10,
        ATA_WAIT_ANY_BIT                        = 0x20,
        ATA_CHECK_DEVICE_FAULT          = 0x40
};


class ATADevice;
class ATARequest;

extern scsi_for_sim_interface *gSCSIModule;
extern device_manager_info *gDeviceManager;

bool copy_sg_data(scsi_ccb *ccb, uint offset, uint allocationLength,
        void *buffer, int size, bool toBuffer);
void swap_words(void *data, size_t size);


class ATAChannel {
public:
                                                                ATAChannel(device_node *node);
                                                                ~ATAChannel();

                        status_t                        InitCheck();
                        uint32                          ChannelID() const { return fChannelID; }

                        // SCSI stuff
                        void                            SetBus(scsi_bus bus);
                        scsi_bus                        Bus() const { return fSCSIBus; }
                        status_t                        ScanBus();

                        void                            PathInquiry(scsi_path_inquiry *info);
                        void                            GetRestrictions(uint8 targetID, bool *isATAPI,
                                                                        bool *noAutoSense, uint32 *maxBlocks);
                        status_t                        ExecuteIO(scsi_ccb *ccb);
                        status_t                        Control(uint8 targetID, uint32 op, void *buffer,
                                                                        size_t length);

                        // ATA stuff
                        status_t                        SelectDevice(uint8 index);
                        uint8                           SelectedDevice();

                        status_t                        Reset();

                        bool                            UseDMA() const { return fUseDMA; }

                        status_t                        Wait(uint8 setBits, uint8 clearedBits,
                                                                        uint32 flags, bigtime_t timeout);
                        status_t                        WaitDataRequest(bool high);
                        status_t                        WaitDeviceReady();
                        status_t                        WaitForIdle();

                        void                            PrepareWaitingForInterrupt();
                        status_t                        WaitForInterrupt(bigtime_t timeout);
                        status_t                        RecoverLostInterrupt();

                        // request handling
                        status_t                        SendRequest(ATARequest *request, uint32 flags);
                        status_t                        FinishRequest(ATARequest *request, uint32 flags,
                                                                        uint8 errorMask);

                        // data transfers
                        status_t                        PrepareDMA(ATARequest *request);
                        status_t                        StartDMA();
                        status_t                        FinishDMA();

                        status_t                        ExecutePIOTransfer(ATARequest *request);

                        status_t                        ReadRegs(ATADevice *device);
                        uint8                           AltStatus();

                        status_t                        ReadPIO(uint8 *buffer, size_t length);
                        status_t                        WritePIO(uint8 *buffer, size_t length);

                        status_t                        Interrupt(uint8 status);

private:
                        status_t                        _ReadRegs(ata_task_file *taskFile,
                                                                        ata_reg_mask mask);
                        status_t                        _WriteRegs(ata_task_file *taskFile,
                                                                        ata_reg_mask mask);
                        status_t                        _WriteControl(uint8 value);
                        uint8                           _Status();

                        void                            _FlushAndWait(bigtime_t waitTime);

                        bool                            _DevicePresent(int device);

                        status_t                        _ReadPIOBlock(ATARequest *request,
                                                                        size_t length);
                        status_t                        _WritePIOBlock(ATARequest *request,
                                                                        size_t length);
                        status_t                        _TransferPIOBlock(ATARequest *request,
                                                                        size_t length, size_t *transferred);
                        status_t                        _TransferPIOPhysical(ATARequest *request,
                                                                        addr_t physicalAddress, size_t length,
                                                                        size_t *transferred);
                        status_t                        _TransferPIOVirtual(ATARequest *request,
                                                                        uint8 *virtualAddress, size_t length,
                                                                        size_t *transferred);

                        const char *            _DebugContext() { return fDebugContext; }

private:
                        device_node *           fNode;
                        uint32                          fChannelID;
                        ata_controller_interface *fController;
                        void *                          fCookie;

                        spinlock                        fInterruptLock;
                        ConditionVariable       fInterruptCondition;
                        ConditionVariableEntry fInterruptConditionEntry;
                        bool                            fExpectsInterrupt;

                        status_t                        fStatus;
                        scsi_bus                        fSCSIBus;
                        uint8                           fDeviceCount;
                        ATADevice **            fDevices;
                        bool                            fUseDMA;
                        ATARequest *            fRequest;

                        char                            fDebugContext[16];
};


class ATADevice {
public:
                                                                ATADevice(ATAChannel *channel, uint8 index);
        virtual                                         ~ATADevice();

        // SCSI stuff
                        status_t                        ModeSense(ATARequest *request);
                        status_t                        TestUnitReady(ATARequest *request);
                        status_t                        SynchronizeCache(ATARequest *request);
                        status_t                        Eject(ATARequest *request);
                        status_t                        Inquiry(ATARequest *request);
                        status_t                        ReadCapacity(ATARequest *request);
                        status_t                        ReadCapacity16(ATARequest *request);
        virtual status_t                        ExecuteIO(ATARequest *request);

                        void                            GetRestrictions(bool *noAutoSense,
                                                                        uint32 *maxBlocks);
                        status_t                        Control(uint32 op, void *buffer, size_t length);

        // ATA stuff
        virtual bool                            IsATAPI() const { return false; }

                        bool                            UseDMA() const { return fUseDMA; }
                        bool                            Use48Bits() const { return fUse48Bits; }
                        size_t                          BlockSize() const { return fBlockSize; }

                        status_t                        Select();

                        ata_task_file *         TaskFile() { return &fTaskFile; }
                        ata_reg_mask            RegisterMask() const { return fRegisterMask; }

                        status_t                        SetFeature(int feature);
                        status_t                        DisableCommandQueueing();
                        status_t                        ConfigureDMA();

        virtual status_t                        Configure();
                        status_t                        Identify();

                        status_t                        ExecuteReadWrite(ATARequest *request,
                                                                        uint64 address, uint32 sectorCount);

        protected:
                        const char *            _DebugContext() { return fDebugContext; }

                        ATAChannel *            fChannel;
                        ata_device_infoblock fInfoBlock;
                        ata_task_file           fTaskFile;
                        ata_reg_mask            fRegisterMask;

                        bool                            fUseDMA;
                        uint8                           fDMAMode;
                        uint8                           fDMAFailures;

        private:
                        status_t                        _FillTaskFile(ATARequest *request,
                                                                        uint64 address);

                        uint64                          fTotalSectors;
                        size_t                          fBlockSize;
                        size_t                          fPhysicalBlockSize;
                        size_t                          fBlockOffset;
                        uint8                           fIndex;
                        bool                            fUse48Bits;

                        char                            fDebugContext[16];
};


class ATAPIDevice : public ATADevice {
public:
                                                                ATAPIDevice(ATAChannel *channel, uint8 index);
        virtual                                         ~ATAPIDevice();

                        status_t                        SendPacket(ATARequest *request);
        virtual status_t                        ExecuteIO(ATARequest *request);

        virtual bool                            IsATAPI() const { return true; }

        virtual status_t                        Configure();

        private:
                        status_t                        _FillTaskFilePacket(ATARequest *request);
                        status_t                        _FinishRequest(ATARequest *request,
                                                                        uint32 flags);

private:
                        uint8                           fPacket[12];
};


class ATARequest {
public:
                                                                ATARequest(bool hasLock);
                                                                ~ATARequest();

                        void                            SetStatus(uint8 status);
                        uint8                           Status() const { return fStatus; }

                        void                            ClearSense();
                        void                            SetSense(uint8 key, uint16 codeQualifier);
                        uint8                           SenseKey() const { return fSenseKey; }
                        uint8                           SenseCode() const { return fSenseCode; }
                        uint8                           SenseQualifier() const
                                                                        { return fSenseQualifier; }

                        void                            SetDevice(ATADevice *device);
                        ATADevice *                     Device() const { return fDevice; }

                        void                            SetTimeout(bigtime_t timeout);
                        bigtime_t                       Timeout() const { return fTimeout; }

                        void                            SetIsWrite(bool isWrite);
                        bool                            IsWrite() const { return fIsWrite; }

                        void                            SetUseDMA(bool useDMA);
                        bool                            UseDMA() const { return fUseDMA; }

                        void                            SetBytesLeft(uint32 bytesLeft);
                        size_t *                        BytesLeft() { return &fBytesLeft; }

                        bool                            HasData() const
                                                                        { return fCCB->data_length > 0; }
                        bool                            HasSense() const { return fSenseKey != 0; }

                        status_t                        Finish(bool resubmit);

                        // SCSI stuff
                        status_t                        Start(scsi_ccb *ccb);
                        scsi_ccb *                      CCB() { return fCCB; }

                        void                            PrepareSGInfo();
                        void                            AdvanceSG(uint32 bytes);

                        uint32                          SGElementsLeft() const
                                                                        { return fSGElementsLeft; }
                        const physical_entry *CurrentSGElement() const
                                                                        { return fCurrentSGElement; }
                        uint32                          CurrentSGOffset() const
                                                                        { return fCurrentSGOffset; }

                        void                            SetOddByte(uint8 byte);
                        bool                            GetOddByte(uint8 *byte);

                        void                            RequestSense();

private:
                        void                            _FillSense(scsi_sense *sense);

                        const char *            _DebugContext() { return " request"; };

                        mutex                           fLock;
                        bool                            fHasLock;

                        uint8                           fStatus;
                        uint8                           fSenseKey;
                        uint8                           fSenseCode;
                        uint8                           fSenseQualifier;

                        ATADevice *                     fDevice;
                        bigtime_t                       fTimeout;
                        size_t                          fBytesLeft;
                        bool                            fIsWrite;
                        bool                            fUseDMA;
                        scsi_ccb *                      fCCB;

                        uint32                          fSGElementsLeft;
                        const physical_entry *fCurrentSGElement;
                        uint32                          fCurrentSGOffset;
                        bool                            fHasOddByte;
                        uint8                           fOddByte;
};

#endif // ATA_PRIVATE_H