/* * 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 */ /* * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Link upper_path_table structure * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_WRITER] * -. uinst_t->u_lock : M * -. uinst_t->l_lock : A * -. uinst_t->c_lock : A */ void oplmsu_link_upath(upath_t *add_upath) { ASSERT(add_upath != NULL); ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); if (oplmsu_uinst->first_upath == NULL) { oplmsu_uinst->first_upath = add_upath; add_upath->u_prev = NULL; } else { upath_t *last_upath; last_upath = oplmsu_uinst->last_upath; last_upath->u_next = add_upath; add_upath->u_prev = last_upath; } oplmsu_uinst->last_upath = add_upath; add_upath->u_next = NULL; } /* * Unlink upper_path_table structure * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_WRITER] * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_unlink_upath(upath_t *del_upath) { upath_t **first, **last; ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); first = &oplmsu_uinst->first_upath; last = &oplmsu_uinst->last_upath; if ((*first != del_upath) && (*last != del_upath)) { del_upath->u_prev->u_next = del_upath->u_next; del_upath->u_next->u_prev = del_upath->u_prev; } else { if (*first == del_upath) { *first = (*first)->u_next; if (*first) { (*first)->u_prev = NULL; } } if (*last == del_upath) { *last = (*last)->u_prev; if (*last) { (*last)->u_next = NULL; } } } del_upath->u_next = NULL; del_upath->u_prev = NULL; } /* * Link lower_path_table structure * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_WRITER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : M * -. uinst_t->c_lock : A */ void oplmsu_link_lpath(lpath_t *add_lpath) { ASSERT(add_lpath != NULL); ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); if (oplmsu_uinst->first_lpath == NULL) { oplmsu_uinst->first_lpath = add_lpath; add_lpath->l_prev = NULL; } else { lpath_t *last_lpath; last_lpath = oplmsu_uinst->last_lpath; last_lpath->l_next = add_lpath; add_lpath->l_prev = last_lpath; } oplmsu_uinst->last_lpath = add_lpath; add_lpath->l_next = NULL; } /* * Unlink lower_path_table structure * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_WRITER] * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_unlink_lpath(lpath_t *del_lpath) { lpath_t **first, **last; ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); first = &oplmsu_uinst->first_lpath; last = &oplmsu_uinst->last_lpath; if ((*first != del_lpath) && (*last != del_lpath)) { del_lpath->l_prev->l_next = del_lpath->l_next; del_lpath->l_next->l_prev = del_lpath->l_prev; } else { if (*first == del_lpath) { *first = (*first)->l_next; if (*first) { (*first)->l_prev = NULL; } } if (*last == del_lpath) { *last = (*last)->l_prev; if (*last) { (*last)->l_next = NULL; } } } del_lpath->l_next = NULL; del_lpath->l_prev = NULL; } /* * Link msgb structure of high priority * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : A [It depends on caller] * -. uinst_t->c_lock : A [It depends on caller] */ void oplmsu_link_high_primsg(mblk_t **first, mblk_t **last, mblk_t *add_msg) { ASSERT(add_msg != NULL); ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); if (*first == NULL) { *first = add_msg; add_msg->b_prev = NULL; } else { (*last)->b_next = add_msg; add_msg->b_prev = *last; } *last = add_msg; add_msg->b_next = NULL; } /* * Check whether lower path is usable by lower path info table address * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : M * -. uinst_t->c_lock : P */ int oplmsu_check_lpath_usable(void) { lpath_t *lpath; int rval = SUCCESS; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock)); lpath = oplmsu_uinst->first_lpath; while (lpath) { if ((lpath->hndl_uqueue != NULL) || (lpath->hndl_mp != NULL)) { rval = BUSY; break; } lpath = lpath->l_next; } return (rval); } /* * Search upath_t by path number * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : M * -. uinst_t->l_lock : A * -. uinst_t->c_lock : P */ upath_t * oplmsu_search_upath_info(int path_no) { upath_t *upath; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); upath = oplmsu_uinst->first_upath; while (upath) { if (upath->path_no == path_no) { break; } upath = upath->u_next; } return (upath); } /* * Send M_IOCACK(or M_IOCNAK) message to stream * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : P * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_iocack(queue_t *q, mblk_t *mp, int errno) { struct iocblk *iocp = NULL; ASSERT(mp != NULL); iocp = (struct iocblk *)mp->b_rptr; iocp->ioc_error = errno; if (errno) { /* Error */ mp->b_datap->db_type = M_IOCNAK; iocp->ioc_rval = FAILURE; OPLMSU_TRACE(q, mp, MSU_TRC_UO); qreply(q, mp); } else { /* Good */ mp->b_datap->db_type = M_IOCACK; iocp->ioc_rval = SUCCESS; OPLMSU_TRACE(q, mp, MSU_TRC_UO); qreply(q, mp); } } /* * Delete all upath_t * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_WRITER] * -. uinst_t->u_lock : M * -. uinst_t->l_lock : A * -. uinst_t->c_lock : A */ void oplmsu_delete_upath_info(void) { upath_t *upath, *next_upath; ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); upath = oplmsu_uinst->first_upath; oplmsu_uinst->first_upath = NULL; oplmsu_uinst->last_upath = NULL; while (upath) { next_upath = upath->u_next; kmem_free(upath, sizeof (upath_t)); upath = next_upath; } } /* * Set queue and ioctl to lpath_t * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : M * -. uinst_t->c_lock : P */ int oplmsu_set_ioctl_path(lpath_t *lpath, queue_t *hndl_queue, mblk_t *mp) { int rval = SUCCESS; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock)); if ((lpath->hndl_uqueue == NULL) && (lpath->hndl_mp == NULL) && (lpath->sw_flag == 0)) { if ((lpath->status == MSU_EXT_NOTUSED) || (lpath->status == MSU_EXT_ACTIVE_CANDIDATE) || (lpath->status == MSU_SETID_NU)) { if (hndl_queue == NULL) { lpath->hndl_uqueue = hndl_queue; } else { lpath->hndl_uqueue = WR(hndl_queue); } lpath->hndl_mp = mp; } else { rval = BUSY; } } else { rval = BUSY; } return (rval); } /* * Clear queue and ioctl to lpath_t * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : M * -. uinst_t->c_lock : P */ void oplmsu_clear_ioctl_path(lpath_t *lpath) { ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock)); lpath->hndl_uqueue = NULL; lpath->hndl_mp = NULL; } /* * Get instanse status from status of upath_t * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : M * -. uinst_t->l_lock : A * -. uinst_t->c_lock : P */ int oplmsu_get_inst_status(void) { upath_t *upath; int sts, pre_sts = INST_STAT_UNCONFIGURED; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); upath = oplmsu_uinst->first_upath; while (upath) { if (((upath->status == MSU_PSTAT_ACTIVE) && (upath->traditional_status == MSU_ACTIVE)) || ((upath->status == MSU_PSTAT_STANDBY) && (upath->traditional_status == MSU_STANDBY))) { sts = INST_STAT_ONLINE; } else if (((upath->status == MSU_PSTAT_STOP) && (upath->traditional_status == MSU_STOP)) || ((upath->status == MSU_PSTAT_FAIL) && (upath->traditional_status == MSU_FAIL))) { sts = INST_STAT_OFFLINE; } else if (((upath->status == MSU_PSTAT_DISCON) && (upath->traditional_status == MSU_DISCON)) || ((upath->status == MSU_PSTAT_EMPTY) && (upath->traditional_status == MSU_EMPTY))) { sts = INST_STAT_UNCONFIGURED; } else { sts = INST_STAT_BUSY; } if (pre_sts > sts) { pre_sts = sts; } upath = upath->u_next; } return (pre_sts); } /* * Search path of "online:standby" status * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : M * -. uinst_t->l_lock : A * -. uinst_t->c_lock : P */ upath_t * oplmsu_search_standby(void) { upath_t *upath, *altn_upath = NULL; int max_pathnum = UNDEFINED; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); upath = oplmsu_uinst->first_upath; while (upath) { if ((upath->status == MSU_PSTAT_STANDBY) && (upath->traditional_status == MSU_STANDBY) && (upath->lpath != NULL)) { if ((max_pathnum == UNDEFINED) || (max_pathnum > upath->path_no)) { max_pathnum = upath->path_no; altn_upath = upath; } } upath = upath->u_next; } return (altn_upath); } /* * Search path of "offline:stop" status, and minimum path number * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : M * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_search_min_stop_path(void) { upath_t *upath, *min_upath; lpath_t *lpath; int min_no = UNDEFINED; int active_flag = 0; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); upath = oplmsu_uinst->first_upath; while (upath) { if ((upath->status == MSU_PSTAT_ACTIVE) && (upath->traditional_status == MSU_ACTIVE)) { active_flag = 1; break; } else if ((upath->status == MSU_PSTAT_STOP) && (upath->traditional_status == MSU_STOP)) { if (upath->lpath != NULL) { if ((min_no == UNDEFINED) || (upath->path_no < min_no)) { lpath = upath->lpath; mutex_enter(&oplmsu_uinst->l_lock); if (lpath->status == MSU_EXT_NOTUSED) { min_upath = upath; min_no = upath->path_no; } mutex_exit(&oplmsu_uinst->l_lock); } } } upath = upath->u_next; } if (active_flag == 0) { lpath = min_upath->lpath; mutex_enter(&oplmsu_uinst->l_lock); lpath->src_upath = NULL; lpath->status = MSU_EXT_ACTIVE_CANDIDATE; mutex_exit(&oplmsu_uinst->l_lock); } } /* * Get the total number of serial paths * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_WRITER] * -. uinst_t->u_lock : M * -. uinst_t->l_lock : A * -. uinst_t->c_lock : A */ int oplmsu_get_pathnum(void) { upath_t *upath; int total_num = 0; ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); if (oplmsu_uinst->first_upath != NULL) { upath = oplmsu_uinst->first_upath; while (upath) { total_num++; upath = upath->u_next; } } return (total_num); } /* * Put XOFF/ XON message on write queue * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : A * -. uinst_t->c_lock : A */ int oplmsu_cmn_put_xoffxon(queue_t *queue, int data) { mblk_t *mp; int rval = SUCCESS; /* Send M_START */ if ((mp = allocb(0, BPRI_LO)) != NULL) { mp->b_datap->db_type = M_START; (void) putq(queue, mp); /* Send M_DATA(XOFF, XON) */ if ((mp = allocb(sizeof (int), BPRI_LO)) != NULL) { *(uint_t *)mp->b_rptr = data; mp->b_wptr = mp->b_rptr + sizeof (int); (void) putq(queue, mp); } else { rval = FAILURE; } } else { rval = FAILURE; } return (rval); } /* * Put XOFF message on write queue for all standby paths * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : M * -. uinst_t->l_lock : M * -. uinst_t->c_lock : P */ void oplmsu_cmn_putxoff_standby(void) { upath_t *upath; lpath_t *lpath; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock)); upath = oplmsu_uinst->first_upath; while (upath) { lpath = upath->lpath; if ((upath->status != MSU_PSTAT_STANDBY) || (lpath == NULL)) { upath = upath->u_next; continue; } (void) oplmsu_cmn_put_xoffxon( WR(lpath->lower_queue), MSU_XOFF_4); upath = upath->u_next; } } /* * Set M_FLUSH message * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : A [RW_READER or RW_WRITER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : A * -. uinst_t->c_lock : A */ void oplmsu_cmn_set_mflush(mblk_t *mp) { mp->b_datap->db_type = M_FLUSH; *mp->b_rptr = FLUSHW; mp->b_wptr = mp->b_rptr + sizeof (char); } /* * Set status informations of upath_t * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : M * -. uinst_t->l_lock : A * -. uinst_t->c_lock : A */ void oplmsu_cmn_set_upath_sts(upath_t *upath, int sts, int prev_sts, ulong_t trad_sts) { ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); upath->status = sts; upath->prev_status = prev_sts; upath->traditional_status = trad_sts; } /* * Allocate a message block * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ int oplmsu_cmn_allocmb(queue_t *q, mblk_t *mp, mblk_t **nmp, size_t size, int rw_flag) { int rval = SUCCESS; ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); if ((*nmp = (mblk_t *)allocb(size, BPRI_LO)) == NULL) { oplmsu_cmn_bufcall(q, mp, size, rw_flag); rval = FAILURE; } else { (*nmp)->b_wptr = (*nmp)->b_rptr + size; } return (rval); } /* * Copy a message * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ int oplmsu_cmn_copymb(queue_t *q, mblk_t *mp, mblk_t **nmp, mblk_t *cmp, int rw_flag) { int rval = SUCCESS; ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); if ((*nmp = copymsg(cmp)) == NULL) { oplmsu_cmn_bufcall(q, mp, msgsize(cmp), rw_flag); rval = FAILURE; } return (rval); } /* * bufcall request * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_cmn_bufcall(queue_t *q, mblk_t *mp, size_t size, int rw_flag) { ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); if (rw_flag == MSU_WRITE_SIDE) { ctrl_t *ctrl; (void) putbq(q, mp); mutex_enter(&oplmsu_uinst->c_lock); ctrl = (ctrl_t *)q->q_ptr; if (ctrl->wbuf_id != 0) { mutex_exit(&oplmsu_uinst->c_lock); return; } ctrl->wbuftbl->q = q; ctrl->wbuftbl->rw_flag = rw_flag; ctrl->wbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb, (void *)ctrl->wbuftbl); if (ctrl->wbuf_id == 0) { if (ctrl->wtout_id != 0) { mutex_exit(&oplmsu_uinst->c_lock); return; } ctrl->wtout_id = timeout(oplmsu_cmn_bufcb, (void *)ctrl->wbuftbl, drv_usectohz(MSU_TM_500MS)); } mutex_exit(&oplmsu_uinst->c_lock); } else if (rw_flag == MSU_READ_SIDE) { lpath_t *lpath; mblk_t *wrk_msg; mutex_enter(&oplmsu_uinst->l_lock); lpath = (lpath_t *)q->q_ptr; if (mp->b_datap->db_type >= QPCTL) { if (lpath->first_lpri_hi == NULL) { lpath->last_lpri_hi = mp; mp->b_next = NULL; } else { wrk_msg = lpath->first_lpri_hi; wrk_msg->b_prev = mp; mp->b_next = wrk_msg; } mp->b_prev = NULL; lpath->first_lpri_hi = mp; } else { (void) putbq(q, mp); } if (lpath->rbuf_id != 0) { mutex_exit(&oplmsu_uinst->l_lock); return; } lpath->rbuftbl->q = q; lpath->rbuftbl->rw_flag = rw_flag; lpath->rbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb, (void *)lpath->rbuftbl); if (lpath->rbuf_id == 0) { if (lpath->rtout_id != 0) { mutex_exit(&oplmsu_uinst->l_lock); return; } lpath->rtout_id = timeout(oplmsu_cmn_bufcb, (void *)lpath->rbuftbl, drv_usectohz(MSU_TM_500MS)); } mutex_exit(&oplmsu_uinst->l_lock); } } /* * Previous sequence for active path change * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ int oplmsu_cmn_prechg(queue_t *q, mblk_t *mp, int rw_flag, mblk_t **term_mp, int *term_ioctl, int *term_stat) { ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); if (oplmsu_uinst->tcsets_p != NULL) { struct iocblk *iocp; if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tcsets_p, rw_flag) == -1) { return (FAILURE); } iocp = (struct iocblk *)(*term_mp)->b_rptr; *term_ioctl = iocp->ioc_cmd; *term_stat = MSU_WTCS_ACK; } else if (oplmsu_uinst->tiocmset_p != NULL) { if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocmset_p, rw_flag) == -1) { return (FAILURE); } *term_ioctl = TIOCMSET; *term_stat = MSU_WTMS_ACK; } else if (oplmsu_uinst->tiocspps_p != NULL) { if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocspps_p, rw_flag) == -1) { return (FAILURE); } *term_ioctl = TIOCSPPS; *term_stat = MSU_WPPS_ACK; } else if (oplmsu_uinst->tiocswinsz_p != NULL) { if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocswinsz_p, rw_flag) == -1) { return (FAILURE); } *term_ioctl = TIOCSWINSZ; *term_stat = MSU_WWSZ_ACK; } else if (oplmsu_uinst->tiocssoftcar_p != NULL) { if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocssoftcar_p, rw_flag) == -1) { return (FAILURE); } *term_ioctl = TIOCSSOFTCAR; *term_stat = MSU_WCAR_ACK; } else { *term_stat = MSU_WPTH_CHG; *term_mp = NULL; } return (SUCCESS); } /* * Pick up termios to re-set * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : A * -. uinst_t->c_lock : A */ int oplmsu_stop_prechg(mblk_t **term_mp, int *term_ioctl, int *term_stat) { ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); if (oplmsu_uinst->tcsets_p != NULL) { struct iocblk *iocp; if ((*term_mp = copymsg(oplmsu_uinst->tcsets_p)) == NULL) { return (FAILURE); } iocp = (struct iocblk *)(*term_mp)->b_rptr; *term_ioctl = iocp->ioc_cmd; *term_stat = MSU_WTCS_ACK; } else if (oplmsu_uinst->tiocmset_p != NULL) { if ((*term_mp = copymsg(oplmsu_uinst->tiocmset_p)) == NULL) { return (FAILURE); } *term_ioctl = TIOCMSET; *term_stat = MSU_WTMS_ACK; } else if (oplmsu_uinst->tiocspps_p != NULL) { if ((*term_mp = copymsg(oplmsu_uinst->tiocspps_p)) == NULL) { return (FAILURE); } *term_ioctl = TIOCSPPS; *term_stat = MSU_WPPS_ACK; } else if (oplmsu_uinst->tiocswinsz_p != NULL) { if ((*term_mp = copymsg(oplmsu_uinst->tiocswinsz_p)) == NULL) { return (FAILURE); } *term_ioctl = TIOCSWINSZ; *term_stat = MSU_WWSZ_ACK; } else if (oplmsu_uinst->tiocssoftcar_p != NULL) { if ((*term_mp = copymsg(oplmsu_uinst->tiocssoftcar_p)) == NULL) { return (FAILURE); } *term_ioctl = TIOCSSOFTCAR; *term_stat = MSU_WCAR_ACK; } else { *term_stat = MSU_WPTH_CHG; *term_mp = NULL; } return (SUCCESS); } /* * Previous sequence for active path change termio * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ int oplmsu_cmn_prechg_termio(queue_t *q, mblk_t *mp, int rw_flag, int prev_flag, mblk_t **term_mp, int *term_stat) { ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); if ((prev_flag == MSU_TIOS_TCSETS) && (oplmsu_uinst->tiocmset_p != NULL)) { if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocmset_p, rw_flag) == FAILURE) { return (FAILURE); } *term_stat = MSU_WTMS_ACK; } else if ((prev_flag <= MSU_TIOS_MSET) && (oplmsu_uinst->tiocspps_p != NULL)) { if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocspps_p, rw_flag) == FAILURE) { return (FAILURE); } *term_stat = MSU_WPPS_ACK; } else if ((prev_flag <= MSU_TIOS_PPS) && (oplmsu_uinst->tiocswinsz_p != NULL)) { if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocswinsz_p, rw_flag) == FAILURE) { return (FAILURE); } *term_stat = MSU_WWSZ_ACK; } else if ((prev_flag <= MSU_TIOS_WINSZP) && (oplmsu_uinst->tiocssoftcar_p != NULL)) { if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocssoftcar_p, rw_flag) == FAILURE) { return (FAILURE); } *term_stat = MSU_WCAR_ACK; } else if (prev_flag <= MSU_TIOS_SOFTCAR) { *term_mp = NULL; *term_stat = MSU_WPTH_CHG; } return (SUCCESS); } /* * Pull up messages * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : P * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ int oplmsu_cmn_pullup_msg(queue_t *q, mblk_t *mp) { mblk_t *nmp = NULL; if ((mp != NULL) && (mp->b_cont != NULL) && (mp->b_cont->b_cont != NULL)) { if ((nmp = msgpullup(mp->b_cont, -1)) == NULL) { oplmsu_iocack(q, mp, ENOSR); return (FAILURE); } else { freemsg(mp->b_cont); mp->b_cont = nmp; } } return (SUCCESS); } /* * Wake up flow control * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_cmn_wakeup(queue_t *q) { ctrl_t *ctrl; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); mutex_enter(&oplmsu_uinst->c_lock); ctrl = (ctrl_t *)q->q_ptr; if (ctrl->sleep_flag == CV_SLEEP) { ctrl->sleep_flag = CV_WAKEUP; cv_signal(&ctrl->cvp); } mutex_exit(&oplmsu_uinst->c_lock); } /* * bufcall() and timeout() callback entry for read/write stream * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : P * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_cmn_bufcb(void *arg) { struct buf_tbl *buftbl = arg; lpath_t *lpath; ctrl_t *ctrl; queue_t *q; int lq_flag = 0; rw_enter(&oplmsu_uinst->lock, RW_WRITER); mutex_enter(&oplmsu_uinst->l_lock); lpath = oplmsu_uinst->first_lpath; while (lpath) { if ((buftbl == lpath->rbuftbl) && (buftbl->rw_flag == MSU_READ_SIDE)) { if ((lpath->rbuf_id == 0) && (lpath->rtout_id == 0)) { mutex_exit(&oplmsu_uinst->l_lock); rw_exit(&oplmsu_uinst->lock); } else { q = lpath->rbuftbl->q; lpath->rbuftbl->q = NULL; lpath->rbuftbl->rw_flag = UNDEFINED; if (lpath->rbuf_id) { lpath->rbuf_id = 0; } else { lpath->rtout_id = 0; } mutex_exit(&oplmsu_uinst->l_lock); if (oplmsu_queue_flag == 1) { lq_flag = 1; oplmsu_queue_flag = 0; } rw_exit(&oplmsu_uinst->lock); oplmsu_rcmn_high_qenable(q); if (lq_flag == 1) { rw_enter(&oplmsu_uinst->lock, RW_WRITER); oplmsu_queue_flag = 1; rw_exit(&oplmsu_uinst->lock); } } return; } lpath = lpath->l_next; } mutex_exit(&oplmsu_uinst->l_lock); mutex_enter(&oplmsu_uinst->c_lock); if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) { if ((buftbl == ctrl->wbuftbl) && (buftbl->rw_flag == MSU_WRITE_SIDE)) { oplmsu_wbufcb_posthndl(ctrl); mutex_exit(&oplmsu_uinst->c_lock); rw_exit(&oplmsu_uinst->lock); return; } } if ((ctrl = oplmsu_uinst->meta_ctrl) != NULL) { if ((buftbl == ctrl->wbuftbl) && (buftbl->rw_flag == MSU_WRITE_SIDE)) { oplmsu_wbufcb_posthndl(ctrl); mutex_exit(&oplmsu_uinst->c_lock); rw_exit(&oplmsu_uinst->lock); return; } } mutex_exit(&oplmsu_uinst->c_lock); rw_exit(&oplmsu_uinst->lock); } /* * bufcall() or timeout() callback post handling for write stream * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_WRITER] * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : M */ void oplmsu_wbufcb_posthndl(ctrl_t *ctrl) { queue_t *q; int lq_flag = 0; ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); ASSERT(MUTEX_HELD(&oplmsu_uinst->c_lock)); if ((ctrl->wbuf_id == 0) && (ctrl->wtout_id == 0)) { return; } q = ctrl->wbuftbl->q; ctrl->wbuftbl->q = NULL; ctrl->wbuftbl->rw_flag = UNDEFINED; if (ctrl->wbuf_id) { ctrl->wbuf_id = 0; } else { ctrl->wtout_id = 0; } if (oplmsu_queue_flag == 1) { lq_flag = 1; oplmsu_queue_flag = 0; } mutex_exit(&oplmsu_uinst->c_lock); oplmsu_wcmn_high_qenable(q, RW_WRITER); mutex_enter(&oplmsu_uinst->c_lock); if (lq_flag == 1) { oplmsu_queue_flag = 1; } } /* * COMMON FUNCTIONS FOR WRITE STREAM */ /* * Check control node and driver privilege * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : A * -. uinst_t->c_lock : P */ int oplmsu_wcmn_chknode(queue_t *q, int node, mblk_t *mp) { struct iocblk *iocp; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); mutex_enter(&oplmsu_uinst->c_lock); if (((ctrl_t *)q->q_ptr)->node_type != node) { mutex_exit(&oplmsu_uinst->c_lock); cmn_err(CE_WARN, "oplmsu: chk-node: ctrl node type = %d", node); return (EINVAL); } mutex_exit(&oplmsu_uinst->c_lock); /* Check super-user by oplmsu.conf */ if (oplmsu_check_su != 0) { iocp = (struct iocblk *)mp->b_rptr; if (drv_priv(iocp->ioc_cr) != 0) { cmn_err(CE_WARN, "oplmsu: chk-node: Permission denied"); return (EPERM); } } return (SUCCESS); } /* * Flush handle for write side stream * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_wcmn_flush_hndl(queue_t *q, mblk_t *mp, krw_t rw) { queue_t *dst_queue = NULL; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); if (*mp->b_rptr & FLUSHW) { /* Write side */ flushq(q, FLUSHDATA); } dst_queue = oplmsu_uinst->lower_queue; if (dst_queue == NULL) { if (*mp->b_rptr & FLUSHR) { flushq(RD(q), FLUSHDATA); *mp->b_rptr &= ~FLUSHW; rw_exit(&oplmsu_uinst->lock); OPLMSU_TRACE(q, mp, MSU_TRC_UO); qreply(q, mp); rw_enter(&oplmsu_uinst->lock, rw); } else { freemsg(mp); } } else { (void) putq(WR(dst_queue), mp); } } /* * Through message handle for write side stream * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ int oplmsu_wcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag, krw_t rw) { queue_t *usr_queue = NULL, *dst_queue = NULL; ctrl_t *ctrl; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); mutex_enter(&oplmsu_uinst->c_lock); if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) { usr_queue = ctrl->queue; mutex_exit(&oplmsu_uinst->c_lock); } else { mutex_exit(&oplmsu_uinst->c_lock); if (mp->b_datap->db_type == M_IOCTL) { rw_exit(&oplmsu_uinst->lock); oplmsu_iocack(q, mp, ENODEV); rw_enter(&oplmsu_uinst->lock, rw); } else { freemsg(mp); } return (SUCCESS); } if (oplmsu_uinst->lower_queue != NULL) { dst_queue = WR(oplmsu_uinst->lower_queue); } else { cmn_err(CE_WARN, "!oplmsu: through-lwq: " "Active path doesn't exist"); if (mp->b_datap->db_type == M_IOCTL) { rw_exit(&oplmsu_uinst->lock); oplmsu_iocack(q, mp, ENODEV); rw_enter(&oplmsu_uinst->lock, rw); } else { freemsg(mp); } return (SUCCESS); } if ((usr_queue == WR(q)) || (usr_queue == RD(q))) { if (pri_flag == MSU_HIGH) { (void) putq(dst_queue, mp); } else { if (canput(dst_queue)) { (void) putq(dst_queue, mp); } else { oplmsu_wcmn_norm_putbq(WR(q), mp, dst_queue); return (FAILURE); } } } else { cmn_err(CE_WARN, "oplmsu: through-lwq: " "Inappropriate message for this node"); if (mp->b_datap->db_type == M_IOCTL) { rw_exit(&oplmsu_uinst->lock); oplmsu_iocack(q, mp, ENODEV); rw_enter(&oplmsu_uinst->lock, rw); } else { freemsg(mp); } } return (SUCCESS); } /* * Get high priority message from buffer for upper write stream * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : A * -. uinst_t->c_lock : P */ mblk_t * oplmsu_wcmn_high_getq(queue_t *uwq) { mblk_t *mp; ctrl_t *ctrl; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); mutex_enter(&oplmsu_uinst->c_lock); ctrl = (ctrl_t *)uwq->q_ptr; mp = ctrl->first_upri_hi; if (mp != NULL) { if (mp->b_next == NULL) { ctrl->first_upri_hi = NULL; ctrl->last_upri_hi = NULL; } else { ctrl->first_upri_hi = mp->b_next; mp->b_next->b_prev = NULL; mp->b_next = NULL; } mp->b_prev = NULL; } mutex_exit(&oplmsu_uinst->c_lock); return (mp); } /* * putbq() function for normal priority message of write stream * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_wcmn_norm_putbq(queue_t *uwq, mblk_t *mp, queue_t *dq) { lpath_t *lpath; ASSERT(mp != NULL); ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); mutex_enter(&oplmsu_uinst->l_lock); lpath = (lpath_t *)dq->q_ptr; lpath->uwq_flag = 1; lpath->uwq_queue = uwq; mutex_exit(&oplmsu_uinst->l_lock); (void) putbq(uwq, mp); } /* * Restart queuing for high priority message of write stream when flow control * failed * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER or RW_WRITER] * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_wcmn_high_qenable(queue_t *q, krw_t rw) { mblk_t *mp; ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); if (oplmsu_queue_flag == 1) { return; } /* Handle high priority message */ while (mp = oplmsu_wcmn_high_getq(WR(q))) { if (mp->b_datap->db_type & M_FLUSH) { oplmsu_wcmn_flush_hndl(q, mp, rw); continue; } if (oplmsu_wcmn_through_hndl(q, mp, MSU_HIGH, rw) == FAILURE) { return; } } qenable(WR(q)); /* enable upper write queue */ } /* * COMMON FUNCTIONS FOR READ STREAM */ /* * Flush handle for read side stream * * Requires lock ( M: mandatory P: prohibited A: allowed * -. uinst_t->lock : M [RW_READER] * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_rcmn_flush_hndl(queue_t *q, mblk_t *mp) { queue_t *dst_queue = NULL; ctrl_t *ctrl; ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); if (*mp->b_rptr & FLUSHR) { /* Remove only data messages from read queue */ flushq(q, FLUSHDATA); } mutex_enter(&oplmsu_uinst->c_lock); if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) { dst_queue = RD(ctrl->queue); mutex_exit(&oplmsu_uinst->c_lock); if (dst_queue != NULL) { (void) putq(dst_queue, mp); } else { if (*mp->b_rptr & FLUSHW) { flushq(WR(q), FLUSHDATA); *mp->b_rptr &= ~FLUSHR; rw_exit(&oplmsu_uinst->lock); OPLMSU_TRACE(q, mp, MSU_TRC_LO); qreply(q, mp); rw_enter(&oplmsu_uinst->lock, RW_READER); } else { freemsg(mp); } } } else { mutex_exit(&oplmsu_uinst->c_lock); if (*mp->b_rptr & FLUSHW) { flushq(WR(q), FLUSHDATA); *mp->b_rptr &= ~FLUSHR; rw_exit(&oplmsu_uinst->lock); OPLMSU_TRACE(q, mp, MSU_TRC_LO); qreply(q, mp); rw_enter(&oplmsu_uinst->lock, RW_READER); } else { freemsg(mp); } } } /* * Through message handle for read side stream * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : M [RW_READER] * -. uinst_t->u_lock : A * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ int oplmsu_rcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag) { lpath_t *lpath; ctrl_t *ctrl; queue_t *dst_queue = NULL; int act_flag; ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); mutex_enter(&oplmsu_uinst->l_lock); lpath = (lpath_t *)q->q_ptr; if (lpath->uinst != NULL) { act_flag = ACTIVE_RES; } else { act_flag = NOT_ACTIVE_RES; } mutex_exit(&oplmsu_uinst->l_lock); mutex_enter(&oplmsu_uinst->c_lock); if (((ctrl = oplmsu_uinst->user_ctrl) != NULL) && (((mp->b_datap->db_type == M_IOCACK) || (mp->b_datap->db_type == M_IOCNAK)) || (act_flag == ACTIVE_RES))) { dst_queue = RD(ctrl->queue); } else { mutex_exit(&oplmsu_uinst->c_lock); freemsg(mp); return (SUCCESS); } if (pri_flag == MSU_HIGH) { (void) putq(dst_queue, mp); } else { if (canput(dst_queue)) { (void) putq(dst_queue, mp); } else { /* * Place a normal priority message at the head of * read queue */ ctrl = (ctrl_t *)dst_queue->q_ptr; ctrl->lrq_flag = 1; ctrl->lrq_queue = q; mutex_exit(&oplmsu_uinst->c_lock); (void) putbq(q, mp); return (FAILURE); } } mutex_exit(&oplmsu_uinst->c_lock); return (SUCCESS); } /* * Restart queuing for high priority message of read stream * when flow control failed * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : P * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_rcmn_high_qenable(queue_t *q) { mblk_t *mp; struct iocblk *iocp = NULL; lpath_t *lpath; int rval; rw_enter(&oplmsu_uinst->lock, RW_READER); for (;;) { /* Handle high priority message */ mutex_enter(&oplmsu_uinst->l_lock); lpath = (lpath_t *)q->q_ptr; if ((mp = lpath->first_lpri_hi) == NULL) { mutex_exit(&oplmsu_uinst->l_lock); break; } if (mp->b_next == NULL) { lpath->first_lpri_hi = NULL; lpath->last_lpri_hi = NULL; } else { lpath->first_lpri_hi = mp->b_next; mp->b_next->b_prev = NULL; mp->b_next = NULL; } mp->b_prev = NULL; mutex_exit(&oplmsu_uinst->l_lock); rval = SUCCESS; switch (mp->b_datap->db_type) { case M_IOCACK : /* FALLTHRU */ case M_IOCNAK : iocp = (struct iocblk *)mp->b_rptr; switch (iocp->ioc_cmd) { case TCSETS : /* FALLTHRU */ case TCSETSW : /* FALLTHRU */ case TCSETSF : /* FALLTHRU */ case TIOCMSET : /* FALLTHRU */ case TIOCSPPS : /* FALLTHRU */ case TIOCSWINSZ : /* FALLTHRU */ case TIOCSSOFTCAR : rw_exit(&oplmsu_uinst->lock); rval = oplmsu_lrioctl_termios(q, mp); rw_enter(&oplmsu_uinst->lock, RW_WRITER); break; default : rval = oplmsu_rcmn_through_hndl( q, mp, MSU_HIGH); if (rval == FAILURE) { rw_exit(&oplmsu_uinst->lock); return; } } break; case M_ERROR : rw_exit(&oplmsu_uinst->lock); rval = oplmsu_lrmsg_error(q, mp); rw_enter(&oplmsu_uinst->lock, RW_WRITER); break; case M_FLUSH : oplmsu_rcmn_flush_hndl(q, mp); break; default : rval = oplmsu_rcmn_through_hndl(q, mp, MSU_HIGH); if (rval == FAILURE) { rw_exit(&oplmsu_uinst->lock); return; } } if (rval == FAILURE) { break; } } rw_exit(&oplmsu_uinst->lock); qenable(q); /* Enable lower read queue */ } #ifdef DEBUG /* * Online trace * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : P * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_cmn_trace(queue_t *q, mblk_t *mp, int op) { struct iocblk *iocp; if ((op < MSU_TRC_UI) || (op > MSU_TRC_CLS)) { return; } mutex_enter(&oplmsu_ltrc_lock); if (oplmsu_debug_mode & MSU_DPRINT_ON) { oplmsu_cmn_msglog(mp, op); } /* Trace current counter */ (void) drv_getparm(LBOLT, (void *)&oplmsu_ltrc_ccnt); if (oplmsu_ltrc_cur == oplmsu_ltrc_tail) { oplmsu_ltrc_cur = oplmsu_ltrc_top; } else { oplmsu_ltrc_cur++; } oplmsu_ltrc_cur->q = q; oplmsu_ltrc_cur->mp = mp; switch (op) { case MSU_TRC_UI : oplmsu_ltrc_cur->op[0] = 'u'; oplmsu_ltrc_cur->op[1] = 'i'; break; case MSU_TRC_UO : oplmsu_ltrc_cur->op[0] = 'u'; oplmsu_ltrc_cur->op[1] = 'o'; break; case MSU_TRC_LI : oplmsu_ltrc_cur->op[0] = 'l'; oplmsu_ltrc_cur->op[1] = 'i'; break; case MSU_TRC_LO : oplmsu_ltrc_cur->op[0] = 'l'; oplmsu_ltrc_cur->op[1] = 'o'; break; case MSU_TRC_OPN : oplmsu_ltrc_cur->op[0] = 'o'; oplmsu_ltrc_cur->op[1] = 'p'; break; case MSU_TRC_CLS : oplmsu_ltrc_cur->op[0] = 'c'; oplmsu_ltrc_cur->op[1] = 'l'; break; } if ((op == MSU_TRC_LI) || (op == MSU_TRC_LO)) { mutex_enter(&oplmsu_uinst->l_lock); oplmsu_ltrc_cur->pathno = ((lpath_t *)q->q_ptr)->path_no; mutex_exit(&oplmsu_uinst->l_lock); } else { oplmsu_ltrc_cur->pathno = 0; } if ((op == MSU_TRC_OPN) || (op == MSU_TRC_CLS)) { oplmsu_ltrc_cur->msg_type = 0; oplmsu_ltrc_cur->msg_cmd = 0; oplmsu_ltrc_cur->data = 0; switch ((ulong_t)mp) { case MSU_NODE_USER : oplmsu_ltrc_cur->data = MSU_TRC_USER; break; case MSU_NODE_META : oplmsu_ltrc_cur->data = MSU_TRC_META; break; } oplmsu_ltrc_cur->mp = NULL; } else { oplmsu_ltrc_cur->msg_type = mp->b_datap->db_type; iocp = (struct iocblk *)mp->b_rptr; oplmsu_ltrc_cur->msg_cmd = iocp->ioc_cmd; if ((mp->b_datap->db_type == M_IOCTL) || (mp->b_datap->db_type == M_IOCACK) || (mp->b_datap->db_type == M_IOCNAK)) { oplmsu_ltrc_cur->msg_cmd = iocp->ioc_cmd; if (mp->b_cont != NULL) { oplmsu_ltrc_cur->data = (ulong_t)mp->b_cont->b_rptr; } else { oplmsu_ltrc_cur->data = 0; } } else { oplmsu_ltrc_cur->msg_cmd = 0; if (mp->b_rptr == NULL) { oplmsu_ltrc_cur->data = 0; } else { oplmsu_ltrc_cur->data = *(ulong_t *)mp->b_rptr; } } } mutex_exit(&oplmsu_ltrc_lock); } /* * Display message log to console * * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) * -. uinst_t->lock : P * -. uinst_t->u_lock : P * -. uinst_t->l_lock : P * -. uinst_t->c_lock : P */ void oplmsu_cmn_msglog(mblk_t *mp, int direction) { uchar_t *cur = NULL; mblk_t *tmp_mp = NULL; ulong_t len; ulong_t line; ulong_t col; ulong_t row; ulong_t count; char buffer[70]; char *bufp; if (mp == NULL) { return; } switch (direction) { case 0: cmn_err(CE_NOTE, "!---------- Upper in --------"); break; case 1: cmn_err(CE_NOTE, "!---------- Upper out -------"); break; case 2: cmn_err(CE_NOTE, "!---------- Lower in --------"); break; case 3: cmn_err(CE_NOTE, "!---------- Lower out -------"); break; default: return; } for (tmp_mp = mp; tmp_mp; tmp_mp = tmp_mp->b_cont) { cmn_err(CE_NOTE, "!db_type = 0x%02x", tmp_mp->b_datap->db_type); len = tmp_mp->b_wptr - tmp_mp->b_rptr; line = (len + 31) / 32; cur = (uchar_t *)tmp_mp->b_rptr; count = 0; for (col = 0; col < line; col++) { bufp = buffer; for (row = 0; row < 32; row++) { if (row != 0 && (row % 8) == 0) { *bufp = ' '; bufp++; } (void) sprintf(bufp, "%02x", *cur); bufp += 2; cur++; count++; if (count >= len) { break; } } *bufp = '\0'; cmn_err(CE_NOTE, "!%s", buffer); if (count >= len) { break; } } } } void oplmsu_cmn_prt_pathname(dev_info_t *dip) { char pathname[128]; char wrkbuf[128]; (void) ddi_pathname(dip, wrkbuf); *(wrkbuf + strlen(wrkbuf)) = '\0'; (void) sprintf(pathname, "/devices%s:%c", wrkbuf, 'a'+ ddi_get_instance(dip)); DBG_PRINT((CE_NOTE, "oplmsu: debug-info: " "Active path change to path => %s", pathname)); } #endif