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/file.h> 30 #include <sys/open.h> 31 #include <sys/cred.h> 32 #include <sys/kmem.h> 33 #include <sys/ddi.h> 34 35 #include <sys/ncall/ncall.h> 36 37 #define __NSC_GEN__ 38 #include "nsc_dev.h" 39 #include "nsc_ncallio.h" 40 #include "../nsctl.h" 41 42 43 extern nsc_mem_t *_nsc_local_mem; 44 45 extern void _nsc_init_ncio(void); 46 extern void _nsc_deinit_ncio(void); 47 48 static nsc_io_t *nsc_ncio_io; 49 static kmutex_t nsc_ncio_lock; 50 static nsc_ncio_dev_t *nsc_ncio_top; 51 52 53 /* 54 * ncall-io io provider - client side. 55 */ 56 57 58 static int 59 nsc_ncio_split(char *node_and_path, char **pathp) 60 { 61 char *cp; 62 int i, snode; 63 64 snode = 0; 65 for (cp = node_and_path; *cp && *cp != ':'; cp++) { 66 i = *cp - '0'; 67 if (i < 0 || i > 9) 68 break; 69 70 snode = (10 * snode) + i; 71 } 72 73 if (*cp != ':') { 74 cmn_err(CE_WARN, 75 "ncio: failed to convert %s to node and path", 76 node_and_path); 77 return (-1); 78 } 79 80 *pathp = cp + 1; 81 return (snode); 82 } 83 84 85 /* 86 * nsc_ncio_open() 87 * 88 * The pathname that is used with the NSC_NCALL io provider should be 89 * of the form "<node>:<pathname>", where <node> is the decimal ncall 90 * nodeid of the server machine and <pathname> is the pathname of the 91 * device on the server node. 92 */ 93 94 /* ARGSUSED */ 95 static int 96 nsc_ncio_open(char *node_and_path, int flag, blind_t *cdp, void *iodev) 97 { 98 nsc_ncio_dev_t *ncp, *new; 99 char *path = NULL; 100 uint64_t phash; 101 int snode; 102 103 snode = nsc_ncio_split(node_and_path, &path); 104 if (snode < 0) 105 return (EINVAL); 106 107 new = nsc_kmem_zalloc(sizeof (*new), KM_SLEEP, _nsc_local_mem); 108 phash = nsc_strhash(path); 109 110 if (new) { 111 (void) strncpy(new->path, path, sizeof (new->path)); 112 new->phash = phash; 113 new->snode = snode; 114 } 115 116 mutex_enter(&nsc_ncio_lock); 117 118 for (ncp = nsc_ncio_top; ncp; ncp = ncp->next) 119 if (ncp->phash == phash && strcmp(path, ncp->path) == 0) 120 break; 121 122 if (ncp == NULL && new != NULL) { 123 ncp = new; 124 new = NULL; 125 ncp->next = nsc_ncio_top; 126 nsc_ncio_top = ncp; 127 } 128 129 if (ncp != NULL) 130 ncp->ref++; 131 132 mutex_exit(&nsc_ncio_lock); 133 134 if (new) 135 nsc_kmem_free(new, sizeof (*new)); 136 137 if (!ncp) 138 return (ENOMEM); 139 140 *cdp = (blind_t)ncp; 141 return (0); 142 } 143 144 145 static int 146 nsc_ncio_close(nsc_ncio_dev_t *ncp) 147 { 148 nsc_ncio_dev_t **ncpp; 149 int found, free; 150 151 if (ncp == NULL) 152 return (EINVAL); 153 154 found = 0; 155 free = 0; 156 157 mutex_enter(&nsc_ncio_lock); 158 159 for (ncpp = &nsc_ncio_top; *ncpp; ncpp = &((*ncpp)->next)) { 160 if (*ncpp == ncp) { 161 found = 1; 162 break; 163 } 164 } 165 166 if (!found) { 167 mutex_exit(&nsc_ncio_lock); 168 return (ENODEV); 169 } 170 171 ncp->ref--; 172 if (ncp->ref == 0) { 173 *ncpp = ncp->next; 174 free = 1; 175 } 176 177 mutex_exit(&nsc_ncio_lock); 178 179 if (free) 180 nsc_kmem_free(ncp, sizeof (*ncp)); 181 182 return (0); 183 } 184 185 186 /* ARGSUSED1 */ 187 static nsc_buf_t * 188 nsc_ncio_alloch(void (*d_cb)(), void (*r_cb)(), void (*w_cb)()) 189 { 190 nsc_ncio_buf_t *h; 191 192 if ((h = nsc_kmem_zalloc(sizeof (*h), KM_SLEEP, 193 _nsc_local_mem)) == NULL) 194 return (NULL); 195 196 h->disc = d_cb; 197 h->bufh.sb_flag = NSC_HALLOCATED; 198 199 return (&h->bufh); 200 } 201 202 203 static int 204 nsc_ncio_freeh(nsc_ncio_buf_t *h) 205 { 206 nsc_kmem_free(h, sizeof (*h)); 207 return (0); 208 } 209 210 211 static int 212 nsc_ncio_rwb(nsc_ncio_buf_t *h, nsc_off_t pos, nsc_size_t len, 213 int flag, const int rwflag) 214 { 215 nsc_ncio_rw_t *rw; 216 ncall_t *ncall; 217 int ncall_flag; 218 int ncall_proc; 219 int ncall_len; 220 int rc, err; 221 222 if (h->bufh.sb_flag & NSC_ABUF) 223 return (EIO); 224 225 if (pos < h->bufh.sb_pos || 226 (pos + len) > (h->bufh.sb_pos + h->bufh.sb_len)) { 227 return (EINVAL); 228 } 229 230 if (!len) 231 return (0); 232 233 if (rwflag == NSC_READ && (flag & NSC_RDAHEAD)) 234 return (0); 235 236 /* CONSTCOND */ 237 if (sizeof (*rw) > NCALL_DATA_SZ) { 238 /* CONSTCOND */ 239 ASSERT(sizeof (*rw) <= NCALL_DATA_SZ); 240 return (ENXIO); 241 } 242 243 if (rwflag == NSC_READ) { 244 ncall_flag = NCALL_RDATA; 245 ncall_proc = NSC_NCIO_READ; 246 ncall_len = sizeof (*rw) - sizeof (rw->rw_data); 247 } else { 248 ncall_flag = 0; 249 ncall_proc = NSC_NCIO_WRITE; 250 ncall_len = sizeof (*rw); 251 } 252 253 rw = &h->rw; 254 255 if (rwflag == 0) { 256 /* zero */ 257 bzero(rw->rw_data, sizeof (rw->rw_data)); 258 } 259 260 if (h->disc) 261 (*h->disc)(h); 262 263 rc = ncall_alloc(rw->rw_snode, 0, 0, &ncall); 264 if (rc != 0) { 265 return (rc); 266 } 267 268 rw->rw_pos = (uint64_t)pos; 269 rw->rw_len = (uint64_t)len; 270 rc = ncall_put_data(ncall, rw, ncall_len); 271 if (rc != 0) { 272 return (rc); 273 } 274 275 rc = ncall_send(ncall, ncall_flag, ncall_proc); 276 if (rc != 0) { 277 return (rc); 278 } 279 280 rc = ncall_read_reply(ncall, 1, &err); 281 if (rc != 0 || err != 0) { 282 return (rc ? rc : err); 283 } 284 285 if (rwflag == NSC_READ) { 286 rc = ncall_get_data(ncall, rw, sizeof (*rw)); 287 if (rc != 0) { 288 return (rc); 289 } 290 } 291 292 ncall_free(ncall); 293 return (0); 294 } 295 296 297 static int 298 nsc_ncio_read(nsc_ncio_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag) 299 { 300 return (nsc_ncio_rwb(h, pos, len, flag, NSC_READ)); 301 } 302 303 304 static int 305 nsc_ncio_write(nsc_ncio_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag) 306 { 307 return (nsc_ncio_rwb(h, pos, len, flag, NSC_WRITE)); 308 } 309 310 311 static int 312 nsc_ncio_zero(nsc_ncio_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag) 313 { 314 return (nsc_ncio_rwb(h, pos, len, flag, 0)); 315 } 316 317 318 static void 319 nsc_wait_ncio(nsc_ncio_buf_t *h) 320 { 321 nsc_iodev_t *iodev = h->bufh.sb_fd->sf_iodev; 322 void (*fn)() = h->disc; 323 nsc_ncio_buf_t *hp; 324 325 mutex_enter(&iodev->si_lock); 326 327 h->next = iodev->si_active; 328 iodev->si_active = h; 329 330 /* CONSTCOND */ 331 332 while (1) { 333 for (hp = h->next; hp; hp = hp->next) { 334 if ((h->bufh.sb_pos + h->bufh.sb_len) > 335 hp->bufh.sb_pos && 336 h->bufh.sb_pos < 337 (hp->bufh.sb_pos + hp->bufh.sb_len)) { 338 /* found overlapping io in progress */ 339 break; 340 } 341 } 342 343 if (!hp) 344 break; 345 346 if (fn) { 347 (*fn)(h); 348 fn = NULL; 349 } 350 351 cv_wait(&iodev->si_cv, &iodev->si_lock); 352 } 353 354 mutex_exit(&iodev->si_lock); 355 } 356 357 358 static int 359 nsc_ncio_freeb(nsc_ncio_buf_t *h) 360 { 361 nsc_ncio_buf_t **hpp, *hp; 362 nsc_iodev_t *iodev; 363 int wake = 0; 364 365 if ((h->bufh.sb_flag & NSC_HACTIVE) && 366 h->bufh.sb_fd && !(h->bufh.sb_flag & NSC_ABUF)) { 367 iodev = h->bufh.sb_fd->sf_iodev; 368 369 mutex_enter(&iodev->si_lock); 370 371 for (hpp = (nsc_ncio_buf_t **)&iodev->si_active; 372 *hpp; hpp = &hp->next) { 373 if ((hp = *hpp) == h) { 374 *hpp = h->next; 375 break; 376 } 377 378 if ((h->bufh.sb_pos + h->bufh.sb_len) > 379 hp->bufh.sb_pos && 380 h->bufh.sb_pos < 381 (hp->bufh.sb_pos + hp->bufh.sb_len)) { 382 wake = 1; 383 } 384 } 385 386 if (wake) 387 cv_broadcast(&iodev->si_cv); 388 389 mutex_exit(&iodev->si_lock); 390 } 391 392 /* clear flags, preserve NSC_HALLOCATED */ 393 h->bufh.sb_flag &= NSC_HALLOCATED; 394 395 if ((h->bufh.sb_flag & NSC_HALLOCATED) == 0) 396 (void) nsc_ncio_freeh(h); 397 398 return (0); 399 } 400 401 402 static int 403 nsc_ncio_allocb(nsc_ncio_dev_t *ncp, nsc_off_t pos, nsc_size_t len, 404 int flag, nsc_ncio_buf_t **hp) 405 { 406 nsc_ncio_buf_t *h = *hp; 407 int rc; 408 409 if (h == NULL) { 410 cmn_err(CE_WARN, "nsc_ncio_allocb: NULL handle!"); 411 return (EIO); 412 } 413 414 if (FBA_SIZE(len) > NSC_NCIO_MAXDATA) { 415 /* too large */ 416 return (ENXIO); 417 } 418 419 if ((blind_t)ncp == NSC_ANON_CD) { 420 flag &= ~(NSC_READ | NSC_WRITE | NSC_RDAHEAD); 421 } 422 423 if (h->disc) 424 (*h->disc)(h); 425 426 h->bufh.sb_pos = pos; 427 h->bufh.sb_len = len; 428 h->bufh.sb_error = 0; 429 h->bufh.sb_flag |= flag | NSC_HACTIVE; 430 h->bufh.sb_vec = &h->vec[0]; 431 432 if (!((blind_t)ncp == NSC_ANON_CD)) { 433 (void) strncpy(h->rw.rw_path, ncp->path, 434 sizeof (h->rw.rw_path)); 435 h->rw.rw_snode = ncp->snode; 436 } 437 438 h->vec[0].sv_len = FBA_SIZE(len); 439 h->vec[0].sv_addr = (uchar_t *)&h->rw.rw_data[0]; 440 h->vec[0].sv_vme = 0; 441 442 h->vec[1].sv_len = 0; 443 h->vec[1].sv_addr = 0; 444 h->vec[1].sv_vme = 0; 445 446 if ((flag & NSC_RDAHEAD) || ((blind_t)ncp == NSC_ANON_CD)) 447 return (NSC_DONE); 448 449 nsc_wait_ncio(h); 450 451 if (flag & NSC_READ) { 452 if ((rc = nsc_ncio_read(h, pos, len, flag)) != 0) { 453 (void) nsc_ncio_freeb(h); 454 return (rc); 455 } 456 } 457 458 return (NSC_DONE); 459 } 460 461 462 static int 463 nsc_ncio_partsize(nsc_ncio_dev_t *ncp, nsc_size_t *rvalp) 464 { 465 *rvalp = (nsc_size_t)ncp->partsize; 466 return (0); 467 } 468 469 470 /* ARGSUSED */ 471 static int 472 nsc_ncio_maxfbas(nsc_ncio_dev_t *ncp, int flag, nsc_size_t *ptr) 473 { 474 if (flag == NSC_CACHEBLK) 475 *ptr = 1; 476 else 477 *ptr = FBA_NUM(NSC_NCIO_MAXDATA); 478 479 return (0); 480 } 481 482 483 static int 484 nsc_ncio_attach(nsc_ncio_dev_t *ncp) 485 { 486 nsc_ncio_size_t *size; 487 ncall_t *ncall; 488 int sizeh, sizel; 489 int rc, err; 490 491 /* CONSTCOND */ 492 if (sizeof (*size) > NCALL_DATA_SZ) { 493 /* CONSTCOND */ 494 ASSERT(sizeof (*size) <= NCALL_DATA_SZ); 495 return (ENXIO); 496 } 497 498 size = kmem_zalloc(sizeof (*size), KM_SLEEP); 499 (void) strncpy(size->path, ncp->path, sizeof (size->path)); 500 501 rc = ncall_alloc(ncp->snode, 0, 0, &ncall); 502 if (rc != 0) { 503 kmem_free(size, sizeof (*size)); 504 return (rc); 505 } 506 507 rc = ncall_put_data(ncall, size, sizeof (*size)); 508 kmem_free(size, sizeof (*size)); 509 size = NULL; 510 if (rc != 0) 511 return (rc); 512 513 rc = ncall_send(ncall, 0, NSC_NCIO_PARTSIZE); 514 if (rc != 0) 515 return (0); 516 517 rc = ncall_read_reply(ncall, 3, &err, &sizeh, &sizel); 518 if (rc != 0 || err != 0) 519 return (rc ? rc : err); 520 521 ncall_free(ncall); 522 523 ncp->partsize = (uint64_t)(((uint64_t)sizeh << 32) | (uint64_t)sizel); 524 return (0); 525 } 526 527 528 static nsc_def_t nsc_ncio_def[] = { 529 { "Open", (uintptr_t)nsc_ncio_open, 0 }, 530 { "Close", (uintptr_t)nsc_ncio_close, 0 }, 531 { "Attach", (uintptr_t)nsc_ncio_attach, 0 }, 532 { "AllocHandle", (uintptr_t)nsc_ncio_alloch, 0 }, 533 { "FreeHandle", (uintptr_t)nsc_ncio_freeh, 0 }, 534 { "AllocBuf", (uintptr_t)nsc_ncio_allocb, 0 }, 535 { "FreeBuf", (uintptr_t)nsc_ncio_freeb, 0 }, 536 { "Read", (uintptr_t)nsc_ncio_read, 0 }, 537 { "Write", (uintptr_t)nsc_ncio_write, 0 }, 538 { "Zero", (uintptr_t)nsc_ncio_zero, 0 }, 539 { "PartSize", (uintptr_t)nsc_ncio_partsize, 0 }, 540 { "MaxFbas", (uintptr_t)nsc_ncio_maxfbas, 0 }, 541 { "Provide", NSC_NCALL, 0 }, 542 { 0, 0, 0 } 543 }; 544 545 546 /* 547 * ncall-io io provider - server side. 548 */ 549 550 /* ARGSUSED1 */ 551 static void 552 nsc_rncio_partsize(ncall_t *ncall, int *ap) 553 { 554 nsc_ncio_size_t *size; 555 nsc_size_t partsize; 556 int sizeh, sizel; 557 nsc_fd_t *fd; 558 int rc; 559 560 size = kmem_alloc(sizeof (*size), KM_SLEEP); 561 rc = ncall_get_data(ncall, size, sizeof (*size)); 562 if (rc != 0) { 563 ncall_reply(ncall, EFAULT, 0, 0); 564 kmem_free(size, sizeof (*size)); 565 return; 566 } 567 568 fd = nsc_open(size->path, NSC_CACHE | NSC_DEVICE | NSC_READ, 569 NULL, NULL, &rc); 570 kmem_free(size, sizeof (*size)); 571 size = NULL; 572 if (fd == NULL) { 573 ncall_reply(ncall, rc, 0, 0); 574 return; 575 } 576 577 rc = nsc_reserve(fd, NSC_PCATCH); 578 if (rc != 0) { 579 (void) nsc_close(fd); 580 ncall_reply(ncall, rc, 0, 0); 581 return; 582 } 583 584 sizeh = sizel = 0; 585 rc = nsc_partsize(fd, &partsize); 586 sizel = (int)(partsize & 0xffffffff); 587 /* CONSTCOND */ 588 if (sizeof (nsc_size_t) > sizeof (int)) { 589 sizeh = (int)((partsize & 0xffffffff00000000) >> 32); 590 } 591 592 nsc_release(fd); 593 (void) nsc_close(fd); 594 595 ncall_reply(ncall, rc, sizeh, sizel); 596 } 597 598 599 static int 600 nsc_rncio_copy(char *data, nsc_buf_t *bufp, const int read) 601 { 602 nsc_vec_t *vec; 603 char *datap; 604 uint64_t tocopy; /* bytes */ 605 int thischunk; /* bytes */ 606 int rc; 607 608 rc = 0; 609 datap = data; 610 vec = bufp->sb_vec; 611 612 tocopy = FBA_SIZE(bufp->sb_len); 613 614 while (tocopy > 0) { 615 if (vec->sv_len == 0 || vec->sv_addr == 0) { 616 rc = ENOSPC; 617 break; 618 } 619 620 thischunk = (int)min((nsc_size_t)vec->sv_len, tocopy); 621 622 if (read) { 623 bcopy(vec->sv_addr, datap, thischunk); 624 } else { 625 bcopy(datap, vec->sv_addr, thischunk); 626 } 627 628 tocopy -= thischunk; 629 if (thischunk == vec->sv_len) 630 vec++; 631 } 632 633 return (rc); 634 } 635 636 637 /* ARGSUSED */ 638 static void 639 nsc_rncio_io(ncall_t *ncall, int *ap, const int read) 640 { 641 nsc_ncio_rw_t *rw; 642 nsc_buf_t *bufp; 643 nsc_fd_t *fd; 644 nsc_size_t len; 645 nsc_off_t pos; 646 int ioflag; 647 int rc; 648 649 rw = kmem_alloc(sizeof (*rw), KM_SLEEP); 650 rc = ncall_get_data(ncall, rw, sizeof (*rw)); 651 if (rc != 0) { 652 ncall_reply(ncall, EFAULT); 653 kmem_free(rw, sizeof (*rw)); 654 return; 655 } 656 657 ioflag = (read ? NSC_READ : NSC_WRITE); 658 pos = (nsc_off_t)rw->rw_pos; 659 len = (nsc_size_t)rw->rw_len; 660 661 fd = nsc_open(rw->rw_path, NSC_CACHE | NSC_DEVICE | NSC_READ | ioflag, 662 NULL, NULL, &rc); 663 if (fd == NULL) { 664 ncall_reply(ncall, rc); 665 kmem_free(rw, sizeof (*rw)); 666 return; 667 } 668 669 rc = nsc_reserve(fd, NSC_PCATCH); 670 if (rc != 0) { 671 ncall_reply(ncall, rc); 672 (void) nsc_close(fd); 673 kmem_free(rw, sizeof (*rw)); 674 return; 675 } 676 677 bufp = NULL; 678 rc = nsc_alloc_buf(fd, pos, len, NSC_NOCACHE | ioflag, &bufp); 679 if (rc > 0) { 680 ncall_reply(ncall, rc); 681 if (bufp != NULL) { 682 (void) nsc_free_buf(bufp); 683 } 684 nsc_release(fd); 685 (void) nsc_close(fd); 686 kmem_free(rw, sizeof (*rw)); 687 return; 688 } 689 690 rc = nsc_rncio_copy(&rw->rw_data[0], bufp, read); 691 if (rc == 0) { 692 if (read) { 693 /* store reply data */ 694 rc = ncall_put_data(ncall, rw, sizeof (*rw)); 695 } else { 696 /* write new data */ 697 rc = nsc_write(bufp, pos, len, 0); 698 } 699 } 700 701 ncall_reply(ncall, rc); 702 703 (void) nsc_free_buf(bufp); 704 nsc_release(fd); 705 (void) nsc_close(fd); 706 kmem_free(rw, sizeof (*rw)); 707 } 708 709 710 static void 711 nsc_rncio_read(ncall_t *ncall, int *ap) 712 { 713 nsc_rncio_io(ncall, ap, TRUE); 714 } 715 716 717 static void 718 nsc_rncio_write(ncall_t *ncall, int *ap) 719 { 720 nsc_rncio_io(ncall, ap, FALSE); 721 } 722 723 724 /* 725 * ncall-io io provider - setup. 726 */ 727 728 void 729 _nsc_init_ncio(void) 730 { 731 mutex_init(&nsc_ncio_lock, NULL, MUTEX_DRIVER, NULL); 732 733 ncall_register_svc(NSC_NCIO_PARTSIZE, nsc_rncio_partsize); 734 ncall_register_svc(NSC_NCIO_WRITE, nsc_rncio_write); 735 ncall_register_svc(NSC_NCIO_READ, nsc_rncio_read); 736 737 nsc_ncio_io = nsc_register_io("ncall-io", 738 NSC_NCALL_ID | NSC_REFCNT, nsc_ncio_def); 739 740 if (!nsc_ncio_io) 741 cmn_err(CE_WARN, "_nsc_ncio_init: register io failed - ncall"); 742 } 743 744 745 void 746 _nsc_deinit_ncio(void) 747 { 748 if (nsc_ncio_io) 749 (void) nsc_unregister_io(nsc_ncio_io, 0); 750 751 ncall_unregister_svc(NSC_NCIO_PARTSIZE); 752 ncall_unregister_svc(NSC_NCIO_WRITE); 753 ncall_unregister_svc(NSC_NCIO_READ); 754 755 nsc_ncio_io = NULL; 756 mutex_destroy(&nsc_ncio_lock); 757 }