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 { NULL, (uintptr_t)NULL, 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 81 _nsc_add_cache(nsc_io_t *io) 82 { 83 } 84 85 86 nsc_buf_t * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 449 nsc_get_pinned(nsc_fd_t *fd) 450 { 451 return (*fd->sf_aio->getpin)(fd->sf_cd); 452 } 453 454 455 int 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 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 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 }