17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * sun4v machine description driver 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/file.h> 337c478bd9Sstevel@tonic-gate #include <sys/errno.h> 347c478bd9Sstevel@tonic-gate #include <sys/open.h> 357c478bd9Sstevel@tonic-gate #include <sys/cred.h> 367c478bd9Sstevel@tonic-gate #include <sys/uio.h> 377c478bd9Sstevel@tonic-gate #include <sys/stat.h> 387c478bd9Sstevel@tonic-gate #include <sys/ksynch.h> 397c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 407c478bd9Sstevel@tonic-gate #include <sys/conf.h> 417c478bd9Sstevel@tonic-gate #include <sys/devops.h> 427c478bd9Sstevel@tonic-gate #include <sys/debug.h> 437c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 447c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 457c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include <sys/mdesc.h> 487c478bd9Sstevel@tonic-gate #include <sys/mach_descrip.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #define MDESC_NAME "mdesc" 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * Operational state flags 547c478bd9Sstevel@tonic-gate */ 557c478bd9Sstevel@tonic-gate 561ae08745Sheppo #define MDESC_GOT_HANDLE 0x10 /* Got mdesc handle */ 577c478bd9Sstevel@tonic-gate #define MDESC_BUSY 0x20 /* Device is busy */ 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate static void *mdesc_state_head; 601ae08745Sheppo static vmem_t *mdesc_minor; 611ae08745Sheppo static uint16_t mdesc_max_opens = 256; 621ae08745Sheppo static uint16_t mdesc_opens = 0; 631ae08745Sheppo static int mdesc_attached = 0; 641ae08745Sheppo static dev_info_t *mdesc_devi; 651ae08745Sheppo static kmutex_t mdesc_lock; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate struct mdesc_state { 687c478bd9Sstevel@tonic-gate int instance; 691ae08745Sheppo dev_t dev; 707c478bd9Sstevel@tonic-gate kmutex_t lock; 717c478bd9Sstevel@tonic-gate kcondvar_t cv; 727c478bd9Sstevel@tonic-gate size_t mdesc_len; 731ae08745Sheppo md_t *mdesc; 747c478bd9Sstevel@tonic-gate int flags; 757c478bd9Sstevel@tonic-gate }; 767c478bd9Sstevel@tonic-gate 771ae08745Sheppo typedef struct mdesc_state mdesc_state_t; 781ae08745Sheppo 797c478bd9Sstevel@tonic-gate static int mdesc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 807c478bd9Sstevel@tonic-gate static int mdesc_attach(dev_info_t *, ddi_attach_cmd_t); 817c478bd9Sstevel@tonic-gate static int mdesc_detach(dev_info_t *, ddi_detach_cmd_t); 827c478bd9Sstevel@tonic-gate static int mdesc_open(dev_t *, int, int, cred_t *); 837c478bd9Sstevel@tonic-gate static int mdesc_close(dev_t, int, int, cred_t *); 847c478bd9Sstevel@tonic-gate static int mdesc_read(dev_t, struct uio *, cred_t *); 857c478bd9Sstevel@tonic-gate static int mdesc_write(dev_t, struct uio *, cred_t *); 867c478bd9Sstevel@tonic-gate static int mdesc_rw(dev_t, struct uio *, enum uio_rw); 877c478bd9Sstevel@tonic-gate static int mdesc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate static struct cb_ops mdesc_cb_ops = { 907c478bd9Sstevel@tonic-gate mdesc_open, /* cb_open */ 917c478bd9Sstevel@tonic-gate mdesc_close, /* cb_close */ 927c478bd9Sstevel@tonic-gate nodev, /* cb_strategy */ 937c478bd9Sstevel@tonic-gate nodev, /* cb_print */ 947c478bd9Sstevel@tonic-gate nodev, /* cb_dump */ 957c478bd9Sstevel@tonic-gate mdesc_read, /* cb_read */ 967c478bd9Sstevel@tonic-gate nodev, /* cb_write */ 977c478bd9Sstevel@tonic-gate mdesc_ioctl, /* cb_ioctl */ 987c478bd9Sstevel@tonic-gate nodev, /* cb_devmap */ 997c478bd9Sstevel@tonic-gate nodev, /* cb_mmap */ 1007c478bd9Sstevel@tonic-gate nodev, /* cb_segmap */ 1017c478bd9Sstevel@tonic-gate nochpoll, /* cb_chpoll */ 1027c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1037c478bd9Sstevel@tonic-gate (struct streamtab *)NULL, /* cb_str */ 1047c478bd9Sstevel@tonic-gate D_MP | D_64BIT, /* cb_flag */ 1057c478bd9Sstevel@tonic-gate CB_REV, /* cb_rev */ 1067c478bd9Sstevel@tonic-gate nodev, /* cb_aread */ 1077c478bd9Sstevel@tonic-gate nodev /* cb_awrite */ 1087c478bd9Sstevel@tonic-gate }; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate static struct dev_ops mdesc_dev_ops = { 1117c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 1127c478bd9Sstevel@tonic-gate 0, /* devo_refcnt */ 1137c478bd9Sstevel@tonic-gate mdesc_getinfo, /* devo_getinfo */ 1147c478bd9Sstevel@tonic-gate nulldev, /* devo_identify */ 1157c478bd9Sstevel@tonic-gate nulldev, /* devo_probe */ 1167c478bd9Sstevel@tonic-gate mdesc_attach, /* devo_attach */ 1177c478bd9Sstevel@tonic-gate mdesc_detach, /* devo_detach */ 1187c478bd9Sstevel@tonic-gate nodev, /* devo_reset */ 1197c478bd9Sstevel@tonic-gate &mdesc_cb_ops, /* devo_cb_ops */ 1207c478bd9Sstevel@tonic-gate (struct bus_ops *)NULL, /* devo_bus_ops */ 121*19397407SSherry Moore nulldev, /* devo_power */ 122*19397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 1237c478bd9Sstevel@tonic-gate }; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1267c478bd9Sstevel@tonic-gate &mod_driverops, 127*19397407SSherry Moore "Machine Description Driver", 1287c478bd9Sstevel@tonic-gate &mdesc_dev_ops}; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1317c478bd9Sstevel@tonic-gate MODREV_1, 1327c478bd9Sstevel@tonic-gate (void *)&modldrv, 1337c478bd9Sstevel@tonic-gate NULL 1347c478bd9Sstevel@tonic-gate }; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate int 1387c478bd9Sstevel@tonic-gate _init(void) 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate int retval; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if ((retval = ddi_soft_state_init(&mdesc_state_head, 1431ae08745Sheppo sizeof (struct mdesc_state), mdesc_max_opens)) != 0) 1447c478bd9Sstevel@tonic-gate return (retval); 1457c478bd9Sstevel@tonic-gate if ((retval = mod_install(&modlinkage)) != 0) { 1467c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&mdesc_state_head); 1477c478bd9Sstevel@tonic-gate return (retval); 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate return (retval); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate int 1577c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1587c478bd9Sstevel@tonic-gate { 1597c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate int 1667c478bd9Sstevel@tonic-gate _fini(void) 1677c478bd9Sstevel@tonic-gate { 1687c478bd9Sstevel@tonic-gate int retval; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate if ((retval = mod_remove(&modlinkage)) != 0) 1717c478bd9Sstevel@tonic-gate return (retval); 1727c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&mdesc_state_head); 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate return (retval); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1817c478bd9Sstevel@tonic-gate static int 1827c478bd9Sstevel@tonic-gate mdesc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 1837c478bd9Sstevel@tonic-gate { 1847c478bd9Sstevel@tonic-gate struct mdesc_state *mdsp; 1857c478bd9Sstevel@tonic-gate int retval = DDI_FAILURE; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate ASSERT(resultp != NULL); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate switch (cmd) { 1907c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 1911ae08745Sheppo mdsp = ddi_get_soft_state(mdesc_state_head, 1921ae08745Sheppo getminor((dev_t)arg)); 1931ae08745Sheppo if (mdsp != NULL) { 1941ae08745Sheppo *resultp = mdesc_devi; 1957c478bd9Sstevel@tonic-gate retval = DDI_SUCCESS; 1967c478bd9Sstevel@tonic-gate } else 1977c478bd9Sstevel@tonic-gate *resultp = NULL; 1987c478bd9Sstevel@tonic-gate break; 1997c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2000bd5614cSiskreen *resultp = (void *)(uintptr_t)getminor((dev_t)arg); 2017c478bd9Sstevel@tonic-gate retval = DDI_SUCCESS; 2027c478bd9Sstevel@tonic-gate break; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate return (retval); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate static int 2127c478bd9Sstevel@tonic-gate mdesc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate switch (cmd) { 2177c478bd9Sstevel@tonic-gate case DDI_ATTACH: 2181ae08745Sheppo 2197c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, MDESC_NAME, S_IFCHR, instance, 2207c478bd9Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS) { 2217c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s@%d: Unable to create minor node", 2227c478bd9Sstevel@tonic-gate MDESC_NAME, instance); 2237c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 2261ae08745Sheppo mdesc_devi = dip; 2271ae08745Sheppo mdesc_minor = vmem_create("mdesc_minor", (void *) 1, 2281ae08745Sheppo mdesc_max_opens, 1, NULL, NULL, NULL, 0, 2291ae08745Sheppo VM_SLEEP | VMC_IDENTIFIER); 2301ae08745Sheppo mutex_init(&mdesc_lock, NULL, MUTEX_DRIVER, NULL); 2311ae08745Sheppo mdesc_attached = 1; 2327c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2337c478bd9Sstevel@tonic-gate case DDI_RESUME: 2347c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2357c478bd9Sstevel@tonic-gate default: 2367c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2401ae08745Sheppo /*ARGSUSED*/ 2417c478bd9Sstevel@tonic-gate static int 2427c478bd9Sstevel@tonic-gate mdesc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2437c478bd9Sstevel@tonic-gate { 2447c478bd9Sstevel@tonic-gate switch (cmd) { 2457c478bd9Sstevel@tonic-gate case DDI_DETACH: 2461ae08745Sheppo mutex_destroy(&mdesc_lock); 2471ae08745Sheppo vmem_destroy(mdesc_minor); 2481ae08745Sheppo ddi_remove_minor_node(mdesc_devi, NULL); 2491ae08745Sheppo mdesc_attached = 0; 2507c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 2537c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate default: 2567c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2601ae08745Sheppo static void 2611ae08745Sheppo mdesc_destroy_state(mdesc_state_t *mdsp) 2621ae08745Sheppo { 2631ae08745Sheppo minor_t minor = getminor(mdsp->dev); 2641ae08745Sheppo 2651ae08745Sheppo if (mdsp->flags & MDESC_GOT_HANDLE) 2661ae08745Sheppo (void) md_fini_handle(mdsp->mdesc); 2671ae08745Sheppo 2681ae08745Sheppo cv_destroy(&mdsp->cv); 2691ae08745Sheppo mutex_destroy(&mdsp->lock); 2701ae08745Sheppo ddi_soft_state_free(mdesc_state_head, minor); 2711ae08745Sheppo vmem_free(mdesc_minor, (void *)(uintptr_t)minor, 1); 2721ae08745Sheppo } 2731ae08745Sheppo 2741ae08745Sheppo static mdesc_state_t * 2751ae08745Sheppo mdesc_create_state(dev_t *devp) 2761ae08745Sheppo { 2771ae08745Sheppo major_t major; 2781ae08745Sheppo minor_t minor; 2791ae08745Sheppo mdesc_state_t *mdsp; 2801ae08745Sheppo 2811ae08745Sheppo minor = (minor_t)(uintptr_t)vmem_alloc(mdesc_minor, 1, 2821ae08745Sheppo VM_BESTFIT | VM_SLEEP); 2831ae08745Sheppo 2841ae08745Sheppo if (ddi_soft_state_zalloc(mdesc_state_head, minor) != 2851ae08745Sheppo DDI_SUCCESS) { 2861ae08745Sheppo cmn_err(CE_WARN, "%s@%d: Unable to allocate state", 2871ae08745Sheppo MDESC_NAME, minor); 2881ae08745Sheppo vmem_free(mdesc_minor, (void *)(uintptr_t)minor, 1); 2891ae08745Sheppo return (NULL); 2901ae08745Sheppo } 2911ae08745Sheppo 2921ae08745Sheppo mdsp = ddi_get_soft_state(mdesc_state_head, minor); 2931ae08745Sheppo 2941ae08745Sheppo if (devp != NULL) { 2951ae08745Sheppo major = getemajor(*devp); 2961ae08745Sheppo } else { 2971ae08745Sheppo major = ddi_driver_major(mdesc_devi); 2981ae08745Sheppo } 2991ae08745Sheppo 3001ae08745Sheppo mdsp->dev = makedevice(major, minor); 3011ae08745Sheppo 3021ae08745Sheppo if (devp != NULL) 3031ae08745Sheppo *devp = mdsp->dev; 3041ae08745Sheppo 3051ae08745Sheppo mdsp->instance = minor; 3061ae08745Sheppo 3071ae08745Sheppo mutex_init(&mdsp->lock, NULL, MUTEX_DRIVER, NULL); 3081ae08745Sheppo 3091ae08745Sheppo cv_init(&mdsp->cv, NULL, CV_DRIVER, NULL); 3101ae08745Sheppo 3111ae08745Sheppo mdsp->mdesc = md_get_handle(); 3121ae08745Sheppo 3131ae08745Sheppo if (mdsp->mdesc == NULL) { 3141ae08745Sheppo mdesc_destroy_state(mdsp); 3151ae08745Sheppo return (NULL); 3161ae08745Sheppo } 3171ae08745Sheppo mdsp->flags |= MDESC_GOT_HANDLE; 3181ae08745Sheppo 3191ae08745Sheppo mdsp->mdesc_len = md_get_bin_size(mdsp->mdesc); 3201ae08745Sheppo 3211ae08745Sheppo if (mdsp->mdesc_len == 0) { 3221ae08745Sheppo mdesc_destroy_state(mdsp); 3231ae08745Sheppo mdsp = NULL; 3241ae08745Sheppo } 3251ae08745Sheppo 3261ae08745Sheppo return (mdsp); 3271ae08745Sheppo } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3317c478bd9Sstevel@tonic-gate static int 3327c478bd9Sstevel@tonic-gate mdesc_open(dev_t *devp, int flag, int otyp, cred_t *credp) 3337c478bd9Sstevel@tonic-gate { 3347c478bd9Sstevel@tonic-gate struct mdesc_state *mdsp; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 3377c478bd9Sstevel@tonic-gate return (EINVAL); 3381ae08745Sheppo if (!mdesc_attached) 3391ae08745Sheppo return (ENXIO); 3401ae08745Sheppo 3411ae08745Sheppo mutex_enter(&mdesc_lock); 3421ae08745Sheppo 3431ae08745Sheppo if (mdesc_opens >= mdesc_max_opens) { 3441ae08745Sheppo mutex_exit(&mdesc_lock); 3451ae08745Sheppo return (ENXIO); 3461ae08745Sheppo } 3471ae08745Sheppo 3481ae08745Sheppo mdsp = mdesc_create_state(devp); 3491ae08745Sheppo 3501ae08745Sheppo if (mdsp == NULL) { 3511ae08745Sheppo mutex_exit(&mdesc_lock); 3521ae08745Sheppo return (ENXIO); 3531ae08745Sheppo } 3541ae08745Sheppo 3551ae08745Sheppo mdesc_opens++; 3561ae08745Sheppo 3571ae08745Sheppo mutex_exit(&mdesc_lock); 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate return (0); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3637c478bd9Sstevel@tonic-gate static int 3647c478bd9Sstevel@tonic-gate mdesc_close(dev_t dev, int flag, int otyp, cred_t *credp) 3657c478bd9Sstevel@tonic-gate { 3667c478bd9Sstevel@tonic-gate struct mdesc_state *mdsp; 3677c478bd9Sstevel@tonic-gate int instance = getminor(dev); 3687c478bd9Sstevel@tonic-gate 3691ae08745Sheppo if (otyp != OTYP_CHR) 3701ae08745Sheppo return (EINVAL); 3711ae08745Sheppo 3721ae08745Sheppo mutex_enter(&mdesc_lock); 3731ae08745Sheppo if (mdesc_opens == 0) { 3741ae08745Sheppo mutex_exit(&mdesc_lock); 3751ae08745Sheppo return (0); 3761ae08745Sheppo } 3771ae08745Sheppo mutex_exit(&mdesc_lock); 3781ae08745Sheppo 3797c478bd9Sstevel@tonic-gate if ((mdsp = ddi_get_soft_state(mdesc_state_head, instance)) == NULL) 3807c478bd9Sstevel@tonic-gate return (ENXIO); 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate ASSERT(mdsp->instance == instance); 3837c478bd9Sstevel@tonic-gate 3841ae08745Sheppo mdesc_destroy_state(mdsp); 3851ae08745Sheppo mutex_enter(&mdesc_lock); 3861ae08745Sheppo mdesc_opens--; 3871ae08745Sheppo mutex_exit(&mdesc_lock); 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate return (0); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3967c478bd9Sstevel@tonic-gate static int 3977c478bd9Sstevel@tonic-gate mdesc_read(dev_t dev, struct uio *uiop, cred_t *credp) 3987c478bd9Sstevel@tonic-gate { 3997c478bd9Sstevel@tonic-gate return (mdesc_rw(dev, uiop, UIO_READ)); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4067c478bd9Sstevel@tonic-gate static int 4077c478bd9Sstevel@tonic-gate mdesc_write(dev_t dev, struct uio *uiop, cred_t *credp) 4087c478bd9Sstevel@tonic-gate { 4097c478bd9Sstevel@tonic-gate return (ENXIO); /* This driver version does not allow updates */ 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate static int 4167c478bd9Sstevel@tonic-gate mdesc_rw(dev_t dev, struct uio *uiop, enum uio_rw rw) 4177c478bd9Sstevel@tonic-gate { 4187c478bd9Sstevel@tonic-gate struct mdesc_state *mdsp; 4197c478bd9Sstevel@tonic-gate int instance = getminor(dev); 4207c478bd9Sstevel@tonic-gate size_t len; 4217c478bd9Sstevel@tonic-gate int retval; 4221ae08745Sheppo caddr_t buf; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate len = uiop->uio_resid; 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate if ((mdsp = ddi_get_soft_state(mdesc_state_head, instance)) == NULL) 4277c478bd9Sstevel@tonic-gate return (ENXIO); 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate ASSERT(mdsp->instance == instance); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate if (len == 0) 4327c478bd9Sstevel@tonic-gate return (0); 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate mutex_enter(&mdsp->lock); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate while (mdsp->flags & MDESC_BUSY) { 4377c478bd9Sstevel@tonic-gate if (cv_wait_sig(&mdsp->cv, &mdsp->lock) == 0) { 4387c478bd9Sstevel@tonic-gate mutex_exit(&mdsp->lock); 4397c478bd9Sstevel@tonic-gate return (EINTR); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate if (uiop->uio_offset < 0 || uiop->uio_offset > mdsp->mdesc_len) { 4447c478bd9Sstevel@tonic-gate mutex_exit(&mdsp->lock); 4457c478bd9Sstevel@tonic-gate return (EINVAL); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate if (len > (mdsp->mdesc_len - uiop->uio_offset)) 4497c478bd9Sstevel@tonic-gate len = mdsp->mdesc_len - uiop->uio_offset; 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate /* already checked that offset<mdesc_len above */ 4527c478bd9Sstevel@tonic-gate if (len == 0) { 4537c478bd9Sstevel@tonic-gate mutex_exit(&mdsp->lock); 4547c478bd9Sstevel@tonic-gate return (rw == UIO_WRITE ? ENOSPC : 0); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate mdsp->flags |= MDESC_BUSY; 4587c478bd9Sstevel@tonic-gate mutex_exit(&mdsp->lock); 4597c478bd9Sstevel@tonic-gate 4601ae08745Sheppo buf = md_get_md_raw(mdsp->mdesc); 4611ae08745Sheppo if (buf == NULL) 4621ae08745Sheppo return (ENXIO); 4631ae08745Sheppo 4641ae08745Sheppo retval = uiomove((void *)(buf + uiop->uio_offset), 4657c478bd9Sstevel@tonic-gate len, rw, uiop); 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate mutex_enter(&mdsp->lock); 4687c478bd9Sstevel@tonic-gate mdsp->flags &= ~MDESC_BUSY; 4697c478bd9Sstevel@tonic-gate cv_broadcast(&mdsp->cv); 4707c478bd9Sstevel@tonic-gate mutex_exit(&mdsp->lock); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate return (retval); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4797c478bd9Sstevel@tonic-gate static int 4807c478bd9Sstevel@tonic-gate mdesc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 4817c478bd9Sstevel@tonic-gate int *rvalp) 4827c478bd9Sstevel@tonic-gate { 4837c478bd9Sstevel@tonic-gate struct mdesc_state *mdsp; 4847c478bd9Sstevel@tonic-gate int instance = getminor(dev); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if ((mdsp = ddi_get_soft_state(mdesc_state_head, instance)) == NULL) 4877c478bd9Sstevel@tonic-gate return (ENXIO); 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate ASSERT(mdsp->instance == instance); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate switch (cmd) { 4927c478bd9Sstevel@tonic-gate case MDESCIOCGSZ: { 4937c478bd9Sstevel@tonic-gate /* 4947c478bd9Sstevel@tonic-gate * We are not guaranteed that ddi_copyout(9F) will read 4957c478bd9Sstevel@tonic-gate * atomically anything larger than a byte. Therefore we 4967c478bd9Sstevel@tonic-gate * must duplicate the size before copying it out to the user. 4977c478bd9Sstevel@tonic-gate */ 4987c478bd9Sstevel@tonic-gate size_t sz = mdsp->mdesc_len; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate if (!(mode & FREAD)) 5017c478bd9Sstevel@tonic-gate return (EACCES); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 5047c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 5057c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: { 5067c478bd9Sstevel@tonic-gate size32_t sz32 = (size32_t)sz; 5077c478bd9Sstevel@tonic-gate if (ddi_copyout(&sz32, (void *)arg, sizeof (size32_t), 5087c478bd9Sstevel@tonic-gate mode) != 0) 5097c478bd9Sstevel@tonic-gate return (EFAULT); 5107c478bd9Sstevel@tonic-gate return (0); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 5137c478bd9Sstevel@tonic-gate if (ddi_copyout(&sz, (void *)arg, sizeof (size_t), 5147c478bd9Sstevel@tonic-gate mode) != 0) 5157c478bd9Sstevel@tonic-gate return (EFAULT); 5167c478bd9Sstevel@tonic-gate return (0); 5177c478bd9Sstevel@tonic-gate default: 5187c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 5197c478bd9Sstevel@tonic-gate "mdesc: Invalid data model %d in ioctl\n", 5207c478bd9Sstevel@tonic-gate ddi_model_convert_from(mode & FMODELS)); 5217c478bd9Sstevel@tonic-gate return (ENOTSUP); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 5247c478bd9Sstevel@tonic-gate if (ddi_copyout(&sz, (void *)arg, sizeof (size_t), mode) != 0) 5257c478bd9Sstevel@tonic-gate return (EFAULT); 5267c478bd9Sstevel@tonic-gate return (0); 5277c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate default: 5317c478bd9Sstevel@tonic-gate return (ENOTTY); 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate } 534