xref: /titanic_52/usr/src/uts/common/avs/ns/nsctl/nsc_ncallio.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/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 }
758