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 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 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 27125cf1a30Sjl139090 _info(struct modinfo *modinfop) 27225cf1a30Sjl139090 { 27325cf1a30Sjl139090 return (mod_info(&modlinkage, modinfop)); 27425cf1a30Sjl139090 } 27525cf1a30Sjl139090 27625cf1a30Sjl139090 /* ARGSUSED */ 27725cf1a30Sjl139090 int 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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