13f7d54a6SGarrett D'Amore /* 23f7d54a6SGarrett D'Amore * CDDL HEADER START 33f7d54a6SGarrett D'Amore * 43f7d54a6SGarrett D'Amore * The contents of this file are subject to the terms of the 53f7d54a6SGarrett D'Amore * Common Development and Distribution License (the "License"). 63f7d54a6SGarrett D'Amore * You may not use this file except in compliance with the License. 73f7d54a6SGarrett D'Amore * 83f7d54a6SGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93f7d54a6SGarrett D'Amore * or http://www.opensolaris.org/os/licensing. 103f7d54a6SGarrett D'Amore * See the License for the specific language governing permissions 113f7d54a6SGarrett D'Amore * and limitations under the License. 123f7d54a6SGarrett D'Amore * 133f7d54a6SGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each 143f7d54a6SGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153f7d54a6SGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the 163f7d54a6SGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying 173f7d54a6SGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner] 183f7d54a6SGarrett D'Amore * 193f7d54a6SGarrett D'Amore * CDDL HEADER END 203f7d54a6SGarrett D'Amore */ 213f7d54a6SGarrett D'Amore /* 223f7d54a6SGarrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23cd21e7c5SGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 24679ac156SAlexey Zaytsev * Copyright 2012 Alexey Zaytsev <alexey.zaytsev@gmail.com> All rights reserved. 251a3a6deeSHans Rosenfeld * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 2610624986SYouzhong Yang * Copyright 2017 The MathWorks, Inc. All rights reserved. 2786e3bca6SGarrett D'Amore */ 2886e3bca6SGarrett D'Amore 293f7d54a6SGarrett D'Amore #include <sys/types.h> 303f7d54a6SGarrett D'Amore #include <sys/ksynch.h> 313f7d54a6SGarrett D'Amore #include <sys/kmem.h> 323f7d54a6SGarrett D'Amore #include <sys/file.h> 333f7d54a6SGarrett D'Amore #include <sys/errno.h> 343f7d54a6SGarrett D'Amore #include <sys/open.h> 353f7d54a6SGarrett D'Amore #include <sys/buf.h> 363f7d54a6SGarrett D'Amore #include <sys/uio.h> 373f7d54a6SGarrett D'Amore #include <sys/aio_req.h> 383f7d54a6SGarrett D'Amore #include <sys/cred.h> 393f7d54a6SGarrett D'Amore #include <sys/modctl.h> 403f7d54a6SGarrett D'Amore #include <sys/cmlb.h> 413f7d54a6SGarrett D'Amore #include <sys/conf.h> 423f7d54a6SGarrett D'Amore #include <sys/devops.h> 433f7d54a6SGarrett D'Amore #include <sys/list.h> 443f7d54a6SGarrett D'Amore #include <sys/sysmacros.h> 453f7d54a6SGarrett D'Amore #include <sys/dkio.h> 463f7d54a6SGarrett D'Amore #include <sys/vtoc.h> 473f7d54a6SGarrett D'Amore #include <sys/scsi/scsi.h> /* for DTYPE_DIRECT */ 483f7d54a6SGarrett D'Amore #include <sys/kstat.h> 493f7d54a6SGarrett D'Amore #include <sys/fs/dv_node.h> 503f7d54a6SGarrett D'Amore #include <sys/ddi.h> 513f7d54a6SGarrett D'Amore #include <sys/sunddi.h> 523f7d54a6SGarrett D'Amore #include <sys/note.h> 533f7d54a6SGarrett D'Amore #include <sys/blkdev.h> 54510a6847SHans Rosenfeld #include <sys/scsi/impl/inquiry.h> 553f7d54a6SGarrett D'Amore 563f7d54a6SGarrett D'Amore #define BD_MAXPART 64 573f7d54a6SGarrett D'Amore #define BDINST(dev) (getminor(dev) / BD_MAXPART) 583f7d54a6SGarrett D'Amore #define BDPART(dev) (getminor(dev) % BD_MAXPART) 593f7d54a6SGarrett D'Amore 603f7d54a6SGarrett D'Amore typedef struct bd bd_t; 613f7d54a6SGarrett D'Amore typedef struct bd_xfer_impl bd_xfer_impl_t; 623f7d54a6SGarrett D'Amore 633f7d54a6SGarrett D'Amore struct bd { 643f7d54a6SGarrett D'Amore void *d_private; 653f7d54a6SGarrett D'Amore dev_info_t *d_dip; 663f7d54a6SGarrett D'Amore kmutex_t d_ocmutex; 673f7d54a6SGarrett D'Amore kmutex_t d_iomutex; 68bef9e21aSHans Rosenfeld kmutex_t *d_errmutex; 693f7d54a6SGarrett D'Amore kmutex_t d_statemutex; 703f7d54a6SGarrett D'Amore kcondvar_t d_statecv; 713f7d54a6SGarrett D'Amore enum dkio_state d_state; 723f7d54a6SGarrett D'Amore cmlb_handle_t d_cmlbh; 733f7d54a6SGarrett D'Amore unsigned d_open_lyr[BD_MAXPART]; /* open count */ 743f7d54a6SGarrett D'Amore uint64_t d_open_excl; /* bit mask indexed by partition */ 753f7d54a6SGarrett D'Amore uint64_t d_open_reg[OTYPCNT]; /* bit mask */ 763f7d54a6SGarrett D'Amore 773f7d54a6SGarrett D'Amore uint32_t d_qsize; 783f7d54a6SGarrett D'Amore uint32_t d_qactive; 793f7d54a6SGarrett D'Amore uint32_t d_maxxfer; 803f7d54a6SGarrett D'Amore uint32_t d_blkshift; 8132ce6b81SHans Rosenfeld uint32_t d_pblkshift; 823f7d54a6SGarrett D'Amore uint64_t d_numblks; 833f7d54a6SGarrett D'Amore ddi_devid_t d_devid; 843f7d54a6SGarrett D'Amore 853f7d54a6SGarrett D'Amore kmem_cache_t *d_cache; 863f7d54a6SGarrett D'Amore list_t d_runq; 873f7d54a6SGarrett D'Amore list_t d_waitq; 883f7d54a6SGarrett D'Amore kstat_t *d_ksp; 893f7d54a6SGarrett D'Amore kstat_io_t *d_kiop; 90bef9e21aSHans Rosenfeld kstat_t *d_errstats; 91bef9e21aSHans Rosenfeld struct bd_errstats *d_kerr; 923f7d54a6SGarrett D'Amore 933f7d54a6SGarrett D'Amore boolean_t d_rdonly; 9459d8f100SGarrett D'Amore boolean_t d_ssd; 953f7d54a6SGarrett D'Amore boolean_t d_removable; 963f7d54a6SGarrett D'Amore boolean_t d_hotpluggable; 973f7d54a6SGarrett D'Amore boolean_t d_use_dma; 983f7d54a6SGarrett D'Amore 993f7d54a6SGarrett D'Amore ddi_dma_attr_t d_dma; 1003f7d54a6SGarrett D'Amore bd_ops_t d_ops; 1013f7d54a6SGarrett D'Amore bd_handle_t d_handle; 1023f7d54a6SGarrett D'Amore }; 1033f7d54a6SGarrett D'Amore 1043f7d54a6SGarrett D'Amore struct bd_handle { 1053f7d54a6SGarrett D'Amore bd_ops_t h_ops; 1063f7d54a6SGarrett D'Amore ddi_dma_attr_t *h_dma; 1073f7d54a6SGarrett D'Amore dev_info_t *h_parent; 1083f7d54a6SGarrett D'Amore dev_info_t *h_child; 1093f7d54a6SGarrett D'Amore void *h_private; 1103f7d54a6SGarrett D'Amore bd_t *h_bd; 1113f7d54a6SGarrett D'Amore char *h_name; 112fa27e351SHans Rosenfeld char h_addr[30]; /* enough for w%0.16x,%X */ 1133f7d54a6SGarrett D'Amore }; 1143f7d54a6SGarrett D'Amore 1153f7d54a6SGarrett D'Amore struct bd_xfer_impl { 1163f7d54a6SGarrett D'Amore bd_xfer_t i_public; 1173f7d54a6SGarrett D'Amore list_node_t i_linkage; 1183f7d54a6SGarrett D'Amore bd_t *i_bd; 1193f7d54a6SGarrett D'Amore buf_t *i_bp; 1203f7d54a6SGarrett D'Amore uint_t i_num_win; 1213f7d54a6SGarrett D'Amore uint_t i_cur_win; 1223f7d54a6SGarrett D'Amore off_t i_offset; 1233f7d54a6SGarrett D'Amore int (*i_func)(void *, bd_xfer_t *); 1243f7d54a6SGarrett D'Amore uint32_t i_blkshift; 1253f7d54a6SGarrett D'Amore size_t i_len; 1263f7d54a6SGarrett D'Amore size_t i_resid; 1273f7d54a6SGarrett D'Amore }; 1283f7d54a6SGarrett D'Amore 1293f7d54a6SGarrett D'Amore #define i_dmah i_public.x_dmah 1303f7d54a6SGarrett D'Amore #define i_dmac i_public.x_dmac 1313f7d54a6SGarrett D'Amore #define i_ndmac i_public.x_ndmac 1323f7d54a6SGarrett D'Amore #define i_kaddr i_public.x_kaddr 1333f7d54a6SGarrett D'Amore #define i_nblks i_public.x_nblks 1343f7d54a6SGarrett D'Amore #define i_blkno i_public.x_blkno 13586e3bca6SGarrett D'Amore #define i_flags i_public.x_flags 1363f7d54a6SGarrett D'Amore 1373f7d54a6SGarrett D'Amore 1383f7d54a6SGarrett D'Amore /* 1393f7d54a6SGarrett D'Amore * Private prototypes. 1403f7d54a6SGarrett D'Amore */ 1413f7d54a6SGarrett D'Amore 142510a6847SHans Rosenfeld static void bd_prop_update_inqstring(dev_info_t *, char *, char *, size_t); 143510a6847SHans Rosenfeld static void bd_create_inquiry_props(dev_info_t *, bd_drive_t *); 144bef9e21aSHans Rosenfeld static void bd_create_errstats(bd_t *, int, bd_drive_t *); 145bef9e21aSHans Rosenfeld static void bd_errstats_setstr(kstat_named_t *, char *, size_t, char *); 146bef9e21aSHans Rosenfeld static void bd_init_errstats(bd_t *, bd_drive_t *); 147510a6847SHans Rosenfeld 1483f7d54a6SGarrett D'Amore static int bd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 1493f7d54a6SGarrett D'Amore static int bd_attach(dev_info_t *, ddi_attach_cmd_t); 1503f7d54a6SGarrett D'Amore static int bd_detach(dev_info_t *, ddi_detach_cmd_t); 1513f7d54a6SGarrett D'Amore 1523f7d54a6SGarrett D'Amore static int bd_open(dev_t *, int, int, cred_t *); 1533f7d54a6SGarrett D'Amore static int bd_close(dev_t, int, int, cred_t *); 1543f7d54a6SGarrett D'Amore static int bd_strategy(struct buf *); 1553f7d54a6SGarrett D'Amore static int bd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 15686e3bca6SGarrett D'Amore static int bd_dump(dev_t, caddr_t, daddr_t, int); 1573f7d54a6SGarrett D'Amore static int bd_read(dev_t, struct uio *, cred_t *); 1583f7d54a6SGarrett D'Amore static int bd_write(dev_t, struct uio *, cred_t *); 1593f7d54a6SGarrett D'Amore static int bd_aread(dev_t, struct aio_req *, cred_t *); 1603f7d54a6SGarrett D'Amore static int bd_awrite(dev_t, struct aio_req *, cred_t *); 1613f7d54a6SGarrett D'Amore static int bd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, 1623f7d54a6SGarrett D'Amore caddr_t, int *); 1633f7d54a6SGarrett D'Amore 1643f7d54a6SGarrett D'Amore static int bd_tg_rdwr(dev_info_t *, uchar_t, void *, diskaddr_t, size_t, 1653f7d54a6SGarrett D'Amore void *); 1663f7d54a6SGarrett D'Amore static int bd_tg_getinfo(dev_info_t *, int, void *, void *); 1673f7d54a6SGarrett D'Amore static int bd_xfer_ctor(void *, void *, int); 1683f7d54a6SGarrett D'Amore static void bd_xfer_dtor(void *, void *); 1693f7d54a6SGarrett D'Amore static void bd_sched(bd_t *); 1703f7d54a6SGarrett D'Amore static void bd_submit(bd_t *, bd_xfer_impl_t *); 1713f7d54a6SGarrett D'Amore static void bd_runq_exit(bd_xfer_impl_t *, int); 1723f7d54a6SGarrett D'Amore static void bd_update_state(bd_t *); 1733f7d54a6SGarrett D'Amore static int bd_check_state(bd_t *, enum dkio_state *); 1743f7d54a6SGarrett D'Amore static int bd_flush_write_cache(bd_t *, struct dk_callback *); 17510624986SYouzhong Yang static int bd_check_uio(dev_t, struct uio *); 1763f7d54a6SGarrett D'Amore 1773f7d54a6SGarrett D'Amore struct cmlb_tg_ops bd_tg_ops = { 1783f7d54a6SGarrett D'Amore TG_DK_OPS_VERSION_1, 1793f7d54a6SGarrett D'Amore bd_tg_rdwr, 1803f7d54a6SGarrett D'Amore bd_tg_getinfo, 1813f7d54a6SGarrett D'Amore }; 1823f7d54a6SGarrett D'Amore 1833f7d54a6SGarrett D'Amore static struct cb_ops bd_cb_ops = { 1843f7d54a6SGarrett D'Amore bd_open, /* open */ 1853f7d54a6SGarrett D'Amore bd_close, /* close */ 1863f7d54a6SGarrett D'Amore bd_strategy, /* strategy */ 1873f7d54a6SGarrett D'Amore nodev, /* print */ 18886e3bca6SGarrett D'Amore bd_dump, /* dump */ 1893f7d54a6SGarrett D'Amore bd_read, /* read */ 1903f7d54a6SGarrett D'Amore bd_write, /* write */ 1913f7d54a6SGarrett D'Amore bd_ioctl, /* ioctl */ 1923f7d54a6SGarrett D'Amore nodev, /* devmap */ 1933f7d54a6SGarrett D'Amore nodev, /* mmap */ 1943f7d54a6SGarrett D'Amore nodev, /* segmap */ 1953f7d54a6SGarrett D'Amore nochpoll, /* poll */ 1963f7d54a6SGarrett D'Amore bd_prop_op, /* cb_prop_op */ 1973f7d54a6SGarrett D'Amore 0, /* streamtab */ 1983f7d54a6SGarrett D'Amore D_64BIT | D_MP, /* Driver comaptibility flag */ 1993f7d54a6SGarrett D'Amore CB_REV, /* cb_rev */ 2003f7d54a6SGarrett D'Amore bd_aread, /* async read */ 2013f7d54a6SGarrett D'Amore bd_awrite /* async write */ 2023f7d54a6SGarrett D'Amore }; 2033f7d54a6SGarrett D'Amore 2043f7d54a6SGarrett D'Amore struct dev_ops bd_dev_ops = { 2053f7d54a6SGarrett D'Amore DEVO_REV, /* devo_rev, */ 2063f7d54a6SGarrett D'Amore 0, /* refcnt */ 2073f7d54a6SGarrett D'Amore bd_getinfo, /* getinfo */ 2083f7d54a6SGarrett D'Amore nulldev, /* identify */ 2093f7d54a6SGarrett D'Amore nulldev, /* probe */ 2103f7d54a6SGarrett D'Amore bd_attach, /* attach */ 2113f7d54a6SGarrett D'Amore bd_detach, /* detach */ 2123f7d54a6SGarrett D'Amore nodev, /* reset */ 2133f7d54a6SGarrett D'Amore &bd_cb_ops, /* driver operations */ 2143f7d54a6SGarrett D'Amore NULL, /* bus operations */ 2153f7d54a6SGarrett D'Amore NULL, /* power */ 2163f7d54a6SGarrett D'Amore ddi_quiesce_not_needed, /* quiesce */ 2173f7d54a6SGarrett D'Amore }; 2183f7d54a6SGarrett D'Amore 2193f7d54a6SGarrett D'Amore static struct modldrv modldrv = { 2203f7d54a6SGarrett D'Amore &mod_driverops, 2213f7d54a6SGarrett D'Amore "Generic Block Device", 2223f7d54a6SGarrett D'Amore &bd_dev_ops, 2233f7d54a6SGarrett D'Amore }; 2243f7d54a6SGarrett D'Amore 2253f7d54a6SGarrett D'Amore static struct modlinkage modlinkage = { 2263f7d54a6SGarrett D'Amore MODREV_1, { &modldrv, NULL } 2273f7d54a6SGarrett D'Amore }; 2283f7d54a6SGarrett D'Amore 2293f7d54a6SGarrett D'Amore static void *bd_state; 2303f7d54a6SGarrett D'Amore static krwlock_t bd_lock; 2313f7d54a6SGarrett D'Amore 2323f7d54a6SGarrett D'Amore int 2333f7d54a6SGarrett D'Amore _init(void) 2343f7d54a6SGarrett D'Amore { 2353f7d54a6SGarrett D'Amore int rv; 2363f7d54a6SGarrett D'Amore 2373f7d54a6SGarrett D'Amore rv = ddi_soft_state_init(&bd_state, sizeof (struct bd), 2); 2383f7d54a6SGarrett D'Amore if (rv != DDI_SUCCESS) { 2393f7d54a6SGarrett D'Amore return (rv); 2403f7d54a6SGarrett D'Amore } 2413f7d54a6SGarrett D'Amore rw_init(&bd_lock, NULL, RW_DRIVER, NULL); 2423f7d54a6SGarrett D'Amore rv = mod_install(&modlinkage); 2433f7d54a6SGarrett D'Amore if (rv != DDI_SUCCESS) { 2443f7d54a6SGarrett D'Amore rw_destroy(&bd_lock); 2453f7d54a6SGarrett D'Amore ddi_soft_state_fini(&bd_state); 2463f7d54a6SGarrett D'Amore } 2473f7d54a6SGarrett D'Amore return (rv); 2483f7d54a6SGarrett D'Amore } 2493f7d54a6SGarrett D'Amore 2503f7d54a6SGarrett D'Amore int 2513f7d54a6SGarrett D'Amore _fini(void) 2523f7d54a6SGarrett D'Amore { 2533f7d54a6SGarrett D'Amore int rv; 2543f7d54a6SGarrett D'Amore 2553f7d54a6SGarrett D'Amore rv = mod_remove(&modlinkage); 2563f7d54a6SGarrett D'Amore if (rv == DDI_SUCCESS) { 2573f7d54a6SGarrett D'Amore rw_destroy(&bd_lock); 2583f7d54a6SGarrett D'Amore ddi_soft_state_fini(&bd_state); 2593f7d54a6SGarrett D'Amore } 2603f7d54a6SGarrett D'Amore return (rv); 2613f7d54a6SGarrett D'Amore } 2623f7d54a6SGarrett D'Amore 2633f7d54a6SGarrett D'Amore int 2643f7d54a6SGarrett D'Amore _info(struct modinfo *modinfop) 2653f7d54a6SGarrett D'Amore { 2663f7d54a6SGarrett D'Amore return (mod_info(&modlinkage, modinfop)); 2673f7d54a6SGarrett D'Amore } 2683f7d54a6SGarrett D'Amore 2693f7d54a6SGarrett D'Amore static int 2703f7d54a6SGarrett D'Amore bd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 2713f7d54a6SGarrett D'Amore { 2723f7d54a6SGarrett D'Amore bd_t *bd; 2733f7d54a6SGarrett D'Amore minor_t inst; 2743f7d54a6SGarrett D'Amore 2753f7d54a6SGarrett D'Amore _NOTE(ARGUNUSED(dip)); 2763f7d54a6SGarrett D'Amore 2773f7d54a6SGarrett D'Amore inst = BDINST((dev_t)arg); 2783f7d54a6SGarrett D'Amore 2793f7d54a6SGarrett D'Amore switch (cmd) { 2803f7d54a6SGarrett D'Amore case DDI_INFO_DEVT2DEVINFO: 2813f7d54a6SGarrett D'Amore bd = ddi_get_soft_state(bd_state, inst); 2823f7d54a6SGarrett D'Amore if (bd == NULL) { 2833f7d54a6SGarrett D'Amore return (DDI_FAILURE); 2843f7d54a6SGarrett D'Amore } 2853f7d54a6SGarrett D'Amore *resultp = (void *)bd->d_dip; 2863f7d54a6SGarrett D'Amore break; 2873f7d54a6SGarrett D'Amore 2883f7d54a6SGarrett D'Amore case DDI_INFO_DEVT2INSTANCE: 2893f7d54a6SGarrett D'Amore *resultp = (void *)(intptr_t)inst; 2903f7d54a6SGarrett D'Amore break; 2913f7d54a6SGarrett D'Amore 2923f7d54a6SGarrett D'Amore default: 2933f7d54a6SGarrett D'Amore return (DDI_FAILURE); 2943f7d54a6SGarrett D'Amore } 2953f7d54a6SGarrett D'Amore return (DDI_SUCCESS); 2963f7d54a6SGarrett D'Amore } 2973f7d54a6SGarrett D'Amore 298510a6847SHans Rosenfeld static void 299510a6847SHans Rosenfeld bd_prop_update_inqstring(dev_info_t *dip, char *name, char *data, size_t len) 300510a6847SHans Rosenfeld { 301510a6847SHans Rosenfeld int ilen; 302510a6847SHans Rosenfeld char *data_string; 303510a6847SHans Rosenfeld 304510a6847SHans Rosenfeld ilen = scsi_ascii_inquiry_len(data, len); 305510a6847SHans Rosenfeld ASSERT3U(ilen, <=, len); 306510a6847SHans Rosenfeld if (ilen <= 0) 307510a6847SHans Rosenfeld return; 308510a6847SHans Rosenfeld /* ensure null termination */ 309510a6847SHans Rosenfeld data_string = kmem_zalloc(ilen + 1, KM_SLEEP); 310510a6847SHans Rosenfeld bcopy(data, data_string, ilen); 311510a6847SHans Rosenfeld (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, name, data_string); 312510a6847SHans Rosenfeld kmem_free(data_string, ilen + 1); 313510a6847SHans Rosenfeld } 314510a6847SHans Rosenfeld 315510a6847SHans Rosenfeld static void 316510a6847SHans Rosenfeld bd_create_inquiry_props(dev_info_t *dip, bd_drive_t *drive) 317510a6847SHans Rosenfeld { 318510a6847SHans Rosenfeld if (drive->d_vendor_len > 0) 319510a6847SHans Rosenfeld bd_prop_update_inqstring(dip, INQUIRY_VENDOR_ID, 320510a6847SHans Rosenfeld drive->d_vendor, drive->d_vendor_len); 321510a6847SHans Rosenfeld 322510a6847SHans Rosenfeld if (drive->d_product_len > 0) 323510a6847SHans Rosenfeld bd_prop_update_inqstring(dip, INQUIRY_PRODUCT_ID, 324510a6847SHans Rosenfeld drive->d_product, drive->d_product_len); 325510a6847SHans Rosenfeld 326510a6847SHans Rosenfeld if (drive->d_serial_len > 0) 327510a6847SHans Rosenfeld bd_prop_update_inqstring(dip, INQUIRY_SERIAL_NO, 328510a6847SHans Rosenfeld drive->d_serial, drive->d_serial_len); 329510a6847SHans Rosenfeld 330510a6847SHans Rosenfeld if (drive->d_revision_len > 0) 331510a6847SHans Rosenfeld bd_prop_update_inqstring(dip, INQUIRY_REVISION_ID, 332510a6847SHans Rosenfeld drive->d_revision, drive->d_revision_len); 333510a6847SHans Rosenfeld } 334510a6847SHans Rosenfeld 335bef9e21aSHans Rosenfeld static void 336bef9e21aSHans Rosenfeld bd_create_errstats(bd_t *bd, int inst, bd_drive_t *drive) 337bef9e21aSHans Rosenfeld { 338bef9e21aSHans Rosenfeld char ks_module[KSTAT_STRLEN]; 339bef9e21aSHans Rosenfeld char ks_name[KSTAT_STRLEN]; 340bef9e21aSHans Rosenfeld int ndata = sizeof (struct bd_errstats) / sizeof (kstat_named_t); 341bef9e21aSHans Rosenfeld 342bef9e21aSHans Rosenfeld if (bd->d_errstats != NULL) 343bef9e21aSHans Rosenfeld return; 344bef9e21aSHans Rosenfeld 345bef9e21aSHans Rosenfeld (void) snprintf(ks_module, sizeof (ks_module), "%serr", 346bef9e21aSHans Rosenfeld ddi_driver_name(bd->d_dip)); 347bef9e21aSHans Rosenfeld (void) snprintf(ks_name, sizeof (ks_name), "%s%d,err", 348bef9e21aSHans Rosenfeld ddi_driver_name(bd->d_dip), inst); 349bef9e21aSHans Rosenfeld 350bef9e21aSHans Rosenfeld bd->d_errstats = kstat_create(ks_module, inst, ks_name, "device_error", 351bef9e21aSHans Rosenfeld KSTAT_TYPE_NAMED, ndata, KSTAT_FLAG_PERSISTENT); 352bef9e21aSHans Rosenfeld 353bef9e21aSHans Rosenfeld if (bd->d_errstats == NULL) { 354bef9e21aSHans Rosenfeld /* 355bef9e21aSHans Rosenfeld * Even if we cannot create the kstat, we create a 356bef9e21aSHans Rosenfeld * scratch kstat. The reason for this is to ensure 357bef9e21aSHans Rosenfeld * that we can update the kstat all of the time, 358bef9e21aSHans Rosenfeld * without adding an extra branch instruction. 359bef9e21aSHans Rosenfeld */ 360bef9e21aSHans Rosenfeld bd->d_kerr = kmem_zalloc(sizeof (struct bd_errstats), 361bef9e21aSHans Rosenfeld KM_SLEEP); 362bef9e21aSHans Rosenfeld bd->d_errmutex = kmem_zalloc(sizeof (kmutex_t), KM_SLEEP); 363bef9e21aSHans Rosenfeld mutex_init(bd->d_errmutex, NULL, MUTEX_DRIVER, NULL); 364bef9e21aSHans Rosenfeld } else { 365bef9e21aSHans Rosenfeld if (bd->d_errstats->ks_lock == NULL) { 366bef9e21aSHans Rosenfeld bd->d_errstats->ks_lock = kmem_zalloc(sizeof (kmutex_t), 367bef9e21aSHans Rosenfeld KM_SLEEP); 368bef9e21aSHans Rosenfeld mutex_init(bd->d_errstats->ks_lock, NULL, MUTEX_DRIVER, 369bef9e21aSHans Rosenfeld NULL); 370bef9e21aSHans Rosenfeld } 371bef9e21aSHans Rosenfeld 372bef9e21aSHans Rosenfeld bd->d_errmutex = bd->d_errstats->ks_lock; 373bef9e21aSHans Rosenfeld bd->d_kerr = (struct bd_errstats *)bd->d_errstats->ks_data; 374bef9e21aSHans Rosenfeld } 375bef9e21aSHans Rosenfeld 376bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_softerrs, "Soft Errors", 377bef9e21aSHans Rosenfeld KSTAT_DATA_UINT32); 378bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_harderrs, "Hard Errors", 379bef9e21aSHans Rosenfeld KSTAT_DATA_UINT32); 380bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_transerrs, "Transport Errors", 381bef9e21aSHans Rosenfeld KSTAT_DATA_UINT32); 382bef9e21aSHans Rosenfeld 383bef9e21aSHans Rosenfeld if (drive->d_model_len > 0) { 384bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_model, "Model", 385bef9e21aSHans Rosenfeld KSTAT_DATA_STRING); 386bef9e21aSHans Rosenfeld } else { 387bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_vid, "Vendor", 388bef9e21aSHans Rosenfeld KSTAT_DATA_STRING); 389bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_pid, "Product", 390bef9e21aSHans Rosenfeld KSTAT_DATA_STRING); 391bef9e21aSHans Rosenfeld } 392bef9e21aSHans Rosenfeld 393bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_revision, "Revision", 394bef9e21aSHans Rosenfeld KSTAT_DATA_STRING); 395bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_serial, "Serial No", 396bef9e21aSHans Rosenfeld KSTAT_DATA_STRING); 397bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_capacity, "Size", 398bef9e21aSHans Rosenfeld KSTAT_DATA_ULONGLONG); 399bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_rq_media_err, "Media Error", 400bef9e21aSHans Rosenfeld KSTAT_DATA_UINT32); 401bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_rq_ntrdy_err, "Device Not Ready", 402bef9e21aSHans Rosenfeld KSTAT_DATA_UINT32); 403bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_rq_nodev_err, "No Device", 404bef9e21aSHans Rosenfeld KSTAT_DATA_UINT32); 405bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_rq_recov_err, "Recoverable", 406bef9e21aSHans Rosenfeld KSTAT_DATA_UINT32); 407bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_rq_illrq_err, "Illegal Request", 408bef9e21aSHans Rosenfeld KSTAT_DATA_UINT32); 409bef9e21aSHans Rosenfeld kstat_named_init(&bd->d_kerr->bd_rq_pfa_err, 410bef9e21aSHans Rosenfeld "Predictive Failure Analysis", KSTAT_DATA_UINT32); 411bef9e21aSHans Rosenfeld 412bef9e21aSHans Rosenfeld bd->d_errstats->ks_private = bd; 413bef9e21aSHans Rosenfeld 414bef9e21aSHans Rosenfeld kstat_install(bd->d_errstats); 415bef9e21aSHans Rosenfeld } 416bef9e21aSHans Rosenfeld 417bef9e21aSHans Rosenfeld static void 418bef9e21aSHans Rosenfeld bd_errstats_setstr(kstat_named_t *k, char *str, size_t len, char *alt) 419bef9e21aSHans Rosenfeld { 420bef9e21aSHans Rosenfeld char *tmp; 421bef9e21aSHans Rosenfeld 422bef9e21aSHans Rosenfeld if (KSTAT_NAMED_STR_PTR(k) == NULL) { 423bef9e21aSHans Rosenfeld if (len > 0) { 424bef9e21aSHans Rosenfeld tmp = kmem_alloc(len + 1, KM_SLEEP); 4251a3a6deeSHans Rosenfeld (void) strlcpy(tmp, str, len + 1); 426bef9e21aSHans Rosenfeld } else { 427bef9e21aSHans Rosenfeld tmp = alt; 428bef9e21aSHans Rosenfeld } 429bef9e21aSHans Rosenfeld 430bef9e21aSHans Rosenfeld kstat_named_setstr(k, tmp); 431bef9e21aSHans Rosenfeld } 432bef9e21aSHans Rosenfeld } 433bef9e21aSHans Rosenfeld 434bef9e21aSHans Rosenfeld static void 435bef9e21aSHans Rosenfeld bd_init_errstats(bd_t *bd, bd_drive_t *drive) 436bef9e21aSHans Rosenfeld { 437bef9e21aSHans Rosenfeld struct bd_errstats *est = bd->d_kerr; 438bef9e21aSHans Rosenfeld 439bef9e21aSHans Rosenfeld mutex_enter(bd->d_errmutex); 440bef9e21aSHans Rosenfeld 441bef9e21aSHans Rosenfeld if (drive->d_model_len > 0 && 442bef9e21aSHans Rosenfeld KSTAT_NAMED_STR_PTR(&est->bd_model) == NULL) { 443bef9e21aSHans Rosenfeld bd_errstats_setstr(&est->bd_model, drive->d_model, 444bef9e21aSHans Rosenfeld drive->d_model_len, NULL); 445bef9e21aSHans Rosenfeld } else { 446bef9e21aSHans Rosenfeld bd_errstats_setstr(&est->bd_vid, drive->d_vendor, 447bef9e21aSHans Rosenfeld drive->d_vendor_len, "Unknown "); 448bef9e21aSHans Rosenfeld bd_errstats_setstr(&est->bd_pid, drive->d_product, 449bef9e21aSHans Rosenfeld drive->d_product_len, "Unknown "); 450bef9e21aSHans Rosenfeld } 451bef9e21aSHans Rosenfeld 452bef9e21aSHans Rosenfeld bd_errstats_setstr(&est->bd_revision, drive->d_revision, 453bef9e21aSHans Rosenfeld drive->d_revision_len, "0001"); 454bef9e21aSHans Rosenfeld bd_errstats_setstr(&est->bd_serial, drive->d_serial, 455bef9e21aSHans Rosenfeld drive->d_serial_len, "0 "); 456bef9e21aSHans Rosenfeld 457bef9e21aSHans Rosenfeld mutex_exit(bd->d_errmutex); 458bef9e21aSHans Rosenfeld } 459bef9e21aSHans Rosenfeld 4603f7d54a6SGarrett D'Amore static int 4613f7d54a6SGarrett D'Amore bd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4623f7d54a6SGarrett D'Amore { 4633f7d54a6SGarrett D'Amore int inst; 4643f7d54a6SGarrett D'Amore bd_handle_t hdl; 4653f7d54a6SGarrett D'Amore bd_t *bd; 4663f7d54a6SGarrett D'Amore bd_drive_t drive; 4673f7d54a6SGarrett D'Amore int rv; 4683f7d54a6SGarrett D'Amore char name[16]; 4693f7d54a6SGarrett D'Amore char kcache[32]; 4703f7d54a6SGarrett D'Amore 4713f7d54a6SGarrett D'Amore switch (cmd) { 4723f7d54a6SGarrett D'Amore case DDI_ATTACH: 4733f7d54a6SGarrett D'Amore break; 4743f7d54a6SGarrett D'Amore case DDI_RESUME: 4753f7d54a6SGarrett D'Amore /* We don't do anything native for suspend/resume */ 4763f7d54a6SGarrett D'Amore return (DDI_SUCCESS); 4773f7d54a6SGarrett D'Amore default: 4783f7d54a6SGarrett D'Amore return (DDI_FAILURE); 4793f7d54a6SGarrett D'Amore } 4803f7d54a6SGarrett D'Amore 4813f7d54a6SGarrett D'Amore inst = ddi_get_instance(dip); 4823f7d54a6SGarrett D'Amore hdl = ddi_get_parent_data(dip); 4833f7d54a6SGarrett D'Amore 4843f7d54a6SGarrett D'Amore (void) snprintf(name, sizeof (name), "%s%d", 4853f7d54a6SGarrett D'Amore ddi_driver_name(dip), ddi_get_instance(dip)); 4863f7d54a6SGarrett D'Amore (void) snprintf(kcache, sizeof (kcache), "%s_xfer", name); 4873f7d54a6SGarrett D'Amore 4883f7d54a6SGarrett D'Amore if (hdl == NULL) { 4893f7d54a6SGarrett D'Amore cmn_err(CE_WARN, "%s: missing parent data!", name); 4903f7d54a6SGarrett D'Amore return (DDI_FAILURE); 4913f7d54a6SGarrett D'Amore } 4923f7d54a6SGarrett D'Amore 4933f7d54a6SGarrett D'Amore if (ddi_soft_state_zalloc(bd_state, inst) != DDI_SUCCESS) { 4943f7d54a6SGarrett D'Amore cmn_err(CE_WARN, "%s: unable to zalloc soft state!", name); 4953f7d54a6SGarrett D'Amore return (DDI_FAILURE); 4963f7d54a6SGarrett D'Amore } 4973f7d54a6SGarrett D'Amore bd = ddi_get_soft_state(bd_state, inst); 4983f7d54a6SGarrett D'Amore 4993f7d54a6SGarrett D'Amore if (hdl->h_dma) { 5003f7d54a6SGarrett D'Amore bd->d_dma = *(hdl->h_dma); 5013f7d54a6SGarrett D'Amore bd->d_dma.dma_attr_granular = 5023f7d54a6SGarrett D'Amore max(DEV_BSIZE, bd->d_dma.dma_attr_granular); 5033f7d54a6SGarrett D'Amore bd->d_use_dma = B_TRUE; 5043f7d54a6SGarrett D'Amore 5053f7d54a6SGarrett D'Amore if (bd->d_maxxfer && 5063f7d54a6SGarrett D'Amore (bd->d_maxxfer != bd->d_dma.dma_attr_maxxfer)) { 5073f7d54a6SGarrett D'Amore cmn_err(CE_WARN, 5083f7d54a6SGarrett D'Amore "%s: inconsistent maximum transfer size!", 5093f7d54a6SGarrett D'Amore name); 5103f7d54a6SGarrett D'Amore /* We force it */ 5113f7d54a6SGarrett D'Amore bd->d_maxxfer = bd->d_dma.dma_attr_maxxfer; 5123f7d54a6SGarrett D'Amore } else { 5133f7d54a6SGarrett D'Amore bd->d_maxxfer = bd->d_dma.dma_attr_maxxfer; 5143f7d54a6SGarrett D'Amore } 5153f7d54a6SGarrett D'Amore } else { 5163f7d54a6SGarrett D'Amore bd->d_use_dma = B_FALSE; 5173f7d54a6SGarrett D'Amore if (bd->d_maxxfer == 0) { 5183f7d54a6SGarrett D'Amore bd->d_maxxfer = 1024 * 1024; 5193f7d54a6SGarrett D'Amore } 5203f7d54a6SGarrett D'Amore } 5213f7d54a6SGarrett D'Amore bd->d_ops = hdl->h_ops; 5223f7d54a6SGarrett D'Amore bd->d_private = hdl->h_private; 5233f7d54a6SGarrett D'Amore bd->d_blkshift = 9; /* 512 bytes, to start */ 5243f7d54a6SGarrett D'Amore 5253f7d54a6SGarrett D'Amore if (bd->d_maxxfer % DEV_BSIZE) { 5263f7d54a6SGarrett D'Amore cmn_err(CE_WARN, "%s: maximum transfer misaligned!", name); 5273f7d54a6SGarrett D'Amore bd->d_maxxfer &= ~(DEV_BSIZE - 1); 5283f7d54a6SGarrett D'Amore } 5293f7d54a6SGarrett D'Amore if (bd->d_maxxfer < DEV_BSIZE) { 5303f7d54a6SGarrett D'Amore cmn_err(CE_WARN, "%s: maximum transfer size too small!", name); 5313f7d54a6SGarrett D'Amore ddi_soft_state_free(bd_state, inst); 5323f7d54a6SGarrett D'Amore return (DDI_FAILURE); 5333f7d54a6SGarrett D'Amore } 5343f7d54a6SGarrett D'Amore 5353f7d54a6SGarrett D'Amore bd->d_dip = dip; 5363f7d54a6SGarrett D'Amore bd->d_handle = hdl; 5373f7d54a6SGarrett D'Amore hdl->h_bd = bd; 5383f7d54a6SGarrett D'Amore ddi_set_driver_private(dip, bd); 5393f7d54a6SGarrett D'Amore 5403f7d54a6SGarrett D'Amore mutex_init(&bd->d_iomutex, NULL, MUTEX_DRIVER, NULL); 5413f7d54a6SGarrett D'Amore mutex_init(&bd->d_ocmutex, NULL, MUTEX_DRIVER, NULL); 5423f7d54a6SGarrett D'Amore mutex_init(&bd->d_statemutex, NULL, MUTEX_DRIVER, NULL); 5433f7d54a6SGarrett D'Amore cv_init(&bd->d_statecv, NULL, CV_DRIVER, NULL); 5443f7d54a6SGarrett D'Amore 5453f7d54a6SGarrett D'Amore list_create(&bd->d_waitq, sizeof (bd_xfer_impl_t), 5463f7d54a6SGarrett D'Amore offsetof(struct bd_xfer_impl, i_linkage)); 5473f7d54a6SGarrett D'Amore list_create(&bd->d_runq, sizeof (bd_xfer_impl_t), 5483f7d54a6SGarrett D'Amore offsetof(struct bd_xfer_impl, i_linkage)); 5493f7d54a6SGarrett D'Amore 5503f7d54a6SGarrett D'Amore bd->d_cache = kmem_cache_create(kcache, sizeof (bd_xfer_impl_t), 8, 5513f7d54a6SGarrett D'Amore bd_xfer_ctor, bd_xfer_dtor, NULL, bd, NULL, 0); 5523f7d54a6SGarrett D'Amore 5533f7d54a6SGarrett D'Amore bd->d_ksp = kstat_create(ddi_driver_name(dip), inst, NULL, "disk", 5543f7d54a6SGarrett D'Amore KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 5553f7d54a6SGarrett D'Amore if (bd->d_ksp != NULL) { 5563f7d54a6SGarrett D'Amore bd->d_ksp->ks_lock = &bd->d_iomutex; 5573f7d54a6SGarrett D'Amore kstat_install(bd->d_ksp); 5583f7d54a6SGarrett D'Amore bd->d_kiop = bd->d_ksp->ks_data; 5593f7d54a6SGarrett D'Amore } else { 5603f7d54a6SGarrett D'Amore /* 5613f7d54a6SGarrett D'Amore * Even if we cannot create the kstat, we create a 5623f7d54a6SGarrett D'Amore * scratch kstat. The reason for this is to ensure 5633f7d54a6SGarrett D'Amore * that we can update the kstat all of the time, 5643f7d54a6SGarrett D'Amore * without adding an extra branch instruction. 5653f7d54a6SGarrett D'Amore */ 5663f7d54a6SGarrett D'Amore bd->d_kiop = kmem_zalloc(sizeof (kstat_io_t), KM_SLEEP); 5673f7d54a6SGarrett D'Amore } 5683f7d54a6SGarrett D'Amore 5693f7d54a6SGarrett D'Amore cmlb_alloc_handle(&bd->d_cmlbh); 5703f7d54a6SGarrett D'Amore 5713f7d54a6SGarrett D'Amore bd->d_state = DKIO_NONE; 5723f7d54a6SGarrett D'Amore 5733f7d54a6SGarrett D'Amore bzero(&drive, sizeof (drive)); 5743f7d54a6SGarrett D'Amore bd->d_ops.o_drive_info(bd->d_private, &drive); 5753f7d54a6SGarrett D'Amore bd->d_qsize = drive.d_qsize; 5763f7d54a6SGarrett D'Amore bd->d_removable = drive.d_removable; 5773f7d54a6SGarrett D'Amore bd->d_hotpluggable = drive.d_hotpluggable; 5783f7d54a6SGarrett D'Amore 579bc220884SAlexey Zaytsev if (drive.d_maxxfer && drive.d_maxxfer < bd->d_maxxfer) 580bc220884SAlexey Zaytsev bd->d_maxxfer = drive.d_maxxfer; 581bc220884SAlexey Zaytsev 582510a6847SHans Rosenfeld bd_create_inquiry_props(dip, &drive); 583bc220884SAlexey Zaytsev 584bef9e21aSHans Rosenfeld bd_create_errstats(bd, inst, &drive); 585bef9e21aSHans Rosenfeld bd_init_errstats(bd, &drive); 586bef9e21aSHans Rosenfeld bd_update_state(bd); 587bef9e21aSHans Rosenfeld 5883f7d54a6SGarrett D'Amore rv = cmlb_attach(dip, &bd_tg_ops, DTYPE_DIRECT, 5893f7d54a6SGarrett D'Amore bd->d_removable, bd->d_hotpluggable, 590fa27e351SHans Rosenfeld /*LINTED: E_BAD_PTR_CAST_ALIGN*/ 591fa27e351SHans Rosenfeld *(uint64_t *)drive.d_eui64 != 0 ? DDI_NT_BLOCK_BLKDEV : 5923f7d54a6SGarrett D'Amore drive.d_lun >= 0 ? DDI_NT_BLOCK_CHAN : DDI_NT_BLOCK, 59386e3bca6SGarrett D'Amore CMLB_FAKE_LABEL_ONE_PARTITION, bd->d_cmlbh, 0); 5943f7d54a6SGarrett D'Amore if (rv != 0) { 5953f7d54a6SGarrett D'Amore cmlb_free_handle(&bd->d_cmlbh); 5963f7d54a6SGarrett D'Amore kmem_cache_destroy(bd->d_cache); 5973f7d54a6SGarrett D'Amore mutex_destroy(&bd->d_iomutex); 5983f7d54a6SGarrett D'Amore mutex_destroy(&bd->d_ocmutex); 5993f7d54a6SGarrett D'Amore mutex_destroy(&bd->d_statemutex); 6003f7d54a6SGarrett D'Amore cv_destroy(&bd->d_statecv); 6013f7d54a6SGarrett D'Amore list_destroy(&bd->d_waitq); 6023f7d54a6SGarrett D'Amore list_destroy(&bd->d_runq); 6033f7d54a6SGarrett D'Amore if (bd->d_ksp != NULL) { 6043f7d54a6SGarrett D'Amore kstat_delete(bd->d_ksp); 6053f7d54a6SGarrett D'Amore bd->d_ksp = NULL; 6063f7d54a6SGarrett D'Amore } else { 6073f7d54a6SGarrett D'Amore kmem_free(bd->d_kiop, sizeof (kstat_io_t)); 6083f7d54a6SGarrett D'Amore } 6093f7d54a6SGarrett D'Amore ddi_soft_state_free(bd_state, inst); 6103f7d54a6SGarrett D'Amore return (DDI_FAILURE); 6113f7d54a6SGarrett D'Amore } 6123f7d54a6SGarrett D'Amore 6133f7d54a6SGarrett D'Amore if (bd->d_ops.o_devid_init != NULL) { 6143f7d54a6SGarrett D'Amore rv = bd->d_ops.o_devid_init(bd->d_private, dip, &bd->d_devid); 6153f7d54a6SGarrett D'Amore if (rv == DDI_SUCCESS) { 6163f7d54a6SGarrett D'Amore if (ddi_devid_register(dip, bd->d_devid) != 6173f7d54a6SGarrett D'Amore DDI_SUCCESS) { 6183f7d54a6SGarrett D'Amore cmn_err(CE_WARN, 6193f7d54a6SGarrett D'Amore "%s: unable to register devid", name); 6203f7d54a6SGarrett D'Amore } 6213f7d54a6SGarrett D'Amore } 6223f7d54a6SGarrett D'Amore } 6233f7d54a6SGarrett D'Amore 6243f7d54a6SGarrett D'Amore /* 6253f7d54a6SGarrett D'Amore * Add a zero-length attribute to tell the world we support 6263f7d54a6SGarrett D'Amore * kernel ioctls (for layered drivers). Also set up properties 6273f7d54a6SGarrett D'Amore * used by HAL to identify removable media. 6283f7d54a6SGarrett D'Amore */ 6293f7d54a6SGarrett D'Amore (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 6303f7d54a6SGarrett D'Amore DDI_KERNEL_IOCTL, NULL, 0); 6313f7d54a6SGarrett D'Amore if (bd->d_removable) { 6323f7d54a6SGarrett D'Amore (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 6333f7d54a6SGarrett D'Amore "removable-media", NULL, 0); 6343f7d54a6SGarrett D'Amore } 6353f7d54a6SGarrett D'Amore if (bd->d_hotpluggable) { 6363f7d54a6SGarrett D'Amore (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 6373f7d54a6SGarrett D'Amore "hotpluggable", NULL, 0); 6383f7d54a6SGarrett D'Amore } 6393f7d54a6SGarrett D'Amore 6403f7d54a6SGarrett D'Amore ddi_report_dev(dip); 6413f7d54a6SGarrett D'Amore 6423f7d54a6SGarrett D'Amore return (DDI_SUCCESS); 6433f7d54a6SGarrett D'Amore } 6443f7d54a6SGarrett D'Amore 6453f7d54a6SGarrett D'Amore static int 6463f7d54a6SGarrett D'Amore bd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 6473f7d54a6SGarrett D'Amore { 6483f7d54a6SGarrett D'Amore bd_t *bd; 6493f7d54a6SGarrett D'Amore 6503f7d54a6SGarrett D'Amore bd = ddi_get_driver_private(dip); 6513f7d54a6SGarrett D'Amore 6523f7d54a6SGarrett D'Amore switch (cmd) { 6533f7d54a6SGarrett D'Amore case DDI_DETACH: 6543f7d54a6SGarrett D'Amore break; 6553f7d54a6SGarrett D'Amore case DDI_SUSPEND: 6563f7d54a6SGarrett D'Amore /* We don't suspend, but our parent does */ 6573f7d54a6SGarrett D'Amore return (DDI_SUCCESS); 6583f7d54a6SGarrett D'Amore default: 6593f7d54a6SGarrett D'Amore return (DDI_FAILURE); 6603f7d54a6SGarrett D'Amore } 6613f7d54a6SGarrett D'Amore if (bd->d_ksp != NULL) { 6623f7d54a6SGarrett D'Amore kstat_delete(bd->d_ksp); 6633f7d54a6SGarrett D'Amore bd->d_ksp = NULL; 6643f7d54a6SGarrett D'Amore } else { 6653f7d54a6SGarrett D'Amore kmem_free(bd->d_kiop, sizeof (kstat_io_t)); 6663f7d54a6SGarrett D'Amore } 667bef9e21aSHans Rosenfeld 668bef9e21aSHans Rosenfeld if (bd->d_errstats != NULL) { 669bef9e21aSHans Rosenfeld kstat_delete(bd->d_errstats); 670bef9e21aSHans Rosenfeld bd->d_errstats = NULL; 671bef9e21aSHans Rosenfeld } else { 672bef9e21aSHans Rosenfeld kmem_free(bd->d_kerr, sizeof (struct bd_errstats)); 673bef9e21aSHans Rosenfeld mutex_destroy(bd->d_errmutex); 674bef9e21aSHans Rosenfeld } 675bef9e21aSHans Rosenfeld 67686e3bca6SGarrett D'Amore cmlb_detach(bd->d_cmlbh, 0); 6773f7d54a6SGarrett D'Amore cmlb_free_handle(&bd->d_cmlbh); 6783f7d54a6SGarrett D'Amore if (bd->d_devid) 6793f7d54a6SGarrett D'Amore ddi_devid_free(bd->d_devid); 6803f7d54a6SGarrett D'Amore kmem_cache_destroy(bd->d_cache); 6813f7d54a6SGarrett D'Amore mutex_destroy(&bd->d_iomutex); 6823f7d54a6SGarrett D'Amore mutex_destroy(&bd->d_ocmutex); 6833f7d54a6SGarrett D'Amore mutex_destroy(&bd->d_statemutex); 6843f7d54a6SGarrett D'Amore cv_destroy(&bd->d_statecv); 6853f7d54a6SGarrett D'Amore list_destroy(&bd->d_waitq); 6863f7d54a6SGarrett D'Amore list_destroy(&bd->d_runq); 6873f7d54a6SGarrett D'Amore ddi_soft_state_free(bd_state, ddi_get_instance(dip)); 6883f7d54a6SGarrett D'Amore return (DDI_SUCCESS); 6893f7d54a6SGarrett D'Amore } 6903f7d54a6SGarrett D'Amore 6913f7d54a6SGarrett D'Amore static int 6923f7d54a6SGarrett D'Amore bd_xfer_ctor(void *buf, void *arg, int kmflag) 6933f7d54a6SGarrett D'Amore { 6943f7d54a6SGarrett D'Amore bd_xfer_impl_t *xi; 6953f7d54a6SGarrett D'Amore bd_t *bd = arg; 6963f7d54a6SGarrett D'Amore int (*dcb)(caddr_t); 6973f7d54a6SGarrett D'Amore 698679ac156SAlexey Zaytsev if (kmflag == KM_PUSHPAGE || kmflag == KM_SLEEP) { 6993f7d54a6SGarrett D'Amore dcb = DDI_DMA_SLEEP; 7003f7d54a6SGarrett D'Amore } else { 7013f7d54a6SGarrett D'Amore dcb = DDI_DMA_DONTWAIT; 7023f7d54a6SGarrett D'Amore } 7033f7d54a6SGarrett D'Amore 7043f7d54a6SGarrett D'Amore xi = buf; 7053f7d54a6SGarrett D'Amore bzero(xi, sizeof (*xi)); 7063f7d54a6SGarrett D'Amore xi->i_bd = bd; 7073f7d54a6SGarrett D'Amore 7083f7d54a6SGarrett D'Amore if (bd->d_use_dma) { 7093f7d54a6SGarrett D'Amore if (ddi_dma_alloc_handle(bd->d_dip, &bd->d_dma, dcb, NULL, 7103f7d54a6SGarrett D'Amore &xi->i_dmah) != DDI_SUCCESS) { 7113f7d54a6SGarrett D'Amore return (-1); 7123f7d54a6SGarrett D'Amore } 7133f7d54a6SGarrett D'Amore } 7143f7d54a6SGarrett D'Amore 7153f7d54a6SGarrett D'Amore return (0); 7163f7d54a6SGarrett D'Amore } 7173f7d54a6SGarrett D'Amore 7183f7d54a6SGarrett D'Amore static void 7193f7d54a6SGarrett D'Amore bd_xfer_dtor(void *buf, void *arg) 7203f7d54a6SGarrett D'Amore { 7213f7d54a6SGarrett D'Amore bd_xfer_impl_t *xi = buf; 7223f7d54a6SGarrett D'Amore 7233f7d54a6SGarrett D'Amore _NOTE(ARGUNUSED(arg)); 7243f7d54a6SGarrett D'Amore 7253f7d54a6SGarrett D'Amore if (xi->i_dmah) 7263f7d54a6SGarrett D'Amore ddi_dma_free_handle(&xi->i_dmah); 7273f7d54a6SGarrett D'Amore xi->i_dmah = NULL; 7283f7d54a6SGarrett D'Amore } 7293f7d54a6SGarrett D'Amore 7303f7d54a6SGarrett D'Amore static bd_xfer_impl_t * 7313f7d54a6SGarrett D'Amore bd_xfer_alloc(bd_t *bd, struct buf *bp, int (*func)(void *, bd_xfer_t *), 7323f7d54a6SGarrett D'Amore int kmflag) 7333f7d54a6SGarrett D'Amore { 7343f7d54a6SGarrett D'Amore bd_xfer_impl_t *xi; 735a0cb694bSSteve Ma int rv = 0; 7363f7d54a6SGarrett D'Amore int status; 7373f7d54a6SGarrett D'Amore unsigned dir; 7383f7d54a6SGarrett D'Amore int (*cb)(caddr_t); 7393f7d54a6SGarrett D'Amore size_t len; 7403f7d54a6SGarrett D'Amore uint32_t shift; 7413f7d54a6SGarrett D'Amore 7423f7d54a6SGarrett D'Amore if (kmflag == KM_SLEEP) { 7433f7d54a6SGarrett D'Amore cb = DDI_DMA_SLEEP; 7443f7d54a6SGarrett D'Amore } else { 7453f7d54a6SGarrett D'Amore cb = DDI_DMA_DONTWAIT; 7463f7d54a6SGarrett D'Amore } 7473f7d54a6SGarrett D'Amore 7483f7d54a6SGarrett D'Amore xi = kmem_cache_alloc(bd->d_cache, kmflag); 7493f7d54a6SGarrett D'Amore if (xi == NULL) { 7503f7d54a6SGarrett D'Amore bioerror(bp, ENOMEM); 7513f7d54a6SGarrett D'Amore return (NULL); 7523f7d54a6SGarrett D'Amore } 7533f7d54a6SGarrett D'Amore 7543f7d54a6SGarrett D'Amore ASSERT(bp); 7553f7d54a6SGarrett D'Amore 7563f7d54a6SGarrett D'Amore xi->i_bp = bp; 7573f7d54a6SGarrett D'Amore xi->i_func = func; 75810624986SYouzhong Yang xi->i_blkno = bp->b_lblkno >> (bd->d_blkshift - DEV_BSHIFT); 7593f7d54a6SGarrett D'Amore 7603f7d54a6SGarrett D'Amore if (bp->b_bcount == 0) { 7613f7d54a6SGarrett D'Amore xi->i_len = 0; 7623f7d54a6SGarrett D'Amore xi->i_nblks = 0; 7633f7d54a6SGarrett D'Amore xi->i_kaddr = NULL; 7643f7d54a6SGarrett D'Amore xi->i_resid = 0; 7653f7d54a6SGarrett D'Amore xi->i_num_win = 0; 7663f7d54a6SGarrett D'Amore goto done; 7673f7d54a6SGarrett D'Amore } 7683f7d54a6SGarrett D'Amore 7693f7d54a6SGarrett D'Amore if (bp->b_flags & B_READ) { 7703f7d54a6SGarrett D'Amore dir = DDI_DMA_READ; 7713f7d54a6SGarrett D'Amore xi->i_func = bd->d_ops.o_read; 7723f7d54a6SGarrett D'Amore } else { 7733f7d54a6SGarrett D'Amore dir = DDI_DMA_WRITE; 7743f7d54a6SGarrett D'Amore xi->i_func = bd->d_ops.o_write; 7753f7d54a6SGarrett D'Amore } 7763f7d54a6SGarrett D'Amore 7773f7d54a6SGarrett D'Amore shift = bd->d_blkshift; 7783f7d54a6SGarrett D'Amore xi->i_blkshift = shift; 7793f7d54a6SGarrett D'Amore 7803f7d54a6SGarrett D'Amore if (!bd->d_use_dma) { 7813f7d54a6SGarrett D'Amore bp_mapin(bp); 7823f7d54a6SGarrett D'Amore rv = 0; 7833f7d54a6SGarrett D'Amore xi->i_offset = 0; 7843f7d54a6SGarrett D'Amore xi->i_num_win = 7853f7d54a6SGarrett D'Amore (bp->b_bcount + (bd->d_maxxfer - 1)) / bd->d_maxxfer; 7863f7d54a6SGarrett D'Amore xi->i_cur_win = 0; 7873f7d54a6SGarrett D'Amore xi->i_len = min(bp->b_bcount, bd->d_maxxfer); 7883f7d54a6SGarrett D'Amore xi->i_nblks = xi->i_len >> shift; 7893f7d54a6SGarrett D'Amore xi->i_kaddr = bp->b_un.b_addr; 7903f7d54a6SGarrett D'Amore xi->i_resid = bp->b_bcount; 7913f7d54a6SGarrett D'Amore } else { 7923f7d54a6SGarrett D'Amore 7933f7d54a6SGarrett D'Amore /* 7943f7d54a6SGarrett D'Amore * We have to use consistent DMA if the address is misaligned. 7953f7d54a6SGarrett D'Amore */ 7963f7d54a6SGarrett D'Amore if (((bp->b_flags & (B_PAGEIO | B_REMAPPED)) != B_PAGEIO) && 7973f7d54a6SGarrett D'Amore ((uintptr_t)bp->b_un.b_addr & 0x7)) { 7983f7d54a6SGarrett D'Amore dir |= DDI_DMA_CONSISTENT | DDI_DMA_PARTIAL; 7993f7d54a6SGarrett D'Amore } else { 8003f7d54a6SGarrett D'Amore dir |= DDI_DMA_STREAMING | DDI_DMA_PARTIAL; 8013f7d54a6SGarrett D'Amore } 8023f7d54a6SGarrett D'Amore 8033f7d54a6SGarrett D'Amore status = ddi_dma_buf_bind_handle(xi->i_dmah, bp, dir, cb, 8043f7d54a6SGarrett D'Amore NULL, &xi->i_dmac, &xi->i_ndmac); 8053f7d54a6SGarrett D'Amore switch (status) { 8063f7d54a6SGarrett D'Amore case DDI_DMA_MAPPED: 8073f7d54a6SGarrett D'Amore xi->i_num_win = 1; 8083f7d54a6SGarrett D'Amore xi->i_cur_win = 0; 8093f7d54a6SGarrett D'Amore xi->i_offset = 0; 8103f7d54a6SGarrett D'Amore xi->i_len = bp->b_bcount; 8113f7d54a6SGarrett D'Amore xi->i_nblks = xi->i_len >> shift; 8123f7d54a6SGarrett D'Amore xi->i_resid = bp->b_bcount; 8133f7d54a6SGarrett D'Amore rv = 0; 8143f7d54a6SGarrett D'Amore break; 8153f7d54a6SGarrett D'Amore case DDI_DMA_PARTIAL_MAP: 8163f7d54a6SGarrett D'Amore xi->i_cur_win = 0; 8173f7d54a6SGarrett D'Amore 8183f7d54a6SGarrett D'Amore if ((ddi_dma_numwin(xi->i_dmah, &xi->i_num_win) != 8193f7d54a6SGarrett D'Amore DDI_SUCCESS) || 8203f7d54a6SGarrett D'Amore (ddi_dma_getwin(xi->i_dmah, 0, &xi->i_offset, 8213f7d54a6SGarrett D'Amore &len, &xi->i_dmac, &xi->i_ndmac) != 8223f7d54a6SGarrett D'Amore DDI_SUCCESS) || 82310624986SYouzhong Yang (P2PHASE(len, (1U << shift)) != 0)) { 8243f7d54a6SGarrett D'Amore (void) ddi_dma_unbind_handle(xi->i_dmah); 8253f7d54a6SGarrett D'Amore rv = EFAULT; 8263f7d54a6SGarrett D'Amore goto done; 8273f7d54a6SGarrett D'Amore } 8283f7d54a6SGarrett D'Amore xi->i_len = len; 8293f7d54a6SGarrett D'Amore xi->i_nblks = xi->i_len >> shift; 8303f7d54a6SGarrett D'Amore xi->i_resid = bp->b_bcount; 8313f7d54a6SGarrett D'Amore rv = 0; 8323f7d54a6SGarrett D'Amore break; 8333f7d54a6SGarrett D'Amore case DDI_DMA_NORESOURCES: 8343f7d54a6SGarrett D'Amore rv = EAGAIN; 8353f7d54a6SGarrett D'Amore goto done; 8363f7d54a6SGarrett D'Amore case DDI_DMA_TOOBIG: 8373f7d54a6SGarrett D'Amore rv = EINVAL; 8383f7d54a6SGarrett D'Amore goto done; 8393f7d54a6SGarrett D'Amore case DDI_DMA_NOMAPPING: 8403f7d54a6SGarrett D'Amore case DDI_DMA_INUSE: 8413f7d54a6SGarrett D'Amore default: 8423f7d54a6SGarrett D'Amore rv = EFAULT; 8433f7d54a6SGarrett D'Amore goto done; 8443f7d54a6SGarrett D'Amore } 8453f7d54a6SGarrett D'Amore } 8463f7d54a6SGarrett D'Amore 8473f7d54a6SGarrett D'Amore done: 8483f7d54a6SGarrett D'Amore if (rv != 0) { 8493f7d54a6SGarrett D'Amore kmem_cache_free(bd->d_cache, xi); 8503f7d54a6SGarrett D'Amore bioerror(bp, rv); 8513f7d54a6SGarrett D'Amore return (NULL); 8523f7d54a6SGarrett D'Amore } 8533f7d54a6SGarrett D'Amore 8543f7d54a6SGarrett D'Amore return (xi); 8553f7d54a6SGarrett D'Amore } 8563f7d54a6SGarrett D'Amore 8573f7d54a6SGarrett D'Amore static void 8583f7d54a6SGarrett D'Amore bd_xfer_free(bd_xfer_impl_t *xi) 8593f7d54a6SGarrett D'Amore { 8603f7d54a6SGarrett D'Amore if (xi->i_dmah) { 8613f7d54a6SGarrett D'Amore (void) ddi_dma_unbind_handle(xi->i_dmah); 8623f7d54a6SGarrett D'Amore } 8633f7d54a6SGarrett D'Amore kmem_cache_free(xi->i_bd->d_cache, xi); 8643f7d54a6SGarrett D'Amore } 8653f7d54a6SGarrett D'Amore 8663f7d54a6SGarrett D'Amore static int 8673f7d54a6SGarrett D'Amore bd_open(dev_t *devp, int flag, int otyp, cred_t *credp) 8683f7d54a6SGarrett D'Amore { 8693f7d54a6SGarrett D'Amore dev_t dev = *devp; 8703f7d54a6SGarrett D'Amore bd_t *bd; 8713f7d54a6SGarrett D'Amore minor_t part; 8723f7d54a6SGarrett D'Amore minor_t inst; 8733f7d54a6SGarrett D'Amore uint64_t mask; 8743f7d54a6SGarrett D'Amore boolean_t ndelay; 8753f7d54a6SGarrett D'Amore int rv; 8763f7d54a6SGarrett D'Amore diskaddr_t nblks; 8773f7d54a6SGarrett D'Amore diskaddr_t lba; 8783f7d54a6SGarrett D'Amore 8793f7d54a6SGarrett D'Amore _NOTE(ARGUNUSED(credp)); 8803f7d54a6SGarrett D'Amore 8813f7d54a6SGarrett D'Amore part = BDPART(dev); 8823f7d54a6SGarrett D'Amore inst = BDINST(dev); 8833f7d54a6SGarrett D'Amore 8843f7d54a6SGarrett D'Amore if (otyp >= OTYPCNT) 8853f7d54a6SGarrett D'Amore return (EINVAL); 8863f7d54a6SGarrett D'Amore 8873f7d54a6SGarrett D'Amore ndelay = (flag & (FNDELAY | FNONBLOCK)) ? B_TRUE : B_FALSE; 8883f7d54a6SGarrett D'Amore 8893f7d54a6SGarrett D'Amore /* 8903f7d54a6SGarrett D'Amore * Block any DR events from changing the set of registered 8913f7d54a6SGarrett D'Amore * devices while we function. 8923f7d54a6SGarrett D'Amore */ 8933f7d54a6SGarrett D'Amore rw_enter(&bd_lock, RW_READER); 8943f7d54a6SGarrett D'Amore if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) { 8953f7d54a6SGarrett D'Amore rw_exit(&bd_lock); 8963f7d54a6SGarrett D'Amore return (ENXIO); 8973f7d54a6SGarrett D'Amore } 8983f7d54a6SGarrett D'Amore 8993f7d54a6SGarrett D'Amore mutex_enter(&bd->d_ocmutex); 9003f7d54a6SGarrett D'Amore 9013f7d54a6SGarrett D'Amore ASSERT(part < 64); 9023f7d54a6SGarrett D'Amore mask = (1U << part); 9033f7d54a6SGarrett D'Amore 9043f7d54a6SGarrett D'Amore bd_update_state(bd); 9053f7d54a6SGarrett D'Amore 90686e3bca6SGarrett D'Amore if (cmlb_validate(bd->d_cmlbh, 0, 0) != 0) { 9073f7d54a6SGarrett D'Amore 9083f7d54a6SGarrett D'Amore /* non-blocking opens are allowed to succeed */ 9093f7d54a6SGarrett D'Amore if (!ndelay) { 9103f7d54a6SGarrett D'Amore rv = ENXIO; 9113f7d54a6SGarrett D'Amore goto done; 9123f7d54a6SGarrett D'Amore } 9133f7d54a6SGarrett D'Amore } else if (cmlb_partinfo(bd->d_cmlbh, part, &nblks, &lba, 91486e3bca6SGarrett D'Amore NULL, NULL, 0) == 0) { 9153f7d54a6SGarrett D'Amore 9163f7d54a6SGarrett D'Amore /* 9173f7d54a6SGarrett D'Amore * We read the partinfo, verify valid ranges. If the 9183f7d54a6SGarrett D'Amore * partition is invalid, and we aren't blocking or 9193f7d54a6SGarrett D'Amore * doing a raw access, then fail. (Non-blocking and 9203f7d54a6SGarrett D'Amore * raw accesses can still succeed to allow a disk with 9213f7d54a6SGarrett D'Amore * bad partition data to opened by format and fdisk.) 9223f7d54a6SGarrett D'Amore */ 9233f7d54a6SGarrett D'Amore if ((!nblks) && ((!ndelay) || (otyp != OTYP_CHR))) { 9243f7d54a6SGarrett D'Amore rv = ENXIO; 9253f7d54a6SGarrett D'Amore goto done; 9263f7d54a6SGarrett D'Amore } 9273f7d54a6SGarrett D'Amore } else if (!ndelay) { 9283f7d54a6SGarrett D'Amore /* 9293f7d54a6SGarrett D'Amore * cmlb_partinfo failed -- invalid partition or no 9303f7d54a6SGarrett D'Amore * disk label. 9313f7d54a6SGarrett D'Amore */ 9323f7d54a6SGarrett D'Amore rv = ENXIO; 9333f7d54a6SGarrett D'Amore goto done; 9343f7d54a6SGarrett D'Amore } 9353f7d54a6SGarrett D'Amore 9363f7d54a6SGarrett D'Amore if ((flag & FWRITE) && bd->d_rdonly) { 9373f7d54a6SGarrett D'Amore rv = EROFS; 9383f7d54a6SGarrett D'Amore goto done; 9393f7d54a6SGarrett D'Amore } 9403f7d54a6SGarrett D'Amore 9413f7d54a6SGarrett D'Amore if ((bd->d_open_excl) & (mask)) { 9423f7d54a6SGarrett D'Amore rv = EBUSY; 9433f7d54a6SGarrett D'Amore goto done; 9443f7d54a6SGarrett D'Amore } 9453f7d54a6SGarrett D'Amore if (flag & FEXCL) { 9463f7d54a6SGarrett D'Amore if (bd->d_open_lyr[part]) { 9473f7d54a6SGarrett D'Amore rv = EBUSY; 9483f7d54a6SGarrett D'Amore goto done; 9493f7d54a6SGarrett D'Amore } 9503f7d54a6SGarrett D'Amore for (int i = 0; i < OTYP_LYR; i++) { 9513f7d54a6SGarrett D'Amore if (bd->d_open_reg[i] & mask) { 9523f7d54a6SGarrett D'Amore rv = EBUSY; 9533f7d54a6SGarrett D'Amore goto done; 9543f7d54a6SGarrett D'Amore } 9553f7d54a6SGarrett D'Amore } 9563f7d54a6SGarrett D'Amore } 9573f7d54a6SGarrett D'Amore 9583f7d54a6SGarrett D'Amore if (otyp == OTYP_LYR) { 9593f7d54a6SGarrett D'Amore bd->d_open_lyr[part]++; 9603f7d54a6SGarrett D'Amore } else { 9613f7d54a6SGarrett D'Amore bd->d_open_reg[otyp] |= mask; 9623f7d54a6SGarrett D'Amore } 9633f7d54a6SGarrett D'Amore if (flag & FEXCL) { 9643f7d54a6SGarrett D'Amore bd->d_open_excl |= mask; 9653f7d54a6SGarrett D'Amore } 9663f7d54a6SGarrett D'Amore 9673f7d54a6SGarrett D'Amore rv = 0; 9683f7d54a6SGarrett D'Amore done: 9693f7d54a6SGarrett D'Amore mutex_exit(&bd->d_ocmutex); 9703f7d54a6SGarrett D'Amore rw_exit(&bd_lock); 9713f7d54a6SGarrett D'Amore 9723f7d54a6SGarrett D'Amore return (rv); 9733f7d54a6SGarrett D'Amore } 9743f7d54a6SGarrett D'Amore 9753f7d54a6SGarrett D'Amore static int 9763f7d54a6SGarrett D'Amore bd_close(dev_t dev, int flag, int otyp, cred_t *credp) 9773f7d54a6SGarrett D'Amore { 9783f7d54a6SGarrett D'Amore bd_t *bd; 9793f7d54a6SGarrett D'Amore minor_t inst; 9803f7d54a6SGarrett D'Amore minor_t part; 9813f7d54a6SGarrett D'Amore uint64_t mask; 9823f7d54a6SGarrett D'Amore boolean_t last = B_TRUE; 9833f7d54a6SGarrett D'Amore 9843f7d54a6SGarrett D'Amore _NOTE(ARGUNUSED(flag)); 9853f7d54a6SGarrett D'Amore _NOTE(ARGUNUSED(credp)); 9863f7d54a6SGarrett D'Amore 9873f7d54a6SGarrett D'Amore part = BDPART(dev); 9883f7d54a6SGarrett D'Amore inst = BDINST(dev); 9893f7d54a6SGarrett D'Amore 9903f7d54a6SGarrett D'Amore ASSERT(part < 64); 9913f7d54a6SGarrett D'Amore mask = (1U << part); 9923f7d54a6SGarrett D'Amore 9933f7d54a6SGarrett D'Amore rw_enter(&bd_lock, RW_READER); 9943f7d54a6SGarrett D'Amore 9953f7d54a6SGarrett D'Amore if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) { 9963f7d54a6SGarrett D'Amore rw_exit(&bd_lock); 9973f7d54a6SGarrett D'Amore return (ENXIO); 9983f7d54a6SGarrett D'Amore } 9993f7d54a6SGarrett D'Amore 10003f7d54a6SGarrett D'Amore mutex_enter(&bd->d_ocmutex); 10013f7d54a6SGarrett D'Amore if (bd->d_open_excl & mask) { 10023f7d54a6SGarrett D'Amore bd->d_open_excl &= ~mask; 10033f7d54a6SGarrett D'Amore } 10043f7d54a6SGarrett D'Amore if (otyp == OTYP_LYR) { 10053f7d54a6SGarrett D'Amore bd->d_open_lyr[part]--; 10063f7d54a6SGarrett D'Amore } else { 10073f7d54a6SGarrett D'Amore bd->d_open_reg[otyp] &= ~mask; 10083f7d54a6SGarrett D'Amore } 10093f7d54a6SGarrett D'Amore for (int i = 0; i < 64; i++) { 10103f7d54a6SGarrett D'Amore if (bd->d_open_lyr[part]) { 10113f7d54a6SGarrett D'Amore last = B_FALSE; 10123f7d54a6SGarrett D'Amore } 10133f7d54a6SGarrett D'Amore } 10143f7d54a6SGarrett D'Amore for (int i = 0; last && (i < OTYP_LYR); i++) { 10153f7d54a6SGarrett D'Amore if (bd->d_open_reg[i]) { 10163f7d54a6SGarrett D'Amore last = B_FALSE; 10173f7d54a6SGarrett D'Amore } 10183f7d54a6SGarrett D'Amore } 10193f7d54a6SGarrett D'Amore mutex_exit(&bd->d_ocmutex); 10203f7d54a6SGarrett D'Amore 10213f7d54a6SGarrett D'Amore if (last) { 102286e3bca6SGarrett D'Amore cmlb_invalidate(bd->d_cmlbh, 0); 10233f7d54a6SGarrett D'Amore } 10243f7d54a6SGarrett D'Amore rw_exit(&bd_lock); 10253f7d54a6SGarrett D'Amore 10263f7d54a6SGarrett D'Amore return (0); 10273f7d54a6SGarrett D'Amore } 10283f7d54a6SGarrett D'Amore 10293f7d54a6SGarrett D'Amore static int 103086e3bca6SGarrett D'Amore bd_dump(dev_t dev, caddr_t caddr, daddr_t blkno, int nblk) 103186e3bca6SGarrett D'Amore { 103286e3bca6SGarrett D'Amore minor_t inst; 103386e3bca6SGarrett D'Amore minor_t part; 103486e3bca6SGarrett D'Amore diskaddr_t pstart; 103586e3bca6SGarrett D'Amore diskaddr_t psize; 103686e3bca6SGarrett D'Amore bd_t *bd; 103786e3bca6SGarrett D'Amore bd_xfer_impl_t *xi; 103886e3bca6SGarrett D'Amore buf_t *bp; 103986e3bca6SGarrett D'Amore int rv; 104010624986SYouzhong Yang uint32_t shift; 104110624986SYouzhong Yang daddr_t d_blkno; 104210624986SYouzhong Yang int d_nblk; 104386e3bca6SGarrett D'Amore 104486e3bca6SGarrett D'Amore rw_enter(&bd_lock, RW_READER); 104586e3bca6SGarrett D'Amore 104686e3bca6SGarrett D'Amore part = BDPART(dev); 104786e3bca6SGarrett D'Amore inst = BDINST(dev); 104886e3bca6SGarrett D'Amore 104986e3bca6SGarrett D'Amore if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) { 105086e3bca6SGarrett D'Amore rw_exit(&bd_lock); 105186e3bca6SGarrett D'Amore return (ENXIO); 105286e3bca6SGarrett D'Amore } 105310624986SYouzhong Yang shift = bd->d_blkshift; 105410624986SYouzhong Yang d_blkno = blkno >> (shift - DEV_BSHIFT); 105510624986SYouzhong Yang d_nblk = nblk >> (shift - DEV_BSHIFT); 105686e3bca6SGarrett D'Amore /* 105786e3bca6SGarrett D'Amore * do cmlb, but do it synchronously unless we already have the 105886e3bca6SGarrett D'Amore * partition (which we probably should.) 105986e3bca6SGarrett D'Amore */ 106086e3bca6SGarrett D'Amore if (cmlb_partinfo(bd->d_cmlbh, part, &psize, &pstart, NULL, NULL, 106186e3bca6SGarrett D'Amore (void *)1)) { 106286e3bca6SGarrett D'Amore rw_exit(&bd_lock); 106386e3bca6SGarrett D'Amore return (ENXIO); 106486e3bca6SGarrett D'Amore } 106586e3bca6SGarrett D'Amore 106610624986SYouzhong Yang if ((d_blkno + d_nblk) > psize) { 106786e3bca6SGarrett D'Amore rw_exit(&bd_lock); 106886e3bca6SGarrett D'Amore return (EINVAL); 106986e3bca6SGarrett D'Amore } 107086e3bca6SGarrett D'Amore bp = getrbuf(KM_NOSLEEP); 107186e3bca6SGarrett D'Amore if (bp == NULL) { 107286e3bca6SGarrett D'Amore rw_exit(&bd_lock); 107386e3bca6SGarrett D'Amore return (ENOMEM); 107486e3bca6SGarrett D'Amore } 107586e3bca6SGarrett D'Amore 107610624986SYouzhong Yang bp->b_bcount = nblk << DEV_BSHIFT; 107786e3bca6SGarrett D'Amore bp->b_resid = bp->b_bcount; 107886e3bca6SGarrett D'Amore bp->b_lblkno = blkno; 107986e3bca6SGarrett D'Amore bp->b_un.b_addr = caddr; 108086e3bca6SGarrett D'Amore 108186e3bca6SGarrett D'Amore xi = bd_xfer_alloc(bd, bp, bd->d_ops.o_write, KM_NOSLEEP); 108286e3bca6SGarrett D'Amore if (xi == NULL) { 108386e3bca6SGarrett D'Amore rw_exit(&bd_lock); 108486e3bca6SGarrett D'Amore freerbuf(bp); 108586e3bca6SGarrett D'Amore return (ENOMEM); 108686e3bca6SGarrett D'Amore } 108710624986SYouzhong Yang xi->i_blkno = d_blkno + pstart; 108886e3bca6SGarrett D'Amore xi->i_flags = BD_XFER_POLL; 108986e3bca6SGarrett D'Amore bd_submit(bd, xi); 109086e3bca6SGarrett D'Amore rw_exit(&bd_lock); 109186e3bca6SGarrett D'Amore 109286e3bca6SGarrett D'Amore /* 109386e3bca6SGarrett D'Amore * Generally, we should have run this entirely synchronously 109486e3bca6SGarrett D'Amore * at this point and the biowait call should be a no-op. If 109586e3bca6SGarrett D'Amore * it didn't happen this way, it's a bug in the underlying 109686e3bca6SGarrett D'Amore * driver not honoring BD_XFER_POLL. 109786e3bca6SGarrett D'Amore */ 109886e3bca6SGarrett D'Amore (void) biowait(bp); 109986e3bca6SGarrett D'Amore rv = geterror(bp); 110086e3bca6SGarrett D'Amore freerbuf(bp); 110186e3bca6SGarrett D'Amore return (rv); 110286e3bca6SGarrett D'Amore } 110386e3bca6SGarrett D'Amore 11049d75dfdaSAlexey Zaytsev void 11059d75dfdaSAlexey Zaytsev bd_minphys(struct buf *bp) 11069d75dfdaSAlexey Zaytsev { 11079d75dfdaSAlexey Zaytsev minor_t inst; 11089d75dfdaSAlexey Zaytsev bd_t *bd; 11099d75dfdaSAlexey Zaytsev inst = BDINST(bp->b_edev); 11109d75dfdaSAlexey Zaytsev 11119d75dfdaSAlexey Zaytsev bd = ddi_get_soft_state(bd_state, inst); 11129d75dfdaSAlexey Zaytsev 11139d75dfdaSAlexey Zaytsev /* 11149d75dfdaSAlexey Zaytsev * In a non-debug kernel, bd_strategy will catch !bd as 11159d75dfdaSAlexey Zaytsev * well, and will fail nicely. 11169d75dfdaSAlexey Zaytsev */ 11179d75dfdaSAlexey Zaytsev ASSERT(bd); 11189d75dfdaSAlexey Zaytsev 11199d75dfdaSAlexey Zaytsev if (bp->b_bcount > bd->d_maxxfer) 11209d75dfdaSAlexey Zaytsev bp->b_bcount = bd->d_maxxfer; 11219d75dfdaSAlexey Zaytsev } 11229d75dfdaSAlexey Zaytsev 112386e3bca6SGarrett D'Amore static int 112410624986SYouzhong Yang bd_check_uio(dev_t dev, struct uio *uio) 112510624986SYouzhong Yang { 112610624986SYouzhong Yang bd_t *bd; 112710624986SYouzhong Yang uint32_t shift; 112810624986SYouzhong Yang 112910624986SYouzhong Yang if ((bd = ddi_get_soft_state(bd_state, BDINST(dev))) == NULL) { 113010624986SYouzhong Yang return (ENXIO); 113110624986SYouzhong Yang } 113210624986SYouzhong Yang 113310624986SYouzhong Yang shift = bd->d_blkshift; 113410624986SYouzhong Yang if ((P2PHASE(uio->uio_loffset, (1U << shift)) != 0) || 113510624986SYouzhong Yang (P2PHASE(uio->uio_iov->iov_len, (1U << shift)) != 0)) { 113610624986SYouzhong Yang return (EINVAL); 113710624986SYouzhong Yang } 113810624986SYouzhong Yang 113910624986SYouzhong Yang return (0); 114010624986SYouzhong Yang } 114110624986SYouzhong Yang 114210624986SYouzhong Yang static int 11433f7d54a6SGarrett D'Amore bd_read(dev_t dev, struct uio *uio, cred_t *credp) 11443f7d54a6SGarrett D'Amore { 11453f7d54a6SGarrett D'Amore _NOTE(ARGUNUSED(credp)); 114610624986SYouzhong Yang int ret = bd_check_uio(dev, uio); 114710624986SYouzhong Yang if (ret != 0) { 114810624986SYouzhong Yang return (ret); 114910624986SYouzhong Yang } 11509d75dfdaSAlexey Zaytsev return (physio(bd_strategy, NULL, dev, B_READ, bd_minphys, uio)); 11513f7d54a6SGarrett D'Amore } 11523f7d54a6SGarrett D'Amore 11533f7d54a6SGarrett D'Amore static int 11543f7d54a6SGarrett D'Amore bd_write(dev_t dev, struct uio *uio, cred_t *credp) 11553f7d54a6SGarrett D'Amore { 11563f7d54a6SGarrett D'Amore _NOTE(ARGUNUSED(credp)); 115710624986SYouzhong Yang int ret = bd_check_uio(dev, uio); 115810624986SYouzhong Yang if (ret != 0) { 115910624986SYouzhong Yang return (ret); 116010624986SYouzhong Yang } 11619d75dfdaSAlexey Zaytsev return (physio(bd_strategy, NULL, dev, B_WRITE, bd_minphys, uio)); 11623f7d54a6SGarrett D'Amore } 11633f7d54a6SGarrett D'Amore 11643f7d54a6SGarrett D'Amore static int 11653f7d54a6SGarrett D'Amore bd_aread(dev_t dev, struct aio_req *aio, cred_t *credp) 11663f7d54a6SGarrett D'Amore { 11673f7d54a6SGarrett D'Amore _NOTE(ARGUNUSED(credp)); 116810624986SYouzhong Yang int ret = bd_check_uio(dev, aio->aio_uio); 116910624986SYouzhong Yang if (ret != 0) { 117010624986SYouzhong Yang return (ret); 117110624986SYouzhong Yang } 11729d75dfdaSAlexey Zaytsev return (aphysio(bd_strategy, anocancel, dev, B_READ, bd_minphys, aio)); 11733f7d54a6SGarrett D'Amore } 11743f7d54a6SGarrett D'Amore 11753f7d54a6SGarrett D'Amore static int 11763f7d54a6SGarrett D'Amore bd_awrite(dev_t dev, struct aio_req *aio, cred_t *credp) 11773f7d54a6SGarrett D'Amore { 11783f7d54a6SGarrett D'Amore _NOTE(ARGUNUSED(credp)); 117910624986SYouzhong Yang int ret = bd_check_uio(dev, aio->aio_uio); 118010624986SYouzhong Yang if (ret != 0) { 118110624986SYouzhong Yang return (ret); 118210624986SYouzhong Yang } 11839d75dfdaSAlexey Zaytsev return (aphysio(bd_strategy, anocancel, dev, B_WRITE, bd_minphys, aio)); 11843f7d54a6SGarrett D'Amore } 11853f7d54a6SGarrett D'Amore 11863f7d54a6SGarrett D'Amore static int 11873f7d54a6SGarrett D'Amore bd_strategy(struct buf *bp) 11883f7d54a6SGarrett D'Amore { 11893f7d54a6SGarrett D'Amore minor_t inst; 11903f7d54a6SGarrett D'Amore minor_t part; 11913f7d54a6SGarrett D'Amore bd_t *bd; 11923f7d54a6SGarrett D'Amore diskaddr_t p_lba; 11933f7d54a6SGarrett D'Amore diskaddr_t p_nblks; 11943f7d54a6SGarrett D'Amore diskaddr_t b_nblks; 11953f7d54a6SGarrett D'Amore bd_xfer_impl_t *xi; 11963f7d54a6SGarrett D'Amore uint32_t shift; 11973f7d54a6SGarrett D'Amore int (*func)(void *, bd_xfer_t *); 119810624986SYouzhong Yang diskaddr_t lblkno; 11993f7d54a6SGarrett D'Amore 12003f7d54a6SGarrett D'Amore part = BDPART(bp->b_edev); 12013f7d54a6SGarrett D'Amore inst = BDINST(bp->b_edev); 12023f7d54a6SGarrett D'Amore 12033f7d54a6SGarrett D'Amore ASSERT(bp); 12043f7d54a6SGarrett D'Amore 12053f7d54a6SGarrett D'Amore bp->b_resid = bp->b_bcount; 12063f7d54a6SGarrett D'Amore 12073f7d54a6SGarrett D'Amore if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) { 12083f7d54a6SGarrett D'Amore bioerror(bp, ENXIO); 12093f7d54a6SGarrett D'Amore biodone(bp); 12103f7d54a6SGarrett D'Amore return (0); 12113f7d54a6SGarrett D'Amore } 12123f7d54a6SGarrett D'Amore 12133f7d54a6SGarrett D'Amore if (cmlb_partinfo(bd->d_cmlbh, part, &p_nblks, &p_lba, 121486e3bca6SGarrett D'Amore NULL, NULL, 0)) { 12153f7d54a6SGarrett D'Amore bioerror(bp, ENXIO); 12163f7d54a6SGarrett D'Amore biodone(bp); 12173f7d54a6SGarrett D'Amore return (0); 12183f7d54a6SGarrett D'Amore } 12193f7d54a6SGarrett D'Amore 12203f7d54a6SGarrett D'Amore shift = bd->d_blkshift; 122110624986SYouzhong Yang lblkno = bp->b_lblkno >> (shift - DEV_BSHIFT); 122210624986SYouzhong Yang if ((P2PHASE(bp->b_lblkno, (1U << (shift - DEV_BSHIFT))) != 0) || 122310624986SYouzhong Yang (P2PHASE(bp->b_bcount, (1U << shift)) != 0) || 122410624986SYouzhong Yang (lblkno > p_nblks)) { 122510624986SYouzhong Yang bioerror(bp, EINVAL); 12263f7d54a6SGarrett D'Amore biodone(bp); 12273f7d54a6SGarrett D'Amore return (0); 12283f7d54a6SGarrett D'Amore } 12293f7d54a6SGarrett D'Amore b_nblks = bp->b_bcount >> shift; 123010624986SYouzhong Yang if ((lblkno == p_nblks) || (bp->b_bcount == 0)) { 12313f7d54a6SGarrett D'Amore biodone(bp); 12323f7d54a6SGarrett D'Amore return (0); 12333f7d54a6SGarrett D'Amore } 12343f7d54a6SGarrett D'Amore 123510624986SYouzhong Yang if ((b_nblks + lblkno) > p_nblks) { 123610624986SYouzhong Yang bp->b_resid = ((lblkno + b_nblks - p_nblks) << shift); 12373f7d54a6SGarrett D'Amore bp->b_bcount -= bp->b_resid; 12383f7d54a6SGarrett D'Amore } else { 12393f7d54a6SGarrett D'Amore bp->b_resid = 0; 12403f7d54a6SGarrett D'Amore } 12413f7d54a6SGarrett D'Amore func = (bp->b_flags & B_READ) ? bd->d_ops.o_read : bd->d_ops.o_write; 12423f7d54a6SGarrett D'Amore 12433f7d54a6SGarrett D'Amore xi = bd_xfer_alloc(bd, bp, func, KM_NOSLEEP); 12443f7d54a6SGarrett D'Amore if (xi == NULL) { 12453f7d54a6SGarrett D'Amore xi = bd_xfer_alloc(bd, bp, func, KM_PUSHPAGE); 12463f7d54a6SGarrett D'Amore } 12473f7d54a6SGarrett D'Amore if (xi == NULL) { 12483f7d54a6SGarrett D'Amore /* bd_request_alloc will have done bioerror */ 12493f7d54a6SGarrett D'Amore biodone(bp); 12503f7d54a6SGarrett D'Amore return (0); 12513f7d54a6SGarrett D'Amore } 125210624986SYouzhong Yang xi->i_blkno = lblkno + p_lba; 12533f7d54a6SGarrett D'Amore 12543f7d54a6SGarrett D'Amore bd_submit(bd, xi); 12553f7d54a6SGarrett D'Amore 12563f7d54a6SGarrett D'Amore return (0); 12573f7d54a6SGarrett D'Amore } 12583f7d54a6SGarrett D'Amore 12593f7d54a6SGarrett D'Amore static int 12603f7d54a6SGarrett D'Amore bd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp) 12613f7d54a6SGarrett D'Amore { 12623f7d54a6SGarrett D'Amore minor_t inst; 12633f7d54a6SGarrett D'Amore uint16_t part; 12643f7d54a6SGarrett D'Amore bd_t *bd; 12653f7d54a6SGarrett D'Amore void *ptr = (void *)arg; 12663f7d54a6SGarrett D'Amore int rv; 12673f7d54a6SGarrett D'Amore 12683f7d54a6SGarrett D'Amore part = BDPART(dev); 12693f7d54a6SGarrett D'Amore inst = BDINST(dev); 12703f7d54a6SGarrett D'Amore 12713f7d54a6SGarrett D'Amore if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) { 12723f7d54a6SGarrett D'Amore return (ENXIO); 12733f7d54a6SGarrett D'Amore } 12743f7d54a6SGarrett D'Amore 127586e3bca6SGarrett D'Amore rv = cmlb_ioctl(bd->d_cmlbh, dev, cmd, arg, flag, credp, rvalp, 0); 12763f7d54a6SGarrett D'Amore if (rv != ENOTTY) 12773f7d54a6SGarrett D'Amore return (rv); 12783f7d54a6SGarrett D'Amore 1279a0cb694bSSteve Ma if (rvalp != NULL) { 1280a0cb694bSSteve Ma /* the return value of the ioctl is 0 by default */ 1281a0cb694bSSteve Ma *rvalp = 0; 1282a0cb694bSSteve Ma } 1283a0cb694bSSteve Ma 12843f7d54a6SGarrett D'Amore switch (cmd) { 12853f7d54a6SGarrett D'Amore case DKIOCGMEDIAINFO: { 12863f7d54a6SGarrett D'Amore struct dk_minfo minfo; 12873f7d54a6SGarrett D'Amore 12883f7d54a6SGarrett D'Amore /* make sure our state information is current */ 12893f7d54a6SGarrett D'Amore bd_update_state(bd); 12903f7d54a6SGarrett D'Amore bzero(&minfo, sizeof (minfo)); 12913f7d54a6SGarrett D'Amore minfo.dki_media_type = DK_FIXED_DISK; 12923f7d54a6SGarrett D'Amore minfo.dki_lbsize = (1U << bd->d_blkshift); 12933f7d54a6SGarrett D'Amore minfo.dki_capacity = bd->d_numblks; 12943f7d54a6SGarrett D'Amore if (ddi_copyout(&minfo, ptr, sizeof (minfo), flag)) { 12953f7d54a6SGarrett D'Amore return (EFAULT); 12963f7d54a6SGarrett D'Amore } 12973f7d54a6SGarrett D'Amore return (0); 12983f7d54a6SGarrett D'Amore } 1299dba604f9SDan McDonald case DKIOCGMEDIAINFOEXT: { 1300dba604f9SDan McDonald struct dk_minfo_ext miext; 1301dba604f9SDan McDonald 1302dba604f9SDan McDonald /* make sure our state information is current */ 1303dba604f9SDan McDonald bd_update_state(bd); 1304dba604f9SDan McDonald bzero(&miext, sizeof (miext)); 1305dba604f9SDan McDonald miext.dki_media_type = DK_FIXED_DISK; 1306dba604f9SDan McDonald miext.dki_lbsize = (1U << bd->d_blkshift); 130732ce6b81SHans Rosenfeld miext.dki_pbsize = (1U << bd->d_pblkshift); 1308dba604f9SDan McDonald miext.dki_capacity = bd->d_numblks; 1309dba604f9SDan McDonald if (ddi_copyout(&miext, ptr, sizeof (miext), flag)) { 1310dba604f9SDan McDonald return (EFAULT); 1311dba604f9SDan McDonald } 1312dba604f9SDan McDonald return (0); 1313dba604f9SDan McDonald } 13143f7d54a6SGarrett D'Amore case DKIOCINFO: { 13153f7d54a6SGarrett D'Amore struct dk_cinfo cinfo; 13163f7d54a6SGarrett D'Amore bzero(&cinfo, sizeof (cinfo)); 13173f7d54a6SGarrett D'Amore cinfo.dki_ctype = DKC_BLKDEV; 13183f7d54a6SGarrett D'Amore cinfo.dki_cnum = ddi_get_instance(ddi_get_parent(bd->d_dip)); 13193f7d54a6SGarrett D'Amore (void) snprintf(cinfo.dki_cname, sizeof (cinfo.dki_cname), 13203f7d54a6SGarrett D'Amore "%s", ddi_driver_name(ddi_get_parent(bd->d_dip))); 13213f7d54a6SGarrett D'Amore (void) snprintf(cinfo.dki_dname, sizeof (cinfo.dki_dname), 13223f7d54a6SGarrett D'Amore "%s", ddi_driver_name(bd->d_dip)); 13233f7d54a6SGarrett D'Amore cinfo.dki_unit = inst; 13243f7d54a6SGarrett D'Amore cinfo.dki_flags = DKI_FMTVOL; 13253f7d54a6SGarrett D'Amore cinfo.dki_partition = part; 13263f7d54a6SGarrett D'Amore cinfo.dki_maxtransfer = bd->d_maxxfer / DEV_BSIZE; 13273f7d54a6SGarrett D'Amore cinfo.dki_addr = 0; 13283f7d54a6SGarrett D'Amore cinfo.dki_slave = 0; 13293f7d54a6SGarrett D'Amore cinfo.dki_space = 0; 13303f7d54a6SGarrett D'Amore cinfo.dki_prio = 0; 13313f7d54a6SGarrett D'Amore cinfo.dki_vec = 0; 13323f7d54a6SGarrett D'Amore if (ddi_copyout(&cinfo, ptr, sizeof (cinfo), flag)) { 13333f7d54a6SGarrett D'Amore return (EFAULT); 13343f7d54a6SGarrett D'Amore } 13353f7d54a6SGarrett D'Amore return (0); 13363f7d54a6SGarrett D'Amore } 13373f7d54a6SGarrett D'Amore case DKIOCREMOVABLE: { 13383f7d54a6SGarrett D'Amore int i; 13393f7d54a6SGarrett D'Amore i = bd->d_removable ? 1 : 0; 13403f7d54a6SGarrett D'Amore if (ddi_copyout(&i, ptr, sizeof (i), flag)) { 13413f7d54a6SGarrett D'Amore return (EFAULT); 13423f7d54a6SGarrett D'Amore } 13433f7d54a6SGarrett D'Amore return (0); 13443f7d54a6SGarrett D'Amore } 13453f7d54a6SGarrett D'Amore case DKIOCHOTPLUGGABLE: { 13463f7d54a6SGarrett D'Amore int i; 13473f7d54a6SGarrett D'Amore i = bd->d_hotpluggable ? 1 : 0; 13483f7d54a6SGarrett D'Amore if (ddi_copyout(&i, ptr, sizeof (i), flag)) { 13493f7d54a6SGarrett D'Amore return (EFAULT); 13503f7d54a6SGarrett D'Amore } 13513f7d54a6SGarrett D'Amore return (0); 13523f7d54a6SGarrett D'Amore } 13533f7d54a6SGarrett D'Amore case DKIOCREADONLY: { 13543f7d54a6SGarrett D'Amore int i; 13553f7d54a6SGarrett D'Amore i = bd->d_rdonly ? 1 : 0; 13563f7d54a6SGarrett D'Amore if (ddi_copyout(&i, ptr, sizeof (i), flag)) { 13573f7d54a6SGarrett D'Amore return (EFAULT); 13583f7d54a6SGarrett D'Amore } 13593f7d54a6SGarrett D'Amore return (0); 13603f7d54a6SGarrett D'Amore } 136159d8f100SGarrett D'Amore case DKIOCSOLIDSTATE: { 136259d8f100SGarrett D'Amore int i; 136359d8f100SGarrett D'Amore i = bd->d_ssd ? 1 : 0; 136459d8f100SGarrett D'Amore if (ddi_copyout(&i, ptr, sizeof (i), flag)) { 136559d8f100SGarrett D'Amore return (EFAULT); 136659d8f100SGarrett D'Amore } 136759d8f100SGarrett D'Amore return (0); 136859d8f100SGarrett D'Amore } 13693f7d54a6SGarrett D'Amore case DKIOCSTATE: { 13703f7d54a6SGarrett D'Amore enum dkio_state state; 13713f7d54a6SGarrett D'Amore if (ddi_copyin(ptr, &state, sizeof (state), flag)) { 13723f7d54a6SGarrett D'Amore return (EFAULT); 13733f7d54a6SGarrett D'Amore } 13743f7d54a6SGarrett D'Amore if ((rv = bd_check_state(bd, &state)) != 0) { 13753f7d54a6SGarrett D'Amore return (rv); 13763f7d54a6SGarrett D'Amore } 13773f7d54a6SGarrett D'Amore if (ddi_copyout(&state, ptr, sizeof (state), flag)) { 13783f7d54a6SGarrett D'Amore return (EFAULT); 13793f7d54a6SGarrett D'Amore } 13803f7d54a6SGarrett D'Amore return (0); 13813f7d54a6SGarrett D'Amore } 13823f7d54a6SGarrett D'Amore case DKIOCFLUSHWRITECACHE: { 1383f097ef9cSAlexey Zaytsev struct dk_callback *dkc = NULL; 13843f7d54a6SGarrett D'Amore 1385f097ef9cSAlexey Zaytsev if (flag & FKIOCTL) 1386f097ef9cSAlexey Zaytsev dkc = (void *)arg; 1387f097ef9cSAlexey Zaytsev 13883f7d54a6SGarrett D'Amore rv = bd_flush_write_cache(bd, dkc); 13893f7d54a6SGarrett D'Amore return (rv); 13903f7d54a6SGarrett D'Amore } 13913f7d54a6SGarrett D'Amore 13923f7d54a6SGarrett D'Amore default: 13933f7d54a6SGarrett D'Amore break; 13943f7d54a6SGarrett D'Amore 13953f7d54a6SGarrett D'Amore } 13963f7d54a6SGarrett D'Amore return (ENOTTY); 13973f7d54a6SGarrett D'Amore } 13983f7d54a6SGarrett D'Amore 13993f7d54a6SGarrett D'Amore static int 14003f7d54a6SGarrett D'Amore bd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 14013f7d54a6SGarrett D'Amore char *name, caddr_t valuep, int *lengthp) 14023f7d54a6SGarrett D'Amore { 14033f7d54a6SGarrett D'Amore bd_t *bd; 14043f7d54a6SGarrett D'Amore 14053f7d54a6SGarrett D'Amore bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip)); 14063f7d54a6SGarrett D'Amore if (bd == NULL) 14073f7d54a6SGarrett D'Amore return (ddi_prop_op(dev, dip, prop_op, mod_flags, 14083f7d54a6SGarrett D'Amore name, valuep, lengthp)); 14093f7d54a6SGarrett D'Amore 14103f7d54a6SGarrett D'Amore return (cmlb_prop_op(bd->d_cmlbh, dev, dip, prop_op, mod_flags, name, 141186e3bca6SGarrett D'Amore valuep, lengthp, BDPART(dev), 0)); 14123f7d54a6SGarrett D'Amore } 14133f7d54a6SGarrett D'Amore 14143f7d54a6SGarrett D'Amore 14153f7d54a6SGarrett D'Amore static int 14163f7d54a6SGarrett D'Amore bd_tg_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, diskaddr_t start, 14173f7d54a6SGarrett D'Amore size_t length, void *tg_cookie) 14183f7d54a6SGarrett D'Amore { 14193f7d54a6SGarrett D'Amore bd_t *bd; 14203f7d54a6SGarrett D'Amore buf_t *bp; 14213f7d54a6SGarrett D'Amore bd_xfer_impl_t *xi; 14223f7d54a6SGarrett D'Amore int rv; 14233f7d54a6SGarrett D'Amore int (*func)(void *, bd_xfer_t *); 142486e3bca6SGarrett D'Amore int kmflag; 14253f7d54a6SGarrett D'Amore 142686e3bca6SGarrett D'Amore /* 142786e3bca6SGarrett D'Amore * If we are running in polled mode (such as during dump(9e) 142886e3bca6SGarrett D'Amore * execution), then we cannot sleep for kernel allocations. 142986e3bca6SGarrett D'Amore */ 143086e3bca6SGarrett D'Amore kmflag = tg_cookie ? KM_NOSLEEP : KM_SLEEP; 14313f7d54a6SGarrett D'Amore 143286e3bca6SGarrett D'Amore bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip)); 14333f7d54a6SGarrett D'Amore 14343f7d54a6SGarrett D'Amore if (P2PHASE(length, (1U << bd->d_blkshift)) != 0) { 14353f7d54a6SGarrett D'Amore /* We can only transfer whole blocks at a time! */ 14363f7d54a6SGarrett D'Amore return (EINVAL); 14373f7d54a6SGarrett D'Amore } 14383f7d54a6SGarrett D'Amore 143986e3bca6SGarrett D'Amore if ((bp = getrbuf(kmflag)) == NULL) { 144086e3bca6SGarrett D'Amore return (ENOMEM); 144186e3bca6SGarrett D'Amore } 14423f7d54a6SGarrett D'Amore 14433f7d54a6SGarrett D'Amore switch (cmd) { 14443f7d54a6SGarrett D'Amore case TG_READ: 14453f7d54a6SGarrett D'Amore bp->b_flags = B_READ; 14463f7d54a6SGarrett D'Amore func = bd->d_ops.o_read; 14473f7d54a6SGarrett D'Amore break; 14483f7d54a6SGarrett D'Amore case TG_WRITE: 14493f7d54a6SGarrett D'Amore bp->b_flags = B_WRITE; 14503f7d54a6SGarrett D'Amore func = bd->d_ops.o_write; 14513f7d54a6SGarrett D'Amore break; 14523f7d54a6SGarrett D'Amore default: 14533f7d54a6SGarrett D'Amore freerbuf(bp); 14543f7d54a6SGarrett D'Amore return (EINVAL); 14553f7d54a6SGarrett D'Amore } 14563f7d54a6SGarrett D'Amore 14573f7d54a6SGarrett D'Amore bp->b_un.b_addr = bufaddr; 14583f7d54a6SGarrett D'Amore bp->b_bcount = length; 145986e3bca6SGarrett D'Amore xi = bd_xfer_alloc(bd, bp, func, kmflag); 14603f7d54a6SGarrett D'Amore if (xi == NULL) { 14613f7d54a6SGarrett D'Amore rv = geterror(bp); 14623f7d54a6SGarrett D'Amore freerbuf(bp); 14633f7d54a6SGarrett D'Amore return (rv); 14643f7d54a6SGarrett D'Amore } 146586e3bca6SGarrett D'Amore xi->i_flags = tg_cookie ? BD_XFER_POLL : 0; 14663f7d54a6SGarrett D'Amore xi->i_blkno = start; 14673f7d54a6SGarrett D'Amore bd_submit(bd, xi); 14683f7d54a6SGarrett D'Amore (void) biowait(bp); 14693f7d54a6SGarrett D'Amore rv = geterror(bp); 14703f7d54a6SGarrett D'Amore freerbuf(bp); 14713f7d54a6SGarrett D'Amore 14723f7d54a6SGarrett D'Amore return (rv); 14733f7d54a6SGarrett D'Amore } 14743f7d54a6SGarrett D'Amore 14753f7d54a6SGarrett D'Amore static int 14763f7d54a6SGarrett D'Amore bd_tg_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) 14773f7d54a6SGarrett D'Amore { 14783f7d54a6SGarrett D'Amore bd_t *bd; 14793f7d54a6SGarrett D'Amore 148086e3bca6SGarrett D'Amore _NOTE(ARGUNUSED(tg_cookie)); 148186e3bca6SGarrett D'Amore bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip)); 14823f7d54a6SGarrett D'Amore 14833f7d54a6SGarrett D'Amore switch (cmd) { 14843f7d54a6SGarrett D'Amore case TG_GETPHYGEOM: 14853f7d54a6SGarrett D'Amore case TG_GETVIRTGEOM: 14863f7d54a6SGarrett D'Amore /* 14873f7d54a6SGarrett D'Amore * We don't have any "geometry" as such, let cmlb 14883f7d54a6SGarrett D'Amore * fabricate something. 14893f7d54a6SGarrett D'Amore */ 14903f7d54a6SGarrett D'Amore return (ENOTTY); 14913f7d54a6SGarrett D'Amore 14923f7d54a6SGarrett D'Amore case TG_GETCAPACITY: 14933f7d54a6SGarrett D'Amore bd_update_state(bd); 14943f7d54a6SGarrett D'Amore *(diskaddr_t *)arg = bd->d_numblks; 14953f7d54a6SGarrett D'Amore return (0); 14963f7d54a6SGarrett D'Amore 14973f7d54a6SGarrett D'Amore case TG_GETBLOCKSIZE: 14983f7d54a6SGarrett D'Amore *(uint32_t *)arg = (1U << bd->d_blkshift); 14993f7d54a6SGarrett D'Amore return (0); 15003f7d54a6SGarrett D'Amore 15013f7d54a6SGarrett D'Amore case TG_GETATTR: 15023f7d54a6SGarrett D'Amore /* 15033f7d54a6SGarrett D'Amore * It turns out that cmlb really doesn't do much for 15043f7d54a6SGarrett D'Amore * non-writable media, but lets make the information 15053f7d54a6SGarrett D'Amore * available for it in case it does more in the 15063f7d54a6SGarrett D'Amore * future. (The value is currently used for 15073f7d54a6SGarrett D'Amore * triggering special behavior for CD-ROMs.) 15083f7d54a6SGarrett D'Amore */ 15093f7d54a6SGarrett D'Amore bd_update_state(bd); 15103f7d54a6SGarrett D'Amore ((tg_attribute_t *)arg)->media_is_writable = 15113f7d54a6SGarrett D'Amore bd->d_rdonly ? B_FALSE : B_TRUE; 151259d8f100SGarrett D'Amore ((tg_attribute_t *)arg)->media_is_solid_state = bd->d_ssd; 1513b2b61b8fSYuri Pankov ((tg_attribute_t *)arg)->media_is_rotational = B_FALSE; 15143f7d54a6SGarrett D'Amore return (0); 15153f7d54a6SGarrett D'Amore 15163f7d54a6SGarrett D'Amore default: 15173f7d54a6SGarrett D'Amore return (EINVAL); 15183f7d54a6SGarrett D'Amore } 15193f7d54a6SGarrett D'Amore } 15203f7d54a6SGarrett D'Amore 15213f7d54a6SGarrett D'Amore 15223f7d54a6SGarrett D'Amore static void 15233f7d54a6SGarrett D'Amore bd_sched(bd_t *bd) 15243f7d54a6SGarrett D'Amore { 15253f7d54a6SGarrett D'Amore bd_xfer_impl_t *xi; 15263f7d54a6SGarrett D'Amore struct buf *bp; 15273f7d54a6SGarrett D'Amore int rv; 15283f7d54a6SGarrett D'Amore 152986e3bca6SGarrett D'Amore mutex_enter(&bd->d_iomutex); 15303f7d54a6SGarrett D'Amore 15313f7d54a6SGarrett D'Amore while ((bd->d_qactive < bd->d_qsize) && 15323f7d54a6SGarrett D'Amore ((xi = list_remove_head(&bd->d_waitq)) != NULL)) { 15333f7d54a6SGarrett D'Amore bd->d_qactive++; 15343f7d54a6SGarrett D'Amore kstat_waitq_to_runq(bd->d_kiop); 15353f7d54a6SGarrett D'Amore list_insert_tail(&bd->d_runq, xi); 15363f7d54a6SGarrett D'Amore 153786e3bca6SGarrett D'Amore /* 153886e3bca6SGarrett D'Amore * Submit the job to the driver. We drop the I/O mutex 153986e3bca6SGarrett D'Amore * so that we can deal with the case where the driver 154086e3bca6SGarrett D'Amore * completion routine calls back into us synchronously. 154186e3bca6SGarrett D'Amore */ 15423f7d54a6SGarrett D'Amore 15433f7d54a6SGarrett D'Amore mutex_exit(&bd->d_iomutex); 154486e3bca6SGarrett D'Amore 154586e3bca6SGarrett D'Amore rv = xi->i_func(bd->d_private, &xi->i_public); 154686e3bca6SGarrett D'Amore if (rv != 0) { 15473f7d54a6SGarrett D'Amore bp = xi->i_bp; 15483f7d54a6SGarrett D'Amore bioerror(bp, rv); 15493f7d54a6SGarrett D'Amore biodone(bp); 155086e3bca6SGarrett D'Amore 1551bef9e21aSHans Rosenfeld atomic_inc_32(&bd->d_kerr->bd_transerrs.value.ui32); 1552bef9e21aSHans Rosenfeld 155386e3bca6SGarrett D'Amore mutex_enter(&bd->d_iomutex); 155486e3bca6SGarrett D'Amore bd->d_qactive--; 155586e3bca6SGarrett D'Amore kstat_runq_exit(bd->d_kiop); 155686e3bca6SGarrett D'Amore list_remove(&bd->d_runq, xi); 1557dd3928f8SHans Rosenfeld bd_xfer_free(xi); 155886e3bca6SGarrett D'Amore } else { 15593f7d54a6SGarrett D'Amore mutex_enter(&bd->d_iomutex); 15603f7d54a6SGarrett D'Amore } 15613f7d54a6SGarrett D'Amore } 156286e3bca6SGarrett D'Amore 156386e3bca6SGarrett D'Amore mutex_exit(&bd->d_iomutex); 15643f7d54a6SGarrett D'Amore } 15653f7d54a6SGarrett D'Amore 15663f7d54a6SGarrett D'Amore static void 15673f7d54a6SGarrett D'Amore bd_submit(bd_t *bd, bd_xfer_impl_t *xi) 15683f7d54a6SGarrett D'Amore { 15693f7d54a6SGarrett D'Amore mutex_enter(&bd->d_iomutex); 15703f7d54a6SGarrett D'Amore list_insert_tail(&bd->d_waitq, xi); 15713f7d54a6SGarrett D'Amore kstat_waitq_enter(bd->d_kiop); 15723f7d54a6SGarrett D'Amore mutex_exit(&bd->d_iomutex); 157386e3bca6SGarrett D'Amore 157486e3bca6SGarrett D'Amore bd_sched(bd); 15753f7d54a6SGarrett D'Amore } 15763f7d54a6SGarrett D'Amore 15773f7d54a6SGarrett D'Amore static void 15783f7d54a6SGarrett D'Amore bd_runq_exit(bd_xfer_impl_t *xi, int err) 15793f7d54a6SGarrett D'Amore { 15803f7d54a6SGarrett D'Amore bd_t *bd = xi->i_bd; 15813f7d54a6SGarrett D'Amore buf_t *bp = xi->i_bp; 15823f7d54a6SGarrett D'Amore 158386e3bca6SGarrett D'Amore mutex_enter(&bd->d_iomutex); 15843f7d54a6SGarrett D'Amore bd->d_qactive--; 15853f7d54a6SGarrett D'Amore kstat_runq_exit(bd->d_kiop); 158686e3bca6SGarrett D'Amore list_remove(&bd->d_runq, xi); 158786e3bca6SGarrett D'Amore mutex_exit(&bd->d_iomutex); 158886e3bca6SGarrett D'Amore 15893f7d54a6SGarrett D'Amore if (err == 0) { 15903f7d54a6SGarrett D'Amore if (bp->b_flags & B_READ) { 15913f7d54a6SGarrett D'Amore bd->d_kiop->reads++; 15923f7d54a6SGarrett D'Amore bd->d_kiop->nread += (bp->b_bcount - xi->i_resid); 15933f7d54a6SGarrett D'Amore } else { 15943f7d54a6SGarrett D'Amore bd->d_kiop->writes++; 15953f7d54a6SGarrett D'Amore bd->d_kiop->nwritten += (bp->b_bcount - xi->i_resid); 15963f7d54a6SGarrett D'Amore } 15973f7d54a6SGarrett D'Amore } 15983f7d54a6SGarrett D'Amore bd_sched(bd); 15993f7d54a6SGarrett D'Amore } 16003f7d54a6SGarrett D'Amore 16013f7d54a6SGarrett D'Amore static void 16023f7d54a6SGarrett D'Amore bd_update_state(bd_t *bd) 16033f7d54a6SGarrett D'Amore { 160432ce6b81SHans Rosenfeld enum dkio_state state = DKIO_INSERTED; 16053f7d54a6SGarrett D'Amore boolean_t docmlb = B_FALSE; 160632ce6b81SHans Rosenfeld bd_media_t media; 16073f7d54a6SGarrett D'Amore 16083f7d54a6SGarrett D'Amore bzero(&media, sizeof (media)); 16093f7d54a6SGarrett D'Amore 16103f7d54a6SGarrett D'Amore mutex_enter(&bd->d_statemutex); 161132ce6b81SHans Rosenfeld if (bd->d_ops.o_media_info(bd->d_private, &media) != 0) { 161232ce6b81SHans Rosenfeld bd->d_numblks = 0; 161332ce6b81SHans Rosenfeld state = DKIO_EJECTED; 161432ce6b81SHans Rosenfeld goto done; 161532ce6b81SHans Rosenfeld } 161632ce6b81SHans Rosenfeld 16173f7d54a6SGarrett D'Amore if ((media.m_blksize < 512) || 16183f7d54a6SGarrett D'Amore (!ISP2(media.m_blksize)) || 16193f7d54a6SGarrett D'Amore (P2PHASE(bd->d_maxxfer, media.m_blksize))) { 162032ce6b81SHans Rosenfeld cmn_err(CE_WARN, "%s%d: Invalid media block size (%d)", 162132ce6b81SHans Rosenfeld ddi_driver_name(bd->d_dip), ddi_get_instance(bd->d_dip), 16223f7d54a6SGarrett D'Amore media.m_blksize); 16233f7d54a6SGarrett D'Amore /* 162432ce6b81SHans Rosenfeld * We can't use the media, treat it as not present. 16253f7d54a6SGarrett D'Amore */ 16263f7d54a6SGarrett D'Amore state = DKIO_EJECTED; 16273f7d54a6SGarrett D'Amore bd->d_numblks = 0; 162832ce6b81SHans Rosenfeld goto done; 162932ce6b81SHans Rosenfeld } 163032ce6b81SHans Rosenfeld 163132ce6b81SHans Rosenfeld if (((1U << bd->d_blkshift) != media.m_blksize) || 163232ce6b81SHans Rosenfeld (bd->d_numblks != media.m_nblks)) { 163332ce6b81SHans Rosenfeld /* Device size changed */ 163432ce6b81SHans Rosenfeld docmlb = B_TRUE; 163532ce6b81SHans Rosenfeld } 163632ce6b81SHans Rosenfeld 16373f7d54a6SGarrett D'Amore bd->d_blkshift = ddi_ffs(media.m_blksize) - 1; 163832ce6b81SHans Rosenfeld bd->d_pblkshift = bd->d_blkshift; 16393f7d54a6SGarrett D'Amore bd->d_numblks = media.m_nblks; 16403f7d54a6SGarrett D'Amore bd->d_rdonly = media.m_readonly; 164159d8f100SGarrett D'Amore bd->d_ssd = media.m_solidstate; 16423f7d54a6SGarrett D'Amore 164332ce6b81SHans Rosenfeld /* 164432ce6b81SHans Rosenfeld * Only use the supplied physical block size if it is non-zero, 164532ce6b81SHans Rosenfeld * greater or equal to the block size, and a power of 2. Ignore it 164632ce6b81SHans Rosenfeld * if not, it's just informational and we can still use the media. 164732ce6b81SHans Rosenfeld */ 164832ce6b81SHans Rosenfeld if ((media.m_pblksize != 0) && 164932ce6b81SHans Rosenfeld (media.m_pblksize >= media.m_blksize) && 165032ce6b81SHans Rosenfeld (ISP2(media.m_pblksize))) 165132ce6b81SHans Rosenfeld bd->d_pblkshift = ddi_ffs(media.m_pblksize) - 1; 16523f7d54a6SGarrett D'Amore 165332ce6b81SHans Rosenfeld done: 16543f7d54a6SGarrett D'Amore if (state != bd->d_state) { 16553f7d54a6SGarrett D'Amore bd->d_state = state; 16563f7d54a6SGarrett D'Amore cv_broadcast(&bd->d_statecv); 16573f7d54a6SGarrett D'Amore docmlb = B_TRUE; 16583f7d54a6SGarrett D'Amore } 16593f7d54a6SGarrett D'Amore mutex_exit(&bd->d_statemutex); 16603f7d54a6SGarrett D'Amore 1661bef9e21aSHans Rosenfeld bd->d_kerr->bd_capacity.value.ui64 = bd->d_numblks << bd->d_blkshift; 1662bef9e21aSHans Rosenfeld 16633f7d54a6SGarrett D'Amore if (docmlb) { 16643f7d54a6SGarrett D'Amore if (state == DKIO_INSERTED) { 166586e3bca6SGarrett D'Amore (void) cmlb_validate(bd->d_cmlbh, 0, 0); 16663f7d54a6SGarrett D'Amore } else { 166786e3bca6SGarrett D'Amore cmlb_invalidate(bd->d_cmlbh, 0); 16683f7d54a6SGarrett D'Amore } 16693f7d54a6SGarrett D'Amore } 16703f7d54a6SGarrett D'Amore } 16713f7d54a6SGarrett D'Amore 16723f7d54a6SGarrett D'Amore static int 16733f7d54a6SGarrett D'Amore bd_check_state(bd_t *bd, enum dkio_state *state) 16743f7d54a6SGarrett D'Amore { 16753f7d54a6SGarrett D'Amore clock_t when; 16763f7d54a6SGarrett D'Amore 16773f7d54a6SGarrett D'Amore for (;;) { 16783f7d54a6SGarrett D'Amore 16793f7d54a6SGarrett D'Amore bd_update_state(bd); 16803f7d54a6SGarrett D'Amore 16813f7d54a6SGarrett D'Amore mutex_enter(&bd->d_statemutex); 16823f7d54a6SGarrett D'Amore 16833f7d54a6SGarrett D'Amore if (bd->d_state != *state) { 16843f7d54a6SGarrett D'Amore *state = bd->d_state; 16853f7d54a6SGarrett D'Amore mutex_exit(&bd->d_statemutex); 16863f7d54a6SGarrett D'Amore break; 16873f7d54a6SGarrett D'Amore } 16883f7d54a6SGarrett D'Amore 16893f7d54a6SGarrett D'Amore when = drv_usectohz(1000000); 16903f7d54a6SGarrett D'Amore if (cv_reltimedwait_sig(&bd->d_statecv, &bd->d_statemutex, 16913f7d54a6SGarrett D'Amore when, TR_CLOCK_TICK) == 0) { 16923f7d54a6SGarrett D'Amore mutex_exit(&bd->d_statemutex); 16933f7d54a6SGarrett D'Amore return (EINTR); 16943f7d54a6SGarrett D'Amore } 16953f7d54a6SGarrett D'Amore 16963f7d54a6SGarrett D'Amore mutex_exit(&bd->d_statemutex); 16973f7d54a6SGarrett D'Amore } 16983f7d54a6SGarrett D'Amore 16993f7d54a6SGarrett D'Amore return (0); 17003f7d54a6SGarrett D'Amore } 17013f7d54a6SGarrett D'Amore 17023f7d54a6SGarrett D'Amore static int 17033f7d54a6SGarrett D'Amore bd_flush_write_cache_done(struct buf *bp) 17043f7d54a6SGarrett D'Amore { 17053f7d54a6SGarrett D'Amore struct dk_callback *dc = (void *)bp->b_private; 17063f7d54a6SGarrett D'Amore 17073f7d54a6SGarrett D'Amore (*dc->dkc_callback)(dc->dkc_cookie, geterror(bp)); 17083f7d54a6SGarrett D'Amore kmem_free(dc, sizeof (*dc)); 17093f7d54a6SGarrett D'Amore freerbuf(bp); 17103f7d54a6SGarrett D'Amore return (0); 17113f7d54a6SGarrett D'Amore } 17123f7d54a6SGarrett D'Amore 17133f7d54a6SGarrett D'Amore static int 17143f7d54a6SGarrett D'Amore bd_flush_write_cache(bd_t *bd, struct dk_callback *dkc) 17153f7d54a6SGarrett D'Amore { 17163f7d54a6SGarrett D'Amore buf_t *bp; 17173f7d54a6SGarrett D'Amore struct dk_callback *dc; 17183f7d54a6SGarrett D'Amore bd_xfer_impl_t *xi; 17193f7d54a6SGarrett D'Amore int rv; 17203f7d54a6SGarrett D'Amore 17213f7d54a6SGarrett D'Amore if (bd->d_ops.o_sync_cache == NULL) { 17223f7d54a6SGarrett D'Amore return (ENOTSUP); 17233f7d54a6SGarrett D'Amore } 17243f7d54a6SGarrett D'Amore if ((bp = getrbuf(KM_SLEEP)) == NULL) { 17253f7d54a6SGarrett D'Amore return (ENOMEM); 17263f7d54a6SGarrett D'Amore } 17273f7d54a6SGarrett D'Amore bp->b_resid = 0; 17283f7d54a6SGarrett D'Amore bp->b_bcount = 0; 17293f7d54a6SGarrett D'Amore 17303f7d54a6SGarrett D'Amore xi = bd_xfer_alloc(bd, bp, bd->d_ops.o_sync_cache, KM_SLEEP); 17313f7d54a6SGarrett D'Amore if (xi == NULL) { 17323f7d54a6SGarrett D'Amore rv = geterror(bp); 17333f7d54a6SGarrett D'Amore freerbuf(bp); 17343f7d54a6SGarrett D'Amore return (rv); 17353f7d54a6SGarrett D'Amore } 17363f7d54a6SGarrett D'Amore 1737f097ef9cSAlexey Zaytsev /* Make an asynchronous flush, but only if there is a callback */ 1738f097ef9cSAlexey Zaytsev if (dkc != NULL && dkc->dkc_callback != NULL) { 17393f7d54a6SGarrett D'Amore /* Make a private copy of the callback structure */ 17403f7d54a6SGarrett D'Amore dc = kmem_alloc(sizeof (*dc), KM_SLEEP); 17413f7d54a6SGarrett D'Amore *dc = *dkc; 17423f7d54a6SGarrett D'Amore bp->b_private = dc; 17433f7d54a6SGarrett D'Amore bp->b_iodone = bd_flush_write_cache_done; 17443f7d54a6SGarrett D'Amore 17453f7d54a6SGarrett D'Amore bd_submit(bd, xi); 1746f097ef9cSAlexey Zaytsev return (0); 1747f097ef9cSAlexey Zaytsev } 1748f097ef9cSAlexey Zaytsev 1749f097ef9cSAlexey Zaytsev /* In case there is no callback, perform a synchronous flush */ 1750f097ef9cSAlexey Zaytsev bd_submit(bd, xi); 17513f7d54a6SGarrett D'Amore (void) biowait(bp); 17523f7d54a6SGarrett D'Amore rv = geterror(bp); 17533f7d54a6SGarrett D'Amore freerbuf(bp); 1754f097ef9cSAlexey Zaytsev 17553f7d54a6SGarrett D'Amore return (rv); 17563f7d54a6SGarrett D'Amore } 17573f7d54a6SGarrett D'Amore 17583f7d54a6SGarrett D'Amore /* 17593f7d54a6SGarrett D'Amore * Nexus support. 17603f7d54a6SGarrett D'Amore */ 17613f7d54a6SGarrett D'Amore int 17623f7d54a6SGarrett D'Amore bd_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 17633f7d54a6SGarrett D'Amore void *arg, void *result) 17643f7d54a6SGarrett D'Amore { 17653f7d54a6SGarrett D'Amore bd_handle_t hdl; 17663f7d54a6SGarrett D'Amore 17673f7d54a6SGarrett D'Amore switch (ctlop) { 17683f7d54a6SGarrett D'Amore case DDI_CTLOPS_REPORTDEV: 17693f7d54a6SGarrett D'Amore cmn_err(CE_CONT, "?Block device: %s@%s, %s%d\n", 17703f7d54a6SGarrett D'Amore ddi_node_name(rdip), ddi_get_name_addr(rdip), 17713f7d54a6SGarrett D'Amore ddi_driver_name(rdip), ddi_get_instance(rdip)); 17723f7d54a6SGarrett D'Amore return (DDI_SUCCESS); 17733f7d54a6SGarrett D'Amore 17743f7d54a6SGarrett D'Amore case DDI_CTLOPS_INITCHILD: 17753f7d54a6SGarrett D'Amore hdl = ddi_get_parent_data((dev_info_t *)arg); 17763f7d54a6SGarrett D'Amore if (hdl == NULL) { 17773f7d54a6SGarrett D'Amore return (DDI_NOT_WELL_FORMED); 17783f7d54a6SGarrett D'Amore } 17793f7d54a6SGarrett D'Amore ddi_set_name_addr((dev_info_t *)arg, hdl->h_addr); 17803f7d54a6SGarrett D'Amore return (DDI_SUCCESS); 17813f7d54a6SGarrett D'Amore 17823f7d54a6SGarrett D'Amore case DDI_CTLOPS_UNINITCHILD: 17833f7d54a6SGarrett D'Amore ddi_set_name_addr((dev_info_t *)arg, NULL); 17843f7d54a6SGarrett D'Amore ndi_prop_remove_all((dev_info_t *)arg); 17853f7d54a6SGarrett D'Amore return (DDI_SUCCESS); 17863f7d54a6SGarrett D'Amore 17873f7d54a6SGarrett D'Amore default: 17883f7d54a6SGarrett D'Amore return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 17893f7d54a6SGarrett D'Amore } 17903f7d54a6SGarrett D'Amore } 17913f7d54a6SGarrett D'Amore 17923f7d54a6SGarrett D'Amore /* 17933f7d54a6SGarrett D'Amore * Functions for device drivers. 17943f7d54a6SGarrett D'Amore */ 17953f7d54a6SGarrett D'Amore bd_handle_t 17963f7d54a6SGarrett D'Amore bd_alloc_handle(void *private, bd_ops_t *ops, ddi_dma_attr_t *dma, int kmflag) 17973f7d54a6SGarrett D'Amore { 17983f7d54a6SGarrett D'Amore bd_handle_t hdl; 17993f7d54a6SGarrett D'Amore 18003f7d54a6SGarrett D'Amore hdl = kmem_zalloc(sizeof (*hdl), kmflag); 18013f7d54a6SGarrett D'Amore if (hdl != NULL) { 18023f7d54a6SGarrett D'Amore hdl->h_ops = *ops; 18033f7d54a6SGarrett D'Amore hdl->h_dma = dma; 18043f7d54a6SGarrett D'Amore hdl->h_private = private; 18053f7d54a6SGarrett D'Amore } 18063f7d54a6SGarrett D'Amore 18073f7d54a6SGarrett D'Amore return (hdl); 18083f7d54a6SGarrett D'Amore } 18093f7d54a6SGarrett D'Amore 18103f7d54a6SGarrett D'Amore void 18113f7d54a6SGarrett D'Amore bd_free_handle(bd_handle_t hdl) 18123f7d54a6SGarrett D'Amore { 18133f7d54a6SGarrett D'Amore kmem_free(hdl, sizeof (*hdl)); 18143f7d54a6SGarrett D'Amore } 18153f7d54a6SGarrett D'Amore 18163f7d54a6SGarrett D'Amore int 18173f7d54a6SGarrett D'Amore bd_attach_handle(dev_info_t *dip, bd_handle_t hdl) 18183f7d54a6SGarrett D'Amore { 18193f7d54a6SGarrett D'Amore dev_info_t *child; 1820510a6847SHans Rosenfeld bd_drive_t drive = { 0 }; 18213f7d54a6SGarrett D'Amore 1822*ecee5a1fSHans Rosenfeld /* 1823*ecee5a1fSHans Rosenfeld * It's not an error if bd_attach_handle() is called on a handle that 1824*ecee5a1fSHans Rosenfeld * already is attached. We just ignore the request to attach and return. 1825*ecee5a1fSHans Rosenfeld * This way drivers using blkdev don't have to keep track about blkdev 1826*ecee5a1fSHans Rosenfeld * state, they can just call this function to make sure it attached. 1827*ecee5a1fSHans Rosenfeld */ 1828*ecee5a1fSHans Rosenfeld if (hdl->h_child != NULL) { 1829*ecee5a1fSHans Rosenfeld return (DDI_SUCCESS); 1830*ecee5a1fSHans Rosenfeld } 1831*ecee5a1fSHans Rosenfeld 18323f7d54a6SGarrett D'Amore /* if drivers don't override this, make it assume none */ 18333f7d54a6SGarrett D'Amore drive.d_lun = -1; 18343f7d54a6SGarrett D'Amore hdl->h_ops.o_drive_info(hdl->h_private, &drive); 18353f7d54a6SGarrett D'Amore 18363f7d54a6SGarrett D'Amore hdl->h_parent = dip; 18373f7d54a6SGarrett D'Amore hdl->h_name = "blkdev"; 18383f7d54a6SGarrett D'Amore 1839fa27e351SHans Rosenfeld /*LINTED: E_BAD_PTR_CAST_ALIGN*/ 1840fa27e351SHans Rosenfeld if (*(uint64_t *)drive.d_eui64 != 0) { 18413f7d54a6SGarrett D'Amore if (drive.d_lun >= 0) { 1842fa27e351SHans Rosenfeld (void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), 1843fa27e351SHans Rosenfeld "w%02X%02X%02X%02X%02X%02X%02X%02X,%X", 1844fa27e351SHans Rosenfeld drive.d_eui64[0], drive.d_eui64[1], 1845fa27e351SHans Rosenfeld drive.d_eui64[2], drive.d_eui64[3], 1846fa27e351SHans Rosenfeld drive.d_eui64[4], drive.d_eui64[5], 1847fa27e351SHans Rosenfeld drive.d_eui64[6], drive.d_eui64[7], drive.d_lun); 18483f7d54a6SGarrett D'Amore } else { 1849fa27e351SHans Rosenfeld (void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), 1850fa27e351SHans Rosenfeld "w%02X%02X%02X%02X%02X%02X%02X%02X", 1851fa27e351SHans Rosenfeld drive.d_eui64[0], drive.d_eui64[1], 1852fa27e351SHans Rosenfeld drive.d_eui64[2], drive.d_eui64[3], 1853fa27e351SHans Rosenfeld drive.d_eui64[4], drive.d_eui64[5], 1854fa27e351SHans Rosenfeld drive.d_eui64[6], drive.d_eui64[7]); 18553f7d54a6SGarrett D'Amore } 1856fa27e351SHans Rosenfeld } else { 1857fa27e351SHans Rosenfeld if (drive.d_lun >= 0) { 1858fa27e351SHans Rosenfeld (void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), 1859fa27e351SHans Rosenfeld "%X,%X", drive.d_target, drive.d_lun); 1860fa27e351SHans Rosenfeld } else { 1861fa27e351SHans Rosenfeld (void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), 1862fa27e351SHans Rosenfeld "%X", drive.d_target); 1863fa27e351SHans Rosenfeld } 1864fa27e351SHans Rosenfeld } 1865fa27e351SHans Rosenfeld 18663f7d54a6SGarrett D'Amore if (ndi_devi_alloc(dip, hdl->h_name, (pnode_t)DEVI_SID_NODEID, 18673f7d54a6SGarrett D'Amore &child) != NDI_SUCCESS) { 18683f7d54a6SGarrett D'Amore cmn_err(CE_WARN, "%s%d: unable to allocate node %s@%s", 18693f7d54a6SGarrett D'Amore ddi_driver_name(dip), ddi_get_instance(dip), 18703f7d54a6SGarrett D'Amore "blkdev", hdl->h_addr); 18713f7d54a6SGarrett D'Amore return (DDI_FAILURE); 18723f7d54a6SGarrett D'Amore } 18733f7d54a6SGarrett D'Amore 18743f7d54a6SGarrett D'Amore ddi_set_parent_data(child, hdl); 18753f7d54a6SGarrett D'Amore hdl->h_child = child; 18763f7d54a6SGarrett D'Amore 18773f7d54a6SGarrett D'Amore if (ndi_devi_online(child, 0) == NDI_FAILURE) { 18783f7d54a6SGarrett D'Amore cmn_err(CE_WARN, "%s%d: failed bringing node %s@%s online", 18793f7d54a6SGarrett D'Amore ddi_driver_name(dip), ddi_get_instance(dip), 18803f7d54a6SGarrett D'Amore hdl->h_name, hdl->h_addr); 18813f7d54a6SGarrett D'Amore (void) ndi_devi_free(child); 18823f7d54a6SGarrett D'Amore return (DDI_FAILURE); 18833f7d54a6SGarrett D'Amore } 18843f7d54a6SGarrett D'Amore 18853f7d54a6SGarrett D'Amore return (DDI_SUCCESS); 18863f7d54a6SGarrett D'Amore } 18873f7d54a6SGarrett D'Amore 18883f7d54a6SGarrett D'Amore int 18893f7d54a6SGarrett D'Amore bd_detach_handle(bd_handle_t hdl) 18903f7d54a6SGarrett D'Amore { 18913f7d54a6SGarrett D'Amore int circ; 18923f7d54a6SGarrett D'Amore int rv; 18933f7d54a6SGarrett D'Amore char *devnm; 18943f7d54a6SGarrett D'Amore 1895*ecee5a1fSHans Rosenfeld /* 1896*ecee5a1fSHans Rosenfeld * It's not an error if bd_detach_handle() is called on a handle that 1897*ecee5a1fSHans Rosenfeld * already is detached. We just ignore the request to detach and return. 1898*ecee5a1fSHans Rosenfeld * This way drivers using blkdev don't have to keep track about blkdev 1899*ecee5a1fSHans Rosenfeld * state, they can just call this function to make sure it detached. 1900*ecee5a1fSHans Rosenfeld */ 19013f7d54a6SGarrett D'Amore if (hdl->h_child == NULL) { 19023f7d54a6SGarrett D'Amore return (DDI_SUCCESS); 19033f7d54a6SGarrett D'Amore } 19043f7d54a6SGarrett D'Amore ndi_devi_enter(hdl->h_parent, &circ); 19053f7d54a6SGarrett D'Amore if (i_ddi_node_state(hdl->h_child) < DS_INITIALIZED) { 19063f7d54a6SGarrett D'Amore rv = ddi_remove_child(hdl->h_child, 0); 19073f7d54a6SGarrett D'Amore } else { 19083f7d54a6SGarrett D'Amore devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP); 19093f7d54a6SGarrett D'Amore (void) ddi_deviname(hdl->h_child, devnm); 19103f7d54a6SGarrett D'Amore (void) devfs_clean(hdl->h_parent, devnm + 1, DV_CLEAN_FORCE); 19113f7d54a6SGarrett D'Amore rv = ndi_devi_unconfig_one(hdl->h_parent, devnm + 1, NULL, 19123f7d54a6SGarrett D'Amore NDI_DEVI_REMOVE | NDI_UNCONFIG); 19133f7d54a6SGarrett D'Amore kmem_free(devnm, MAXNAMELEN + 1); 19143f7d54a6SGarrett D'Amore } 19153f7d54a6SGarrett D'Amore if (rv == 0) { 19163f7d54a6SGarrett D'Amore hdl->h_child = NULL; 19173f7d54a6SGarrett D'Amore } 19183f7d54a6SGarrett D'Amore 19193f7d54a6SGarrett D'Amore ndi_devi_exit(hdl->h_parent, circ); 1920aad3a447SHans Rosenfeld return (rv == NDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE); 19213f7d54a6SGarrett D'Amore } 19223f7d54a6SGarrett D'Amore 19233f7d54a6SGarrett D'Amore void 19243f7d54a6SGarrett D'Amore bd_xfer_done(bd_xfer_t *xfer, int err) 19253f7d54a6SGarrett D'Amore { 19263f7d54a6SGarrett D'Amore bd_xfer_impl_t *xi = (void *)xfer; 19273f7d54a6SGarrett D'Amore buf_t *bp = xi->i_bp; 192806711e0cSDmitry Yusupov int rv = DDI_SUCCESS; 19293f7d54a6SGarrett D'Amore bd_t *bd = xi->i_bd; 19303f7d54a6SGarrett D'Amore size_t len; 19313f7d54a6SGarrett D'Amore 19323f7d54a6SGarrett D'Amore if (err != 0) { 19333f7d54a6SGarrett D'Amore bd_runq_exit(xi, err); 1934bef9e21aSHans Rosenfeld atomic_inc_32(&bd->d_kerr->bd_harderrs.value.ui32); 19353f7d54a6SGarrett D'Amore 19363f7d54a6SGarrett D'Amore bp->b_resid += xi->i_resid; 19373f7d54a6SGarrett D'Amore bd_xfer_free(xi); 19383f7d54a6SGarrett D'Amore bioerror(bp, err); 19393f7d54a6SGarrett D'Amore biodone(bp); 19403f7d54a6SGarrett D'Amore return; 19413f7d54a6SGarrett D'Amore } 19423f7d54a6SGarrett D'Amore 19433f7d54a6SGarrett D'Amore xi->i_cur_win++; 19443f7d54a6SGarrett D'Amore xi->i_resid -= xi->i_len; 19453f7d54a6SGarrett D'Amore 19463f7d54a6SGarrett D'Amore if (xi->i_resid == 0) { 19473f7d54a6SGarrett D'Amore /* Job completed succcessfully! */ 19483f7d54a6SGarrett D'Amore bd_runq_exit(xi, 0); 19493f7d54a6SGarrett D'Amore 19503f7d54a6SGarrett D'Amore bd_xfer_free(xi); 19513f7d54a6SGarrett D'Amore biodone(bp); 19523f7d54a6SGarrett D'Amore return; 19533f7d54a6SGarrett D'Amore } 19543f7d54a6SGarrett D'Amore 19553f7d54a6SGarrett D'Amore xi->i_blkno += xi->i_nblks; 19563f7d54a6SGarrett D'Amore 19573f7d54a6SGarrett D'Amore if (bd->d_use_dma) { 19583f7d54a6SGarrett D'Amore /* More transfer still pending... advance to next DMA window. */ 19593f7d54a6SGarrett D'Amore rv = ddi_dma_getwin(xi->i_dmah, xi->i_cur_win, 19603f7d54a6SGarrett D'Amore &xi->i_offset, &len, &xi->i_dmac, &xi->i_ndmac); 19613f7d54a6SGarrett D'Amore } else { 19623f7d54a6SGarrett D'Amore /* Advance memory window. */ 19633f7d54a6SGarrett D'Amore xi->i_kaddr += xi->i_len; 19643f7d54a6SGarrett D'Amore xi->i_offset += xi->i_len; 19653f7d54a6SGarrett D'Amore len = min(bp->b_bcount - xi->i_offset, bd->d_maxxfer); 19663f7d54a6SGarrett D'Amore } 19673f7d54a6SGarrett D'Amore 19683f7d54a6SGarrett D'Amore 19693f7d54a6SGarrett D'Amore if ((rv != DDI_SUCCESS) || 197010624986SYouzhong Yang (P2PHASE(len, (1U << xi->i_blkshift)) != 0)) { 19713f7d54a6SGarrett D'Amore bd_runq_exit(xi, EFAULT); 19723f7d54a6SGarrett D'Amore 19733f7d54a6SGarrett D'Amore bp->b_resid += xi->i_resid; 19743f7d54a6SGarrett D'Amore bd_xfer_free(xi); 19753f7d54a6SGarrett D'Amore bioerror(bp, EFAULT); 19763f7d54a6SGarrett D'Amore biodone(bp); 19773f7d54a6SGarrett D'Amore return; 19783f7d54a6SGarrett D'Amore } 19793f7d54a6SGarrett D'Amore xi->i_len = len; 19803f7d54a6SGarrett D'Amore xi->i_nblks = len >> xi->i_blkshift; 19813f7d54a6SGarrett D'Amore 19823f7d54a6SGarrett D'Amore /* Submit next window to hardware. */ 19833f7d54a6SGarrett D'Amore rv = xi->i_func(bd->d_private, &xi->i_public); 19843f7d54a6SGarrett D'Amore if (rv != 0) { 19853f7d54a6SGarrett D'Amore bd_runq_exit(xi, rv); 19863f7d54a6SGarrett D'Amore 1987bef9e21aSHans Rosenfeld atomic_inc_32(&bd->d_kerr->bd_transerrs.value.ui32); 1988bef9e21aSHans Rosenfeld 19893f7d54a6SGarrett D'Amore bp->b_resid += xi->i_resid; 19903f7d54a6SGarrett D'Amore bd_xfer_free(xi); 19913f7d54a6SGarrett D'Amore bioerror(bp, rv); 19923f7d54a6SGarrett D'Amore biodone(bp); 19933f7d54a6SGarrett D'Amore } 19943f7d54a6SGarrett D'Amore } 19953f7d54a6SGarrett D'Amore 19963f7d54a6SGarrett D'Amore void 1997bef9e21aSHans Rosenfeld bd_error(bd_xfer_t *xfer, int error) 1998bef9e21aSHans Rosenfeld { 1999bef9e21aSHans Rosenfeld bd_xfer_impl_t *xi = (void *)xfer; 2000bef9e21aSHans Rosenfeld bd_t *bd = xi->i_bd; 2001bef9e21aSHans Rosenfeld 2002bef9e21aSHans Rosenfeld switch (error) { 2003bef9e21aSHans Rosenfeld case BD_ERR_MEDIA: 2004bef9e21aSHans Rosenfeld atomic_inc_32(&bd->d_kerr->bd_rq_media_err.value.ui32); 2005bef9e21aSHans Rosenfeld break; 2006bef9e21aSHans Rosenfeld case BD_ERR_NTRDY: 2007bef9e21aSHans Rosenfeld atomic_inc_32(&bd->d_kerr->bd_rq_ntrdy_err.value.ui32); 2008bef9e21aSHans Rosenfeld break; 2009bef9e21aSHans Rosenfeld case BD_ERR_NODEV: 2010bef9e21aSHans Rosenfeld atomic_inc_32(&bd->d_kerr->bd_rq_nodev_err.value.ui32); 2011bef9e21aSHans Rosenfeld break; 2012bef9e21aSHans Rosenfeld case BD_ERR_RECOV: 2013bef9e21aSHans Rosenfeld atomic_inc_32(&bd->d_kerr->bd_rq_recov_err.value.ui32); 2014bef9e21aSHans Rosenfeld break; 2015bef9e21aSHans Rosenfeld case BD_ERR_ILLRQ: 2016bef9e21aSHans Rosenfeld atomic_inc_32(&bd->d_kerr->bd_rq_illrq_err.value.ui32); 2017bef9e21aSHans Rosenfeld break; 2018bef9e21aSHans Rosenfeld case BD_ERR_PFA: 2019bef9e21aSHans Rosenfeld atomic_inc_32(&bd->d_kerr->bd_rq_pfa_err.value.ui32); 2020bef9e21aSHans Rosenfeld break; 2021bef9e21aSHans Rosenfeld default: 2022bef9e21aSHans Rosenfeld cmn_err(CE_PANIC, "bd_error: unknown error type %d", error); 2023bef9e21aSHans Rosenfeld break; 2024bef9e21aSHans Rosenfeld } 2025bef9e21aSHans Rosenfeld } 2026bef9e21aSHans Rosenfeld 2027bef9e21aSHans Rosenfeld void 20283f7d54a6SGarrett D'Amore bd_state_change(bd_handle_t hdl) 20293f7d54a6SGarrett D'Amore { 20303f7d54a6SGarrett D'Amore bd_t *bd; 20313f7d54a6SGarrett D'Amore 20323f7d54a6SGarrett D'Amore if ((bd = hdl->h_bd) != NULL) { 20333f7d54a6SGarrett D'Amore bd_update_state(bd); 20343f7d54a6SGarrett D'Amore } 20353f7d54a6SGarrett D'Amore } 20363f7d54a6SGarrett D'Amore 20373f7d54a6SGarrett D'Amore void 20383f7d54a6SGarrett D'Amore bd_mod_init(struct dev_ops *devops) 20393f7d54a6SGarrett D'Amore { 20403f7d54a6SGarrett D'Amore static struct bus_ops bd_bus_ops = { 20413f7d54a6SGarrett D'Amore BUSO_REV, /* busops_rev */ 20423f7d54a6SGarrett D'Amore nullbusmap, /* bus_map */ 20433f7d54a6SGarrett D'Amore NULL, /* bus_get_intrspec (OBSOLETE) */ 20443f7d54a6SGarrett D'Amore NULL, /* bus_add_intrspec (OBSOLETE) */ 20453f7d54a6SGarrett D'Amore NULL, /* bus_remove_intrspec (OBSOLETE) */ 20463f7d54a6SGarrett D'Amore i_ddi_map_fault, /* bus_map_fault */ 2047cd21e7c5SGarrett D'Amore NULL, /* bus_dma_map (OBSOLETE) */ 20483f7d54a6SGarrett D'Amore ddi_dma_allochdl, /* bus_dma_allochdl */ 20493f7d54a6SGarrett D'Amore ddi_dma_freehdl, /* bus_dma_freehdl */ 20503f7d54a6SGarrett D'Amore ddi_dma_bindhdl, /* bus_dma_bindhdl */ 20513f7d54a6SGarrett D'Amore ddi_dma_unbindhdl, /* bus_dma_unbindhdl */ 20523f7d54a6SGarrett D'Amore ddi_dma_flush, /* bus_dma_flush */ 20533f7d54a6SGarrett D'Amore ddi_dma_win, /* bus_dma_win */ 20543f7d54a6SGarrett D'Amore ddi_dma_mctl, /* bus_dma_ctl */ 20553f7d54a6SGarrett D'Amore bd_bus_ctl, /* bus_ctl */ 20563f7d54a6SGarrett D'Amore ddi_bus_prop_op, /* bus_prop_op */ 20573f7d54a6SGarrett D'Amore NULL, /* bus_get_eventcookie */ 20583f7d54a6SGarrett D'Amore NULL, /* bus_add_eventcall */ 20593f7d54a6SGarrett D'Amore NULL, /* bus_remove_eventcall */ 20603f7d54a6SGarrett D'Amore NULL, /* bus_post_event */ 20613f7d54a6SGarrett D'Amore NULL, /* bus_intr_ctl (OBSOLETE) */ 20623f7d54a6SGarrett D'Amore NULL, /* bus_config */ 20633f7d54a6SGarrett D'Amore NULL, /* bus_unconfig */ 20643f7d54a6SGarrett D'Amore NULL, /* bus_fm_init */ 20653f7d54a6SGarrett D'Amore NULL, /* bus_fm_fini */ 20663f7d54a6SGarrett D'Amore NULL, /* bus_fm_access_enter */ 20673f7d54a6SGarrett D'Amore NULL, /* bus_fm_access_exit */ 20683f7d54a6SGarrett D'Amore NULL, /* bus_power */ 20693f7d54a6SGarrett D'Amore NULL, /* bus_intr_op */ 20703f7d54a6SGarrett D'Amore }; 20713f7d54a6SGarrett D'Amore 20723f7d54a6SGarrett D'Amore devops->devo_bus_ops = &bd_bus_ops; 20733f7d54a6SGarrett D'Amore 20743f7d54a6SGarrett D'Amore /* 20753f7d54a6SGarrett D'Amore * NB: The device driver is free to supply its own 20763f7d54a6SGarrett D'Amore * character entry device support. 20773f7d54a6SGarrett D'Amore */ 20783f7d54a6SGarrett D'Amore } 20793f7d54a6SGarrett D'Amore 20803f7d54a6SGarrett D'Amore void 20813f7d54a6SGarrett D'Amore bd_mod_fini(struct dev_ops *devops) 20823f7d54a6SGarrett D'Amore { 20833f7d54a6SGarrett D'Amore devops->devo_bus_ops = NULL; 20843f7d54a6SGarrett D'Amore } 2085