xref: /onnv-gate/usr/src/uts/common/avs/ns/nsctl/nsc_disk.c (revision 7836:4e95154b5b7a)
1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM  * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM  *
4*7836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM  *
8*7836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM  * and limitations under the License.
12*7836SJohn.Forte@Sun.COM  *
13*7836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM  *
19*7836SJohn.Forte@Sun.COM  * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM  */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7836SJohn.Forte@Sun.COM  * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM  */
25*7836SJohn.Forte@Sun.COM 
26*7836SJohn.Forte@Sun.COM #include <sys/types.h>
27*7836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
28*7836SJohn.Forte@Sun.COM #include <sys/errno.h>
29*7836SJohn.Forte@Sun.COM #include <sys/file.h>
30*7836SJohn.Forte@Sun.COM #include <sys/open.h>
31*7836SJohn.Forte@Sun.COM #include <sys/cred.h>
32*7836SJohn.Forte@Sun.COM #include <sys/kmem.h>
33*7836SJohn.Forte@Sun.COM #include <sys/uio.h>
34*7836SJohn.Forte@Sun.COM #include <sys/ddi.h>
35*7836SJohn.Forte@Sun.COM #include <sys/sdt.h>
36*7836SJohn.Forte@Sun.COM 
37*7836SJohn.Forte@Sun.COM #define	__NSC_GEN__
38*7836SJohn.Forte@Sun.COM #include "nsc_dev.h"
39*7836SJohn.Forte@Sun.COM #include "nsc_disk.h"
40*7836SJohn.Forte@Sun.COM #include "../nsctl.h"
41*7836SJohn.Forte@Sun.COM 
42*7836SJohn.Forte@Sun.COM 
43*7836SJohn.Forte@Sun.COM #define	_I(x)	(((long)(&((nsc_io_t *)0)->x))/sizeof (long))
44*7836SJohn.Forte@Sun.COM 
45*7836SJohn.Forte@Sun.COM nsc_def_t _nsc_disk_def[] = {
46*7836SJohn.Forte@Sun.COM 	"UserRead",	(uintptr_t)nsc_ioerr,	_I(uread),
47*7836SJohn.Forte@Sun.COM 	"UserWrite",	(uintptr_t)nsc_ioerr,	_I(uwrite),
48*7836SJohn.Forte@Sun.COM 	"PartSize",	(uintptr_t)nsc_null,	_I(partsize),
49*7836SJohn.Forte@Sun.COM 	"MaxFbas",	(uintptr_t)nsc_null,	_I(maxfbas),
50*7836SJohn.Forte@Sun.COM 	"Control",	(uintptr_t)nsc_ioerr,	_I(control),
51*7836SJohn.Forte@Sun.COM 	0,		0,		0
52*7836SJohn.Forte@Sun.COM };
53*7836SJohn.Forte@Sun.COM 
54*7836SJohn.Forte@Sun.COM 
55*7836SJohn.Forte@Sun.COM extern nsc_mem_t *_nsc_local_mem;
56*7836SJohn.Forte@Sun.COM 
57*7836SJohn.Forte@Sun.COM static int _nsc_uread(dev_t, uio_t *, cred_t *, nsc_fd_t *);
58*7836SJohn.Forte@Sun.COM static int _nsc_uwrite(dev_t, uio_t *, cred_t *, nsc_fd_t *);
59*7836SJohn.Forte@Sun.COM static int _nsc_rw_uio(nsc_fd_t *, uio_t *, uio_rw_t);
60*7836SJohn.Forte@Sun.COM 
61*7836SJohn.Forte@Sun.COM static int _nsc_free_dhandle(nsc_dbuf_t *);
62*7836SJohn.Forte@Sun.COM static int _nsc_alloc_dbuf(blind_t, nsc_off_t, nsc_size_t, int, nsc_dbuf_t **);
63*7836SJohn.Forte@Sun.COM static int _nsc_free_dbuf(nsc_dbuf_t *);
64*7836SJohn.Forte@Sun.COM static void _nsc_wait_dbuf(nsc_dbuf_t *);
65*7836SJohn.Forte@Sun.COM static int _nsc_read_dbuf(nsc_dbuf_t *, nsc_off_t, nsc_size_t, int);
66*7836SJohn.Forte@Sun.COM static int _nsc_write_dbuf(nsc_dbuf_t *, nsc_off_t, nsc_size_t, int);
67*7836SJohn.Forte@Sun.COM static int _nsc_zero_dbuf(nsc_dbuf_t *, nsc_off_t, nsc_size_t, int);
68*7836SJohn.Forte@Sun.COM static int _nsc_dbuf_io(int (*)(), nsc_dbuf_t *, nsc_off_t, nsc_size_t, int);
69*7836SJohn.Forte@Sun.COM 
70*7836SJohn.Forte@Sun.COM static nsc_dbuf_t *_nsc_alloc_dhandle(void (*)(), void (*)(), void (*)());
71*7836SJohn.Forte@Sun.COM 
72*7836SJohn.Forte@Sun.COM 
73*7836SJohn.Forte@Sun.COM /*
74*7836SJohn.Forte@Sun.COM  * void
75*7836SJohn.Forte@Sun.COM  * _nsc_add_disk (nsc_io_t *io)
76*7836SJohn.Forte@Sun.COM  *	Add disk interface functions.
77*7836SJohn.Forte@Sun.COM  *
78*7836SJohn.Forte@Sun.COM  * Calling/Exit State:
79*7836SJohn.Forte@Sun.COM  *	Updates the I/O module with the appropriate
80*7836SJohn.Forte@Sun.COM  *	interface routines.
81*7836SJohn.Forte@Sun.COM  *
82*7836SJohn.Forte@Sun.COM  * Description:
83*7836SJohn.Forte@Sun.COM  *	Add functions to the I/O module to provide a disk
84*7836SJohn.Forte@Sun.COM  *	or cache interface as appropriate.
85*7836SJohn.Forte@Sun.COM  */
86*7836SJohn.Forte@Sun.COM void
_nsc_add_disk(nsc_io_t * io)87*7836SJohn.Forte@Sun.COM _nsc_add_disk(nsc_io_t *io)
88*7836SJohn.Forte@Sun.COM {
89*7836SJohn.Forte@Sun.COM 	if ((io->alloc_buf != nsc_ioerr && io->free_buf != nsc_fatal) ||
90*7836SJohn.Forte@Sun.COM 	    (io->flag & NSC_FILTER)) {
91*7836SJohn.Forte@Sun.COM 		if (io->uread == nsc_ioerr)
92*7836SJohn.Forte@Sun.COM 			io->uread = _nsc_uread;
93*7836SJohn.Forte@Sun.COM 
94*7836SJohn.Forte@Sun.COM 		if (io->uwrite == nsc_ioerr &&
95*7836SJohn.Forte@Sun.COM 		    (io->write != nsc_fatal || (io->flag & NSC_FILTER)))
96*7836SJohn.Forte@Sun.COM 			io->uwrite = _nsc_uwrite;
97*7836SJohn.Forte@Sun.COM 
98*7836SJohn.Forte@Sun.COM 		return;
99*7836SJohn.Forte@Sun.COM 	}
100*7836SJohn.Forte@Sun.COM 
101*7836SJohn.Forte@Sun.COM 	if (io->alloc_h != (nsc_buf_t *(*)())nsc_null ||
102*7836SJohn.Forte@Sun.COM 	    io->free_h != nsc_fatal || io->alloc_buf != nsc_ioerr ||
103*7836SJohn.Forte@Sun.COM 	    io->free_buf != nsc_fatal || io->read != nsc_fatal ||
104*7836SJohn.Forte@Sun.COM 	    io->write != nsc_fatal || io->zero != nsc_fatal)
105*7836SJohn.Forte@Sun.COM 		return;
106*7836SJohn.Forte@Sun.COM 
107*7836SJohn.Forte@Sun.COM 	if (io->uread == nsc_ioerr && io->uwrite == nsc_ioerr)
108*7836SJohn.Forte@Sun.COM 		return;
109*7836SJohn.Forte@Sun.COM 
110*7836SJohn.Forte@Sun.COM 	/*
111*7836SJohn.Forte@Sun.COM 	 * Layer the generic nsc_buf_t provider onto a uio_t provider.
112*7836SJohn.Forte@Sun.COM 	 */
113*7836SJohn.Forte@Sun.COM 
114*7836SJohn.Forte@Sun.COM 	io->alloc_h = (nsc_buf_t *(*)())_nsc_alloc_dhandle;
115*7836SJohn.Forte@Sun.COM 	io->free_h = _nsc_free_dhandle;
116*7836SJohn.Forte@Sun.COM 	io->alloc_buf = _nsc_alloc_dbuf;
117*7836SJohn.Forte@Sun.COM 	io->free_buf = _nsc_free_dbuf;
118*7836SJohn.Forte@Sun.COM 
119*7836SJohn.Forte@Sun.COM 	io->read = _nsc_read_dbuf;
120*7836SJohn.Forte@Sun.COM 	io->write = _nsc_write_dbuf;
121*7836SJohn.Forte@Sun.COM 	io->zero = _nsc_zero_dbuf;
122*7836SJohn.Forte@Sun.COM 
123*7836SJohn.Forte@Sun.COM 	io->provide |= NSC_ANON;
124*7836SJohn.Forte@Sun.COM }
125*7836SJohn.Forte@Sun.COM 
126*7836SJohn.Forte@Sun.COM 
127*7836SJohn.Forte@Sun.COM int
nsc_uread(nsc_fd_t * fd,void * uiop,void * crp)128*7836SJohn.Forte@Sun.COM nsc_uread(nsc_fd_t *fd, void *uiop, void *crp)
129*7836SJohn.Forte@Sun.COM {
130*7836SJohn.Forte@Sun.COM 	return (*fd->sf_aio->uread)(fd->sf_cd, uiop, crp, fd);
131*7836SJohn.Forte@Sun.COM }
132*7836SJohn.Forte@Sun.COM 
133*7836SJohn.Forte@Sun.COM 
134*7836SJohn.Forte@Sun.COM int
nsc_uwrite(nsc_fd_t * fd,void * uiop,void * crp)135*7836SJohn.Forte@Sun.COM nsc_uwrite(nsc_fd_t *fd, void *uiop, void *crp)
136*7836SJohn.Forte@Sun.COM {
137*7836SJohn.Forte@Sun.COM 	if ((fd->sf_avail & NSC_WRITE) == 0)
138*7836SJohn.Forte@Sun.COM 		return (EIO);
139*7836SJohn.Forte@Sun.COM 
140*7836SJohn.Forte@Sun.COM 	return (*fd->sf_aio->uwrite)(fd->sf_cd, uiop, crp, fd);
141*7836SJohn.Forte@Sun.COM }
142*7836SJohn.Forte@Sun.COM 
143*7836SJohn.Forte@Sun.COM 
144*7836SJohn.Forte@Sun.COM int
nsc_partsize(nsc_fd_t * fd,nsc_size_t * valp)145*7836SJohn.Forte@Sun.COM nsc_partsize(nsc_fd_t *fd, nsc_size_t *valp)
146*7836SJohn.Forte@Sun.COM {
147*7836SJohn.Forte@Sun.COM 	*valp = 0;
148*7836SJohn.Forte@Sun.COM 	return (*fd->sf_aio->partsize)(fd->sf_cd, valp);
149*7836SJohn.Forte@Sun.COM }
150*7836SJohn.Forte@Sun.COM 
151*7836SJohn.Forte@Sun.COM 
152*7836SJohn.Forte@Sun.COM int
nsc_maxfbas(nsc_fd_t * fd,int flag,nsc_size_t * valp)153*7836SJohn.Forte@Sun.COM nsc_maxfbas(nsc_fd_t *fd, int flag, nsc_size_t *valp)
154*7836SJohn.Forte@Sun.COM {
155*7836SJohn.Forte@Sun.COM 	*valp = 0;
156*7836SJohn.Forte@Sun.COM 	return (*fd->sf_aio->maxfbas)(fd->sf_cd, flag, valp);
157*7836SJohn.Forte@Sun.COM }
158*7836SJohn.Forte@Sun.COM 
159*7836SJohn.Forte@Sun.COM int
nsc_control(nsc_fd_t * fd,int command,void * argp,int argl)160*7836SJohn.Forte@Sun.COM nsc_control(nsc_fd_t *fd, int command, void *argp, int argl)
161*7836SJohn.Forte@Sun.COM {
162*7836SJohn.Forte@Sun.COM 	return (*fd->sf_aio->control)(fd->sf_cd, command, argp, argl);
163*7836SJohn.Forte@Sun.COM }
164*7836SJohn.Forte@Sun.COM 
165*7836SJohn.Forte@Sun.COM 
166*7836SJohn.Forte@Sun.COM /* ARGSUSED */
167*7836SJohn.Forte@Sun.COM 
168*7836SJohn.Forte@Sun.COM static int
_nsc_uread(dev_t dev,uio_t * uiop,cred_t * crp,nsc_fd_t * fd)169*7836SJohn.Forte@Sun.COM _nsc_uread(dev_t dev, uio_t *uiop, cred_t *crp, nsc_fd_t *fd)
170*7836SJohn.Forte@Sun.COM {
171*7836SJohn.Forte@Sun.COM 	return (_nsc_rw_uio(fd, uiop, UIO_READ));
172*7836SJohn.Forte@Sun.COM }
173*7836SJohn.Forte@Sun.COM 
174*7836SJohn.Forte@Sun.COM 
175*7836SJohn.Forte@Sun.COM /* ARGSUSED */
176*7836SJohn.Forte@Sun.COM 
177*7836SJohn.Forte@Sun.COM static int
_nsc_uwrite(dev_t dev,uio_t * uiop,cred_t * crp,nsc_fd_t * fd)178*7836SJohn.Forte@Sun.COM _nsc_uwrite(dev_t dev, uio_t *uiop, cred_t *crp, nsc_fd_t *fd)
179*7836SJohn.Forte@Sun.COM {
180*7836SJohn.Forte@Sun.COM 	return (_nsc_rw_uio(fd, uiop, UIO_WRITE));
181*7836SJohn.Forte@Sun.COM }
182*7836SJohn.Forte@Sun.COM 
183*7836SJohn.Forte@Sun.COM 
184*7836SJohn.Forte@Sun.COM static int
_nsc_rw_uio(nsc_fd_t * fd,uio_t * uiop,uio_rw_t rw)185*7836SJohn.Forte@Sun.COM _nsc_rw_uio(nsc_fd_t *fd, uio_t *uiop, uio_rw_t rw)
186*7836SJohn.Forte@Sun.COM {
187*7836SJohn.Forte@Sun.COM 	nsc_size_t buflen, len, limit, chunk;
188*7836SJohn.Forte@Sun.COM 	nsc_off_t pos, off;
189*7836SJohn.Forte@Sun.COM 	nsc_buf_t *buf;
190*7836SJohn.Forte@Sun.COM 	nsc_vec_t *vec;
191*7836SJohn.Forte@Sun.COM 	size_t n;
192*7836SJohn.Forte@Sun.COM 	int rc;
193*7836SJohn.Forte@Sun.COM 
194*7836SJohn.Forte@Sun.COM 	pos = FPOS_TO_FBA(uiop);
195*7836SJohn.Forte@Sun.COM 	off = FPOS_TO_OFF(uiop);
196*7836SJohn.Forte@Sun.COM 	len = FBA_LEN(uiop->uio_resid + off);
197*7836SJohn.Forte@Sun.COM 
198*7836SJohn.Forte@Sun.COM 	DTRACE_PROBE3(_nsc_rw_uio_io,
199*7836SJohn.Forte@Sun.COM 		uint64_t, pos,
200*7836SJohn.Forte@Sun.COM 		uint64_t, off,
201*7836SJohn.Forte@Sun.COM 		uint64_t, len);
202*7836SJohn.Forte@Sun.COM 
203*7836SJohn.Forte@Sun.COM 	/* prevent non-FBA bounded I/O - this is a disk driver! */
204*7836SJohn.Forte@Sun.COM 	if (off != 0 || FBA_OFF(uiop->uio_resid) != 0)
205*7836SJohn.Forte@Sun.COM 		return (EINVAL);
206*7836SJohn.Forte@Sun.COM 
207*7836SJohn.Forte@Sun.COM 	if ((rc = nsc_partsize(fd, &limit)) != 0)
208*7836SJohn.Forte@Sun.COM 		return (rc);
209*7836SJohn.Forte@Sun.COM 
210*7836SJohn.Forte@Sun.COM 	if ((rc = nsc_maxfbas(fd, 0, &chunk)) != 0)
211*7836SJohn.Forte@Sun.COM 		return (rc);
212*7836SJohn.Forte@Sun.COM 
213*7836SJohn.Forte@Sun.COM 	DTRACE_PROBE2(_nsc_rw_uio_limit,
214*7836SJohn.Forte@Sun.COM 		uint64_t, limit,
215*7836SJohn.Forte@Sun.COM 		uint64_t, chunk);
216*7836SJohn.Forte@Sun.COM 
217*7836SJohn.Forte@Sun.COM 	if (limit && pos >= limit) {
218*7836SJohn.Forte@Sun.COM 		if (pos > limit || rw == UIO_WRITE)
219*7836SJohn.Forte@Sun.COM 			return (ENXIO);
220*7836SJohn.Forte@Sun.COM 		return (0);
221*7836SJohn.Forte@Sun.COM 	}
222*7836SJohn.Forte@Sun.COM 
223*7836SJohn.Forte@Sun.COM 	if (limit && pos + len > limit)
224*7836SJohn.Forte@Sun.COM 		len = limit - pos;
225*7836SJohn.Forte@Sun.COM 
226*7836SJohn.Forte@Sun.COM 	while (len > 0) {
227*7836SJohn.Forte@Sun.COM 		buflen = min(len, chunk);
228*7836SJohn.Forte@Sun.COM 
229*7836SJohn.Forte@Sun.COM 		buf = NULL;	/* always use a temporary buffer */
230*7836SJohn.Forte@Sun.COM 		if ((rc = nsc_alloc_buf(fd, pos, buflen,
231*7836SJohn.Forte@Sun.COM 		    (rw == UIO_READ) ? NSC_RDBUF : NSC_WRBUF, &buf)) > 0)
232*7836SJohn.Forte@Sun.COM 			return (rc);
233*7836SJohn.Forte@Sun.COM 
234*7836SJohn.Forte@Sun.COM 		vec = buf->sb_vec;
235*7836SJohn.Forte@Sun.COM 
236*7836SJohn.Forte@Sun.COM 		for (rc = 0;
237*7836SJohn.Forte@Sun.COM 		    !rc && uiop->uio_resid && vec->sv_addr;
238*7836SJohn.Forte@Sun.COM 		    vec++, off = 0) {
239*7836SJohn.Forte@Sun.COM 			n = min(vec->sv_len - off, uiop->uio_resid);
240*7836SJohn.Forte@Sun.COM 			rc = uiomove((char *)vec->sv_addr + off,
241*7836SJohn.Forte@Sun.COM 			    n, rw, uiop);
242*7836SJohn.Forte@Sun.COM 		}
243*7836SJohn.Forte@Sun.COM 
244*7836SJohn.Forte@Sun.COM 		if (rw == UIO_WRITE) {
245*7836SJohn.Forte@Sun.COM 			if (rc) {
246*7836SJohn.Forte@Sun.COM 				(void) nsc_uncommit(buf, pos, buflen, 0);
247*7836SJohn.Forte@Sun.COM 			} else if ((rc = nsc_write(buf, pos, buflen, 0)) < 0) {
248*7836SJohn.Forte@Sun.COM 				rc = 0;
249*7836SJohn.Forte@Sun.COM 			}
250*7836SJohn.Forte@Sun.COM 		}
251*7836SJohn.Forte@Sun.COM 
252*7836SJohn.Forte@Sun.COM 		(void) nsc_free_buf(buf);
253*7836SJohn.Forte@Sun.COM 
254*7836SJohn.Forte@Sun.COM 		len -= buflen;
255*7836SJohn.Forte@Sun.COM 		pos += buflen;
256*7836SJohn.Forte@Sun.COM 	}
257*7836SJohn.Forte@Sun.COM 
258*7836SJohn.Forte@Sun.COM 	return (rc);
259*7836SJohn.Forte@Sun.COM }
260*7836SJohn.Forte@Sun.COM 
261*7836SJohn.Forte@Sun.COM 
262*7836SJohn.Forte@Sun.COM /* ARGSUSED */
263*7836SJohn.Forte@Sun.COM 
264*7836SJohn.Forte@Sun.COM static nsc_dbuf_t *
_nsc_alloc_dhandle(void (* d_cb)(),void (* r_cb)(),void (* w_cb)())265*7836SJohn.Forte@Sun.COM _nsc_alloc_dhandle(void (*d_cb)(), void (*r_cb)(), void (*w_cb)())
266*7836SJohn.Forte@Sun.COM {
267*7836SJohn.Forte@Sun.COM 	nsc_dbuf_t *h;
268*7836SJohn.Forte@Sun.COM 
269*7836SJohn.Forte@Sun.COM 	if ((h = nsc_kmem_zalloc(sizeof (nsc_dbuf_t),
270*7836SJohn.Forte@Sun.COM 			KM_SLEEP, _nsc_local_mem)) == NULL)
271*7836SJohn.Forte@Sun.COM 		return (NULL);
272*7836SJohn.Forte@Sun.COM 
273*7836SJohn.Forte@Sun.COM 	h->db_disc = d_cb;
274*7836SJohn.Forte@Sun.COM 	h->db_flag = NSC_HALLOCATED;
275*7836SJohn.Forte@Sun.COM 
276*7836SJohn.Forte@Sun.COM 	return (h);
277*7836SJohn.Forte@Sun.COM }
278*7836SJohn.Forte@Sun.COM 
279*7836SJohn.Forte@Sun.COM 
280*7836SJohn.Forte@Sun.COM static int
_nsc_free_dhandle(nsc_dbuf_t * h)281*7836SJohn.Forte@Sun.COM _nsc_free_dhandle(nsc_dbuf_t *h)
282*7836SJohn.Forte@Sun.COM {
283*7836SJohn.Forte@Sun.COM 	nsc_kmem_free(h, sizeof (*h));
284*7836SJohn.Forte@Sun.COM 	return (0);
285*7836SJohn.Forte@Sun.COM }
286*7836SJohn.Forte@Sun.COM 
287*7836SJohn.Forte@Sun.COM 
288*7836SJohn.Forte@Sun.COM static int
_nsc_alloc_dbuf(blind_t cd,nsc_off_t pos,nsc_size_t len,int flag,nsc_dbuf_t ** hp)289*7836SJohn.Forte@Sun.COM _nsc_alloc_dbuf(blind_t cd, nsc_off_t pos, nsc_size_t len,
290*7836SJohn.Forte@Sun.COM     int flag, nsc_dbuf_t **hp)
291*7836SJohn.Forte@Sun.COM {
292*7836SJohn.Forte@Sun.COM 	nsc_dbuf_t *h = *hp;
293*7836SJohn.Forte@Sun.COM 	int rc;
294*7836SJohn.Forte@Sun.COM 
295*7836SJohn.Forte@Sun.COM 	if (cd == NSC_ANON_CD) {
296*7836SJohn.Forte@Sun.COM 		flag &= ~(NSC_READ | NSC_WRITE | NSC_RDAHEAD);
297*7836SJohn.Forte@Sun.COM 	} else {
298*7836SJohn.Forte@Sun.COM 		if (h->db_maxfbas == 0) {
299*7836SJohn.Forte@Sun.COM 			rc = nsc_maxfbas(h->db_fd, 0, &h->db_maxfbas);
300*7836SJohn.Forte@Sun.COM 			if (rc != 0)
301*7836SJohn.Forte@Sun.COM 				return (rc);
302*7836SJohn.Forte@Sun.COM 			else if (h->db_maxfbas == 0)
303*7836SJohn.Forte@Sun.COM 				return (EIO);
304*7836SJohn.Forte@Sun.COM 		}
305*7836SJohn.Forte@Sun.COM 
306*7836SJohn.Forte@Sun.COM 		if (len > h->db_maxfbas)
307*7836SJohn.Forte@Sun.COM 			return (ENOSPC);
308*7836SJohn.Forte@Sun.COM 	}
309*7836SJohn.Forte@Sun.COM 
310*7836SJohn.Forte@Sun.COM 	if (flag & NSC_NODATA) {
311*7836SJohn.Forte@Sun.COM 		ASSERT(!(flag & NSC_RDBUF));
312*7836SJohn.Forte@Sun.COM 		h->db_addr = NULL;
313*7836SJohn.Forte@Sun.COM 	} else {
314*7836SJohn.Forte@Sun.COM 		if (h->db_disc)
315*7836SJohn.Forte@Sun.COM 			(*h->db_disc)(h);
316*7836SJohn.Forte@Sun.COM 
317*7836SJohn.Forte@Sun.COM 		if (!(h->db_addr = nsc_kmem_alloc(FBA_SIZE(len), KM_SLEEP, 0)))
318*7836SJohn.Forte@Sun.COM 			return (ENOMEM);
319*7836SJohn.Forte@Sun.COM 	}
320*7836SJohn.Forte@Sun.COM 
321*7836SJohn.Forte@Sun.COM 	h->db_pos = pos;
322*7836SJohn.Forte@Sun.COM 	h->db_len = len;
323*7836SJohn.Forte@Sun.COM 	h->db_error = 0;
324*7836SJohn.Forte@Sun.COM 	h->db_flag |= flag;
325*7836SJohn.Forte@Sun.COM 
326*7836SJohn.Forte@Sun.COM 	if (flag & NSC_NODATA) {
327*7836SJohn.Forte@Sun.COM 		h->db_vec = NULL;
328*7836SJohn.Forte@Sun.COM 	} else {
329*7836SJohn.Forte@Sun.COM 		h->db_vec = &h->db_bvec[0];
330*7836SJohn.Forte@Sun.COM 		h->db_bvec[0].sv_len = FBA_SIZE(len);
331*7836SJohn.Forte@Sun.COM 		h->db_bvec[0].sv_addr = (void *)h->db_addr;
332*7836SJohn.Forte@Sun.COM 		h->db_bvec[0].sv_vme = 0;
333*7836SJohn.Forte@Sun.COM 
334*7836SJohn.Forte@Sun.COM 		h->db_bvec[1].sv_len = 0;
335*7836SJohn.Forte@Sun.COM 		h->db_bvec[1].sv_addr = 0;
336*7836SJohn.Forte@Sun.COM 		h->db_bvec[1].sv_vme = 0;
337*7836SJohn.Forte@Sun.COM 	}
338*7836SJohn.Forte@Sun.COM 
339*7836SJohn.Forte@Sun.COM 	if ((flag & NSC_RDAHEAD) || (cd == NSC_ANON_CD))
340*7836SJohn.Forte@Sun.COM 		return (NSC_DONE);
341*7836SJohn.Forte@Sun.COM 
342*7836SJohn.Forte@Sun.COM 	_nsc_wait_dbuf(h);
343*7836SJohn.Forte@Sun.COM 
344*7836SJohn.Forte@Sun.COM 	if (flag & NSC_RDBUF) {
345*7836SJohn.Forte@Sun.COM 		if ((rc = _nsc_dbuf_io(nsc_uread, h, pos, len, flag)) != 0) {
346*7836SJohn.Forte@Sun.COM 			(void) _nsc_free_dbuf(h);
347*7836SJohn.Forte@Sun.COM 			return (rc);
348*7836SJohn.Forte@Sun.COM 		}
349*7836SJohn.Forte@Sun.COM 	}
350*7836SJohn.Forte@Sun.COM 
351*7836SJohn.Forte@Sun.COM 	return (NSC_DONE);
352*7836SJohn.Forte@Sun.COM }
353*7836SJohn.Forte@Sun.COM 
354*7836SJohn.Forte@Sun.COM 
355*7836SJohn.Forte@Sun.COM static void
_nsc_wait_dbuf(nsc_dbuf_t * h)356*7836SJohn.Forte@Sun.COM _nsc_wait_dbuf(nsc_dbuf_t *h)
357*7836SJohn.Forte@Sun.COM {
358*7836SJohn.Forte@Sun.COM 	nsc_iodev_t *iodev = h->db_fd->sf_iodev;
359*7836SJohn.Forte@Sun.COM 	void (*fn)() = h->db_disc;
360*7836SJohn.Forte@Sun.COM 	nsc_dbuf_t *hp;
361*7836SJohn.Forte@Sun.COM 
362*7836SJohn.Forte@Sun.COM 	mutex_enter(&iodev->si_lock);
363*7836SJohn.Forte@Sun.COM 
364*7836SJohn.Forte@Sun.COM 	h->db_next = iodev->si_active;
365*7836SJohn.Forte@Sun.COM 	iodev->si_active = h;
366*7836SJohn.Forte@Sun.COM 
367*7836SJohn.Forte@Sun.COM 	/* CONSTCOND */
368*7836SJohn.Forte@Sun.COM 
369*7836SJohn.Forte@Sun.COM 	while (1) {
370*7836SJohn.Forte@Sun.COM 		for (hp = h->db_next; hp; hp = hp->db_next)
371*7836SJohn.Forte@Sun.COM 			if (h->db_pos + h->db_len > hp->db_pos &&
372*7836SJohn.Forte@Sun.COM 			    h->db_pos < hp->db_pos + hp->db_len) break;
373*7836SJohn.Forte@Sun.COM 
374*7836SJohn.Forte@Sun.COM 		if (!hp)
375*7836SJohn.Forte@Sun.COM 			break;
376*7836SJohn.Forte@Sun.COM 
377*7836SJohn.Forte@Sun.COM 		if (fn)
378*7836SJohn.Forte@Sun.COM 			(*fn)(h), fn = NULL;
379*7836SJohn.Forte@Sun.COM 
380*7836SJohn.Forte@Sun.COM 		cv_wait(&iodev->si_cv, &iodev->si_lock);
381*7836SJohn.Forte@Sun.COM 	}
382*7836SJohn.Forte@Sun.COM 
383*7836SJohn.Forte@Sun.COM 	mutex_exit(&iodev->si_lock);
384*7836SJohn.Forte@Sun.COM }
385*7836SJohn.Forte@Sun.COM 
386*7836SJohn.Forte@Sun.COM 
387*7836SJohn.Forte@Sun.COM static int
_nsc_free_dbuf(nsc_dbuf_t * h)388*7836SJohn.Forte@Sun.COM _nsc_free_dbuf(nsc_dbuf_t *h)
389*7836SJohn.Forte@Sun.COM {
390*7836SJohn.Forte@Sun.COM 	nsc_dbuf_t **hpp, *hp;
391*7836SJohn.Forte@Sun.COM 	nsc_iodev_t *iodev;
392*7836SJohn.Forte@Sun.COM 	int wake = 0;
393*7836SJohn.Forte@Sun.COM 
394*7836SJohn.Forte@Sun.COM 	if (h->db_fd && !(h->db_flag & NSC_ABUF)) {
395*7836SJohn.Forte@Sun.COM 		iodev = h->db_fd->sf_iodev;
396*7836SJohn.Forte@Sun.COM 
397*7836SJohn.Forte@Sun.COM 		mutex_enter(&iodev->si_lock);
398*7836SJohn.Forte@Sun.COM 
399*7836SJohn.Forte@Sun.COM 		hpp = (nsc_dbuf_t **)&iodev->si_active;
400*7836SJohn.Forte@Sun.COM 
401*7836SJohn.Forte@Sun.COM 		for (; *hpp; hpp = &hp->db_next) {
402*7836SJohn.Forte@Sun.COM 			if ((hp = *hpp) == h) {
403*7836SJohn.Forte@Sun.COM 				*hpp = h->db_next;
404*7836SJohn.Forte@Sun.COM 				break;
405*7836SJohn.Forte@Sun.COM 			}
406*7836SJohn.Forte@Sun.COM 
407*7836SJohn.Forte@Sun.COM 			if (h->db_pos + h->db_len > hp->db_pos &&
408*7836SJohn.Forte@Sun.COM 			    h->db_pos < hp->db_pos + hp->db_len) wake = 1;
409*7836SJohn.Forte@Sun.COM 
410*7836SJohn.Forte@Sun.COM 		}
411*7836SJohn.Forte@Sun.COM 		if (wake)
412*7836SJohn.Forte@Sun.COM 			cv_broadcast(&iodev->si_cv);
413*7836SJohn.Forte@Sun.COM 
414*7836SJohn.Forte@Sun.COM 		mutex_exit(&iodev->si_lock);
415*7836SJohn.Forte@Sun.COM 	}
416*7836SJohn.Forte@Sun.COM 
417*7836SJohn.Forte@Sun.COM 	if (!(h->db_flag & NSC_NODATA) && h->db_addr)
418*7836SJohn.Forte@Sun.COM 		nsc_kmem_free(h->db_addr, FBA_SIZE(h->db_len));
419*7836SJohn.Forte@Sun.COM 
420*7836SJohn.Forte@Sun.COM 	h->db_addr = NULL;
421*7836SJohn.Forte@Sun.COM 	h->db_flag &= NSC_HALLOCATED; /* clear flags, preserve NSC_HALLOCATED */
422*7836SJohn.Forte@Sun.COM 
423*7836SJohn.Forte@Sun.COM 	if ((h->db_flag & NSC_HALLOCATED) == 0)
424*7836SJohn.Forte@Sun.COM 		(void) _nsc_free_dhandle(h);
425*7836SJohn.Forte@Sun.COM 
426*7836SJohn.Forte@Sun.COM 
427*7836SJohn.Forte@Sun.COM 	return (0);
428*7836SJohn.Forte@Sun.COM }
429*7836SJohn.Forte@Sun.COM 
430*7836SJohn.Forte@Sun.COM 
431*7836SJohn.Forte@Sun.COM static int
_nsc_read_dbuf(nsc_dbuf_t * h,nsc_off_t pos,nsc_size_t len,int flag)432*7836SJohn.Forte@Sun.COM _nsc_read_dbuf(nsc_dbuf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
433*7836SJohn.Forte@Sun.COM {
434*7836SJohn.Forte@Sun.COM 	return (_nsc_dbuf_io(nsc_uread, h, pos, len, flag));
435*7836SJohn.Forte@Sun.COM }
436*7836SJohn.Forte@Sun.COM 
437*7836SJohn.Forte@Sun.COM 
438*7836SJohn.Forte@Sun.COM static int
_nsc_write_dbuf(nsc_dbuf_t * h,nsc_off_t pos,nsc_size_t len,int flag)439*7836SJohn.Forte@Sun.COM _nsc_write_dbuf(nsc_dbuf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
440*7836SJohn.Forte@Sun.COM {
441*7836SJohn.Forte@Sun.COM 	return (_nsc_dbuf_io(nsc_uwrite, h, pos, len, flag));
442*7836SJohn.Forte@Sun.COM }
443*7836SJohn.Forte@Sun.COM 
444*7836SJohn.Forte@Sun.COM 
445*7836SJohn.Forte@Sun.COM static int
_nsc_zero_dbuf(nsc_dbuf_t * h,nsc_off_t pos,nsc_size_t len,int flag)446*7836SJohn.Forte@Sun.COM _nsc_zero_dbuf(nsc_dbuf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
447*7836SJohn.Forte@Sun.COM {
448*7836SJohn.Forte@Sun.COM 	return (_nsc_dbuf_io(NULL, h, pos, len, flag));
449*7836SJohn.Forte@Sun.COM }
450*7836SJohn.Forte@Sun.COM 
451*7836SJohn.Forte@Sun.COM 
452*7836SJohn.Forte@Sun.COM static int
_nsc_dbuf_io(int (* fn)(),nsc_dbuf_t * h,nsc_off_t pos,nsc_size_t len,int flag)453*7836SJohn.Forte@Sun.COM _nsc_dbuf_io(int (*fn)(), nsc_dbuf_t *h, nsc_off_t pos,
454*7836SJohn.Forte@Sun.COM     nsc_size_t len, int flag)
455*7836SJohn.Forte@Sun.COM {
456*7836SJohn.Forte@Sun.COM 	nsc_vec_t *vp = NULL;
457*7836SJohn.Forte@Sun.COM 	cred_t *crp = NULL;
458*7836SJohn.Forte@Sun.COM 	iovec_t *iovp;
459*7836SJohn.Forte@Sun.COM 	nsc_size_t thisio;		/* bytes in this io */
460*7836SJohn.Forte@Sun.COM 	nsc_size_t todo;		/* anticipated bytes to go */
461*7836SJohn.Forte@Sun.COM 	nsc_size_t truedo;		/* actual bytes to go */
462*7836SJohn.Forte@Sun.COM 	nsc_off_t xpos;			/* offset of this io */
463*7836SJohn.Forte@Sun.COM 	int destidx;
464*7836SJohn.Forte@Sun.COM 	nsc_size_t firstentryfix;	/* value used for first entry */
465*7836SJohn.Forte@Sun.COM 
466*7836SJohn.Forte@Sun.COM 	int (*iofn)();
467*7836SJohn.Forte@Sun.COM 	int rc = 0;
468*7836SJohn.Forte@Sun.COM 
469*7836SJohn.Forte@Sun.COM 	if (!h->db_vec || (h->db_flag & NSC_ABUF))
470*7836SJohn.Forte@Sun.COM 		return (EIO);
471*7836SJohn.Forte@Sun.COM 
472*7836SJohn.Forte@Sun.COM 	if (pos < h->db_pos || pos + len > h->db_pos + h->db_len)
473*7836SJohn.Forte@Sun.COM 		return (EINVAL);
474*7836SJohn.Forte@Sun.COM 
475*7836SJohn.Forte@Sun.COM 	if (!len)
476*7836SJohn.Forte@Sun.COM 		return (0);
477*7836SJohn.Forte@Sun.COM 	if (fn == nsc_uread && (flag & NSC_RDAHEAD))
478*7836SJohn.Forte@Sun.COM 		return (0);
479*7836SJohn.Forte@Sun.COM 
480*7836SJohn.Forte@Sun.COM 	if (h->db_disc)
481*7836SJohn.Forte@Sun.COM 		(*h->db_disc)(h);
482*7836SJohn.Forte@Sun.COM 
483*7836SJohn.Forte@Sun.COM 	crp = ddi_get_cred();
484*7836SJohn.Forte@Sun.COM 	bzero(&h->db_uio, sizeof (uio_t));
485*7836SJohn.Forte@Sun.COM 	bzero(&h->db_iov[0], (_NSC_DBUF_NVEC * sizeof (iovec_t)));
486*7836SJohn.Forte@Sun.COM 
487*7836SJohn.Forte@Sun.COM 	todo = FBA_SIZE(len);
488*7836SJohn.Forte@Sun.COM 
489*7836SJohn.Forte@Sun.COM 	/*
490*7836SJohn.Forte@Sun.COM 	 * determine where in the vector array we should start.
491*7836SJohn.Forte@Sun.COM 	 */
492*7836SJohn.Forte@Sun.COM 	vp = h->db_vec;
493*7836SJohn.Forte@Sun.COM 	xpos = pos - h->db_pos;
494*7836SJohn.Forte@Sun.COM 	for (; xpos >= FBA_NUM(vp->sv_len); vp++)
495*7836SJohn.Forte@Sun.COM 		xpos -= FBA_NUM(vp->sv_len);
496*7836SJohn.Forte@Sun.COM 
497*7836SJohn.Forte@Sun.COM 	firstentryfix = FBA_SIZE(xpos);
498*7836SJohn.Forte@Sun.COM 
499*7836SJohn.Forte@Sun.COM 	xpos = pos;
500*7836SJohn.Forte@Sun.COM 
501*7836SJohn.Forte@Sun.COM 	/*
502*7836SJohn.Forte@Sun.COM 	 * Loop performing i/o to the underlying driver.
503*7836SJohn.Forte@Sun.COM 	 */
504*7836SJohn.Forte@Sun.COM 	while (todo) {
505*7836SJohn.Forte@Sun.COM 		destidx = 0;
506*7836SJohn.Forte@Sun.COM 		thisio = 0;
507*7836SJohn.Forte@Sun.COM 		iofn = fn;
508*7836SJohn.Forte@Sun.COM 
509*7836SJohn.Forte@Sun.COM 		/*
510*7836SJohn.Forte@Sun.COM 		 * Copy up to _NSC_DBUF_NVEC vector entries from the
511*7836SJohn.Forte@Sun.COM 		 * nsc_vec_t into the iovec_t so that the number of
512*7836SJohn.Forte@Sun.COM 		 * i/o operations is minimised.
513*7836SJohn.Forte@Sun.COM 		 */
514*7836SJohn.Forte@Sun.COM 		while (destidx < _NSC_DBUF_NVEC && todo) {
515*7836SJohn.Forte@Sun.COM 			iovp = &h->db_iov[destidx];
516*7836SJohn.Forte@Sun.COM 
517*7836SJohn.Forte@Sun.COM 			ASSERT(FBA_LEN(vp->sv_len) == FBA_NUM(vp->sv_len));
518*7836SJohn.Forte@Sun.COM 			ASSERT((vp->sv_len - firstentryfix) && vp->sv_addr);
519*7836SJohn.Forte@Sun.COM 
520*7836SJohn.Forte@Sun.COM 			truedo = min(vp->sv_len - firstentryfix, todo);
521*7836SJohn.Forte@Sun.COM 			iovp->iov_base = (caddr_t)vp->sv_addr + firstentryfix;
522*7836SJohn.Forte@Sun.COM 			firstentryfix = 0;
523*7836SJohn.Forte@Sun.COM 			iovp->iov_len = (size_t)truedo;
524*7836SJohn.Forte@Sun.COM 			if (!iofn) {
525*7836SJohn.Forte@Sun.COM 				bzero(iovp->iov_base, iovp->iov_len);
526*7836SJohn.Forte@Sun.COM 			}
527*7836SJohn.Forte@Sun.COM 			thisio += truedo;
528*7836SJohn.Forte@Sun.COM 			todo -= truedo;
529*7836SJohn.Forte@Sun.COM 			destidx++;
530*7836SJohn.Forte@Sun.COM 			vp++;
531*7836SJohn.Forte@Sun.COM 		}
532*7836SJohn.Forte@Sun.COM 
533*7836SJohn.Forte@Sun.COM 		h->db_uio.uio_iovcnt = destidx;
534*7836SJohn.Forte@Sun.COM 		h->db_uio.uio_iov = &h->db_iov[0];
535*7836SJohn.Forte@Sun.COM 		h->db_uio.uio_segflg = UIO_SYSSPACE;
536*7836SJohn.Forte@Sun.COM 		h->db_uio.uio_resid = (size_t)thisio;
537*7836SJohn.Forte@Sun.COM 
538*7836SJohn.Forte@Sun.COM 		SET_FPOS(&h->db_uio, xpos);
539*7836SJohn.Forte@Sun.COM 
540*7836SJohn.Forte@Sun.COM 		if (!iofn) {
541*7836SJohn.Forte@Sun.COM 			iofn = nsc_uwrite;
542*7836SJohn.Forte@Sun.COM 		}
543*7836SJohn.Forte@Sun.COM 
544*7836SJohn.Forte@Sun.COM 		rc = (*iofn)(h->db_fd, &h->db_uio, crp);
545*7836SJohn.Forte@Sun.COM 		if (rc != 0) {
546*7836SJohn.Forte@Sun.COM 			break;
547*7836SJohn.Forte@Sun.COM 		}
548*7836SJohn.Forte@Sun.COM 
549*7836SJohn.Forte@Sun.COM 		ASSERT(FBA_LEN(thisio) == FBA_NUM(thisio));
550*7836SJohn.Forte@Sun.COM 		xpos += FBA_LEN(thisio);
551*7836SJohn.Forte@Sun.COM 	}
552*7836SJohn.Forte@Sun.COM 
553*7836SJohn.Forte@Sun.COM 	return (rc);
554*7836SJohn.Forte@Sun.COM }
555