root/usr/src/uts/common/sys/sata/adapters/si3124/si3124var.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#ifndef _SI3124VAR_H
#define _SI3124VAR_H

#ifdef  __cplusplus
extern "C" {
#endif

#define SI3124_MAX_PORTS                4
#define SI3132_MAX_PORTS                2
#define SI3531_MAX_PORTS                1
#define SI_MAX_PORTS                    SI3124_MAX_PORTS

#define SI_LOGBUF_LEN                   512

#define SI_SUCCESS                      (0)     /* successful return */
#define SI_TIMEOUT                      (1)     /* timed out */
#define SI_FAILURE                      (-1)    /* unsuccessful return */

#define SI_MAX_SGT_TABLES_PER_PRB       21844
#define SI_DEFAULT_SGT_TABLES_PER_PRB   85
#define SI_MIN_SGT_TABLES_PER_PRB       1
/*
 * While the si_sge_t and si_sgt_t correspond to the actual SGE and SGT
 * definitions as per the datasheet, the si_sgblock_t (i.e scatter gather
 * block) is a logical data structure which can hold dynamic SGEs and it
 * is tunable through global variables /etc/system si3124:si_dma_sg_number.
 * The idea is to use multiple tunable chained SGT tables per each PRB request.
 */

typedef struct si_sgblock {
        si_sgt_t sgb_sgt[1];
} si_sgblock_t;

/*
 * Each SGT (Scatter Gather Table) has 4 SGEs (Scatter Gather Entries).
 * But each SGT effectively can host only 3 SGEs since the last SGE entry
 * is used to hold a link to the next SGT in the chain. However the last
 * SGT in the chain can host all the 4 entries since it does not need to
 * link any more.
 */
#define SGE_LENGTH(x)   (3*(x)+1)
#define SI_DEFAULT_SGL_LENGTH   SGE_LENGTH(SI_DEFAULT_SGT_TABLES_PER_PRB)

/* Argument to be used for calls to timeout() */
typedef struct si_event_arg {
        void *siea_ctlp;
        int siea_port;
} si_event_arg_t;

typedef struct si_portmult_state {
        int sipm_num_ports;
        uint8_t sipm_port_type[15];
        /* one of PORT_TYPE_[NODEV | MULTIPLIER | ATAPI | DISK | UNKNOWN] */

        /*
         * sipm_port_type[] is good enough to capture the state of ports
         * behind the multiplier. Since any of the port behind a multiplier
         * is accessed through the same main controller port, we don't need
         * additional si_port_state_t here.
         */

} si_portmult_state_t;


/* The following are for port types */
#define PORT_TYPE_NODEV         0x0
#define PORT_TYPE_MULTIPLIER    0x1
#define PORT_TYPE_ATAPI         0x2
#define PORT_TYPE_DISK          0x3
#define PORT_TYPE_UNKNOWN       0x4

/* The following are for active state */
#define PORT_INACTIVE           0x0
#define PORT_ACTIVE             0x1

typedef struct si_port_state {
        struct si_ctl_state *siport_ctlp;       /* back pointer to controller */

        uint8_t siport_port_type;
        /* one of PORT_TYPE_[NODEV | MULTIPLIER | ATAPI | DISK | UNKNOWN] */

        uint8_t siport_active;          /* one of ACTIVE or INACTIVE */

        uint8_t siport_port_num;        /* port number */

        si_portmult_state_t siport_portmult_state;

        si_prb_t *siport_prbpool;       /* These are 31 incore PRBs */
        uint64_t siport_prbpool_physaddr;
        ddi_dma_handle_t siport_prbpool_dma_handle;
        ddi_acc_handle_t siport_prbpool_acc_handle;


        si_sgblock_t *siport_sgbpool;   /* These are 31 incore sg blocks */
        uint64_t siport_sgbpool_physaddr;
        ddi_dma_handle_t siport_sgbpool_dma_handle;
        ddi_acc_handle_t siport_sgbpool_acc_handle;

        kmutex_t siport_mutex;          /* main per port mutex */
        uint32_t siport_pending_tags;   /* remembers the pending tags */
        sata_pkt_t *siport_slot_pkts[SI_NUM_SLOTS];

        /*
         * While the reset is in progress, we don't accept any more commands
         * until we receive the command with SATA_CLEAR_DEV_RESET_STATE flag.
         * However any commands with SATA_IGNORE_DEV_RESET_STATE are allowed in
         * during such blockage.
         */
        int siport_reset_in_progress;

        /* Argument to be used for calls to timeout() */
        si_event_arg_t *siport_event_args;

        /*
         * We mop the commands for either abort, reset, timeout or
         * error handling cases. This counts how many mops are in progress.
         * It is also used to return BUSY in tran_start if a mop is going on.
         */
        int mopping_in_progress;

        /* error recovery related info */
        uint32_t siport_err_tags_SDBERROR;
        uint32_t siport_err_tags_nonSDBERROR;
        int siport_pending_ncq_count;

} si_port_state_t;

/* Warlock annotation */
_NOTE(MUTEX_PROTECTS_DATA(si_port_state_t::siport_mutex, si_port_state_t))
_NOTE(READ_ONLY_DATA(si_port_state_t::siport_prbpool_dma_handle))
_NOTE(READ_ONLY_DATA(si_port_state_t::siport_sgbpool_dma_handle))
_NOTE(DATA_READABLE_WITHOUT_LOCK(si_port_state_t::siport_ctlp))
_NOTE(DATA_READABLE_WITHOUT_LOCK(si_port_state_t::siport_port_num))


typedef struct si_ctl_state {

        dev_info_t *sictl_devinfop;

        int sictl_num_ports;    /* number of controller ports */
        si_port_state_t *sictl_ports[SI_MAX_PORTS];

        int sictl_devid; /* device id of the controller */
        int sictl_flags; /* some important state of controller */
        int sictl_power_level;

        /* pci config space handle */
        ddi_acc_handle_t sictl_pci_conf_handle;

        /* mapping into bar 0 */
        ddi_acc_handle_t sictl_global_acc_handle;
        uintptr_t sictl_global_addr;

        /* mapping into bar 1 */
        ddi_acc_handle_t sictl_port_acc_handle;
        uintptr_t sictl_port_addr;

        struct sata_hba_tran *sictl_sata_hba_tran;
        timeout_id_t sictl_timeout_id;

        kmutex_t sictl_mutex;                   /* per controller mutex */

        ddi_intr_handle_t *sictl_htable;        /* For array of interrupts */
        int sictl_intr_type;                    /* What type of interrupt */
        int sictl_intr_cnt;                     /* # of intrs count returned */
        size_t sictl_intr_size;                 /* Size of intr array */
        uint_t sictl_intr_pri;                  /* Interrupt priority */
        int sictl_intr_cap;                     /* Interrupt capabilities */
        int fm_capabilities;                    /* FMA capabilities */

} si_ctl_state_t;

/* Warlock annotation */
_NOTE(MUTEX_PROTECTS_DATA(si_ctl_state_t::sictl_mutex,
                                        si_ctl_state_t::sictl_ports))
_NOTE(MUTEX_PROTECTS_DATA(si_ctl_state_t::sictl_mutex,
                                        si_ctl_state_t::sictl_power_level))
_NOTE(MUTEX_PROTECTS_DATA(si_ctl_state_t::sictl_mutex,
                                        si_ctl_state_t::sictl_flags))
_NOTE(MUTEX_PROTECTS_DATA(si_ctl_state_t::sictl_mutex,
                                        si_ctl_state_t::sictl_timeout_id))
_NOTE(DATA_READABLE_WITHOUT_LOCK(si_ctl_state_t::sictl_ports))
/*
 * flags for si_flags
 */
#define SI_PM                   0x01
#define SI_ATTACH               0x02
#define SI_DETACH               0x04
#define SI_NO_TIMEOUTS          0x08
#define SI_FRAMEWORK_ATTACHED   0x10    /* are we attached to framework ? */

/* progress values for si_attach */
#define ATTACH_PROGRESS_NONE                    (1<<0)
#define ATTACH_PROGRESS_STATEP_ALLOC            (1<<1)
#define ATTACH_PROGRESS_INIT_FMA                (1<<2)
#define ATTACH_PROGRESS_CONF_HANDLE             (1<<3)
#define ATTACH_PROGRESS_BAR0_MAP                (1<<4)
#define ATTACH_PROGRESS_BAR1_MAP                (1<<5)
#define ATTACH_PROGRESS_INTR_ADDED              (1<<6)
#define ATTACH_PROGRESS_MUTEX_INIT              (1<<7)
#define ATTACH_PROGRESS_HW_INIT                 (1<<8)

#define SI_10MS_TICKS   (drv_usectohz(10000))   /* ticks in 10 millisec */
#define SI_1MS_TICKS    (drv_usectohz(1000))    /* ticks in 1 millisec */
#define SI_1MS_USECS    (1000)                  /* usecs in 1 millisec */
#define SI_POLLRATE_SOFT_RESET          1000
#define SI_POLLRATE_SSTATUS             10
#define SI_POLLRATE_PORTREADY           50
#define SI_POLLRATE_SLOTSTATUS          50
#define SI_POLLRATE_RECOVERPORTMULT     1000

#define PORTMULT_CONTROL_PORT           0xf

/* clearing & setting the n'th bit in a given tag */
#define CLEAR_BIT(tag, bit)     (tag &= ~(0x1<<bit))
#define SET_BIT(tag, bit)       (tag |= (0x1<<bit))

#if DEBUG

#define SI_DEBUG        1

#endif /* DEBUG */

/* si_debug_flags */
#define SIDBG_TEST      0x0001
#define SIDBG_INIT      0x0002
#define SIDBG_ENTRY     0x0004
#define SIDBG_DUMP_PRB  0x0008
#define SIDBG_EVENT     0x0010
#define SIDBG_POLL_LOOP 0x0020
#define SIDBG_PKTCOMP   0x0040
#define SIDBG_TIMEOUT   0x0080
#define SIDBG_INFO      0x0100
#define SIDBG_VERBOSE   0x0200
#define SIDBG_INTR      0x0400
#define SIDBG_ERRS      0x0800
#define SIDBG_COOKIES   0x1000
#define SIDBG_POWER     0x2000
#define SIDBG_RESET     0x4000

extern uint32_t si_debug_flags;

#define SIDBG(flag, format, args ...) \
        if (si_debug_flags & (flag)) { \
                si_log(NULL, NULL, format, ## args); \
        }

#define SIDBG_P(flag, si_portp, format, args ...) \
        if (si_debug_flags & (flag)) { \
                si_log(NULL, si_portp, format, ## args); \
        }

#define SIDBG_C(flag, si_ctlp, format, args ...) \
        if (si_debug_flags & (flag)) { \
                si_log(si_ctlp, NULL, format, ## args); \
        }


/* Flags controlling the reset behavior */
#define SI_PORT_RESET           0x1     /* Reset the port */
#define SI_DEVICE_RESET         0x2     /* Reset the device, not the port */
#define SI_RESET_NO_EVENTS_UP   0x4     /* Don't send reset events up */

#ifdef  __cplusplus
}
#endif

#endif /* _SI3124VAR_H */