125cf1a30Sjl139090 /*
225cf1a30Sjl139090 * CDDL HEADER START
325cf1a30Sjl139090 *
425cf1a30Sjl139090 * The contents of this file are subject to the terms of the
525cf1a30Sjl139090 * Common Development and Distribution License (the "License").
625cf1a30Sjl139090 * You may not use this file except in compliance with the License.
725cf1a30Sjl139090 *
825cf1a30Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl139090 * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl139090 * See the License for the specific language governing permissions
1125cf1a30Sjl139090 * and limitations under the License.
1225cf1a30Sjl139090 *
1325cf1a30Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl139090 * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl139090 *
1925cf1a30Sjl139090 * CDDL HEADER END
2025cf1a30Sjl139090 */
2119397407SSherry Moore
2225cf1a30Sjl139090 /*
2325cf1a30Sjl139090 * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006
2425cf1a30Sjl139090 */
2525cf1a30Sjl139090
2619397407SSherry Moore /*
2707d06da5SSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2819397407SSherry Moore * Use is subject to license terms.
2919397407SSherry Moore */
3019397407SSherry Moore
31*3fe80ca4SDan Cross /*
32*3fe80ca4SDan Cross * Copyright 2023 Oxide Computer Company
33*3fe80ca4SDan Cross */
3425cf1a30Sjl139090
3525cf1a30Sjl139090 #include <sys/errno.h>
3625cf1a30Sjl139090 #include <sys/modctl.h>
3725cf1a30Sjl139090 #include <sys/stat.h>
3825cf1a30Sjl139090 #include <sys/kmem.h>
3925cf1a30Sjl139090 #include <sys/ksynch.h>
4025cf1a30Sjl139090 #include <sys/stream.h>
4125cf1a30Sjl139090 #include <sys/stropts.h>
4225cf1a30Sjl139090 #include <sys/termio.h>
4325cf1a30Sjl139090 #include <sys/ddi.h>
4425cf1a30Sjl139090 #include <sys/file.h>
4525cf1a30Sjl139090 #include <sys/disp.h>
4625cf1a30Sjl139090 #include <sys/sunddi.h>
4725cf1a30Sjl139090 #include <sys/sunldi.h>
4825cf1a30Sjl139090 #include <sys/sunndi.h>
4925cf1a30Sjl139090 #include <sys/kbio.h>
5025cf1a30Sjl139090 #include <sys/prom_plat.h>
5125cf1a30Sjl139090 #include <sys/oplmsu/oplmsu.h>
5225cf1a30Sjl139090 #include <sys/oplmsu/oplmsu_proto.h>
5325cf1a30Sjl139090
5425cf1a30Sjl139090 extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
5525cf1a30Sjl139090
5625cf1a30Sjl139090 #define MOD_ID 0xe145
5725cf1a30Sjl139090 #define MOD_NAME "oplmsu"
5825cf1a30Sjl139090
5925cf1a30Sjl139090 #define META_NAME "oplmsu"
6025cf1a30Sjl139090 #define USER_NAME "a"
6125cf1a30Sjl139090
6225cf1a30Sjl139090 struct module_info oplmsu_mod_info = {
6325cf1a30Sjl139090 MOD_ID,
6425cf1a30Sjl139090 MOD_NAME,
6525cf1a30Sjl139090 0,
6625cf1a30Sjl139090 16384,
6725cf1a30Sjl139090 14336,
6825cf1a30Sjl139090 2048
6925cf1a30Sjl139090 };
7025cf1a30Sjl139090
7125cf1a30Sjl139090 struct qinit oplmsu_urinit = {
7225cf1a30Sjl139090 NULL,
7325cf1a30Sjl139090 oplmsu_ursrv,
7425cf1a30Sjl139090 oplmsu_open,
7525cf1a30Sjl139090 oplmsu_close,
7625cf1a30Sjl139090 NULL,
7725cf1a30Sjl139090 &oplmsu_mod_info,
7825cf1a30Sjl139090 NULL
7925cf1a30Sjl139090 };
8025cf1a30Sjl139090
8125cf1a30Sjl139090 struct qinit oplmsu_uwinit = {
8225cf1a30Sjl139090 oplmsu_uwput,
8325cf1a30Sjl139090 oplmsu_uwsrv,
8425cf1a30Sjl139090 oplmsu_open,
8525cf1a30Sjl139090 oplmsu_close,
8625cf1a30Sjl139090 NULL,
8725cf1a30Sjl139090 &oplmsu_mod_info,
8825cf1a30Sjl139090 NULL
8925cf1a30Sjl139090 };
9025cf1a30Sjl139090
9125cf1a30Sjl139090 struct qinit oplmsu_lrinit = {
9225cf1a30Sjl139090 oplmsu_lrput,
9325cf1a30Sjl139090 oplmsu_lrsrv,
9425cf1a30Sjl139090 oplmsu_open,
9525cf1a30Sjl139090 oplmsu_close,
9625cf1a30Sjl139090 NULL,
9725cf1a30Sjl139090 &oplmsu_mod_info,
9825cf1a30Sjl139090 NULL
9925cf1a30Sjl139090 };
10025cf1a30Sjl139090
10125cf1a30Sjl139090 struct qinit oplmsu_lwinit = {
10225cf1a30Sjl139090 NULL,
10325cf1a30Sjl139090 oplmsu_lwsrv,
10425cf1a30Sjl139090 oplmsu_open,
10525cf1a30Sjl139090 oplmsu_close,
10625cf1a30Sjl139090 NULL,
10725cf1a30Sjl139090 &oplmsu_mod_info,
10825cf1a30Sjl139090 NULL
10925cf1a30Sjl139090 };
11025cf1a30Sjl139090
11125cf1a30Sjl139090 struct streamtab oplmsu_info = {
11225cf1a30Sjl139090 &oplmsu_urinit,
11325cf1a30Sjl139090 &oplmsu_uwinit,
11425cf1a30Sjl139090 &oplmsu_lrinit,
11525cf1a30Sjl139090 &oplmsu_lwinit
11625cf1a30Sjl139090 };
11725cf1a30Sjl139090
11825cf1a30Sjl139090 static struct cb_ops cb_oplmsu_ops = {
11925cf1a30Sjl139090 nulldev, /* cb_open */
12025cf1a30Sjl139090 nulldev, /* cb_close */
12125cf1a30Sjl139090 nodev, /* cb_strategy */
12225cf1a30Sjl139090 nodev, /* cb_print */
12325cf1a30Sjl139090 nodev, /* cb_dump */
12425cf1a30Sjl139090 nodev, /* cb_read */
12525cf1a30Sjl139090 nodev, /* cb_write */
12625cf1a30Sjl139090 nodev, /* cb_ioctl */
12725cf1a30Sjl139090 nodev, /* cb_devmap */
12825cf1a30Sjl139090 nodev, /* cb_mmap */
12925cf1a30Sjl139090 nodev, /* cb_segmap */
13025cf1a30Sjl139090 nochpoll, /* cb_chpoll */
13125cf1a30Sjl139090 ddi_prop_op, /* cb_prop_op */
13225cf1a30Sjl139090 (&oplmsu_info), /* cb_stream */
13325cf1a30Sjl139090 (int)(D_NEW|D_MP|D_HOTPLUG) /* cb_flag */
13425cf1a30Sjl139090 };
13525cf1a30Sjl139090
13625cf1a30Sjl139090 static struct dev_ops oplmsu_ops = {
13725cf1a30Sjl139090 DEVO_REV, /* devo_rev */
13825cf1a30Sjl139090 0, /* devo_refcnt */
13925cf1a30Sjl139090 (oplmsu_getinfo), /* devo_getinfo */
14025cf1a30Sjl139090 (nulldev), /* devo_identify */
14125cf1a30Sjl139090 (nulldev), /* devo_probe */
14225cf1a30Sjl139090 (oplmsu_attach), /* devo_attach */
14325cf1a30Sjl139090 (oplmsu_detach), /* devo_detach */
14425cf1a30Sjl139090 (nodev), /* devo_reset */
14525cf1a30Sjl139090 &(cb_oplmsu_ops), /* devo_cb_ops */
14625cf1a30Sjl139090 (struct bus_ops *)NULL, /* devo_bus_ops */
14719397407SSherry Moore NULL, /* devo_power */
14819397407SSherry Moore ddi_quiesce_not_needed, /* dev_quiesce */
14925cf1a30Sjl139090 };
15025cf1a30Sjl139090
15125cf1a30Sjl139090 struct modldrv modldrv = {
15225cf1a30Sjl139090 &mod_driverops,
15319397407SSherry Moore "OPL serial mux driver",
15425cf1a30Sjl139090 &oplmsu_ops
15525cf1a30Sjl139090 };
15625cf1a30Sjl139090
15725cf1a30Sjl139090 struct modlinkage modlinkage = {
15825cf1a30Sjl139090 MODREV_1,
15925cf1a30Sjl139090 (void *)&modldrv,
16025cf1a30Sjl139090 NULL
16125cf1a30Sjl139090 };
16225cf1a30Sjl139090
16325cf1a30Sjl139090 uinst_t oplmsu_uinst_local; /* upper_instance_table structure */
16425cf1a30Sjl139090 uinst_t *oplmsu_uinst = &oplmsu_uinst_local;
16525cf1a30Sjl139090 int oplmsu_queue_flag; /* Enable/disable queueing flag */
16625cf1a30Sjl139090 int oplmsu_check_su; /* Check super-user flag */
16725cf1a30Sjl139090
16825cf1a30Sjl139090 #ifdef DEBUG
16925cf1a30Sjl139090 int oplmsu_debug_mode = 0; /* Enable/disable debug mode */
17025cf1a30Sjl139090 int oplmsu_trace_on; /* Enable/disable trace */
17125cf1a30Sjl139090 uint_t oplmsu_ltrc_size; /* Trace buffer size */
17225cf1a30Sjl139090 msu_trc_t *oplmsu_ltrc_top; /* Top of trace data area */
17325cf1a30Sjl139090 msu_trc_t *oplmsu_ltrc_tail; /* Tail of trace data area */
17425cf1a30Sjl139090 msu_trc_t *oplmsu_ltrc_cur; /* Current pointer of trace data area */
17525cf1a30Sjl139090 ulong_t oplmsu_ltrc_ccnt; /* Current counter */
17625cf1a30Sjl139090 kmutex_t oplmsu_ltrc_lock; /* Lock table for trace mode */
17725cf1a30Sjl139090 #endif
17825cf1a30Sjl139090
17925cf1a30Sjl139090 /* oplmsu_conf_st */
18025cf1a30Sjl139090 #define MSU_CONFIGURED 2
18125cf1a30Sjl139090 #define MSU_CONFIGURING 1
18225cf1a30Sjl139090 #define MSU_UNCONFIGURED 0
18325cf1a30Sjl139090
18425cf1a30Sjl139090 static kmutex_t oplmsu_bthrd_excl;
18525cf1a30Sjl139090 static kthread_id_t oplmsu_bthrd_id = NULL;
18625cf1a30Sjl139090 static int oplmsu_conf_st = MSU_UNCONFIGURED;
18725cf1a30Sjl139090 static kcondvar_t oplmsu_conf_cv;
18825cf1a30Sjl139090
18925cf1a30Sjl139090
19025cf1a30Sjl139090 /*
19125cf1a30Sjl139090 * Locking hierarcy of oplmsu driver. This driver have 5 locks in uinst_t.
19225cf1a30Sjl139090 *
19325cf1a30Sjl139090 * Each mutex guards as follows.
19425cf1a30Sjl139090 *
19525cf1a30Sjl139090 * uinst_t->lock: This mutex is read/write mutex.
19625cf1a30Sjl139090 * read lock : acquired if the member of uinst_t is refered only.
19725cf1a30Sjl139090 * write lock: acquired if the member of uinst_t is changed.
19825cf1a30Sjl139090 *
19925cf1a30Sjl139090 * uinst_t->u_lock: This mutex is normal mutex.
20025cf1a30Sjl139090 * This mutex is acquired at reading/changing the member of all upath_t.
20125cf1a30Sjl139090 *
20225cf1a30Sjl139090 * uinst_t->l_lock: This mutex is normal mutex.
20325cf1a30Sjl139090 * This mutex is acquired at reading/changing the member of all lpath_t.
20425cf1a30Sjl139090 *
20525cf1a30Sjl139090 * uinst_t->c_lock: This mutex is normal mutex.
20625cf1a30Sjl139090 * This mutex is acquired at reading/changing the member of the ctrl_t.
20725cf1a30Sjl139090 *
20825cf1a30Sjl139090 * oplmsu_bthrd_excl: This mutex is normal mutex.
20925cf1a30Sjl139090 * This mutex is used only to start/stop the configuring thread of the
21025cf1a30Sjl139090 * multiplexed STREAMS.
21125cf1a30Sjl139090 * This mutex is exclusively acquired with the above-mentioned 4 mutexes.
21225cf1a30Sjl139090 *
21325cf1a30Sjl139090 * To guard of the deadlock by cross locking, the base locking hierarcy
21425cf1a30Sjl139090 * is as follows:
21525cf1a30Sjl139090 *
21625cf1a30Sjl139090 * uisnt->lock ==> uinst->u_lock ==> uinst->l_lock ==> uinst->c_lock
21725cf1a30Sjl139090 *
21825cf1a30Sjl139090 */
21925cf1a30Sjl139090
22025cf1a30Sjl139090
22125cf1a30Sjl139090 int
_init(void)22225cf1a30Sjl139090 _init(void)
22325cf1a30Sjl139090 {
22425cf1a30Sjl139090 int rval;
22525cf1a30Sjl139090
22625cf1a30Sjl139090 /* Initialize R/W lock for uinst_t */
22725cf1a30Sjl139090 rw_init(&oplmsu_uinst->lock, "uinst rwlock", RW_DRIVER, NULL);
22825cf1a30Sjl139090
22925cf1a30Sjl139090 /* Initialize mutex for upath_t */
23025cf1a30Sjl139090 mutex_init(&oplmsu_uinst->u_lock, "upath lock", MUTEX_DRIVER, NULL);
23125cf1a30Sjl139090
23225cf1a30Sjl139090 /* Initialize mutex for lpath_t */
23325cf1a30Sjl139090 mutex_init(&oplmsu_uinst->l_lock, "lpath lock", MUTEX_DRIVER, NULL);
23425cf1a30Sjl139090
23525cf1a30Sjl139090 /* Initialize mutex for ctrl_t */
23625cf1a30Sjl139090 mutex_init(&oplmsu_uinst->c_lock, "ctrl lock", MUTEX_DRIVER, NULL);
23725cf1a30Sjl139090
23825cf1a30Sjl139090 /* Initialize mutex for protecting background thread */
23925cf1a30Sjl139090 mutex_init(&oplmsu_bthrd_excl, NULL, MUTEX_DRIVER, NULL);
24025cf1a30Sjl139090
24125cf1a30Sjl139090 /* Initialize condition variable */
24225cf1a30Sjl139090 cv_init(&oplmsu_conf_cv, NULL, CV_DRIVER, NULL);
24325cf1a30Sjl139090
24425cf1a30Sjl139090 rval = mod_install(&modlinkage);
24525cf1a30Sjl139090 if (rval != DDI_SUCCESS) {
24625cf1a30Sjl139090 cv_destroy(&oplmsu_conf_cv);
24725cf1a30Sjl139090 mutex_destroy(&oplmsu_bthrd_excl);
24825cf1a30Sjl139090 mutex_destroy(&oplmsu_uinst->c_lock);
24925cf1a30Sjl139090 mutex_destroy(&oplmsu_uinst->l_lock);
25025cf1a30Sjl139090 mutex_destroy(&oplmsu_uinst->u_lock);
25125cf1a30Sjl139090 rw_destroy(&oplmsu_uinst->lock);
25225cf1a30Sjl139090 }
25325cf1a30Sjl139090 return (rval);
25425cf1a30Sjl139090 }
25525cf1a30Sjl139090
25625cf1a30Sjl139090 int
_fini(void)25725cf1a30Sjl139090 _fini(void)
25825cf1a30Sjl139090 {
25925cf1a30Sjl139090 int rval;
26025cf1a30Sjl139090
26125cf1a30Sjl139090 rval = mod_remove(&modlinkage);
26225cf1a30Sjl139090 if (rval == DDI_SUCCESS) {
26325cf1a30Sjl139090 cv_destroy(&oplmsu_conf_cv);
26425cf1a30Sjl139090 mutex_destroy(&oplmsu_bthrd_excl);
26525cf1a30Sjl139090 mutex_destroy(&oplmsu_uinst->c_lock);
26625cf1a30Sjl139090 mutex_destroy(&oplmsu_uinst->l_lock);
26725cf1a30Sjl139090 mutex_destroy(&oplmsu_uinst->u_lock);
26825cf1a30Sjl139090 rw_destroy(&oplmsu_uinst->lock);
26925cf1a30Sjl139090 }
27025cf1a30Sjl139090 return (rval);
27125cf1a30Sjl139090 }
27225cf1a30Sjl139090
27325cf1a30Sjl139090 int
_info(struct modinfo * modinfop)27425cf1a30Sjl139090 _info(struct modinfo *modinfop)
27525cf1a30Sjl139090 {
27625cf1a30Sjl139090 return (mod_info(&modlinkage, modinfop));
27725cf1a30Sjl139090 }
27825cf1a30Sjl139090
27925cf1a30Sjl139090 /* ARGSUSED */
28025cf1a30Sjl139090 int
oplmsu_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)28125cf1a30Sjl139090 oplmsu_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
28225cf1a30Sjl139090 {
28325cf1a30Sjl139090 dev_t dev = (dev_t)arg;
28425cf1a30Sjl139090 minor_t inst;
28525cf1a30Sjl139090 int rval = DDI_SUCCESS;
28625cf1a30Sjl139090
28725cf1a30Sjl139090 switch (cmd) {
28825cf1a30Sjl139090 case DDI_INFO_DEVT2DEVINFO :
28925cf1a30Sjl139090 if (oplmsu_uinst->msu_dip == NULL) {
29025cf1a30Sjl139090 rval = DDI_FAILURE;
29125cf1a30Sjl139090 } else {
29225cf1a30Sjl139090 *resultp = oplmsu_uinst->msu_dip;
29325cf1a30Sjl139090 }
29425cf1a30Sjl139090 break;
29525cf1a30Sjl139090
29625cf1a30Sjl139090 case DDI_INFO_DEVT2INSTANCE :
29725cf1a30Sjl139090 inst = getminor(dev) & ~(META_NODE_MASK|USER_NODE_MASK);
29825cf1a30Sjl139090 *resultp = (void *)(uintptr_t)inst;
29925cf1a30Sjl139090 break;
30025cf1a30Sjl139090
30125cf1a30Sjl139090 default :
30225cf1a30Sjl139090 rval = DDI_FAILURE;
30325cf1a30Sjl139090 break;
30425cf1a30Sjl139090 }
30525cf1a30Sjl139090 return (rval);
30625cf1a30Sjl139090 }
30725cf1a30Sjl139090
30825cf1a30Sjl139090 int
oplmsu_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)30925cf1a30Sjl139090 oplmsu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
31025cf1a30Sjl139090 {
31125cf1a30Sjl139090 minor_t meta_minor, user_minor;
31225cf1a30Sjl139090 int rval = 0;
31325cf1a30Sjl139090 int instance;
31425cf1a30Sjl139090 #define CNTRL(c) ((c) & 037)
31525cf1a30Sjl139090 char abt_ch_seq[3] = { '\r', '~', CNTRL('b') };
31625cf1a30Sjl139090
31725cf1a30Sjl139090 if (cmd == DDI_RESUME) {
31825cf1a30Sjl139090 return (DDI_SUCCESS);
31925cf1a30Sjl139090 }
32025cf1a30Sjl139090
32125cf1a30Sjl139090 if (cmd != DDI_ATTACH) {
32225cf1a30Sjl139090 return (DDI_FAILURE);
32325cf1a30Sjl139090 }
32425cf1a30Sjl139090
32525cf1a30Sjl139090 instance = ddi_get_instance(dip);
32625cf1a30Sjl139090 if (instance != 0) {
32725cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: attach: "
32825cf1a30Sjl139090 "Invaild instance => %d", instance);
32925cf1a30Sjl139090 return (DDI_FAILURE);
33025cf1a30Sjl139090 }
33125cf1a30Sjl139090
33225cf1a30Sjl139090 /* Create minor number for meta control node */
33325cf1a30Sjl139090 meta_minor = instance | META_NODE_MASK;
33425cf1a30Sjl139090 /* Create minor number for user access node */
33525cf1a30Sjl139090 user_minor = instance | USER_NODE_MASK;
33625cf1a30Sjl139090
33725cf1a30Sjl139090 /* Create minor node for user access */
33825cf1a30Sjl139090 rval = ddi_create_minor_node(dip, USER_NAME, S_IFCHR, user_minor,
33925cf1a30Sjl139090 DDI_NT_SERIAL, 0);
34025cf1a30Sjl139090 if (rval != DDI_SUCCESS) {
34125cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: attach: "
34225cf1a30Sjl139090 "ddi_create_minor_node failed. errno = %d", rval);
34325cf1a30Sjl139090 ddi_remove_minor_node(dip, NULL);
34425cf1a30Sjl139090 return (rval);
34525cf1a30Sjl139090 }
34625cf1a30Sjl139090
34725cf1a30Sjl139090 /* Create minor node for meta control */
34825cf1a30Sjl139090 rval = ddi_create_internal_pathname(dip, META_NAME, S_IFCHR,
34925cf1a30Sjl139090 meta_minor);
35025cf1a30Sjl139090 if (rval != DDI_SUCCESS) {
35125cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: attach: "
35225cf1a30Sjl139090 "ddi_create_internal_pathname failed. errno = %d", rval);
35325cf1a30Sjl139090 ddi_remove_minor_node(dip, NULL);
35425cf1a30Sjl139090 return (rval);
35525cf1a30Sjl139090 }
35625cf1a30Sjl139090
35725cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
35825cf1a30Sjl139090
35925cf1a30Sjl139090 /* Get each properties */
36025cf1a30Sjl139090 oplmsu_check_su = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
36125cf1a30Sjl139090 (DDI_PROP_DONTPASS|DDI_PROP_NOTPROM), "check-superuser", 1);
36225cf1a30Sjl139090
36325cf1a30Sjl139090 /*
36425cf1a30Sjl139090 * Initialize members of uinst_t
36525cf1a30Sjl139090 */
36625cf1a30Sjl139090
36725cf1a30Sjl139090 oplmsu_uinst->inst_status = INST_STAT_UNCONFIGURED;
36825cf1a30Sjl139090 oplmsu_uinst->path_num = UNDEFINED;
36925cf1a30Sjl139090 oplmsu_uinst->msu_dip = dip;
37025cf1a30Sjl139090 (void) strcpy(oplmsu_uinst->abts, abt_ch_seq);
37125cf1a30Sjl139090
37225cf1a30Sjl139090 #ifdef DEBUG
37325cf1a30Sjl139090 oplmsu_trace_on = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
37425cf1a30Sjl139090 (DDI_PROP_DONTPASS|DDI_PROP_NOTPROM), "trace-mode", 1);
37525cf1a30Sjl139090 oplmsu_ltrc_size = (uint_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
37625cf1a30Sjl139090 (DDI_PROP_DONTPASS|DDI_PROP_NOTPROM), "trace-bufsize", 128);
37725cf1a30Sjl139090
37825cf1a30Sjl139090 if (oplmsu_trace_on == MSU_TRACE_ON) {
37925cf1a30Sjl139090 /* Initialize mutex for msu_trc_t */
38025cf1a30Sjl139090 mutex_init(&oplmsu_ltrc_lock, "trc lock", MUTEX_DRIVER, NULL);
38125cf1a30Sjl139090
38225cf1a30Sjl139090 mutex_enter(&oplmsu_ltrc_lock);
38325cf1a30Sjl139090 oplmsu_ltrc_top = (msu_trc_t *)kmem_zalloc(
38425cf1a30Sjl139090 (sizeof (msu_trc_t) * oplmsu_ltrc_size), KM_SLEEP);
38525cf1a30Sjl139090 oplmsu_ltrc_cur = (msu_trc_t *)(oplmsu_ltrc_top - 1);
38625cf1a30Sjl139090 oplmsu_ltrc_tail =
38725cf1a30Sjl139090 (msu_trc_t *)(oplmsu_ltrc_top + (oplmsu_ltrc_size - 1));
38825cf1a30Sjl139090 mutex_exit(&oplmsu_ltrc_lock);
38925cf1a30Sjl139090 }
39025cf1a30Sjl139090 #endif
39125cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
39225cf1a30Sjl139090 ddi_report_dev(dip);
39325cf1a30Sjl139090 return (rval);
39425cf1a30Sjl139090 }
39525cf1a30Sjl139090
39625cf1a30Sjl139090 int
oplmsu_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)39725cf1a30Sjl139090 oplmsu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
39825cf1a30Sjl139090 {
39925cf1a30Sjl139090 lpath_t *lpath, *next_lpath;
40025cf1a30Sjl139090
40125cf1a30Sjl139090 if (cmd == DDI_SUSPEND) {
40225cf1a30Sjl139090 return (DDI_SUCCESS);
40325cf1a30Sjl139090 }
40425cf1a30Sjl139090
40525cf1a30Sjl139090 if (cmd != DDI_DETACH) {
40625cf1a30Sjl139090 return (DDI_FAILURE);
40725cf1a30Sjl139090 }
40825cf1a30Sjl139090
40925cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
41025cf1a30Sjl139090
41125cf1a30Sjl139090 /* Delete all upath_t */
41225cf1a30Sjl139090 oplmsu_delete_upath_info();
41325cf1a30Sjl139090
41425cf1a30Sjl139090 /* Delete all lpath_t */
41525cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
41625cf1a30Sjl139090 lpath = oplmsu_uinst->first_lpath;
41725cf1a30Sjl139090 oplmsu_uinst->first_lpath = NULL;
41825cf1a30Sjl139090 oplmsu_uinst->last_lpath = NULL;
41925cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
42025cf1a30Sjl139090
42125cf1a30Sjl139090 #ifdef DEBUG
42225cf1a30Sjl139090 if (oplmsu_trace_on == MSU_TRACE_ON) {
42325cf1a30Sjl139090 mutex_enter(&oplmsu_ltrc_lock);
42425cf1a30Sjl139090 if (oplmsu_ltrc_top != NULL) {
42525cf1a30Sjl139090 kmem_free(oplmsu_ltrc_top,
42625cf1a30Sjl139090 (sizeof (msu_trc_t) * oplmsu_ltrc_size));
42725cf1a30Sjl139090 }
42825cf1a30Sjl139090 oplmsu_ltrc_top = NULL;
42925cf1a30Sjl139090 oplmsu_ltrc_cur = NULL;
43025cf1a30Sjl139090 oplmsu_ltrc_tail = NULL;
43125cf1a30Sjl139090 mutex_exit(&oplmsu_ltrc_lock);
43225cf1a30Sjl139090
43325cf1a30Sjl139090 mutex_destroy(&oplmsu_ltrc_lock);
43425cf1a30Sjl139090 }
43525cf1a30Sjl139090 #endif
43625cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
43725cf1a30Sjl139090
43825cf1a30Sjl139090 while (lpath) {
43925cf1a30Sjl139090 if (lpath->rbuf_id) {
44025cf1a30Sjl139090 unbufcall(lpath->rbuf_id);
44125cf1a30Sjl139090 }
44225cf1a30Sjl139090
44325cf1a30Sjl139090 if (lpath->rtout_id) {
44407d06da5SSurya Prakki (void) untimeout(lpath->rtout_id);
44525cf1a30Sjl139090 }
44625cf1a30Sjl139090
44725cf1a30Sjl139090 if (lpath->rbuftbl) {
44825cf1a30Sjl139090 kmem_free(lpath->rbuftbl, sizeof (struct buf_tbl));
44925cf1a30Sjl139090 }
45025cf1a30Sjl139090
45125cf1a30Sjl139090 cv_destroy(&lpath->sw_cv);
45225cf1a30Sjl139090 next_lpath = lpath->l_next;
45325cf1a30Sjl139090 kmem_free(lpath, sizeof (lpath_t));
45425cf1a30Sjl139090 lpath = next_lpath;
45525cf1a30Sjl139090 }
45625cf1a30Sjl139090 ddi_remove_minor_node(dip, NULL);
45725cf1a30Sjl139090 return (DDI_SUCCESS);
45825cf1a30Sjl139090 }
45925cf1a30Sjl139090
46025cf1a30Sjl139090 /* ARGSUSED */
46125cf1a30Sjl139090 int
oplmsu_open(queue_t * urq,dev_t * dev,int oflag,int sflag,cred_t * cred_p)46225cf1a30Sjl139090 oplmsu_open(queue_t *urq, dev_t *dev, int oflag, int sflag, cred_t *cred_p)
46325cf1a30Sjl139090 {
46425cf1a30Sjl139090 ctrl_t *ctrl;
46525cf1a30Sjl139090 minor_t mindev = 0;
46625cf1a30Sjl139090 minor_t qmindev = 0;
46725cf1a30Sjl139090 major_t majdev;
46825cf1a30Sjl139090 ulong_t node_flag;
46925cf1a30Sjl139090
47025cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: open: "
47125cf1a30Sjl139090 "devt = 0x%lx, sflag = 0x%x", *dev, sflag));
47225cf1a30Sjl139090
47325cf1a30Sjl139090 if (sflag == CLONEOPEN) {
47425cf1a30Sjl139090 return (EINVAL);
47525cf1a30Sjl139090 }
47625cf1a30Sjl139090
47725cf1a30Sjl139090 /* Get minor device number */
47825cf1a30Sjl139090 qmindev = (minor_t)getminor(*dev);
47925cf1a30Sjl139090 /* Get node type */
48025cf1a30Sjl139090 node_flag = MSU_NODE_TYPE(qmindev);
48125cf1a30Sjl139090 if ((node_flag != MSU_NODE_USER) && (node_flag != MSU_NODE_META)) {
48225cf1a30Sjl139090 return (EINVAL);
48325cf1a30Sjl139090 }
48425cf1a30Sjl139090
48525cf1a30Sjl139090 mutex_enter(&oplmsu_bthrd_excl);
48625cf1a30Sjl139090 if ((node_flag == MSU_NODE_USER) &&
48725cf1a30Sjl139090 (oplmsu_conf_st != MSU_CONFIGURED)) { /* User access & First open */
48825cf1a30Sjl139090 int cv_rval;
48925cf1a30Sjl139090
49025cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: open: "
49125cf1a30Sjl139090 "oplmsu_conf_st = %x", oplmsu_conf_st));
49225cf1a30Sjl139090
49325cf1a30Sjl139090 if (oplmsu_conf_st == MSU_UNCONFIGURED) {
49425cf1a30Sjl139090 oplmsu_conf_st = MSU_CONFIGURING;
49525cf1a30Sjl139090
49625cf1a30Sjl139090 /* Start up background thread */
49725cf1a30Sjl139090 oplmsu_bthrd_id = thread_create(NULL, 2 * DEFAULTSTKSZ,
49825cf1a30Sjl139090 oplmsu_setup, (void *)oplmsu_uinst, 0, &p0, TS_RUN,
49925cf1a30Sjl139090 minclsyspri);
50025cf1a30Sjl139090 }
50125cf1a30Sjl139090
50225cf1a30Sjl139090 /*
50325cf1a30Sjl139090 * Wait with cv_wait_sig() until background thread is
50425cf1a30Sjl139090 * completed.
50525cf1a30Sjl139090 */
50625cf1a30Sjl139090 while (oplmsu_conf_st == MSU_CONFIGURING) {
50725cf1a30Sjl139090 cv_rval =
50825cf1a30Sjl139090 cv_wait_sig(&oplmsu_conf_cv, &oplmsu_bthrd_excl);
50925cf1a30Sjl139090 if (cv_rval == 0) {
51025cf1a30Sjl139090 mutex_exit(&oplmsu_bthrd_excl);
51125cf1a30Sjl139090 return (EINTR);
51225cf1a30Sjl139090 }
51325cf1a30Sjl139090 }
51425cf1a30Sjl139090 }
51525cf1a30Sjl139090 mutex_exit(&oplmsu_bthrd_excl);
51625cf1a30Sjl139090
51725cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
51825cf1a30Sjl139090
51925cf1a30Sjl139090 /*
52025cf1a30Sjl139090 * If the node which will open is meta-control-node or
52125cf1a30Sjl139090 * user-access-node, and q_ptr, this is queue_t queue
52225cf1a30Sjl139090 * table member, is not NULL, then oplmsu returns
52325cf1a30Sjl139090 * SUCCESS immidiately.
52425cf1a30Sjl139090 * This process is used to protect dual open.
52525cf1a30Sjl139090 */
52625cf1a30Sjl139090
52725cf1a30Sjl139090 if ((urq != NULL) && (urq->q_ptr != NULL)) {
52825cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
52925cf1a30Sjl139090 return (SUCCESS);
53025cf1a30Sjl139090 }
53125cf1a30Sjl139090
53225cf1a30Sjl139090 /*
53325cf1a30Sjl139090 * If the node which will open is User-Access-Node, and instance
53425cf1a30Sjl139090 * status of oplmsu is no ONLINE, then oplmsu_open process fails
53525cf1a30Sjl139090 * with return value 'EIO'.
53625cf1a30Sjl139090 */
53725cf1a30Sjl139090
53825cf1a30Sjl139090 if ((node_flag == MSU_NODE_USER) &&
53925cf1a30Sjl139090 (oplmsu_uinst->inst_status != INST_STAT_ONLINE)) {
54025cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
54125cf1a30Sjl139090 return (EIO);
54225cf1a30Sjl139090 }
54325cf1a30Sjl139090
54425cf1a30Sjl139090 mindev |= qmindev; /* Create minor device number */
54525cf1a30Sjl139090 majdev = getmajor(*dev); /* Get major device number */
54625cf1a30Sjl139090 *dev = makedevice(majdev, mindev); /* Make device number */
54725cf1a30Sjl139090
54825cf1a30Sjl139090 /* Allocate kernel memory for ctrl_t */
54925cf1a30Sjl139090 ctrl = (ctrl_t *)kmem_zalloc(sizeof (ctrl_t), KM_SLEEP);
55025cf1a30Sjl139090
55125cf1a30Sjl139090 /*
55225cf1a30Sjl139090 * Initialize members of ctrl_t
55325cf1a30Sjl139090 */
55425cf1a30Sjl139090 ctrl->minor = (minor_t)mindev;
55525cf1a30Sjl139090 ctrl->queue = urq;
55625cf1a30Sjl139090 ctrl->sleep_flag = CV_WAKEUP;
55725cf1a30Sjl139090 ctrl->node_type = node_flag;
55825cf1a30Sjl139090 ctrl->wbuftbl =
55925cf1a30Sjl139090 (struct buf_tbl *)kmem_zalloc(sizeof (struct buf_tbl), KM_SLEEP);
56025cf1a30Sjl139090 cv_init(&ctrl->cvp, "oplmsu ctrl_tbl condvar", CV_DRIVER, NULL);
56125cf1a30Sjl139090
56225cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->c_lock);
56325cf1a30Sjl139090
56425cf1a30Sjl139090 if (node_flag == MSU_NODE_USER) { /* User access node */
56525cf1a30Sjl139090
56625cf1a30Sjl139090 oplmsu_uinst->user_ctrl = ctrl;
56725cf1a30Sjl139090 oplmsu_queue_flag = 0;
56825cf1a30Sjl139090
56925cf1a30Sjl139090 } else { /* Meta control node */
57025cf1a30Sjl139090
57125cf1a30Sjl139090 oplmsu_uinst->meta_ctrl = ctrl;
57225cf1a30Sjl139090 }
57325cf1a30Sjl139090
57425cf1a30Sjl139090 RD(urq)->q_ptr = ctrl;
57525cf1a30Sjl139090 WR(urq)->q_ptr = ctrl;
57625cf1a30Sjl139090
57725cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->c_lock);
57825cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
57925cf1a30Sjl139090
58025cf1a30Sjl139090 OPLMSU_TRACE(urq, (mblk_t *)node_flag, MSU_TRC_OPN);
58125cf1a30Sjl139090
58225cf1a30Sjl139090 qprocson(urq); /* Enable put and service routine */
58325cf1a30Sjl139090 return (SUCCESS);
58425cf1a30Sjl139090 }
58525cf1a30Sjl139090
58625cf1a30Sjl139090 /* ARGSUSED */
58725cf1a30Sjl139090 int
oplmsu_close(queue_t * urq,int flag,cred_t * cred_p)58825cf1a30Sjl139090 oplmsu_close(queue_t *urq, int flag, cred_t *cred_p)
58925cf1a30Sjl139090 {
59025cf1a30Sjl139090 ctrl_t *ctrl;
59125cf1a30Sjl139090 minor_t qmindev = 0;
59225cf1a30Sjl139090 lpath_t *lpath;
59325cf1a30Sjl139090 ulong_t node_flag;
59425cf1a30Sjl139090 bufcall_id_t wbuf_id;
59525cf1a30Sjl139090 timeout_id_t wtout_id;
59625cf1a30Sjl139090
59725cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
59825cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
59925cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->c_lock);
60025cf1a30Sjl139090 if ((ctrl = urq->q_ptr) == NULL) {
60125cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->c_lock);
60225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
60325cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
60425cf1a30Sjl139090
60525cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: close: "
60625cf1a30Sjl139090 "close has already been completed"));
60725cf1a30Sjl139090 return (FAILURE);
60825cf1a30Sjl139090 }
60925cf1a30Sjl139090 qmindev = ctrl->minor;
61025cf1a30Sjl139090
61125cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: close: ctrl->minor = 0x%x", qmindev));
61225cf1a30Sjl139090
61325cf1a30Sjl139090 node_flag = MSU_NODE_TYPE(qmindev);
61425cf1a30Sjl139090 if (node_flag > MSU_NODE_META) {
61525cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->c_lock);
61625cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
61725cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
61825cf1a30Sjl139090 return (EINVAL);
61925cf1a30Sjl139090 }
62025cf1a30Sjl139090
62125cf1a30Sjl139090 /*
62225cf1a30Sjl139090 * Check that queue which is waiting for response from lower stream
62325cf1a30Sjl139090 * exist. If queue exists, oplmsu sets CV_SLEEP to sleep_flag.
62425cf1a30Sjl139090 */
62525cf1a30Sjl139090
62625cf1a30Sjl139090 for (lpath = oplmsu_uinst->first_lpath; lpath; ) {
62725cf1a30Sjl139090 if (((RD(urq) == lpath->hndl_uqueue) ||
62825cf1a30Sjl139090 (WR(urq) == lpath->hndl_uqueue)) &&
62925cf1a30Sjl139090 (lpath->hndl_mp != NULL)) {
63025cf1a30Sjl139090 ctrl->sleep_flag = CV_SLEEP;
63125cf1a30Sjl139090 break;
63225cf1a30Sjl139090 }
63325cf1a30Sjl139090
63425cf1a30Sjl139090 lpath = lpath->l_next;
63525cf1a30Sjl139090 }
63625cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
63725cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
63825cf1a30Sjl139090
63925cf1a30Sjl139090 /* If sleep_flag is not CV_SLEEP, oplmsu calls cv_wait. */
64025cf1a30Sjl139090 if (lpath) {
64125cf1a30Sjl139090 while (ctrl->sleep_flag != CV_WAKEUP) {
64225cf1a30Sjl139090 cv_wait(&ctrl->cvp, &oplmsu_uinst->c_lock);
64325cf1a30Sjl139090 }
64425cf1a30Sjl139090 }
64525cf1a30Sjl139090
64625cf1a30Sjl139090 flushq(RD(urq), FLUSHALL);
64725cf1a30Sjl139090 flushq(WR(urq), FLUSHALL);
64825cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->c_lock);
64925cf1a30Sjl139090 qprocsoff(urq); /* Disable queuing of queue */
65025cf1a30Sjl139090
65125cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
65225cf1a30Sjl139090 switch (node_flag) {
65325cf1a30Sjl139090 case MSU_NODE_USER : /* User access node */
65425cf1a30Sjl139090 oplmsu_uinst->user_ctrl = NULL;
65525cf1a30Sjl139090 oplmsu_queue_flag = 0;
65625cf1a30Sjl139090 break;
65725cf1a30Sjl139090
65825cf1a30Sjl139090 case MSU_NODE_META : /* Meta control node */
65925cf1a30Sjl139090 oplmsu_uinst->meta_ctrl = NULL;
66025cf1a30Sjl139090 break;
66125cf1a30Sjl139090
66225cf1a30Sjl139090 default :
66325cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: close: node_flag = 0x%lx", node_flag);
66425cf1a30Sjl139090 }
66525cf1a30Sjl139090
666bbe1232eSToomas Soome ctrl->minor = 0;
66725cf1a30Sjl139090 ctrl->queue = NULL;
66825cf1a30Sjl139090 wbuf_id = ctrl->wbuf_id;
66925cf1a30Sjl139090 wtout_id = ctrl->wtout_id;
67025cf1a30Sjl139090 ctrl->wbuf_id = 0;
67125cf1a30Sjl139090 ctrl->wtout_id = 0;
67225cf1a30Sjl139090
67325cf1a30Sjl139090 cv_destroy(&ctrl->cvp);
67425cf1a30Sjl139090 kmem_free(ctrl->wbuftbl, sizeof (struct buf_tbl));
67525cf1a30Sjl139090 ctrl->wbuftbl = NULL;
67625cf1a30Sjl139090
67725cf1a30Sjl139090 RD(urq)->q_ptr = NULL;
67825cf1a30Sjl139090 WR(urq)->q_ptr = NULL;
67925cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
68025cf1a30Sjl139090
68125cf1a30Sjl139090 if (wbuf_id != 0) {
68225cf1a30Sjl139090 unbufcall(wbuf_id);
68325cf1a30Sjl139090 }
68425cf1a30Sjl139090
68525cf1a30Sjl139090 if (wtout_id != 0) {
68607d06da5SSurya Prakki (void) untimeout(wtout_id);
68725cf1a30Sjl139090 }
68825cf1a30Sjl139090
68925cf1a30Sjl139090 /* Free kernel memory for ctrl_t */
69025cf1a30Sjl139090 kmem_free(ctrl, sizeof (ctrl_t));
69125cf1a30Sjl139090
69225cf1a30Sjl139090 OPLMSU_TRACE(urq, (mblk_t *)node_flag, MSU_TRC_CLS);
69325cf1a30Sjl139090 return (SUCCESS);
69425cf1a30Sjl139090 }
69525cf1a30Sjl139090
69625cf1a30Sjl139090 /*
69725cf1a30Sjl139090 * Upper write put procedure
69825cf1a30Sjl139090 */
69925cf1a30Sjl139090 int
oplmsu_uwput(queue_t * uwq,mblk_t * mp)70025cf1a30Sjl139090 oplmsu_uwput(queue_t *uwq, mblk_t *mp)
70125cf1a30Sjl139090 {
70225cf1a30Sjl139090
70325cf1a30Sjl139090 if (mp == NULL) {
70425cf1a30Sjl139090 return (SUCCESS);
70525cf1a30Sjl139090 }
70625cf1a30Sjl139090
70725cf1a30Sjl139090 if ((uwq == NULL) || (uwq->q_ptr == NULL)) {
70825cf1a30Sjl139090 freemsg(mp);
70925cf1a30Sjl139090 return (SUCCESS);
71025cf1a30Sjl139090 }
71125cf1a30Sjl139090
71225cf1a30Sjl139090 OPLMSU_TRACE(uwq, mp, MSU_TRC_UI);
71325cf1a30Sjl139090
71425cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
71525cf1a30Sjl139090 if (mp->b_datap->db_type == M_FLUSH) {
71625cf1a30Sjl139090 oplmsu_wcmn_flush_hndl(uwq, mp, RW_READER);
71725cf1a30Sjl139090 } else if (mp->b_datap->db_type >= QPCTL) {
71825cf1a30Sjl139090 ctrl_t *ctrl;
71925cf1a30Sjl139090
72025cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->c_lock);
72125cf1a30Sjl139090 ctrl = (ctrl_t *)uwq->q_ptr;
72225cf1a30Sjl139090
72325cf1a30Sjl139090 /* Link high priority message to local queue */
72425cf1a30Sjl139090 oplmsu_link_high_primsg(&ctrl->first_upri_hi,
72525cf1a30Sjl139090 &ctrl->last_upri_hi, mp);
72625cf1a30Sjl139090
72725cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->c_lock);
72825cf1a30Sjl139090 oplmsu_wcmn_high_qenable(WR(uwq), RW_READER);
72925cf1a30Sjl139090 } else {
73007d06da5SSurya Prakki (void) putq(WR(uwq), mp);
73125cf1a30Sjl139090 }
73225cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
73325cf1a30Sjl139090 return (SUCCESS);
73425cf1a30Sjl139090 }
73525cf1a30Sjl139090
73625cf1a30Sjl139090 /*
73725cf1a30Sjl139090 * Upper write service procedure
73825cf1a30Sjl139090 */
73925cf1a30Sjl139090 int
oplmsu_uwsrv(queue_t * uwq)74025cf1a30Sjl139090 oplmsu_uwsrv(queue_t *uwq)
74125cf1a30Sjl139090 {
74225cf1a30Sjl139090 struct iocblk *iocp = NULL;
74325cf1a30Sjl139090 mblk_t *mp = NULL;
74425cf1a30Sjl139090 int rval;
74525cf1a30Sjl139090
74625cf1a30Sjl139090 if ((uwq == NULL) || (uwq->q_ptr == NULL)) {
74725cf1a30Sjl139090 return (FAILURE);
74825cf1a30Sjl139090 }
74925cf1a30Sjl139090
75025cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
75125cf1a30Sjl139090
75225cf1a30Sjl139090 /* Handle high priority message */
75325cf1a30Sjl139090 while (mp = oplmsu_wcmn_high_getq(uwq)) {
75425cf1a30Sjl139090 if (mp->b_datap->db_type == M_FLUSH) {
75525cf1a30Sjl139090 oplmsu_wcmn_flush_hndl(uwq, mp, RW_READER);
75625cf1a30Sjl139090 continue;
75725cf1a30Sjl139090 }
75825cf1a30Sjl139090
75925cf1a30Sjl139090 if (oplmsu_wcmn_through_hndl(uwq, mp, MSU_HIGH, RW_READER) ==
76025cf1a30Sjl139090 FAILURE) {
76125cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
76225cf1a30Sjl139090 return (SUCCESS);
76325cf1a30Sjl139090 }
76425cf1a30Sjl139090 }
76525cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
76625cf1a30Sjl139090
76725cf1a30Sjl139090 /* Handle normal priority message */
76825cf1a30Sjl139090 while (mp = getq(uwq)) {
76925cf1a30Sjl139090 rval = SUCCESS;
77025cf1a30Sjl139090 switch (mp->b_datap->db_type) {
77125cf1a30Sjl139090 case M_IOCTL :
77225cf1a30Sjl139090 iocp = (struct iocblk *)mp->b_rptr;
77325cf1a30Sjl139090 switch (iocp->ioc_cmd) {
77425cf1a30Sjl139090 case I_PLINK :
77525cf1a30Sjl139090 if (oplmsu_cmn_pullup_msg(uwq, mp) != FAILURE) {
77625cf1a30Sjl139090 rval = oplmsu_uwioctl_iplink(uwq, mp);
77725cf1a30Sjl139090 }
77825cf1a30Sjl139090 break;
77925cf1a30Sjl139090
78025cf1a30Sjl139090 case I_PUNLINK :
78125cf1a30Sjl139090 if (oplmsu_cmn_pullup_msg(uwq, mp) != FAILURE) {
78225cf1a30Sjl139090 rval = oplmsu_uwioctl_ipunlink(uwq, mp);
78325cf1a30Sjl139090 }
78425cf1a30Sjl139090 break;
78525cf1a30Sjl139090
78625cf1a30Sjl139090 case TCSETS : /* FALLTHRU */
78725cf1a30Sjl139090 case TCSETSW : /* FALLTHRU */
78825cf1a30Sjl139090 case TCSETSF : /* FALLTHRU */
78925cf1a30Sjl139090 case TIOCMSET : /* FALLTHRU */
79025cf1a30Sjl139090 case TIOCSPPS : /* FALLTHRU */
79125cf1a30Sjl139090 case TIOCSWINSZ : /* FALLTHRU */
79225cf1a30Sjl139090 case TIOCSSOFTCAR :
79325cf1a30Sjl139090 rval = oplmsu_uwioctl_termios(uwq, mp);
79425cf1a30Sjl139090 break;
79525cf1a30Sjl139090
79625cf1a30Sjl139090 default :
79725cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
79825cf1a30Sjl139090 rval = oplmsu_wcmn_through_hndl(uwq, mp,
79925cf1a30Sjl139090 MSU_NORM, RW_READER);
80025cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
80125cf1a30Sjl139090 break;
80225cf1a30Sjl139090 }
80325cf1a30Sjl139090 break;
80425cf1a30Sjl139090
80525cf1a30Sjl139090 default :
80625cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
80725cf1a30Sjl139090 rval = oplmsu_wcmn_through_hndl(uwq, mp, MSU_NORM,
80825cf1a30Sjl139090 RW_READER);
80925cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
81025cf1a30Sjl139090 break;
81125cf1a30Sjl139090 }
81225cf1a30Sjl139090
81325cf1a30Sjl139090 if (rval == FAILURE) {
81425cf1a30Sjl139090 break;
81525cf1a30Sjl139090 }
81625cf1a30Sjl139090 }
81725cf1a30Sjl139090 return (SUCCESS);
81825cf1a30Sjl139090 }
81925cf1a30Sjl139090
82025cf1a30Sjl139090 /*
82125cf1a30Sjl139090 * Lower write service procedure
82225cf1a30Sjl139090 */
82325cf1a30Sjl139090 int
oplmsu_lwsrv(queue_t * lwq)82425cf1a30Sjl139090 oplmsu_lwsrv(queue_t *lwq)
82525cf1a30Sjl139090 {
82625cf1a30Sjl139090 mblk_t *mp;
82725cf1a30Sjl139090 queue_t *dst_queue;
82825cf1a30Sjl139090 lpath_t *lpath;
82925cf1a30Sjl139090
83025cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
83125cf1a30Sjl139090 while (mp = getq(lwq)) {
83225cf1a30Sjl139090 if (mp->b_datap->db_type >= QPCTL) {
83325cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
83425cf1a30Sjl139090 OPLMSU_TRACE(WR(lwq), mp, MSU_TRC_LO);
83525cf1a30Sjl139090 putnext(WR(lwq), mp);
83625cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
83725cf1a30Sjl139090 continue;
83825cf1a30Sjl139090 }
83925cf1a30Sjl139090
84025cf1a30Sjl139090 dst_queue = WR(lwq);
84125cf1a30Sjl139090 if (canputnext(dst_queue)) {
84225cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
84325cf1a30Sjl139090 OPLMSU_TRACE(dst_queue, mp, MSU_TRC_LO);
84425cf1a30Sjl139090 putnext(dst_queue, mp);
84525cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
84625cf1a30Sjl139090 } else {
84707d06da5SSurya Prakki (void) putbq(WR(lwq), mp);
84825cf1a30Sjl139090 break;
84925cf1a30Sjl139090 }
85025cf1a30Sjl139090 }
85125cf1a30Sjl139090
85225cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
85325cf1a30Sjl139090 lpath = (lpath_t *)lwq->q_ptr;
85425cf1a30Sjl139090 if (lpath->uwq_flag != 0) {
85525cf1a30Sjl139090 qenable(WR(lpath->uwq_queue));
85625cf1a30Sjl139090 lpath->uwq_flag = 0;
85725cf1a30Sjl139090 lpath->uwq_queue = NULL;
85825cf1a30Sjl139090 }
85925cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
86025cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
86125cf1a30Sjl139090 return (SUCCESS);
86225cf1a30Sjl139090 }
86325cf1a30Sjl139090
86425cf1a30Sjl139090 /*
86525cf1a30Sjl139090 * Lower read put procedure
86625cf1a30Sjl139090 */
86725cf1a30Sjl139090 int
oplmsu_lrput(queue_t * lrq,mblk_t * mp)86825cf1a30Sjl139090 oplmsu_lrput(queue_t *lrq, mblk_t *mp)
86925cf1a30Sjl139090 {
87025cf1a30Sjl139090
87125cf1a30Sjl139090 if (mp == NULL) {
87225cf1a30Sjl139090 return (SUCCESS);
87325cf1a30Sjl139090 }
87425cf1a30Sjl139090
87525cf1a30Sjl139090 if ((lrq == NULL) || (lrq->q_ptr == NULL)) {
87625cf1a30Sjl139090 freemsg(mp);
87725cf1a30Sjl139090 return (SUCCESS);
87825cf1a30Sjl139090 }
87925cf1a30Sjl139090
88025cf1a30Sjl139090 OPLMSU_TRACE(lrq, mp, MSU_TRC_LI);
88125cf1a30Sjl139090
88225cf1a30Sjl139090 if (mp->b_datap->db_type == M_FLUSH) {
88325cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
88425cf1a30Sjl139090 oplmsu_rcmn_flush_hndl(lrq, mp);
88525cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
88625cf1a30Sjl139090 } else if (mp->b_datap->db_type >= QPCTL) {
88725cf1a30Sjl139090 lpath_t *lpath;
88825cf1a30Sjl139090
88925cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
89025cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
89125cf1a30Sjl139090 lpath = lrq->q_ptr;
89225cf1a30Sjl139090
89325cf1a30Sjl139090 /* Link high priority message to local queue */
89425cf1a30Sjl139090 oplmsu_link_high_primsg(&lpath->first_lpri_hi,
89525cf1a30Sjl139090 &lpath->last_lpri_hi, mp);
89625cf1a30Sjl139090
89725cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
89825cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
89925cf1a30Sjl139090 oplmsu_rcmn_high_qenable(lrq);
90025cf1a30Sjl139090 } else {
90107d06da5SSurya Prakki (void) putq(lrq, mp);
90225cf1a30Sjl139090 }
90325cf1a30Sjl139090 return (SUCCESS);
90425cf1a30Sjl139090 }
90525cf1a30Sjl139090
90625cf1a30Sjl139090 /*
90725cf1a30Sjl139090 * Lower read service procedure
90825cf1a30Sjl139090 */
90925cf1a30Sjl139090 int
oplmsu_lrsrv(queue_t * lrq)91025cf1a30Sjl139090 oplmsu_lrsrv(queue_t *lrq)
91125cf1a30Sjl139090 {
91225cf1a30Sjl139090 mblk_t *mp;
91325cf1a30Sjl139090 boolean_t aborted;
91425cf1a30Sjl139090 int rval;
91525cf1a30Sjl139090
91625cf1a30Sjl139090 if ((lrq == NULL) || (lrq->q_ptr == NULL)) {
91725cf1a30Sjl139090 return (FAILURE);
91825cf1a30Sjl139090 }
91925cf1a30Sjl139090
92025cf1a30Sjl139090 /* Handle normal priority message */
92125cf1a30Sjl139090 while (mp = getq(lrq)) {
92225cf1a30Sjl139090 if (mp->b_datap->db_type >= QPCTL) {
92325cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: lr-srv: "
92425cf1a30Sjl139090 "Invalid db_type => %x", mp->b_datap->db_type);
92525cf1a30Sjl139090 }
92625cf1a30Sjl139090
92725cf1a30Sjl139090 switch (mp->b_datap->db_type) {
92825cf1a30Sjl139090 case M_DATA :
92925cf1a30Sjl139090 aborted = B_FALSE;
93025cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
93125cf1a30Sjl139090 if ((abort_enable == KIOCABORTALTERNATE) &&
93225cf1a30Sjl139090 (RD(oplmsu_uinst->lower_queue) == lrq)) {
93325cf1a30Sjl139090 uchar_t *rx_char = mp->b_rptr;
93425cf1a30Sjl139090 lpath_t *lpath;
93525cf1a30Sjl139090
93625cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
93725cf1a30Sjl139090 lpath = lrq->q_ptr;
93825cf1a30Sjl139090 while (rx_char != mp->b_wptr) {
93925cf1a30Sjl139090 if (*rx_char == *lpath->abt_char) {
94025cf1a30Sjl139090 lpath->abt_char++;
94125cf1a30Sjl139090 if (*lpath->abt_char == '\0') {
94219397407SSherry Moore abort_sequence_enter((char *)
94319397407SSherry Moore NULL);
94425cf1a30Sjl139090 lpath->abt_char
94525cf1a30Sjl139090 = oplmsu_uinst->abts;
94625cf1a30Sjl139090 aborted = B_TRUE;
94725cf1a30Sjl139090 break;
94825cf1a30Sjl139090 }
94925cf1a30Sjl139090 } else {
95025cf1a30Sjl139090 lpath->abt_char = (*rx_char ==
95125cf1a30Sjl139090 *oplmsu_uinst->abts) ?
95225cf1a30Sjl139090 oplmsu_uinst->abts + 1 :
95325cf1a30Sjl139090 oplmsu_uinst->abts;
95425cf1a30Sjl139090 }
95525cf1a30Sjl139090 rx_char++;
95625cf1a30Sjl139090 }
95725cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
95825cf1a30Sjl139090 }
95925cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
96025cf1a30Sjl139090
96125cf1a30Sjl139090 if (aborted) {
96225cf1a30Sjl139090 freemsg(mp);
96325cf1a30Sjl139090 continue;
96425cf1a30Sjl139090 }
96525cf1a30Sjl139090
96625cf1a30Sjl139090 /*
96725cf1a30Sjl139090 * When 1st byte of the received M_DATA is XON or,
96825cf1a30Sjl139090 * 1st byte is XOFF and 2nd byte is XON.
96925cf1a30Sjl139090 */
97025cf1a30Sjl139090
97125cf1a30Sjl139090 if ((*(mp->b_rptr) == MSU_XON) ||
97225cf1a30Sjl139090 (((mp->b_wptr - mp->b_rptr) == 2) &&
97325cf1a30Sjl139090 ((*(mp->b_rptr) == MSU_XOFF) &&
97425cf1a30Sjl139090 (*(mp->b_rptr + 1) == MSU_XON)))) {
97525cf1a30Sjl139090 /* Path switching by XOFF/XON */
97625cf1a30Sjl139090 if (oplmsu_lrdata_xoffxon(lrq, mp) == FAILURE) {
97725cf1a30Sjl139090 return (SUCCESS);
97825cf1a30Sjl139090 }
97925cf1a30Sjl139090 } else {
98025cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
98125cf1a30Sjl139090 rval =
98225cf1a30Sjl139090 oplmsu_rcmn_through_hndl(lrq, mp, MSU_NORM);
98325cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
98425cf1a30Sjl139090
98525cf1a30Sjl139090 if (rval == FAILURE) {
98625cf1a30Sjl139090 return (SUCCESS);
98725cf1a30Sjl139090 }
98825cf1a30Sjl139090 }
98925cf1a30Sjl139090 break;
99025cf1a30Sjl139090
99125cf1a30Sjl139090 case M_BREAK :
99225cf1a30Sjl139090 if ((mp->b_wptr - mp->b_rptr) == 0 && msgdsize(mp)
99325cf1a30Sjl139090 == 0) {
99425cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
99525cf1a30Sjl139090 if ((abort_enable != KIOCABORTALTERNATE) &&
99625cf1a30Sjl139090 (RD(oplmsu_uinst->lower_queue) == lrq)) {
99725cf1a30Sjl139090 abort_sequence_enter((char *)NULL);
99825cf1a30Sjl139090 }
99925cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
100025cf1a30Sjl139090 freemsg(mp);
100125cf1a30Sjl139090 break;
100225cf1a30Sjl139090 }
100325cf1a30Sjl139090 /* FALLTHRU */
100425cf1a30Sjl139090
100525cf1a30Sjl139090 default :
100625cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
100725cf1a30Sjl139090 (void) oplmsu_rcmn_through_hndl(lrq, mp, MSU_NORM);
100825cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
100925cf1a30Sjl139090 break;
101025cf1a30Sjl139090 }
101125cf1a30Sjl139090 }
101225cf1a30Sjl139090 return (SUCCESS);
101325cf1a30Sjl139090 }
101425cf1a30Sjl139090
101525cf1a30Sjl139090 /*
101625cf1a30Sjl139090 * Upper read service procedure
101725cf1a30Sjl139090 */
101825cf1a30Sjl139090 int
oplmsu_ursrv(queue_t * urq)101925cf1a30Sjl139090 oplmsu_ursrv(queue_t *urq)
102025cf1a30Sjl139090 {
102125cf1a30Sjl139090 mblk_t *mp;
102225cf1a30Sjl139090 queue_t *dst_queue;
102325cf1a30Sjl139090 lpath_t *lpath;
102425cf1a30Sjl139090 ctrl_t *ctrl;
102525cf1a30Sjl139090 int res_chk = 0;
102625cf1a30Sjl139090
102725cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
102825cf1a30Sjl139090 while (mp = getq(urq)) {
102925cf1a30Sjl139090 if (mp->b_datap->db_type >= QPCTL) {
103025cf1a30Sjl139090 if ((mp->b_datap->db_type == M_IOCACK) ||
103125cf1a30Sjl139090 (mp->b_datap->db_type == M_IOCNAK)) {
103225cf1a30Sjl139090 res_chk = 1;
103325cf1a30Sjl139090 }
103425cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
103525cf1a30Sjl139090 OPLMSU_TRACE(RD(urq), mp, MSU_TRC_UO);
103625cf1a30Sjl139090 putnext(RD(urq), mp);
103725cf1a30Sjl139090
103825cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
103925cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
104025cf1a30Sjl139090 lpath = oplmsu_uinst->first_lpath;
104125cf1a30Sjl139090 while (lpath) {
104225cf1a30Sjl139090 qenable(RD(lpath->lower_queue));
104325cf1a30Sjl139090 lpath = lpath->l_next;
104425cf1a30Sjl139090 }
104525cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
104625cf1a30Sjl139090
104725cf1a30Sjl139090 if (res_chk == 1) {
104825cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->c_lock);
104925cf1a30Sjl139090 ctrl = (ctrl_t *)urq->q_ptr;
105025cf1a30Sjl139090 if (ctrl != NULL) {
105125cf1a30Sjl139090 if (ctrl->wait_queue != NULL) {
105225cf1a30Sjl139090 qenable(WR(ctrl->wait_queue));
105325cf1a30Sjl139090 ctrl->wait_queue = NULL;
105425cf1a30Sjl139090 }
105525cf1a30Sjl139090 }
105625cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->c_lock);
105725cf1a30Sjl139090 res_chk = 0;
105825cf1a30Sjl139090 }
105925cf1a30Sjl139090 continue;
106025cf1a30Sjl139090 }
106125cf1a30Sjl139090
106225cf1a30Sjl139090 dst_queue = RD(urq);
106325cf1a30Sjl139090 if (canputnext(dst_queue)) {
106425cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
106525cf1a30Sjl139090 OPLMSU_TRACE(dst_queue, mp, MSU_TRC_UO);
106625cf1a30Sjl139090 putnext(dst_queue, mp);
106725cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
106825cf1a30Sjl139090 } else {
106907d06da5SSurya Prakki (void) putbq(urq, mp);
107025cf1a30Sjl139090 break;
107125cf1a30Sjl139090 }
107225cf1a30Sjl139090 }
107325cf1a30Sjl139090
107425cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->c_lock);
107525cf1a30Sjl139090 ctrl = urq->q_ptr;
107625cf1a30Sjl139090 if (ctrl->lrq_flag != 0) {
107725cf1a30Sjl139090 qenable(ctrl->lrq_queue);
107825cf1a30Sjl139090 ctrl->lrq_flag = 0;
107925cf1a30Sjl139090 ctrl->lrq_queue = NULL;
108025cf1a30Sjl139090 }
108125cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->c_lock);
108225cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
108325cf1a30Sjl139090 return (SUCCESS);
108425cf1a30Sjl139090 }
108525cf1a30Sjl139090
108625cf1a30Sjl139090 int
oplmsu_open_msu(dev_info_t * dip,ldi_ident_t * lip,ldi_handle_t * lhp)108725cf1a30Sjl139090 oplmsu_open_msu(dev_info_t *dip, ldi_ident_t *lip, ldi_handle_t *lhp)
108825cf1a30Sjl139090 {
108925cf1a30Sjl139090 dev_t devt;
109025cf1a30Sjl139090 int rval;
109125cf1a30Sjl139090
109225cf1a30Sjl139090 /* Allocate LDI identifier */
109325cf1a30Sjl139090 rval = ldi_ident_from_dip(dip, lip);
109425cf1a30Sjl139090 if (rval != 0) {
109525cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: open-msu: "
109625cf1a30Sjl139090 "ldi_ident_from_dip failed. errno = %d", rval);
109725cf1a30Sjl139090 return (rval);
109825cf1a30Sjl139090 }
109925cf1a30Sjl139090
110025cf1a30Sjl139090 /* Open oplmsu(meta ctrl node) */
110125cf1a30Sjl139090 devt = makedevice(ddi_driver_major(dip), META_NODE_MASK);
110225cf1a30Sjl139090 rval =
110325cf1a30Sjl139090 ldi_open_by_dev(&devt, OTYP_CHR, (FREAD|FWRITE), kcred, lhp, *lip);
110425cf1a30Sjl139090 if (rval != 0) {
110525cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: open-msu: "
110625cf1a30Sjl139090 "ldi_open_by_dev failed. errno = %d", rval);
110725cf1a30Sjl139090 ldi_ident_release(*lip);
110825cf1a30Sjl139090 }
110925cf1a30Sjl139090 return (rval);
111025cf1a30Sjl139090 }
111125cf1a30Sjl139090
111225cf1a30Sjl139090 int
oplmsu_plink_serial(dev_info_t * dip,ldi_handle_t msu_lh,int * id)111325cf1a30Sjl139090 oplmsu_plink_serial(dev_info_t *dip, ldi_handle_t msu_lh, int *id)
111425cf1a30Sjl139090 {
111525cf1a30Sjl139090 ldi_ident_t li = NULL;
111625cf1a30Sjl139090 ldi_handle_t lh = NULL;
111725cf1a30Sjl139090 int param;
111825cf1a30Sjl139090 int rval;
111925cf1a30Sjl139090 char pathname[MSU_PATHNAME_SIZE];
112025cf1a30Sjl139090 char wrkbuf[MSU_PATHNAME_SIZE];
112125cf1a30Sjl139090
112225cf1a30Sjl139090 /* Create physical path-name for serial */
112307d06da5SSurya Prakki (void) ddi_pathname(dip, wrkbuf);
112425cf1a30Sjl139090 *(wrkbuf + strlen(wrkbuf)) = '\0';
112507d06da5SSurya Prakki (void) sprintf(pathname, "/devices%s:%c", wrkbuf,
112607d06da5SSurya Prakki 'a'+ ddi_get_instance(dip));
112725cf1a30Sjl139090
112825cf1a30Sjl139090 /* Allocate LDI identifier */
112925cf1a30Sjl139090 rval = ldi_ident_from_dip(dip, &li);
113025cf1a30Sjl139090 if (rval != 0) {
113125cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: plink-serial: "
113225cf1a30Sjl139090 "%s ldi_ident_from_dip failed. errno = %d", pathname, rval);
113325cf1a30Sjl139090 return (rval);
113425cf1a30Sjl139090 }
113525cf1a30Sjl139090
113625cf1a30Sjl139090 /* Open serial */
113725cf1a30Sjl139090 rval = ldi_open_by_name(pathname, (FREAD|FWRITE|FEXCL), kcred, &lh, li);
113825cf1a30Sjl139090 if (rval != 0) {
113925cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: plink-serial: "
114025cf1a30Sjl139090 "%s open failed. errno = %d", pathname, rval);
114125cf1a30Sjl139090 ldi_ident_release(li);
114225cf1a30Sjl139090 return (rval);
114325cf1a30Sjl139090 }
114425cf1a30Sjl139090
114525cf1a30Sjl139090 /* Try to remove the top module from the stream */
114625cf1a30Sjl139090 param = 0;
114725cf1a30Sjl139090 while ((ldi_ioctl(lh, I_POP, (intptr_t)0, FKIOCTL, kcred, ¶m))
114825cf1a30Sjl139090 == 0) {
114925cf1a30Sjl139090 continue;
115025cf1a30Sjl139090 }
115125cf1a30Sjl139090
115225cf1a30Sjl139090 /* Issue ioctl(I_PLINK) */
115325cf1a30Sjl139090 param = 0;
115425cf1a30Sjl139090 rval = ldi_ioctl(msu_lh, I_PLINK, (intptr_t)lh, FKIOCTL, kcred, ¶m);
115525cf1a30Sjl139090 if (rval != 0) {
115625cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: plink-serial: "
115725cf1a30Sjl139090 "%s ioctl(I_PLINK) failed. errno = %d", pathname, rval);
115825cf1a30Sjl139090 }
115925cf1a30Sjl139090
116025cf1a30Sjl139090 (void) ldi_close(lh, (FREAD|FWRITE|FEXCL), kcred);
116125cf1a30Sjl139090 ldi_ident_release(li);
116225cf1a30Sjl139090
116325cf1a30Sjl139090 *id = param; /* Save link-id */
116425cf1a30Sjl139090 return (rval);
116525cf1a30Sjl139090 }
116625cf1a30Sjl139090
116725cf1a30Sjl139090 int
oplmsu_set_lpathnum(int lnk_id,int instance)116825cf1a30Sjl139090 oplmsu_set_lpathnum(int lnk_id, int instance)
116925cf1a30Sjl139090 {
117025cf1a30Sjl139090 lpath_t *lpath;
117125cf1a30Sjl139090 int rval = SUCCESS;
117225cf1a30Sjl139090
117325cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
117425cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
117525cf1a30Sjl139090 lpath = oplmsu_uinst->first_lpath;
117625cf1a30Sjl139090 while (lpath) {
117725cf1a30Sjl139090 if ((lpath->path_no == UNDEFINED) &&
117825cf1a30Sjl139090 (lpath->link_id == lnk_id)) {
117925cf1a30Sjl139090 lpath->path_no = instance; /* Set instance number */
118025cf1a30Sjl139090 lpath->src_upath = NULL;
118125cf1a30Sjl139090 lpath->status = MSU_SETID_NU;
118225cf1a30Sjl139090 break;
118325cf1a30Sjl139090 }
118425cf1a30Sjl139090 lpath = lpath->l_next;
118525cf1a30Sjl139090 }
118625cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
118725cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
118825cf1a30Sjl139090
118925cf1a30Sjl139090 if (lpath == NULL) {
119025cf1a30Sjl139090 rval = EINVAL;
119125cf1a30Sjl139090 }
119225cf1a30Sjl139090 return (rval);
119325cf1a30Sjl139090 }
119425cf1a30Sjl139090
119525cf1a30Sjl139090 int
oplmsu_dr_attach(dev_info_t * dip)119625cf1a30Sjl139090 oplmsu_dr_attach(dev_info_t *dip)
119725cf1a30Sjl139090 {
119825cf1a30Sjl139090 ldi_ident_t msu_li = NULL;
119925cf1a30Sjl139090 ldi_handle_t msu_lh = NULL;
120025cf1a30Sjl139090 upath_t *upath;
120125cf1a30Sjl139090 int len;
120225cf1a30Sjl139090 int instance;
120325cf1a30Sjl139090 int lnk_id = 0;
120425cf1a30Sjl139090 int param = 0;
120525cf1a30Sjl139090 int rval;
120625cf1a30Sjl139090
120725cf1a30Sjl139090 /* Get instance for serial */
120825cf1a30Sjl139090 instance = ddi_get_instance(dip);
120925cf1a30Sjl139090
121025cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
121125cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->u_lock);
121225cf1a30Sjl139090
121325cf1a30Sjl139090 /* Get current number of paths */
121425cf1a30Sjl139090 oplmsu_uinst->path_num = oplmsu_get_pathnum();
121525cf1a30Sjl139090
121625cf1a30Sjl139090 /* Check specified upath_t */
121725cf1a30Sjl139090 upath = oplmsu_uinst->first_upath;
121825cf1a30Sjl139090 while (upath) {
121925cf1a30Sjl139090 if (instance == upath->path_no) {
122025cf1a30Sjl139090 break;
122125cf1a30Sjl139090 }
122225cf1a30Sjl139090 upath = upath->u_next;
122325cf1a30Sjl139090 }
122425cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
122525cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
122625cf1a30Sjl139090
122725cf1a30Sjl139090 if (upath != NULL) {
122825cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: attach(dr): "
122925cf1a30Sjl139090 "Instance %d already exist", instance);
123025cf1a30Sjl139090 return (EINVAL);
123125cf1a30Sjl139090 }
123225cf1a30Sjl139090
123325cf1a30Sjl139090 /* Open oplmsu */
123425cf1a30Sjl139090 rval = oplmsu_open_msu(oplmsu_uinst->msu_dip, &msu_li, &msu_lh);
123525cf1a30Sjl139090 if (rval != 0) {
123625cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: attach(dr): "
123725cf1a30Sjl139090 "msu open failed. errno = %d", rval);
123825cf1a30Sjl139090 return (rval);
123925cf1a30Sjl139090 }
124025cf1a30Sjl139090
124125cf1a30Sjl139090 /* Connect two streams */
124225cf1a30Sjl139090 rval = oplmsu_plink_serial(dip, msu_lh, &lnk_id);
124325cf1a30Sjl139090 if (rval != 0) {
124425cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: attach(dr): "
124525cf1a30Sjl139090 "i_plink failed. errno = %d", rval);
124625cf1a30Sjl139090 (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred);
124725cf1a30Sjl139090 ldi_ident_release(msu_li);
124825cf1a30Sjl139090 return (rval);
124925cf1a30Sjl139090 }
125025cf1a30Sjl139090
125125cf1a30Sjl139090 rval = oplmsu_set_lpathnum(lnk_id, instance);
125225cf1a30Sjl139090 if (rval != 0) {
125325cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: attach(dr): "
125425cf1a30Sjl139090 "Link id %d is not found", lnk_id);
125525cf1a30Sjl139090 /* Issue ioctl(I_PUNLINK) */
125625cf1a30Sjl139090 (void) ldi_ioctl(msu_lh, I_PUNLINK, (intptr_t)lnk_id, FKIOCTL,
125725cf1a30Sjl139090 kcred, ¶m);
125825cf1a30Sjl139090 (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred);
125925cf1a30Sjl139090 ldi_ident_release(msu_li);
126025cf1a30Sjl139090 return (rval);
126125cf1a30Sjl139090 }
126225cf1a30Sjl139090
126325cf1a30Sjl139090 /* Add the path */
126425cf1a30Sjl139090 rval = oplmsu_config_add(dip);
126525cf1a30Sjl139090 if (rval != 0) {
126625cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: attach(dr): "
126725cf1a30Sjl139090 "Failed to add the path. errno = %d", rval);
126825cf1a30Sjl139090 /* Issue ioctl(I_PUNLINK) */
126925cf1a30Sjl139090 (void) ldi_ioctl(msu_lh, I_PUNLINK, (intptr_t)lnk_id, FKIOCTL,
127025cf1a30Sjl139090 kcred, ¶m);
127125cf1a30Sjl139090
127225cf1a30Sjl139090 (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred);
127325cf1a30Sjl139090 ldi_ident_release(msu_li);
127425cf1a30Sjl139090 return (rval);
127525cf1a30Sjl139090 }
127625cf1a30Sjl139090
127725cf1a30Sjl139090 /* Start to use the path */
127825cf1a30Sjl139090 rval = oplmsu_config_start(instance);
127925cf1a30Sjl139090 if (rval != 0) {
128025cf1a30Sjl139090 struct msu_path *mpath;
128125cf1a30Sjl139090 struct msu_dev *mdev;
128225cf1a30Sjl139090
128325cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: attach(dr): "
128425cf1a30Sjl139090 "Failed to start the path. errno = %d", rval);
128525cf1a30Sjl139090
128625cf1a30Sjl139090 len = sizeof (struct msu_path) + sizeof (struct msu_dev);
128725cf1a30Sjl139090 mpath = (struct msu_path *)kmem_zalloc((size_t)len, KM_SLEEP);
128825cf1a30Sjl139090 mpath->num = 1;
128925cf1a30Sjl139090 mdev = (struct msu_dev *)(mpath + 1);
129025cf1a30Sjl139090 mdev->dip = dip;
129125cf1a30Sjl139090
129225cf1a30Sjl139090 /* Delete the path */
129325cf1a30Sjl139090 if ((oplmsu_config_del(mpath)) == 0) {
129425cf1a30Sjl139090 /* Issue ioctl(I_PUNLINK) */
129525cf1a30Sjl139090 (void) ldi_ioctl(msu_lh, I_PUNLINK, (intptr_t)lnk_id,
129625cf1a30Sjl139090 FKIOCTL, kcred, ¶m);
129725cf1a30Sjl139090 }
129825cf1a30Sjl139090 kmem_free(mpath, (size_t)len);
129925cf1a30Sjl139090 }
130025cf1a30Sjl139090
130125cf1a30Sjl139090 /* Close oplmsu */
130225cf1a30Sjl139090 (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred);
130325cf1a30Sjl139090 ldi_ident_release(msu_li);
130425cf1a30Sjl139090 return (rval);
130525cf1a30Sjl139090 }
130625cf1a30Sjl139090
130725cf1a30Sjl139090 int
oplmsu_dr_detach(dev_info_t * dip)130825cf1a30Sjl139090 oplmsu_dr_detach(dev_info_t *dip)
130925cf1a30Sjl139090 {
131025cf1a30Sjl139090 ldi_ident_t msu_li = NULL;
131125cf1a30Sjl139090 ldi_handle_t msu_lh = NULL;
131225cf1a30Sjl139090 struct msu_path *mpath;
131325cf1a30Sjl139090 struct msu_dev *mdev;
131425cf1a30Sjl139090 upath_t *upath;
131525cf1a30Sjl139090 lpath_t *lpath;
131625cf1a30Sjl139090 int len;
131725cf1a30Sjl139090 int instance;
131825cf1a30Sjl139090 int count = 0;
131925cf1a30Sjl139090 int param = 0;
132025cf1a30Sjl139090 int status;
132125cf1a30Sjl139090 int rval;
132225cf1a30Sjl139090
132325cf1a30Sjl139090 /* Get instance for serial */
132425cf1a30Sjl139090 instance = ddi_get_instance(dip);
132525cf1a30Sjl139090
132625cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
132725cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->u_lock);
132825cf1a30Sjl139090
132925cf1a30Sjl139090 /* Get current number of paths */
133025cf1a30Sjl139090 oplmsu_uinst->path_num = oplmsu_get_pathnum();
133125cf1a30Sjl139090
133225cf1a30Sjl139090 rval = FAILURE;
133325cf1a30Sjl139090
133425cf1a30Sjl139090 /* Check specified upath_t */
133525cf1a30Sjl139090 upath = oplmsu_uinst->first_upath;
133625cf1a30Sjl139090 while (upath) {
133725cf1a30Sjl139090 if (instance == upath->path_no) {
133825cf1a30Sjl139090 /* Save status of specified path */
133925cf1a30Sjl139090 status = upath->status;
134025cf1a30Sjl139090 rval = SUCCESS;
134125cf1a30Sjl139090 }
134225cf1a30Sjl139090 upath = upath->u_next;
134325cf1a30Sjl139090 count += 1;
134425cf1a30Sjl139090 }
134525cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
134625cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
134725cf1a30Sjl139090
134825cf1a30Sjl139090 if (rval == FAILURE) {
134925cf1a30Sjl139090 if (count <= 1) {
135025cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: detach(dr): "
135125cf1a30Sjl139090 "Instance %d is last path", instance);
135225cf1a30Sjl139090 } else {
135325cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: detach(dr): "
135425cf1a30Sjl139090 "Instance %d doesn't find", instance);
135525cf1a30Sjl139090 }
135625cf1a30Sjl139090 return (EINVAL);
135725cf1a30Sjl139090 }
135825cf1a30Sjl139090
135925cf1a30Sjl139090 /* Check status of specified path */
136025cf1a30Sjl139090 if ((status == MSU_PSTAT_ACTIVE) || (status == MSU_PSTAT_STANDBY)) {
136125cf1a30Sjl139090 /* Stop to use the path */
136225cf1a30Sjl139090 rval = oplmsu_config_stop(instance);
136325cf1a30Sjl139090 if (rval != 0) {
136425cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: detach(dr): "
136525cf1a30Sjl139090 "Failed to stop the path. errno = %d", rval);
136625cf1a30Sjl139090 return (rval);
136725cf1a30Sjl139090 }
136825cf1a30Sjl139090 }
136925cf1a30Sjl139090
137025cf1a30Sjl139090 /* Prepare to unlink the path */
137125cf1a30Sjl139090 rval = oplmsu_config_disc(instance);
137225cf1a30Sjl139090 if (rval != 0) {
137325cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: detach(dr): "
137425cf1a30Sjl139090 "Failed to disconnect the path. errno = %d", rval);
137525cf1a30Sjl139090 return (rval);
137625cf1a30Sjl139090 }
137725cf1a30Sjl139090
137825cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
137925cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
138025cf1a30Sjl139090 lpath = oplmsu_uinst->first_lpath;
138125cf1a30Sjl139090 while (lpath) {
138225cf1a30Sjl139090 if (lpath->path_no == instance) { /* Get link ID */
138325cf1a30Sjl139090 break;
138425cf1a30Sjl139090 }
138525cf1a30Sjl139090 lpath = lpath->l_next;
138625cf1a30Sjl139090 }
138725cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
138825cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
138925cf1a30Sjl139090
139025cf1a30Sjl139090 if (lpath == NULL) {
139125cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: detach(dr): Can not find link ID");
139225cf1a30Sjl139090 return (EINVAL);
139325cf1a30Sjl139090 }
139425cf1a30Sjl139090
139525cf1a30Sjl139090 /* Open oplmsu */
139625cf1a30Sjl139090 rval = oplmsu_open_msu(oplmsu_uinst->msu_dip, &msu_li, &msu_lh);
139725cf1a30Sjl139090 if (rval != 0) {
139825cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: detach(dr): "
139925cf1a30Sjl139090 "msu open failed. errno = %d", rval);
140025cf1a30Sjl139090 return (rval);
140125cf1a30Sjl139090 }
140225cf1a30Sjl139090
140325cf1a30Sjl139090 /* Issue ioctl(I_PUNLINK) */
140425cf1a30Sjl139090 rval = ldi_ioctl(msu_lh, I_PUNLINK, (intptr_t)lpath->link_id, FKIOCTL,
140525cf1a30Sjl139090 kcred, ¶m);
140625cf1a30Sjl139090 if (rval != 0) {
140725cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: detach(dr): "
140825cf1a30Sjl139090 "ioctl(I_PUNLINK) failed. errno = %d", rval);
140925cf1a30Sjl139090 (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred);
141025cf1a30Sjl139090 ldi_ident_release(msu_li);
141125cf1a30Sjl139090 return (rval);
141225cf1a30Sjl139090 }
141325cf1a30Sjl139090
141425cf1a30Sjl139090 /* Close oplmsu(meta node) */
141525cf1a30Sjl139090 (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred);
141625cf1a30Sjl139090 ldi_ident_release(msu_li);
141725cf1a30Sjl139090
141825cf1a30Sjl139090 len = sizeof (struct msu_path) + sizeof (struct msu_dev);
141925cf1a30Sjl139090 mpath = (struct msu_path *)kmem_zalloc((size_t)len, KM_SLEEP);
142025cf1a30Sjl139090 mpath->num = 1;
142125cf1a30Sjl139090 mdev = (struct msu_dev *)(mpath + 1);
142225cf1a30Sjl139090 mdev->dip = dip;
142325cf1a30Sjl139090
142425cf1a30Sjl139090 /* Delete the path */
142525cf1a30Sjl139090 rval = oplmsu_config_del(mpath);
142625cf1a30Sjl139090 if (rval != 0) {
142725cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: detach(dr): "
142825cf1a30Sjl139090 "Failed to delete the path. errno = %d", rval);
142925cf1a30Sjl139090 }
143025cf1a30Sjl139090
143125cf1a30Sjl139090 kmem_free(mpath, (size_t)len);
143225cf1a30Sjl139090 return (rval);
143325cf1a30Sjl139090 }
143425cf1a30Sjl139090
143525cf1a30Sjl139090 /*
143625cf1a30Sjl139090 * The ebus and the serial device path under a given CMU_CH chip
143725cf1a30Sjl139090 * is expected to be always at the same address. So, it is safe
143825cf1a30Sjl139090 * to hard-code the pathnames as below.
143925cf1a30Sjl139090 */
144025cf1a30Sjl139090 #define EBUS_PATH "ebus@1"
144125cf1a30Sjl139090 #define SERIAL_PATH "serial@14,400000"
144225cf1a30Sjl139090 #define EBUS_SERIAL_PATH ("/" EBUS_PATH "/" SERIAL_PATH)
144325cf1a30Sjl139090
144425cf1a30Sjl139090 /*
144525cf1a30Sjl139090 * Given the CMU_CH dip, find the serial device dip.
144625cf1a30Sjl139090 */
144725cf1a30Sjl139090 dev_info_t *
oplmsu_find_ser_dip(dev_info_t * cmuch_dip)144825cf1a30Sjl139090 oplmsu_find_ser_dip(dev_info_t *cmuch_dip)
144925cf1a30Sjl139090 {
145025cf1a30Sjl139090 dev_info_t *ebus_dip;
145125cf1a30Sjl139090 dev_info_t *ser_dip = NULL;
145225cf1a30Sjl139090
1453*3fe80ca4SDan Cross ndi_devi_enter(cmuch_dip);
145425cf1a30Sjl139090 ebus_dip = ndi_devi_findchild(cmuch_dip, EBUS_PATH);
145525cf1a30Sjl139090
145625cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: find-serial-dip: "
145707d06da5SSurya Prakki "ebus_dip = %p", (void *)ebus_dip));
145825cf1a30Sjl139090
145925cf1a30Sjl139090 if (ebus_dip != NULL) {
1460*3fe80ca4SDan Cross ndi_devi_enter(ebus_dip);
146125cf1a30Sjl139090 ser_dip = ndi_devi_findchild(ebus_dip, SERIAL_PATH);
146225cf1a30Sjl139090
146325cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: find-serial-dip: "
146407d06da5SSurya Prakki "ser_dip = %p", (void *)ser_dip));
1465*3fe80ca4SDan Cross ndi_devi_exit(ebus_dip);
146625cf1a30Sjl139090 }
1467*3fe80ca4SDan Cross ndi_devi_exit(cmuch_dip);
146825cf1a30Sjl139090 return (ser_dip);
146925cf1a30Sjl139090 }
147025cf1a30Sjl139090
147125cf1a30Sjl139090 /*
147225cf1a30Sjl139090 * Find all console related serial devices.
147325cf1a30Sjl139090 */
147425cf1a30Sjl139090 int
oplmsu_find_serial(ser_devl_t ** ser_dl)147525cf1a30Sjl139090 oplmsu_find_serial(ser_devl_t **ser_dl)
147625cf1a30Sjl139090 {
147725cf1a30Sjl139090 dev_info_t *root_dip;
147825cf1a30Sjl139090 dev_info_t *cmuch_dip;
147925cf1a30Sjl139090 dev_info_t *dip;
148025cf1a30Sjl139090 ser_devl_t *wrk_ser_dl;
148125cf1a30Sjl139090 int count = 0;
148225cf1a30Sjl139090 char pathname[MSU_PATHNAME_SIZE];
148325cf1a30Sjl139090 dev_t devt;
148425cf1a30Sjl139090 char *namep;
148525cf1a30Sjl139090
148625cf1a30Sjl139090 root_dip = ddi_root_node();
1487*3fe80ca4SDan Cross ndi_devi_enter(root_dip);
148825cf1a30Sjl139090 cmuch_dip = ddi_get_child(root_dip);
148925cf1a30Sjl139090
149025cf1a30Sjl139090 while (cmuch_dip != NULL) {
149125cf1a30Sjl139090 namep = ddi_binding_name(cmuch_dip); /* Get binding name */
149225cf1a30Sjl139090 if (namep == NULL) {
149325cf1a30Sjl139090 cmuch_dip = ddi_get_next_sibling(cmuch_dip);
149425cf1a30Sjl139090 continue;
149525cf1a30Sjl139090 }
149625cf1a30Sjl139090
149725cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: find-serial: name => %s", namep));
149825cf1a30Sjl139090
149925cf1a30Sjl139090 if ((strcmp(namep, MSU_CMUCH_FF) != 0) &&
150025cf1a30Sjl139090 (strcmp(namep, MSU_CMUCH_DC) != 0)) {
150125cf1a30Sjl139090 #ifdef DEBUG
150225cf1a30Sjl139090 if (strcmp(namep, MSU_CMUCH_DBG) != 0) {
150325cf1a30Sjl139090 cmuch_dip = ddi_get_next_sibling(cmuch_dip);
150425cf1a30Sjl139090 continue;
150525cf1a30Sjl139090 }
150625cf1a30Sjl139090 #else
150725cf1a30Sjl139090 cmuch_dip = ddi_get_next_sibling(cmuch_dip);
150825cf1a30Sjl139090 continue;
150925cf1a30Sjl139090 #endif
151025cf1a30Sjl139090 }
151125cf1a30Sjl139090
15125b20806aSraghuram /*
15135b20806aSraghuram * Online the cmuch_dip so that its in the right state
15145b20806aSraghuram * to get the complete path, that is both name and address.
15155b20806aSraghuram */
15165b20806aSraghuram (void) ndi_devi_online(cmuch_dip, 0);
151725cf1a30Sjl139090 (void) ddi_pathname(cmuch_dip, pathname);
151825cf1a30Sjl139090 DBG_PRINT((CE_NOTE,
151925cf1a30Sjl139090 "oplmsu: find-serial: cmu-ch path => %s", pathname));
152025cf1a30Sjl139090 (void) strcat(pathname, EBUS_SERIAL_PATH);
152125cf1a30Sjl139090
152225cf1a30Sjl139090 /*
152325cf1a30Sjl139090 * Call ddi_pathname_to_dev_t to forceload and attach
152425cf1a30Sjl139090 * the required drivers.
152525cf1a30Sjl139090 */
152625cf1a30Sjl139090 devt = ddi_pathname_to_dev_t(pathname);
152725cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: find-serial: serial device "
152825cf1a30Sjl139090 "dev_t = %lx", devt));
152925cf1a30Sjl139090 if ((devt != NODEV) &&
153025cf1a30Sjl139090 ((dip = oplmsu_find_ser_dip(cmuch_dip)) != NULL)) {
153125cf1a30Sjl139090 wrk_ser_dl = (ser_devl_t *)
153225cf1a30Sjl139090 kmem_zalloc(sizeof (ser_devl_t), KM_SLEEP);
153325cf1a30Sjl139090 wrk_ser_dl->dip = dip;
153425cf1a30Sjl139090 count += 1;
153525cf1a30Sjl139090
153625cf1a30Sjl139090 if (*ser_dl != NULL) {
153725cf1a30Sjl139090 wrk_ser_dl->next = *ser_dl;
153825cf1a30Sjl139090 }
153925cf1a30Sjl139090 *ser_dl = wrk_ser_dl;
154025cf1a30Sjl139090 }
154125cf1a30Sjl139090 cmuch_dip = ddi_get_next_sibling(cmuch_dip);
154225cf1a30Sjl139090 }
1543*3fe80ca4SDan Cross ndi_devi_exit(root_dip);
154425cf1a30Sjl139090 return (count);
154525cf1a30Sjl139090 }
154625cf1a30Sjl139090
154725cf1a30Sjl139090 /* Configure STREAM */
154825cf1a30Sjl139090 void
oplmsu_conf_stream(uinst_t * msu_uinst)154925cf1a30Sjl139090 oplmsu_conf_stream(uinst_t *msu_uinst)
155025cf1a30Sjl139090 {
155125cf1a30Sjl139090 ldi_ident_t msu_li = NULL;
155225cf1a30Sjl139090 ldi_handle_t msu_lh = NULL;
155325cf1a30Sjl139090 struct msu_path *mpath;
155425cf1a30Sjl139090 struct msu_dev *mdev;
155525cf1a30Sjl139090 ser_devl_t *ser_dl = NULL, *next_ser_dl;
155625cf1a30Sjl139090 int *plink_id;
155725cf1a30Sjl139090 int size;
155825cf1a30Sjl139090 int i;
155925cf1a30Sjl139090 int param;
156025cf1a30Sjl139090 int connected = 0;
156125cf1a30Sjl139090 int devcnt = 0;
156225cf1a30Sjl139090 int rval;
156325cf1a30Sjl139090
156425cf1a30Sjl139090 DBG_PRINT((CE_NOTE,
156525cf1a30Sjl139090 "oplmsu: conf-stream: stream configuration start!"));
156625cf1a30Sjl139090
156725cf1a30Sjl139090 /* Find serial devices */
156825cf1a30Sjl139090 devcnt = oplmsu_find_serial(&ser_dl);
156925cf1a30Sjl139090 if ((devcnt == 0) || (ser_dl == NULL)) {
157025cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stream: "
157125cf1a30Sjl139090 "Discovered serial device = %d", devcnt);
157225cf1a30Sjl139090 return;
157325cf1a30Sjl139090 }
157425cf1a30Sjl139090
157525cf1a30Sjl139090 /* Open oplmsu */
157625cf1a30Sjl139090 rval = oplmsu_open_msu(msu_uinst->msu_dip, &msu_li, &msu_lh);
157725cf1a30Sjl139090 if (rval != 0) {
157825cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stream: "
157925cf1a30Sjl139090 "msu open failed. errno = %d", rval);
158025cf1a30Sjl139090 return;
158125cf1a30Sjl139090 }
158225cf1a30Sjl139090
158325cf1a30Sjl139090 size = (sizeof (struct msu_path) + (sizeof (struct msu_dev) * devcnt));
158425cf1a30Sjl139090 mpath = (struct msu_path *)kmem_zalloc((size_t)size, KM_SLEEP);
158525cf1a30Sjl139090 plink_id = (int *)kmem_zalloc((sizeof (int) * devcnt), KM_SLEEP);
158625cf1a30Sjl139090
158725cf1a30Sjl139090 mdev = (struct msu_dev *)(mpath + 1);
158825cf1a30Sjl139090 for (i = 0; i < devcnt; i++) {
158925cf1a30Sjl139090 /* Connect two streams */
159025cf1a30Sjl139090 rval = oplmsu_plink_serial(ser_dl->dip, msu_lh, &plink_id[i]);
159125cf1a30Sjl139090 if (rval != 0) {
159225cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stream: "
159325cf1a30Sjl139090 "i_plink failed. errno = %d", rval);
159425cf1a30Sjl139090 next_ser_dl = ser_dl->next;
159525cf1a30Sjl139090 kmem_free(ser_dl, sizeof (ser_devl_t));
159625cf1a30Sjl139090 ser_dl = next_ser_dl;
159725cf1a30Sjl139090 continue;
159825cf1a30Sjl139090 }
159925cf1a30Sjl139090
160025cf1a30Sjl139090 rval = oplmsu_set_lpathnum(plink_id[i],
160125cf1a30Sjl139090 ddi_get_instance(ser_dl->dip));
160225cf1a30Sjl139090 if (rval != 0) {
160325cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stream: "
160425cf1a30Sjl139090 "Link id %d is not found", plink_id[i]);
160525cf1a30Sjl139090 /* Issue ioctl(I_PUNLINK) */
160625cf1a30Sjl139090 (void) ldi_ioctl(msu_lh, I_PUNLINK,
160725cf1a30Sjl139090 (intptr_t)plink_id[i], FKIOCTL, kcred, ¶m);
160825cf1a30Sjl139090 next_ser_dl = ser_dl->next;
160925cf1a30Sjl139090 kmem_free(ser_dl, sizeof (ser_devl_t));
161025cf1a30Sjl139090 ser_dl = next_ser_dl;
161125cf1a30Sjl139090 continue;
161225cf1a30Sjl139090 }
161325cf1a30Sjl139090
161425cf1a30Sjl139090 mdev->dip = ser_dl->dip;
161525cf1a30Sjl139090 next_ser_dl = ser_dl->next;
161625cf1a30Sjl139090 kmem_free(ser_dl, sizeof (ser_devl_t));
161725cf1a30Sjl139090 ser_dl = next_ser_dl;
161825cf1a30Sjl139090
161925cf1a30Sjl139090 mdev++;
162025cf1a30Sjl139090 connected++;
162125cf1a30Sjl139090 }
162225cf1a30Sjl139090
162325cf1a30Sjl139090 if (connected == 0) {
162425cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stream: "
162525cf1a30Sjl139090 "Connected paths = %d", connected);
162625cf1a30Sjl139090 (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred);
162725cf1a30Sjl139090 ldi_ident_release(msu_li);
162825cf1a30Sjl139090 kmem_free(plink_id, (sizeof (int) * devcnt));
162925cf1a30Sjl139090 kmem_free(mpath, size);
163025cf1a30Sjl139090 return;
163125cf1a30Sjl139090 }
163225cf1a30Sjl139090
163325cf1a30Sjl139090 /* Setup all structure */
163425cf1a30Sjl139090 mpath->num = connected;
163525cf1a30Sjl139090 rval = oplmsu_config_new(mpath);
163625cf1a30Sjl139090 if (rval != 0) {
163725cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stream: "
163825cf1a30Sjl139090 "Failed to create all paths. errno = %d", rval);
163925cf1a30Sjl139090 oplmsu_unlinks(msu_lh, plink_id, devcnt);
164025cf1a30Sjl139090 (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred);
164125cf1a30Sjl139090 ldi_ident_release(msu_li);
164225cf1a30Sjl139090 kmem_free(plink_id, (sizeof (int) * devcnt));
164325cf1a30Sjl139090 kmem_free(mpath, size);
164425cf1a30Sjl139090 return;
164525cf1a30Sjl139090 }
164625cf1a30Sjl139090
164725cf1a30Sjl139090 /* Start to use all paths */
164825cf1a30Sjl139090 rval = oplmsu_config_start(MSU_PATH_ALL);
164925cf1a30Sjl139090 if (rval != 0) {
165025cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stream: "
165125cf1a30Sjl139090 "Failed to start all paths. errno = %d", rval);
165225cf1a30Sjl139090
165325cf1a30Sjl139090 /* Delete the path */
165425cf1a30Sjl139090 rval = oplmsu_config_del(mpath);
165525cf1a30Sjl139090 if (rval == 0) {
165625cf1a30Sjl139090 oplmsu_unlinks(msu_lh, plink_id, devcnt);
165725cf1a30Sjl139090 }
165825cf1a30Sjl139090 }
165925cf1a30Sjl139090
166025cf1a30Sjl139090 (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred);
166125cf1a30Sjl139090 ldi_ident_release(msu_li);
166225cf1a30Sjl139090 kmem_free(plink_id, (sizeof (int) * devcnt));
166325cf1a30Sjl139090 kmem_free(mpath, size);
166425cf1a30Sjl139090
166525cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: conf-stream: stream configuration end!"));
166625cf1a30Sjl139090 }
166725cf1a30Sjl139090
166825cf1a30Sjl139090 void
oplmsu_unlinks(ldi_handle_t msu_lh,int * plink_id,int devcnt)166925cf1a30Sjl139090 oplmsu_unlinks(ldi_handle_t msu_lh, int *plink_id, int devcnt)
167025cf1a30Sjl139090 {
167125cf1a30Sjl139090 int i;
167225cf1a30Sjl139090 int param = 0;
167325cf1a30Sjl139090
167425cf1a30Sjl139090 for (i = 0; i < devcnt; i++) {
167525cf1a30Sjl139090 if (plink_id[i] == 0) {
167625cf1a30Sjl139090 continue;
167725cf1a30Sjl139090 }
167825cf1a30Sjl139090
167925cf1a30Sjl139090 /* Issue ioctl(I_PUNLINK) */
168025cf1a30Sjl139090 (void) ldi_ioctl(msu_lh, I_PUNLINK, (intptr_t)plink_id[i],
168125cf1a30Sjl139090 FKIOCTL, kcred, ¶m);
168225cf1a30Sjl139090 }
168325cf1a30Sjl139090 }
168425cf1a30Sjl139090
168525cf1a30Sjl139090 void
oplmsu_setup(uinst_t * msu_uinst)168625cf1a30Sjl139090 oplmsu_setup(uinst_t *msu_uinst)
168725cf1a30Sjl139090 {
168825cf1a30Sjl139090
168925cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: setup: Background thread start!"));
169025cf1a30Sjl139090
169125cf1a30Sjl139090 mutex_enter(&oplmsu_bthrd_excl);
169225cf1a30Sjl139090 if (oplmsu_conf_st == MSU_CONFIGURING) {
169325cf1a30Sjl139090 mutex_exit(&oplmsu_bthrd_excl);
169425cf1a30Sjl139090 oplmsu_conf_stream(msu_uinst); /* Configure stream */
169525cf1a30Sjl139090 mutex_enter(&oplmsu_bthrd_excl);
169625cf1a30Sjl139090 oplmsu_conf_st = MSU_CONFIGURED;
169725cf1a30Sjl139090 cv_broadcast(&oplmsu_conf_cv); /* Wake up from cv_wait_sig() */
169825cf1a30Sjl139090 }
169925cf1a30Sjl139090
170025cf1a30Sjl139090 if (oplmsu_bthrd_id != NULL) {
170125cf1a30Sjl139090 oplmsu_bthrd_id = NULL;
170225cf1a30Sjl139090 }
170325cf1a30Sjl139090 mutex_exit(&oplmsu_bthrd_excl);
170425cf1a30Sjl139090
170525cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: setup: Background thread end!"));
170625cf1a30Sjl139090
170725cf1a30Sjl139090 thread_exit();
170825cf1a30Sjl139090 }
170925cf1a30Sjl139090
171025cf1a30Sjl139090 int
oplmsu_create_upath(dev_info_t * dip)171125cf1a30Sjl139090 oplmsu_create_upath(dev_info_t *dip)
171225cf1a30Sjl139090 {
171325cf1a30Sjl139090 upath_t *upath;
171425cf1a30Sjl139090 lpath_t *lpath;
171525cf1a30Sjl139090 dev_info_t *cmuch_dip;
171625cf1a30Sjl139090 int instance;
171725cf1a30Sjl139090 int lsb;
171825cf1a30Sjl139090
171925cf1a30Sjl139090 cmuch_dip = ddi_get_parent(ddi_get_parent(dip));
172025cf1a30Sjl139090 lsb = ddi_prop_get_int(DDI_DEV_T_ANY, cmuch_dip, 0, MSU_BOARD_PROP,
172125cf1a30Sjl139090 FAILURE);
172225cf1a30Sjl139090 if (lsb == FAILURE) {
172325cf1a30Sjl139090 return (lsb);
172425cf1a30Sjl139090 }
172525cf1a30Sjl139090
172625cf1a30Sjl139090 instance = ddi_get_instance(dip);
172725cf1a30Sjl139090
172825cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
172925cf1a30Sjl139090 lpath = oplmsu_uinst->first_lpath;
173025cf1a30Sjl139090 while (lpath) {
173125cf1a30Sjl139090 if (lpath->path_no == instance) {
173225cf1a30Sjl139090 break;
173325cf1a30Sjl139090 }
173425cf1a30Sjl139090 lpath = lpath->l_next;
173525cf1a30Sjl139090 }
173625cf1a30Sjl139090
173725cf1a30Sjl139090 if (lpath == NULL) {
173825cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
173925cf1a30Sjl139090 return (ENODEV);
174025cf1a30Sjl139090 }
174125cf1a30Sjl139090
174225cf1a30Sjl139090 upath = (upath_t *)kmem_zalloc(sizeof (upath_t), KM_SLEEP);
174325cf1a30Sjl139090
174425cf1a30Sjl139090 /*
174525cf1a30Sjl139090 * Initialize members of upath_t
174625cf1a30Sjl139090 */
174725cf1a30Sjl139090
174825cf1a30Sjl139090 upath->path_no = instance;
174925cf1a30Sjl139090 upath->lpath = lpath;
175025cf1a30Sjl139090 upath->ser_devcb.dip = dip;
175125cf1a30Sjl139090 upath->ser_devcb.lsb = lsb;
175225cf1a30Sjl139090 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_STOP, MSU_PSTAT_EMPTY,
175325cf1a30Sjl139090 MSU_STOP);
175425cf1a30Sjl139090
175525cf1a30Sjl139090 lpath->src_upath = NULL;
175625cf1a30Sjl139090 lpath->status = MSU_EXT_NOTUSED;
175725cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
175825cf1a30Sjl139090
175925cf1a30Sjl139090 oplmsu_link_upath(upath);
176025cf1a30Sjl139090 return (SUCCESS);
176125cf1a30Sjl139090 }
176225cf1a30Sjl139090
176325cf1a30Sjl139090 /* Setup new upper instance structure */
176425cf1a30Sjl139090 int
oplmsu_config_new(struct msu_path * mpath)176525cf1a30Sjl139090 oplmsu_config_new(struct msu_path *mpath)
176625cf1a30Sjl139090 {
176725cf1a30Sjl139090 struct msu_dev *mdev;
176825cf1a30Sjl139090 int i;
176925cf1a30Sjl139090 int rval = SUCCESS;
177025cf1a30Sjl139090
177125cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: conf-new: config_new() called"));
177225cf1a30Sjl139090 ASSERT(mpath);
177325cf1a30Sjl139090
177425cf1a30Sjl139090 if (mpath->num == 0) {
177525cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-new: "
177625cf1a30Sjl139090 "Number of paths = %d", mpath->num);
177725cf1a30Sjl139090 return (EINVAL);
177825cf1a30Sjl139090 }
177925cf1a30Sjl139090
178025cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
178125cf1a30Sjl139090
178225cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
178325cf1a30Sjl139090 rval = oplmsu_check_lpath_usable();
178425cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
178525cf1a30Sjl139090
178625cf1a30Sjl139090 if (rval == BUSY) { /* Check whether Lower path is usable */
178725cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
178825cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-new: "
178925cf1a30Sjl139090 "Other processing is using this device");
179025cf1a30Sjl139090 return (EBUSY);
179125cf1a30Sjl139090 }
179225cf1a30Sjl139090
179325cf1a30Sjl139090 /*
179425cf1a30Sjl139090 * Because the OPLMSU instance already exists when the upper path
179525cf1a30Sjl139090 * table exists, the configure_new processing cannot be done.
179625cf1a30Sjl139090 */
179725cf1a30Sjl139090
179825cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->u_lock);
179925cf1a30Sjl139090
180025cf1a30Sjl139090 if ((oplmsu_uinst->first_upath != NULL) ||
180125cf1a30Sjl139090 (oplmsu_uinst->last_upath != NULL)) {
180225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
180325cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
180425cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-new: upath_t already exist");
180525cf1a30Sjl139090 return (EINVAL);
180625cf1a30Sjl139090 }
180725cf1a30Sjl139090
180825cf1a30Sjl139090 /*
180925cf1a30Sjl139090 * Because the config_new processing has already been done
181025cf1a30Sjl139090 * if oplmsu_uinst->path_num isn't -1, this processing cannot be
181125cf1a30Sjl139090 * continued.
181225cf1a30Sjl139090 */
181325cf1a30Sjl139090
181425cf1a30Sjl139090 if (oplmsu_uinst->path_num != UNDEFINED) {
181525cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
181625cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
181725cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-new: "
181825cf1a30Sjl139090 "conf-new processing has already been completed");
181925cf1a30Sjl139090 return (EINVAL);
182025cf1a30Sjl139090 }
182125cf1a30Sjl139090
182225cf1a30Sjl139090 /*
182325cf1a30Sjl139090 * Only the number of specified paths makes the upper path
182425cf1a30Sjl139090 * information tables.
182525cf1a30Sjl139090 */
182625cf1a30Sjl139090
182725cf1a30Sjl139090 mdev = (struct msu_dev *)(mpath + 1);
182825cf1a30Sjl139090 for (i = 0; i < mpath->num; i++) {
182925cf1a30Sjl139090 /*
183025cf1a30Sjl139090 * Associate upper path information table with lower path
183125cf1a30Sjl139090 * information table.
183225cf1a30Sjl139090 *
183325cf1a30Sjl139090 * If the upper path information table and the lower path
183425cf1a30Sjl139090 * information table cannot be associated, the link list of
183525cf1a30Sjl139090 * the upper path information table is released.
183625cf1a30Sjl139090 */
183725cf1a30Sjl139090 rval = oplmsu_create_upath(mdev->dip);
183825cf1a30Sjl139090 if (rval != SUCCESS) {
183925cf1a30Sjl139090 oplmsu_delete_upath_info();
184025cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
184125cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
184225cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-new: "
184325cf1a30Sjl139090 "Failed to create upath %d", rval);
184425cf1a30Sjl139090 return (rval);
184525cf1a30Sjl139090 }
184625cf1a30Sjl139090
184725cf1a30Sjl139090 mdev++;
184825cf1a30Sjl139090 }
184925cf1a30Sjl139090
185025cf1a30Sjl139090 /*
185125cf1a30Sjl139090 * Setup members of uinst_t
185225cf1a30Sjl139090 */
185325cf1a30Sjl139090
185425cf1a30Sjl139090 oplmsu_uinst->inst_status = oplmsu_get_inst_status();
185525cf1a30Sjl139090 oplmsu_uinst->path_num = mpath->num;
185625cf1a30Sjl139090 oplmsu_uinst->lower_queue = NULL;
185725cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
185825cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
185925cf1a30Sjl139090 return (SUCCESS);
186025cf1a30Sjl139090 }
186125cf1a30Sjl139090
186225cf1a30Sjl139090 /* Add path information */
186325cf1a30Sjl139090 int
oplmsu_config_add(dev_info_t * dip)186425cf1a30Sjl139090 oplmsu_config_add(dev_info_t *dip)
186525cf1a30Sjl139090 {
186625cf1a30Sjl139090 upath_t *upath;
186725cf1a30Sjl139090 int instance;
186825cf1a30Sjl139090 int rval = SUCCESS;
186925cf1a30Sjl139090
187025cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: conf-add: config_add() called"));
187125cf1a30Sjl139090 ASSERT(dip);
187225cf1a30Sjl139090
187325cf1a30Sjl139090 instance = ddi_get_instance(dip);
187425cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
187525cf1a30Sjl139090
187625cf1a30Sjl139090 if (oplmsu_uinst->path_num == UNDEFINED) {
187725cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
187825cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-add: "
187925cf1a30Sjl139090 "conf-new processing has not been completed yet");
188025cf1a30Sjl139090 return (EINVAL);
188125cf1a30Sjl139090 }
188225cf1a30Sjl139090
188325cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->u_lock);
188425cf1a30Sjl139090 upath = oplmsu_search_upath_info(instance);
188525cf1a30Sjl139090 if (upath != NULL) {
188625cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
188725cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
188825cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-add: "
188925cf1a30Sjl139090 "Proper upath_t doesn't find");
189025cf1a30Sjl139090 return (EINVAL);
189125cf1a30Sjl139090 }
189225cf1a30Sjl139090
189325cf1a30Sjl139090 rval = oplmsu_create_upath(dip);
189425cf1a30Sjl139090 if (rval != SUCCESS) {
189525cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
189625cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
189725cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-add: "
189825cf1a30Sjl139090 "Failed to create upath %d", rval);
189925cf1a30Sjl139090 return (rval);
190025cf1a30Sjl139090 }
190125cf1a30Sjl139090
190225cf1a30Sjl139090 oplmsu_uinst->inst_status = oplmsu_get_inst_status();
190325cf1a30Sjl139090 oplmsu_uinst->path_num = oplmsu_get_pathnum();
190425cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
190525cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
190625cf1a30Sjl139090 return (SUCCESS);
190725cf1a30Sjl139090 }
190825cf1a30Sjl139090
190925cf1a30Sjl139090 /* Delete each path information */
191025cf1a30Sjl139090 int
oplmsu_config_del(struct msu_path * mpath)191125cf1a30Sjl139090 oplmsu_config_del(struct msu_path *mpath)
191225cf1a30Sjl139090 {
191325cf1a30Sjl139090 struct msu_dev *mdev;
191425cf1a30Sjl139090 upath_t *upath;
191525cf1a30Sjl139090 lpath_t *lpath;
191625cf1a30Sjl139090 int rval = SUCCESS;
191725cf1a30Sjl139090 int use_flag;
191825cf1a30Sjl139090 int i;
191925cf1a30Sjl139090
192025cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: conf-del: config_del() called"));
192125cf1a30Sjl139090 ASSERT(mpath);
192225cf1a30Sjl139090
192325cf1a30Sjl139090 mdev = (struct msu_dev *)(mpath + 1);
192425cf1a30Sjl139090
192525cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
192625cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->u_lock);
192725cf1a30Sjl139090 for (i = 0; i < mpath->num; i++) {
192825cf1a30Sjl139090 upath = oplmsu_search_upath_info(ddi_get_instance(mdev->dip));
192925cf1a30Sjl139090 if (upath == NULL) {
193025cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-del: "
193125cf1a30Sjl139090 "Proper upath_t doesn't find");
193225cf1a30Sjl139090 rval = ENODEV;
193325cf1a30Sjl139090 mdev++;
193425cf1a30Sjl139090 continue;
193525cf1a30Sjl139090 }
193625cf1a30Sjl139090
193725cf1a30Sjl139090 lpath = upath->lpath;
193825cf1a30Sjl139090 if (lpath == NULL) {
193925cf1a30Sjl139090 if ((upath->traditional_status == MSU_WSTP_ACK) ||
194025cf1a30Sjl139090 (upath->traditional_status == MSU_WSTR_ACK) ||
194125cf1a30Sjl139090 (upath->traditional_status == MSU_WPTH_CHG) ||
194225cf1a30Sjl139090 (upath->traditional_status == MSU_WTCS_ACK) ||
194325cf1a30Sjl139090 (upath->traditional_status == MSU_WTMS_ACK) ||
194425cf1a30Sjl139090 (upath->traditional_status == MSU_WPPS_ACK) ||
194525cf1a30Sjl139090 (upath->traditional_status == MSU_WWSZ_ACK) ||
194625cf1a30Sjl139090 (upath->traditional_status == MSU_WCAR_ACK)) {
194725cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-del: "
194825cf1a30Sjl139090 "Other processing is using this device");
194925cf1a30Sjl139090 rval = EBUSY;
195025cf1a30Sjl139090 mdev++;
195125cf1a30Sjl139090 continue;
195225cf1a30Sjl139090 }
195325cf1a30Sjl139090
195425cf1a30Sjl139090 if ((upath->status != MSU_PSTAT_DISCON) ||
195525cf1a30Sjl139090 (upath->traditional_status != MSU_DISCON)) {
195625cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-del: "
195725cf1a30Sjl139090 "Status of path is improper");
195825cf1a30Sjl139090 rval = EINVAL;
195925cf1a30Sjl139090 mdev++;
196025cf1a30Sjl139090 continue;
196125cf1a30Sjl139090 }
196225cf1a30Sjl139090 } else {
196325cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
196425cf1a30Sjl139090 use_flag = oplmsu_set_ioctl_path(lpath, NULL, NULL);
196525cf1a30Sjl139090 if (use_flag == BUSY) {
196625cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
196725cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-del: "
196825cf1a30Sjl139090 "Other processing is using lower path");
196925cf1a30Sjl139090 rval = EBUSY;
197025cf1a30Sjl139090 mdev++;
197125cf1a30Sjl139090 continue;
197225cf1a30Sjl139090 }
197325cf1a30Sjl139090
197425cf1a30Sjl139090 if (((upath->status != MSU_PSTAT_STOP) ||
197525cf1a30Sjl139090 (upath->traditional_status != MSU_STOP)) &&
197625cf1a30Sjl139090 ((upath->status != MSU_PSTAT_FAIL) ||
197725cf1a30Sjl139090 (upath->traditional_status != MSU_FAIL))) {
197825cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
197925cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
198025cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-del: "
198125cf1a30Sjl139090 "Status of path isn't 'Offline:stop/fail'");
198225cf1a30Sjl139090 rval = EINVAL;
198325cf1a30Sjl139090 mdev++;
198425cf1a30Sjl139090 continue;
198525cf1a30Sjl139090 }
198625cf1a30Sjl139090 lpath->src_upath = NULL;
198725cf1a30Sjl139090 lpath->status = MSU_SETID_NU;
198825cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
198925cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
199025cf1a30Sjl139090 }
199125cf1a30Sjl139090 oplmsu_unlink_upath(upath); /* Unlink upath_t */
199225cf1a30Sjl139090 kmem_free(upath, sizeof (upath_t));
199325cf1a30Sjl139090 mdev++;
199425cf1a30Sjl139090 }
199525cf1a30Sjl139090
199625cf1a30Sjl139090 oplmsu_uinst->inst_status = oplmsu_get_inst_status();
199725cf1a30Sjl139090 oplmsu_uinst->path_num = oplmsu_get_pathnum();
199825cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
199925cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
200025cf1a30Sjl139090 return (rval);
200125cf1a30Sjl139090 }
200225cf1a30Sjl139090
200325cf1a30Sjl139090 /* Stop to use the path */
200425cf1a30Sjl139090 int
oplmsu_config_stop(int pathnum)200525cf1a30Sjl139090 oplmsu_config_stop(int pathnum)
200625cf1a30Sjl139090 {
200725cf1a30Sjl139090 upath_t *upath, *altn_upath;
200825cf1a30Sjl139090 lpath_t *lpath, *altn_lpath;
200925cf1a30Sjl139090 queue_t *stp_queue = NULL;
201025cf1a30Sjl139090 queue_t *dst_queue = NULL;
201125cf1a30Sjl139090 mblk_t *nmp = NULL, *fmp = NULL;
201225cf1a30Sjl139090 ctrl_t *ctrl;
201325cf1a30Sjl139090 int term_ioctl, term_stat;
201425cf1a30Sjl139090 int use_flag;
201525cf1a30Sjl139090
201625cf1a30Sjl139090 DBG_PRINT((CE_NOTE,
201725cf1a30Sjl139090 "oplmsu: conf-stop: config_stop(%d) called", pathnum));
201825cf1a30Sjl139090
201925cf1a30Sjl139090 if (pathnum == MSU_PATH_ALL) {
202025cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stop: "
202125cf1a30Sjl139090 "All path can't be transferred to the status of "
202225cf1a30Sjl139090 "'Offline:stop'");
202325cf1a30Sjl139090 return (EINVAL);
202425cf1a30Sjl139090 }
202525cf1a30Sjl139090
202625cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
202725cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->u_lock);
202825cf1a30Sjl139090
202925cf1a30Sjl139090 upath = oplmsu_search_upath_info(pathnum); /* Search upath_t */
203025cf1a30Sjl139090 if (upath == NULL) {
203125cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
203225cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
203325cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stop: "
203425cf1a30Sjl139090 "Proper upath_t doesn't find");
203525cf1a30Sjl139090 return (ENODEV);
203625cf1a30Sjl139090 }
203725cf1a30Sjl139090
203825cf1a30Sjl139090 lpath = upath->lpath;
203925cf1a30Sjl139090 if (lpath == NULL) {
204025cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
204125cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
204225cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stop: "
204325cf1a30Sjl139090 "Proper lpath_t doesn't exist");
204425cf1a30Sjl139090 return (ENODEV);
204525cf1a30Sjl139090 }
204625cf1a30Sjl139090
204725cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
204825cf1a30Sjl139090
204925cf1a30Sjl139090 /* Check status of lpath_t */
205025cf1a30Sjl139090 use_flag = oplmsu_set_ioctl_path(lpath, NULL, NULL);
205125cf1a30Sjl139090 if (use_flag == BUSY) {
205225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
205325cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
205425cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
205525cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stop: "
205625cf1a30Sjl139090 "Other processing is using lower path");
205725cf1a30Sjl139090 return (EBUSY);
205825cf1a30Sjl139090 }
205925cf1a30Sjl139090
206025cf1a30Sjl139090 if (upath->status == MSU_PSTAT_FAIL) {
206125cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
206225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
206325cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
206425cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
206525cf1a30Sjl139090 return (EIO);
206625cf1a30Sjl139090 } else if ((upath->status == MSU_PSTAT_STOP) &&
206725cf1a30Sjl139090 (upath->traditional_status == MSU_STOP)) {
206825cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
206925cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
207025cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
207125cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
207225cf1a30Sjl139090 return (SUCCESS);
207325cf1a30Sjl139090 } else if ((upath->status == MSU_PSTAT_STANDBY) &&
207425cf1a30Sjl139090 (upath->traditional_status == MSU_STANDBY)) {
207525cf1a30Sjl139090 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_STOP,
207625cf1a30Sjl139090 upath->status, MSU_STOP);
207725cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
207825cf1a30Sjl139090 lpath->src_upath = NULL;
207925cf1a30Sjl139090 lpath->status = MSU_EXT_NOTUSED;
208025cf1a30Sjl139090
208125cf1a30Sjl139090 oplmsu_uinst->inst_status = oplmsu_get_inst_status();
208225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
208325cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
208425cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
208525cf1a30Sjl139090 return (SUCCESS);
208625cf1a30Sjl139090 } else if ((upath->status == MSU_PSTAT_ACTIVE) &&
208725cf1a30Sjl139090 (upath->traditional_status == MSU_ACTIVE)) {
208825cf1a30Sjl139090 altn_upath = oplmsu_search_standby();
208925cf1a30Sjl139090 if (altn_upath == NULL) { /* Alternate path doesn't exist */
209025cf1a30Sjl139090 DBG_PRINT((CE_NOTE, "oplmsu: conf-stop: "
209125cf1a30Sjl139090 "Alternate upper path doesn't find"));
209225cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
209325cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
209425cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
209525cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
209625cf1a30Sjl139090 return (EINVAL);
209725cf1a30Sjl139090 }
209825cf1a30Sjl139090
209925cf1a30Sjl139090 if ((fmp = allocb(sizeof (char), BPRI_LO)) == NULL) {
210025cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
210125cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
210225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
210325cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
210425cf1a30Sjl139090 return (ENOSR);
210525cf1a30Sjl139090 }
210625cf1a30Sjl139090
210725cf1a30Sjl139090 if (oplmsu_stop_prechg(&nmp, &term_ioctl, &term_stat) !=
210825cf1a30Sjl139090 SUCCESS) {
210925cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
211025cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
211125cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
211225cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
211325cf1a30Sjl139090 freeb(fmp);
211425cf1a30Sjl139090 return (ENOSR);
211525cf1a30Sjl139090 }
211625cf1a30Sjl139090
211725cf1a30Sjl139090 altn_lpath = altn_upath->lpath;
211825cf1a30Sjl139090 use_flag = oplmsu_set_ioctl_path(altn_lpath, NULL, NULL);
211925cf1a30Sjl139090 if (use_flag == BUSY) {
212025cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
212125cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
212225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
212325cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
212425cf1a30Sjl139090
212525cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stop: "
212625cf1a30Sjl139090 "Other processing is using alternate lower path");
212725cf1a30Sjl139090 freeb(fmp);
212825cf1a30Sjl139090 freemsg(nmp);
212925cf1a30Sjl139090 return (EBUSY);
213025cf1a30Sjl139090 }
213125cf1a30Sjl139090
213225cf1a30Sjl139090 dst_queue = WR(altn_lpath->lower_queue);
213325cf1a30Sjl139090
213425cf1a30Sjl139090 /* termios is not held. Change alternate path to MSU_ACTIVE */
213525cf1a30Sjl139090 if (nmp == NULL) {
213625cf1a30Sjl139090 altn_upath->traditional_status = term_stat;
213725cf1a30Sjl139090 altn_lpath->src_upath = upath;
213825cf1a30Sjl139090 altn_lpath->status = MSU_EXT_VOID;
213925cf1a30Sjl139090
214025cf1a30Sjl139090 oplmsu_uinst->lower_queue = NULL;
214125cf1a30Sjl139090
214225cf1a30Sjl139090 ctrl = oplmsu_uinst->user_ctrl;
214325cf1a30Sjl139090 if (ctrl != NULL) {
214425cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->c_lock);
214525cf1a30Sjl139090 stp_queue = WR(ctrl->queue);
214625cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->c_lock);
214725cf1a30Sjl139090 noenable(stp_queue);
214825cf1a30Sjl139090 oplmsu_queue_flag = 1;
214925cf1a30Sjl139090 }
215025cf1a30Sjl139090
215125cf1a30Sjl139090 /* Make M_FLUSH and send to alternate path */
215225cf1a30Sjl139090 oplmsu_cmn_set_mflush(fmp);
215307d06da5SSurya Prakki (void) putq(dst_queue, fmp);
215425cf1a30Sjl139090
215525cf1a30Sjl139090 /* Change status of alternate path */
215625cf1a30Sjl139090 oplmsu_cmn_set_upath_sts(altn_upath, MSU_PSTAT_ACTIVE,
215725cf1a30Sjl139090 altn_upath->status, MSU_ACTIVE);
215825cf1a30Sjl139090
215925cf1a30Sjl139090 oplmsu_clear_ioctl_path(altn_lpath);
216025cf1a30Sjl139090 altn_lpath->uinst = oplmsu_uinst;
216125cf1a30Sjl139090 altn_lpath->src_upath = NULL;
216225cf1a30Sjl139090 altn_lpath->status = MSU_EXT_NOTUSED;
216325cf1a30Sjl139090
216425cf1a30Sjl139090 /* Notify of the active path changing */
216507d06da5SSurya Prakki (void) prom_opl_switch_console(
216607d06da5SSurya Prakki altn_upath->ser_devcb.lsb);
216725cf1a30Sjl139090
216825cf1a30Sjl139090 /* Send XON to notify active path */
216925cf1a30Sjl139090 (void) oplmsu_cmn_put_xoffxon(dst_queue, MSU_XON_4);
217025cf1a30Sjl139090
217125cf1a30Sjl139090 /* Send XOFF to notify all standby paths */
217225cf1a30Sjl139090 oplmsu_cmn_putxoff_standby();
217325cf1a30Sjl139090
217425cf1a30Sjl139090 oplmsu_uinst->lower_queue = RD(dst_queue);
217525cf1a30Sjl139090 ctrl = oplmsu_uinst->user_ctrl;
217625cf1a30Sjl139090
217725cf1a30Sjl139090 /* Switch active path of oplmsu */
217825cf1a30Sjl139090 if (ctrl != NULL) {
217925cf1a30Sjl139090 queue_t *altn_queue;
218025cf1a30Sjl139090
218125cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->c_lock);
218225cf1a30Sjl139090 altn_queue = WR(ctrl->queue);
218325cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->c_lock);
218425cf1a30Sjl139090
218525cf1a30Sjl139090 /* Restart queuing of user access node */
218625cf1a30Sjl139090 enableok(altn_queue);
218725cf1a30Sjl139090
218825cf1a30Sjl139090 oplmsu_queue_flag = 0;
218925cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
219025cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
219125cf1a30Sjl139090 oplmsu_wcmn_high_qenable(altn_queue, RW_WRITER);
219225cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->u_lock);
219325cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
219425cf1a30Sjl139090 }
219525cf1a30Sjl139090
219625cf1a30Sjl139090 /* Stop previous active path */
219725cf1a30Sjl139090 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_STOP,
219825cf1a30Sjl139090 upath->status, MSU_STOP);
219925cf1a30Sjl139090
220025cf1a30Sjl139090 lpath->uinst = NULL;
220125cf1a30Sjl139090 lpath->src_upath = NULL;
220225cf1a30Sjl139090 lpath->status = MSU_EXT_NOTUSED;
220325cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
220425cf1a30Sjl139090
220525cf1a30Sjl139090 oplmsu_uinst->inst_status = oplmsu_get_inst_status();
220625cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
220725cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
220825cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
220925cf1a30Sjl139090 return (SUCCESS);
221025cf1a30Sjl139090 }
221125cf1a30Sjl139090
221225cf1a30Sjl139090 /* Send termios information to alternate path */
221325cf1a30Sjl139090 if (canput(dst_queue)) {
221425cf1a30Sjl139090 altn_upath->traditional_status = term_stat;
221525cf1a30Sjl139090 altn_lpath->src_upath = upath;
221625cf1a30Sjl139090 altn_lpath->status = MSU_EXT_VOID;
221725cf1a30Sjl139090
221825cf1a30Sjl139090 upath->traditional_status = MSU_WSTP_ACK;
221925cf1a30Sjl139090 lpath->uinst = NULL;
222025cf1a30Sjl139090
222125cf1a30Sjl139090 oplmsu_uinst->lower_queue = NULL;
222225cf1a30Sjl139090
222325cf1a30Sjl139090 ctrl = oplmsu_uinst->user_ctrl;
222425cf1a30Sjl139090 if (ctrl != NULL) {
222525cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->c_lock);
222625cf1a30Sjl139090 stp_queue = WR(ctrl->queue);
222725cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->c_lock);
222825cf1a30Sjl139090 noenable(stp_queue);
222925cf1a30Sjl139090 oplmsu_queue_flag = 1;
223025cf1a30Sjl139090 }
223125cf1a30Sjl139090
223225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
223325cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
223425cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
223525cf1a30Sjl139090 oplmsu_cmn_set_mflush(fmp);
223607d06da5SSurya Prakki (void) putq(dst_queue, fmp);
223707d06da5SSurya Prakki (void) putq(dst_queue, nmp);
223825cf1a30Sjl139090
223925cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
224025cf1a30Sjl139090 lpath->sw_flag = 1;
224125cf1a30Sjl139090 while (lpath->sw_flag != 0) {
224225cf1a30Sjl139090 /* Wait for the completion of path switching */
224325cf1a30Sjl139090 cv_wait(&lpath->sw_cv, &oplmsu_uinst->l_lock);
224425cf1a30Sjl139090 }
224525cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
224625cf1a30Sjl139090 return (SUCCESS);
224725cf1a30Sjl139090 } else {
224825cf1a30Sjl139090 oplmsu_clear_ioctl_path(altn_lpath);
224925cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
225025cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
225125cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
225225cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
225325cf1a30Sjl139090 freeb(fmp);
225425cf1a30Sjl139090 freemsg(nmp);
225525cf1a30Sjl139090 return (FAILURE);
225625cf1a30Sjl139090 }
225725cf1a30Sjl139090 /* NOTREACHED */
225825cf1a30Sjl139090 } else {
225925cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
226025cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
226125cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
226225cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
226325cf1a30Sjl139090
226425cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-stop: "
226525cf1a30Sjl139090 "Status of path is improper");
226625cf1a30Sjl139090 return (EINVAL);
226725cf1a30Sjl139090 }
226825cf1a30Sjl139090 /* NOTREACHED */
226925cf1a30Sjl139090 }
227025cf1a30Sjl139090
227125cf1a30Sjl139090 /* Start to use path */
227225cf1a30Sjl139090 int
oplmsu_config_start(int pathnum)227325cf1a30Sjl139090 oplmsu_config_start(int pathnum)
227425cf1a30Sjl139090 {
227525cf1a30Sjl139090 upath_t *upath = NULL;
227625cf1a30Sjl139090 lpath_t *lpath = NULL;
227725cf1a30Sjl139090 queue_t *dst_queue, *main_rq = NULL;
227825cf1a30Sjl139090 int msu_tty_port;
227925cf1a30Sjl139090
228025cf1a30Sjl139090 DBG_PRINT((CE_NOTE,
228125cf1a30Sjl139090 "oplmsu: conf-start: config_start(%d) called", pathnum));
228225cf1a30Sjl139090
228325cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_WRITER);
228425cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->u_lock);
228525cf1a30Sjl139090
228625cf1a30Sjl139090 if (oplmsu_get_inst_status() == INST_STAT_BUSY) {
228725cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
228825cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
228925cf1a30Sjl139090 return (EBUSY);
229025cf1a30Sjl139090 }
229125cf1a30Sjl139090
229225cf1a30Sjl139090 if (pathnum == MSU_PATH_ALL) {
229325cf1a30Sjl139090 (void) oplmsu_search_min_stop_path();
229425cf1a30Sjl139090 }
229525cf1a30Sjl139090
229625cf1a30Sjl139090 for (upath = oplmsu_uinst->first_upath; upath; ) {
229725cf1a30Sjl139090 if ((pathnum != MSU_PATH_ALL) && (upath->path_no != pathnum)) {
229825cf1a30Sjl139090 upath = upath->u_next;
229925cf1a30Sjl139090 continue;
230025cf1a30Sjl139090 }
230125cf1a30Sjl139090
230225cf1a30Sjl139090 if (upath->path_no == pathnum) {
230325cf1a30Sjl139090 lpath = upath->lpath;
230425cf1a30Sjl139090 if (lpath == NULL) {
230525cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
230625cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
230725cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-start: "
230825cf1a30Sjl139090 "Proper lpath_t doesn't exist");
230925cf1a30Sjl139090 return (EINVAL);
231025cf1a30Sjl139090 }
231125cf1a30Sjl139090
231225cf1a30Sjl139090 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_STANDBY,
231325cf1a30Sjl139090 upath->status, MSU_STANDBY);
231425cf1a30Sjl139090
231525cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
231625cf1a30Sjl139090 lpath->src_upath = NULL;
231725cf1a30Sjl139090 lpath->status = MSU_EXT_NOTUSED;
231825cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
231925cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
232025cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
232125cf1a30Sjl139090 return (SUCCESS);
232225cf1a30Sjl139090 }
232325cf1a30Sjl139090
232425cf1a30Sjl139090 /*
232525cf1a30Sjl139090 * with PATH_ALL
232625cf1a30Sjl139090 */
232725cf1a30Sjl139090 lpath = upath->lpath;
232825cf1a30Sjl139090 if (lpath == NULL) {
232925cf1a30Sjl139090 upath = upath->u_next;
233025cf1a30Sjl139090
233125cf1a30Sjl139090 DBG_PRINT((CE_WARN, "oplmsu: conf-start: "
233225cf1a30Sjl139090 "Proper lpath_t doesn't exist"));
233325cf1a30Sjl139090 continue;
233425cf1a30Sjl139090 }
233525cf1a30Sjl139090
233625cf1a30Sjl139090 msu_tty_port = ddi_prop_get_int(DDI_DEV_T_ANY,
233725cf1a30Sjl139090 oplmsu_uinst->msu_dip, 0, MSU_TTY_PORT_PROP, -1);
233825cf1a30Sjl139090
233925cf1a30Sjl139090 if (upath->ser_devcb.lsb == msu_tty_port) {
234025cf1a30Sjl139090 /* Notify of the active path changing */
234107d06da5SSurya Prakki (void) prom_opl_switch_console(upath->ser_devcb.lsb);
234225cf1a30Sjl139090
234325cf1a30Sjl139090 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_ACTIVE,
234425cf1a30Sjl139090 upath->status, MSU_ACTIVE);
234525cf1a30Sjl139090
234625cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
234725cf1a30Sjl139090 main_rq = RD(lpath->lower_queue);
234825cf1a30Sjl139090 dst_queue = WR(lpath->lower_queue);
234925cf1a30Sjl139090 lpath->src_upath = NULL;
235025cf1a30Sjl139090 lpath->status = MSU_EXT_NOTUSED;
235125cf1a30Sjl139090 lpath->uinst = oplmsu_uinst;
235225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
235325cf1a30Sjl139090
235425cf1a30Sjl139090 /* Send XON to notify active path */
235525cf1a30Sjl139090 (void) oplmsu_cmn_put_xoffxon(dst_queue, MSU_XON_4);
235625cf1a30Sjl139090 } else {
235725cf1a30Sjl139090 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_STANDBY,
235825cf1a30Sjl139090 upath->status, MSU_STANDBY);
235925cf1a30Sjl139090
236025cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
236125cf1a30Sjl139090 lpath->src_upath = NULL;
236225cf1a30Sjl139090 lpath->status = MSU_EXT_NOTUSED;
236325cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
236425cf1a30Sjl139090 }
236525cf1a30Sjl139090 upath = upath->u_next;
236625cf1a30Sjl139090 }
236725cf1a30Sjl139090
236825cf1a30Sjl139090 if (main_rq == NULL) {
236925cf1a30Sjl139090 upath_t *altn_upath;
237025cf1a30Sjl139090 lpath_t *altn_lpath;
237125cf1a30Sjl139090
237225cf1a30Sjl139090 altn_upath = oplmsu_search_standby();
237325cf1a30Sjl139090 if (altn_upath) {
237425cf1a30Sjl139090 oplmsu_cmn_set_upath_sts(altn_upath, MSU_PSTAT_ACTIVE,
237525cf1a30Sjl139090 altn_upath->status, MSU_ACTIVE);
237625cf1a30Sjl139090
237725cf1a30Sjl139090 /* Notify of the active path changing */
237807d06da5SSurya Prakki (void) prom_opl_switch_console(
237907d06da5SSurya Prakki altn_upath->ser_devcb.lsb);
238025cf1a30Sjl139090
238125cf1a30Sjl139090 altn_lpath = altn_upath->lpath;
238225cf1a30Sjl139090 if (altn_lpath) {
238325cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
238425cf1a30Sjl139090 main_rq = RD(altn_lpath->lower_queue);
238525cf1a30Sjl139090 dst_queue = WR(altn_lpath->lower_queue);
238625cf1a30Sjl139090 altn_lpath->src_upath = NULL;
238725cf1a30Sjl139090 altn_lpath->status = MSU_EXT_NOTUSED;
238825cf1a30Sjl139090 altn_lpath->uinst = oplmsu_uinst;
238925cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
239025cf1a30Sjl139090
239125cf1a30Sjl139090 /* Send XON to notify active path */
239225cf1a30Sjl139090 (void) oplmsu_cmn_put_xoffxon(dst_queue,
239325cf1a30Sjl139090 MSU_XON_4);
239425cf1a30Sjl139090 } else {
239525cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-start: "
239625cf1a30Sjl139090 "Proper alternate lpath_t doesn't exist");
239725cf1a30Sjl139090 }
239825cf1a30Sjl139090 } else {
239925cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-start: "
240025cf1a30Sjl139090 "Proper alternate upath_t doesn't exist");
240125cf1a30Sjl139090 }
240225cf1a30Sjl139090 }
240325cf1a30Sjl139090
240425cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
240525cf1a30Sjl139090
240625cf1a30Sjl139090 /* Send XOFF to notify all standby paths */
240725cf1a30Sjl139090 oplmsu_cmn_putxoff_standby();
240825cf1a30Sjl139090
240925cf1a30Sjl139090 /* Change active path of oplmsu */
241025cf1a30Sjl139090 oplmsu_uinst->lower_queue = main_rq;
241125cf1a30Sjl139090 oplmsu_uinst->inst_status = oplmsu_get_inst_status();
241225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
241325cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
241425cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
241525cf1a30Sjl139090 return (SUCCESS);
241625cf1a30Sjl139090 }
241725cf1a30Sjl139090
241825cf1a30Sjl139090 /* Prepare of unlink path */
241925cf1a30Sjl139090 int
oplmsu_config_disc(int pathnum)242025cf1a30Sjl139090 oplmsu_config_disc(int pathnum)
242125cf1a30Sjl139090 {
242225cf1a30Sjl139090 upath_t *upath;
242325cf1a30Sjl139090 lpath_t *lpath;
242425cf1a30Sjl139090 int use_flag;
242525cf1a30Sjl139090
242625cf1a30Sjl139090 DBG_PRINT((CE_NOTE,
242725cf1a30Sjl139090 "oplmsu: conf-disc: config_disc(%d) called", pathnum));
242825cf1a30Sjl139090
242925cf1a30Sjl139090 rw_enter(&oplmsu_uinst->lock, RW_READER);
243025cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->u_lock);
243125cf1a30Sjl139090
243225cf1a30Sjl139090 upath = oplmsu_search_upath_info(pathnum);
243325cf1a30Sjl139090 if (upath == NULL) {
243425cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
243525cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
243625cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-disc: "
243725cf1a30Sjl139090 "Proper upath_t doesn't find");
243825cf1a30Sjl139090 return (EINVAL);
243925cf1a30Sjl139090 }
244025cf1a30Sjl139090
244125cf1a30Sjl139090 if ((upath->status == MSU_PSTAT_DISCON) ||
244225cf1a30Sjl139090 (upath->traditional_status == MSU_DISCON)) {
244325cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
244425cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
244525cf1a30Sjl139090 return (SUCCESS);
244625cf1a30Sjl139090 } else if (((upath->status != MSU_PSTAT_STOP) ||
244725cf1a30Sjl139090 (upath->traditional_status != MSU_STOP)) &&
244825cf1a30Sjl139090 ((upath->status != MSU_PSTAT_FAIL) ||
244925cf1a30Sjl139090 (upath->traditional_status != MSU_FAIL))) {
245025cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
245125cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
245225cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-disc: "
245325cf1a30Sjl139090 "Status of path is improper");
245425cf1a30Sjl139090 return (EINVAL);
245525cf1a30Sjl139090 }
245625cf1a30Sjl139090
245725cf1a30Sjl139090 lpath = upath->lpath;
245825cf1a30Sjl139090 if (lpath == NULL) {
245925cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
246025cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
246125cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-disc: "
246225cf1a30Sjl139090 "Proper lpath_t doesn't exist");
246325cf1a30Sjl139090 return (ENODEV);
246425cf1a30Sjl139090 }
246525cf1a30Sjl139090
246625cf1a30Sjl139090 mutex_enter(&oplmsu_uinst->l_lock);
246725cf1a30Sjl139090
246825cf1a30Sjl139090 /* Check lower path status */
246925cf1a30Sjl139090 use_flag = oplmsu_set_ioctl_path(lpath, NULL, NULL);
247025cf1a30Sjl139090 if (use_flag == BUSY) {
247125cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
247225cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
247325cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
247425cf1a30Sjl139090 cmn_err(CE_WARN, "oplmsu: conf-disc: "
247525cf1a30Sjl139090 "Other processing is using lower path");
247625cf1a30Sjl139090 return (EBUSY);
247725cf1a30Sjl139090 }
247825cf1a30Sjl139090
247925cf1a30Sjl139090 upath->status = MSU_PSTAT_STOP;
248025cf1a30Sjl139090 upath->traditional_status = MSU_SETID;
248125cf1a30Sjl139090
248225cf1a30Sjl139090 oplmsu_clear_ioctl_path(lpath);
248325cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->l_lock);
248425cf1a30Sjl139090 mutex_exit(&oplmsu_uinst->u_lock);
248525cf1a30Sjl139090 rw_exit(&oplmsu_uinst->lock);
248625cf1a30Sjl139090 return (SUCCESS);
248725cf1a30Sjl139090 }
2488