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