#ifndef _GHD_H
#define _GHD_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/kmem.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/debug.h>
#include <sys/scsi/scsi.h>
#include "ghd_queue.h"
#include "ghd_scsi.h"
#include "ghd_waitq.h"
#include "ghd_debug.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef enum {
GCMD_STATE_IDLE = 0,
GCMD_STATE_WAITQ,
GCMD_STATE_ACTIVE,
GCMD_STATE_DONEQ,
GCMD_STATE_ABORTING_CMD,
GCMD_STATE_ABORTING_DEV,
GCMD_STATE_RESETTING_DEV,
GCMD_STATE_RESETTING_BUS,
GCMD_STATE_HUNG,
GCMD_NSTATES
} cmdstate_t;
typedef enum {
GACTION_EARLY_TIMEOUT = 0,
GACTION_EARLY_ABORT,
GACTION_ABORT_CMD,
GACTION_ABORT_DEV,
GACTION_RESET_TARGET,
GACTION_RESET_BUS,
GACTION_INCOMPLETE
} gact_t;
typedef enum {
GHD_TIMER_POLL_ALL = 0,
GHD_TIMER_POLL_ONE
} gtimer_poll_t;
typedef struct ghd_cmd {
L2el_t cmd_q;
cmdstate_t cmd_state;
ulong_t cmd_waitq_level;
int cmd_flags;
L2el_t cmd_timer_link;
ulong_t cmd_start_time;
ulong_t cmd_timeout;
opaque_t cmd_private;
void *cmd_pktp;
gtgt_t *cmd_gtgtp;
int cmd_dma_flags;
ddi_dma_handle_t cmd_dma_handle;
ddi_dma_win_t cmd_dmawin;
ddi_dma_seg_t cmd_dmaseg;
uint_t cmd_wcount;
uint_t cmd_windex;
uint_t cmd_ccount;
uint_t cmd_cindex;
long cmd_totxfer;
ddi_dma_cookie_t cmd_first_cookie;
int use_first;
} gcmd_t;
#define GCMDFLG_RESET_NOTIFY 1
#define GHD_GCMD_INIT(gcmdp, cmdp, gtgtp) \
(L2_INIT(&(gcmdp)->cmd_q), \
L2_INIT(&(gcmdp)->cmd_timer_link), \
(gcmdp)->cmd_private = (cmdp), \
(gcmdp)->cmd_gtgtp = (gtgtp) \
)
typedef struct tmr_conf {
kmutex_t t_mutex;
timeout_id_t t_timeout_id;
long t_ticks;
int t_refs;
struct cmd_ctl *t_ccc_listp;
} tmr_t;
typedef struct cmd_ctl {
struct cmd_ctl *ccc_nextp;
struct tmr_conf *ccc_tmrp;
char *ccc_label;
kmutex_t ccc_activel_mutex;
L2el_t ccc_activel;
dev_info_t *ccc_hba_dip;
ddi_iblock_cookie_t ccc_iblock;
ddi_softintr_t ccc_soft_id;
kmutex_t ccc_hba_mutex;
int ccc_hba_pollmode;
L1_t ccc_devs;
kmutex_t ccc_waitq_mutex;
Q_t ccc_waitq;
clock_t ccc_waitq_freezetime;
uint_t ccc_waitq_freezedelay;
ddi_softintr_t ccc_doneq_softid;
kmutex_t ccc_doneq_mutex;
L2el_t ccc_doneq;
void *ccc_hba_handle;
int (*ccc_ccballoc)();
void (*ccc_ccbfree)();
void (*ccc_sg_func)();
int (*ccc_hba_start)(void *handle, gcmd_t *);
void (*ccc_hba_complete)(void *handle, gcmd_t *, int);
void (*ccc_process_intr)(void *handle, void *intr_status);
int (*ccc_get_status)(void *handle, void *intr_status);
int (*ccc_timeout_func)(void *handle, gcmd_t *cmdp, gtgt_t *gtgtp,
gact_t action, int calltype);
void (*ccc_hba_reset_notify_callback)(gtgt_t *gtgtp,
void (*callback)(caddr_t),
caddr_t arg);
L2el_t ccc_reset_notify_list;
kmutex_t ccc_reset_notify_mutex;
char ccc_timeout_pending;
char ccc_waitq_frozen;
char ccc_waitq_held;
} ccc_t;
#define GHBA_QHEAD(cccp) ((cccp)->ccc_waitq.Q_qhead)
#define GHBA_MAXACTIVE(cccp) ((cccp)->ccc_waitq.Q_maxactive)
#define GHBA_NACTIVE(cccp) ((cccp)->ccc_waitq.Q_nactive)
#define CCCP_INIT(cccp) { \
L1HEADER_INIT(&(cccp)->ccc_devs); \
L2_INIT(&(cccp)->ccc_doneq); \
L2_INIT(&(cccp)->ccc_reset_notify_list); \
}
#define CCCP2GDEVP(cccp) \
(L1_EMPTY(&(cccp)->ccc_devs) \
? (gdev_t *)NULL \
: (gdev_t *)((cccp)->ccc_devs.l1_headp->le_datap))
typedef struct ghd_reset_notify_list {
gtgt_t *gtgtp;
void (*callback)(caddr_t);
caddr_t arg;
L2el_t l2_link;
} ghd_reset_notify_list_t;
#include "ghd_scsa.h"
#include "ghd_dma.h"
void ghd_complete(ccc_t *cccp, gcmd_t *cmdp);
void ghd_doneq_put_head(ccc_t *cccp, gcmd_t *cmdp);
void ghd_doneq_put_tail(ccc_t *cccp, gcmd_t *cmdp);
int ghd_intr(ccc_t *cccp, void *status);
int ghd_register(char *, ccc_t *, dev_info_t *, int, void *hba_handle,
int (*ccc_ccballoc)(gtgt_t *, gcmd_t *, int, int,
int, int),
void (*ccc_ccbfree)(gcmd_t *),
void (*ccc_sg_func)(gcmd_t *, ddi_dma_cookie_t *,
int, int),
int (*hba_start)(void *, gcmd_t *),
void (*hba_complete)(void *, gcmd_t *, int),
uint_t (*int_handler)(caddr_t),
int (*get_status)(void *, void *),
void (*process_intr)(void *, void *),
int (*timeout_func)(void *, gcmd_t *, gtgt_t *,
gact_t, int),
tmr_t *tmrp,
void (*hba_reset_notify_callback)(gtgt_t *,
void (*)(caddr_t), caddr_t));
void ghd_unregister(ccc_t *cccp);
int ghd_transport(ccc_t *cccp, gcmd_t *cmdp, gtgt_t *gtgtp,
ulong_t timeout, int polled, void *intr_status);
int ghd_tran_abort(ccc_t *cccp, gcmd_t *cmdp, gtgt_t *gtgtp,
void *intr_status);
int ghd_tran_abort_lun(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status);
int ghd_tran_reset_target(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status);
int ghd_tran_reset_bus(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status);
int ghd_reset_notify(ccc_t *cccp, gtgt_t *gtgtp, int flag,
void (*callback)(caddr_t), caddr_t arg);
void ghd_freeze_waitq(ccc_t *cccp, int delay);
void ghd_trigger_reset_notify(ccc_t *cccp);
void ghd_queue_hold(ccc_t *cccp);
void ghd_queue_unhold(ccc_t *cccp);
gcmd_t *ghd_gcmd_alloc(gtgt_t *gtgtp, int ccblen, int sleep);
void ghd_gcmd_free(gcmd_t *gcmdp);
int ghd_timer_attach(ccc_t *cccp, tmr_t *tmrp,
int (*timeout_func)(void *handle, gcmd_t *, gtgt_t *,
gact_t, int));
void ghd_timer_detach(ccc_t *cccp);
void ghd_timer_fini(tmr_t *tmrp);
void ghd_timer_init(tmr_t *tmrp, long ticks);
void ghd_timer_newstate(ccc_t *cccp, gcmd_t *cmdp, gtgt_t *gtgtp,
gact_t action, int calltype);
void ghd_timer_poll(ccc_t *cccp, gtimer_poll_t calltype);
void ghd_timer_start(ccc_t *cccp, gcmd_t *cmdp, long cmd_timeout);
void ghd_timer_stop(ccc_t *cccp, gcmd_t *cmdp);
gtgt_t *ghd_target_init(dev_info_t *, dev_info_t *, ccc_t *, size_t,
void *, ushort_t, uchar_t);
void ghd_target_free(dev_info_t *, dev_info_t *, ccc_t *, gtgt_t *);
void ghd_waitq_shuffle_up(ccc_t *, gdev_t *);
void ghd_waitq_delete(ccc_t *, gcmd_t *);
int ghd_waitq_process_and_mutex_hold(ccc_t *);
void ghd_waitq_process_and_mutex_exit(ccc_t *);
#define GHD_TGTREQ 0
#define GHD_TIMEOUT 1
#define GHD_INLINE 1
#if defined(GHD_DEBUG) || defined(DEBUG) || defined(__lint)
#undef GHD_INLINE
#endif
#if defined(GHD_INLINE)
#define GHD_COMPLETE(cccp, gcmpd) GHD_COMPLETE_INLINE(cccp, gcmdp)
#define GHD_TIMER_STOP(cccp, gcmdp) GHD_TIMER_STOP_INLINE(cccp, gcmdp)
#define GHD_DONEQ_PUT_HEAD(cccp, gcmdp) GHD_DONEQ_PUT_HEAD_INLINE(cccp, gcmdp)
#define GHD_DONEQ_PUT_TAIL(cccp, gcmdp) GHD_DONEQ_PUT_TAIL_INLINE(cccp, gcmdp)
#else
#define GHD_COMPLETE(cccp, gcmpd) ghd_complete(cccp, gcmdp)
#define GHD_TIMER_STOP(cccp, gcmdp) ghd_timer_stop(cccp, gcmdp)
#define GHD_DONEQ_PUT_HEAD(cccp, gcmdp) ghd_doneq_put_head(cccp, gcmdp)
#define GHD_DONEQ_PUT_TAIL(cccp, gcmdp) ghd_doneq_put_tail(cccp, gcmdp)
#endif
#define GHD_COMPLETE_INLINE(cccp, gcmdp) \
{ \
ghd_waitq_delete(cccp, gcmdp); \
(gcmdp)->cmd_state = GCMD_STATE_DONEQ; \
GHD_TIMER_STOP((cccp), (gcmdp)); \
GHD_DONEQ_PUT_TAIL((cccp), (gcmdp)); \
}
#define GHD_TIMER_STOP_INLINE(cccp, gcmdp) \
{ \
mutex_enter(&(cccp)->ccc_activel_mutex);\
L2_delete(&(gcmdp)->cmd_timer_link); \
mutex_exit(&(cccp)->ccc_activel_mutex); \
}
#define GHD_DONEQ_PUT_HEAD_INLINE(cccp, gcmdp) \
{ \
kmutex_t *doneq_mutexp = &(cccp)->ccc_doneq_mutex; \
\
mutex_enter(doneq_mutexp); \
(gcmdp)->cmd_state = GCMD_STATE_DONEQ; \
L2_add_head(&(cccp)->ccc_doneq, &(gcmdp)->cmd_q, (gcmdp)); \
if (!(cccp)->ccc_hba_pollmode) \
ddi_trigger_softintr((cccp)->ccc_doneq_softid); \
mutex_exit(doneq_mutexp); \
}
#define GHD_DONEQ_PUT_TAIL_INLINE(cccp, gcmdp) \
{ \
kmutex_t *doneq_mutexp = &(cccp)->ccc_doneq_mutex; \
\
mutex_enter(doneq_mutexp); \
(gcmdp)->cmd_state = GCMD_STATE_DONEQ; \
L2_add(&(cccp)->ccc_doneq, &(gcmdp)->cmd_q, (gcmdp)); \
if (!(cccp)->ccc_hba_pollmode) \
ddi_trigger_softintr((cccp)->ccc_doneq_softid); \
mutex_exit(doneq_mutexp); \
}
#define GCMDP2PKTP(gcmdp) ((gcmdp)->cmd_pktp)
#define GCMDP2GTGTP(gcmdp) ((gcmdp)->cmd_gtgtp)
#define GCMDP2GDEVP(gcmdp) ((gcmdp)->cmd_gtgtp->gt_gdevp)
#define GCMDP2CCCP(gcmdp) (GCMDP2GTGTP(gcmdp)->gt_ccc)
#define PKTP2GCMDP(pktp) ((gcmd_t *)(pktp)->pkt_ha_private)
#define ADDR2TRAN(ap) ((ap)->a_hba_tran)
#define SDEV2ADDR(sdp) (&(sdp)->sd_address)
#define SDEV2TRAN(sdp) ADDR2TRAN(SDEV2ADDR(sdp))
#define PKTP2TRAN(pktp) ADDR2TRAN(&(pktp)->pkt_address)
#define TRAN2GTGTP(tranp) ((gtgt_t *)((tranp)->tran_tgt_private))
#define SDEV2GTGTP(sd) TRAN2GTGTP(SDEV2TRAN(sd))
#define PKTP2GTGTP(pktp) TRAN2GTGTP(PKTP2TRAN(pktp))
#define TRAN2HBA(tranp) ((tranp)->tran_hba_private)
#define SDEV2HBA(sd) TRAN2HBA(SDEV2TRAN(sd))
#define ADDR2GTGTP(ap) TRAN2GTGTP(ADDR2TRAN(ap))
#ifdef __cplusplus
}
#endif
#endif