/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SBP2_DRIVER_H #define _SYS_SBP2_DRIVER_H #pragma ident "%Z%%M% %I% %E% SMI" /* * Serial Bus Protocol 2 (SBP-2) driver interfaces */ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* * Config ROM definitions * * bus info block */ typedef struct sbp2_cfgrom_bib { int cb_len; /* info_length */ uint32_t *cb_buf; /* data buffer */ } sbp2_cfgrom_bib_t; /* directory */ typedef struct sbp2_cfgrom_dir { struct sbp2_cfgrom_ent *cd_ent; /* array of entries */ int cd_cnt; /* # of entries with data */ int cd_size; /* # of allocated entries */ } sbp2_cfgrom_dir_t; /* directory entry */ typedef struct sbp2_cfgrom_ent { uint8_t ce_kt; /* key type */ uint8_t ce_kv; /* key value */ uint16_t ce_len; /* length in quadlets */ uint64_t ce_offset; /* entry's CSR offset */ struct sbp2_cfgrom_ent *ce_ref; /* referred entry (text leaf) */ union { /* data depends on key type: */ uint32_t imm; /* immediate value */ uint32_t offset; /* CSR offset */ uint32_t *leaf; /* leaf */ sbp2_cfgrom_dir_t dir; /* directory */ } ce_data; } sbp2_cfgrom_ent_t; /* entire Config ROM */ typedef struct sbp2_cfgrom { sbp2_cfgrom_bib_t cr_bib; /* bus info block */ sbp2_cfgrom_ent_t cr_root; /* root directory */ } sbp2_cfgrom_t; _NOTE(SCHEME_PROTECTS_DATA("stable data", { sbp2_cfgrom_bib sbp2_cfgrom_dir sbp2_cfgrom_ent sbp2_cfgrom })) /* * SBP-2 definitions */ /* task states */ typedef enum { SBP2_TASK_INIT, /* initial state */ SBP2_TASK_PEND, /* put on the list, pending completion */ SBP2_TASK_COMP, /* task completed */ SBP2_TASK_PROC /* status being processed */ } sbp2_task_state_t; /* task errors */ typedef enum { SBP2_TASK_ERR_NONE, /* no error */ SBP2_TASK_ERR_DEAD, /* agent dead */ SBP2_TASK_ERR_BUS, /* bus error */ SBP2_TASK_ERR_TIMEOUT, /* timed out */ SBP2_TASK_ERR_ABORT, /* task aborted */ SBP2_TASK_ERR_LUN_RESET, /* lun reset */ SBP2_TASK_ERR_TGT_RESET /* target reset */ } sbp2_task_error; /* * task */ typedef struct sbp2_task { struct sbp2_task *ts_next; /* next task */ struct sbp2_task *ts_prev; /* previous task */ struct sbp2_ses *ts_ses; /* session we belong to */ void *ts_drv_priv; /* driver private data */ sbp2_bus_buf_t *ts_buf; /* bus buffer */ int ts_timeout; /* task timeout in seconds */ timeout_id_t ts_timeout_id; /* timeout ID */ sbp2_task_state_t ts_state; /* task state */ sbp2_task_error ts_error; /* error */ int ts_bus_error; /* bus error */ sbp2_status_t ts_status; /* status block */ hrtime_t ts_time_start; hrtime_t ts_time_comp; } sbp2_task_t; _NOTE(SCHEME_PROTECTS_DATA("unique per call", sbp2_task)) /* fetch agent */ typedef struct sbp2_agent { struct sbp2_tgt *a_tgt; /* target we belong to */ kmutex_t a_mutex; /* structure mutex */ uint16_t a_state; /* current agent state */ kcondvar_t a_cv; /* agent state cv */ boolean_t a_acquired; /* acquired flag */ /* commands */ void *a_cmd; /* fetch agent cmd */ mblk_t *a_cmd_data; /* cmd data */ sbp2_task_t *a_active_task; /* active task */ /* register offsets */ uint64_t a_reg_agent_state; /* AGENT_STATE */ uint64_t a_reg_agent_reset; /* AGENT_RESET */ uint64_t a_reg_orbp; /* ORB_POINTER */ uint64_t a_reg_doorbell; /* DOORBELL */ uint64_t a_reg_unsol_status_enable; /* UNSOLICITED_STATUS_ENABLE */ } sbp2_agent_t; _NOTE(MUTEX_PROTECTS_DATA(sbp2_agent::a_mutex, sbp2_agent)) _NOTE(SCHEME_PROTECTS_DATA("stable data", sbp2_agent::{ a_tgt a_reg_agent_state a_reg_agent_reset a_reg_orbp a_reg_doorbell a_reg_unsol_status_enable })) _NOTE(SCHEME_PROTECTS_DATA("a_acquired", sbp2_agent::{ a_cmd a_cmd_data a_active_task })) /* session is a period between login and logout */ typedef struct sbp2_ses { struct sbp2_tgt *s_tgt; /* target we belong to */ struct sbp2_lun *s_lun; /* unit we belong to */ kmutex_t s_mutex; /* structure mutex */ struct sbp2_ses *s_next; /* next session */ uint16_t s_id; /* login ID */ uint64_t s_agent_offset; /* fetch agent offset */ sbp2_agent_t s_agent; /* fetch agent */ sbp2_bus_buf_t s_status_fifo_buf; /* status FIFO */ /* task list (command ORB's) */ kmutex_t s_task_mutex; /* protects task list */ sbp2_task_t *s_task_head; /* first on the list */ sbp2_task_t *s_task_tail; /* last on the list */ int s_task_cnt; /* # tasks */ void (*s_status_cb)(void *, sbp2_task_t *); void *s_status_cb_arg; } sbp2_ses_t; _NOTE(MUTEX_PROTECTS_DATA(sbp2_ses::s_mutex, sbp2_ses)) _NOTE(SCHEME_PROTECTS_DATA("stable data", sbp2_ses::{ s_tgt s_lun s_id s_agent_offset s_agent s_status_fifo_buf s_status_cb s_status_cb_arg })) _NOTE(MUTEX_PROTECTS_DATA(sbp2_ses::s_task_mutex, sbp2_ses::{ s_task_head s_task_tail s_task_cnt })) _NOTE(MUTEX_PROTECTS_DATA(sbp2_ses::s_task_mutex, sbp2_task::{ ts_next ts_prev })) /* buffer list */ typedef struct sbp2_buf_list { kmutex_t bl_mutex; int bl_len; /* number of elements */ sbp2_bus_buf_t *bl_head; /* first element */ sbp2_bus_buf_t *bl_tail; /* last element */ } sbp2_buf_list_t; /* logical unit */ typedef struct sbp2_lun { struct sbp2_tgt *l_tgt; /* target we belong to */ uint16_t l_lun; /* logical unit number */ uint8_t l_type; /* device type */ sbp2_ses_t *l_ses; /* login sessions */ sbp2_buf_list_t l_orb_freelist; /* ORB freelist */ sbp2_login_resp_t l_login_resp; /* login response */ boolean_t l_logged_in; /* true if logged in */ boolean_t l_reconnecting; /* true if being reconnected */ } sbp2_lun_t; enum { SBP2_ORB_FREELIST_MAX = 3 /* max # of elements on freelist */ }; /* per-target statistics */ typedef struct sbp2_tgt_stat { hrtime_t stat_cfgrom_last_parse_time; uint_t stat_submit_orbp; uint_t stat_submit_doorbell; uint_t stat_status_dead; uint_t stat_status_short; uint_t stat_status_unsolicited; uint_t stat_status_notask; uint_t stat_status_mgt_notask; uint_t stat_agent_worbp; uint_t stat_agent_worbp_fail; uint_t stat_agent_wreset; uint_t stat_agent_wreset_fail; uint_t stat_task_max; } sbp2_tgt_stat_t; /* target */ typedef struct sbp2_tgt { struct sbp2_bus *t_bus; /* bus */ void *t_bus_hdl; /* bus handle */ kmutex_t t_mutex; /* structure mutex */ sbp2_lun_t *t_lun; /* logical unit array */ int t_nluns; /* # logical units */ int t_nluns_alloc; /* # luns allocated */ /* congif ROM */ sbp2_cfgrom_t t_cfgrom; /* parsed cfgrom */ hrtime_t t_last_cfgrd; /* cfgrom timestamp */ int t_orb_size; /* ORB_size */ /* management agent */ uint64_t t_mgt_agent; /* mgt agent address */ int t_mot; /* mgt timeout, ms */ boolean_t t_mgt_agent_acquired; /* acquired flag */ kcondvar_t t_mgt_agent_cv; /* cv for busy flag */ sbp2_bus_buf_t t_mgt_orb_buf; /* mgt ORB */ void *t_mgt_cmd; /* command */ mblk_t *t_mgt_cmd_data; /* command data */ sbp2_bus_buf_t t_mgt_status_fifo_buf; /* status FIFO buf */ sbp2_status_t t_mgt_status; /* status block */ boolean_t t_mgt_status_rcvd; /* status received? */ kcondvar_t t_mgt_status_cv; /* status FIFO cv */ sbp2_bus_buf_t t_mgt_login_resp_buf; /* login response */ sbp2_tgt_stat_t t_stat; /* statistics */ } sbp2_tgt_t; _NOTE(MUTEX_PROTECTS_DATA(sbp2_tgt::t_mutex, sbp2_tgt)) _NOTE(SCHEME_PROTECTS_DATA("stable data", sbp2_tgt::{ t_bus t_bus_hdl t_lun t_nluns t_nluns_alloc t_cfgrom t_last_cfgrd t_orb_size t_mgt_agent t_mot })) _NOTE(SCHEME_PROTECTS_DATA("t_mgt_agent_cv", sbp2_tgt::{ t_mgt_orb_buf t_mgt_cmd t_mgt_cmd_data t_mgt_status_fifo_buf t_mgt_status_rcvd t_mgt_login_resp_buf })) _NOTE(SCHEME_PROTECTS_DATA("statistics", sbp2_tgt::t_stat)) _NOTE(MUTEX_PROTECTS_DATA(sbp2_tgt::t_mutex, sbp2_lun)) _NOTE(SCHEME_PROTECTS_DATA("stable data", sbp2_lun::{ l_tgt l_lun l_type l_ses })) _NOTE(SCHEME_PROTECTS_DATA("t_mgt_agent_cv", sbp2_lun::l_login_resp)) _NOTE(LOCK_ORDER(sbp2_tgt::t_mutex sbp2_ses::s_mutex)) _NOTE(LOCK_ORDER(sbp2_tgt::t_mutex sbp2_ses::s_task_mutex)) _NOTE(LOCK_ORDER(sbp2_tgt::t_mutex sbp2_agent::a_mutex)) #define SBP2_ORB_SIZE_ROUNDUP(tp, size) roundup(size, (tp)->t_orb_size) /* walker flags */ enum { SBP2_WALK_DIRONLY = 0x01 /* walk directories only */ }; /* walker return codes */ enum { SBP2_WALK_CONTINUE, SBP2_WALK_STOP }; int sbp2_tgt_init(void *, struct sbp2_bus *, int, sbp2_tgt_t **); void sbp2_tgt_fini(sbp2_tgt_t *); void sbp2_tgt_disconnect(sbp2_tgt_t *); int sbp2_tgt_reconnect(sbp2_tgt_t *); int sbp2_tgt_reset(sbp2_tgt_t *, int *); int sbp2_tgt_get_cfgrom(sbp2_tgt_t *, sbp2_cfgrom_t **); int sbp2_tgt_get_lun_cnt(sbp2_tgt_t *); sbp2_lun_t *sbp2_tgt_get_lun(sbp2_tgt_t *, int); int sbp2_lun_reset(sbp2_lun_t *, int *); int sbp2_lun_login(sbp2_lun_t *, sbp2_ses_t **, void (*)(void *, sbp2_task_t *), void *, int *); int sbp2_lun_logout(sbp2_lun_t *, sbp2_ses_t **, int *, boolean_t); int sbp2_ses_reconnect(sbp2_ses_t *, int *, uint16_t); int sbp2_ses_submit_task(sbp2_ses_t *, sbp2_task_t *); void sbp2_ses_nudge(sbp2_ses_t *); int sbp2_ses_remove_task(sbp2_ses_t *, sbp2_task_t *); sbp2_task_t *sbp2_ses_find_task_state(sbp2_ses_t *, sbp2_task_state_t); sbp2_task_t *sbp2_ses_remove_first_task(sbp2_ses_t *); sbp2_task_t *sbp2_ses_remove_first_task_state(sbp2_ses_t *, sbp2_task_state_t); sbp2_task_t *sbp2_ses_cancel_first_task(sbp2_ses_t *); int sbp2_ses_agent_reset(sbp2_ses_t *, int *); int sbp2_ses_abort_task(sbp2_ses_t *, sbp2_task_t *, int *); int sbp2_ses_abort_task_set(sbp2_ses_t *, int *); int sbp2_task_orb_alloc(sbp2_lun_t *, sbp2_task_t *, int); void sbp2_task_orb_free(sbp2_lun_t *, sbp2_task_t *); void *sbp2_task_orb_kaddr(sbp2_task_t *); void sbp2_task_orb_sync(sbp2_lun_t *, sbp2_task_t *, int); void sbp2_swap32_buf(uint32_t *, int); void sbp2_cfgrom_walk(sbp2_cfgrom_ent_t *, int (*)(void *, sbp2_cfgrom_ent_t *, int), void *); sbp2_cfgrom_ent_t *sbp2_cfgrom_ent_by_key(sbp2_cfgrom_ent_t *, int8_t, int8_t, int); #ifdef __cplusplus } #endif #endif /* _SYS_SBP2_DRIVER_H */