#pragma once /// \file port.h /// Definition for AHCI ports #include #include #include "kutil/vector.h" #include "block_device.h" namespace ahci { struct cmd_list_entry; struct cmd_table; struct fis_register_h2d; class hba; enum class sata_signature : uint32_t; enum class port_cmd : uint32_t; struct port_data; /// A port on an AHCI HBA class port : public block_device { public: /// Constructor. /// \arg device The HBA device this port belongs to /// \arg index Index of the port on its HBA /// \arg data Pointer to the device's registers for this port /// \arg impl Whether this port is marked as implemented in the HBA port(hba *device, uint8_t index, port_data volatile *data, bool impl); /// Destructor ~port(); /// Get the index of this port on the HBA /// \returns The port index inline uint8_t index() const { return m_index; } enum class state : uint8_t { unimpl, inactive, active }; /// Get the current state of this device /// \returns An enum representing the state inline state get_state() const { return m_state; } /// Check if this device is active /// \returns True if the device state is active inline bool active() const { return m_state == state::active; } /// Get the type signature of this device /// \returns An enum representing the type of device inline sata_signature get_type() const { return m_type; } /// Update the state of this object from the register data void update(); /// Return whether the port is currently busy bool busy(); /// Start command processing from this port void start_commands(); /// Stop command processing from this port void stop_commands(); /// Start a read operation from the drive. /// \arg offset Offset to start from /// \arg length Number of bytes to read /// \arg dest A buffer where the data will be placed /// \returns A handle to the read operation, or -1 on error int read_async(uint64_t offset, size_t length, void *dest); /// Read from the drive, blocking until finished. /// \arg offset Offset to start from /// \arg length Number of bytes to read /// \arg dest A buffer where the data will be placed /// \returns The number of bytes read virtual size_t read(uint64_t offset, size_t length, void *dest); /// Start an identify operation for the drive. /// \returns A handle to the read operation, or -1 on error int identify_async(); /// Tell the HBA to reconnect to the SATA device. A successful /// reconnect will kick off an identify command. void sata_reconnect(); /// Handle an incoming interrupt void handle_interrupt(); /// Dump the port registers to the console void dump(); private: /// Rebase the port command structures to a new location in system /// memory, to be allocated from the page manager. void rebase(); /// Initialize a command structure /// \arg length The number of bytes of data needed in the PRDs /// \arg fis [out] The FIS for this command /// \returns The index of the command slot, or -1 if none available int make_command(size_t length, fis_register_h2d **fis); /// Send a constructed command to the hardware /// \arg slot The index of the command slot used /// \returns True if the command was successfully sent bool issue_command(int slot); /// Free the data structures allocated by command creation /// \arg slot The index of the command slot used void free_command(int slot); /// Finish a read command started by `read()`. This will /// free the structures allocated, so `free_command()` is /// not necessary. /// \arg slot The command slot that the read command used void finish_read(int slot); /// Finish an identify command started by `identify_async()`. /// This will free the structures allocated, so `free_command()` is /// not necessary. /// \arg slot The command slot that the read command used void finish_identify(int slot); sata_signature m_type; uint8_t m_index; state m_state; hba *m_hba; port_data volatile *m_data; void *m_fis; cmd_list_entry *m_cmd_list; cmd_table *m_cmd_table; enum class command_type : uint8_t { none, read, write, identify, finished }; struct pending { command_type type; uint8_t offset; size_t count; void *data; }; kutil::vector m_pending; }; } // namespace ahci