xref: /titanic_50/usr/src/uts/common/avs/ns/nsctl/nsc_cache.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/ksynch.h>
28 #include <sys/errno.h>
29 #include <sys/uio.h>
30 #include <sys/ddi.h>
31 
32 #define	__NSC_GEN__
33 #include "nsc_dev.h"
34 
35 #ifdef DS_DDICT
36 #include "../contract.h"
37 #endif
38 
39 #include "../nsctl.h"
40 
41 
42 #define	_I(x)	(((long)(&((nsc_io_t *)0)->x))/sizeof (long))
43 
44 
45 nsc_def_t _nsc_cache_def[] = {
46 	"AllocBuf",	(uintptr_t)nsc_ioerr,	_I(alloc_buf),
47 	"FreeBuf",	(uintptr_t)nsc_fatal,	_I(free_buf),
48 	"Read",		(uintptr_t)nsc_fatal,	_I(read),
49 	"Write",	(uintptr_t)nsc_fatal,	_I(write),
50 	"Zero",		(uintptr_t)nsc_fatal,	_I(zero),
51 	"Copy",		(uintptr_t)nsc_ioerr,	_I(copy),
52 	"CopyDirect",	(uintptr_t)nsc_ioerr,	_I(copy_direct),
53 	"Uncommit",	(uintptr_t)nsc_null,	_I(uncommit),
54 	"AllocHandle",	(uintptr_t)nsc_null,	_I(alloc_h),
55 	"FreeHandle",	(uintptr_t)nsc_fatal,	_I(free_h),
56 	"TrackSize",	(uintptr_t)nsc_null,	_I(trksize),
57 	"Discard",	(uintptr_t)nsc_null,	_I(discard),
58 	"Sizes",	(uintptr_t)nsc_null,	_I(sizes),
59 	"GetPinned",	(uintptr_t)nsc_null,	_I(getpin),
60 	"NodeHints",	(uintptr_t)nsc_inval,	_I(nodehints),
61 	0,		0,		0
62 };
63 
64 
65 static int _nsc_alloc_buf_h(blind_t, nsc_off_t, nsc_size_t, int,
66     nsc_buf_t **, nsc_fd_t *);
67 static int _nsc_copy_h(nsc_buf_t *, nsc_buf_t *, nsc_off_t,
68     nsc_off_t, nsc_size_t);
69 
70 extern nsc_io_t *_nsc_reserve_io(char *, int);
71 extern void _nsc_release_io(nsc_io_t *);
72 
73 extern kmutex_t _nsc_io_lock;
74 
75 
76 
77 
78 /* ARGSUSED */
79 
80 void
_nsc_add_cache(nsc_io_t * io)81 _nsc_add_cache(nsc_io_t *io)
82 {
83 }
84 
85 
86 nsc_buf_t *
nsc_alloc_handle(nsc_fd_t * fd,void (* d_cb)(),void (* r_cb)(),void (* w_cb)())87 nsc_alloc_handle(nsc_fd_t *fd, void (*d_cb)(), void (*r_cb)(), void (*w_cb)())
88 {
89 	nsc_buf_t *h = (*fd->sf_aio->alloc_h)(d_cb, r_cb, w_cb, fd->sf_cd);
90 
91 	if (h)
92 		h->sb_fd = fd;
93 
94 	return (h);
95 }
96 
97 
98 int
nsc_free_handle(nsc_buf_t * h)99 nsc_free_handle(nsc_buf_t *h)
100 {
101 	if (h == NULL || (h->sb_flag & NSC_ABUF))
102 		return (EINVAL);
103 
104 	return ((*h->sb_fd->sf_aio->free_h)(h, h->sb_fd->sf_cd));
105 }
106 
107 
108 int
nsc_alloc_abuf(nsc_off_t pos,nsc_size_t len,int flag,nsc_buf_t ** ptr)109 nsc_alloc_abuf(nsc_off_t pos, nsc_size_t len, int flag, nsc_buf_t **ptr)
110 {
111 	nsc_buf_t *h;
112 	nsc_io_t *io;
113 	int rc;
114 
115 	if (*ptr != NULL)
116 		return (EINVAL);
117 
118 	if (flag & NSC_NODATA)
119 		return (EINVAL);
120 
121 	io = _nsc_reserve_io(NULL, NSC_ANON);
122 	if (io == NULL)
123 		return (ENOBUFS);
124 
125 	if ((h = (*io->alloc_h)(NULL, NULL, NULL, NSC_ANON_CD)) == NULL) {
126 		_nsc_release_io(io);
127 		return (ENOBUFS);
128 	}
129 
130 	rc = (*io->alloc_buf)(NSC_ANON_CD, pos, len,
131 	    NSC_NOCACHE|flag, &h, NULL);
132 	if (rc <= 0) {
133 		h->sb_flag &= ~NSC_HALLOCATED;
134 		h->sb_flag |= NSC_ABUF;
135 		h->sb_fd = (nsc_fd_t *)io;	/* note overloaded field */
136 
137 		*ptr = h;
138 
139 		mutex_enter(&_nsc_io_lock);
140 		io->abufcnt++;
141 		mutex_exit(&_nsc_io_lock);
142 	}
143 
144 	_nsc_release_io(io);
145 	return (rc);
146 }
147 
148 
149 int
nsc_alloc_buf(nsc_fd_t * fd,nsc_off_t pos,nsc_size_t len,int flag,nsc_buf_t ** ptr)150 nsc_alloc_buf(nsc_fd_t *fd, nsc_off_t pos, nsc_size_t len,
151     int flag, nsc_buf_t **ptr)
152 {
153 	int (*fn)() = _nsc_alloc_buf_h;
154 
155 	if ((fd->sf_avail & NSC_WRITE) == 0)
156 		if (flag & NSC_WRBUF)
157 			return (EACCES);
158 
159 	if ((flag & (NSC_READ|NSC_WRITE|NSC_NODATA)) ==
160 	    (NSC_READ|NSC_NODATA)) {
161 		/*
162 		 * NSC_NODATA access checks.
163 		 *
164 		 * - NSC_READ|NSC_NODATA is illegal since there would
165 		 *   be no data buffer to immediately read the data into.
166 		 * - NSC_WRITE|NSC_NODATA is valid since the client can
167 		 *   provide the buffer and then call nsc_write() as
168 		 *   necessary.
169 		 * - NSC_NODATA is valid since the client can provide the
170 		 *   buffer and then call nsc_read() or nsc_write() as
171 		 *   necessary.
172 		 */
173 		return (EACCES);
174 	}
175 
176 	if (*ptr) {
177 		fn = fd->sf_aio->alloc_buf;
178 		(*ptr)->sb_fd = fd;
179 	}
180 
181 	return (*fn)(fd->sf_cd, pos, len, flag, ptr, fd);
182 }
183 
184 
185 /* ARGSUSED */
186 
187 static int
_nsc_alloc_buf_h(blind_t cd,nsc_off_t pos,nsc_size_t len,int flag,nsc_buf_t ** ptr,nsc_fd_t * fd)188 _nsc_alloc_buf_h(blind_t cd, nsc_off_t pos, nsc_size_t len,
189     int flag, nsc_buf_t **ptr, nsc_fd_t *fd)
190 {
191 	nsc_buf_t *h;
192 	int rc;
193 
194 	if (!(h = nsc_alloc_handle(fd, NULL, NULL, NULL)))
195 		return (ENOBUFS);
196 
197 	if ((rc = nsc_alloc_buf(fd, pos, len, flag, &h)) <= 0) {
198 		h->sb_flag &= ~NSC_HALLOCATED;
199 		*ptr = h;
200 		return (rc);
201 	}
202 
203 	(void) nsc_free_handle(h);
204 	return (rc);
205 }
206 
207 
208 int
nsc_read(nsc_buf_t * h,nsc_off_t pos,nsc_size_t len,int flag)209 nsc_read(nsc_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
210 {
211 	if ((h->sb_flag & NSC_ABUF) ||
212 	    ((h->sb_flag & NSC_NODATA) && h->sb_vec == NULL))
213 		return (EIO);
214 
215 	return ((*h->sb_fd->sf_aio->read)(h, pos, len, flag));
216 }
217 
218 
219 int
nsc_write(nsc_buf_t * h,nsc_off_t pos,nsc_size_t len,int flag)220 nsc_write(nsc_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
221 {
222 	if ((h->sb_flag & NSC_ABUF) ||
223 	    ((h->sb_flag & NSC_NODATA) && h->sb_vec == NULL))
224 		return (EIO);
225 
226 	return ((*h->sb_fd->sf_aio->write)(h, pos, len, flag));
227 }
228 
229 
230 int
nsc_zero(nsc_buf_t * h,nsc_off_t pos,nsc_size_t len,int flag)231 nsc_zero(nsc_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
232 {
233 	if ((h->sb_flag & NSC_ABUF) ||
234 	    ((h->sb_flag & NSC_NODATA) && h->sb_vec == NULL))
235 		return (EIO);
236 
237 	return ((*h->sb_fd->sf_aio->zero)(h, pos, len, flag));
238 }
239 
240 
241 int
nsc_copy(nsc_buf_t * h1,nsc_buf_t * h2,nsc_off_t pos1,nsc_off_t pos2,nsc_size_t len)242 nsc_copy(nsc_buf_t *h1, nsc_buf_t *h2, nsc_off_t pos1,
243     nsc_off_t pos2, nsc_size_t len)
244 {
245 	nsc_io_t *io1, *io2;
246 	int rc = EIO;
247 
248 	if (((h1->sb_flag & NSC_NODATA) && h1->sb_vec == NULL) ||
249 	    ((h2->sb_flag & NSC_NODATA) && h2->sb_vec == NULL))
250 		return (EIO);
251 
252 	if (h1->sb_fd && h2->sb_fd) {
253 		io1 = (h1->sb_flag & NSC_ABUF) ?
254 		    (nsc_io_t *)h1->sb_fd : h1->sb_fd->sf_aio;
255 
256 		io2 = (h2->sb_flag & NSC_ABUF) ?
257 		    (nsc_io_t *)h2->sb_fd : h2->sb_fd->sf_aio;
258 
259 		if (io1 == io2)
260 			rc = (*io1->copy)(h1, h2, pos1, pos2, len);
261 	}
262 
263 	if (rc != EIO)
264 		return (rc);
265 
266 	return (_nsc_copy_h(h1, h2, pos1, pos2, len));
267 }
268 
269 
270 static int
_nsc_copy_h(nsc_buf_t * h1,nsc_buf_t * h2,nsc_off_t pos1,nsc_off_t pos2,nsc_size_t len)271 _nsc_copy_h(nsc_buf_t *h1, nsc_buf_t *h2, nsc_off_t pos1,
272     nsc_off_t pos2, nsc_size_t len)
273 {
274 	nsc_vec_t *v1, *v2;
275 	uchar_t *a1, *a2;
276 	int sz, l1, l2, lenbytes;	/* byte sizes within an nsc_vec_t */
277 
278 	if (pos1 < h1->sb_pos || pos1 + len > h1->sb_pos + h1->sb_len ||
279 	    pos2 < h2->sb_pos || pos2 + len > h2->sb_pos + h2->sb_len)
280 		return (EINVAL);
281 
282 	if (!len)
283 		return (0);
284 
285 	/* find starting point in "from" vector */
286 
287 	v1 = h1->sb_vec;
288 	pos1 -= h1->sb_pos;
289 
290 	for (; pos1 >= FBA_NUM(v1->sv_len); v1++)
291 		pos1 -= FBA_NUM(v1->sv_len);
292 
293 	a1 = v1->sv_addr + FBA_SIZE(pos1);
294 	l1 = v1->sv_len - FBA_SIZE(pos1);
295 
296 	/* find starting point in "to" vector */
297 
298 	v2 = h2->sb_vec;
299 	pos2 -= h2->sb_pos;
300 
301 	for (; pos2 >= FBA_NUM(v2->sv_len); v2++)
302 		pos2 -= FBA_NUM(v2->sv_len);
303 
304 	a2 = v2->sv_addr + FBA_SIZE(pos2);
305 	l2 = v2->sv_len - FBA_SIZE(pos2);
306 
307 	/* copy required data */
308 
309 	ASSERT(FBA_SIZE(len) < INT_MAX);
310 	lenbytes = (int)FBA_SIZE(len);
311 
312 	while (lenbytes) {
313 		sz = min(l1, l2);
314 		sz = min(sz, lenbytes);
315 
316 		bcopy(a1, a2, sz);
317 
318 		l1 -= sz; l2 -= sz;
319 		a1 += sz; a2 += sz;
320 		lenbytes -= sz;
321 
322 		if (!l1)
323 			a1 = (++v1)->sv_addr, l1 = v1->sv_len;
324 		if (!l2)
325 			a2 = (++v2)->sv_addr, l2 = v2->sv_len;
326 	}
327 
328 	return (0);
329 }
330 
331 
332 int
nsc_copy_direct(nsc_buf_t * h1,nsc_buf_t * h2,nsc_off_t pos1,nsc_off_t pos2,nsc_size_t len)333 nsc_copy_direct(nsc_buf_t *h1, nsc_buf_t *h2, nsc_off_t pos1,
334     nsc_off_t pos2, nsc_size_t len)
335 {
336 	int rc = EIO;
337 
338 	if (!h1 || !h2)
339 		return (EINVAL);
340 
341 	if (((h1->sb_flag & NSC_NODATA) && h1->sb_vec == NULL) ||
342 	    ((h2->sb_flag & NSC_NODATA) && h2->sb_vec == NULL))
343 		return (EIO);
344 
345 	if ((h2->sb_flag & NSC_RDWR) != NSC_WRITE) {
346 		cmn_err(CE_WARN,
347 		    "nsc_copy_direct: h2 (%p) flags (%x) include NSC_READ",
348 		    (void *)h2, h2->sb_flag);
349 	}
350 
351 	if ((h2->sb_flag & NSC_WRTHRU) == 0) {
352 		cmn_err(CE_WARN,
353 		    "nsc_copy_direct: h2 (%p) flags (%x) do not "
354 		    "include NSC_WRTHRU", (void *)h2, h2->sb_flag);
355 		h2->sb_flag |= NSC_WRTHRU;
356 	}
357 
358 	if (h1->sb_fd && h2->sb_fd && h1->sb_fd->sf_aio == h2->sb_fd->sf_aio)
359 		rc = (*h1->sb_fd->sf_aio->copy_direct)(h1, h2, pos1, pos2, len);
360 
361 	if (rc != EIO)
362 		return (rc);
363 
364 	/*
365 	 * The slow way ...
366 	 */
367 
368 	rc = nsc_copy(h1, h2, pos1, pos2, len);
369 	if (rc <= 0)
370 		rc = nsc_write(h2, pos2, len, NSC_WRTHRU);
371 
372 	return (rc);
373 }
374 
375 
376 int
nsc_uncommit(nsc_buf_t * h,nsc_off_t pos,nsc_size_t len,int flag)377 nsc_uncommit(nsc_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
378 {
379 	if (h->sb_flag & NSC_ABUF)
380 		return (EIO);
381 
382 	return ((*h->sb_fd->sf_aio->uncommit)(h, pos, len, flag));
383 }
384 
385 
386 int
nsc_free_buf(nsc_buf_t * h)387 nsc_free_buf(nsc_buf_t *h)
388 {
389 	nsc_io_t *io;
390 	int abuf;
391 	int rc;
392 
393 	if (h == NULL)
394 		return (0);
395 
396 	if ((h->sb_flag & NSC_NODATA) && (h->sb_vec != NULL)) {
397 		h->sb_vec = NULL;
398 	}
399 
400 	abuf = (h->sb_flag & NSC_ABUF);
401 
402 	if (abuf)
403 		io = (nsc_io_t *)h->sb_fd;
404 	else
405 		io = h->sb_fd->sf_aio;
406 
407 	rc = (*io->free_buf)(h);
408 
409 	if (abuf && rc <= 0) {
410 		mutex_enter(&_nsc_io_lock);
411 		io->abufcnt--;
412 		mutex_exit(&_nsc_io_lock);
413 	}
414 
415 	return (rc);
416 }
417 
418 
419 int
nsc_node_hints(uint_t * hints)420 nsc_node_hints(uint_t *hints)
421 {
422 	return (_nsc_call_io(_I(nodehints), (blind_t)hints,
423 	    (blind_t)NSC_GET_NODE_HINT, 0));
424 }
425 
426 int
nsc_node_hints_set(uint_t hints)427 nsc_node_hints_set(uint_t hints)
428 {
429 	return (_nsc_call_io(_I(nodehints), (blind_t)(unsigned long)hints,
430 	    (blind_t)NSC_SET_NODE_HINT, 0));
431 }
432 
433 
434 int
nsc_cache_sizes(int * asize,int * wsize)435 nsc_cache_sizes(int *asize, int *wsize)
436 {
437 	return (_nsc_call_io(_I(sizes), (blind_t)asize, (blind_t)wsize, 0));
438 }
439 
440 
441 int
nsc_set_trksize(nsc_fd_t * fd,nsc_size_t trsize)442 nsc_set_trksize(nsc_fd_t *fd, nsc_size_t trsize)
443 {
444 	return (*fd->sf_aio->trksize)(fd->sf_cd, trsize);
445 }
446 
447 
448 int
nsc_get_pinned(nsc_fd_t * fd)449 nsc_get_pinned(nsc_fd_t *fd)
450 {
451 	return (*fd->sf_aio->getpin)(fd->sf_cd);
452 }
453 
454 
455 int
nsc_discard_pinned(nsc_fd_t * fd,nsc_off_t pos,nsc_size_t len)456 nsc_discard_pinned(nsc_fd_t *fd, nsc_off_t pos, nsc_size_t len)
457 {
458 	return (*fd->sf_aio->discard)(fd->sf_cd, pos, len);
459 }
460 
461 
462 void
nsc_pinned_data(nsc_iodev_t * iodev,nsc_off_t pos,nsc_size_t len)463 nsc_pinned_data(nsc_iodev_t *iodev, nsc_off_t pos, nsc_size_t len)
464 {
465 	nsc_fd_t *fd;
466 
467 	if (!iodev)
468 		return;
469 
470 	mutex_enter(&iodev->si_dev->nsc_lock);
471 	iodev->si_busy++;
472 	mutex_exit(&iodev->si_dev->nsc_lock);
473 
474 	for (fd = iodev->si_open; fd; fd = fd->sf_next)
475 		if (fd->sf_avail & _NSC_ATTACH)
476 			(*fd->sf_pinned)(fd->sf_arg, pos, len);
477 
478 	_nsc_wake_dev(iodev->si_dev, &iodev->si_busy);
479 }
480 
481 
482 void
nsc_unpinned_data(nsc_iodev_t * iodev,nsc_off_t pos,nsc_size_t len)483 nsc_unpinned_data(nsc_iodev_t *iodev, nsc_off_t pos, nsc_size_t len)
484 {
485 	nsc_fd_t *fd;
486 
487 	if (!iodev)
488 		return;
489 
490 	mutex_enter(&iodev->si_dev->nsc_lock);
491 	iodev->si_busy++;
492 	mutex_exit(&iodev->si_dev->nsc_lock);
493 
494 	for (fd = iodev->si_open; fd; fd = fd->sf_next)
495 		if (fd->sf_avail & _NSC_ATTACH)
496 			(*fd->sf_unpinned)(fd->sf_arg, pos, len);
497 
498 	_nsc_wake_dev(iodev->si_dev, &iodev->si_busy);
499 }
500