xref: /onnv-gate/usr/src/uts/common/io/blkdev/blkdev.c (revision 12426:cdff5d2ea989)
1*12426Sgdamore@opensolaris.org /*
2*12426Sgdamore@opensolaris.org  * CDDL HEADER START
3*12426Sgdamore@opensolaris.org  *
4*12426Sgdamore@opensolaris.org  * The contents of this file are subject to the terms of the
5*12426Sgdamore@opensolaris.org  * Common Development and Distribution License (the "License").
6*12426Sgdamore@opensolaris.org  * You may not use this file except in compliance with the License.
7*12426Sgdamore@opensolaris.org  *
8*12426Sgdamore@opensolaris.org  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12426Sgdamore@opensolaris.org  * or http://www.opensolaris.org/os/licensing.
10*12426Sgdamore@opensolaris.org  * See the License for the specific language governing permissions
11*12426Sgdamore@opensolaris.org  * and limitations under the License.
12*12426Sgdamore@opensolaris.org  *
13*12426Sgdamore@opensolaris.org  * When distributing Covered Code, include this CDDL HEADER in each
14*12426Sgdamore@opensolaris.org  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12426Sgdamore@opensolaris.org  * If applicable, add the following below this CDDL HEADER, with the
16*12426Sgdamore@opensolaris.org  * fields enclosed by brackets "[]" replaced with your own identifying
17*12426Sgdamore@opensolaris.org  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12426Sgdamore@opensolaris.org  *
19*12426Sgdamore@opensolaris.org  * CDDL HEADER END
20*12426Sgdamore@opensolaris.org  */
21*12426Sgdamore@opensolaris.org /*
22*12426Sgdamore@opensolaris.org  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23*12426Sgdamore@opensolaris.org  */
24*12426Sgdamore@opensolaris.org 
25*12426Sgdamore@opensolaris.org #include <sys/types.h>
26*12426Sgdamore@opensolaris.org #include <sys/ksynch.h>
27*12426Sgdamore@opensolaris.org #include <sys/kmem.h>
28*12426Sgdamore@opensolaris.org #include <sys/file.h>
29*12426Sgdamore@opensolaris.org #include <sys/errno.h>
30*12426Sgdamore@opensolaris.org #include <sys/open.h>
31*12426Sgdamore@opensolaris.org #include <sys/buf.h>
32*12426Sgdamore@opensolaris.org #include <sys/uio.h>
33*12426Sgdamore@opensolaris.org #include <sys/aio_req.h>
34*12426Sgdamore@opensolaris.org #include <sys/cred.h>
35*12426Sgdamore@opensolaris.org #include <sys/modctl.h>
36*12426Sgdamore@opensolaris.org #include <sys/cmlb.h>
37*12426Sgdamore@opensolaris.org #include <sys/conf.h>
38*12426Sgdamore@opensolaris.org #include <sys/devops.h>
39*12426Sgdamore@opensolaris.org #include <sys/list.h>
40*12426Sgdamore@opensolaris.org #include <sys/sysmacros.h>
41*12426Sgdamore@opensolaris.org #include <sys/dkio.h>
42*12426Sgdamore@opensolaris.org #include <sys/vtoc.h>
43*12426Sgdamore@opensolaris.org #include <sys/scsi/scsi.h>	/* for DTYPE_DIRECT */
44*12426Sgdamore@opensolaris.org #include <sys/kstat.h>
45*12426Sgdamore@opensolaris.org #include <sys/fs/dv_node.h>
46*12426Sgdamore@opensolaris.org #include <sys/ddi.h>
47*12426Sgdamore@opensolaris.org #include <sys/sunddi.h>
48*12426Sgdamore@opensolaris.org #include <sys/note.h>
49*12426Sgdamore@opensolaris.org #include <sys/blkdev.h>
50*12426Sgdamore@opensolaris.org 
51*12426Sgdamore@opensolaris.org #define	BD_MAXPART	64
52*12426Sgdamore@opensolaris.org #define	BDINST(dev)	(getminor(dev) / BD_MAXPART)
53*12426Sgdamore@opensolaris.org #define	BDPART(dev)	(getminor(dev) % BD_MAXPART)
54*12426Sgdamore@opensolaris.org 
55*12426Sgdamore@opensolaris.org typedef struct bd bd_t;
56*12426Sgdamore@opensolaris.org typedef struct bd_xfer_impl bd_xfer_impl_t;
57*12426Sgdamore@opensolaris.org 
58*12426Sgdamore@opensolaris.org struct bd {
59*12426Sgdamore@opensolaris.org 	void		*d_private;
60*12426Sgdamore@opensolaris.org 	dev_info_t	*d_dip;
61*12426Sgdamore@opensolaris.org 	kmutex_t	d_ocmutex;
62*12426Sgdamore@opensolaris.org 	kmutex_t	d_iomutex;
63*12426Sgdamore@opensolaris.org 	kmutex_t	d_statemutex;
64*12426Sgdamore@opensolaris.org 	kcondvar_t	d_statecv;
65*12426Sgdamore@opensolaris.org 	enum dkio_state	d_state;
66*12426Sgdamore@opensolaris.org 	cmlb_handle_t	d_cmlbh;
67*12426Sgdamore@opensolaris.org 	unsigned	d_open_lyr[BD_MAXPART];	/* open count */
68*12426Sgdamore@opensolaris.org 	uint64_t	d_open_excl;	/* bit mask indexed by partition */
69*12426Sgdamore@opensolaris.org 	uint64_t	d_open_reg[OTYPCNT];		/* bit mask */
70*12426Sgdamore@opensolaris.org 
71*12426Sgdamore@opensolaris.org 	uint32_t	d_qsize;
72*12426Sgdamore@opensolaris.org 	uint32_t	d_qactive;
73*12426Sgdamore@opensolaris.org 	uint32_t	d_maxxfer;
74*12426Sgdamore@opensolaris.org 	uint32_t	d_blkshift;
75*12426Sgdamore@opensolaris.org 	uint64_t	d_numblks;
76*12426Sgdamore@opensolaris.org 	ddi_devid_t	d_devid;
77*12426Sgdamore@opensolaris.org 
78*12426Sgdamore@opensolaris.org 	kmem_cache_t	*d_cache;
79*12426Sgdamore@opensolaris.org 	list_t		d_runq;
80*12426Sgdamore@opensolaris.org 	list_t		d_waitq;
81*12426Sgdamore@opensolaris.org 	kstat_t		*d_ksp;
82*12426Sgdamore@opensolaris.org 	kstat_io_t	*d_kiop;
83*12426Sgdamore@opensolaris.org 
84*12426Sgdamore@opensolaris.org 	boolean_t	d_rdonly;
85*12426Sgdamore@opensolaris.org 	boolean_t	d_removable;
86*12426Sgdamore@opensolaris.org 	boolean_t	d_hotpluggable;
87*12426Sgdamore@opensolaris.org 	boolean_t	d_use_dma;
88*12426Sgdamore@opensolaris.org 
89*12426Sgdamore@opensolaris.org 	ddi_dma_attr_t	d_dma;
90*12426Sgdamore@opensolaris.org 	bd_ops_t	d_ops;
91*12426Sgdamore@opensolaris.org 	bd_handle_t	d_handle;
92*12426Sgdamore@opensolaris.org };
93*12426Sgdamore@opensolaris.org 
94*12426Sgdamore@opensolaris.org struct bd_handle {
95*12426Sgdamore@opensolaris.org 	bd_ops_t	h_ops;
96*12426Sgdamore@opensolaris.org 	ddi_dma_attr_t	*h_dma;
97*12426Sgdamore@opensolaris.org 	dev_info_t	*h_parent;
98*12426Sgdamore@opensolaris.org 	dev_info_t	*h_child;
99*12426Sgdamore@opensolaris.org 	void		*h_private;
100*12426Sgdamore@opensolaris.org 	bd_t		*h_bd;
101*12426Sgdamore@opensolaris.org 	char		*h_name;
102*12426Sgdamore@opensolaris.org 	char		h_addr[20];	/* enough for %X,%X */
103*12426Sgdamore@opensolaris.org };
104*12426Sgdamore@opensolaris.org 
105*12426Sgdamore@opensolaris.org struct bd_xfer_impl {
106*12426Sgdamore@opensolaris.org 	bd_xfer_t	i_public;
107*12426Sgdamore@opensolaris.org 	list_node_t	i_linkage;
108*12426Sgdamore@opensolaris.org 	bd_t		*i_bd;
109*12426Sgdamore@opensolaris.org 	buf_t		*i_bp;
110*12426Sgdamore@opensolaris.org 	uint_t		i_num_win;
111*12426Sgdamore@opensolaris.org 	uint_t		i_cur_win;
112*12426Sgdamore@opensolaris.org 	off_t		i_offset;
113*12426Sgdamore@opensolaris.org 	int		(*i_func)(void *, bd_xfer_t *);
114*12426Sgdamore@opensolaris.org 	uint32_t	i_blkshift;
115*12426Sgdamore@opensolaris.org 	size_t		i_len;
116*12426Sgdamore@opensolaris.org 	size_t		i_resid;
117*12426Sgdamore@opensolaris.org };
118*12426Sgdamore@opensolaris.org 
119*12426Sgdamore@opensolaris.org #define	i_dmah		i_public.x_dmah
120*12426Sgdamore@opensolaris.org #define	i_dmac		i_public.x_dmac
121*12426Sgdamore@opensolaris.org #define	i_ndmac		i_public.x_ndmac
122*12426Sgdamore@opensolaris.org #define	i_kaddr		i_public.x_kaddr
123*12426Sgdamore@opensolaris.org #define	i_nblks		i_public.x_nblks
124*12426Sgdamore@opensolaris.org #define	i_blkno		i_public.x_blkno
125*12426Sgdamore@opensolaris.org 
126*12426Sgdamore@opensolaris.org 
127*12426Sgdamore@opensolaris.org /*
128*12426Sgdamore@opensolaris.org  * Private prototypes.
129*12426Sgdamore@opensolaris.org  */
130*12426Sgdamore@opensolaris.org 
131*12426Sgdamore@opensolaris.org static int bd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
132*12426Sgdamore@opensolaris.org static int bd_attach(dev_info_t *, ddi_attach_cmd_t);
133*12426Sgdamore@opensolaris.org static int bd_detach(dev_info_t *, ddi_detach_cmd_t);
134*12426Sgdamore@opensolaris.org 
135*12426Sgdamore@opensolaris.org static int bd_open(dev_t *, int, int, cred_t *);
136*12426Sgdamore@opensolaris.org static int bd_close(dev_t, int, int, cred_t *);
137*12426Sgdamore@opensolaris.org static int bd_strategy(struct buf *);
138*12426Sgdamore@opensolaris.org static int bd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
139*12426Sgdamore@opensolaris.org static int bd_read(dev_t, struct uio *, cred_t *);
140*12426Sgdamore@opensolaris.org static int bd_write(dev_t, struct uio *, cred_t *);
141*12426Sgdamore@opensolaris.org static int bd_aread(dev_t, struct aio_req *, cred_t *);
142*12426Sgdamore@opensolaris.org static int bd_awrite(dev_t, struct aio_req *, cred_t *);
143*12426Sgdamore@opensolaris.org static int bd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
144*12426Sgdamore@opensolaris.org     caddr_t, int *);
145*12426Sgdamore@opensolaris.org 
146*12426Sgdamore@opensolaris.org static int bd_tg_rdwr(dev_info_t *, uchar_t, void *, diskaddr_t, size_t,
147*12426Sgdamore@opensolaris.org     void *);
148*12426Sgdamore@opensolaris.org static int bd_tg_getinfo(dev_info_t *, int, void *, void *);
149*12426Sgdamore@opensolaris.org static int bd_xfer_ctor(void *, void *, int);
150*12426Sgdamore@opensolaris.org static void bd_xfer_dtor(void *, void *);
151*12426Sgdamore@opensolaris.org static void bd_sched(bd_t *);
152*12426Sgdamore@opensolaris.org static void bd_submit(bd_t *, bd_xfer_impl_t *);
153*12426Sgdamore@opensolaris.org static void bd_runq_exit(bd_xfer_impl_t *, int);
154*12426Sgdamore@opensolaris.org static void bd_update_state(bd_t *);
155*12426Sgdamore@opensolaris.org static int bd_check_state(bd_t *, enum dkio_state *);
156*12426Sgdamore@opensolaris.org static int bd_flush_write_cache(bd_t *, struct dk_callback *);
157*12426Sgdamore@opensolaris.org 
158*12426Sgdamore@opensolaris.org struct cmlb_tg_ops bd_tg_ops = {
159*12426Sgdamore@opensolaris.org 	TG_DK_OPS_VERSION_1,
160*12426Sgdamore@opensolaris.org 	bd_tg_rdwr,
161*12426Sgdamore@opensolaris.org 	bd_tg_getinfo,
162*12426Sgdamore@opensolaris.org };
163*12426Sgdamore@opensolaris.org 
164*12426Sgdamore@opensolaris.org static struct cb_ops bd_cb_ops = {
165*12426Sgdamore@opensolaris.org 	bd_open, 		/* open */
166*12426Sgdamore@opensolaris.org 	bd_close, 		/* close */
167*12426Sgdamore@opensolaris.org 	bd_strategy, 		/* strategy */
168*12426Sgdamore@opensolaris.org 	nodev, 			/* print */
169*12426Sgdamore@opensolaris.org 	nodev,			/* dump */
170*12426Sgdamore@opensolaris.org 	bd_read, 		/* read */
171*12426Sgdamore@opensolaris.org 	bd_write, 		/* write */
172*12426Sgdamore@opensolaris.org 	bd_ioctl, 		/* ioctl */
173*12426Sgdamore@opensolaris.org 	nodev, 			/* devmap */
174*12426Sgdamore@opensolaris.org 	nodev, 			/* mmap */
175*12426Sgdamore@opensolaris.org 	nodev, 			/* segmap */
176*12426Sgdamore@opensolaris.org 	nochpoll, 		/* poll */
177*12426Sgdamore@opensolaris.org 	bd_prop_op, 		/* cb_prop_op */
178*12426Sgdamore@opensolaris.org 	0, 			/* streamtab  */
179*12426Sgdamore@opensolaris.org 	D_64BIT | D_MP,		/* Driver comaptibility flag */
180*12426Sgdamore@opensolaris.org 	CB_REV,			/* cb_rev */
181*12426Sgdamore@opensolaris.org 	bd_aread,		/* async read */
182*12426Sgdamore@opensolaris.org 	bd_awrite		/* async write */
183*12426Sgdamore@opensolaris.org };
184*12426Sgdamore@opensolaris.org 
185*12426Sgdamore@opensolaris.org struct dev_ops bd_dev_ops = {
186*12426Sgdamore@opensolaris.org 	DEVO_REV, 		/* devo_rev, */
187*12426Sgdamore@opensolaris.org 	0, 			/* refcnt  */
188*12426Sgdamore@opensolaris.org 	bd_getinfo,		/* getinfo */
189*12426Sgdamore@opensolaris.org 	nulldev, 		/* identify */
190*12426Sgdamore@opensolaris.org 	nulldev, 		/* probe */
191*12426Sgdamore@opensolaris.org 	bd_attach, 		/* attach */
192*12426Sgdamore@opensolaris.org 	bd_detach,		/* detach */
193*12426Sgdamore@opensolaris.org 	nodev, 			/* reset */
194*12426Sgdamore@opensolaris.org 	&bd_cb_ops, 		/* driver operations */
195*12426Sgdamore@opensolaris.org 	NULL,			/* bus operations */
196*12426Sgdamore@opensolaris.org 	NULL,			/* power */
197*12426Sgdamore@opensolaris.org 	ddi_quiesce_not_needed,	/* quiesce */
198*12426Sgdamore@opensolaris.org };
199*12426Sgdamore@opensolaris.org 
200*12426Sgdamore@opensolaris.org static struct modldrv modldrv = {
201*12426Sgdamore@opensolaris.org 	&mod_driverops,
202*12426Sgdamore@opensolaris.org 	"Generic Block Device",
203*12426Sgdamore@opensolaris.org 	&bd_dev_ops,
204*12426Sgdamore@opensolaris.org };
205*12426Sgdamore@opensolaris.org 
206*12426Sgdamore@opensolaris.org static struct modlinkage modlinkage = {
207*12426Sgdamore@opensolaris.org 	MODREV_1, { &modldrv, NULL }
208*12426Sgdamore@opensolaris.org };
209*12426Sgdamore@opensolaris.org 
210*12426Sgdamore@opensolaris.org static void *bd_state;
211*12426Sgdamore@opensolaris.org static krwlock_t bd_lock;
212*12426Sgdamore@opensolaris.org 
213*12426Sgdamore@opensolaris.org int
_init(void)214*12426Sgdamore@opensolaris.org _init(void)
215*12426Sgdamore@opensolaris.org {
216*12426Sgdamore@opensolaris.org 	int	rv;
217*12426Sgdamore@opensolaris.org 
218*12426Sgdamore@opensolaris.org 	rv = ddi_soft_state_init(&bd_state, sizeof (struct bd), 2);
219*12426Sgdamore@opensolaris.org 	if (rv != DDI_SUCCESS) {
220*12426Sgdamore@opensolaris.org 		return (rv);
221*12426Sgdamore@opensolaris.org 	}
222*12426Sgdamore@opensolaris.org 	rw_init(&bd_lock, NULL, RW_DRIVER, NULL);
223*12426Sgdamore@opensolaris.org 	rv = mod_install(&modlinkage);
224*12426Sgdamore@opensolaris.org 	if (rv != DDI_SUCCESS) {
225*12426Sgdamore@opensolaris.org 		rw_destroy(&bd_lock);
226*12426Sgdamore@opensolaris.org 		ddi_soft_state_fini(&bd_state);
227*12426Sgdamore@opensolaris.org 	}
228*12426Sgdamore@opensolaris.org 	return (rv);
229*12426Sgdamore@opensolaris.org }
230*12426Sgdamore@opensolaris.org 
231*12426Sgdamore@opensolaris.org int
_fini(void)232*12426Sgdamore@opensolaris.org _fini(void)
233*12426Sgdamore@opensolaris.org {
234*12426Sgdamore@opensolaris.org 	int	rv;
235*12426Sgdamore@opensolaris.org 
236*12426Sgdamore@opensolaris.org 	rv = mod_remove(&modlinkage);
237*12426Sgdamore@opensolaris.org 	if (rv == DDI_SUCCESS) {
238*12426Sgdamore@opensolaris.org 		rw_destroy(&bd_lock);
239*12426Sgdamore@opensolaris.org 		ddi_soft_state_fini(&bd_state);
240*12426Sgdamore@opensolaris.org 	}
241*12426Sgdamore@opensolaris.org 	return (rv);
242*12426Sgdamore@opensolaris.org }
243*12426Sgdamore@opensolaris.org 
244*12426Sgdamore@opensolaris.org int
_info(struct modinfo * modinfop)245*12426Sgdamore@opensolaris.org _info(struct modinfo *modinfop)
246*12426Sgdamore@opensolaris.org {
247*12426Sgdamore@opensolaris.org 	return (mod_info(&modlinkage, modinfop));
248*12426Sgdamore@opensolaris.org }
249*12426Sgdamore@opensolaris.org 
250*12426Sgdamore@opensolaris.org static int
bd_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)251*12426Sgdamore@opensolaris.org bd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
252*12426Sgdamore@opensolaris.org {
253*12426Sgdamore@opensolaris.org 	bd_t	*bd;
254*12426Sgdamore@opensolaris.org 	minor_t	inst;
255*12426Sgdamore@opensolaris.org 
256*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(dip));
257*12426Sgdamore@opensolaris.org 
258*12426Sgdamore@opensolaris.org 	inst = BDINST((dev_t)arg);
259*12426Sgdamore@opensolaris.org 
260*12426Sgdamore@opensolaris.org 	switch (cmd) {
261*12426Sgdamore@opensolaris.org 	case DDI_INFO_DEVT2DEVINFO:
262*12426Sgdamore@opensolaris.org 		bd = ddi_get_soft_state(bd_state, inst);
263*12426Sgdamore@opensolaris.org 		if (bd == NULL) {
264*12426Sgdamore@opensolaris.org 			return (DDI_FAILURE);
265*12426Sgdamore@opensolaris.org 		}
266*12426Sgdamore@opensolaris.org 		*resultp = (void *)bd->d_dip;
267*12426Sgdamore@opensolaris.org 		break;
268*12426Sgdamore@opensolaris.org 
269*12426Sgdamore@opensolaris.org 	case DDI_INFO_DEVT2INSTANCE:
270*12426Sgdamore@opensolaris.org 		*resultp = (void *)(intptr_t)inst;
271*12426Sgdamore@opensolaris.org 		break;
272*12426Sgdamore@opensolaris.org 
273*12426Sgdamore@opensolaris.org 	default:
274*12426Sgdamore@opensolaris.org 		return (DDI_FAILURE);
275*12426Sgdamore@opensolaris.org 	}
276*12426Sgdamore@opensolaris.org 	return (DDI_SUCCESS);
277*12426Sgdamore@opensolaris.org }
278*12426Sgdamore@opensolaris.org 
279*12426Sgdamore@opensolaris.org static int
bd_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)280*12426Sgdamore@opensolaris.org bd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
281*12426Sgdamore@opensolaris.org {
282*12426Sgdamore@opensolaris.org 	int		inst;
283*12426Sgdamore@opensolaris.org 	bd_handle_t	hdl;
284*12426Sgdamore@opensolaris.org 	bd_t		*bd;
285*12426Sgdamore@opensolaris.org 	bd_drive_t	drive;
286*12426Sgdamore@opensolaris.org 	int		rv;
287*12426Sgdamore@opensolaris.org 	char		name[16];
288*12426Sgdamore@opensolaris.org 	char		kcache[32];
289*12426Sgdamore@opensolaris.org 
290*12426Sgdamore@opensolaris.org 	switch (cmd) {
291*12426Sgdamore@opensolaris.org 	case DDI_ATTACH:
292*12426Sgdamore@opensolaris.org 		break;
293*12426Sgdamore@opensolaris.org 	case DDI_RESUME:
294*12426Sgdamore@opensolaris.org 		/* We don't do anything native for suspend/resume */
295*12426Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
296*12426Sgdamore@opensolaris.org 	default:
297*12426Sgdamore@opensolaris.org 		return (DDI_FAILURE);
298*12426Sgdamore@opensolaris.org 	}
299*12426Sgdamore@opensolaris.org 
300*12426Sgdamore@opensolaris.org 	inst = ddi_get_instance(dip);
301*12426Sgdamore@opensolaris.org 	hdl = ddi_get_parent_data(dip);
302*12426Sgdamore@opensolaris.org 
303*12426Sgdamore@opensolaris.org 	(void) snprintf(name, sizeof (name), "%s%d",
304*12426Sgdamore@opensolaris.org 	    ddi_driver_name(dip), ddi_get_instance(dip));
305*12426Sgdamore@opensolaris.org 	(void) snprintf(kcache, sizeof (kcache), "%s_xfer", name);
306*12426Sgdamore@opensolaris.org 
307*12426Sgdamore@opensolaris.org 	if (hdl == NULL) {
308*12426Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "%s: missing parent data!", name);
309*12426Sgdamore@opensolaris.org 		return (DDI_FAILURE);
310*12426Sgdamore@opensolaris.org 	}
311*12426Sgdamore@opensolaris.org 
312*12426Sgdamore@opensolaris.org 	if (ddi_soft_state_zalloc(bd_state, inst) != DDI_SUCCESS) {
313*12426Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "%s: unable to zalloc soft state!", name);
314*12426Sgdamore@opensolaris.org 		return (DDI_FAILURE);
315*12426Sgdamore@opensolaris.org 	}
316*12426Sgdamore@opensolaris.org 	bd = ddi_get_soft_state(bd_state, inst);
317*12426Sgdamore@opensolaris.org 
318*12426Sgdamore@opensolaris.org 	if (hdl->h_dma) {
319*12426Sgdamore@opensolaris.org 		bd->d_dma = *(hdl->h_dma);
320*12426Sgdamore@opensolaris.org 		bd->d_dma.dma_attr_granular =
321*12426Sgdamore@opensolaris.org 		    max(DEV_BSIZE, bd->d_dma.dma_attr_granular);
322*12426Sgdamore@opensolaris.org 		bd->d_use_dma = B_TRUE;
323*12426Sgdamore@opensolaris.org 
324*12426Sgdamore@opensolaris.org 		if (bd->d_maxxfer &&
325*12426Sgdamore@opensolaris.org 		    (bd->d_maxxfer != bd->d_dma.dma_attr_maxxfer)) {
326*12426Sgdamore@opensolaris.org 			cmn_err(CE_WARN,
327*12426Sgdamore@opensolaris.org 			    "%s: inconsistent maximum transfer size!",
328*12426Sgdamore@opensolaris.org 			    name);
329*12426Sgdamore@opensolaris.org 			/* We force it */
330*12426Sgdamore@opensolaris.org 			bd->d_maxxfer = bd->d_dma.dma_attr_maxxfer;
331*12426Sgdamore@opensolaris.org 		} else {
332*12426Sgdamore@opensolaris.org 			bd->d_maxxfer = bd->d_dma.dma_attr_maxxfer;
333*12426Sgdamore@opensolaris.org 		}
334*12426Sgdamore@opensolaris.org 	} else {
335*12426Sgdamore@opensolaris.org 		bd->d_use_dma = B_FALSE;
336*12426Sgdamore@opensolaris.org 		if (bd->d_maxxfer == 0) {
337*12426Sgdamore@opensolaris.org 			bd->d_maxxfer = 1024 * 1024;
338*12426Sgdamore@opensolaris.org 		}
339*12426Sgdamore@opensolaris.org 	}
340*12426Sgdamore@opensolaris.org 	bd->d_ops = hdl->h_ops;
341*12426Sgdamore@opensolaris.org 	bd->d_private = hdl->h_private;
342*12426Sgdamore@opensolaris.org 	bd->d_blkshift = 9;	/* 512 bytes, to start */
343*12426Sgdamore@opensolaris.org 
344*12426Sgdamore@opensolaris.org 	if (bd->d_maxxfer % DEV_BSIZE) {
345*12426Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "%s: maximum transfer misaligned!", name);
346*12426Sgdamore@opensolaris.org 		bd->d_maxxfer &= ~(DEV_BSIZE - 1);
347*12426Sgdamore@opensolaris.org 	}
348*12426Sgdamore@opensolaris.org 	if (bd->d_maxxfer < DEV_BSIZE) {
349*12426Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "%s: maximum transfer size too small!", name);
350*12426Sgdamore@opensolaris.org 		ddi_soft_state_free(bd_state, inst);
351*12426Sgdamore@opensolaris.org 		return (DDI_FAILURE);
352*12426Sgdamore@opensolaris.org 	}
353*12426Sgdamore@opensolaris.org 
354*12426Sgdamore@opensolaris.org 	bd->d_dip = dip;
355*12426Sgdamore@opensolaris.org 	bd->d_handle = hdl;
356*12426Sgdamore@opensolaris.org 	hdl->h_bd = bd;
357*12426Sgdamore@opensolaris.org 	ddi_set_driver_private(dip, bd);
358*12426Sgdamore@opensolaris.org 
359*12426Sgdamore@opensolaris.org 	mutex_init(&bd->d_iomutex, NULL, MUTEX_DRIVER, NULL);
360*12426Sgdamore@opensolaris.org 	mutex_init(&bd->d_ocmutex, NULL, MUTEX_DRIVER, NULL);
361*12426Sgdamore@opensolaris.org 	mutex_init(&bd->d_statemutex, NULL, MUTEX_DRIVER, NULL);
362*12426Sgdamore@opensolaris.org 	cv_init(&bd->d_statecv, NULL, CV_DRIVER, NULL);
363*12426Sgdamore@opensolaris.org 
364*12426Sgdamore@opensolaris.org 	list_create(&bd->d_waitq, sizeof (bd_xfer_impl_t),
365*12426Sgdamore@opensolaris.org 	    offsetof(struct bd_xfer_impl, i_linkage));
366*12426Sgdamore@opensolaris.org 	list_create(&bd->d_runq, sizeof (bd_xfer_impl_t),
367*12426Sgdamore@opensolaris.org 	    offsetof(struct bd_xfer_impl, i_linkage));
368*12426Sgdamore@opensolaris.org 
369*12426Sgdamore@opensolaris.org 	bd->d_cache = kmem_cache_create(kcache, sizeof (bd_xfer_impl_t), 8,
370*12426Sgdamore@opensolaris.org 	    bd_xfer_ctor, bd_xfer_dtor, NULL, bd, NULL, 0);
371*12426Sgdamore@opensolaris.org 
372*12426Sgdamore@opensolaris.org 	bd->d_ksp = kstat_create(ddi_driver_name(dip), inst, NULL, "disk",
373*12426Sgdamore@opensolaris.org 	    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
374*12426Sgdamore@opensolaris.org 	if (bd->d_ksp != NULL) {
375*12426Sgdamore@opensolaris.org 		bd->d_ksp->ks_lock = &bd->d_iomutex;
376*12426Sgdamore@opensolaris.org 		kstat_install(bd->d_ksp);
377*12426Sgdamore@opensolaris.org 		bd->d_kiop = bd->d_ksp->ks_data;
378*12426Sgdamore@opensolaris.org 	} else {
379*12426Sgdamore@opensolaris.org 		/*
380*12426Sgdamore@opensolaris.org 		 * Even if we cannot create the kstat, we create a
381*12426Sgdamore@opensolaris.org 		 * scratch kstat.  The reason for this is to ensure
382*12426Sgdamore@opensolaris.org 		 * that we can update the kstat all of the time,
383*12426Sgdamore@opensolaris.org 		 * without adding an extra branch instruction.
384*12426Sgdamore@opensolaris.org 		 */
385*12426Sgdamore@opensolaris.org 		bd->d_kiop = kmem_zalloc(sizeof (kstat_io_t), KM_SLEEP);
386*12426Sgdamore@opensolaris.org 	}
387*12426Sgdamore@opensolaris.org 
388*12426Sgdamore@opensolaris.org 	cmlb_alloc_handle(&bd->d_cmlbh);
389*12426Sgdamore@opensolaris.org 
390*12426Sgdamore@opensolaris.org 	bd->d_state = DKIO_NONE;
391*12426Sgdamore@opensolaris.org 
392*12426Sgdamore@opensolaris.org 	bzero(&drive, sizeof (drive));
393*12426Sgdamore@opensolaris.org 	bd->d_ops.o_drive_info(bd->d_private, &drive);
394*12426Sgdamore@opensolaris.org 	bd->d_qsize = drive.d_qsize;
395*12426Sgdamore@opensolaris.org 	bd->d_maxxfer = drive.d_maxxfer;
396*12426Sgdamore@opensolaris.org 	bd->d_removable = drive.d_removable;
397*12426Sgdamore@opensolaris.org 	bd->d_hotpluggable = drive.d_hotpluggable;
398*12426Sgdamore@opensolaris.org 
399*12426Sgdamore@opensolaris.org 	rv = cmlb_attach(dip, &bd_tg_ops, DTYPE_DIRECT,
400*12426Sgdamore@opensolaris.org 	    bd->d_removable, bd->d_hotpluggable,
401*12426Sgdamore@opensolaris.org 	    drive.d_lun >= 0 ? DDI_NT_BLOCK_CHAN : DDI_NT_BLOCK,
402*12426Sgdamore@opensolaris.org 	    CMLB_FAKE_LABEL_ONE_PARTITION, bd->d_cmlbh, bd);
403*12426Sgdamore@opensolaris.org 	if (rv != 0) {
404*12426Sgdamore@opensolaris.org 		cmlb_free_handle(&bd->d_cmlbh);
405*12426Sgdamore@opensolaris.org 		kmem_cache_destroy(bd->d_cache);
406*12426Sgdamore@opensolaris.org 		mutex_destroy(&bd->d_iomutex);
407*12426Sgdamore@opensolaris.org 		mutex_destroy(&bd->d_ocmutex);
408*12426Sgdamore@opensolaris.org 		mutex_destroy(&bd->d_statemutex);
409*12426Sgdamore@opensolaris.org 		cv_destroy(&bd->d_statecv);
410*12426Sgdamore@opensolaris.org 		list_destroy(&bd->d_waitq);
411*12426Sgdamore@opensolaris.org 		list_destroy(&bd->d_runq);
412*12426Sgdamore@opensolaris.org 		if (bd->d_ksp != NULL) {
413*12426Sgdamore@opensolaris.org 			kstat_delete(bd->d_ksp);
414*12426Sgdamore@opensolaris.org 			bd->d_ksp = NULL;
415*12426Sgdamore@opensolaris.org 		} else {
416*12426Sgdamore@opensolaris.org 			kmem_free(bd->d_kiop, sizeof (kstat_io_t));
417*12426Sgdamore@opensolaris.org 		}
418*12426Sgdamore@opensolaris.org 		ddi_soft_state_free(bd_state, inst);
419*12426Sgdamore@opensolaris.org 		return (DDI_FAILURE);
420*12426Sgdamore@opensolaris.org 	}
421*12426Sgdamore@opensolaris.org 
422*12426Sgdamore@opensolaris.org 	if (bd->d_ops.o_devid_init != NULL) {
423*12426Sgdamore@opensolaris.org 		rv = bd->d_ops.o_devid_init(bd->d_private, dip, &bd->d_devid);
424*12426Sgdamore@opensolaris.org 		if (rv == DDI_SUCCESS) {
425*12426Sgdamore@opensolaris.org 			if (ddi_devid_register(dip, bd->d_devid) !=
426*12426Sgdamore@opensolaris.org 			    DDI_SUCCESS) {
427*12426Sgdamore@opensolaris.org 				cmn_err(CE_WARN,
428*12426Sgdamore@opensolaris.org 				    "%s: unable to register devid", name);
429*12426Sgdamore@opensolaris.org 			}
430*12426Sgdamore@opensolaris.org 		}
431*12426Sgdamore@opensolaris.org 	}
432*12426Sgdamore@opensolaris.org 
433*12426Sgdamore@opensolaris.org 	/*
434*12426Sgdamore@opensolaris.org 	 * Add a zero-length attribute to tell the world we support
435*12426Sgdamore@opensolaris.org 	 * kernel ioctls (for layered drivers).  Also set up properties
436*12426Sgdamore@opensolaris.org 	 * used by HAL to identify removable media.
437*12426Sgdamore@opensolaris.org 	 */
438*12426Sgdamore@opensolaris.org 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
439*12426Sgdamore@opensolaris.org 	    DDI_KERNEL_IOCTL, NULL, 0);
440*12426Sgdamore@opensolaris.org 	if (bd->d_removable) {
441*12426Sgdamore@opensolaris.org 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
442*12426Sgdamore@opensolaris.org 		    "removable-media", NULL, 0);
443*12426Sgdamore@opensolaris.org 	}
444*12426Sgdamore@opensolaris.org 	if (bd->d_hotpluggable) {
445*12426Sgdamore@opensolaris.org 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
446*12426Sgdamore@opensolaris.org 		    "hotpluggable", NULL, 0);
447*12426Sgdamore@opensolaris.org 	}
448*12426Sgdamore@opensolaris.org 
449*12426Sgdamore@opensolaris.org 	ddi_report_dev(dip);
450*12426Sgdamore@opensolaris.org 
451*12426Sgdamore@opensolaris.org 	return (DDI_SUCCESS);
452*12426Sgdamore@opensolaris.org }
453*12426Sgdamore@opensolaris.org 
454*12426Sgdamore@opensolaris.org static int
bd_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)455*12426Sgdamore@opensolaris.org bd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
456*12426Sgdamore@opensolaris.org {
457*12426Sgdamore@opensolaris.org 	bd_t	*bd;
458*12426Sgdamore@opensolaris.org 
459*12426Sgdamore@opensolaris.org 	bd = ddi_get_driver_private(dip);
460*12426Sgdamore@opensolaris.org 
461*12426Sgdamore@opensolaris.org 	switch (cmd) {
462*12426Sgdamore@opensolaris.org 	case DDI_DETACH:
463*12426Sgdamore@opensolaris.org 		break;
464*12426Sgdamore@opensolaris.org 	case DDI_SUSPEND:
465*12426Sgdamore@opensolaris.org 		/* We don't suspend, but our parent does */
466*12426Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
467*12426Sgdamore@opensolaris.org 	default:
468*12426Sgdamore@opensolaris.org 		return (DDI_FAILURE);
469*12426Sgdamore@opensolaris.org 	}
470*12426Sgdamore@opensolaris.org 	if (bd->d_ksp != NULL) {
471*12426Sgdamore@opensolaris.org 		kstat_delete(bd->d_ksp);
472*12426Sgdamore@opensolaris.org 		bd->d_ksp = NULL;
473*12426Sgdamore@opensolaris.org 	} else {
474*12426Sgdamore@opensolaris.org 		kmem_free(bd->d_kiop, sizeof (kstat_io_t));
475*12426Sgdamore@opensolaris.org 	}
476*12426Sgdamore@opensolaris.org 	cmlb_detach(bd->d_cmlbh, bd);
477*12426Sgdamore@opensolaris.org 	cmlb_free_handle(&bd->d_cmlbh);
478*12426Sgdamore@opensolaris.org 	if (bd->d_devid)
479*12426Sgdamore@opensolaris.org 		ddi_devid_free(bd->d_devid);
480*12426Sgdamore@opensolaris.org 	kmem_cache_destroy(bd->d_cache);
481*12426Sgdamore@opensolaris.org 	mutex_destroy(&bd->d_iomutex);
482*12426Sgdamore@opensolaris.org 	mutex_destroy(&bd->d_ocmutex);
483*12426Sgdamore@opensolaris.org 	mutex_destroy(&bd->d_statemutex);
484*12426Sgdamore@opensolaris.org 	cv_destroy(&bd->d_statecv);
485*12426Sgdamore@opensolaris.org 	list_destroy(&bd->d_waitq);
486*12426Sgdamore@opensolaris.org 	list_destroy(&bd->d_runq);
487*12426Sgdamore@opensolaris.org 	ddi_soft_state_free(bd_state, ddi_get_instance(dip));
488*12426Sgdamore@opensolaris.org 	return (DDI_SUCCESS);
489*12426Sgdamore@opensolaris.org }
490*12426Sgdamore@opensolaris.org 
491*12426Sgdamore@opensolaris.org static int
bd_xfer_ctor(void * buf,void * arg,int kmflag)492*12426Sgdamore@opensolaris.org bd_xfer_ctor(void *buf, void *arg, int kmflag)
493*12426Sgdamore@opensolaris.org {
494*12426Sgdamore@opensolaris.org 	bd_xfer_impl_t	*xi;
495*12426Sgdamore@opensolaris.org 	bd_t		*bd = arg;
496*12426Sgdamore@opensolaris.org 	int		(*dcb)(caddr_t);
497*12426Sgdamore@opensolaris.org 
498*12426Sgdamore@opensolaris.org 	if (kmflag == KM_SLEEP) {
499*12426Sgdamore@opensolaris.org 		dcb = DDI_DMA_SLEEP;
500*12426Sgdamore@opensolaris.org 	} else {
501*12426Sgdamore@opensolaris.org 		dcb = DDI_DMA_DONTWAIT;
502*12426Sgdamore@opensolaris.org 	}
503*12426Sgdamore@opensolaris.org 
504*12426Sgdamore@opensolaris.org 	xi = buf;
505*12426Sgdamore@opensolaris.org 	bzero(xi, sizeof (*xi));
506*12426Sgdamore@opensolaris.org 	xi->i_bd = bd;
507*12426Sgdamore@opensolaris.org 
508*12426Sgdamore@opensolaris.org 	if (bd->d_use_dma) {
509*12426Sgdamore@opensolaris.org 		if (ddi_dma_alloc_handle(bd->d_dip, &bd->d_dma, dcb, NULL,
510*12426Sgdamore@opensolaris.org 		    &xi->i_dmah) != DDI_SUCCESS) {
511*12426Sgdamore@opensolaris.org 			return (-1);
512*12426Sgdamore@opensolaris.org 		}
513*12426Sgdamore@opensolaris.org 	}
514*12426Sgdamore@opensolaris.org 
515*12426Sgdamore@opensolaris.org 	return (0);
516*12426Sgdamore@opensolaris.org }
517*12426Sgdamore@opensolaris.org 
518*12426Sgdamore@opensolaris.org static void
bd_xfer_dtor(void * buf,void * arg)519*12426Sgdamore@opensolaris.org bd_xfer_dtor(void *buf, void *arg)
520*12426Sgdamore@opensolaris.org {
521*12426Sgdamore@opensolaris.org 	bd_xfer_impl_t	*xi = buf;
522*12426Sgdamore@opensolaris.org 
523*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(arg));
524*12426Sgdamore@opensolaris.org 
525*12426Sgdamore@opensolaris.org 	if (xi->i_dmah)
526*12426Sgdamore@opensolaris.org 		ddi_dma_free_handle(&xi->i_dmah);
527*12426Sgdamore@opensolaris.org 	xi->i_dmah = NULL;
528*12426Sgdamore@opensolaris.org }
529*12426Sgdamore@opensolaris.org 
530*12426Sgdamore@opensolaris.org static bd_xfer_impl_t *
bd_xfer_alloc(bd_t * bd,struct buf * bp,int (* func)(void *,bd_xfer_t *),int kmflag)531*12426Sgdamore@opensolaris.org bd_xfer_alloc(bd_t *bd, struct buf *bp, int (*func)(void *, bd_xfer_t *),
532*12426Sgdamore@opensolaris.org     int kmflag)
533*12426Sgdamore@opensolaris.org {
534*12426Sgdamore@opensolaris.org 	bd_xfer_impl_t		*xi;
535*12426Sgdamore@opensolaris.org 	int			rv;
536*12426Sgdamore@opensolaris.org 	int			status;
537*12426Sgdamore@opensolaris.org 	unsigned		dir;
538*12426Sgdamore@opensolaris.org 	int			(*cb)(caddr_t);
539*12426Sgdamore@opensolaris.org 	size_t			len;
540*12426Sgdamore@opensolaris.org 	uint32_t		shift;
541*12426Sgdamore@opensolaris.org 
542*12426Sgdamore@opensolaris.org 	if (kmflag == KM_SLEEP) {
543*12426Sgdamore@opensolaris.org 		cb = DDI_DMA_SLEEP;
544*12426Sgdamore@opensolaris.org 	} else {
545*12426Sgdamore@opensolaris.org 		cb = DDI_DMA_DONTWAIT;
546*12426Sgdamore@opensolaris.org 	}
547*12426Sgdamore@opensolaris.org 
548*12426Sgdamore@opensolaris.org 	xi = kmem_cache_alloc(bd->d_cache, kmflag);
549*12426Sgdamore@opensolaris.org 	if (xi == NULL) {
550*12426Sgdamore@opensolaris.org 		bioerror(bp, ENOMEM);
551*12426Sgdamore@opensolaris.org 		return (NULL);
552*12426Sgdamore@opensolaris.org 	}
553*12426Sgdamore@opensolaris.org 
554*12426Sgdamore@opensolaris.org 	ASSERT(bp);
555*12426Sgdamore@opensolaris.org 	ASSERT(bp->b_bcount);
556*12426Sgdamore@opensolaris.org 
557*12426Sgdamore@opensolaris.org 	xi->i_bp = bp;
558*12426Sgdamore@opensolaris.org 	xi->i_func = func;
559*12426Sgdamore@opensolaris.org 	xi->i_blkno = bp->b_lblkno;
560*12426Sgdamore@opensolaris.org 
561*12426Sgdamore@opensolaris.org 	if (bp->b_bcount == 0) {
562*12426Sgdamore@opensolaris.org 		xi->i_len = 0;
563*12426Sgdamore@opensolaris.org 		xi->i_nblks = 0;
564*12426Sgdamore@opensolaris.org 		xi->i_kaddr = NULL;
565*12426Sgdamore@opensolaris.org 		xi->i_resid = 0;
566*12426Sgdamore@opensolaris.org 		xi->i_num_win = 0;
567*12426Sgdamore@opensolaris.org 		goto done;
568*12426Sgdamore@opensolaris.org 	}
569*12426Sgdamore@opensolaris.org 
570*12426Sgdamore@opensolaris.org 	if (bp->b_flags & B_READ) {
571*12426Sgdamore@opensolaris.org 		dir = DDI_DMA_READ;
572*12426Sgdamore@opensolaris.org 		xi->i_func = bd->d_ops.o_read;
573*12426Sgdamore@opensolaris.org 	} else {
574*12426Sgdamore@opensolaris.org 		dir = DDI_DMA_WRITE;
575*12426Sgdamore@opensolaris.org 		xi->i_func = bd->d_ops.o_write;
576*12426Sgdamore@opensolaris.org 	}
577*12426Sgdamore@opensolaris.org 
578*12426Sgdamore@opensolaris.org 	shift = bd->d_blkshift;
579*12426Sgdamore@opensolaris.org 	xi->i_blkshift = shift;
580*12426Sgdamore@opensolaris.org 
581*12426Sgdamore@opensolaris.org 	if (!bd->d_use_dma) {
582*12426Sgdamore@opensolaris.org 		bp_mapin(bp);
583*12426Sgdamore@opensolaris.org 		rv = 0;
584*12426Sgdamore@opensolaris.org 		xi->i_offset = 0;
585*12426Sgdamore@opensolaris.org 		xi->i_num_win =
586*12426Sgdamore@opensolaris.org 		    (bp->b_bcount + (bd->d_maxxfer - 1)) / bd->d_maxxfer;
587*12426Sgdamore@opensolaris.org 		xi->i_cur_win = 0;
588*12426Sgdamore@opensolaris.org 		xi->i_len = min(bp->b_bcount, bd->d_maxxfer);
589*12426Sgdamore@opensolaris.org 		xi->i_nblks = xi->i_len >> shift;
590*12426Sgdamore@opensolaris.org 		xi->i_kaddr = bp->b_un.b_addr;
591*12426Sgdamore@opensolaris.org 		xi->i_resid = bp->b_bcount;
592*12426Sgdamore@opensolaris.org 	} else {
593*12426Sgdamore@opensolaris.org 
594*12426Sgdamore@opensolaris.org 		/*
595*12426Sgdamore@opensolaris.org 		 * We have to use consistent DMA if the address is misaligned.
596*12426Sgdamore@opensolaris.org 		 */
597*12426Sgdamore@opensolaris.org 		if (((bp->b_flags & (B_PAGEIO | B_REMAPPED)) != B_PAGEIO) &&
598*12426Sgdamore@opensolaris.org 		    ((uintptr_t)bp->b_un.b_addr & 0x7)) {
599*12426Sgdamore@opensolaris.org 			dir |= DDI_DMA_CONSISTENT | DDI_DMA_PARTIAL;
600*12426Sgdamore@opensolaris.org 		} else {
601*12426Sgdamore@opensolaris.org 			dir |= DDI_DMA_STREAMING | DDI_DMA_PARTIAL;
602*12426Sgdamore@opensolaris.org 		}
603*12426Sgdamore@opensolaris.org 
604*12426Sgdamore@opensolaris.org 		status = ddi_dma_buf_bind_handle(xi->i_dmah, bp, dir, cb,
605*12426Sgdamore@opensolaris.org 		    NULL, &xi->i_dmac, &xi->i_ndmac);
606*12426Sgdamore@opensolaris.org 		switch (status) {
607*12426Sgdamore@opensolaris.org 		case DDI_DMA_MAPPED:
608*12426Sgdamore@opensolaris.org 			xi->i_num_win = 1;
609*12426Sgdamore@opensolaris.org 			xi->i_cur_win = 0;
610*12426Sgdamore@opensolaris.org 			xi->i_offset = 0;
611*12426Sgdamore@opensolaris.org 			xi->i_len = bp->b_bcount;
612*12426Sgdamore@opensolaris.org 			xi->i_nblks = xi->i_len >> shift;
613*12426Sgdamore@opensolaris.org 			xi->i_resid = bp->b_bcount;
614*12426Sgdamore@opensolaris.org 			rv = 0;
615*12426Sgdamore@opensolaris.org 			break;
616*12426Sgdamore@opensolaris.org 		case DDI_DMA_PARTIAL_MAP:
617*12426Sgdamore@opensolaris.org 			xi->i_cur_win = 0;
618*12426Sgdamore@opensolaris.org 
619*12426Sgdamore@opensolaris.org 			if ((ddi_dma_numwin(xi->i_dmah, &xi->i_num_win) !=
620*12426Sgdamore@opensolaris.org 			    DDI_SUCCESS) ||
621*12426Sgdamore@opensolaris.org 			    (ddi_dma_getwin(xi->i_dmah, 0, &xi->i_offset,
622*12426Sgdamore@opensolaris.org 			    &len, &xi->i_dmac, &xi->i_ndmac) !=
623*12426Sgdamore@opensolaris.org 			    DDI_SUCCESS) ||
624*12426Sgdamore@opensolaris.org 			    (P2PHASE(len, shift) != 0)) {
625*12426Sgdamore@opensolaris.org 				(void) ddi_dma_unbind_handle(xi->i_dmah);
626*12426Sgdamore@opensolaris.org 				rv = EFAULT;
627*12426Sgdamore@opensolaris.org 				goto done;
628*12426Sgdamore@opensolaris.org 			}
629*12426Sgdamore@opensolaris.org 			xi->i_len = len;
630*12426Sgdamore@opensolaris.org 			xi->i_nblks = xi->i_len >> shift;
631*12426Sgdamore@opensolaris.org 			xi->i_resid = bp->b_bcount;
632*12426Sgdamore@opensolaris.org 			rv = 0;
633*12426Sgdamore@opensolaris.org 			break;
634*12426Sgdamore@opensolaris.org 		case DDI_DMA_NORESOURCES:
635*12426Sgdamore@opensolaris.org 			rv = EAGAIN;
636*12426Sgdamore@opensolaris.org 			goto done;
637*12426Sgdamore@opensolaris.org 		case DDI_DMA_TOOBIG:
638*12426Sgdamore@opensolaris.org 			rv = EINVAL;
639*12426Sgdamore@opensolaris.org 			goto done;
640*12426Sgdamore@opensolaris.org 		case DDI_DMA_NOMAPPING:
641*12426Sgdamore@opensolaris.org 		case DDI_DMA_INUSE:
642*12426Sgdamore@opensolaris.org 		default:
643*12426Sgdamore@opensolaris.org 			rv = EFAULT;
644*12426Sgdamore@opensolaris.org 			goto done;
645*12426Sgdamore@opensolaris.org 		}
646*12426Sgdamore@opensolaris.org 	}
647*12426Sgdamore@opensolaris.org 
648*12426Sgdamore@opensolaris.org done:
649*12426Sgdamore@opensolaris.org 	if (rv != 0) {
650*12426Sgdamore@opensolaris.org 		kmem_cache_free(bd->d_cache, xi);
651*12426Sgdamore@opensolaris.org 		bioerror(bp, rv);
652*12426Sgdamore@opensolaris.org 		return (NULL);
653*12426Sgdamore@opensolaris.org 	}
654*12426Sgdamore@opensolaris.org 
655*12426Sgdamore@opensolaris.org 	return (xi);
656*12426Sgdamore@opensolaris.org }
657*12426Sgdamore@opensolaris.org 
658*12426Sgdamore@opensolaris.org static void
bd_xfer_free(bd_xfer_impl_t * xi)659*12426Sgdamore@opensolaris.org bd_xfer_free(bd_xfer_impl_t *xi)
660*12426Sgdamore@opensolaris.org {
661*12426Sgdamore@opensolaris.org 	if (xi->i_dmah) {
662*12426Sgdamore@opensolaris.org 		(void) ddi_dma_unbind_handle(xi->i_dmah);
663*12426Sgdamore@opensolaris.org 	}
664*12426Sgdamore@opensolaris.org 	kmem_cache_free(xi->i_bd->d_cache, xi);
665*12426Sgdamore@opensolaris.org }
666*12426Sgdamore@opensolaris.org 
667*12426Sgdamore@opensolaris.org static int
bd_open(dev_t * devp,int flag,int otyp,cred_t * credp)668*12426Sgdamore@opensolaris.org bd_open(dev_t *devp, int flag, int otyp, cred_t *credp)
669*12426Sgdamore@opensolaris.org {
670*12426Sgdamore@opensolaris.org 	dev_t		dev = *devp;
671*12426Sgdamore@opensolaris.org 	bd_t		*bd;
672*12426Sgdamore@opensolaris.org 	minor_t		part;
673*12426Sgdamore@opensolaris.org 	minor_t		inst;
674*12426Sgdamore@opensolaris.org 	uint64_t	mask;
675*12426Sgdamore@opensolaris.org 	boolean_t	ndelay;
676*12426Sgdamore@opensolaris.org 	int		rv;
677*12426Sgdamore@opensolaris.org 	diskaddr_t	nblks;
678*12426Sgdamore@opensolaris.org 	diskaddr_t	lba;
679*12426Sgdamore@opensolaris.org 
680*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(credp));
681*12426Sgdamore@opensolaris.org 
682*12426Sgdamore@opensolaris.org 	part = BDPART(dev);
683*12426Sgdamore@opensolaris.org 	inst = BDINST(dev);
684*12426Sgdamore@opensolaris.org 
685*12426Sgdamore@opensolaris.org 	if (otyp >= OTYPCNT)
686*12426Sgdamore@opensolaris.org 		return (EINVAL);
687*12426Sgdamore@opensolaris.org 
688*12426Sgdamore@opensolaris.org 	ndelay = (flag & (FNDELAY | FNONBLOCK)) ? B_TRUE : B_FALSE;
689*12426Sgdamore@opensolaris.org 
690*12426Sgdamore@opensolaris.org 	/*
691*12426Sgdamore@opensolaris.org 	 * Block any DR events from changing the set of registered
692*12426Sgdamore@opensolaris.org 	 * devices while we function.
693*12426Sgdamore@opensolaris.org 	 */
694*12426Sgdamore@opensolaris.org 	rw_enter(&bd_lock, RW_READER);
695*12426Sgdamore@opensolaris.org 	if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
696*12426Sgdamore@opensolaris.org 		rw_exit(&bd_lock);
697*12426Sgdamore@opensolaris.org 		return (ENXIO);
698*12426Sgdamore@opensolaris.org 	}
699*12426Sgdamore@opensolaris.org 
700*12426Sgdamore@opensolaris.org 	mutex_enter(&bd->d_ocmutex);
701*12426Sgdamore@opensolaris.org 
702*12426Sgdamore@opensolaris.org 	ASSERT(part < 64);
703*12426Sgdamore@opensolaris.org 	mask = (1U << part);
704*12426Sgdamore@opensolaris.org 
705*12426Sgdamore@opensolaris.org 	bd_update_state(bd);
706*12426Sgdamore@opensolaris.org 
707*12426Sgdamore@opensolaris.org 	if (cmlb_validate(bd->d_cmlbh, 0, bd) != 0) {
708*12426Sgdamore@opensolaris.org 
709*12426Sgdamore@opensolaris.org 		/* non-blocking opens are allowed to succeed */
710*12426Sgdamore@opensolaris.org 		if (!ndelay) {
711*12426Sgdamore@opensolaris.org 			rv = ENXIO;
712*12426Sgdamore@opensolaris.org 			goto done;
713*12426Sgdamore@opensolaris.org 		}
714*12426Sgdamore@opensolaris.org 	} else if (cmlb_partinfo(bd->d_cmlbh, part, &nblks, &lba,
715*12426Sgdamore@opensolaris.org 	    NULL, NULL, bd) == 0) {
716*12426Sgdamore@opensolaris.org 
717*12426Sgdamore@opensolaris.org 		/*
718*12426Sgdamore@opensolaris.org 		 * We read the partinfo, verify valid ranges.  If the
719*12426Sgdamore@opensolaris.org 		 * partition is invalid, and we aren't blocking or
720*12426Sgdamore@opensolaris.org 		 * doing a raw access, then fail. (Non-blocking and
721*12426Sgdamore@opensolaris.org 		 * raw accesses can still succeed to allow a disk with
722*12426Sgdamore@opensolaris.org 		 * bad partition data to opened by format and fdisk.)
723*12426Sgdamore@opensolaris.org 		 */
724*12426Sgdamore@opensolaris.org 		if ((!nblks) && ((!ndelay) || (otyp != OTYP_CHR))) {
725*12426Sgdamore@opensolaris.org 			rv = ENXIO;
726*12426Sgdamore@opensolaris.org 			goto done;
727*12426Sgdamore@opensolaris.org 		}
728*12426Sgdamore@opensolaris.org 	} else if (!ndelay) {
729*12426Sgdamore@opensolaris.org 		/*
730*12426Sgdamore@opensolaris.org 		 * cmlb_partinfo failed -- invalid partition or no
731*12426Sgdamore@opensolaris.org 		 * disk label.
732*12426Sgdamore@opensolaris.org 		 */
733*12426Sgdamore@opensolaris.org 		rv = ENXIO;
734*12426Sgdamore@opensolaris.org 		goto done;
735*12426Sgdamore@opensolaris.org 	}
736*12426Sgdamore@opensolaris.org 
737*12426Sgdamore@opensolaris.org 	if ((flag & FWRITE) && bd->d_rdonly) {
738*12426Sgdamore@opensolaris.org 		rv = EROFS;
739*12426Sgdamore@opensolaris.org 		goto done;
740*12426Sgdamore@opensolaris.org 	}
741*12426Sgdamore@opensolaris.org 
742*12426Sgdamore@opensolaris.org 	if ((bd->d_open_excl) & (mask)) {
743*12426Sgdamore@opensolaris.org 		rv = EBUSY;
744*12426Sgdamore@opensolaris.org 		goto done;
745*12426Sgdamore@opensolaris.org 	}
746*12426Sgdamore@opensolaris.org 	if (flag & FEXCL) {
747*12426Sgdamore@opensolaris.org 		if (bd->d_open_lyr[part]) {
748*12426Sgdamore@opensolaris.org 			rv = EBUSY;
749*12426Sgdamore@opensolaris.org 			goto done;
750*12426Sgdamore@opensolaris.org 		}
751*12426Sgdamore@opensolaris.org 		for (int i = 0; i < OTYP_LYR; i++) {
752*12426Sgdamore@opensolaris.org 			if (bd->d_open_reg[i] & mask) {
753*12426Sgdamore@opensolaris.org 				rv = EBUSY;
754*12426Sgdamore@opensolaris.org 				goto done;
755*12426Sgdamore@opensolaris.org 			}
756*12426Sgdamore@opensolaris.org 		}
757*12426Sgdamore@opensolaris.org 	}
758*12426Sgdamore@opensolaris.org 
759*12426Sgdamore@opensolaris.org 	if (otyp == OTYP_LYR) {
760*12426Sgdamore@opensolaris.org 		bd->d_open_lyr[part]++;
761*12426Sgdamore@opensolaris.org 	} else {
762*12426Sgdamore@opensolaris.org 		bd->d_open_reg[otyp] |= mask;
763*12426Sgdamore@opensolaris.org 	}
764*12426Sgdamore@opensolaris.org 	if (flag & FEXCL) {
765*12426Sgdamore@opensolaris.org 		bd->d_open_excl |= mask;
766*12426Sgdamore@opensolaris.org 	}
767*12426Sgdamore@opensolaris.org 
768*12426Sgdamore@opensolaris.org 	rv = 0;
769*12426Sgdamore@opensolaris.org done:
770*12426Sgdamore@opensolaris.org 	mutex_exit(&bd->d_ocmutex);
771*12426Sgdamore@opensolaris.org 	rw_exit(&bd_lock);
772*12426Sgdamore@opensolaris.org 
773*12426Sgdamore@opensolaris.org 	return (rv);
774*12426Sgdamore@opensolaris.org }
775*12426Sgdamore@opensolaris.org 
776*12426Sgdamore@opensolaris.org static int
bd_close(dev_t dev,int flag,int otyp,cred_t * credp)777*12426Sgdamore@opensolaris.org bd_close(dev_t dev, int flag, int otyp, cred_t *credp)
778*12426Sgdamore@opensolaris.org {
779*12426Sgdamore@opensolaris.org 	bd_t		*bd;
780*12426Sgdamore@opensolaris.org 	minor_t		inst;
781*12426Sgdamore@opensolaris.org 	minor_t		part;
782*12426Sgdamore@opensolaris.org 	uint64_t	mask;
783*12426Sgdamore@opensolaris.org 	boolean_t	last = B_TRUE;
784*12426Sgdamore@opensolaris.org 
785*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(flag));
786*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(credp));
787*12426Sgdamore@opensolaris.org 
788*12426Sgdamore@opensolaris.org 	part = BDPART(dev);
789*12426Sgdamore@opensolaris.org 	inst = BDINST(dev);
790*12426Sgdamore@opensolaris.org 
791*12426Sgdamore@opensolaris.org 	ASSERT(part < 64);
792*12426Sgdamore@opensolaris.org 	mask = (1U << part);
793*12426Sgdamore@opensolaris.org 
794*12426Sgdamore@opensolaris.org 	rw_enter(&bd_lock, RW_READER);
795*12426Sgdamore@opensolaris.org 
796*12426Sgdamore@opensolaris.org 	if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
797*12426Sgdamore@opensolaris.org 		rw_exit(&bd_lock);
798*12426Sgdamore@opensolaris.org 		return (ENXIO);
799*12426Sgdamore@opensolaris.org 	}
800*12426Sgdamore@opensolaris.org 
801*12426Sgdamore@opensolaris.org 	mutex_enter(&bd->d_ocmutex);
802*12426Sgdamore@opensolaris.org 	if (bd->d_open_excl & mask) {
803*12426Sgdamore@opensolaris.org 		bd->d_open_excl &= ~mask;
804*12426Sgdamore@opensolaris.org 	}
805*12426Sgdamore@opensolaris.org 	if (otyp == OTYP_LYR) {
806*12426Sgdamore@opensolaris.org 		bd->d_open_lyr[part]--;
807*12426Sgdamore@opensolaris.org 	} else {
808*12426Sgdamore@opensolaris.org 		bd->d_open_reg[otyp] &= ~mask;
809*12426Sgdamore@opensolaris.org 	}
810*12426Sgdamore@opensolaris.org 	for (int i = 0; i < 64; i++) {
811*12426Sgdamore@opensolaris.org 		if (bd->d_open_lyr[part]) {
812*12426Sgdamore@opensolaris.org 			last = B_FALSE;
813*12426Sgdamore@opensolaris.org 		}
814*12426Sgdamore@opensolaris.org 	}
815*12426Sgdamore@opensolaris.org 	for (int i = 0; last && (i < OTYP_LYR); i++) {
816*12426Sgdamore@opensolaris.org 		if (bd->d_open_reg[i]) {
817*12426Sgdamore@opensolaris.org 			last = B_FALSE;
818*12426Sgdamore@opensolaris.org 		}
819*12426Sgdamore@opensolaris.org 	}
820*12426Sgdamore@opensolaris.org 	mutex_exit(&bd->d_ocmutex);
821*12426Sgdamore@opensolaris.org 
822*12426Sgdamore@opensolaris.org 	if (last) {
823*12426Sgdamore@opensolaris.org 		cmlb_invalidate(bd->d_cmlbh, bd);
824*12426Sgdamore@opensolaris.org 	}
825*12426Sgdamore@opensolaris.org 	rw_exit(&bd_lock);
826*12426Sgdamore@opensolaris.org 
827*12426Sgdamore@opensolaris.org 	return (0);
828*12426Sgdamore@opensolaris.org }
829*12426Sgdamore@opensolaris.org 
830*12426Sgdamore@opensolaris.org static int
bd_read(dev_t dev,struct uio * uio,cred_t * credp)831*12426Sgdamore@opensolaris.org bd_read(dev_t dev, struct uio *uio, cred_t *credp)
832*12426Sgdamore@opensolaris.org {
833*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(credp));
834*12426Sgdamore@opensolaris.org 	return (physio(bd_strategy, NULL, dev, B_READ, minphys, uio));
835*12426Sgdamore@opensolaris.org }
836*12426Sgdamore@opensolaris.org 
837*12426Sgdamore@opensolaris.org static int
bd_write(dev_t dev,struct uio * uio,cred_t * credp)838*12426Sgdamore@opensolaris.org bd_write(dev_t dev, struct uio *uio, cred_t *credp)
839*12426Sgdamore@opensolaris.org {
840*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(credp));
841*12426Sgdamore@opensolaris.org 	return (physio(bd_strategy, NULL, dev, B_WRITE, minphys, uio));
842*12426Sgdamore@opensolaris.org }
843*12426Sgdamore@opensolaris.org 
844*12426Sgdamore@opensolaris.org static int
bd_aread(dev_t dev,struct aio_req * aio,cred_t * credp)845*12426Sgdamore@opensolaris.org bd_aread(dev_t dev, struct aio_req *aio, cred_t *credp)
846*12426Sgdamore@opensolaris.org {
847*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(credp));
848*12426Sgdamore@opensolaris.org 	return (aphysio(bd_strategy, anocancel, dev, B_READ, minphys, aio));
849*12426Sgdamore@opensolaris.org }
850*12426Sgdamore@opensolaris.org 
851*12426Sgdamore@opensolaris.org static int
bd_awrite(dev_t dev,struct aio_req * aio,cred_t * credp)852*12426Sgdamore@opensolaris.org bd_awrite(dev_t dev, struct aio_req *aio, cred_t *credp)
853*12426Sgdamore@opensolaris.org {
854*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(credp));
855*12426Sgdamore@opensolaris.org 	return (aphysio(bd_strategy, anocancel, dev, B_WRITE, minphys, aio));
856*12426Sgdamore@opensolaris.org }
857*12426Sgdamore@opensolaris.org 
858*12426Sgdamore@opensolaris.org static int
bd_strategy(struct buf * bp)859*12426Sgdamore@opensolaris.org bd_strategy(struct buf *bp)
860*12426Sgdamore@opensolaris.org {
861*12426Sgdamore@opensolaris.org 	minor_t		inst;
862*12426Sgdamore@opensolaris.org 	minor_t		part;
863*12426Sgdamore@opensolaris.org 	bd_t		*bd;
864*12426Sgdamore@opensolaris.org 	diskaddr_t	p_lba;
865*12426Sgdamore@opensolaris.org 	diskaddr_t	p_nblks;
866*12426Sgdamore@opensolaris.org 	diskaddr_t	b_nblks;
867*12426Sgdamore@opensolaris.org 	bd_xfer_impl_t	*xi;
868*12426Sgdamore@opensolaris.org 	uint32_t	shift;
869*12426Sgdamore@opensolaris.org 	int		(*func)(void *, bd_xfer_t *);
870*12426Sgdamore@opensolaris.org 
871*12426Sgdamore@opensolaris.org 	part = BDPART(bp->b_edev);
872*12426Sgdamore@opensolaris.org 	inst = BDINST(bp->b_edev);
873*12426Sgdamore@opensolaris.org 
874*12426Sgdamore@opensolaris.org 	ASSERT(bp);
875*12426Sgdamore@opensolaris.org 
876*12426Sgdamore@opensolaris.org 	bp->b_resid = bp->b_bcount;
877*12426Sgdamore@opensolaris.org 
878*12426Sgdamore@opensolaris.org 	if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
879*12426Sgdamore@opensolaris.org 		bioerror(bp, ENXIO);
880*12426Sgdamore@opensolaris.org 		biodone(bp);
881*12426Sgdamore@opensolaris.org 		return (0);
882*12426Sgdamore@opensolaris.org 	}
883*12426Sgdamore@opensolaris.org 
884*12426Sgdamore@opensolaris.org 	if (cmlb_partinfo(bd->d_cmlbh, part, &p_nblks, &p_lba,
885*12426Sgdamore@opensolaris.org 	    NULL, NULL, bd)) {
886*12426Sgdamore@opensolaris.org 		bioerror(bp, ENXIO);
887*12426Sgdamore@opensolaris.org 		biodone(bp);
888*12426Sgdamore@opensolaris.org 		return (0);
889*12426Sgdamore@opensolaris.org 	}
890*12426Sgdamore@opensolaris.org 
891*12426Sgdamore@opensolaris.org 	shift = bd->d_blkshift;
892*12426Sgdamore@opensolaris.org 
893*12426Sgdamore@opensolaris.org 	if ((P2PHASE(bp->b_bcount, (1U << shift)) != 0) ||
894*12426Sgdamore@opensolaris.org 	    (bp->b_lblkno > p_nblks)) {
895*12426Sgdamore@opensolaris.org 		bioerror(bp, ENXIO);
896*12426Sgdamore@opensolaris.org 		biodone(bp);
897*12426Sgdamore@opensolaris.org 		return (0);
898*12426Sgdamore@opensolaris.org 	}
899*12426Sgdamore@opensolaris.org 	b_nblks = bp->b_bcount >> shift;
900*12426Sgdamore@opensolaris.org 	if ((bp->b_lblkno == p_nblks) || (bp->b_bcount == 0)) {
901*12426Sgdamore@opensolaris.org 		biodone(bp);
902*12426Sgdamore@opensolaris.org 		return (0);
903*12426Sgdamore@opensolaris.org 	}
904*12426Sgdamore@opensolaris.org 
905*12426Sgdamore@opensolaris.org 	if ((b_nblks + bp->b_lblkno) > p_nblks) {
906*12426Sgdamore@opensolaris.org 		bp->b_resid = ((bp->b_lblkno + b_nblks - p_nblks) << shift);
907*12426Sgdamore@opensolaris.org 		bp->b_bcount -= bp->b_resid;
908*12426Sgdamore@opensolaris.org 	} else {
909*12426Sgdamore@opensolaris.org 		bp->b_resid = 0;
910*12426Sgdamore@opensolaris.org 	}
911*12426Sgdamore@opensolaris.org 	func = (bp->b_flags & B_READ) ? bd->d_ops.o_read : bd->d_ops.o_write;
912*12426Sgdamore@opensolaris.org 
913*12426Sgdamore@opensolaris.org 	xi = bd_xfer_alloc(bd, bp, func, KM_NOSLEEP);
914*12426Sgdamore@opensolaris.org 	if (xi == NULL) {
915*12426Sgdamore@opensolaris.org 		xi = bd_xfer_alloc(bd, bp, func, KM_PUSHPAGE);
916*12426Sgdamore@opensolaris.org 	}
917*12426Sgdamore@opensolaris.org 	if (xi == NULL) {
918*12426Sgdamore@opensolaris.org 		/* bd_request_alloc will have done bioerror */
919*12426Sgdamore@opensolaris.org 		biodone(bp);
920*12426Sgdamore@opensolaris.org 		return (0);
921*12426Sgdamore@opensolaris.org 	}
922*12426Sgdamore@opensolaris.org 	xi->i_blkno = bp->b_lblkno + p_lba;
923*12426Sgdamore@opensolaris.org 
924*12426Sgdamore@opensolaris.org 	bd_submit(bd, xi);
925*12426Sgdamore@opensolaris.org 
926*12426Sgdamore@opensolaris.org 	return (0);
927*12426Sgdamore@opensolaris.org }
928*12426Sgdamore@opensolaris.org 
929*12426Sgdamore@opensolaris.org static int
bd_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * credp,int * rvalp)930*12426Sgdamore@opensolaris.org bd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp)
931*12426Sgdamore@opensolaris.org {
932*12426Sgdamore@opensolaris.org 	minor_t		inst;
933*12426Sgdamore@opensolaris.org 	uint16_t	part;
934*12426Sgdamore@opensolaris.org 	bd_t		*bd;
935*12426Sgdamore@opensolaris.org 	void		*ptr = (void *)arg;
936*12426Sgdamore@opensolaris.org 	int		rv;
937*12426Sgdamore@opensolaris.org 
938*12426Sgdamore@opensolaris.org 	part = BDPART(dev);
939*12426Sgdamore@opensolaris.org 	inst = BDINST(dev);
940*12426Sgdamore@opensolaris.org 
941*12426Sgdamore@opensolaris.org 	if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
942*12426Sgdamore@opensolaris.org 		return (ENXIO);
943*12426Sgdamore@opensolaris.org 	}
944*12426Sgdamore@opensolaris.org 
945*12426Sgdamore@opensolaris.org 	rv = cmlb_ioctl(bd->d_cmlbh, dev, cmd, arg, flag, credp, rvalp, bd);
946*12426Sgdamore@opensolaris.org 	if (rv != ENOTTY)
947*12426Sgdamore@opensolaris.org 		return (rv);
948*12426Sgdamore@opensolaris.org 
949*12426Sgdamore@opensolaris.org 	switch (cmd) {
950*12426Sgdamore@opensolaris.org 	case DKIOCGMEDIAINFO: {
951*12426Sgdamore@opensolaris.org 		struct dk_minfo minfo;
952*12426Sgdamore@opensolaris.org 
953*12426Sgdamore@opensolaris.org 		/* make sure our state information is current */
954*12426Sgdamore@opensolaris.org 		bd_update_state(bd);
955*12426Sgdamore@opensolaris.org 		bzero(&minfo, sizeof (minfo));
956*12426Sgdamore@opensolaris.org 		minfo.dki_media_type = DK_FIXED_DISK;
957*12426Sgdamore@opensolaris.org 		minfo.dki_lbsize = (1U << bd->d_blkshift);
958*12426Sgdamore@opensolaris.org 		minfo.dki_capacity = bd->d_numblks;
959*12426Sgdamore@opensolaris.org 		if (ddi_copyout(&minfo, ptr, sizeof (minfo), flag))  {
960*12426Sgdamore@opensolaris.org 			return (EFAULT);
961*12426Sgdamore@opensolaris.org 		}
962*12426Sgdamore@opensolaris.org 		return (0);
963*12426Sgdamore@opensolaris.org 	}
964*12426Sgdamore@opensolaris.org 	case DKIOCINFO: {
965*12426Sgdamore@opensolaris.org 		struct dk_cinfo cinfo;
966*12426Sgdamore@opensolaris.org 		bzero(&cinfo, sizeof (cinfo));
967*12426Sgdamore@opensolaris.org 		cinfo.dki_ctype = DKC_BLKDEV;
968*12426Sgdamore@opensolaris.org 		cinfo.dki_cnum = ddi_get_instance(ddi_get_parent(bd->d_dip));
969*12426Sgdamore@opensolaris.org 		(void) snprintf(cinfo.dki_cname, sizeof (cinfo.dki_cname),
970*12426Sgdamore@opensolaris.org 		    "%s", ddi_driver_name(ddi_get_parent(bd->d_dip)));
971*12426Sgdamore@opensolaris.org 		(void) snprintf(cinfo.dki_dname, sizeof (cinfo.dki_dname),
972*12426Sgdamore@opensolaris.org 		    "%s", ddi_driver_name(bd->d_dip));
973*12426Sgdamore@opensolaris.org 		cinfo.dki_unit = inst;
974*12426Sgdamore@opensolaris.org 		cinfo.dki_flags = DKI_FMTVOL;
975*12426Sgdamore@opensolaris.org 		cinfo.dki_partition = part;
976*12426Sgdamore@opensolaris.org 		cinfo.dki_maxtransfer = bd->d_maxxfer / DEV_BSIZE;
977*12426Sgdamore@opensolaris.org 		cinfo.dki_addr = 0;
978*12426Sgdamore@opensolaris.org 		cinfo.dki_slave = 0;
979*12426Sgdamore@opensolaris.org 		cinfo.dki_space = 0;
980*12426Sgdamore@opensolaris.org 		cinfo.dki_prio = 0;
981*12426Sgdamore@opensolaris.org 		cinfo.dki_vec = 0;
982*12426Sgdamore@opensolaris.org 		if (ddi_copyout(&cinfo, ptr, sizeof (cinfo), flag))  {
983*12426Sgdamore@opensolaris.org 			return (EFAULT);
984*12426Sgdamore@opensolaris.org 		}
985*12426Sgdamore@opensolaris.org 		return (0);
986*12426Sgdamore@opensolaris.org 	}
987*12426Sgdamore@opensolaris.org 	case DKIOCREMOVABLE: {
988*12426Sgdamore@opensolaris.org 		int i;
989*12426Sgdamore@opensolaris.org 		i = bd->d_removable ? 1 : 0;
990*12426Sgdamore@opensolaris.org 		if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
991*12426Sgdamore@opensolaris.org 			return (EFAULT);
992*12426Sgdamore@opensolaris.org 		}
993*12426Sgdamore@opensolaris.org 		return (0);
994*12426Sgdamore@opensolaris.org 	}
995*12426Sgdamore@opensolaris.org 	case DKIOCHOTPLUGGABLE: {
996*12426Sgdamore@opensolaris.org 		int i;
997*12426Sgdamore@opensolaris.org 		i = bd->d_hotpluggable ? 1 : 0;
998*12426Sgdamore@opensolaris.org 		if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
999*12426Sgdamore@opensolaris.org 			return (EFAULT);
1000*12426Sgdamore@opensolaris.org 		}
1001*12426Sgdamore@opensolaris.org 		return (0);
1002*12426Sgdamore@opensolaris.org 	}
1003*12426Sgdamore@opensolaris.org 	case DKIOCREADONLY: {
1004*12426Sgdamore@opensolaris.org 		int i;
1005*12426Sgdamore@opensolaris.org 		i = bd->d_rdonly ? 1 : 0;
1006*12426Sgdamore@opensolaris.org 		if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
1007*12426Sgdamore@opensolaris.org 			return (EFAULT);
1008*12426Sgdamore@opensolaris.org 		}
1009*12426Sgdamore@opensolaris.org 		return (0);
1010*12426Sgdamore@opensolaris.org 	}
1011*12426Sgdamore@opensolaris.org 	case DKIOCSTATE: {
1012*12426Sgdamore@opensolaris.org 		enum dkio_state	state;
1013*12426Sgdamore@opensolaris.org 		if (ddi_copyin(ptr, &state, sizeof (state), flag)) {
1014*12426Sgdamore@opensolaris.org 			return (EFAULT);
1015*12426Sgdamore@opensolaris.org 		}
1016*12426Sgdamore@opensolaris.org 		if ((rv = bd_check_state(bd, &state)) != 0) {
1017*12426Sgdamore@opensolaris.org 			return (rv);
1018*12426Sgdamore@opensolaris.org 		}
1019*12426Sgdamore@opensolaris.org 		if (ddi_copyout(&state, ptr, sizeof (state), flag)) {
1020*12426Sgdamore@opensolaris.org 			return (EFAULT);
1021*12426Sgdamore@opensolaris.org 		}
1022*12426Sgdamore@opensolaris.org 		return (0);
1023*12426Sgdamore@opensolaris.org 	}
1024*12426Sgdamore@opensolaris.org 	case DKIOCFLUSHWRITECACHE: {
1025*12426Sgdamore@opensolaris.org 		struct dk_callback *dkc;
1026*12426Sgdamore@opensolaris.org 
1027*12426Sgdamore@opensolaris.org 		dkc = flag & FKIOCTL ? (void *)arg : NULL;
1028*12426Sgdamore@opensolaris.org 		rv = bd_flush_write_cache(bd, dkc);
1029*12426Sgdamore@opensolaris.org 		return (rv);
1030*12426Sgdamore@opensolaris.org 	}
1031*12426Sgdamore@opensolaris.org 
1032*12426Sgdamore@opensolaris.org 	default:
1033*12426Sgdamore@opensolaris.org 		break;
1034*12426Sgdamore@opensolaris.org 
1035*12426Sgdamore@opensolaris.org 	}
1036*12426Sgdamore@opensolaris.org 	return (ENOTTY);
1037*12426Sgdamore@opensolaris.org }
1038*12426Sgdamore@opensolaris.org 
1039*12426Sgdamore@opensolaris.org static int
bd_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)1040*12426Sgdamore@opensolaris.org bd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
1041*12426Sgdamore@opensolaris.org     char *name, caddr_t valuep, int *lengthp)
1042*12426Sgdamore@opensolaris.org {
1043*12426Sgdamore@opensolaris.org 	bd_t	*bd;
1044*12426Sgdamore@opensolaris.org 
1045*12426Sgdamore@opensolaris.org 	bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip));
1046*12426Sgdamore@opensolaris.org 	if (bd == NULL)
1047*12426Sgdamore@opensolaris.org 		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1048*12426Sgdamore@opensolaris.org 		    name, valuep, lengthp));
1049*12426Sgdamore@opensolaris.org 
1050*12426Sgdamore@opensolaris.org 	return (cmlb_prop_op(bd->d_cmlbh, dev, dip, prop_op, mod_flags, name,
1051*12426Sgdamore@opensolaris.org 	    valuep, lengthp, BDPART(dev), bd));
1052*12426Sgdamore@opensolaris.org }
1053*12426Sgdamore@opensolaris.org 
1054*12426Sgdamore@opensolaris.org 
1055*12426Sgdamore@opensolaris.org static int
bd_tg_rdwr(dev_info_t * dip,uchar_t cmd,void * bufaddr,diskaddr_t start,size_t length,void * tg_cookie)1056*12426Sgdamore@opensolaris.org bd_tg_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, diskaddr_t start,
1057*12426Sgdamore@opensolaris.org     size_t length, void *tg_cookie)
1058*12426Sgdamore@opensolaris.org {
1059*12426Sgdamore@opensolaris.org 	bd_t		*bd;
1060*12426Sgdamore@opensolaris.org 	buf_t		*bp;
1061*12426Sgdamore@opensolaris.org 	bd_xfer_impl_t	*xi;
1062*12426Sgdamore@opensolaris.org 	int		rv;
1063*12426Sgdamore@opensolaris.org 	int		(*func)(void *, bd_xfer_t *);
1064*12426Sgdamore@opensolaris.org 
1065*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(dip));
1066*12426Sgdamore@opensolaris.org 
1067*12426Sgdamore@opensolaris.org 
1068*12426Sgdamore@opensolaris.org 	bd = tg_cookie;
1069*12426Sgdamore@opensolaris.org 	if (P2PHASE(length, (1U << bd->d_blkshift)) != 0) {
1070*12426Sgdamore@opensolaris.org 		/* We can only transfer whole blocks at a time! */
1071*12426Sgdamore@opensolaris.org 		return (EINVAL);
1072*12426Sgdamore@opensolaris.org 	}
1073*12426Sgdamore@opensolaris.org 
1074*12426Sgdamore@opensolaris.org 	bp = getrbuf(KM_SLEEP);
1075*12426Sgdamore@opensolaris.org 
1076*12426Sgdamore@opensolaris.org 	switch (cmd) {
1077*12426Sgdamore@opensolaris.org 	case TG_READ:
1078*12426Sgdamore@opensolaris.org 		bp->b_flags = B_READ;
1079*12426Sgdamore@opensolaris.org 		func = bd->d_ops.o_read;
1080*12426Sgdamore@opensolaris.org 		break;
1081*12426Sgdamore@opensolaris.org 	case TG_WRITE:
1082*12426Sgdamore@opensolaris.org 		bp->b_flags = B_WRITE;
1083*12426Sgdamore@opensolaris.org 		func = bd->d_ops.o_write;
1084*12426Sgdamore@opensolaris.org 		break;
1085*12426Sgdamore@opensolaris.org 	default:
1086*12426Sgdamore@opensolaris.org 		freerbuf(bp);
1087*12426Sgdamore@opensolaris.org 		return (EINVAL);
1088*12426Sgdamore@opensolaris.org 	}
1089*12426Sgdamore@opensolaris.org 
1090*12426Sgdamore@opensolaris.org 	bp->b_un.b_addr = bufaddr;
1091*12426Sgdamore@opensolaris.org 	bp->b_bcount = length;
1092*12426Sgdamore@opensolaris.org 	xi = bd_xfer_alloc(bd, bp, func, KM_SLEEP);
1093*12426Sgdamore@opensolaris.org 	if (xi == NULL) {
1094*12426Sgdamore@opensolaris.org 		rv = geterror(bp);
1095*12426Sgdamore@opensolaris.org 		freerbuf(bp);
1096*12426Sgdamore@opensolaris.org 		return (rv);
1097*12426Sgdamore@opensolaris.org 	}
1098*12426Sgdamore@opensolaris.org 
1099*12426Sgdamore@opensolaris.org 	xi->i_blkno = start;
1100*12426Sgdamore@opensolaris.org 	bd_submit(bd, xi);
1101*12426Sgdamore@opensolaris.org 	(void) biowait(bp);
1102*12426Sgdamore@opensolaris.org 	rv = geterror(bp);
1103*12426Sgdamore@opensolaris.org 	freerbuf(bp);
1104*12426Sgdamore@opensolaris.org 
1105*12426Sgdamore@opensolaris.org 	return (rv);
1106*12426Sgdamore@opensolaris.org }
1107*12426Sgdamore@opensolaris.org 
1108*12426Sgdamore@opensolaris.org static int
bd_tg_getinfo(dev_info_t * dip,int cmd,void * arg,void * tg_cookie)1109*12426Sgdamore@opensolaris.org bd_tg_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie)
1110*12426Sgdamore@opensolaris.org {
1111*12426Sgdamore@opensolaris.org 	bd_t		*bd;
1112*12426Sgdamore@opensolaris.org 
1113*12426Sgdamore@opensolaris.org 	_NOTE(ARGUNUSED(dip));
1114*12426Sgdamore@opensolaris.org 	bd = tg_cookie;
1115*12426Sgdamore@opensolaris.org 
1116*12426Sgdamore@opensolaris.org 	switch (cmd) {
1117*12426Sgdamore@opensolaris.org 	case TG_GETPHYGEOM:
1118*12426Sgdamore@opensolaris.org 	case TG_GETVIRTGEOM:
1119*12426Sgdamore@opensolaris.org 		/*
1120*12426Sgdamore@opensolaris.org 		 * We don't have any "geometry" as such, let cmlb
1121*12426Sgdamore@opensolaris.org 		 * fabricate something.
1122*12426Sgdamore@opensolaris.org 		 */
1123*12426Sgdamore@opensolaris.org 		return (ENOTTY);
1124*12426Sgdamore@opensolaris.org 
1125*12426Sgdamore@opensolaris.org 	case TG_GETCAPACITY:
1126*12426Sgdamore@opensolaris.org 		bd_update_state(bd);
1127*12426Sgdamore@opensolaris.org 		*(diskaddr_t *)arg = bd->d_numblks;
1128*12426Sgdamore@opensolaris.org 		return (0);
1129*12426Sgdamore@opensolaris.org 
1130*12426Sgdamore@opensolaris.org 	case TG_GETBLOCKSIZE:
1131*12426Sgdamore@opensolaris.org 		*(uint32_t *)arg = (1U << bd->d_blkshift);
1132*12426Sgdamore@opensolaris.org 		return (0);
1133*12426Sgdamore@opensolaris.org 
1134*12426Sgdamore@opensolaris.org 	case TG_GETATTR:
1135*12426Sgdamore@opensolaris.org 		/*
1136*12426Sgdamore@opensolaris.org 		 * It turns out that cmlb really doesn't do much for
1137*12426Sgdamore@opensolaris.org 		 * non-writable media, but lets make the information
1138*12426Sgdamore@opensolaris.org 		 * available for it in case it does more in the
1139*12426Sgdamore@opensolaris.org 		 * future.  (The value is currently used for
1140*12426Sgdamore@opensolaris.org 		 * triggering special behavior for CD-ROMs.)
1141*12426Sgdamore@opensolaris.org 		 */
1142*12426Sgdamore@opensolaris.org 		bd_update_state(bd);
1143*12426Sgdamore@opensolaris.org 		((tg_attribute_t *)arg)->media_is_writable =
1144*12426Sgdamore@opensolaris.org 		    bd->d_rdonly ? B_FALSE : B_TRUE;
1145*12426Sgdamore@opensolaris.org 		return (0);
1146*12426Sgdamore@opensolaris.org 
1147*12426Sgdamore@opensolaris.org 	default:
1148*12426Sgdamore@opensolaris.org 		return (EINVAL);
1149*12426Sgdamore@opensolaris.org 	}
1150*12426Sgdamore@opensolaris.org }
1151*12426Sgdamore@opensolaris.org 
1152*12426Sgdamore@opensolaris.org 
1153*12426Sgdamore@opensolaris.org static void
bd_sched(bd_t * bd)1154*12426Sgdamore@opensolaris.org bd_sched(bd_t *bd)
1155*12426Sgdamore@opensolaris.org {
1156*12426Sgdamore@opensolaris.org 	bd_xfer_impl_t	*xi;
1157*12426Sgdamore@opensolaris.org 	struct buf	*bp;
1158*12426Sgdamore@opensolaris.org 	int		rv;
1159*12426Sgdamore@opensolaris.org 
1160*12426Sgdamore@opensolaris.org 	ASSERT(mutex_owned(&bd->d_iomutex));
1161*12426Sgdamore@opensolaris.org 
1162*12426Sgdamore@opensolaris.org 	while ((bd->d_qactive < bd->d_qsize) &&
1163*12426Sgdamore@opensolaris.org 	    ((xi = list_remove_head(&bd->d_waitq)) != NULL)) {
1164*12426Sgdamore@opensolaris.org 		bd->d_qactive++;
1165*12426Sgdamore@opensolaris.org 		kstat_waitq_to_runq(bd->d_kiop);
1166*12426Sgdamore@opensolaris.org 		list_insert_tail(&bd->d_runq, xi);
1167*12426Sgdamore@opensolaris.org 
1168*12426Sgdamore@opensolaris.org 		/* Submit the job to driver */
1169*12426Sgdamore@opensolaris.org 		rv = xi->i_func(bd->d_private, &xi->i_public);
1170*12426Sgdamore@opensolaris.org 		if (rv != 0) {
1171*12426Sgdamore@opensolaris.org 			bd->d_qactive--;
1172*12426Sgdamore@opensolaris.org 			kstat_runq_exit(bd->d_kiop);
1173*12426Sgdamore@opensolaris.org 			list_remove(&bd->d_runq, xi);
1174*12426Sgdamore@opensolaris.org 
1175*12426Sgdamore@opensolaris.org 			mutex_exit(&bd->d_iomutex);
1176*12426Sgdamore@opensolaris.org 			bp = xi->i_bp;
1177*12426Sgdamore@opensolaris.org 			bd_xfer_free(xi);
1178*12426Sgdamore@opensolaris.org 			bioerror(bp, rv);
1179*12426Sgdamore@opensolaris.org 			biodone(bp);
1180*12426Sgdamore@opensolaris.org 			mutex_enter(&bd->d_iomutex);
1181*12426Sgdamore@opensolaris.org 		}
1182*12426Sgdamore@opensolaris.org 	}
1183*12426Sgdamore@opensolaris.org }
1184*12426Sgdamore@opensolaris.org 
1185*12426Sgdamore@opensolaris.org static void
bd_submit(bd_t * bd,bd_xfer_impl_t * xi)1186*12426Sgdamore@opensolaris.org bd_submit(bd_t *bd, bd_xfer_impl_t *xi)
1187*12426Sgdamore@opensolaris.org {
1188*12426Sgdamore@opensolaris.org 	mutex_enter(&bd->d_iomutex);
1189*12426Sgdamore@opensolaris.org 	list_insert_tail(&bd->d_waitq, xi);
1190*12426Sgdamore@opensolaris.org 	kstat_waitq_enter(bd->d_kiop);
1191*12426Sgdamore@opensolaris.org 	bd_sched(bd);
1192*12426Sgdamore@opensolaris.org 	mutex_exit(&bd->d_iomutex);
1193*12426Sgdamore@opensolaris.org }
1194*12426Sgdamore@opensolaris.org 
1195*12426Sgdamore@opensolaris.org static void
bd_runq_exit(bd_xfer_impl_t * xi,int err)1196*12426Sgdamore@opensolaris.org bd_runq_exit(bd_xfer_impl_t *xi, int err)
1197*12426Sgdamore@opensolaris.org {
1198*12426Sgdamore@opensolaris.org 	bd_t	*bd = xi->i_bd;
1199*12426Sgdamore@opensolaris.org 	buf_t	*bp = xi->i_bp;
1200*12426Sgdamore@opensolaris.org 
1201*12426Sgdamore@opensolaris.org 	ASSERT(mutex_owned(&bd->d_iomutex));
1202*12426Sgdamore@opensolaris.org 
1203*12426Sgdamore@opensolaris.org 	bd->d_qactive--;
1204*12426Sgdamore@opensolaris.org 	kstat_runq_exit(bd->d_kiop);
1205*12426Sgdamore@opensolaris.org 	if (err == 0) {
1206*12426Sgdamore@opensolaris.org 		if (bp->b_flags & B_READ) {
1207*12426Sgdamore@opensolaris.org 			bd->d_kiop->reads++;
1208*12426Sgdamore@opensolaris.org 			bd->d_kiop->nread += (bp->b_bcount - xi->i_resid);
1209*12426Sgdamore@opensolaris.org 		} else {
1210*12426Sgdamore@opensolaris.org 			bd->d_kiop->writes++;
1211*12426Sgdamore@opensolaris.org 			bd->d_kiop->nwritten += (bp->b_bcount - xi->i_resid);
1212*12426Sgdamore@opensolaris.org 		}
1213*12426Sgdamore@opensolaris.org 	}
1214*12426Sgdamore@opensolaris.org 	list_remove(&bd->d_runq, xi);
1215*12426Sgdamore@opensolaris.org 	bd_sched(bd);
1216*12426Sgdamore@opensolaris.org }
1217*12426Sgdamore@opensolaris.org 
1218*12426Sgdamore@opensolaris.org static void
bd_update_state(bd_t * bd)1219*12426Sgdamore@opensolaris.org bd_update_state(bd_t *bd)
1220*12426Sgdamore@opensolaris.org {
1221*12426Sgdamore@opensolaris.org 	enum	dkio_state	state;
1222*12426Sgdamore@opensolaris.org 	bd_media_t		media;
1223*12426Sgdamore@opensolaris.org 	boolean_t		docmlb = B_FALSE;
1224*12426Sgdamore@opensolaris.org 
1225*12426Sgdamore@opensolaris.org 	bzero(&media, sizeof (media));
1226*12426Sgdamore@opensolaris.org 
1227*12426Sgdamore@opensolaris.org 	mutex_enter(&bd->d_statemutex);
1228*12426Sgdamore@opensolaris.org 	if (bd->d_ops.o_media_info(bd->d_private, &media) == 0) {
1229*12426Sgdamore@opensolaris.org 		if ((1U << bd->d_blkshift) != media.m_blksize) {
1230*12426Sgdamore@opensolaris.org 			if ((media.m_blksize < 512) ||
1231*12426Sgdamore@opensolaris.org 			    (!ISP2(media.m_blksize)) ||
1232*12426Sgdamore@opensolaris.org 			    (P2PHASE(bd->d_maxxfer, media.m_blksize))) {
1233*12426Sgdamore@opensolaris.org 				cmn_err(CE_WARN,
1234*12426Sgdamore@opensolaris.org 				    "%s%d: Invalid media block size (%d)",
1235*12426Sgdamore@opensolaris.org 				    ddi_driver_name(bd->d_dip),
1236*12426Sgdamore@opensolaris.org 				    ddi_get_instance(bd->d_dip),
1237*12426Sgdamore@opensolaris.org 				    media.m_blksize);
1238*12426Sgdamore@opensolaris.org 				/*
1239*12426Sgdamore@opensolaris.org 				 * We can't use the media, treat it as
1240*12426Sgdamore@opensolaris.org 				 * not present.
1241*12426Sgdamore@opensolaris.org 				 */
1242*12426Sgdamore@opensolaris.org 				state = DKIO_EJECTED;
1243*12426Sgdamore@opensolaris.org 				bd->d_numblks = 0;
1244*12426Sgdamore@opensolaris.org 			} else {
1245*12426Sgdamore@opensolaris.org 				bd->d_blkshift = ddi_ffs(media.m_blksize) - 1;
1246*12426Sgdamore@opensolaris.org 				bd->d_numblks = media.m_nblks;
1247*12426Sgdamore@opensolaris.org 				bd->d_rdonly = media.m_readonly;
1248*12426Sgdamore@opensolaris.org 				state = DKIO_INSERTED;
1249*12426Sgdamore@opensolaris.org 			}
1250*12426Sgdamore@opensolaris.org 
1251*12426Sgdamore@opensolaris.org 			/* Device size changed */
1252*12426Sgdamore@opensolaris.org 			docmlb = B_TRUE;
1253*12426Sgdamore@opensolaris.org 
1254*12426Sgdamore@opensolaris.org 		} else {
1255*12426Sgdamore@opensolaris.org 			if (bd->d_numblks != media.m_nblks) {
1256*12426Sgdamore@opensolaris.org 				/* Device size changed */
1257*12426Sgdamore@opensolaris.org 				docmlb = B_TRUE;
1258*12426Sgdamore@opensolaris.org 			}
1259*12426Sgdamore@opensolaris.org 			bd->d_numblks = media.m_nblks;
1260*12426Sgdamore@opensolaris.org 			bd->d_rdonly = media.m_readonly;
1261*12426Sgdamore@opensolaris.org 			state = DKIO_INSERTED;
1262*12426Sgdamore@opensolaris.org 		}
1263*12426Sgdamore@opensolaris.org 
1264*12426Sgdamore@opensolaris.org 	} else {
1265*12426Sgdamore@opensolaris.org 		bd->d_numblks = 0;
1266*12426Sgdamore@opensolaris.org 		state = DKIO_EJECTED;
1267*12426Sgdamore@opensolaris.org 	}
1268*12426Sgdamore@opensolaris.org 	if (state != bd->d_state) {
1269*12426Sgdamore@opensolaris.org 		bd->d_state = state;
1270*12426Sgdamore@opensolaris.org 		cv_broadcast(&bd->d_statecv);
1271*12426Sgdamore@opensolaris.org 		docmlb = B_TRUE;
1272*12426Sgdamore@opensolaris.org 	}
1273*12426Sgdamore@opensolaris.org 	mutex_exit(&bd->d_statemutex);
1274*12426Sgdamore@opensolaris.org 
1275*12426Sgdamore@opensolaris.org 	if (docmlb) {
1276*12426Sgdamore@opensolaris.org 		if (state == DKIO_INSERTED) {
1277*12426Sgdamore@opensolaris.org 			(void) cmlb_validate(bd->d_cmlbh, 0, bd);
1278*12426Sgdamore@opensolaris.org 		} else {
1279*12426Sgdamore@opensolaris.org 			cmlb_invalidate(bd->d_cmlbh, bd);
1280*12426Sgdamore@opensolaris.org 		}
1281*12426Sgdamore@opensolaris.org 	}
1282*12426Sgdamore@opensolaris.org }
1283*12426Sgdamore@opensolaris.org 
1284*12426Sgdamore@opensolaris.org static int
bd_check_state(bd_t * bd,enum dkio_state * state)1285*12426Sgdamore@opensolaris.org bd_check_state(bd_t *bd, enum dkio_state *state)
1286*12426Sgdamore@opensolaris.org {
1287*12426Sgdamore@opensolaris.org 	clock_t		when;
1288*12426Sgdamore@opensolaris.org 
1289*12426Sgdamore@opensolaris.org 	for (;;) {
1290*12426Sgdamore@opensolaris.org 
1291*12426Sgdamore@opensolaris.org 		bd_update_state(bd);
1292*12426Sgdamore@opensolaris.org 
1293*12426Sgdamore@opensolaris.org 		mutex_enter(&bd->d_statemutex);
1294*12426Sgdamore@opensolaris.org 
1295*12426Sgdamore@opensolaris.org 		if (bd->d_state != *state) {
1296*12426Sgdamore@opensolaris.org 			*state = bd->d_state;
1297*12426Sgdamore@opensolaris.org 			mutex_exit(&bd->d_statemutex);
1298*12426Sgdamore@opensolaris.org 			break;
1299*12426Sgdamore@opensolaris.org 		}
1300*12426Sgdamore@opensolaris.org 
1301*12426Sgdamore@opensolaris.org 		when = drv_usectohz(1000000);
1302*12426Sgdamore@opensolaris.org 		if (cv_reltimedwait_sig(&bd->d_statecv, &bd->d_statemutex,
1303*12426Sgdamore@opensolaris.org 		    when, TR_CLOCK_TICK) == 0) {
1304*12426Sgdamore@opensolaris.org 			mutex_exit(&bd->d_statemutex);
1305*12426Sgdamore@opensolaris.org 			return (EINTR);
1306*12426Sgdamore@opensolaris.org 		}
1307*12426Sgdamore@opensolaris.org 
1308*12426Sgdamore@opensolaris.org 		mutex_exit(&bd->d_statemutex);
1309*12426Sgdamore@opensolaris.org 	}
1310*12426Sgdamore@opensolaris.org 
1311*12426Sgdamore@opensolaris.org 	return (0);
1312*12426Sgdamore@opensolaris.org }
1313*12426Sgdamore@opensolaris.org 
1314*12426Sgdamore@opensolaris.org static int
bd_flush_write_cache_done(struct buf * bp)1315*12426Sgdamore@opensolaris.org bd_flush_write_cache_done(struct buf *bp)
1316*12426Sgdamore@opensolaris.org {
1317*12426Sgdamore@opensolaris.org 	struct dk_callback *dc = (void *)bp->b_private;
1318*12426Sgdamore@opensolaris.org 
1319*12426Sgdamore@opensolaris.org 	(*dc->dkc_callback)(dc->dkc_cookie, geterror(bp));
1320*12426Sgdamore@opensolaris.org 	kmem_free(dc, sizeof (*dc));
1321*12426Sgdamore@opensolaris.org 	freerbuf(bp);
1322*12426Sgdamore@opensolaris.org 	return (0);
1323*12426Sgdamore@opensolaris.org }
1324*12426Sgdamore@opensolaris.org 
1325*12426Sgdamore@opensolaris.org static int
bd_flush_write_cache(bd_t * bd,struct dk_callback * dkc)1326*12426Sgdamore@opensolaris.org bd_flush_write_cache(bd_t *bd, struct dk_callback *dkc)
1327*12426Sgdamore@opensolaris.org {
1328*12426Sgdamore@opensolaris.org 	buf_t			*bp;
1329*12426Sgdamore@opensolaris.org 	struct dk_callback	*dc;
1330*12426Sgdamore@opensolaris.org 	bd_xfer_impl_t		*xi;
1331*12426Sgdamore@opensolaris.org 	int			rv;
1332*12426Sgdamore@opensolaris.org 
1333*12426Sgdamore@opensolaris.org 	if (bd->d_ops.o_sync_cache == NULL) {
1334*12426Sgdamore@opensolaris.org 		return (ENOTSUP);
1335*12426Sgdamore@opensolaris.org 	}
1336*12426Sgdamore@opensolaris.org 	if ((bp = getrbuf(KM_SLEEP)) == NULL) {
1337*12426Sgdamore@opensolaris.org 		return (ENOMEM);
1338*12426Sgdamore@opensolaris.org 	}
1339*12426Sgdamore@opensolaris.org 	bp->b_resid = 0;
1340*12426Sgdamore@opensolaris.org 	bp->b_bcount = 0;
1341*12426Sgdamore@opensolaris.org 
1342*12426Sgdamore@opensolaris.org 	xi = bd_xfer_alloc(bd, bp, bd->d_ops.o_sync_cache, KM_SLEEP);
1343*12426Sgdamore@opensolaris.org 	if (xi == NULL) {
1344*12426Sgdamore@opensolaris.org 		rv = geterror(bp);
1345*12426Sgdamore@opensolaris.org 		freerbuf(bp);
1346*12426Sgdamore@opensolaris.org 		return (rv);
1347*12426Sgdamore@opensolaris.org 	}
1348*12426Sgdamore@opensolaris.org 
1349*12426Sgdamore@opensolaris.org 	if (dkc != NULL) {
1350*12426Sgdamore@opensolaris.org 		/* Make a private copy of the callback structure */
1351*12426Sgdamore@opensolaris.org 		dc = kmem_alloc(sizeof (*dc), KM_SLEEP);
1352*12426Sgdamore@opensolaris.org 		*dc = *dkc;
1353*12426Sgdamore@opensolaris.org 		bp->b_private = dc;
1354*12426Sgdamore@opensolaris.org 		bp->b_iodone = bd_flush_write_cache_done;
1355*12426Sgdamore@opensolaris.org 	}
1356*12426Sgdamore@opensolaris.org 
1357*12426Sgdamore@opensolaris.org 	bd_submit(bd, xi);
1358*12426Sgdamore@opensolaris.org 	if (dkc == NULL) {
1359*12426Sgdamore@opensolaris.org 		/* wait synchronously */
1360*12426Sgdamore@opensolaris.org 		(void) biowait(bp);
1361*12426Sgdamore@opensolaris.org 		rv = geterror(bp);
1362*12426Sgdamore@opensolaris.org 		freerbuf(bp);
1363*12426Sgdamore@opensolaris.org 	} else {
1364*12426Sgdamore@opensolaris.org 		/* deferred via callback */
1365*12426Sgdamore@opensolaris.org 		rv = 0;
1366*12426Sgdamore@opensolaris.org 	}
1367*12426Sgdamore@opensolaris.org 	return (rv);
1368*12426Sgdamore@opensolaris.org }
1369*12426Sgdamore@opensolaris.org 
1370*12426Sgdamore@opensolaris.org /*
1371*12426Sgdamore@opensolaris.org  * Nexus support.
1372*12426Sgdamore@opensolaris.org  */
1373*12426Sgdamore@opensolaris.org int
bd_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)1374*12426Sgdamore@opensolaris.org bd_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
1375*12426Sgdamore@opensolaris.org     void *arg, void *result)
1376*12426Sgdamore@opensolaris.org {
1377*12426Sgdamore@opensolaris.org 	bd_handle_t	hdl;
1378*12426Sgdamore@opensolaris.org 
1379*12426Sgdamore@opensolaris.org 	switch (ctlop) {
1380*12426Sgdamore@opensolaris.org 	case DDI_CTLOPS_REPORTDEV:
1381*12426Sgdamore@opensolaris.org 		cmn_err(CE_CONT, "?Block device: %s@%s, %s%d\n",
1382*12426Sgdamore@opensolaris.org 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
1383*12426Sgdamore@opensolaris.org 		    ddi_driver_name(rdip), ddi_get_instance(rdip));
1384*12426Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
1385*12426Sgdamore@opensolaris.org 
1386*12426Sgdamore@opensolaris.org 	case DDI_CTLOPS_INITCHILD:
1387*12426Sgdamore@opensolaris.org 		hdl = ddi_get_parent_data((dev_info_t *)arg);
1388*12426Sgdamore@opensolaris.org 		if (hdl == NULL) {
1389*12426Sgdamore@opensolaris.org 			return (DDI_NOT_WELL_FORMED);
1390*12426Sgdamore@opensolaris.org 		}
1391*12426Sgdamore@opensolaris.org 		ddi_set_name_addr((dev_info_t *)arg, hdl->h_addr);
1392*12426Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
1393*12426Sgdamore@opensolaris.org 
1394*12426Sgdamore@opensolaris.org 	case DDI_CTLOPS_UNINITCHILD:
1395*12426Sgdamore@opensolaris.org 		ddi_set_name_addr((dev_info_t *)arg, NULL);
1396*12426Sgdamore@opensolaris.org 		ndi_prop_remove_all((dev_info_t *)arg);
1397*12426Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
1398*12426Sgdamore@opensolaris.org 
1399*12426Sgdamore@opensolaris.org 	default:
1400*12426Sgdamore@opensolaris.org 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
1401*12426Sgdamore@opensolaris.org 	}
1402*12426Sgdamore@opensolaris.org }
1403*12426Sgdamore@opensolaris.org 
1404*12426Sgdamore@opensolaris.org /*
1405*12426Sgdamore@opensolaris.org  * Functions for device drivers.
1406*12426Sgdamore@opensolaris.org  */
1407*12426Sgdamore@opensolaris.org bd_handle_t
bd_alloc_handle(void * private,bd_ops_t * ops,ddi_dma_attr_t * dma,int kmflag)1408*12426Sgdamore@opensolaris.org bd_alloc_handle(void *private, bd_ops_t *ops, ddi_dma_attr_t *dma, int kmflag)
1409*12426Sgdamore@opensolaris.org {
1410*12426Sgdamore@opensolaris.org 	bd_handle_t	hdl;
1411*12426Sgdamore@opensolaris.org 
1412*12426Sgdamore@opensolaris.org 	hdl = kmem_zalloc(sizeof (*hdl), kmflag);
1413*12426Sgdamore@opensolaris.org 	if (hdl != NULL) {
1414*12426Sgdamore@opensolaris.org 		hdl->h_ops = *ops;
1415*12426Sgdamore@opensolaris.org 		hdl->h_dma = dma;
1416*12426Sgdamore@opensolaris.org 		hdl->h_private = private;
1417*12426Sgdamore@opensolaris.org 	}
1418*12426Sgdamore@opensolaris.org 
1419*12426Sgdamore@opensolaris.org 	return (hdl);
1420*12426Sgdamore@opensolaris.org }
1421*12426Sgdamore@opensolaris.org 
1422*12426Sgdamore@opensolaris.org void
bd_free_handle(bd_handle_t hdl)1423*12426Sgdamore@opensolaris.org bd_free_handle(bd_handle_t hdl)
1424*12426Sgdamore@opensolaris.org {
1425*12426Sgdamore@opensolaris.org 	kmem_free(hdl, sizeof (*hdl));
1426*12426Sgdamore@opensolaris.org }
1427*12426Sgdamore@opensolaris.org 
1428*12426Sgdamore@opensolaris.org int
bd_attach_handle(dev_info_t * dip,bd_handle_t hdl)1429*12426Sgdamore@opensolaris.org bd_attach_handle(dev_info_t *dip, bd_handle_t hdl)
1430*12426Sgdamore@opensolaris.org {
1431*12426Sgdamore@opensolaris.org 	dev_info_t	*child;
1432*12426Sgdamore@opensolaris.org 	bd_drive_t	drive;
1433*12426Sgdamore@opensolaris.org 
1434*12426Sgdamore@opensolaris.org 	/* if drivers don't override this, make it assume none */
1435*12426Sgdamore@opensolaris.org 	drive.d_lun = -1;
1436*12426Sgdamore@opensolaris.org 	hdl->h_ops.o_drive_info(hdl->h_private, &drive);
1437*12426Sgdamore@opensolaris.org 
1438*12426Sgdamore@opensolaris.org 	hdl->h_parent = dip;
1439*12426Sgdamore@opensolaris.org 	hdl->h_name = "blkdev";
1440*12426Sgdamore@opensolaris.org 
1441*12426Sgdamore@opensolaris.org 	if (drive.d_lun >= 0) {
1442*12426Sgdamore@opensolaris.org 		(void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), "%X,%X",
1443*12426Sgdamore@opensolaris.org 		    drive.d_target, drive.d_lun);
1444*12426Sgdamore@opensolaris.org 	} else {
1445*12426Sgdamore@opensolaris.org 		(void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), "%X",
1446*12426Sgdamore@opensolaris.org 		    drive.d_target);
1447*12426Sgdamore@opensolaris.org 	}
1448*12426Sgdamore@opensolaris.org 	if (ndi_devi_alloc(dip, hdl->h_name, (pnode_t)DEVI_SID_NODEID,
1449*12426Sgdamore@opensolaris.org 	    &child) != NDI_SUCCESS) {
1450*12426Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "%s%d: unable to allocate node %s@%s",
1451*12426Sgdamore@opensolaris.org 		    ddi_driver_name(dip), ddi_get_instance(dip),
1452*12426Sgdamore@opensolaris.org 		    "blkdev", hdl->h_addr);
1453*12426Sgdamore@opensolaris.org 		return (DDI_FAILURE);
1454*12426Sgdamore@opensolaris.org 	}
1455*12426Sgdamore@opensolaris.org 
1456*12426Sgdamore@opensolaris.org 	ddi_set_parent_data(child, hdl);
1457*12426Sgdamore@opensolaris.org 	hdl->h_child = child;
1458*12426Sgdamore@opensolaris.org 
1459*12426Sgdamore@opensolaris.org 	if (ndi_devi_online(child, 0) == NDI_FAILURE) {
1460*12426Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "%s%d: failed bringing node %s@%s online",
1461*12426Sgdamore@opensolaris.org 		    ddi_driver_name(dip), ddi_get_instance(dip),
1462*12426Sgdamore@opensolaris.org 		    hdl->h_name, hdl->h_addr);
1463*12426Sgdamore@opensolaris.org 		(void) ndi_devi_free(child);
1464*12426Sgdamore@opensolaris.org 		return (DDI_FAILURE);
1465*12426Sgdamore@opensolaris.org 	}
1466*12426Sgdamore@opensolaris.org 
1467*12426Sgdamore@opensolaris.org 	return (DDI_SUCCESS);
1468*12426Sgdamore@opensolaris.org }
1469*12426Sgdamore@opensolaris.org 
1470*12426Sgdamore@opensolaris.org int
bd_detach_handle(bd_handle_t hdl)1471*12426Sgdamore@opensolaris.org bd_detach_handle(bd_handle_t hdl)
1472*12426Sgdamore@opensolaris.org {
1473*12426Sgdamore@opensolaris.org 	int	circ;
1474*12426Sgdamore@opensolaris.org 	int	rv;
1475*12426Sgdamore@opensolaris.org 	char	*devnm;
1476*12426Sgdamore@opensolaris.org 
1477*12426Sgdamore@opensolaris.org 	if (hdl->h_child == NULL) {
1478*12426Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
1479*12426Sgdamore@opensolaris.org 	}
1480*12426Sgdamore@opensolaris.org 	ndi_devi_enter(hdl->h_parent, &circ);
1481*12426Sgdamore@opensolaris.org 	if (i_ddi_node_state(hdl->h_child) < DS_INITIALIZED) {
1482*12426Sgdamore@opensolaris.org 		rv = ddi_remove_child(hdl->h_child, 0);
1483*12426Sgdamore@opensolaris.org 	} else {
1484*12426Sgdamore@opensolaris.org 		devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
1485*12426Sgdamore@opensolaris.org 		(void) ddi_deviname(hdl->h_child, devnm);
1486*12426Sgdamore@opensolaris.org 		(void) devfs_clean(hdl->h_parent, devnm + 1, DV_CLEAN_FORCE);
1487*12426Sgdamore@opensolaris.org 		rv = ndi_devi_unconfig_one(hdl->h_parent, devnm + 1, NULL,
1488*12426Sgdamore@opensolaris.org 		    NDI_DEVI_REMOVE | NDI_UNCONFIG);
1489*12426Sgdamore@opensolaris.org 		kmem_free(devnm, MAXNAMELEN + 1);
1490*12426Sgdamore@opensolaris.org 	}
1491*12426Sgdamore@opensolaris.org 	if (rv == 0) {
1492*12426Sgdamore@opensolaris.org 		hdl->h_child = NULL;
1493*12426Sgdamore@opensolaris.org 	}
1494*12426Sgdamore@opensolaris.org 
1495*12426Sgdamore@opensolaris.org 	ndi_devi_exit(hdl->h_parent, circ);
1496*12426Sgdamore@opensolaris.org 	return (rv = NDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
1497*12426Sgdamore@opensolaris.org }
1498*12426Sgdamore@opensolaris.org 
1499*12426Sgdamore@opensolaris.org void
bd_xfer_done(bd_xfer_t * xfer,int err)1500*12426Sgdamore@opensolaris.org bd_xfer_done(bd_xfer_t *xfer, int err)
1501*12426Sgdamore@opensolaris.org {
1502*12426Sgdamore@opensolaris.org 	bd_xfer_impl_t	*xi = (void *)xfer;
1503*12426Sgdamore@opensolaris.org 	buf_t		*bp = xi->i_bp;
1504*12426Sgdamore@opensolaris.org 	int		rv;
1505*12426Sgdamore@opensolaris.org 	bd_t		*bd = xi->i_bd;
1506*12426Sgdamore@opensolaris.org 	size_t		len;
1507*12426Sgdamore@opensolaris.org 
1508*12426Sgdamore@opensolaris.org 	mutex_enter(&bd->d_iomutex);
1509*12426Sgdamore@opensolaris.org 	if (err != 0) {
1510*12426Sgdamore@opensolaris.org 		bd_runq_exit(xi, err);
1511*12426Sgdamore@opensolaris.org 		mutex_exit(&bd->d_iomutex);
1512*12426Sgdamore@opensolaris.org 
1513*12426Sgdamore@opensolaris.org 		bp->b_resid += xi->i_resid;
1514*12426Sgdamore@opensolaris.org 		bd_xfer_free(xi);
1515*12426Sgdamore@opensolaris.org 		bioerror(bp, err);
1516*12426Sgdamore@opensolaris.org 		biodone(bp);
1517*12426Sgdamore@opensolaris.org 		return;
1518*12426Sgdamore@opensolaris.org 	}
1519*12426Sgdamore@opensolaris.org 
1520*12426Sgdamore@opensolaris.org 	xi->i_cur_win++;
1521*12426Sgdamore@opensolaris.org 	xi->i_resid -= xi->i_len;
1522*12426Sgdamore@opensolaris.org 
1523*12426Sgdamore@opensolaris.org 	if (xi->i_resid == 0) {
1524*12426Sgdamore@opensolaris.org 		/* Job completed succcessfully! */
1525*12426Sgdamore@opensolaris.org 		bd_runq_exit(xi, 0);
1526*12426Sgdamore@opensolaris.org 		mutex_exit(&bd->d_iomutex);
1527*12426Sgdamore@opensolaris.org 
1528*12426Sgdamore@opensolaris.org 		bd_xfer_free(xi);
1529*12426Sgdamore@opensolaris.org 		biodone(bp);
1530*12426Sgdamore@opensolaris.org 		return;
1531*12426Sgdamore@opensolaris.org 	}
1532*12426Sgdamore@opensolaris.org 
1533*12426Sgdamore@opensolaris.org 	xi->i_blkno += xi->i_nblks;
1534*12426Sgdamore@opensolaris.org 
1535*12426Sgdamore@opensolaris.org 	if (bd->d_use_dma) {
1536*12426Sgdamore@opensolaris.org 		/* More transfer still pending... advance to next DMA window. */
1537*12426Sgdamore@opensolaris.org 		rv = ddi_dma_getwin(xi->i_dmah, xi->i_cur_win,
1538*12426Sgdamore@opensolaris.org 		    &xi->i_offset, &len, &xi->i_dmac, &xi->i_ndmac);
1539*12426Sgdamore@opensolaris.org 	} else {
1540*12426Sgdamore@opensolaris.org 		/* Advance memory window. */
1541*12426Sgdamore@opensolaris.org 		xi->i_kaddr += xi->i_len;
1542*12426Sgdamore@opensolaris.org 		xi->i_offset += xi->i_len;
1543*12426Sgdamore@opensolaris.org 		len = min(bp->b_bcount - xi->i_offset, bd->d_maxxfer);
1544*12426Sgdamore@opensolaris.org 	}
1545*12426Sgdamore@opensolaris.org 
1546*12426Sgdamore@opensolaris.org 
1547*12426Sgdamore@opensolaris.org 	if ((rv != DDI_SUCCESS) ||
1548*12426Sgdamore@opensolaris.org 	    (P2PHASE(len, (1U << xi->i_blkshift) != 0))) {
1549*12426Sgdamore@opensolaris.org 		bd_runq_exit(xi, EFAULT);
1550*12426Sgdamore@opensolaris.org 		mutex_exit(&bd->d_iomutex);
1551*12426Sgdamore@opensolaris.org 
1552*12426Sgdamore@opensolaris.org 		bp->b_resid += xi->i_resid;
1553*12426Sgdamore@opensolaris.org 		bd_xfer_free(xi);
1554*12426Sgdamore@opensolaris.org 		bioerror(bp, EFAULT);
1555*12426Sgdamore@opensolaris.org 		biodone(bp);
1556*12426Sgdamore@opensolaris.org 		return;
1557*12426Sgdamore@opensolaris.org 	}
1558*12426Sgdamore@opensolaris.org 	xi->i_len = len;
1559*12426Sgdamore@opensolaris.org 	xi->i_nblks = len >> xi->i_blkshift;
1560*12426Sgdamore@opensolaris.org 
1561*12426Sgdamore@opensolaris.org 	/* Submit next window to hardware. */
1562*12426Sgdamore@opensolaris.org 	rv = xi->i_func(bd->d_private, &xi->i_public);
1563*12426Sgdamore@opensolaris.org 	if (rv != 0) {
1564*12426Sgdamore@opensolaris.org 		bd_runq_exit(xi, rv);
1565*12426Sgdamore@opensolaris.org 		mutex_exit(&bd->d_iomutex);
1566*12426Sgdamore@opensolaris.org 
1567*12426Sgdamore@opensolaris.org 		bp->b_resid += xi->i_resid;
1568*12426Sgdamore@opensolaris.org 		bd_xfer_free(xi);
1569*12426Sgdamore@opensolaris.org 		bioerror(bp, rv);
1570*12426Sgdamore@opensolaris.org 		biodone(bp);
1571*12426Sgdamore@opensolaris.org 		return;
1572*12426Sgdamore@opensolaris.org 	}
1573*12426Sgdamore@opensolaris.org 
1574*12426Sgdamore@opensolaris.org 	mutex_exit(&bd->d_iomutex);
1575*12426Sgdamore@opensolaris.org }
1576*12426Sgdamore@opensolaris.org 
1577*12426Sgdamore@opensolaris.org void
bd_state_change(bd_handle_t hdl)1578*12426Sgdamore@opensolaris.org bd_state_change(bd_handle_t hdl)
1579*12426Sgdamore@opensolaris.org {
1580*12426Sgdamore@opensolaris.org 	bd_t		*bd;
1581*12426Sgdamore@opensolaris.org 
1582*12426Sgdamore@opensolaris.org 	if ((bd = hdl->h_bd) != NULL) {
1583*12426Sgdamore@opensolaris.org 		bd_update_state(bd);
1584*12426Sgdamore@opensolaris.org 	}
1585*12426Sgdamore@opensolaris.org }
1586*12426Sgdamore@opensolaris.org 
1587*12426Sgdamore@opensolaris.org void
bd_mod_init(struct dev_ops * devops)1588*12426Sgdamore@opensolaris.org bd_mod_init(struct dev_ops *devops)
1589*12426Sgdamore@opensolaris.org {
1590*12426Sgdamore@opensolaris.org 	static struct bus_ops bd_bus_ops = {
1591*12426Sgdamore@opensolaris.org 		BUSO_REV,		/* busops_rev */
1592*12426Sgdamore@opensolaris.org 		nullbusmap,		/* bus_map */
1593*12426Sgdamore@opensolaris.org 		NULL,			/* bus_get_intrspec (OBSOLETE) */
1594*12426Sgdamore@opensolaris.org 		NULL,			/* bus_add_intrspec (OBSOLETE) */
1595*12426Sgdamore@opensolaris.org 		NULL,			/* bus_remove_intrspec (OBSOLETE) */
1596*12426Sgdamore@opensolaris.org 		i_ddi_map_fault,	/* bus_map_fault */
1597*12426Sgdamore@opensolaris.org 		ddi_dma_map,		/* bus_dma_map */
1598*12426Sgdamore@opensolaris.org 		ddi_dma_allochdl,	/* bus_dma_allochdl */
1599*12426Sgdamore@opensolaris.org 		ddi_dma_freehdl,	/* bus_dma_freehdl */
1600*12426Sgdamore@opensolaris.org 		ddi_dma_bindhdl,	/* bus_dma_bindhdl */
1601*12426Sgdamore@opensolaris.org 		ddi_dma_unbindhdl,	/* bus_dma_unbindhdl */
1602*12426Sgdamore@opensolaris.org 		ddi_dma_flush,		/* bus_dma_flush */
1603*12426Sgdamore@opensolaris.org 		ddi_dma_win,		/* bus_dma_win */
1604*12426Sgdamore@opensolaris.org 		ddi_dma_mctl,		/* bus_dma_ctl */
1605*12426Sgdamore@opensolaris.org 		bd_bus_ctl,		/* bus_ctl */
1606*12426Sgdamore@opensolaris.org 		ddi_bus_prop_op,	/* bus_prop_op */
1607*12426Sgdamore@opensolaris.org 		NULL,			/* bus_get_eventcookie */
1608*12426Sgdamore@opensolaris.org 		NULL,			/* bus_add_eventcall */
1609*12426Sgdamore@opensolaris.org 		NULL,			/* bus_remove_eventcall */
1610*12426Sgdamore@opensolaris.org 		NULL,			/* bus_post_event */
1611*12426Sgdamore@opensolaris.org 		NULL,			/* bus_intr_ctl (OBSOLETE) */
1612*12426Sgdamore@opensolaris.org 		NULL,			/* bus_config */
1613*12426Sgdamore@opensolaris.org 		NULL,			/* bus_unconfig */
1614*12426Sgdamore@opensolaris.org 		NULL,			/* bus_fm_init */
1615*12426Sgdamore@opensolaris.org 		NULL,			/* bus_fm_fini */
1616*12426Sgdamore@opensolaris.org 		NULL,			/* bus_fm_access_enter */
1617*12426Sgdamore@opensolaris.org 		NULL,			/* bus_fm_access_exit */
1618*12426Sgdamore@opensolaris.org 		NULL,			/* bus_power */
1619*12426Sgdamore@opensolaris.org 		NULL,			/* bus_intr_op */
1620*12426Sgdamore@opensolaris.org 	};
1621*12426Sgdamore@opensolaris.org 
1622*12426Sgdamore@opensolaris.org 	devops->devo_bus_ops = &bd_bus_ops;
1623*12426Sgdamore@opensolaris.org 
1624*12426Sgdamore@opensolaris.org 	/*
1625*12426Sgdamore@opensolaris.org 	 * NB: The device driver is free to supply its own
1626*12426Sgdamore@opensolaris.org 	 * character entry device support.
1627*12426Sgdamore@opensolaris.org 	 */
1628*12426Sgdamore@opensolaris.org }
1629*12426Sgdamore@opensolaris.org 
1630*12426Sgdamore@opensolaris.org void
bd_mod_fini(struct dev_ops * devops)1631*12426Sgdamore@opensolaris.org bd_mod_fini(struct dev_ops *devops)
1632*12426Sgdamore@opensolaris.org {
1633*12426Sgdamore@opensolaris.org 	devops->devo_bus_ops = NULL;
1634*12426Sgdamore@opensolaris.org }
1635