xref: /titanic_41/usr/src/uts/common/avs/ns/rdc/rdc_io.c (revision 3270659f55e0928d6edec3d26217cc29398a8149)
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 2009 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/cmn_err.h>
29 #include <sys/kmem.h>
30 #include <sys/conf.h>
31 #include <sys/errno.h>
32 
33 #ifdef _SunOS_5_6
34 /*
35  * on 2.6 both dki_lock.h and rpc/types.h define bool_t so we
36  * define enum_t here as it is all we need from rpc/types.h
37  * anyway and make it look like we included it. Yuck.
38  */
39 #define	_RPC_TYPES_H
40 typedef int enum_t;
41 #else
42 #ifndef DS_DDICT
43 #include <rpc/types.h>
44 #endif
45 #endif /* _SunOS_5_6 */
46 
47 #include <sys/ddi.h>
48 
49 #include <sys/nsc_thread.h>
50 #include <sys/nsctl/nsctl.h>
51 
52 #include <sys/sdt.h>		/* dtrace is S10 or later */
53 
54 #include "rdc_io.h"
55 #include "rdc_bitmap.h"
56 #include "rdc_update.h"
57 #include "rdc_ioctl.h"
58 #include "rdcsrv.h"
59 #include "rdc_diskq.h"
60 
61 #include <sys/unistat/spcs_s.h>
62 #include <sys/unistat/spcs_s_k.h>
63 #include <sys/unistat/spcs_errors.h>
64 
65 volatile int net_exit;
66 nsc_size_t MAX_RDC_FBAS;
67 
68 #ifdef DEBUG
69 int RDC_MAX_SYNC_THREADS = 8;
70 int rdc_maxthreads_last = 8;
71 #endif
72 
73 kmutex_t rdc_ping_lock;		/* Ping lock */
74 static kmutex_t net_blk_lock;
75 
76 /*
77  * rdc_conf_lock is used as a global device configuration lock.
78  * It is also used by enable/resume and disable/suspend code to ensure that
79  * the transition of an rdc set between configured and unconfigured is
80  * atomic.
81  *
82  * krdc->group->lock is used to protect state changes of a configured rdc
83  * set (e.g. changes to urdc->flags), such as enabled to disabled and vice
84  * versa.
85  *
86  * rdc_many_lock is also used to protect changes in group membership. A group
87  * linked list cannot change while this lock is held. The many list and the
88  * multi-hop list are both protected by rdc_many_lock.
89  */
90 kmutex_t rdc_conf_lock;
91 kmutex_t rdc_many_lock;			/* Many/multi-list lock */
92 
93 static kmutex_t rdc_net_hnd_id_lock;	/* Network handle id lock */
94 int rdc_debug = 0;
95 int rdc_debug_sleep = 0;
96 
97 static int rdc_net_hnd_id = 1;
98 
99 extern kmutex_t rdc_clnt_lock;
100 
101 static void rdc_ditemsfree(rdc_net_dataset_t *);
102 void rdc_clnt_destroy(void);
103 
104 rdc_k_info_t *rdc_k_info;
105 rdc_u_info_t *rdc_u_info;
106 
107 unsigned long rdc_async_timeout;
108 
109 nsc_size_t rdc_maxthres_queue = RDC_MAXTHRES_QUEUE;
110 int rdc_max_qitems = RDC_MAX_QITEMS;
111 int rdc_asyncthr = RDC_ASYNCTHR;
112 static nsc_svc_t *rdc_volume_update;
113 static int rdc_prealloc_handle = 1;
114 
115 extern int _rdc_rsrv_diskq(rdc_group_t *group);
116 extern void _rdc_rlse_diskq(rdc_group_t *group);
117 
118 /*
119  * Forward declare all statics that are used before defined
120  * to enforce parameter checking
121  *
122  * Some (if not all) of these could be removed if the code were reordered
123  */
124 
125 static void rdc_volume_update_svc(intptr_t);
126 static void halt_sync(rdc_k_info_t *krdc);
127 void rdc_kstat_create(int index);
128 void rdc_kstat_delete(int index);
129 static int rdc_checkforbitmap(int, nsc_off_t);
130 static int rdc_installbitmap(int, void *, int, nsc_off_t, int, int *, int);
131 static rdc_group_t *rdc_newgroup();
132 
133 int rdc_enable_diskq(rdc_k_info_t *krdc);
134 void rdc_close_diskq(rdc_group_t *group);
135 int rdc_suspend_diskq(rdc_k_info_t *krdc);
136 int rdc_resume_diskq(rdc_k_info_t *krdc);
137 void rdc_init_diskq_header(rdc_group_t *grp, dqheader *header);
138 void rdc_fail_diskq(rdc_k_info_t *krdc, int wait, int dolog);
139 void rdc_unfail_diskq(rdc_k_info_t *krdc);
140 void rdc_unintercept_diskq(rdc_group_t *grp);
141 int rdc_stamp_diskq(rdc_k_info_t *krdc, int rsrvd, int flags);
142 void rdc_qfiller_thr(rdc_k_info_t *krdc);
143 
144 nstset_t *_rdc_ioset;
145 nstset_t *_rdc_flset;
146 
147 /*
148  * RDC threadset tunables
149  */
150 int rdc_threads = 64;		/* default number of threads */
151 int rdc_threads_inc = 8;	/* increment for changing the size of the set */
152 
153 /*
154  * Private threadset manipulation variables
155  */
156 static int rdc_threads_hysteresis = 2;
157 				/* hysteresis for threadset resizing */
158 static int rdc_sets_active;	/* number of sets currently enabled */
159 
160 #ifdef DEBUG
161 kmutex_t rdc_cntlock;
162 #endif
163 
164 /*
165  * rdc_thread_deconfigure - rdc is being deconfigured, stop any
166  * thread activity.
167  *
168  * Inherently single-threaded by the Solaris module unloading code.
169  */
170 static void
rdc_thread_deconfigure(void)171 rdc_thread_deconfigure(void)
172 {
173 	nst_destroy(_rdc_ioset);
174 	_rdc_ioset = NULL;
175 
176 	nst_destroy(_rdc_flset);
177 	_rdc_flset = NULL;
178 
179 	nst_destroy(sync_info.rdc_syncset);
180 	sync_info.rdc_syncset = NULL;
181 }
182 
183 /*
184  * rdc_thread_configure - rdc is being configured, initialize the
185  * threads we need for flushing aync volumes.
186  *
187  * Must be called with rdc_conf_lock held.
188  */
189 static int
rdc_thread_configure(void)190 rdc_thread_configure(void)
191 {
192 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
193 
194 	if ((_rdc_ioset = nst_init("rdc_thr", rdc_threads)) == NULL)
195 		return (EINVAL);
196 
197 	if ((_rdc_flset = nst_init("rdc_flushthr", 2)) == NULL)
198 		return (EINVAL);
199 
200 	if ((sync_info.rdc_syncset =
201 	    nst_init("rdc_syncthr", RDC_MAX_SYNC_THREADS)) == NULL)
202 		return (EINVAL);
203 
204 	return (0);
205 }
206 
207 
208 /*
209  * rdc_thread_tune - called to tune the size of the rdc threadset.
210  *
211  * Called from the config code when an rdc_set has been enabled or disabled.
212  * 'sets' is the increment to the number of active rdc_sets.
213  *
214  * Must be called with rdc_conf_lock held.
215  */
216 static void
rdc_thread_tune(int sets)217 rdc_thread_tune(int sets)
218 {
219 	int incr = (sets > 0) ? 1 : -1;
220 	int change = 0;
221 	int nthreads;
222 
223 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
224 
225 	if (sets < 0)
226 		sets = -sets;
227 
228 	while (sets--) {
229 		nthreads = nst_nthread(_rdc_ioset);
230 		rdc_sets_active += incr;
231 
232 		if (rdc_sets_active >= nthreads)
233 			change += nst_add_thread(_rdc_ioset, rdc_threads_inc);
234 		else if ((rdc_sets_active <
235 		    (nthreads - (rdc_threads_inc + rdc_threads_hysteresis))) &&
236 		    ((nthreads - rdc_threads_inc) >= rdc_threads))
237 			change -= nst_del_thread(_rdc_ioset, rdc_threads_inc);
238 	}
239 
240 #ifdef DEBUG
241 	if (change) {
242 		cmn_err(CE_NOTE, "!rdc_thread_tune: "
243 		    "nsets %d, nthreads %d, nthreads change %d",
244 		    rdc_sets_active, nst_nthread(_rdc_ioset), change);
245 	}
246 #endif
247 }
248 
249 
250 /*
251  * _rdc_unload() - cache is being unloaded,
252  * deallocate any dual copy structures allocated during cache
253  * loading.
254  */
255 void
_rdc_unload(void)256 _rdc_unload(void)
257 {
258 	int i;
259 	rdc_k_info_t *krdc;
260 
261 	if (rdc_volume_update) {
262 		(void) nsc_unregister_svc(rdc_volume_update);
263 		rdc_volume_update = NULL;
264 	}
265 
266 	rdc_thread_deconfigure();
267 
268 	if (rdc_k_info != NULL) {
269 		for (i = 0; i < rdc_max_sets; i++) {
270 			krdc = &rdc_k_info[i];
271 			mutex_destroy(&krdc->dc_sleep);
272 			mutex_destroy(&krdc->bmapmutex);
273 			mutex_destroy(&krdc->kstat_mutex);
274 			mutex_destroy(&krdc->bmp_kstat_mutex);
275 			mutex_destroy(&krdc->syncbitmutex);
276 			cv_destroy(&krdc->busycv);
277 			cv_destroy(&krdc->closingcv);
278 			cv_destroy(&krdc->haltcv);
279 			cv_destroy(&krdc->synccv);
280 		}
281 	}
282 
283 	mutex_destroy(&sync_info.lock);
284 	mutex_destroy(&rdc_ping_lock);
285 	mutex_destroy(&net_blk_lock);
286 	mutex_destroy(&rdc_conf_lock);
287 	mutex_destroy(&rdc_many_lock);
288 	mutex_destroy(&rdc_net_hnd_id_lock);
289 	mutex_destroy(&rdc_clnt_lock);
290 #ifdef DEBUG
291 	mutex_destroy(&rdc_cntlock);
292 #endif
293 	net_exit = ATM_EXIT;
294 
295 	if (rdc_k_info != NULL)
296 		kmem_free(rdc_k_info, sizeof (*rdc_k_info) * rdc_max_sets);
297 	if (rdc_u_info != NULL)
298 		kmem_free(rdc_u_info, sizeof (*rdc_u_info) * rdc_max_sets);
299 	rdc_k_info = NULL;
300 	rdc_u_info = NULL;
301 	rdc_max_sets = 0;
302 }
303 
304 
305 /*
306  * _rdc_load() - rdc is being loaded, Allocate anything
307  * that will be needed while the cache is loaded but doesn't really
308  * depend on configuration parameters.
309  *
310  */
311 int
_rdc_load(void)312 _rdc_load(void)
313 {
314 	int i;
315 	rdc_k_info_t *krdc;
316 
317 	mutex_init(&rdc_ping_lock, NULL, MUTEX_DRIVER, NULL);
318 	mutex_init(&net_blk_lock, NULL, MUTEX_DRIVER, NULL);
319 	mutex_init(&rdc_conf_lock, NULL, MUTEX_DRIVER, NULL);
320 	mutex_init(&rdc_many_lock, NULL, MUTEX_DRIVER, NULL);
321 	mutex_init(&rdc_net_hnd_id_lock, NULL, MUTEX_DRIVER, NULL);
322 	mutex_init(&rdc_clnt_lock, NULL, MUTEX_DRIVER, NULL);
323 	mutex_init(&sync_info.lock, NULL, MUTEX_DRIVER, NULL);
324 
325 #ifdef DEBUG
326 	mutex_init(&rdc_cntlock, NULL, MUTEX_DRIVER, NULL);
327 #endif
328 
329 	if ((i = nsc_max_devices()) < rdc_max_sets)
330 		rdc_max_sets = i;
331 	/* following case for partial installs that may fail */
332 	if (!rdc_max_sets)
333 		rdc_max_sets = 1024;
334 
335 	rdc_k_info = kmem_zalloc(sizeof (*rdc_k_info) * rdc_max_sets, KM_SLEEP);
336 	if (!rdc_k_info)
337 		return (ENOMEM);
338 
339 	rdc_u_info = kmem_zalloc(sizeof (*rdc_u_info) * rdc_max_sets, KM_SLEEP);
340 	if (!rdc_u_info) {
341 		kmem_free(rdc_k_info, sizeof (*rdc_k_info) * rdc_max_sets);
342 		return (ENOMEM);
343 	}
344 
345 	net_exit = ATM_NONE;
346 	for (i = 0; i < rdc_max_sets; i++) {
347 		krdc = &rdc_k_info[i];
348 		bzero(krdc, sizeof (*krdc));
349 		krdc->index = i;
350 		mutex_init(&krdc->dc_sleep, NULL, MUTEX_DRIVER, NULL);
351 		mutex_init(&krdc->bmapmutex, NULL, MUTEX_DRIVER, NULL);
352 		mutex_init(&krdc->kstat_mutex, NULL, MUTEX_DRIVER, NULL);
353 		mutex_init(&krdc->bmp_kstat_mutex, NULL, MUTEX_DRIVER, NULL);
354 		mutex_init(&krdc->syncbitmutex, NULL, MUTEX_DRIVER, NULL);
355 		cv_init(&krdc->busycv, NULL, CV_DRIVER, NULL);
356 		cv_init(&krdc->closingcv, NULL, CV_DRIVER, NULL);
357 		cv_init(&krdc->haltcv, NULL, CV_DRIVER, NULL);
358 		cv_init(&krdc->synccv, NULL, CV_DRIVER, NULL);
359 	}
360 
361 	rdc_volume_update = nsc_register_svc("RDCVolumeUpdated",
362 	    rdc_volume_update_svc);
363 
364 	return (0);
365 }
366 
367 static void
rdc_u_init(rdc_u_info_t * urdc)368 rdc_u_init(rdc_u_info_t *urdc)
369 {
370 	const int index = (int)(urdc - &rdc_u_info[0]);
371 
372 	if (urdc->secondary.addr.maxlen)
373 		free_rdc_netbuf(&urdc->secondary.addr);
374 	if (urdc->primary.addr.maxlen)
375 		free_rdc_netbuf(&urdc->primary.addr);
376 
377 	bzero(urdc, sizeof (rdc_u_info_t));
378 
379 	urdc->index = index;
380 	urdc->maxqfbas = rdc_maxthres_queue;
381 	urdc->maxqitems = rdc_max_qitems;
382 	urdc->asyncthr = rdc_asyncthr;
383 }
384 
385 /*
386  * _rdc_configure() - cache is being configured.
387  *
388  * Initialize dual copy structures
389  */
390 int
_rdc_configure(void)391 _rdc_configure(void)
392 {
393 	int index;
394 	rdc_k_info_t *krdc;
395 
396 	for (index = 0; index < rdc_max_sets; index++) {
397 		krdc = &rdc_k_info[index];
398 
399 		krdc->remote_index = -1;
400 		krdc->dcio_bitmap = NULL;
401 		krdc->bitmap_ref = NULL;
402 		krdc->bitmap_size = 0;
403 		krdc->bitmap_write = 0;
404 		krdc->disk_status = 0;
405 		krdc->many_next = krdc;
406 
407 		rdc_u_init(&rdc_u_info[index]);
408 	}
409 
410 	rdc_async_timeout = 120 * HZ;   /* Seconds * HZ */
411 	MAX_RDC_FBAS = FBA_LEN(RDC_MAXDATA);
412 	if (net_exit != ATM_INIT) {
413 		net_exit = ATM_INIT;
414 		return (0);
415 	}
416 	return (0);
417 }
418 
419 /*
420  * _rdc_deconfigure - rdc is being deconfigured, shut down any
421  * dual copy operations and return to an unconfigured state.
422  */
423 void
_rdc_deconfigure(void)424 _rdc_deconfigure(void)
425 {
426 	rdc_k_info_t *krdc;
427 	rdc_u_info_t *urdc;
428 	int index;
429 
430 	for (index = 0; index < rdc_max_sets; index++) {
431 		krdc = &rdc_k_info[index];
432 		urdc = &rdc_u_info[index];
433 
434 		krdc->remote_index = -1;
435 		krdc->dcio_bitmap = NULL;
436 		krdc->bitmap_ref = NULL;
437 		krdc->bitmap_size = 0;
438 		krdc->bitmap_write = 0;
439 		krdc->disk_status = 0;
440 		krdc->many_next = krdc;
441 
442 		if (urdc->primary.addr.maxlen)
443 			free_rdc_netbuf(&(urdc->primary.addr));
444 
445 		if (urdc->secondary.addr.maxlen)
446 			free_rdc_netbuf(&(urdc->secondary.addr));
447 
448 		bzero(urdc, sizeof (rdc_u_info_t));
449 		urdc->index = index;
450 	}
451 	net_exit = ATM_EXIT;
452 	rdc_clnt_destroy();
453 
454 }
455 
456 
457 /*
458  * Lock primitives, containing checks that lock ordering isn't broken
459  */
460 /*ARGSUSED*/
461 void
rdc_many_enter(rdc_k_info_t * krdc)462 rdc_many_enter(rdc_k_info_t *krdc)
463 {
464 	ASSERT(!MUTEX_HELD(&krdc->bmapmutex));
465 
466 	mutex_enter(&rdc_many_lock);
467 }
468 
469 /* ARGSUSED */
470 void
rdc_many_exit(rdc_k_info_t * krdc)471 rdc_many_exit(rdc_k_info_t *krdc)
472 {
473 	mutex_exit(&rdc_many_lock);
474 }
475 
476 void
rdc_group_enter(rdc_k_info_t * krdc)477 rdc_group_enter(rdc_k_info_t *krdc)
478 {
479 	ASSERT(!MUTEX_HELD(&rdc_many_lock));
480 	ASSERT(!MUTEX_HELD(&rdc_conf_lock));
481 	ASSERT(!MUTEX_HELD(&krdc->bmapmutex));
482 
483 	mutex_enter(&krdc->group->lock);
484 }
485 
486 void
rdc_group_exit(rdc_k_info_t * krdc)487 rdc_group_exit(rdc_k_info_t *krdc)
488 {
489 	mutex_exit(&krdc->group->lock);
490 }
491 
492 /*
493  * Suspend and disable operations use this function to wait until it is safe
494  * to do continue, without trashing data structures used by other ioctls.
495  */
496 static void
wait_busy(rdc_k_info_t * krdc)497 wait_busy(rdc_k_info_t *krdc)
498 {
499 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
500 
501 	while (krdc->busy_count > 0)
502 		cv_wait(&krdc->busycv, &rdc_conf_lock);
503 }
504 
505 
506 /*
507  * Other ioctls use this function to hold off disable and suspend.
508  */
509 void
set_busy(rdc_k_info_t * krdc)510 set_busy(rdc_k_info_t *krdc)
511 {
512 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
513 
514 	wait_busy(krdc);
515 
516 	krdc->busy_count++;
517 }
518 
519 
520 /*
521  * Other ioctls use this function to allow disable and suspend to continue.
522  */
523 void
wakeup_busy(rdc_k_info_t * krdc)524 wakeup_busy(rdc_k_info_t *krdc)
525 {
526 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
527 
528 	if (krdc->busy_count <= 0)
529 		return;
530 
531 	krdc->busy_count--;
532 	cv_broadcast(&krdc->busycv);
533 }
534 
535 
536 /*
537  * Remove the rdc set from its group, and destroy the group if no longer in
538  * use.
539  */
540 static void
remove_from_group(rdc_k_info_t * krdc)541 remove_from_group(rdc_k_info_t *krdc)
542 {
543 	rdc_k_info_t *p;
544 	rdc_group_t *group;
545 
546 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
547 
548 	rdc_many_enter(krdc);
549 	group = krdc->group;
550 
551 	group->count--;
552 
553 	/*
554 	 * lock queue while looking at thrnum
555 	 */
556 	mutex_enter(&group->ra_queue.net_qlock);
557 	if ((group->rdc_thrnum == 0) && (group->count == 0)) {
558 
559 		/*
560 		 * Assure the we've stopped and the flusher thread has not
561 		 * fallen back to sleep
562 		 */
563 		if (krdc->group->ra_queue.qfill_sleeping != RDC_QFILL_DEAD) {
564 			group->ra_queue.qfflags |= RDC_QFILLSTOP;
565 			while (krdc->group->ra_queue.qfflags & RDC_QFILLSTOP) {
566 				if (krdc->group->ra_queue.qfill_sleeping ==
567 				    RDC_QFILL_ASLEEP)
568 					cv_broadcast(&group->ra_queue.qfcv);
569 				mutex_exit(&group->ra_queue.net_qlock);
570 				delay(2);
571 				mutex_enter(&group->ra_queue.net_qlock);
572 			}
573 		}
574 		mutex_exit(&group->ra_queue.net_qlock);
575 
576 		mutex_enter(&group->diskqmutex);
577 		rdc_close_diskq(group);
578 		mutex_exit(&group->diskqmutex);
579 		rdc_delgroup(group);
580 		rdc_many_exit(krdc);
581 		krdc->group = NULL;
582 		return;
583 	}
584 	mutex_exit(&group->ra_queue.net_qlock);
585 	/*
586 	 * Always clear the group field.
587 	 * no, you need it set in rdc_flush_memq().
588 	 * to call rdc_group_log()
589 	 * krdc->group = NULL;
590 	 */
591 
592 	/* Take this rdc structure off the group list */
593 
594 	for (p = krdc->group_next; p->group_next != krdc; p = p->group_next)
595 	;
596 	p->group_next = krdc->group_next;
597 
598 	rdc_many_exit(krdc);
599 }
600 
601 
602 /*
603  * Add the rdc set to its group, setting up a new group if it's the first one.
604  */
605 static int
add_to_group(rdc_k_info_t * krdc,int options,int cmd)606 add_to_group(rdc_k_info_t *krdc, int options, int cmd)
607 {
608 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
609 	rdc_u_info_t *utmp;
610 	rdc_k_info_t *ktmp;
611 	int index;
612 	rdc_group_t *group;
613 	int rc = 0;
614 	nsthread_t *trc;
615 
616 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
617 
618 	/*
619 	 * Look for matching group name, primary host name and secondary
620 	 * host name.
621 	 */
622 
623 	rdc_many_enter(krdc);
624 	for (index = 0; index < rdc_max_sets; index++) {
625 		utmp = &rdc_u_info[index];
626 		ktmp = &rdc_k_info[index];
627 
628 		if (urdc->group_name[0] == 0)
629 			break;
630 
631 		if (!IS_CONFIGURED(ktmp))
632 			continue;
633 
634 		if (strncmp(utmp->group_name, urdc->group_name,
635 		    NSC_MAXPATH) != 0)
636 			continue;
637 		if (strncmp(utmp->primary.intf, urdc->primary.intf,
638 		    MAX_RDC_HOST_SIZE) != 0) {
639 			/* Same group name, different primary interface */
640 			rdc_many_exit(krdc);
641 			return (-1);
642 		}
643 		if (strncmp(utmp->secondary.intf, urdc->secondary.intf,
644 		    MAX_RDC_HOST_SIZE) != 0) {
645 			/* Same group name, different secondary interface */
646 			rdc_many_exit(krdc);
647 			return (-1);
648 		}
649 
650 		/* Group already exists, so add this set to the group */
651 
652 		if (((options & RDC_OPT_ASYNC) == 0) &&
653 		    ((ktmp->type_flag & RDC_ASYNCMODE) != 0)) {
654 			/* Must be same mode as existing group members */
655 			rdc_many_exit(krdc);
656 			return (-1);
657 		}
658 		if (((options & RDC_OPT_ASYNC) != 0) &&
659 		    ((ktmp->type_flag & RDC_ASYNCMODE) == 0)) {
660 			/* Must be same mode as existing group members */
661 			rdc_many_exit(krdc);
662 			return (-1);
663 		}
664 
665 		/* cannont reconfigure existing group into new queue this way */
666 		if ((cmd != RDC_CMD_RESUME) &&
667 		    !RDC_IS_DISKQ(ktmp->group) && urdc->disk_queue[0] != '\0') {
668 			rdc_many_exit(krdc);
669 			return (RDC_EQNOADD);
670 		}
671 
672 		ktmp->group->count++;
673 		krdc->group = ktmp->group;
674 		krdc->group_next = ktmp->group_next;
675 		ktmp->group_next = krdc;
676 
677 		urdc->autosync = utmp->autosync;	/* Same as rest */
678 
679 		(void) strncpy(urdc->disk_queue, utmp->disk_queue, NSC_MAXPATH);
680 
681 		rdc_many_exit(krdc);
682 		return (0);
683 	}
684 
685 	/* This must be a new group */
686 	group = rdc_newgroup();
687 	krdc->group = group;
688 	krdc->group_next = krdc;
689 	urdc->autosync = -1;	/* Unknown */
690 
691 	/*
692 	 * Tune the thread set by one for each thread created
693 	 */
694 	rdc_thread_tune(1);
695 
696 	trc = nst_create(_rdc_ioset, rdc_qfiller_thr, (void *)krdc, NST_SLEEP);
697 	if (trc == NULL) {
698 		rc = -1;
699 		cmn_err(CE_NOTE, "!unable to create queue filler daemon");
700 		goto fail;
701 	}
702 
703 	if (urdc->disk_queue[0] == '\0') {
704 		krdc->group->flags |= RDC_MEMQUE;
705 	} else {
706 		krdc->group->flags |= RDC_DISKQUE;
707 
708 		/* XXX check here for resume or enable and act accordingly */
709 
710 		if (cmd == RDC_CMD_RESUME) {
711 			rc = rdc_resume_diskq(krdc);
712 
713 		} else if (cmd == RDC_CMD_ENABLE) {
714 			rc = rdc_enable_diskq(krdc);
715 			if ((rc == RDC_EQNOADD) && (cmd != RDC_CMD_ENABLE)) {
716 				cmn_err(CE_WARN, "!disk queue %s enable failed,"
717 				    " enabling memory queue",
718 				    urdc->disk_queue);
719 				krdc->group->flags &= ~RDC_DISKQUE;
720 				krdc->group->flags |= RDC_MEMQUE;
721 				bzero(urdc->disk_queue, NSC_MAXPATH);
722 			}
723 		}
724 	}
725 fail:
726 	rdc_many_exit(krdc);
727 	return (rc);
728 }
729 
730 
731 /*
732  * Move the set to a new group if possible
733  */
734 static int
change_group(rdc_k_info_t * krdc,int options)735 change_group(rdc_k_info_t *krdc, int options)
736 {
737 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
738 	rdc_u_info_t *utmp;
739 	rdc_k_info_t *ktmp;
740 	rdc_k_info_t *next;
741 	char tmpq[NSC_MAXPATH];
742 	int index;
743 	int rc = -1;
744 	rdc_group_t *group, *old_group;
745 	nsthread_t *trc;
746 
747 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
748 
749 	/*
750 	 * Look for matching group name, primary host name and secondary
751 	 * host name.
752 	 */
753 
754 	bzero(&tmpq, sizeof (tmpq));
755 	rdc_many_enter(krdc);
756 
757 	old_group = krdc->group;
758 	next = krdc->group_next;
759 
760 	if (RDC_IS_DISKQ(old_group)) { /* can't keep your own queue */
761 		(void) strncpy(tmpq, urdc->disk_queue, NSC_MAXPATH);
762 		bzero(urdc->disk_queue, sizeof (urdc->disk_queue));
763 	}
764 	for (index = 0; index < rdc_max_sets; index++) {
765 		utmp = &rdc_u_info[index];
766 		ktmp = &rdc_k_info[index];
767 
768 		if (ktmp == krdc)
769 			continue;
770 
771 		if (urdc->group_name[0] == 0)
772 			break;
773 
774 		if (!IS_CONFIGURED(ktmp))
775 			continue;
776 
777 		if (strncmp(utmp->group_name, urdc->group_name,
778 		    NSC_MAXPATH) != 0)
779 			continue;
780 		if (strncmp(utmp->primary.intf, urdc->primary.intf,
781 		    MAX_RDC_HOST_SIZE) != 0)
782 			goto bad;
783 		if (strncmp(utmp->secondary.intf, urdc->secondary.intf,
784 		    MAX_RDC_HOST_SIZE) != 0)
785 			goto bad;
786 
787 		/* Group already exists, so add this set to the group */
788 
789 		if (((options & RDC_OPT_ASYNC) == 0) &&
790 		    ((ktmp->type_flag & RDC_ASYNCMODE) != 0)) {
791 			/* Must be same mode as existing group members */
792 			goto bad;
793 		}
794 		if (((options & RDC_OPT_ASYNC) != 0) &&
795 		    ((ktmp->type_flag & RDC_ASYNCMODE) == 0)) {
796 			/* Must be same mode as existing group members */
797 			goto bad;
798 		}
799 
800 		ktmp->group->count++;
801 		krdc->group = ktmp->group;
802 		krdc->group_next = ktmp->group_next;
803 		ktmp->group_next = krdc;
804 		bzero(urdc->disk_queue, sizeof (urdc->disk_queue));
805 		(void) strncpy(urdc->disk_queue, utmp->disk_queue, NSC_MAXPATH);
806 
807 		goto good;
808 	}
809 
810 	/* This must be a new group */
811 	group = rdc_newgroup();
812 	krdc->group = group;
813 	krdc->group_next = krdc;
814 
815 	trc = nst_create(_rdc_ioset, rdc_qfiller_thr, (void *)krdc, NST_SLEEP);
816 	if (trc == NULL) {
817 		rc = -1;
818 		cmn_err(CE_NOTE, "!unable to create queue filler daemon");
819 		goto bad;
820 	}
821 
822 	if (urdc->disk_queue[0] == 0) {
823 		krdc->group->flags |= RDC_MEMQUE;
824 	} else {
825 		krdc->group->flags |= RDC_DISKQUE;
826 		if ((rc = rdc_enable_diskq(krdc)) < 0)
827 			goto bad;
828 	}
829 good:
830 	if (options & RDC_OPT_ASYNC) {
831 		krdc->type_flag |= RDC_ASYNCMODE;
832 		rdc_set_flags(urdc, RDC_ASYNC);
833 	} else {
834 		krdc->type_flag &= ~RDC_ASYNCMODE;
835 		rdc_clr_flags(urdc, RDC_ASYNC);
836 	}
837 
838 	old_group->count--;
839 	if (!old_group->rdc_writer && old_group->count == 0) {
840 		/* Group now empty, so destroy */
841 		if (RDC_IS_DISKQ(old_group)) {
842 			rdc_unintercept_diskq(old_group);
843 			mutex_enter(&old_group->diskqmutex);
844 			rdc_close_diskq(old_group);
845 			mutex_exit(&old_group->diskqmutex);
846 		}
847 
848 		mutex_enter(&old_group->ra_queue.net_qlock);
849 
850 		/*
851 		 * Assure the we've stopped and the flusher thread has not
852 		 * fallen back to sleep
853 		 */
854 		if (old_group->ra_queue.qfill_sleeping != RDC_QFILL_DEAD) {
855 			old_group->ra_queue.qfflags |= RDC_QFILLSTOP;
856 			while (old_group->ra_queue.qfflags & RDC_QFILLSTOP) {
857 				if (old_group->ra_queue.qfill_sleeping ==
858 				    RDC_QFILL_ASLEEP)
859 					cv_broadcast(&old_group->ra_queue.qfcv);
860 				mutex_exit(&old_group->ra_queue.net_qlock);
861 				delay(2);
862 				mutex_enter(&old_group->ra_queue.net_qlock);
863 			}
864 		}
865 		mutex_exit(&old_group->ra_queue.net_qlock);
866 
867 		rdc_delgroup(old_group);
868 		rdc_many_exit(krdc);
869 		return (0);
870 	}
871 
872 	/* Take this rdc structure off the old group list */
873 
874 	for (ktmp = next; ktmp->group_next != krdc; ktmp = ktmp->group_next)
875 	;
876 	ktmp->group_next = next;
877 
878 	rdc_many_exit(krdc);
879 	return (0);
880 
881 bad:
882 	/* Leave existing group status alone */
883 	(void) strncpy(urdc->disk_queue, tmpq, NSC_MAXPATH);
884 	rdc_many_exit(krdc);
885 	return (rc);
886 }
887 
888 
889 /*
890  * Set flags for an rdc set, setting the group flags as necessary.
891  */
892 void
rdc_set_flags(rdc_u_info_t * urdc,int flags)893 rdc_set_flags(rdc_u_info_t *urdc, int flags)
894 {
895 	rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
896 	int vflags, sflags, bflags, ssflags;
897 
898 	DTRACE_PROBE2(rdc_set_flags, int, krdc->index, int, flags);
899 	vflags = flags & RDC_VFLAGS;
900 	sflags = flags & RDC_SFLAGS;
901 	bflags = flags & RDC_BFLAGS;
902 	ssflags = flags & RDC_SYNC_STATE_FLAGS;
903 
904 	if (vflags) {
905 		/* normal volume flags */
906 		ASSERT(MUTEX_HELD(&rdc_conf_lock) ||
907 		    MUTEX_HELD(&krdc->group->lock));
908 		if (ssflags)
909 			mutex_enter(&krdc->bmapmutex);
910 
911 		urdc->flags |= vflags;
912 
913 		if (ssflags)
914 			mutex_exit(&krdc->bmapmutex);
915 	}
916 
917 	if (sflags) {
918 		/* Sync state flags that are protected by a different lock */
919 		ASSERT(MUTEX_HELD(&rdc_many_lock));
920 		urdc->sync_flags |= sflags;
921 	}
922 
923 	if (bflags) {
924 		/* Bmap state flags that are protected by a different lock */
925 		ASSERT(MUTEX_HELD(&krdc->bmapmutex));
926 		urdc->bmap_flags |= bflags;
927 	}
928 
929 }
930 
931 
932 /*
933  * Clear flags for an rdc set, clearing the group flags as necessary.
934  */
935 void
rdc_clr_flags(rdc_u_info_t * urdc,int flags)936 rdc_clr_flags(rdc_u_info_t *urdc, int flags)
937 {
938 	rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
939 	int vflags, sflags, bflags;
940 
941 	DTRACE_PROBE2(rdc_clr_flags, int, krdc->index, int, flags);
942 	vflags = flags & RDC_VFLAGS;
943 	sflags = flags & RDC_SFLAGS;
944 	bflags = flags & RDC_BFLAGS;
945 
946 	if (vflags) {
947 		/* normal volume flags */
948 		ASSERT(MUTEX_HELD(&rdc_conf_lock) ||
949 		    MUTEX_HELD(&krdc->group->lock));
950 		urdc->flags &= ~vflags;
951 
952 	}
953 
954 	if (sflags) {
955 		/* Sync state flags that are protected by a different lock */
956 		ASSERT(MUTEX_HELD(&rdc_many_lock));
957 		urdc->sync_flags &= ~sflags;
958 	}
959 
960 	if (bflags) {
961 		/* Bmap state flags that are protected by a different lock */
962 		ASSERT(MUTEX_HELD(&krdc->bmapmutex));
963 		urdc->bmap_flags &= ~bflags;
964 	}
965 }
966 
967 
968 /*
969  * Get the flags for an rdc set.
970  */
971 int
rdc_get_vflags(rdc_u_info_t * urdc)972 rdc_get_vflags(rdc_u_info_t *urdc)
973 {
974 	return (urdc->flags | urdc->sync_flags | urdc->bmap_flags);
975 }
976 
977 
978 /*
979  * Initialise flags for an rdc set.
980  */
981 static void
rdc_init_flags(rdc_u_info_t * urdc)982 rdc_init_flags(rdc_u_info_t *urdc)
983 {
984 	urdc->flags = 0;
985 	urdc->mflags = 0;
986 	urdc->sync_flags = 0;
987 	urdc->bmap_flags = 0;
988 }
989 
990 
991 /*
992  * Set flags for a many group.
993  */
994 void
rdc_set_mflags(rdc_u_info_t * urdc,int flags)995 rdc_set_mflags(rdc_u_info_t *urdc, int flags)
996 {
997 	rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
998 	rdc_k_info_t *this = krdc;
999 
1000 	ASSERT(!(flags & ~RDC_MFLAGS));
1001 
1002 	if (flags == 0)
1003 		return;
1004 
1005 	ASSERT(MUTEX_HELD(&rdc_many_lock));
1006 
1007 	rdc_set_flags(urdc, flags);	/* set flags on local urdc */
1008 
1009 	urdc->mflags |= flags;
1010 	for (krdc = krdc->many_next; krdc != this; krdc = krdc->many_next) {
1011 		urdc = &rdc_u_info[krdc->index];
1012 		if (!IS_ENABLED(urdc))
1013 			continue;
1014 		urdc->mflags |= flags;
1015 	}
1016 }
1017 
1018 
1019 /*
1020  * Clear flags for a many group.
1021  */
1022 void
rdc_clr_mflags(rdc_u_info_t * urdc,int flags)1023 rdc_clr_mflags(rdc_u_info_t *urdc, int flags)
1024 {
1025 	rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
1026 	rdc_k_info_t *this = krdc;
1027 	rdc_u_info_t *utmp;
1028 
1029 	ASSERT(!(flags & ~RDC_MFLAGS));
1030 
1031 	if (flags == 0)
1032 		return;
1033 
1034 	ASSERT(MUTEX_HELD(&rdc_many_lock));
1035 
1036 	rdc_clr_flags(urdc, flags);	/* clear flags on local urdc */
1037 
1038 	/*
1039 	 * We must maintain the mflags based on the set of flags for
1040 	 * all the urdc's that are chained up.
1041 	 */
1042 
1043 	/*
1044 	 * First look through all the urdc's and remove bits from
1045 	 * the 'flags' variable that are in use elsewhere.
1046 	 */
1047 
1048 	for (krdc = krdc->many_next; krdc != this; krdc = krdc->many_next) {
1049 		utmp = &rdc_u_info[krdc->index];
1050 		if (!IS_ENABLED(utmp))
1051 			continue;
1052 		flags &= ~(rdc_get_vflags(utmp) & RDC_MFLAGS);
1053 		if (flags == 0)
1054 			break;
1055 	}
1056 
1057 	/*
1058 	 * Now clear flags as necessary.
1059 	 */
1060 
1061 	if (flags != 0) {
1062 		urdc->mflags &= ~flags;
1063 		for (krdc = krdc->many_next; krdc != this;
1064 		    krdc = krdc->many_next) {
1065 			utmp = &rdc_u_info[krdc->index];
1066 			if (!IS_ENABLED(utmp))
1067 				continue;
1068 			utmp->mflags &= ~flags;
1069 		}
1070 	}
1071 }
1072 
1073 
1074 int
rdc_get_mflags(rdc_u_info_t * urdc)1075 rdc_get_mflags(rdc_u_info_t *urdc)
1076 {
1077 	return (urdc->mflags);
1078 }
1079 
1080 
1081 void
rdc_set_flags_log(rdc_u_info_t * urdc,int flags,char * why)1082 rdc_set_flags_log(rdc_u_info_t *urdc, int flags, char *why)
1083 {
1084 	DTRACE_PROBE2(rdc_set_flags_log, int, urdc->index, int, flags);
1085 
1086 	rdc_set_flags(urdc, flags);
1087 
1088 	if (why == NULL)
1089 		return;
1090 
1091 	if (flags & RDC_LOGGING)
1092 		cmn_err(CE_NOTE, "!sndr: %s:%s entered logging mode: %s",
1093 		    urdc->secondary.intf, urdc->secondary.file, why);
1094 	if (flags & RDC_VOL_FAILED)
1095 		cmn_err(CE_NOTE, "!sndr: %s:%s volume failed: %s",
1096 		    urdc->secondary.intf, urdc->secondary.file, why);
1097 	if (flags & RDC_BMP_FAILED)
1098 		cmn_err(CE_NOTE, "!sndr: %s:%s bitmap failed: %s",
1099 		    urdc->secondary.intf, urdc->secondary.file, why);
1100 }
1101 /*
1102  * rdc_lor(source, dest, len)
1103  * logically OR memory pointed to by source and dest, copying result into dest.
1104  */
1105 void
rdc_lor(const uchar_t * source,uchar_t * dest,int len)1106 rdc_lor(const uchar_t *source, uchar_t *dest, int len)
1107 {
1108 	int i;
1109 
1110 	if (source == NULL)
1111 		return;
1112 
1113 	for (i = 0; i < len; i++)
1114 		*dest++ |= *source++;
1115 }
1116 
1117 
1118 static int
check_filesize(int index,spcs_s_info_t kstatus)1119 check_filesize(int index, spcs_s_info_t kstatus)
1120 {
1121 	uint64_t remote_size;
1122 	char tmp1[16], tmp2[16];
1123 	rdc_u_info_t *urdc = &rdc_u_info[index];
1124 	int status;
1125 
1126 	status = rdc_net_getsize(index, &remote_size);
1127 	if (status) {
1128 		(void) spcs_s_inttostring(status, tmp1, sizeof (tmp1), 0);
1129 		spcs_s_add(kstatus, RDC_EGETSIZE, urdc->secondary.intf,
1130 		    urdc->secondary.file, tmp1);
1131 		(void) rdc_net_state(index, CCIO_ENABLELOG);
1132 		return (RDC_EGETSIZE);
1133 	}
1134 	if (remote_size < (unsigned long long)urdc->volume_size) {
1135 		(void) spcs_s_inttostring(
1136 		    urdc->volume_size, tmp1, sizeof (tmp1), 0);
1137 		/*
1138 		 * Cheat, and covert to int, until we have
1139 		 * spcs_s_unsignedlonginttostring().
1140 		 */
1141 		status = (int)remote_size;
1142 		(void) spcs_s_inttostring(status, tmp2, sizeof (tmp2), 0);
1143 		spcs_s_add(kstatus, RDC_ESIZE, urdc->primary.intf,
1144 		    urdc->primary.file, tmp1, urdc->secondary.intf,
1145 		    urdc->secondary.file, tmp2);
1146 		(void) rdc_net_state(index, CCIO_ENABLELOG);
1147 		return (RDC_ESIZE);
1148 	}
1149 	return (0);
1150 }
1151 
1152 
1153 static void
rdc_volume_update_svc(intptr_t arg)1154 rdc_volume_update_svc(intptr_t arg)
1155 {
1156 	rdc_update_t *update = (rdc_update_t *)arg;
1157 	rdc_k_info_t *krdc;
1158 	rdc_k_info_t *this;
1159 	rdc_u_info_t *urdc;
1160 	struct net_bdata6 bd;
1161 	int index;
1162 	int rc;
1163 
1164 #ifdef DEBUG_IIUPDATE
1165 	cmn_err(CE_NOTE, "!SNDR received update request for %s",
1166 	    update->volume);
1167 #endif
1168 
1169 	if ((update->protocol != RDC_SVC_ONRETURN) &&
1170 	    (update->protocol != RDC_SVC_VOL_ENABLED)) {
1171 		/* don't understand what the client intends to do */
1172 		update->denied = 1;
1173 		spcs_s_add(update->status, RDC_EVERSION);
1174 		return;
1175 	}
1176 
1177 	index = rdc_lookup_enabled(update->volume, 0);
1178 	if (index < 0)
1179 		return;
1180 
1181 	/*
1182 	 * warn II that this volume is in use by sndr so
1183 	 * II can validate the sizes of the master vs shadow
1184 	 * and avoid trouble later down the line with
1185 	 * size mis-matches between urdc->volume_size and
1186 	 * what is returned from nsc_partsize() which may
1187 	 * be the size of the master when replicating the shadow
1188 	 */
1189 	if (update->protocol == RDC_SVC_VOL_ENABLED) {
1190 		if (index >= 0)
1191 			update->denied = 1;
1192 		return;
1193 	}
1194 
1195 	krdc = &rdc_k_info[index];
1196 	urdc = &rdc_u_info[index];
1197 	this = krdc;
1198 
1199 	do {
1200 		if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) {
1201 #ifdef DEBUG_IIUPDATE
1202 		cmn_err(CE_NOTE, "!SNDR refused update request for %s",
1203 		    update->volume);
1204 #endif
1205 		update->denied = 1;
1206 		spcs_s_add(update->status, RDC_EMIRRORUP);
1207 		return;
1208 		}
1209 		/* 1->many - all must be logging */
1210 		if (IS_MANY(krdc) && IS_STATE(urdc, RDC_PRIMARY)) {
1211 			rdc_many_enter(krdc);
1212 			for (krdc = krdc->many_next; krdc != this;
1213 			    krdc = krdc->many_next) {
1214 				urdc = &rdc_u_info[krdc->index];
1215 				if (!IS_ENABLED(urdc))
1216 					continue;
1217 				break;
1218 			}
1219 			rdc_many_exit(krdc);
1220 		}
1221 	} while (krdc != this);
1222 
1223 #ifdef DEBUG_IIUPDATE
1224 	cmn_err(CE_NOTE, "!SNDR allowed update request for %s", update->volume);
1225 #endif
1226 	urdc = &rdc_u_info[krdc->index];
1227 	do {
1228 
1229 		bd.size = min(krdc->bitmap_size, (nsc_size_t)update->size);
1230 		bd.data.data_val = (char *)update->bitmap;
1231 		bd.offset = 0;
1232 		bd.cd = index;
1233 
1234 		if ((rc = RDC_OR_BITMAP(&bd)) != 0) {
1235 			update->denied = 1;
1236 			spcs_s_add(update->status, rc);
1237 			return;
1238 		}
1239 		urdc = &rdc_u_info[index];
1240 		urdc->bits_set = RDC_COUNT_BITMAP(krdc);
1241 		if (IS_MANY(krdc) && IS_STATE(urdc, RDC_PRIMARY)) {
1242 			rdc_many_enter(krdc);
1243 			for (krdc = krdc->many_next; krdc != this;
1244 			    krdc = krdc->many_next) {
1245 				index = krdc->index;
1246 				if (!IS_ENABLED(urdc))
1247 					continue;
1248 				break;
1249 			}
1250 			rdc_many_exit(krdc);
1251 		}
1252 	} while (krdc != this);
1253 
1254 
1255 	/* II (or something else) has updated us, so no need for a sync */
1256 	if (rdc_get_vflags(urdc) & (RDC_SYNC_NEEDED | RDC_RSYNC_NEEDED)) {
1257 		rdc_many_enter(krdc);
1258 		rdc_clr_flags(urdc, RDC_SYNC_NEEDED | RDC_RSYNC_NEEDED);
1259 		rdc_many_exit(krdc);
1260 	}
1261 
1262 	if (krdc->bitmap_write > 0)
1263 		(void) rdc_write_bitmap(krdc);
1264 }
1265 
1266 
1267 /*
1268  * rdc_check()
1269  *
1270  * Return 0 if the set is configured, enabled and the supplied
1271  * addressing information matches the in-kernel config, otherwise
1272  * return 1.
1273  */
1274 static int
rdc_check(rdc_k_info_t * krdc,rdc_set_t * rdc_set)1275 rdc_check(rdc_k_info_t *krdc, rdc_set_t *rdc_set)
1276 {
1277 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1278 
1279 	ASSERT(MUTEX_HELD(&krdc->group->lock));
1280 
1281 	if (!IS_ENABLED(urdc))
1282 		return (1);
1283 
1284 	if (strncmp(urdc->primary.file, rdc_set->primary.file,
1285 	    NSC_MAXPATH) != 0) {
1286 #ifdef DEBUG
1287 		cmn_err(CE_WARN, "!rdc_check: primary file mismatch %s vs %s",
1288 		    urdc->primary.file, rdc_set->primary.file);
1289 #endif
1290 		return (1);
1291 	}
1292 
1293 	if (rdc_set->primary.addr.len != 0 &&
1294 	    bcmp(urdc->primary.addr.buf, rdc_set->primary.addr.buf,
1295 	    urdc->primary.addr.len) != 0) {
1296 #ifdef DEBUG
1297 		cmn_err(CE_WARN, "!rdc_check: primary address mismatch for %s",
1298 		    urdc->primary.file);
1299 #endif
1300 		return (1);
1301 	}
1302 
1303 	if (strncmp(urdc->secondary.file, rdc_set->secondary.file,
1304 	    NSC_MAXPATH) != 0) {
1305 #ifdef DEBUG
1306 		cmn_err(CE_WARN, "!rdc_check: secondary file mismatch %s vs %s",
1307 		    urdc->secondary.file, rdc_set->secondary.file);
1308 #endif
1309 		return (1);
1310 	}
1311 
1312 	if (rdc_set->secondary.addr.len != 0 &&
1313 	    bcmp(urdc->secondary.addr.buf, rdc_set->secondary.addr.buf,
1314 	    urdc->secondary.addr.len) != 0) {
1315 #ifdef DEBUG
1316 		cmn_err(CE_WARN, "!rdc_check: secondary addr mismatch for %s",
1317 		    urdc->secondary.file);
1318 #endif
1319 		return (1);
1320 	}
1321 
1322 	return (0);
1323 }
1324 
1325 
1326 /*
1327  * Lookup enabled sets for a bitmap match
1328  */
1329 
1330 int
rdc_lookup_bitmap(char * pathname)1331 rdc_lookup_bitmap(char *pathname)
1332 {
1333 	rdc_u_info_t *urdc;
1334 #ifdef DEBUG
1335 	rdc_k_info_t *krdc;
1336 #endif
1337 	int index;
1338 
1339 	for (index = 0; index < rdc_max_sets; index++) {
1340 		urdc = &rdc_u_info[index];
1341 #ifdef DEBUG
1342 		krdc = &rdc_k_info[index];
1343 #endif
1344 		ASSERT(krdc->index == index);
1345 		ASSERT(urdc->index == index);
1346 
1347 		if (!IS_ENABLED(urdc))
1348 			continue;
1349 
1350 		if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1351 			if (strncmp(pathname, urdc->primary.bitmap,
1352 			    NSC_MAXPATH) == 0)
1353 				return (index);
1354 		} else {
1355 			if (strncmp(pathname, urdc->secondary.bitmap,
1356 			    NSC_MAXPATH) == 0)
1357 				return (index);
1358 		}
1359 	}
1360 
1361 	return (-1);
1362 }
1363 
1364 
1365 /*
1366  * Translate a pathname to index into rdc_k_info[].
1367  * Returns first match that is enabled.
1368  */
1369 
1370 int
rdc_lookup_enabled(char * pathname,int allow_disabling)1371 rdc_lookup_enabled(char *pathname, int allow_disabling)
1372 {
1373 	rdc_u_info_t *urdc;
1374 	rdc_k_info_t *krdc;
1375 	int index;
1376 
1377 restart:
1378 	for (index = 0; index < rdc_max_sets; index++) {
1379 		urdc = &rdc_u_info[index];
1380 		krdc = &rdc_k_info[index];
1381 
1382 		ASSERT(krdc->index == index);
1383 		ASSERT(urdc->index == index);
1384 
1385 		if (!IS_ENABLED(urdc))
1386 			continue;
1387 
1388 		if (allow_disabling == 0 && krdc->type_flag & RDC_UNREGISTER)
1389 			continue;
1390 
1391 		if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1392 			if (strncmp(pathname, urdc->primary.file,
1393 			    NSC_MAXPATH) == 0)
1394 				return (index);
1395 		} else {
1396 			if (strncmp(pathname, urdc->secondary.file,
1397 			    NSC_MAXPATH) == 0)
1398 				return (index);
1399 		}
1400 	}
1401 
1402 	if (allow_disabling == 0) {
1403 		/* None found, or only a disabling one found, so try again */
1404 		allow_disabling = 1;
1405 		goto restart;
1406 	}
1407 
1408 	return (-1);
1409 }
1410 
1411 
1412 /*
1413  * Translate a pathname to index into rdc_k_info[].
1414  * Returns first match that is configured.
1415  *
1416  * Used by enable & resume code.
1417  * Must be called with rdc_conf_lock held.
1418  */
1419 
1420 int
rdc_lookup_configured(char * pathname)1421 rdc_lookup_configured(char *pathname)
1422 {
1423 	rdc_u_info_t *urdc;
1424 	rdc_k_info_t *krdc;
1425 	int index;
1426 
1427 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
1428 
1429 	for (index = 0; index < rdc_max_sets; index++) {
1430 		urdc = &rdc_u_info[index];
1431 		krdc = &rdc_k_info[index];
1432 
1433 		ASSERT(krdc->index == index);
1434 		ASSERT(urdc->index == index);
1435 
1436 		if (!IS_CONFIGURED(krdc))
1437 			continue;
1438 
1439 		if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1440 			if (strncmp(pathname, urdc->primary.file,
1441 			    NSC_MAXPATH) == 0)
1442 				return (index);
1443 		} else {
1444 			if (strncmp(pathname, urdc->secondary.file,
1445 			    NSC_MAXPATH) == 0)
1446 				return (index);
1447 		}
1448 	}
1449 
1450 	return (-1);
1451 }
1452 
1453 
1454 /*
1455  * Looks up a configured set with matching secondary interface:volume
1456  * to check for illegal many-to-one volume configs.  To be used during
1457  * enable and resume processing.
1458  *
1459  * Must be called with rdc_conf_lock held.
1460  */
1461 
1462 static int
rdc_lookup_many2one(rdc_set_t * rdc_set)1463 rdc_lookup_many2one(rdc_set_t *rdc_set)
1464 {
1465 	rdc_u_info_t *urdc;
1466 	rdc_k_info_t *krdc;
1467 	int index;
1468 
1469 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
1470 
1471 	for (index = 0; index < rdc_max_sets; index++) {
1472 		urdc = &rdc_u_info[index];
1473 		krdc = &rdc_k_info[index];
1474 
1475 		if (!IS_CONFIGURED(krdc))
1476 			continue;
1477 
1478 		if (strncmp(urdc->secondary.file,
1479 		    rdc_set->secondary.file, NSC_MAXPATH) != 0)
1480 			continue;
1481 		if (strncmp(urdc->secondary.intf,
1482 		    rdc_set->secondary.intf, MAX_RDC_HOST_SIZE) != 0)
1483 			continue;
1484 
1485 		break;
1486 	}
1487 
1488 	if (index < rdc_max_sets)
1489 		return (index);
1490 	else
1491 		return (-1);
1492 }
1493 
1494 
1495 /*
1496  * Looks up an rdc set to check if it is already configured, to be used from
1497  * functions called from the config ioctl where the interface names can be
1498  * used for comparison.
1499  *
1500  * Must be called with rdc_conf_lock held.
1501  */
1502 
1503 int
rdc_lookup_byname(rdc_set_t * rdc_set)1504 rdc_lookup_byname(rdc_set_t *rdc_set)
1505 {
1506 	rdc_u_info_t *urdc;
1507 	rdc_k_info_t *krdc;
1508 	int index;
1509 
1510 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
1511 
1512 	for (index = 0; index < rdc_max_sets; index++) {
1513 		urdc = &rdc_u_info[index];
1514 		krdc = &rdc_k_info[index];
1515 
1516 		ASSERT(krdc->index == index);
1517 		ASSERT(urdc->index == index);
1518 
1519 		if (!IS_CONFIGURED(krdc))
1520 			continue;
1521 
1522 		if (strncmp(urdc->primary.file, rdc_set->primary.file,
1523 		    NSC_MAXPATH) != 0)
1524 			continue;
1525 		if (strncmp(urdc->primary.intf, rdc_set->primary.intf,
1526 		    MAX_RDC_HOST_SIZE) != 0)
1527 			continue;
1528 		if (strncmp(urdc->secondary.file, rdc_set->secondary.file,
1529 		    NSC_MAXPATH) != 0)
1530 			continue;
1531 		if (strncmp(urdc->secondary.intf, rdc_set->secondary.intf,
1532 		    MAX_RDC_HOST_SIZE) != 0)
1533 			continue;
1534 
1535 		break;
1536 	}
1537 
1538 	if (index < rdc_max_sets)
1539 		return (index);
1540 	else
1541 		return (-1);
1542 }
1543 
1544 /*
1545  * Looks up a secondary hostname and device, to be used from
1546  * functions called from the config ioctl where the interface names can be
1547  * used for comparison.
1548  *
1549  * Must be called with rdc_conf_lock held.
1550  */
1551 
1552 int
rdc_lookup_byhostdev(char * intf,char * file)1553 rdc_lookup_byhostdev(char *intf, char *file)
1554 {
1555 	rdc_u_info_t *urdc;
1556 	rdc_k_info_t *krdc;
1557 	int index;
1558 
1559 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
1560 
1561 	for (index = 0; index < rdc_max_sets; index++) {
1562 		urdc = &rdc_u_info[index];
1563 		krdc = &rdc_k_info[index];
1564 
1565 		ASSERT(krdc->index == index);
1566 		ASSERT(urdc->index == index);
1567 
1568 		if (!IS_CONFIGURED(krdc))
1569 			continue;
1570 
1571 		if (strncmp(urdc->secondary.file, file,
1572 		    NSC_MAXPATH) != 0)
1573 			continue;
1574 		if (strncmp(urdc->secondary.intf, intf,
1575 		    MAX_RDC_HOST_SIZE) != 0)
1576 			continue;
1577 		break;
1578 	}
1579 
1580 	if (index < rdc_max_sets)
1581 		return (index);
1582 	else
1583 		return (-1);
1584 }
1585 
1586 
1587 /*
1588  * Looks up an rdc set to see if it is currently enabled, to be used on the
1589  * server so that the interface addresses must be used for comparison, as
1590  * the interface names may differ from those used on the client.
1591  *
1592  */
1593 
1594 int
rdc_lookup_byaddr(rdc_set_t * rdc_set)1595 rdc_lookup_byaddr(rdc_set_t *rdc_set)
1596 {
1597 	rdc_u_info_t *urdc;
1598 #ifdef DEBUG
1599 	rdc_k_info_t *krdc;
1600 #endif
1601 	int index;
1602 
1603 	for (index = 0; index < rdc_max_sets; index++) {
1604 		urdc = &rdc_u_info[index];
1605 #ifdef DEBUG
1606 		krdc = &rdc_k_info[index];
1607 #endif
1608 		ASSERT(krdc->index == index);
1609 		ASSERT(urdc->index == index);
1610 
1611 		if (!IS_ENABLED(urdc))
1612 			continue;
1613 
1614 		if (strcmp(urdc->primary.file, rdc_set->primary.file) != 0)
1615 			continue;
1616 
1617 		if (strcmp(urdc->secondary.file, rdc_set->secondary.file) != 0)
1618 			continue;
1619 
1620 		if (bcmp(urdc->primary.addr.buf, rdc_set->primary.addr.buf,
1621 		    urdc->primary.addr.len) != 0) {
1622 			continue;
1623 		}
1624 
1625 		if (bcmp(urdc->secondary.addr.buf, rdc_set->secondary.addr.buf,
1626 		    urdc->secondary.addr.len) != 0) {
1627 			continue;
1628 		}
1629 
1630 		break;
1631 	}
1632 
1633 	if (index < rdc_max_sets)
1634 		return (index);
1635 	else
1636 		return (-1);
1637 }
1638 
1639 
1640 /*
1641  * Return index of first multihop or 1-to-many
1642  * Behavior controlled by setting ismany.
1643  * ismany TRUE (one-to-many)
1644  * ismany FALSE (multihops)
1645  *
1646  */
1647 static int
rdc_lookup_multimany(rdc_k_info_t * krdc,const int ismany)1648 rdc_lookup_multimany(rdc_k_info_t *krdc, const int ismany)
1649 {
1650 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1651 	rdc_u_info_t *utmp;
1652 	rdc_k_info_t *ktmp;
1653 	char *pathname;
1654 	int index;
1655 	int role;
1656 
1657 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
1658 	ASSERT(MUTEX_HELD(&rdc_many_lock));
1659 
1660 	if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1661 		/* this host is the primary of the krdc set */
1662 		pathname = urdc->primary.file;
1663 		if (ismany) {
1664 			/*
1665 			 * 1-many sets are linked by primary :
1666 			 * look for matching primary on this host
1667 			 */
1668 			role = RDC_PRIMARY;
1669 		} else {
1670 			/*
1671 			 * multihop sets link primary to secondary :
1672 			 * look for matching secondary on this host
1673 			 */
1674 			role = 0;
1675 		}
1676 	} else {
1677 		/* this host is the secondary of the krdc set */
1678 		pathname = urdc->secondary.file;
1679 		if (ismany) {
1680 			/*
1681 			 * 1-many sets are linked by primary, so if
1682 			 * this host is the secondary of the set this
1683 			 * cannot require 1-many linkage.
1684 			 */
1685 			return (-1);
1686 		} else {
1687 			/*
1688 			 * multihop sets link primary to secondary :
1689 			 * look for matching primary on this host
1690 			 */
1691 			role = RDC_PRIMARY;
1692 		}
1693 	}
1694 
1695 	for (index = 0; index < rdc_max_sets; index++) {
1696 		utmp = &rdc_u_info[index];
1697 		ktmp = &rdc_k_info[index];
1698 
1699 		if (!IS_CONFIGURED(ktmp)) {
1700 			continue;
1701 		}
1702 
1703 		if (role == RDC_PRIMARY) {
1704 			/*
1705 			 * Find a primary that is this host and is not
1706 			 * krdc but shares the same data volume as krdc.
1707 			 */
1708 			if ((rdc_get_vflags(utmp) & RDC_PRIMARY) &&
1709 			    strncmp(utmp->primary.file, pathname,
1710 			    NSC_MAXPATH) == 0 && (krdc != ktmp)) {
1711 				break;
1712 			}
1713 		} else {
1714 			/*
1715 			 * Find a secondary that is this host and is not
1716 			 * krdc but shares the same data volume as krdc.
1717 			 */
1718 			if (!(rdc_get_vflags(utmp) & RDC_PRIMARY) &&
1719 			    strncmp(utmp->secondary.file, pathname,
1720 			    NSC_MAXPATH) == 0 && (krdc != ktmp)) {
1721 				break;
1722 			}
1723 		}
1724 	}
1725 
1726 	if (index < rdc_max_sets)
1727 		return (index);
1728 	else
1729 		return (-1);
1730 }
1731 
1732 /*
1733  * Returns secondary match that is configured.
1734  *
1735  * Used by enable & resume code.
1736  * Must be called with rdc_conf_lock held.
1737  */
1738 
1739 static int
rdc_lookup_secondary(char * pathname)1740 rdc_lookup_secondary(char *pathname)
1741 {
1742 	rdc_u_info_t *urdc;
1743 	rdc_k_info_t *krdc;
1744 	int index;
1745 
1746 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
1747 
1748 	for (index = 0; index < rdc_max_sets; index++) {
1749 		urdc = &rdc_u_info[index];
1750 		krdc = &rdc_k_info[index];
1751 
1752 		ASSERT(krdc->index == index);
1753 		ASSERT(urdc->index == index);
1754 
1755 		if (!IS_CONFIGURED(krdc))
1756 			continue;
1757 
1758 		if (!IS_STATE(urdc, RDC_PRIMARY)) {
1759 			if (strncmp(pathname, urdc->secondary.file,
1760 			    NSC_MAXPATH) == 0)
1761 			return (index);
1762 		}
1763 	}
1764 
1765 	return (-1);
1766 }
1767 
1768 
1769 static nsc_fd_t *
rdc_open_direct(rdc_k_info_t * krdc)1770 rdc_open_direct(rdc_k_info_t *krdc)
1771 {
1772 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1773 	int rc;
1774 
1775 	if (krdc->remote_fd == NULL)
1776 		krdc->remote_fd = nsc_open(urdc->direct_file,
1777 		    NSC_RDCHR_ID|NSC_DEVICE|NSC_RDWR, 0, 0, &rc);
1778 	return (krdc->remote_fd);
1779 }
1780 
1781 static void
rdc_close_direct(rdc_k_info_t * krdc)1782 rdc_close_direct(rdc_k_info_t *krdc)
1783 {
1784 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1785 
1786 	urdc->direct_file[0] = 0;
1787 	if (krdc->remote_fd) {
1788 		if (nsc_close(krdc->remote_fd) == 0) {
1789 			krdc->remote_fd = NULL;
1790 		}
1791 	}
1792 }
1793 
1794 
1795 #ifdef DEBUG_MANY
1796 static void
print_many(rdc_k_info_t * start)1797 print_many(rdc_k_info_t *start)
1798 {
1799 	rdc_k_info_t *p = start;
1800 	rdc_u_info_t *q = &rdc_u_info[p->index];
1801 
1802 	do {
1803 		cmn_err(CE_CONT, "!krdc %p, %s %s (many_nxt %p multi_nxt %p)\n",
1804 		    p, q->primary.file, q->secondary.file, p->many_next,
1805 		    p->multi_next);
1806 		delay(10);
1807 		p = p->many_next;
1808 		q = &rdc_u_info[p->index];
1809 	} while (p && p != start);
1810 }
1811 #endif /* DEBUG_MANY */
1812 
1813 
1814 static int
add_to_multi(rdc_k_info_t * krdc)1815 add_to_multi(rdc_k_info_t *krdc)
1816 {
1817 	rdc_u_info_t *urdc;
1818 	rdc_k_info_t *ktmp;
1819 	rdc_u_info_t *utmp;
1820 	int mindex;
1821 	int domulti;
1822 
1823 	urdc = &rdc_u_info[krdc->index];
1824 
1825 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
1826 	ASSERT(MUTEX_HELD(&rdc_many_lock));
1827 
1828 	/* Now find companion krdc */
1829 	mindex = rdc_lookup_multimany(krdc, FALSE);
1830 
1831 #ifdef DEBUG_MANY
1832 	cmn_err(CE_NOTE,
1833 	    "!add_to_multi: lookup_multimany: mindex %d prim %s sec %s",
1834 	    mindex, urdc->primary.file, urdc->secondary.file);
1835 #endif
1836 
1837 	if (mindex >= 0) {
1838 		ktmp = &rdc_k_info[mindex];
1839 		utmp = &rdc_u_info[mindex];
1840 
1841 		domulti = 1;
1842 
1843 		if ((rdc_get_vflags(urdc) & RDC_PRIMARY) &&
1844 		    ktmp->multi_next != NULL) {
1845 			/*
1846 			 * We are adding a new primary to a many
1847 			 * group that is the target of a multihop, just
1848 			 * ignore it since we are linked in elsewhere.
1849 			 */
1850 			domulti = 0;
1851 		}
1852 
1853 		if (domulti) {
1854 			if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1855 				/* Is previous leg using direct file I/O? */
1856 				if (utmp->direct_file[0] != 0) {
1857 					/* It is, so cannot proceed */
1858 					return (-1);
1859 				}
1860 			} else {
1861 				/* Is this leg using direct file I/O? */
1862 				if (urdc->direct_file[0] != 0) {
1863 					/* It is, so cannot proceed */
1864 					return (-1);
1865 				}
1866 			}
1867 			krdc->multi_next = ktmp;
1868 			ktmp->multi_next = krdc;
1869 		}
1870 	} else {
1871 		krdc->multi_next = NULL;
1872 #ifdef DEBUG_MANY
1873 		cmn_err(CE_NOTE, "!add_to_multi: NULL multi_next index %d",
1874 		    krdc->index);
1875 #endif
1876 	}
1877 
1878 	return (0);
1879 }
1880 
1881 
1882 /*
1883  * Add a new set to the circular list of 1-to-many primaries and chain
1884  * up any multihop as well.
1885  */
1886 static int
add_to_many(rdc_k_info_t * krdc)1887 add_to_many(rdc_k_info_t *krdc)
1888 {
1889 	rdc_k_info_t *okrdc;
1890 	int oindex;
1891 
1892 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
1893 
1894 	rdc_many_enter(krdc);
1895 
1896 	if (add_to_multi(krdc) < 0) {
1897 		rdc_many_exit(krdc);
1898 		return (-1);
1899 	}
1900 
1901 	oindex = rdc_lookup_multimany(krdc, TRUE);
1902 	if (oindex < 0) {
1903 #ifdef DEBUG_MANY
1904 		print_many(krdc);
1905 #endif
1906 		rdc_many_exit(krdc);
1907 		return (0);
1908 	}
1909 
1910 	okrdc = &rdc_k_info[oindex];
1911 
1912 #ifdef DEBUG_MANY
1913 	print_many(okrdc);
1914 #endif
1915 	krdc->many_next = okrdc->many_next;
1916 	okrdc->many_next = krdc;
1917 
1918 #ifdef DEBUG_MANY
1919 	print_many(okrdc);
1920 #endif
1921 	rdc_many_exit(krdc);
1922 	return (0);
1923 }
1924 
1925 
1926 /*
1927  * Remove a set from the circular list of 1-to-many primaries.
1928  */
1929 static void
remove_from_many(rdc_k_info_t * old)1930 remove_from_many(rdc_k_info_t *old)
1931 {
1932 	rdc_u_info_t *uold = &rdc_u_info[old->index];
1933 	rdc_k_info_t *p, *q;
1934 
1935 	ASSERT(MUTEX_HELD(&rdc_conf_lock));
1936 
1937 	rdc_many_enter(old);
1938 
1939 #ifdef DEBUG_MANY
1940 	cmn_err(CE_NOTE, "!rdc: before remove_from_many");
1941 	print_many(old);
1942 #endif
1943 
1944 	if (old->many_next == old) {
1945 		/* remove from multihop */
1946 		if ((q = old->multi_next) != NULL) {
1947 			ASSERT(q->multi_next == old);
1948 			q->multi_next = NULL;
1949 			old->multi_next = NULL;
1950 		}
1951 
1952 		rdc_many_exit(old);
1953 		return;
1954 	}
1955 
1956 	/* search */
1957 	for (p = old->many_next; p->many_next != old; p = p->many_next)
1958 	;
1959 
1960 	p->many_next = old->many_next;
1961 	old->many_next = old;
1962 
1963 	if ((q = old->multi_next) != NULL) {
1964 		/*
1965 		 * old was part of a multihop, so switch multi pointers
1966 		 * to someone remaining on the many chain
1967 		 */
1968 		ASSERT(p->multi_next == NULL);
1969 
1970 		q->multi_next = p;
1971 		p->multi_next = q;
1972 		old->multi_next = NULL;
1973 	}
1974 
1975 #ifdef DEBUG_MANY
1976 	if (p == old) {
1977 		cmn_err(CE_NOTE, "!rdc: after remove_from_many empty");
1978 	} else {
1979 		cmn_err(CE_NOTE, "!rdc: after remove_from_many");
1980 		print_many(p);
1981 	}
1982 #endif
1983 
1984 	rdc_clr_mflags(&rdc_u_info[p->index],
1985 	    (rdc_get_vflags(uold) & RDC_MFLAGS));
1986 
1987 	rdc_many_exit(old);
1988 }
1989 
1990 
1991 static int
_rdc_enable(rdc_set_t * rdc_set,int options,spcs_s_info_t kstatus)1992 _rdc_enable(rdc_set_t *rdc_set, int options, spcs_s_info_t kstatus)
1993 {
1994 	int index;
1995 	char *rhost;
1996 	struct netbuf *addrp;
1997 	rdc_k_info_t *krdc;
1998 	rdc_u_info_t *urdc;
1999 	rdc_srv_t *svp = NULL;
2000 	char *local_file;
2001 	char *local_bitmap;
2002 	char *diskq;
2003 	int rc;
2004 	nsc_size_t maxfbas;
2005 	rdc_group_t *grp;
2006 
2007 	if ((rdc_set->primary.intf[0] == 0) ||
2008 	    (rdc_set->primary.addr.len == 0) ||
2009 	    (rdc_set->primary.file[0] == 0) ||
2010 	    (rdc_set->primary.bitmap[0] == 0) ||
2011 	    (rdc_set->secondary.intf[0] == 0) ||
2012 	    (rdc_set->secondary.addr.len == 0) ||
2013 	    (rdc_set->secondary.file[0] == 0) ||
2014 	    (rdc_set->secondary.bitmap[0] == 0)) {
2015 		spcs_s_add(kstatus, RDC_EEMPTY);
2016 		return (RDC_EEMPTY);
2017 	}
2018 
2019 	/* Next check there aren't any enabled rdc sets which match. */
2020 
2021 	mutex_enter(&rdc_conf_lock);
2022 
2023 	if (rdc_lookup_byname(rdc_set) >= 0) {
2024 		mutex_exit(&rdc_conf_lock);
2025 		spcs_s_add(kstatus, RDC_EENABLED, rdc_set->primary.intf,
2026 		    rdc_set->primary.file, rdc_set->secondary.intf,
2027 		    rdc_set->secondary.file);
2028 		return (RDC_EENABLED);
2029 	}
2030 
2031 	if (rdc_lookup_many2one(rdc_set) >= 0) {
2032 		mutex_exit(&rdc_conf_lock);
2033 		spcs_s_add(kstatus, RDC_EMANY2ONE, rdc_set->primary.intf,
2034 		    rdc_set->primary.file, rdc_set->secondary.intf,
2035 		    rdc_set->secondary.file);
2036 		return (RDC_EMANY2ONE);
2037 	}
2038 
2039 	if (rdc_set->netconfig->knc_proto == NULL) {
2040 		mutex_exit(&rdc_conf_lock);
2041 		spcs_s_add(kstatus, RDC_ENETCONFIG);
2042 		return (RDC_ENETCONFIG);
2043 	}
2044 
2045 	if (rdc_set->primary.addr.len == 0) {
2046 		mutex_exit(&rdc_conf_lock);
2047 		spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->primary.file);
2048 		return (RDC_ENETBUF);
2049 	}
2050 
2051 	if (rdc_set->secondary.addr.len == 0) {
2052 		mutex_exit(&rdc_conf_lock);
2053 		spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->secondary.file);
2054 		return (RDC_ENETBUF);
2055 	}
2056 
2057 	/* Check that the local data volume isn't in use as a bitmap */
2058 	if (options & RDC_OPT_PRIMARY)
2059 		local_file = rdc_set->primary.file;
2060 	else
2061 		local_file = rdc_set->secondary.file;
2062 	if (rdc_lookup_bitmap(local_file) >= 0) {
2063 		mutex_exit(&rdc_conf_lock);
2064 		spcs_s_add(kstatus, RDC_EVOLINUSE, local_file);
2065 		return (RDC_EVOLINUSE);
2066 	}
2067 
2068 	/* check that the secondary data volume isn't in use */
2069 	if (!(options & RDC_OPT_PRIMARY)) {
2070 		local_file = rdc_set->secondary.file;
2071 		if (rdc_lookup_secondary(local_file) >= 0) {
2072 			mutex_exit(&rdc_conf_lock);
2073 			spcs_s_add(kstatus, RDC_EVOLINUSE, local_file);
2074 			return (RDC_EVOLINUSE);
2075 		}
2076 	}
2077 
2078 	/* check that the local data vol is not in use as a diskqueue */
2079 	if (options & RDC_OPT_PRIMARY) {
2080 		if (rdc_lookup_diskq(rdc_set->primary.file) >= 0) {
2081 			mutex_exit(&rdc_conf_lock);
2082 			spcs_s_add(kstatus,
2083 			    RDC_EVOLINUSE, rdc_set->primary.file);
2084 			return (RDC_EVOLINUSE);
2085 		}
2086 	}
2087 
2088 	/* Check that the bitmap isn't in use as a data volume */
2089 	if (options & RDC_OPT_PRIMARY)
2090 		local_bitmap = rdc_set->primary.bitmap;
2091 	else
2092 		local_bitmap = rdc_set->secondary.bitmap;
2093 	if (rdc_lookup_configured(local_bitmap) >= 0) {
2094 		mutex_exit(&rdc_conf_lock);
2095 		spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap);
2096 		return (RDC_EBMPINUSE);
2097 	}
2098 
2099 	/* Check that the bitmap isn't already in use as a bitmap */
2100 	if (rdc_lookup_bitmap(local_bitmap) >= 0) {
2101 		mutex_exit(&rdc_conf_lock);
2102 		spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap);
2103 		return (RDC_EBMPINUSE);
2104 	}
2105 
2106 	/* check that the diskq (if here) is not in use */
2107 	diskq = rdc_set->disk_queue;
2108 	if (diskq[0] && rdc_diskq_inuse(rdc_set, diskq)) {
2109 		mutex_exit(&rdc_conf_lock);
2110 		spcs_s_add(kstatus, RDC_EDISKQINUSE, diskq);
2111 		return (RDC_EDISKQINUSE);
2112 	}
2113 
2114 
2115 	/* Set urdc->volume_size */
2116 	index = rdc_dev_open(rdc_set, options);
2117 	if (index < 0) {
2118 		mutex_exit(&rdc_conf_lock);
2119 		if (options & RDC_OPT_PRIMARY)
2120 			spcs_s_add(kstatus, RDC_EOPEN, rdc_set->primary.intf,
2121 			    rdc_set->primary.file);
2122 		else
2123 			spcs_s_add(kstatus, RDC_EOPEN, rdc_set->secondary.intf,
2124 			    rdc_set->secondary.file);
2125 		return (RDC_EOPEN);
2126 	}
2127 
2128 	urdc = &rdc_u_info[index];
2129 	krdc = &rdc_k_info[index];
2130 
2131 	/* copy relevant parts of rdc_set to urdc field by field */
2132 
2133 	(void) strncpy(urdc->primary.intf, rdc_set->primary.intf,
2134 	    MAX_RDC_HOST_SIZE);
2135 	(void) strncpy(urdc->secondary.intf, rdc_set->secondary.intf,
2136 	    MAX_RDC_HOST_SIZE);
2137 
2138 	(void) strncpy(urdc->group_name, rdc_set->group_name, NSC_MAXPATH);
2139 	(void) strncpy(urdc->disk_queue, rdc_set->disk_queue, NSC_MAXPATH);
2140 
2141 	dup_rdc_netbuf(&rdc_set->primary.addr, &urdc->primary.addr);
2142 	(void) strncpy(urdc->primary.file, rdc_set->primary.file, NSC_MAXPATH);
2143 	(void) strncpy(urdc->primary.bitmap, rdc_set->primary.bitmap,
2144 	    NSC_MAXPATH);
2145 
2146 	dup_rdc_netbuf(&rdc_set->secondary.addr, &urdc->secondary.addr);
2147 	(void) strncpy(urdc->secondary.file, rdc_set->secondary.file,
2148 	    NSC_MAXPATH);
2149 	(void) strncpy(urdc->secondary.bitmap, rdc_set->secondary.bitmap,
2150 	    NSC_MAXPATH);
2151 
2152 	urdc->setid = rdc_set->setid;
2153 
2154 	/*
2155 	 * before we try to add to group, or create one, check out
2156 	 * if we are doing the wrong thing with the diskq
2157 	 */
2158 
2159 	if (urdc->disk_queue[0] && (options & RDC_OPT_SYNC)) {
2160 		mutex_exit(&rdc_conf_lock);
2161 		rdc_dev_close(krdc);
2162 		spcs_s_add(kstatus, RDC_EQWRONGMODE);
2163 		return (RDC_EQWRONGMODE);
2164 	}
2165 
2166 	if ((rc = add_to_group(krdc, options, RDC_CMD_ENABLE)) != 0) {
2167 		mutex_exit(&rdc_conf_lock);
2168 		rdc_dev_close(krdc);
2169 		if (rc == RDC_EQNOADD) {
2170 			spcs_s_add(kstatus, RDC_EQNOADD, rdc_set->disk_queue);
2171 			return (RDC_EQNOADD);
2172 		} else {
2173 			spcs_s_add(kstatus, RDC_EGROUP,
2174 			    rdc_set->primary.intf, rdc_set->primary.file,
2175 			    rdc_set->secondary.intf, rdc_set->secondary.file,
2176 			    rdc_set->group_name);
2177 			return (RDC_EGROUP);
2178 		}
2179 	}
2180 
2181 	/*
2182 	 * maxfbas was set in rdc_dev_open as primary's maxfbas.
2183 	 * If diskq's maxfbas is smaller, then use diskq's.
2184 	 */
2185 	grp = krdc->group;
2186 	if (grp && RDC_IS_DISKQ(grp) && (grp->diskqfd != 0)) {
2187 		rc = _rdc_rsrv_diskq(grp);
2188 		if (RDC_SUCCESS(rc)) {
2189 			rc = nsc_maxfbas(grp->diskqfd, 0, &maxfbas);
2190 			if (rc == 0) {
2191 #ifdef DEBUG
2192 				if (krdc->maxfbas != maxfbas)
2193 					cmn_err(CE_NOTE,
2194 					    "!_rdc_enable: diskq maxfbas = %"
2195 					    NSC_SZFMT ", primary maxfbas = %"
2196 					    NSC_SZFMT, maxfbas, krdc->maxfbas);
2197 #endif
2198 				krdc->maxfbas = min(krdc->maxfbas, maxfbas);
2199 			} else {
2200 				cmn_err(CE_WARN,
2201 				    "!_rdc_enable: diskq maxfbas failed (%d)",
2202 				    rc);
2203 			}
2204 			_rdc_rlse_diskq(grp);
2205 		} else {
2206 			cmn_err(CE_WARN,
2207 			    "!_rdc_enable: diskq reserve failed (%d)", rc);
2208 		}
2209 	}
2210 
2211 	rdc_init_flags(urdc);
2212 	(void) strncpy(urdc->direct_file, rdc_set->direct_file, NSC_MAXPATH);
2213 	if ((options & RDC_OPT_PRIMARY) && rdc_set->direct_file[0]) {
2214 		if (rdc_open_direct(krdc) == NULL)
2215 			rdc_set_flags(urdc, RDC_FCAL_FAILED);
2216 	}
2217 
2218 	krdc->many_next = krdc;
2219 
2220 	ASSERT(krdc->type_flag == 0);
2221 	krdc->type_flag = RDC_CONFIGURED;
2222 
2223 	if (options & RDC_OPT_PRIMARY)
2224 		rdc_set_flags(urdc, RDC_PRIMARY);
2225 
2226 	if (options & RDC_OPT_ASYNC)
2227 		krdc->type_flag |= RDC_ASYNCMODE;
2228 
2229 	set_busy(krdc);
2230 	urdc->syshostid = rdc_set->syshostid;
2231 
2232 	if (add_to_many(krdc) < 0) {
2233 		mutex_exit(&rdc_conf_lock);
2234 
2235 		rdc_group_enter(krdc);
2236 
2237 		spcs_s_add(kstatus, RDC_EMULTI);
2238 		rc = RDC_EMULTI;
2239 		goto fail;
2240 	}
2241 
2242 	/* Configured but not enabled */
2243 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2244 
2245 	mutex_exit(&rdc_conf_lock);
2246 
2247 	rdc_group_enter(krdc);
2248 
2249 	/* Configured but not enabled */
2250 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2251 
2252 	/*
2253 	 * The rdc set is configured but not yet enabled. Other operations must
2254 	 * ignore this set until it is enabled.
2255 	 */
2256 
2257 	urdc->sync_pos = 0;
2258 
2259 	if (rdc_set->maxqfbas > 0)
2260 		urdc->maxqfbas = rdc_set->maxqfbas;
2261 	else
2262 		urdc->maxqfbas = rdc_maxthres_queue;
2263 
2264 	if (rdc_set->maxqitems > 0)
2265 		urdc->maxqitems = rdc_set->maxqitems;
2266 	else
2267 		urdc->maxqitems = rdc_max_qitems;
2268 
2269 	if (rdc_set->asyncthr > 0)
2270 		urdc->asyncthr = rdc_set->asyncthr;
2271 	else
2272 		urdc->asyncthr = rdc_asyncthr;
2273 
2274 	if (urdc->autosync == -1) {
2275 		/* Still unknown */
2276 		if (rdc_set->autosync > 0)
2277 			urdc->autosync = 1;
2278 		else
2279 			urdc->autosync = 0;
2280 	}
2281 
2282 	urdc->netconfig = rdc_set->netconfig;
2283 
2284 	if (options & RDC_OPT_PRIMARY) {
2285 		rhost = rdc_set->secondary.intf;
2286 		addrp = &rdc_set->secondary.addr;
2287 	} else {
2288 		rhost = rdc_set->primary.intf;
2289 		addrp = &rdc_set->primary.addr;
2290 	}
2291 
2292 	if (options & RDC_OPT_ASYNC)
2293 		rdc_set_flags(urdc, RDC_ASYNC);
2294 
2295 	svp = rdc_create_svinfo(rhost, addrp, urdc->netconfig);
2296 	if (svp == NULL) {
2297 		spcs_s_add(kstatus, ENOMEM);
2298 		rc = ENOMEM;
2299 		goto fail;
2300 	}
2301 	urdc->netconfig = NULL;		/* This will be no good soon */
2302 
2303 	rdc_kstat_create(index);
2304 
2305 	/* Don't set krdc->intf here */
2306 
2307 	if (rdc_enable_bitmap(krdc, options & RDC_OPT_SETBMP) < 0)
2308 		goto bmpfail;
2309 
2310 	RDC_ZERO_BITREF(krdc);
2311 	if (krdc->lsrv == NULL)
2312 		krdc->lsrv = svp;
2313 	else {
2314 #ifdef DEBUG
2315 		cmn_err(CE_WARN, "!_rdc_enable: krdc->lsrv already set: %p",
2316 		    (void *) krdc->lsrv);
2317 #endif
2318 		rdc_destroy_svinfo(svp);
2319 	}
2320 	svp = NULL;
2321 
2322 	/* Configured but not enabled */
2323 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2324 
2325 	/* And finally */
2326 
2327 	krdc->remote_index = -1;
2328 	/* Should we set the whole group logging? */
2329 	rdc_set_flags(urdc, RDC_ENABLED | RDC_LOGGING);
2330 
2331 	rdc_group_exit(krdc);
2332 
2333 	if (rdc_intercept(krdc) != 0) {
2334 		rdc_group_enter(krdc);
2335 		rdc_clr_flags(urdc, RDC_ENABLED);
2336 		if (options & RDC_OPT_PRIMARY)
2337 			spcs_s_add(kstatus, RDC_EREGISTER, urdc->primary.file);
2338 		else
2339 			spcs_s_add(kstatus, RDC_EREGISTER,
2340 			    urdc->secondary.file);
2341 #ifdef DEBUG
2342 		cmn_err(CE_NOTE, "!nsc_register_path failed %s",
2343 		    urdc->primary.file);
2344 #endif
2345 		rc = RDC_EREGISTER;
2346 		goto bmpfail;
2347 	}
2348 #ifdef DEBUG
2349 	cmn_err(CE_NOTE, "!SNDR: enabled %s %s", urdc->primary.file,
2350 	    urdc->secondary.file);
2351 #endif
2352 
2353 	rdc_write_state(urdc);
2354 
2355 	mutex_enter(&rdc_conf_lock);
2356 	wakeup_busy(krdc);
2357 	mutex_exit(&rdc_conf_lock);
2358 
2359 	return (0);
2360 
2361 bmpfail:
2362 	if (options & RDC_OPT_PRIMARY)
2363 		spcs_s_add(kstatus, RDC_EBITMAP, rdc_set->primary.bitmap);
2364 	else
2365 		spcs_s_add(kstatus, RDC_EBITMAP, rdc_set->secondary.bitmap);
2366 	rc = RDC_EBITMAP;
2367 	if (rdc_get_vflags(urdc) & RDC_ENABLED) {
2368 		rdc_group_exit(krdc);
2369 		(void) rdc_unintercept(krdc);
2370 		rdc_group_enter(krdc);
2371 	}
2372 
2373 fail:
2374 	rdc_kstat_delete(index);
2375 	rdc_group_exit(krdc);
2376 	if (krdc->intf) {
2377 		rdc_if_t *ip = krdc->intf;
2378 		mutex_enter(&rdc_conf_lock);
2379 		krdc->intf = NULL;
2380 		rdc_remove_from_if(ip);
2381 		mutex_exit(&rdc_conf_lock);
2382 	}
2383 	rdc_group_enter(krdc);
2384 	/* Configured but not enabled */
2385 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2386 
2387 	rdc_dev_close(krdc);
2388 	rdc_close_direct(krdc);
2389 	rdc_destroy_svinfo(svp);
2390 
2391 	/* Configured but not enabled */
2392 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2393 
2394 	rdc_group_exit(krdc);
2395 
2396 	mutex_enter(&rdc_conf_lock);
2397 
2398 	/* Configured but not enabled */
2399 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2400 
2401 	remove_from_group(krdc);
2402 
2403 	if (IS_MANY(krdc) || IS_MULTI(krdc))
2404 		remove_from_many(krdc);
2405 
2406 	rdc_u_init(urdc);
2407 
2408 	ASSERT(krdc->type_flag & RDC_CONFIGURED);
2409 	krdc->type_flag = 0;
2410 	wakeup_busy(krdc);
2411 
2412 	mutex_exit(&rdc_conf_lock);
2413 
2414 	return (rc);
2415 }
2416 
2417 static int
rdc_enable(rdc_config_t * uparms,spcs_s_info_t kstatus)2418 rdc_enable(rdc_config_t *uparms, spcs_s_info_t kstatus)
2419 {
2420 	int rc;
2421 	char itmp[10];
2422 
2423 	if (!(uparms->options & RDC_OPT_SYNC) &&
2424 	    !(uparms->options & RDC_OPT_ASYNC)) {
2425 		rc = RDC_EEINVAL;
2426 		(void) spcs_s_inttostring(
2427 		    uparms->options, itmp, sizeof (itmp), 1);
2428 		spcs_s_add(kstatus, RDC_EEINVAL, itmp);
2429 		goto done;
2430 	}
2431 
2432 	if (!(uparms->options & RDC_OPT_PRIMARY) &&
2433 	    !(uparms->options & RDC_OPT_SECONDARY)) {
2434 		rc = RDC_EEINVAL;
2435 		(void) spcs_s_inttostring(
2436 		    uparms->options, itmp, sizeof (itmp), 1);
2437 		spcs_s_add(kstatus, RDC_EEINVAL, itmp);
2438 		goto done;
2439 	}
2440 
2441 	if (!(uparms->options & RDC_OPT_SETBMP) &&
2442 	    !(uparms->options & RDC_OPT_CLRBMP)) {
2443 		rc = RDC_EEINVAL;
2444 		(void) spcs_s_inttostring(
2445 		    uparms->options, itmp, sizeof (itmp), 1);
2446 		spcs_s_add(kstatus, RDC_EEINVAL, itmp);
2447 		goto done;
2448 	}
2449 
2450 	rc = _rdc_enable(uparms->rdc_set, uparms->options, kstatus);
2451 done:
2452 	return (rc);
2453 }
2454 
2455 /* ARGSUSED */
2456 static int
_rdc_disable(rdc_k_info_t * krdc,rdc_config_t * uap,spcs_s_info_t kstatus)2457 _rdc_disable(rdc_k_info_t *krdc, rdc_config_t *uap, spcs_s_info_t kstatus)
2458 {
2459 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
2460 	rdc_if_t *ip;
2461 	int index = krdc->index;
2462 	disk_queue *q;
2463 	rdc_set_t *rdc_set = uap->rdc_set;
2464 
2465 	ASSERT(krdc->group != NULL);
2466 	rdc_group_enter(krdc);
2467 #ifdef DEBUG
2468 	ASSERT(rdc_check(krdc, rdc_set) == 0);
2469 #else
2470 	if (((uap->options & RDC_OPT_FORCE_DISABLE) == 0) &&
2471 	    rdc_check(krdc, rdc_set)) {
2472 		rdc_group_exit(krdc);
2473 		spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
2474 		    rdc_set->secondary.file);
2475 		return (RDC_EALREADY);
2476 	}
2477 #endif
2478 
2479 	if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
2480 		halt_sync(krdc);
2481 		ASSERT(IS_ENABLED(urdc));
2482 	}
2483 	q = &krdc->group->diskq;
2484 
2485 	if (IS_ASYNC(urdc) && RDC_IS_DISKQ(krdc->group) &&
2486 	    ((!IS_STATE(urdc, RDC_LOGGING)) && (!QEMPTY(q)))) {
2487 		krdc->type_flag &= ~RDC_DISABLEPEND;
2488 		rdc_group_exit(krdc);
2489 		spcs_s_add(kstatus, RDC_EQNOTEMPTY, urdc->disk_queue);
2490 		return (RDC_EQNOTEMPTY);
2491 	}
2492 	rdc_group_exit(krdc);
2493 	(void) rdc_unintercept(krdc);
2494 
2495 #ifdef DEBUG
2496 	cmn_err(CE_NOTE, "!SNDR: disabled %s %s", urdc->primary.file,
2497 	    urdc->secondary.file);
2498 #endif
2499 
2500 	/* Configured but not enabled */
2501 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2502 
2503 	/*
2504 	 * No new io can come in through the io provider.
2505 	 * Wait for the async flusher to finish.
2506 	 */
2507 
2508 	if (IS_ASYNC(urdc) && !RDC_IS_DISKQ(krdc->group)) {
2509 		int tries = 2; /* in case of hopelessly stuck flusher threads */
2510 #ifdef DEBUG
2511 		net_queue *qp = &krdc->group->ra_queue;
2512 #endif
2513 		do {
2514 			if (!krdc->group->rdc_writer)
2515 				(void) rdc_writer(krdc->index);
2516 
2517 			(void) rdc_drain_queue(krdc->index);
2518 
2519 		} while (krdc->group->rdc_writer && tries--);
2520 
2521 		/* ok, force it to happen... */
2522 		if (rdc_drain_queue(krdc->index) != 0) {
2523 			do {
2524 				mutex_enter(&krdc->group->ra_queue.net_qlock);
2525 				krdc->group->asyncdis = 1;
2526 				cv_broadcast(&krdc->group->asyncqcv);
2527 				mutex_exit(&krdc->group->ra_queue.net_qlock);
2528 				cmn_err(CE_WARN,
2529 				    "!SNDR: async I/O pending and not flushed "
2530 				    "for %s during disable",
2531 				    urdc->primary.file);
2532 #ifdef DEBUG
2533 				cmn_err(CE_WARN,
2534 				    "!nitems: %" NSC_SZFMT " nblocks: %"
2535 				    NSC_SZFMT " head: 0x%p tail: 0x%p",
2536 				    qp->nitems, qp->blocks,
2537 				    (void *)qp->net_qhead,
2538 				    (void *)qp->net_qtail);
2539 #endif
2540 			} while (krdc->group->rdc_thrnum > 0);
2541 		}
2542 	}
2543 
2544 	mutex_enter(&rdc_conf_lock);
2545 	ip = krdc->intf;
2546 	krdc->intf = 0;
2547 
2548 	if (ip) {
2549 		rdc_remove_from_if(ip);
2550 	}
2551 
2552 	mutex_exit(&rdc_conf_lock);
2553 
2554 	rdc_group_enter(krdc);
2555 
2556 	/* Configured but not enabled */
2557 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2558 
2559 	/* Must not hold group lock during this function */
2560 	rdc_group_exit(krdc);
2561 	while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
2562 		delay(2);
2563 	rdc_group_enter(krdc);
2564 
2565 	(void) rdc_clear_state(krdc);
2566 
2567 	rdc_free_bitmap(krdc, RDC_CMD_DISABLE);
2568 	rdc_close_bitmap(krdc);
2569 
2570 	rdc_dev_close(krdc);
2571 	rdc_close_direct(krdc);
2572 
2573 	/* Configured but not enabled */
2574 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2575 
2576 	rdc_group_exit(krdc);
2577 
2578 	/*
2579 	 * we should now unregister the queue, with no conflicting
2580 	 * locks held. This is the last(only) member of the group
2581 	 */
2582 	if (krdc->group && RDC_IS_DISKQ(krdc->group) &&
2583 	    krdc->group->count == 1) { /* stop protecting queue */
2584 		rdc_unintercept_diskq(krdc->group);
2585 	}
2586 
2587 	mutex_enter(&rdc_conf_lock);
2588 
2589 	/* Configured but not enabled */
2590 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2591 
2592 	wait_busy(krdc);
2593 
2594 	if (IS_MANY(krdc) || IS_MULTI(krdc))
2595 		remove_from_many(krdc);
2596 
2597 	remove_from_group(krdc);
2598 
2599 	krdc->remote_index = -1;
2600 	ASSERT(krdc->type_flag & RDC_CONFIGURED);
2601 	ASSERT(krdc->type_flag & RDC_DISABLEPEND);
2602 	krdc->type_flag = 0;
2603 #ifdef	DEBUG
2604 	if (krdc->dcio_bitmap)
2605 		cmn_err(CE_WARN, "!_rdc_disable: possible mem leak, "
2606 		    "dcio_bitmap");
2607 #endif
2608 	krdc->dcio_bitmap = NULL;
2609 	krdc->bitmap_ref = NULL;
2610 	krdc->bitmap_size = 0;
2611 	krdc->maxfbas = 0;
2612 	krdc->bitmap_write = 0;
2613 	krdc->disk_status = 0;
2614 	rdc_destroy_svinfo(krdc->lsrv);
2615 	krdc->lsrv = NULL;
2616 	krdc->multi_next = NULL;
2617 
2618 	rdc_u_init(urdc);
2619 
2620 	mutex_exit(&rdc_conf_lock);
2621 	rdc_kstat_delete(index);
2622 
2623 	return (0);
2624 }
2625 
2626 static int
rdc_disable(rdc_config_t * uparms,spcs_s_info_t kstatus)2627 rdc_disable(rdc_config_t *uparms, spcs_s_info_t kstatus)
2628 {
2629 	rdc_k_info_t *krdc;
2630 	int index;
2631 	int rc;
2632 
2633 	mutex_enter(&rdc_conf_lock);
2634 
2635 	index = rdc_lookup_byname(uparms->rdc_set);
2636 	if (index >= 0)
2637 		krdc = &rdc_k_info[index];
2638 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
2639 		mutex_exit(&rdc_conf_lock);
2640 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
2641 		    uparms->rdc_set->secondary.file);
2642 		return (RDC_EALREADY);
2643 	}
2644 
2645 	krdc->type_flag |= RDC_DISABLEPEND;
2646 	wait_busy(krdc);
2647 	if (krdc->type_flag == 0) {
2648 		/* A resume or enable failed */
2649 		mutex_exit(&rdc_conf_lock);
2650 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
2651 		    uparms->rdc_set->secondary.file);
2652 		return (RDC_EALREADY);
2653 	}
2654 	mutex_exit(&rdc_conf_lock);
2655 
2656 	rc = _rdc_disable(krdc, uparms, kstatus);
2657 	return (rc);
2658 }
2659 
2660 
2661 /*
2662  * Checks whether the state of one of the other sets in the 1-many or
2663  * multi-hop config should prevent a sync from starting on this one.
2664  * Return NULL if no just cause or impediment is found, otherwise return
2665  * a pointer to the offending set.
2666  */
2667 static rdc_u_info_t *
rdc_allow_pri_sync(rdc_u_info_t * urdc,int options)2668 rdc_allow_pri_sync(rdc_u_info_t *urdc, int options)
2669 {
2670 	rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
2671 	rdc_k_info_t *ktmp;
2672 	rdc_u_info_t *utmp;
2673 	rdc_k_info_t *kmulti = NULL;
2674 
2675 	ASSERT(rdc_get_vflags(urdc) & RDC_PRIMARY);
2676 
2677 	rdc_many_enter(krdc);
2678 
2679 	/*
2680 	 * In the reverse sync case we need to check the previous leg of
2681 	 * the multi-hop config. The link to that set can be from any of
2682 	 * the 1-many list, so as we go through we keep an eye open for it.
2683 	 */
2684 	if ((options & RDC_OPT_REVERSE) && (IS_MULTI(krdc))) {
2685 		/* This set links to the first leg */
2686 		ktmp = krdc->multi_next;
2687 		utmp = &rdc_u_info[ktmp->index];
2688 		if (IS_ENABLED(utmp))
2689 			kmulti = ktmp;
2690 	}
2691 
2692 	if (IS_MANY(krdc)) {
2693 		for (ktmp = krdc->many_next; ktmp != krdc;
2694 		    ktmp = ktmp->many_next) {
2695 			utmp = &rdc_u_info[ktmp->index];
2696 
2697 			if (!IS_ENABLED(utmp))
2698 				continue;
2699 
2700 			if (options & RDC_OPT_FORWARD) {
2701 				/*
2702 				 * Reverse sync needed is bad, as it means a
2703 				 * reverse sync in progress or started and
2704 				 * didn't complete, so this primary volume
2705 				 * is not consistent. So we shouldn't copy
2706 				 * it to its secondary.
2707 				 */
2708 				if (rdc_get_mflags(utmp) & RDC_RSYNC_NEEDED) {
2709 					rdc_many_exit(krdc);
2710 					return (utmp);
2711 				}
2712 			} else {
2713 				/* Reverse, so see if we need to spot kmulti */
2714 				if ((kmulti == NULL) && (IS_MULTI(ktmp))) {
2715 					/* This set links to the first leg */
2716 					kmulti = ktmp->multi_next;
2717 					if (!IS_ENABLED(
2718 					    &rdc_u_info[kmulti->index]))
2719 						kmulti = NULL;
2720 				}
2721 
2722 				/*
2723 				 * Non-logging is bad, as the bitmap will
2724 				 * be updated with the bits for this sync.
2725 				 */
2726 				if (!(rdc_get_vflags(utmp) & RDC_LOGGING)) {
2727 					rdc_many_exit(krdc);
2728 					return (utmp);
2729 				}
2730 			}
2731 		}
2732 	}
2733 
2734 	if (kmulti) {
2735 		utmp = &rdc_u_info[kmulti->index];
2736 		ktmp = kmulti;	/* In case we decide we do need to use ktmp */
2737 
2738 		ASSERT(options & RDC_OPT_REVERSE);
2739 
2740 		if (IS_REPLICATING(utmp)) {
2741 			/*
2742 			 * Replicating is bad as data is already flowing to
2743 			 * the target of the requested sync operation.
2744 			 */
2745 			rdc_many_exit(krdc);
2746 			return (utmp);
2747 		}
2748 
2749 		if (rdc_get_vflags(utmp) & RDC_SYNCING) {
2750 			/*
2751 			 * Forward sync in progress is bad, as data is
2752 			 * already flowing to the target of the requested
2753 			 * sync operation.
2754 			 * Reverse sync in progress is bad, as the primary
2755 			 * has already decided which data to copy.
2756 			 */
2757 			rdc_many_exit(krdc);
2758 			return (utmp);
2759 		}
2760 
2761 		/*
2762 		 * Clear the "sync needed" flags, as the multi-hop secondary
2763 		 * will be updated via this requested sync operation, so does
2764 		 * not need to complete its aborted forward sync.
2765 		 */
2766 		if (rdc_get_vflags(utmp) & RDC_SYNC_NEEDED)
2767 			rdc_clr_flags(utmp, RDC_SYNC_NEEDED);
2768 	}
2769 
2770 	if (IS_MANY(krdc) && (options & RDC_OPT_REVERSE)) {
2771 		for (ktmp = krdc->many_next; ktmp != krdc;
2772 		    ktmp = ktmp->many_next) {
2773 			utmp = &rdc_u_info[ktmp->index];
2774 			if (!IS_ENABLED(utmp))
2775 				continue;
2776 
2777 			/*
2778 			 * Clear any "reverse sync needed" flags, as the
2779 			 * volume will be updated via this requested
2780 			 * sync operation, so does not need to complete
2781 			 * its aborted reverse sync.
2782 			 */
2783 			if (rdc_get_mflags(utmp) & RDC_RSYNC_NEEDED)
2784 				rdc_clr_mflags(utmp, RDC_RSYNC_NEEDED);
2785 		}
2786 	}
2787 
2788 	rdc_many_exit(krdc);
2789 
2790 	return (NULL);
2791 }
2792 
2793 static void
_rdc_sync_wrthr(void * thrinfo)2794 _rdc_sync_wrthr(void *thrinfo)
2795 {
2796 	rdc_syncthr_t *syncinfo = (rdc_syncthr_t *)thrinfo;
2797 	nsc_buf_t *handle = NULL;
2798 	rdc_k_info_t *krdc = syncinfo->krdc;
2799 	int rc;
2800 	int tries = 0;
2801 
2802 	DTRACE_PROBE2(rdc_sync_loop_netwrite_start, int, krdc->index,
2803 	    nsc_buf_t *, handle);
2804 
2805 retry:
2806 	rc = nsc_alloc_buf(RDC_U_FD(krdc), syncinfo->offset, syncinfo->len,
2807 	    NSC_READ | NSC_NOCACHE, &handle);
2808 
2809 	if (!RDC_SUCCESS(rc) || krdc->remote_index < 0) {
2810 		DTRACE_PROBE(rdc_sync_wrthr_alloc_buf_err);
2811 		goto failed;
2812 	}
2813 
2814 	rdc_group_enter(krdc);
2815 	if ((krdc->disk_status == 1) || (krdc->dcio_bitmap == NULL)) {
2816 		rdc_group_exit(krdc);
2817 		goto failed;
2818 	}
2819 	rdc_group_exit(krdc);
2820 
2821 	if ((rc = rdc_net_write(krdc->index, krdc->remote_index, handle,
2822 	    handle->sb_pos, handle->sb_len, RDC_NOSEQ, RDC_NOQUE, NULL)) > 0) {
2823 		rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
2824 
2825 		/*
2826 		 * The following is to handle
2827 		 * the case where the secondary side
2828 		 * has thrown our buffer handle token away in a
2829 		 * attempt to preserve its health on restart
2830 		 */
2831 		if ((rc == EPROTO) && (tries < 3)) {
2832 			(void) nsc_free_buf(handle);
2833 			handle = NULL;
2834 			tries++;
2835 			delay(HZ >> 2);
2836 			goto retry;
2837 		}
2838 
2839 		DTRACE_PROBE(rdc_sync_wrthr_remote_write_err);
2840 		cmn_err(CE_WARN, "!rdc_sync_wrthr: remote write failed (%d) "
2841 		    "0x%x", rc, rdc_get_vflags(urdc));
2842 
2843 		goto failed;
2844 	}
2845 	(void) nsc_free_buf(handle);
2846 	handle = NULL;
2847 
2848 	return;
2849 failed:
2850 	(void) nsc_free_buf(handle);
2851 	syncinfo->status->offset = syncinfo->offset;
2852 }
2853 
2854 /*
2855  * see above comments on _rdc_sync_wrthr
2856  */
2857 static void
_rdc_sync_rdthr(void * thrinfo)2858 _rdc_sync_rdthr(void *thrinfo)
2859 {
2860 	rdc_syncthr_t *syncinfo = (rdc_syncthr_t *)thrinfo;
2861 	nsc_buf_t *handle = NULL;
2862 	rdc_k_info_t *krdc = syncinfo->krdc;
2863 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
2864 	int rc;
2865 
2866 	rc = nsc_alloc_buf(RDC_U_FD(krdc), syncinfo->offset, syncinfo->len,
2867 	    NSC_WRITE | NSC_WRTHRU | NSC_NOCACHE, &handle);
2868 
2869 	if (!RDC_SUCCESS(rc) || krdc->remote_index < 0) {
2870 		goto failed;
2871 	}
2872 	rdc_group_enter(krdc);
2873 	if ((krdc->disk_status == 1) || (krdc->dcio_bitmap == NULL)) {
2874 		rdc_group_exit(krdc);
2875 		goto failed;
2876 	}
2877 	rdc_group_exit(krdc);
2878 
2879 	rc = rdc_net_read(krdc->index, krdc->remote_index, handle,
2880 	    handle->sb_pos, handle->sb_len);
2881 
2882 	if (!RDC_SUCCESS(rc)) {
2883 		cmn_err(CE_WARN, "!rdc_sync_rdthr: remote read failed(%d)", rc);
2884 		goto failed;
2885 	}
2886 	if (!IS_STATE(urdc, RDC_FULL))
2887 		rdc_set_bitmap_many(krdc, handle->sb_pos, handle->sb_len);
2888 
2889 	rc = nsc_write(handle, handle->sb_pos, handle->sb_len, 0);
2890 
2891 	if (!RDC_SUCCESS(rc)) {
2892 		rdc_many_enter(krdc);
2893 		rdc_set_flags_log(urdc, RDC_VOL_FAILED, "nsc_write failed");
2894 		rdc_many_exit(krdc);
2895 		rdc_write_state(urdc);
2896 		goto failed;
2897 	}
2898 
2899 	(void) nsc_free_buf(handle);
2900 	handle = NULL;
2901 
2902 	return;
2903 failed:
2904 	(void) nsc_free_buf(handle);
2905 	syncinfo->status->offset = syncinfo->offset;
2906 }
2907 
2908 /*
2909  * _rdc_sync_wrthr
2910  * sync loop write thread
2911  * if there are avail threads, we have not
2912  * used up the pipe, so the sync loop will, if
2913  * possible use these to multithread the write/read
2914  */
2915 void
_rdc_sync_thread(void * thrinfo)2916 _rdc_sync_thread(void *thrinfo)
2917 {
2918 	rdc_syncthr_t *syncinfo = (rdc_syncthr_t *)thrinfo;
2919 	rdc_k_info_t *krdc = syncinfo->krdc;
2920 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
2921 	rdc_thrsync_t *sync = &krdc->syncs;
2922 	uint_t bitmask;
2923 	int rc;
2924 
2925 	rc = _rdc_rsrv_devs(krdc, RDC_RAW, RDC_INTERNAL);
2926 	if (!RDC_SUCCESS(rc))
2927 		goto failed;
2928 
2929 	if (IS_STATE(urdc, RDC_SLAVE))
2930 		_rdc_sync_rdthr(thrinfo);
2931 	else
2932 		_rdc_sync_wrthr(thrinfo);
2933 
2934 	_rdc_rlse_devs(krdc, RDC_RAW);
2935 
2936 	if (krdc->dcio_bitmap == NULL) {
2937 #ifdef DEBUG
2938 		cmn_err(CE_NOTE, "!_rdc_sync_wrthr: NULL bitmap");
2939 #else
2940 	/*EMPTY*/
2941 #endif
2942 	} else if (syncinfo->status->offset < 0) {
2943 
2944 		RDC_SET_BITMASK(syncinfo->offset, syncinfo->len, &bitmask);
2945 		RDC_CLR_BITMAP(krdc, syncinfo->offset, syncinfo->len, \
2946 		    bitmask, RDC_BIT_FORCE);
2947 	}
2948 
2949 failed:
2950 	/*
2951 	 * done with this, get rid of it.
2952 	 * the status is not freed, it should still be a status chain
2953 	 * that _rdc_sync() has the head of
2954 	 */
2955 	kmem_free(syncinfo, sizeof (*syncinfo));
2956 
2957 	/*
2958 	 * decrement the global sync thread num
2959 	 */
2960 	mutex_enter(&sync_info.lock);
2961 	sync_info.active_thr--;
2962 	/* LINTED */
2963 	RDC_AVAIL_THR_TUNE(sync_info);
2964 	mutex_exit(&sync_info.lock);
2965 
2966 	/*
2967 	 * krdc specific stuff
2968 	 */
2969 	mutex_enter(&sync->lock);
2970 	sync->complete++;
2971 	cv_broadcast(&sync->cv);
2972 	mutex_exit(&sync->lock);
2973 }
2974 
2975 int
_rdc_setup_syncthr(rdc_syncthr_t ** synthr,nsc_off_t offset,nsc_size_t len,rdc_k_info_t * krdc,sync_status_t * stats)2976 _rdc_setup_syncthr(rdc_syncthr_t **synthr, nsc_off_t offset,
2977     nsc_size_t len, rdc_k_info_t *krdc, sync_status_t *stats)
2978 {
2979 	rdc_syncthr_t *tmp;
2980 	/* alloc here, free in the sync thread */
2981 	tmp =
2982 	    (rdc_syncthr_t *)kmem_zalloc(sizeof (rdc_syncthr_t), KM_NOSLEEP);
2983 
2984 	if (tmp == NULL)
2985 		return (-1);
2986 	tmp->offset = offset;
2987 	tmp->len = len;
2988 	tmp->status = stats;
2989 	tmp->krdc = krdc;
2990 
2991 	*synthr = tmp;
2992 	return (0);
2993 }
2994 
2995 sync_status_t *
_rdc_new_sync_status()2996 _rdc_new_sync_status()
2997 {
2998 	sync_status_t *s;
2999 
3000 	s = (sync_status_t *)kmem_zalloc(sizeof (*s), KM_NOSLEEP);
3001 	s->offset = -1;
3002 	return (s);
3003 }
3004 
3005 void
_rdc_free_sync_status(sync_status_t * status)3006 _rdc_free_sync_status(sync_status_t *status)
3007 {
3008 	sync_status_t *s;
3009 
3010 	while (status) {
3011 		s = status->next;
3012 		kmem_free(status, sizeof (*status));
3013 		status = s;
3014 	}
3015 }
3016 int
_rdc_sync_status_ok(sync_status_t * status,int * offset)3017 _rdc_sync_status_ok(sync_status_t *status, int *offset)
3018 {
3019 #ifdef DEBUG_SYNCSTATUS
3020 	int i = 0;
3021 #endif
3022 	while (status) {
3023 		if (status->offset >= 0) {
3024 			*offset = status->offset;
3025 			return (-1);
3026 		}
3027 		status = status->next;
3028 #ifdef DEBUG_SYNCSTATUS
3029 		i++;
3030 #endif
3031 	}
3032 #ifdef DEBUGSYNCSTATUS
3033 	cmn_err(CE_NOTE, "!rdc_sync_status_ok: checked %d statuses", i);
3034 #endif
3035 	return (0);
3036 }
3037 
3038 int mtsync = 1;
3039 /*
3040  * _rdc_sync() : rdc sync loop
3041  *
3042  */
3043 static void
_rdc_sync(rdc_k_info_t * krdc)3044 _rdc_sync(rdc_k_info_t *krdc)
3045 {
3046 	nsc_size_t size = 0;
3047 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
3048 	int rtype;
3049 	int sts;
3050 	int reserved = 0;
3051 	nsc_buf_t *alloc_h = NULL;
3052 	nsc_buf_t *handle = NULL;
3053 	nsc_off_t mask;
3054 	nsc_size_t maxbit;
3055 	nsc_size_t len;
3056 	nsc_off_t offset = 0;
3057 	int sync_completed = 0;
3058 	int tries = 0;
3059 	int rc;
3060 	int queuing = 0;
3061 	uint_t bitmask;
3062 	sync_status_t *ss, *sync_status = NULL;
3063 	rdc_thrsync_t *sync = &krdc->syncs;
3064 	rdc_syncthr_t *syncinfo;
3065 	nsthread_t *trc = NULL;
3066 
3067 	if (IS_STATE(urdc, RDC_QUEUING) && !IS_STATE(urdc, RDC_FULL)) {
3068 		/* flusher is handling the sync in the update case */
3069 		queuing = 1;
3070 		goto sync_done;
3071 	}
3072 
3073 	/*
3074 	 * Main sync/resync loop
3075 	 */
3076 	DTRACE_PROBE(rdc_sync_loop_start);
3077 
3078 	rtype = RDC_RAW;
3079 	sts = _rdc_rsrv_devs(krdc, rtype, RDC_INTERNAL);
3080 
3081 	DTRACE_PROBE(rdc_sync_loop_rsrv);
3082 
3083 	if (sts != 0)
3084 		goto failed_noincr;
3085 
3086 	reserved = 1;
3087 
3088 	/*
3089 	 * pre-allocate a handle if we can - speeds up the sync.
3090 	 */
3091 
3092 	if (rdc_prealloc_handle) {
3093 		alloc_h = nsc_alloc_handle(RDC_U_FD(krdc), NULL, NULL, NULL);
3094 #ifdef DEBUG
3095 		if (!alloc_h) {
3096 			cmn_err(CE_WARN,
3097 			    "!rdc sync: failed to pre-alloc handle");
3098 		}
3099 #endif
3100 	} else {
3101 		alloc_h = NULL;
3102 	}
3103 
3104 	ASSERT(urdc->volume_size != 0);
3105 	size = urdc->volume_size;
3106 	mask = ~(LOG_TO_FBA_NUM(1) - 1);
3107 	maxbit = FBA_TO_LOG_NUM(size - 1);
3108 
3109 	/*
3110 	 * as this while loop can also move data, it is counted as a
3111 	 * sync loop thread
3112 	 */
3113 	rdc_group_enter(krdc);
3114 	rdc_clr_flags(urdc, RDC_LOGGING);
3115 	rdc_set_flags(urdc, RDC_SYNCING);
3116 	krdc->group->synccount++;
3117 	rdc_group_exit(krdc);
3118 	mutex_enter(&sync_info.lock);
3119 	sync_info.active_thr++;
3120 	/* LINTED */
3121 	RDC_AVAIL_THR_TUNE(sync_info);
3122 	mutex_exit(&sync_info.lock);
3123 
3124 	while (offset < size) {
3125 		rdc_group_enter(krdc);
3126 		ASSERT(krdc->aux_state & RDC_AUXSYNCIP);
3127 		if (krdc->disk_status == 1 || krdc->dcio_bitmap == NULL) {
3128 			rdc_group_exit(krdc);
3129 			if (krdc->disk_status == 1) {
3130 				DTRACE_PROBE(rdc_sync_loop_disk_status_err);
3131 			} else {
3132 				DTRACE_PROBE(rdc_sync_loop_dcio_bitmap_err);
3133 			}
3134 			goto failed;		/* halt sync */
3135 		}
3136 		rdc_group_exit(krdc);
3137 
3138 		if (!(rdc_get_vflags(urdc) & RDC_FULL)) {
3139 			mutex_enter(&krdc->syncbitmutex);
3140 			krdc->syncbitpos = FBA_TO_LOG_NUM(offset);
3141 			len = 0;
3142 
3143 			/* skip unnecessary chunks */
3144 
3145 			while (krdc->syncbitpos <= maxbit &&
3146 			    !RDC_BIT_ISSET(krdc, krdc->syncbitpos)) {
3147 				offset += LOG_TO_FBA_NUM(1);
3148 				krdc->syncbitpos++;
3149 			}
3150 
3151 			/* check for boundary */
3152 
3153 			if (offset >= size) {
3154 				mutex_exit(&krdc->syncbitmutex);
3155 				goto sync_done;
3156 			}
3157 
3158 			/* find maximal length we can transfer */
3159 
3160 			while (krdc->syncbitpos <= maxbit &&
3161 			    RDC_BIT_ISSET(krdc, krdc->syncbitpos)) {
3162 				len += LOG_TO_FBA_NUM(1);
3163 				krdc->syncbitpos++;
3164 				/* we can only read maxfbas anyways */
3165 				if (len >= krdc->maxfbas)
3166 					break;
3167 			}
3168 
3169 			len = min(len, (size - offset));
3170 
3171 		} else {
3172 			len = size - offset;
3173 		}
3174 
3175 		/* truncate to the io provider limit */
3176 		ASSERT(krdc->maxfbas != 0);
3177 		len = min(len, krdc->maxfbas);
3178 
3179 		if (len > LOG_TO_FBA_NUM(1)) {
3180 			/*
3181 			 * If the update is larger than a bitmap chunk,
3182 			 * then truncate to a whole number of bitmap
3183 			 * chunks.
3184 			 *
3185 			 * If the update is smaller than a bitmap
3186 			 * chunk, this must be the last write.
3187 			 */
3188 			len &= mask;
3189 		}
3190 
3191 		if (!(rdc_get_vflags(urdc) & RDC_FULL)) {
3192 			krdc->syncbitpos = FBA_TO_LOG_NUM(offset + len);
3193 			mutex_exit(&krdc->syncbitmutex);
3194 		}
3195 
3196 		/*
3197 		 * Find out if we can reserve a thread here ...
3198 		 * note: skip the mutex for the first check, if the number
3199 		 * is up there, why bother even grabbing the mutex to
3200 		 * only realize that we can't have a thread anyways
3201 		 */
3202 
3203 		if (mtsync && sync_info.active_thr < RDC_MAX_SYNC_THREADS) {
3204 
3205 			mutex_enter(&sync_info.lock);
3206 			if (sync_info.avail_thr >= 1) {
3207 				if (sync_status == NULL) {
3208 					ss = sync_status =
3209 					    _rdc_new_sync_status();
3210 				} else {
3211 					ss = ss->next = _rdc_new_sync_status();
3212 				}
3213 				if (ss == NULL) {
3214 					mutex_exit(&sync_info.lock);
3215 #ifdef DEBUG
3216 					cmn_err(CE_WARN, "!rdc_sync: can't "
3217 					    "allocate status for mt sync");
3218 #endif
3219 					goto retry;
3220 				}
3221 				/*
3222 				 * syncinfo protected by sync_info lock but
3223 				 * not part of the sync_info structure
3224 				 * be careful if moving
3225 				 */
3226 				if (_rdc_setup_syncthr(&syncinfo,
3227 				    offset, len, krdc, ss) < 0) {
3228 					_rdc_free_sync_status(ss);
3229 				}
3230 
3231 				trc = nst_create(sync_info.rdc_syncset,
3232 				    _rdc_sync_thread, syncinfo, NST_SLEEP);
3233 
3234 				if (trc == NULL) {
3235 					mutex_exit(&sync_info.lock);
3236 #ifdef DEBUG
3237 					cmn_err(CE_NOTE, "!rdc_sync: unable to "
3238 					    "mt sync");
3239 #endif
3240 					_rdc_free_sync_status(ss);
3241 					kmem_free(syncinfo, sizeof (*syncinfo));
3242 					syncinfo = NULL;
3243 					goto retry;
3244 				} else {
3245 					mutex_enter(&sync->lock);
3246 					sync->threads++;
3247 					mutex_exit(&sync->lock);
3248 				}
3249 
3250 				sync_info.active_thr++;
3251 				/* LINTED */
3252 				RDC_AVAIL_THR_TUNE(sync_info);
3253 
3254 				mutex_exit(&sync_info.lock);
3255 				goto threaded;
3256 			}
3257 			mutex_exit(&sync_info.lock);
3258 		}
3259 retry:
3260 		handle = alloc_h;
3261 		DTRACE_PROBE(rdc_sync_loop_allocbuf_start);
3262 		if (rdc_get_vflags(urdc) & RDC_SLAVE)
3263 			sts = nsc_alloc_buf(RDC_U_FD(krdc), offset, len,
3264 			    NSC_WRITE | NSC_WRTHRU | NSC_NOCACHE, &handle);
3265 		else
3266 			sts = nsc_alloc_buf(RDC_U_FD(krdc), offset, len,
3267 			    NSC_READ | NSC_NOCACHE, &handle);
3268 
3269 		DTRACE_PROBE(rdc_sync_loop_allocbuf_end);
3270 		if (sts > 0) {
3271 			if (handle && handle != alloc_h) {
3272 				(void) nsc_free_buf(handle);
3273 			}
3274 
3275 			handle = NULL;
3276 			DTRACE_PROBE(rdc_sync_loop_allocbuf_err);
3277 			goto failed;
3278 		}
3279 
3280 		if (rdc_get_vflags(urdc) & RDC_SLAVE) {
3281 			/* overwrite buffer with remote data */
3282 			sts = rdc_net_read(krdc->index, krdc->remote_index,
3283 			    handle, handle->sb_pos, handle->sb_len);
3284 
3285 			if (!RDC_SUCCESS(sts)) {
3286 #ifdef DEBUG
3287 				cmn_err(CE_WARN,
3288 				    "!rdc sync: remote read failed (%d)", sts);
3289 #endif
3290 				DTRACE_PROBE(rdc_sync_loop_remote_read_err);
3291 				goto failed;
3292 			}
3293 			if (!(rdc_get_vflags(urdc) & RDC_FULL))
3294 				rdc_set_bitmap_many(krdc, handle->sb_pos,
3295 				    handle->sb_len);
3296 
3297 			/* commit locally */
3298 
3299 			sts = nsc_write(handle, handle->sb_pos,
3300 			    handle->sb_len, 0);
3301 
3302 			if (!RDC_SUCCESS(sts)) {
3303 				/* reverse sync needed already set */
3304 				rdc_many_enter(krdc);
3305 				rdc_set_flags_log(urdc, RDC_VOL_FAILED,
3306 				    "write failed during sync");
3307 				rdc_many_exit(krdc);
3308 				rdc_write_state(urdc);
3309 				DTRACE_PROBE(rdc_sync_loop_nsc_write_err);
3310 				goto failed;
3311 			}
3312 		} else {
3313 			/* send local data to remote */
3314 			DTRACE_PROBE2(rdc_sync_loop_netwrite_start,
3315 			    int, krdc->index, nsc_buf_t *, handle);
3316 
3317 			if ((sts = rdc_net_write(krdc->index,
3318 			    krdc->remote_index, handle, handle->sb_pos,
3319 			    handle->sb_len, RDC_NOSEQ, RDC_NOQUE, NULL)) > 0) {
3320 
3321 				/*
3322 				 * The following is to handle
3323 				 * the case where the secondary side
3324 				 * has thrown our buffer handle token away in a
3325 				 * attempt to preserve its health on restart
3326 				 */
3327 				if ((sts == EPROTO) && (tries < 3)) {
3328 					(void) nsc_free_buf(handle);
3329 					handle = NULL;
3330 					tries++;
3331 					delay(HZ >> 2);
3332 					goto retry;
3333 				}
3334 #ifdef DEBUG
3335 				cmn_err(CE_WARN,
3336 				    "!rdc sync: remote write failed (%d) 0x%x",
3337 				    sts, rdc_get_vflags(urdc));
3338 #endif
3339 				DTRACE_PROBE(rdc_sync_loop_netwrite_err);
3340 				goto failed;
3341 			}
3342 			DTRACE_PROBE(rdc_sync_loop_netwrite_end);
3343 		}
3344 
3345 		(void) nsc_free_buf(handle);
3346 		handle = NULL;
3347 
3348 		if (krdc->dcio_bitmap == NULL) {
3349 #ifdef DEBUG
3350 			cmn_err(CE_NOTE, "!_rdc_sync: NULL bitmap");
3351 #else
3352 		;
3353 		/*EMPTY*/
3354 #endif
3355 		} else {
3356 
3357 			RDC_SET_BITMASK(offset, len, &bitmask);
3358 			RDC_CLR_BITMAP(krdc, offset, len, bitmask, \
3359 			    RDC_BIT_FORCE);
3360 			ASSERT(!IS_ASYNC(urdc));
3361 		}
3362 
3363 		/*
3364 		 * Only release/reserve if someone is waiting
3365 		 */
3366 		if (krdc->devices->id_release || nsc_waiting(RDC_U_FD(krdc))) {
3367 			DTRACE_PROBE(rdc_sync_loop_rlse_start);
3368 			if (alloc_h) {
3369 				(void) nsc_free_handle(alloc_h);
3370 				alloc_h = NULL;
3371 			}
3372 
3373 			_rdc_rlse_devs(krdc, rtype);
3374 			reserved = 0;
3375 			delay(2);
3376 
3377 			rtype = RDC_RAW;
3378 			sts = _rdc_rsrv_devs(krdc, rtype, RDC_INTERNAL);
3379 			if (sts != 0) {
3380 				handle = NULL;
3381 				DTRACE_PROBE(rdc_sync_loop_rdc_rsrv_err);
3382 				goto failed;
3383 			}
3384 
3385 			reserved = 1;
3386 
3387 			if (rdc_prealloc_handle) {
3388 				alloc_h = nsc_alloc_handle(RDC_U_FD(krdc),
3389 				    NULL, NULL, NULL);
3390 #ifdef DEBUG
3391 				if (!alloc_h) {
3392 					cmn_err(CE_WARN, "!rdc_sync: "
3393 					    "failed to pre-alloc handle");
3394 				}
3395 #endif
3396 			}
3397 			DTRACE_PROBE(rdc_sync_loop_rlse_end);
3398 		}
3399 threaded:
3400 		offset += len;
3401 		urdc->sync_pos = offset;
3402 	}
3403 
3404 sync_done:
3405 	sync_completed = 1;
3406 
3407 failed:
3408 	krdc->group->synccount--;
3409 failed_noincr:
3410 	mutex_enter(&sync->lock);
3411 	while (sync->complete != sync->threads) {
3412 		cv_wait(&sync->cv, &sync->lock);
3413 	}
3414 	sync->complete = 0;
3415 	sync->threads = 0;
3416 	mutex_exit(&sync->lock);
3417 
3418 	/*
3419 	 * if sync_completed is 0 here,
3420 	 * we know that the main sync thread failed anyway
3421 	 * so just free the statuses and fail
3422 	 */
3423 	if (sync_completed && (_rdc_sync_status_ok(sync_status, &rc) < 0)) {
3424 		urdc->sync_pos = rc;
3425 		sync_completed = 0; /* at least 1 thread failed */
3426 	}
3427 
3428 	_rdc_free_sync_status(sync_status);
3429 
3430 	/*
3431 	 * we didn't increment, we didn't even sync,
3432 	 * so don't dec sync_info.active_thr
3433 	 */
3434 	if (!queuing) {
3435 		mutex_enter(&sync_info.lock);
3436 		sync_info.active_thr--;
3437 		/* LINTED */
3438 		RDC_AVAIL_THR_TUNE(sync_info);
3439 		mutex_exit(&sync_info.lock);
3440 	}
3441 
3442 	if (handle) {
3443 		(void) nsc_free_buf(handle);
3444 	}
3445 
3446 	if (alloc_h) {
3447 		(void) nsc_free_handle(alloc_h);
3448 	}
3449 
3450 	if (reserved) {
3451 		_rdc_rlse_devs(krdc, rtype);
3452 	}
3453 
3454 notstarted:
3455 	rdc_group_enter(krdc);
3456 	ASSERT(krdc->aux_state & RDC_AUXSYNCIP);
3457 	if (IS_STATE(urdc, RDC_QUEUING))
3458 		rdc_clr_flags(urdc, RDC_QUEUING);
3459 
3460 	if (sync_completed) {
3461 		(void) rdc_net_state(krdc->index, CCIO_DONE);
3462 	} else {
3463 		(void) rdc_net_state(krdc->index, CCIO_ENABLELOG);
3464 	}
3465 
3466 	rdc_clr_flags(urdc, RDC_SYNCING);
3467 	if (rdc_get_vflags(urdc) & RDC_SLAVE) {
3468 		rdc_many_enter(krdc);
3469 		rdc_clr_mflags(urdc, RDC_SLAVE);
3470 		rdc_many_exit(krdc);
3471 	}
3472 	if (krdc->type_flag & RDC_ASYNCMODE)
3473 		rdc_set_flags(urdc, RDC_ASYNC);
3474 	if (sync_completed) {
3475 		rdc_many_enter(krdc);
3476 		rdc_clr_mflags(urdc, RDC_RSYNC_NEEDED);
3477 		rdc_many_exit(krdc);
3478 	} else {
3479 		krdc->remote_index = -1;
3480 		rdc_set_flags_log(urdc, RDC_LOGGING, "sync failed to complete");
3481 	}
3482 	rdc_group_exit(krdc);
3483 	rdc_write_state(urdc);
3484 
3485 	mutex_enter(&net_blk_lock);
3486 	if (sync_completed)
3487 		krdc->sync_done = RDC_COMPLETED;
3488 	else
3489 		krdc->sync_done = RDC_FAILED;
3490 	cv_broadcast(&krdc->synccv);
3491 	mutex_exit(&net_blk_lock);
3492 
3493 }
3494 
3495 
3496 static int
rdc_sync(rdc_config_t * uparms,spcs_s_info_t kstatus)3497 rdc_sync(rdc_config_t *uparms, spcs_s_info_t kstatus)
3498 {
3499 	rdc_set_t *rdc_set = uparms->rdc_set;
3500 	int options = uparms->options;
3501 	int rc = 0;
3502 	int busy = 0;
3503 	int index;
3504 	rdc_k_info_t *krdc;
3505 	rdc_u_info_t *urdc;
3506 	rdc_k_info_t *kmulti;
3507 	rdc_u_info_t *umulti;
3508 	rdc_group_t *group;
3509 	rdc_srv_t *svp;
3510 	int sm, um, md;
3511 	int sync_completed = 0;
3512 	int thrcount;
3513 
3514 	mutex_enter(&rdc_conf_lock);
3515 	index = rdc_lookup_byname(rdc_set);
3516 	if (index >= 0)
3517 		krdc = &rdc_k_info[index];
3518 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
3519 		mutex_exit(&rdc_conf_lock);
3520 		spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
3521 		    rdc_set->secondary.file);
3522 		rc = RDC_EALREADY;
3523 		goto notstarted;
3524 	}
3525 
3526 	urdc = &rdc_u_info[index];
3527 	group = krdc->group;
3528 	set_busy(krdc);
3529 	busy = 1;
3530 	if ((krdc->type_flag == 0) || (krdc->type_flag & RDC_DISABLEPEND)) {
3531 		/* A resume or enable failed  or we raced with a teardown */
3532 		mutex_exit(&rdc_conf_lock);
3533 		spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
3534 		    rdc_set->secondary.file);
3535 		rc = RDC_EALREADY;
3536 		goto notstarted;
3537 	}
3538 	mutex_exit(&rdc_conf_lock);
3539 	rdc_group_enter(krdc);
3540 
3541 	if (!IS_STATE(urdc, RDC_LOGGING)) {
3542 		spcs_s_add(kstatus, RDC_ESETNOTLOGGING, urdc->secondary.intf,
3543 		    urdc->secondary.file);
3544 		rc = RDC_ENOTLOGGING;
3545 		goto notstarted_unlock;
3546 	}
3547 
3548 	if (rdc_check(krdc, rdc_set)) {
3549 		spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
3550 		    rdc_set->secondary.file);
3551 		rc = RDC_EALREADY;
3552 		goto notstarted_unlock;
3553 	}
3554 
3555 	if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) {
3556 		spcs_s_add(kstatus, RDC_ENOTPRIMARY, rdc_set->primary.intf,
3557 		    rdc_set->primary.file, rdc_set->secondary.intf,
3558 		    rdc_set->secondary.file);
3559 		rc = RDC_ENOTPRIMARY;
3560 		goto notstarted_unlock;
3561 	}
3562 
3563 	if ((options & RDC_OPT_REVERSE) && (IS_STATE(urdc, RDC_QUEUING))) {
3564 		/*
3565 		 * cannot reverse sync when queuing, need to go logging first
3566 		 */
3567 		spcs_s_add(kstatus, RDC_EQNORSYNC, rdc_set->primary.intf,
3568 		    rdc_set->primary.file, rdc_set->secondary.intf,
3569 		    rdc_set->secondary.file);
3570 		rc = RDC_EQNORSYNC;
3571 		goto notstarted_unlock;
3572 	}
3573 
3574 	svp = krdc->lsrv;
3575 	krdc->intf = rdc_add_to_if(svp, &(urdc->primary.addr),
3576 	    &(urdc->secondary.addr), 1);
3577 
3578 	if (!krdc->intf) {
3579 		spcs_s_add(kstatus, RDC_EADDTOIF, urdc->primary.intf,
3580 		    urdc->secondary.intf);
3581 		rc = RDC_EADDTOIF;
3582 		goto notstarted_unlock;
3583 	}
3584 
3585 	if (urdc->volume_size == 0) {
3586 		/* Implies reserve failed when previous resume was done */
3587 		rdc_get_details(krdc);
3588 	}
3589 	if (urdc->volume_size == 0) {
3590 		spcs_s_add(kstatus, RDC_ENOBMAP);
3591 		rc = RDC_ENOBMAP;
3592 		goto notstarted_unlock;
3593 	}
3594 
3595 	if (krdc->dcio_bitmap == NULL) {
3596 		if (rdc_resume_bitmap(krdc) < 0) {
3597 			spcs_s_add(kstatus, RDC_ENOBMAP);
3598 			rc = RDC_ENOBMAP;
3599 			goto notstarted_unlock;
3600 		}
3601 	}
3602 
3603 	if ((rdc_get_vflags(urdc) & RDC_BMP_FAILED) && (krdc->bitmapfd)) {
3604 		if (rdc_reset_bitmap(krdc)) {
3605 			spcs_s_add(kstatus, RDC_EBITMAP);
3606 			rc = RDC_EBITMAP;
3607 			goto notstarted_unlock;
3608 		}
3609 	}
3610 
3611 	if (IS_MANY(krdc) || IS_MULTI(krdc)) {
3612 		rdc_u_info_t *ubad;
3613 
3614 		if ((ubad = rdc_allow_pri_sync(urdc, options)) != NULL) {
3615 			spcs_s_add(kstatus, RDC_ESTATE,
3616 			    ubad->primary.intf, ubad->primary.file,
3617 			    ubad->secondary.intf, ubad->secondary.file);
3618 			rc = RDC_ESTATE;
3619 			goto notstarted_unlock;
3620 		}
3621 	}
3622 
3623 	/*
3624 	 * there is a small window where _rdc_sync is still
3625 	 * running, but has cleared the RDC_SYNCING flag.
3626 	 * Use aux_state which is only cleared
3627 	 * after _rdc_sync had done its 'death' broadcast.
3628 	 */
3629 	if (krdc->aux_state & RDC_AUXSYNCIP) {
3630 #ifdef DEBUG
3631 		if (!rdc_get_vflags(urdc) & RDC_SYNCING) {
3632 			cmn_err(CE_WARN, "!rdc_sync: "
3633 			    "RDC_AUXSYNCIP set, SYNCING off");
3634 		}
3635 #endif
3636 		spcs_s_add(kstatus, RDC_ESYNCING, rdc_set->primary.file);
3637 		rc = RDC_ESYNCING;
3638 		goto notstarted_unlock;
3639 	}
3640 	if (krdc->disk_status == 1) {
3641 		spcs_s_add(kstatus, RDC_ESYNCING, rdc_set->primary.file);
3642 		rc = RDC_ESYNCING;
3643 		goto notstarted_unlock;
3644 	}
3645 
3646 	if ((options & RDC_OPT_FORWARD) &&
3647 	    (rdc_get_mflags(urdc) & RDC_RSYNC_NEEDED)) {
3648 		/* cannot forward sync if a reverse sync is needed */
3649 		spcs_s_add(kstatus, RDC_ERSYNCNEEDED, rdc_set->primary.intf,
3650 		    rdc_set->primary.file, rdc_set->secondary.intf,
3651 		    rdc_set->secondary.file);
3652 		rc = RDC_ERSYNCNEEDED;
3653 		goto notstarted_unlock;
3654 	}
3655 
3656 	urdc->sync_pos = 0;
3657 
3658 	/* Check if the rdc set is accessible on the remote node */
3659 	if (rdc_net_getstate(krdc, &sm, &um, &md, FALSE) < 0) {
3660 		/*
3661 		 * Remote end may be inaccessible, or the rdc set is not
3662 		 * enabled at the remote end.
3663 		 */
3664 		spcs_s_add(kstatus, RDC_ECONNOPEN, urdc->secondary.intf,
3665 		    urdc->secondary.file);
3666 		rc = RDC_ECONNOPEN;
3667 		goto notstarted_unlock;
3668 	}
3669 	if (options & RDC_OPT_REVERSE)
3670 		krdc->remote_index = rdc_net_state(index, CCIO_RSYNC);
3671 	else
3672 		krdc->remote_index = rdc_net_state(index, CCIO_SLAVE);
3673 	if (krdc->remote_index < 0) {
3674 		/*
3675 		 * Remote note probably not in a valid state to be synced,
3676 		 * as the state was fetched OK above.
3677 		 */
3678 		spcs_s_add(kstatus, RDC_ERSTATE, urdc->secondary.intf,
3679 		    urdc->secondary.file, urdc->primary.intf,
3680 		    urdc->primary.file);
3681 		rc = RDC_ERSTATE;
3682 		goto notstarted_unlock;
3683 	}
3684 
3685 	rc = check_filesize(index, kstatus);
3686 	if (rc != 0) {
3687 		(void) rdc_net_state(krdc->index, CCIO_ENABLELOG);
3688 		goto notstarted_unlock;
3689 	}
3690 
3691 	krdc->sync_done = 0;
3692 
3693 	mutex_enter(&krdc->bmapmutex);
3694 	krdc->aux_state |= RDC_AUXSYNCIP;
3695 	mutex_exit(&krdc->bmapmutex);
3696 
3697 	if (options & RDC_OPT_REVERSE) {
3698 		rdc_many_enter(krdc);
3699 		rdc_set_mflags(urdc, RDC_SLAVE | RDC_RSYNC_NEEDED);
3700 		mutex_enter(&krdc->bmapmutex);
3701 		rdc_clr_flags(urdc, RDC_VOL_FAILED);
3702 		mutex_exit(&krdc->bmapmutex);
3703 		rdc_write_state(urdc);
3704 		/* LINTED */
3705 		if (kmulti = krdc->multi_next) {
3706 			umulti = &rdc_u_info[kmulti->index];
3707 			if (IS_ENABLED(umulti) && (rdc_get_vflags(umulti) &
3708 			    (RDC_VOL_FAILED | RDC_SYNC_NEEDED))) {
3709 				rdc_clr_flags(umulti, RDC_SYNC_NEEDED);
3710 				rdc_clr_flags(umulti, RDC_VOL_FAILED);
3711 				rdc_write_state(umulti);
3712 			}
3713 		}
3714 		rdc_many_exit(krdc);
3715 	} else {
3716 		rdc_clr_flags(urdc, RDC_FCAL_FAILED);
3717 		rdc_write_state(urdc);
3718 	}
3719 
3720 	if (options & RDC_OPT_UPDATE) {
3721 		ASSERT(urdc->volume_size != 0);
3722 		if (rdc_net_getbmap(index,
3723 		    BMAP_LOG_BYTES(urdc->volume_size)) > 0) {
3724 			spcs_s_add(kstatus, RDC_ENOBMAP);
3725 			rc = RDC_ENOBMAP;
3726 
3727 			(void) rdc_net_state(index, CCIO_ENABLELOG);
3728 
3729 			rdc_clr_flags(urdc, RDC_SYNCING);
3730 			if (options & RDC_OPT_REVERSE) {
3731 				rdc_many_enter(krdc);
3732 				rdc_clr_mflags(urdc, RDC_SLAVE);
3733 				rdc_many_exit(krdc);
3734 			}
3735 			if (krdc->type_flag & RDC_ASYNCMODE)
3736 				rdc_set_flags(urdc, RDC_ASYNC);
3737 			krdc->remote_index = -1;
3738 			rdc_set_flags_log(urdc, RDC_LOGGING,
3739 			    "failed to read remote bitmap");
3740 			rdc_write_state(urdc);
3741 			goto failed;
3742 		}
3743 		rdc_clr_flags(urdc, RDC_FULL);
3744 	} else {
3745 		/*
3746 		 * This is a full sync (not an update sync), mark the
3747 		 * entire bitmap dirty
3748 		 */
3749 		(void) RDC_FILL_BITMAP(krdc, FALSE);
3750 
3751 		rdc_set_flags(urdc, RDC_FULL);
3752 	}
3753 
3754 	rdc_group_exit(krdc);
3755 
3756 	/*
3757 	 * allow diskq->memq flusher to wake up
3758 	 */
3759 	mutex_enter(&krdc->group->ra_queue.net_qlock);
3760 	krdc->group->ra_queue.qfflags &= ~RDC_QFILLSLEEP;
3761 	mutex_exit(&krdc->group->ra_queue.net_qlock);
3762 
3763 	/*
3764 	 * if this is a full sync on a non-diskq set or
3765 	 * a diskq set that has failed, clear the async flag
3766 	 */
3767 	if (krdc->type_flag & RDC_ASYNCMODE) {
3768 		if ((!(options & RDC_OPT_UPDATE)) ||
3769 		    (!RDC_IS_DISKQ(krdc->group)) ||
3770 		    (!(IS_STATE(urdc, RDC_QUEUING)))) {
3771 			/* full syncs, or core queue are synchronous */
3772 			rdc_group_enter(krdc);
3773 			rdc_clr_flags(urdc, RDC_ASYNC);
3774 			rdc_group_exit(krdc);
3775 		}
3776 
3777 		/*
3778 		 * if the queue failed because it was full, lets see
3779 		 * if we can restart it. After _rdc_sync() is done
3780 		 * the modes will switch and we will begin disk
3781 		 * queuing again. NOTE: this should only be called
3782 		 * once per group, as it clears state for all group
3783 		 * members, also clears the async flag for all members
3784 		 */
3785 		if (IS_STATE(urdc, RDC_DISKQ_FAILED)) {
3786 			rdc_unfail_diskq(krdc);
3787 		} else {
3788 		/* don't add insult to injury by flushing a dead queue */
3789 
3790 			/*
3791 			 * if we are updating, and a diskq and
3792 			 * the async thread isn't active, start
3793 			 * it up.
3794 			 */
3795 			if ((options & RDC_OPT_UPDATE) &&
3796 			    (IS_STATE(urdc, RDC_QUEUING))) {
3797 				rdc_group_enter(krdc);
3798 				rdc_clr_flags(urdc, RDC_SYNCING);
3799 				rdc_group_exit(krdc);
3800 				mutex_enter(&krdc->group->ra_queue.net_qlock);
3801 				if (krdc->group->ra_queue.qfill_sleeping ==
3802 				    RDC_QFILL_ASLEEP)
3803 					cv_broadcast(&group->ra_queue.qfcv);
3804 				mutex_exit(&krdc->group->ra_queue.net_qlock);
3805 				thrcount = urdc->asyncthr;
3806 				while ((thrcount-- > 0) &&
3807 				    !krdc->group->rdc_writer) {
3808 					(void) rdc_writer(krdc->index);
3809 				}
3810 			}
3811 		}
3812 	}
3813 
3814 	/*
3815 	 * For a reverse sync, merge the current bitmap with all other sets
3816 	 * that share this volume.
3817 	 */
3818 	if (options & RDC_OPT_REVERSE) {
3819 retry_many:
3820 		rdc_many_enter(krdc);
3821 		if (IS_MANY(krdc)) {
3822 			rdc_k_info_t *kmany;
3823 			rdc_u_info_t *umany;
3824 
3825 			for (kmany = krdc->many_next; kmany != krdc;
3826 			    kmany = kmany->many_next) {
3827 				umany = &rdc_u_info[kmany->index];
3828 				if (!IS_ENABLED(umany))
3829 					continue;
3830 				ASSERT(umany->flags & RDC_PRIMARY);
3831 
3832 				if (!mutex_tryenter(&kmany->group->lock)) {
3833 					rdc_many_exit(krdc);
3834 					/* May merge more than once */
3835 					goto retry_many;
3836 				}
3837 				rdc_merge_bitmaps(krdc, kmany);
3838 				mutex_exit(&kmany->group->lock);
3839 			}
3840 		}
3841 		rdc_many_exit(krdc);
3842 
3843 retry_multi:
3844 		rdc_many_enter(krdc);
3845 		if (IS_MULTI(krdc)) {
3846 			rdc_k_info_t *kmulti = krdc->multi_next;
3847 			rdc_u_info_t *umulti = &rdc_u_info[kmulti->index];
3848 
3849 			if (IS_ENABLED(umulti)) {
3850 				ASSERT(!(umulti->flags & RDC_PRIMARY));
3851 
3852 				if (!mutex_tryenter(&kmulti->group->lock)) {
3853 					rdc_many_exit(krdc);
3854 					goto retry_multi;
3855 				}
3856 				rdc_merge_bitmaps(krdc, kmulti);
3857 				mutex_exit(&kmulti->group->lock);
3858 			}
3859 		}
3860 		rdc_many_exit(krdc);
3861 	}
3862 
3863 	rdc_group_enter(krdc);
3864 
3865 	if (krdc->bitmap_write == 0) {
3866 		if (rdc_write_bitmap_fill(krdc) >= 0)
3867 			krdc->bitmap_write = -1;
3868 	}
3869 
3870 	if (krdc->bitmap_write > 0)
3871 		(void) rdc_write_bitmap(krdc);
3872 
3873 	urdc->bits_set = RDC_COUNT_BITMAP(krdc);
3874 
3875 	rdc_group_exit(krdc);
3876 
3877 	if (options & RDC_OPT_REVERSE) {
3878 		(void) _rdc_sync_event_notify(RDC_SYNC_START,
3879 		    urdc->primary.file, urdc->group_name);
3880 	}
3881 
3882 	/* Now set off the sync itself */
3883 
3884 	mutex_enter(&net_blk_lock);
3885 	if (nsc_create_process(
3886 	    (void (*)(void *))_rdc_sync, (void *)krdc, FALSE)) {
3887 		mutex_exit(&net_blk_lock);
3888 		spcs_s_add(kstatus, RDC_ENOPROC);
3889 		/*
3890 		 * We used to just return here,
3891 		 * but we need to clear the AUXSYNCIP bit
3892 		 * and there is a very small chance that
3893 		 * someone may be waiting on the disk_status flag.
3894 		 */
3895 		rc = RDC_ENOPROC;
3896 		/*
3897 		 * need the group lock held at failed.
3898 		 */
3899 		rdc_group_enter(krdc);
3900 		goto failed;
3901 	}
3902 
3903 	mutex_enter(&rdc_conf_lock);
3904 	wakeup_busy(krdc);
3905 	busy = 0;
3906 	mutex_exit(&rdc_conf_lock);
3907 
3908 	while (krdc->sync_done == 0)
3909 		cv_wait(&krdc->synccv, &net_blk_lock);
3910 	mutex_exit(&net_blk_lock);
3911 
3912 	rdc_group_enter(krdc);
3913 
3914 	if (krdc->sync_done == RDC_FAILED) {
3915 		char siztmp1[16];
3916 		(void) spcs_s_inttostring(
3917 		    urdc->sync_pos, siztmp1, sizeof (siztmp1),
3918 		    0);
3919 		spcs_s_add(kstatus, RDC_EFAIL, siztmp1);
3920 		rc = RDC_EFAIL;
3921 	} else
3922 		sync_completed = 1;
3923 
3924 failed:
3925 	/*
3926 	 * We use this flag now to make halt_sync() wait for
3927 	 * us to terminate and let us take the group lock.
3928 	 */
3929 	krdc->aux_state &= ~RDC_AUXSYNCIP;
3930 	if (krdc->disk_status == 1) {
3931 		krdc->disk_status = 0;
3932 		cv_broadcast(&krdc->haltcv);
3933 	}
3934 
3935 notstarted_unlock:
3936 	rdc_group_exit(krdc);
3937 
3938 	if (sync_completed && (options & RDC_OPT_REVERSE)) {
3939 		(void) _rdc_sync_event_notify(RDC_SYNC_DONE,
3940 		    urdc->primary.file, urdc->group_name);
3941 	}
3942 
3943 notstarted:
3944 	if (busy) {
3945 		mutex_enter(&rdc_conf_lock);
3946 		wakeup_busy(krdc);
3947 		mutex_exit(&rdc_conf_lock);
3948 	}
3949 
3950 	return (rc);
3951 }
3952 
3953 /* ARGSUSED */
3954 static int
_rdc_suspend(rdc_k_info_t * krdc,rdc_set_t * rdc_set,spcs_s_info_t kstatus)3955 _rdc_suspend(rdc_k_info_t *krdc, rdc_set_t *rdc_set, spcs_s_info_t kstatus)
3956 {
3957 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
3958 	rdc_if_t *ip;
3959 	int index = krdc->index;
3960 
3961 	ASSERT(krdc->group != NULL);
3962 	rdc_group_enter(krdc);
3963 #ifdef DEBUG
3964 	ASSERT(rdc_check(krdc, rdc_set) == 0);
3965 #else
3966 	if (rdc_check(krdc, rdc_set)) {
3967 		rdc_group_exit(krdc);
3968 		spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
3969 		    rdc_set->secondary.file);
3970 		return (RDC_EALREADY);
3971 	}
3972 #endif
3973 
3974 	if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
3975 		halt_sync(krdc);
3976 		ASSERT(IS_ENABLED(urdc));
3977 	}
3978 
3979 	rdc_group_exit(krdc);
3980 	(void) rdc_unintercept(krdc);
3981 
3982 #ifdef DEBUG
3983 	cmn_err(CE_NOTE, "!SNDR: suspended %s %s", urdc->primary.file,
3984 	    urdc->secondary.file);
3985 #endif
3986 
3987 	/* Configured but not enabled */
3988 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
3989 
3990 
3991 	if (IS_ASYNC(urdc) && !RDC_IS_DISKQ(krdc->group)) {
3992 		int tries = 2; /* in case of possibly stuck flusher threads */
3993 #ifdef DEBUG
3994 		net_queue *qp = &krdc->group->ra_queue;
3995 #endif
3996 		do {
3997 			if (!krdc->group->rdc_writer)
3998 				(void) rdc_writer(krdc->index);
3999 
4000 			(void) rdc_drain_queue(krdc->index);
4001 
4002 		} while (krdc->group->rdc_writer && tries--);
4003 
4004 		/* ok, force it to happen... */
4005 		if (rdc_drain_queue(krdc->index) != 0) {
4006 			do {
4007 				mutex_enter(&krdc->group->ra_queue.net_qlock);
4008 				krdc->group->asyncdis = 1;
4009 				cv_broadcast(&krdc->group->asyncqcv);
4010 				mutex_exit(&krdc->group->ra_queue.net_qlock);
4011 				cmn_err(CE_WARN,
4012 				    "!SNDR: async I/O pending and not flushed "
4013 				    "for %s during suspend",
4014 				    urdc->primary.file);
4015 #ifdef DEBUG
4016 				cmn_err(CE_WARN,
4017 				    "!nitems: %" NSC_SZFMT " nblocks: %"
4018 				    NSC_SZFMT " head: 0x%p tail: 0x%p",
4019 				    qp->nitems, qp->blocks,
4020 				    (void *)qp->net_qhead,
4021 				    (void *)qp->net_qtail);
4022 #endif
4023 			} while (krdc->group->rdc_thrnum > 0);
4024 		}
4025 	}
4026 
4027 	mutex_enter(&rdc_conf_lock);
4028 	ip = krdc->intf;
4029 	krdc->intf = 0;
4030 
4031 	if (ip) {
4032 		rdc_remove_from_if(ip);
4033 	}
4034 
4035 	mutex_exit(&rdc_conf_lock);
4036 
4037 	rdc_group_enter(krdc);
4038 
4039 	/* Configured but not enabled */
4040 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4041 
4042 	rdc_group_exit(krdc);
4043 	/* Must not hold group lock during this function */
4044 	while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
4045 		delay(2);
4046 	rdc_group_enter(krdc);
4047 
4048 	/* Don't rdc_clear_state, unlike _rdc_disable */
4049 
4050 	rdc_free_bitmap(krdc, RDC_CMD_SUSPEND);
4051 	rdc_close_bitmap(krdc);
4052 
4053 	rdc_dev_close(krdc);
4054 	rdc_close_direct(krdc);
4055 
4056 	/* Configured but not enabled */
4057 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4058 
4059 	rdc_group_exit(krdc);
4060 
4061 	/*
4062 	 * we should now unregister the queue, with no conflicting
4063 	 * locks held. This is the last(only) member of the group
4064 	 */
4065 	if (krdc->group && RDC_IS_DISKQ(krdc->group) &&
4066 	    krdc->group->count == 1) { /* stop protecting queue */
4067 		rdc_unintercept_diskq(krdc->group);
4068 	}
4069 
4070 	mutex_enter(&rdc_conf_lock);
4071 
4072 	/* Configured but not enabled */
4073 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4074 
4075 	wait_busy(krdc);
4076 
4077 	if (IS_MANY(krdc) || IS_MULTI(krdc))
4078 		remove_from_many(krdc);
4079 
4080 	remove_from_group(krdc);
4081 
4082 	krdc->remote_index = -1;
4083 	ASSERT(krdc->type_flag & RDC_CONFIGURED);
4084 	ASSERT(krdc->type_flag & RDC_DISABLEPEND);
4085 	krdc->type_flag = 0;
4086 #ifdef	DEBUG
4087 	if (krdc->dcio_bitmap)
4088 		cmn_err(CE_WARN, "!_rdc_suspend: possible mem leak, "
4089 		    "dcio_bitmap");
4090 #endif
4091 	krdc->dcio_bitmap = NULL;
4092 	krdc->bitmap_ref = NULL;
4093 	krdc->bitmap_size = 0;
4094 	krdc->maxfbas = 0;
4095 	krdc->bitmap_write = 0;
4096 	krdc->disk_status = 0;
4097 	rdc_destroy_svinfo(krdc->lsrv);
4098 	krdc->lsrv = NULL;
4099 	krdc->multi_next = NULL;
4100 
4101 	rdc_u_init(urdc);
4102 
4103 	mutex_exit(&rdc_conf_lock);
4104 	rdc_kstat_delete(index);
4105 	return (0);
4106 }
4107 
4108 static int
rdc_suspend(rdc_config_t * uparms,spcs_s_info_t kstatus)4109 rdc_suspend(rdc_config_t *uparms, spcs_s_info_t kstatus)
4110 {
4111 	rdc_k_info_t *krdc;
4112 	int index;
4113 	int rc;
4114 
4115 	mutex_enter(&rdc_conf_lock);
4116 
4117 	index = rdc_lookup_byname(uparms->rdc_set);
4118 	if (index >= 0)
4119 		krdc = &rdc_k_info[index];
4120 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
4121 		mutex_exit(&rdc_conf_lock);
4122 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4123 		    uparms->rdc_set->secondary.file);
4124 		return (RDC_EALREADY);
4125 	}
4126 
4127 	krdc->type_flag |= RDC_DISABLEPEND;
4128 	wait_busy(krdc);
4129 	if (krdc->type_flag == 0) {
4130 		/* A resume or enable failed */
4131 		mutex_exit(&rdc_conf_lock);
4132 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4133 		    uparms->rdc_set->secondary.file);
4134 		return (RDC_EALREADY);
4135 	}
4136 	mutex_exit(&rdc_conf_lock);
4137 
4138 	rc = _rdc_suspend(krdc, uparms->rdc_set, kstatus);
4139 	return (rc);
4140 }
4141 
4142 static int
_rdc_resume(rdc_set_t * rdc_set,int options,spcs_s_info_t kstatus)4143 _rdc_resume(rdc_set_t *rdc_set, int options, spcs_s_info_t kstatus)
4144 {
4145 	int index;
4146 	char *rhost;
4147 	struct netbuf *addrp;
4148 	rdc_k_info_t *krdc;
4149 	rdc_u_info_t *urdc;
4150 	rdc_srv_t *svp = NULL;
4151 	char *local_file;
4152 	char *local_bitmap;
4153 	int rc, rc1;
4154 	nsc_size_t maxfbas;
4155 	rdc_group_t *grp;
4156 
4157 	if ((rdc_set->primary.intf[0] == 0) ||
4158 	    (rdc_set->primary.addr.len == 0) ||
4159 	    (rdc_set->primary.file[0] == 0) ||
4160 	    (rdc_set->primary.bitmap[0] == 0) ||
4161 	    (rdc_set->secondary.intf[0] == 0) ||
4162 	    (rdc_set->secondary.addr.len == 0) ||
4163 	    (rdc_set->secondary.file[0] == 0) ||
4164 	    (rdc_set->secondary.bitmap[0] == 0)) {
4165 		spcs_s_add(kstatus, RDC_EEMPTY);
4166 		return (RDC_EEMPTY);
4167 	}
4168 
4169 	/* Next check there aren't any enabled rdc sets which match. */
4170 
4171 	mutex_enter(&rdc_conf_lock);
4172 
4173 	if (rdc_lookup_byname(rdc_set) >= 0) {
4174 		mutex_exit(&rdc_conf_lock);
4175 		spcs_s_add(kstatus, RDC_EENABLED, rdc_set->primary.intf,
4176 		    rdc_set->primary.file, rdc_set->secondary.intf,
4177 		    rdc_set->secondary.file);
4178 		return (RDC_EENABLED);
4179 	}
4180 
4181 	if (rdc_lookup_many2one(rdc_set) >= 0) {
4182 		mutex_exit(&rdc_conf_lock);
4183 		spcs_s_add(kstatus, RDC_EMANY2ONE, rdc_set->primary.intf,
4184 		    rdc_set->primary.file, rdc_set->secondary.intf,
4185 		    rdc_set->secondary.file);
4186 		return (RDC_EMANY2ONE);
4187 	}
4188 
4189 	if (rdc_set->netconfig->knc_proto == NULL) {
4190 		mutex_exit(&rdc_conf_lock);
4191 		spcs_s_add(kstatus, RDC_ENETCONFIG);
4192 		return (RDC_ENETCONFIG);
4193 	}
4194 
4195 	if (rdc_set->primary.addr.len == 0) {
4196 		mutex_exit(&rdc_conf_lock);
4197 		spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->primary.file);
4198 		return (RDC_ENETBUF);
4199 	}
4200 
4201 	if (rdc_set->secondary.addr.len == 0) {
4202 		mutex_exit(&rdc_conf_lock);
4203 		spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->secondary.file);
4204 		return (RDC_ENETBUF);
4205 	}
4206 
4207 	/* Check that the local data volume isn't in use as a bitmap */
4208 	if (options & RDC_OPT_PRIMARY)
4209 		local_file = rdc_set->primary.file;
4210 	else
4211 		local_file = rdc_set->secondary.file;
4212 	if (rdc_lookup_bitmap(local_file) >= 0) {
4213 		mutex_exit(&rdc_conf_lock);
4214 		spcs_s_add(kstatus, RDC_EVOLINUSE, local_file);
4215 		return (RDC_EVOLINUSE);
4216 	}
4217 
4218 	/* check that the secondary data volume isn't in use */
4219 	if (!(options & RDC_OPT_PRIMARY)) {
4220 		local_file = rdc_set->secondary.file;
4221 		if (rdc_lookup_secondary(local_file) >= 0) {
4222 			mutex_exit(&rdc_conf_lock);
4223 			spcs_s_add(kstatus, RDC_EVOLINUSE, local_file);
4224 			return (RDC_EVOLINUSE);
4225 		}
4226 	}
4227 
4228 	/* Check that the bitmap isn't in use as a data volume */
4229 	if (options & RDC_OPT_PRIMARY)
4230 		local_bitmap = rdc_set->primary.bitmap;
4231 	else
4232 		local_bitmap = rdc_set->secondary.bitmap;
4233 	if (rdc_lookup_configured(local_bitmap) >= 0) {
4234 		mutex_exit(&rdc_conf_lock);
4235 		spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap);
4236 		return (RDC_EBMPINUSE);
4237 	}
4238 
4239 	/* Check that the bitmap isn't already in use as a bitmap */
4240 	if (rdc_lookup_bitmap(local_bitmap) >= 0) {
4241 		mutex_exit(&rdc_conf_lock);
4242 		spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap);
4243 		return (RDC_EBMPINUSE);
4244 	}
4245 
4246 	/* Set urdc->volume_size */
4247 	index = rdc_dev_open(rdc_set, options);
4248 	if (index < 0) {
4249 		mutex_exit(&rdc_conf_lock);
4250 		if (options & RDC_OPT_PRIMARY)
4251 			spcs_s_add(kstatus, RDC_EOPEN, rdc_set->primary.intf,
4252 			    rdc_set->primary.file);
4253 		else
4254 			spcs_s_add(kstatus, RDC_EOPEN, rdc_set->secondary.intf,
4255 			    rdc_set->secondary.file);
4256 		return (RDC_EOPEN);
4257 	}
4258 
4259 	urdc = &rdc_u_info[index];
4260 	krdc = &rdc_k_info[index];
4261 
4262 	/* copy relevant parts of rdc_set to urdc field by field */
4263 
4264 	(void) strncpy(urdc->primary.intf, rdc_set->primary.intf,
4265 	    MAX_RDC_HOST_SIZE);
4266 	(void) strncpy(urdc->secondary.intf, rdc_set->secondary.intf,
4267 	    MAX_RDC_HOST_SIZE);
4268 
4269 	(void) strncpy(urdc->group_name, rdc_set->group_name, NSC_MAXPATH);
4270 
4271 	dup_rdc_netbuf(&rdc_set->primary.addr, &urdc->primary.addr);
4272 	(void) strncpy(urdc->primary.file, rdc_set->primary.file, NSC_MAXPATH);
4273 	(void) strncpy(urdc->primary.bitmap, rdc_set->primary.bitmap,
4274 	    NSC_MAXPATH);
4275 
4276 	dup_rdc_netbuf(&rdc_set->secondary.addr, &urdc->secondary.addr);
4277 	(void) strncpy(urdc->secondary.file, rdc_set->secondary.file,
4278 	    NSC_MAXPATH);
4279 	(void) strncpy(urdc->secondary.bitmap, rdc_set->secondary.bitmap,
4280 	    NSC_MAXPATH);
4281 	(void) strncpy(urdc->disk_queue, rdc_set->disk_queue, NSC_MAXPATH);
4282 	urdc->setid = rdc_set->setid;
4283 
4284 	if ((options & RDC_OPT_SYNC) && urdc->disk_queue[0]) {
4285 		mutex_exit(&rdc_conf_lock);
4286 		rdc_dev_close(krdc);
4287 		spcs_s_add(kstatus, RDC_EQWRONGMODE);
4288 		return (RDC_EQWRONGMODE);
4289 	}
4290 
4291 	/*
4292 	 * init flags now so that state left by failures in add_to_group()
4293 	 * are preserved.
4294 	 */
4295 	rdc_init_flags(urdc);
4296 
4297 	if ((rc1 = add_to_group(krdc, options, RDC_CMD_RESUME)) != 0) {
4298 		if (rc1 == RDC_EQNOADD) { /* something went wrong with queue */
4299 			rdc_fail_diskq(krdc, RDC_WAIT, RDC_NOLOG);
4300 			/* don't return a failure here, continue with resume */
4301 
4302 		} else { /* some other group add failure */
4303 			mutex_exit(&rdc_conf_lock);
4304 			rdc_dev_close(krdc);
4305 			spcs_s_add(kstatus, RDC_EGROUP,
4306 			    rdc_set->primary.intf, rdc_set->primary.file,
4307 			    rdc_set->secondary.intf, rdc_set->secondary.file,
4308 			    rdc_set->group_name);
4309 			return (RDC_EGROUP);
4310 		}
4311 	}
4312 
4313 	/*
4314 	 * maxfbas was set in rdc_dev_open as primary's maxfbas.
4315 	 * If diskq's maxfbas is smaller, then use diskq's.
4316 	 */
4317 	grp = krdc->group;
4318 	if (grp && RDC_IS_DISKQ(grp) && (grp->diskqfd != 0)) {
4319 		rc = _rdc_rsrv_diskq(grp);
4320 		if (RDC_SUCCESS(rc)) {
4321 			rc = nsc_maxfbas(grp->diskqfd, 0, &maxfbas);
4322 			if (rc == 0) {
4323 #ifdef DEBUG
4324 				if (krdc->maxfbas != maxfbas)
4325 					cmn_err(CE_NOTE,
4326 					    "!_rdc_resume: diskq maxfbas = %"
4327 					    NSC_SZFMT ", primary maxfbas = %"
4328 					    NSC_SZFMT, maxfbas, krdc->maxfbas);
4329 #endif
4330 					krdc->maxfbas = min(krdc->maxfbas,
4331 					    maxfbas);
4332 			} else {
4333 				cmn_err(CE_WARN,
4334 				    "!_rdc_resume: diskq maxfbas failed (%d)",
4335 				    rc);
4336 			}
4337 			_rdc_rlse_diskq(grp);
4338 		} else {
4339 			cmn_err(CE_WARN,
4340 			    "!_rdc_resume: diskq reserve failed (%d)", rc);
4341 		}
4342 	}
4343 
4344 	(void) strncpy(urdc->direct_file, rdc_set->direct_file, NSC_MAXPATH);
4345 	if ((options & RDC_OPT_PRIMARY) && rdc_set->direct_file[0]) {
4346 		if (rdc_open_direct(krdc) == NULL)
4347 			rdc_set_flags(urdc, RDC_FCAL_FAILED);
4348 	}
4349 
4350 	krdc->many_next = krdc;
4351 
4352 	ASSERT(krdc->type_flag == 0);
4353 	krdc->type_flag = RDC_CONFIGURED;
4354 
4355 	if (options & RDC_OPT_PRIMARY)
4356 		rdc_set_flags(urdc, RDC_PRIMARY);
4357 
4358 	if (options & RDC_OPT_ASYNC)
4359 		krdc->type_flag |= RDC_ASYNCMODE;
4360 
4361 	set_busy(krdc);
4362 
4363 	urdc->syshostid = rdc_set->syshostid;
4364 
4365 	if (add_to_many(krdc) < 0) {
4366 		mutex_exit(&rdc_conf_lock);
4367 
4368 		rdc_group_enter(krdc);
4369 
4370 		spcs_s_add(kstatus, RDC_EMULTI);
4371 		rc = RDC_EMULTI;
4372 		goto fail;
4373 	}
4374 
4375 	/* Configured but not enabled */
4376 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4377 
4378 	mutex_exit(&rdc_conf_lock);
4379 
4380 	if (urdc->volume_size == 0) {
4381 		rdc_many_enter(krdc);
4382 		if (options & RDC_OPT_PRIMARY)
4383 			rdc_set_mflags(urdc, RDC_RSYNC_NEEDED);
4384 		else
4385 			rdc_set_flags(urdc, RDC_SYNC_NEEDED);
4386 		rdc_set_flags(urdc, RDC_VOL_FAILED);
4387 		rdc_many_exit(krdc);
4388 	}
4389 
4390 	rdc_group_enter(krdc);
4391 
4392 	/* Configured but not enabled */
4393 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4394 
4395 	/*
4396 	 * The rdc set is configured but not yet enabled. Other operations must
4397 	 * ignore this set until it is enabled.
4398 	 */
4399 
4400 	urdc->sync_pos = 0;
4401 
4402 	/* Set tunable defaults, we'll pick up tunables from the header later */
4403 
4404 	urdc->maxqfbas = rdc_maxthres_queue;
4405 	urdc->maxqitems = rdc_max_qitems;
4406 	urdc->autosync = 0;
4407 	urdc->asyncthr = rdc_asyncthr;
4408 
4409 	urdc->netconfig = rdc_set->netconfig;
4410 
4411 	if (options & RDC_OPT_PRIMARY) {
4412 		rhost = rdc_set->secondary.intf;
4413 		addrp = &rdc_set->secondary.addr;
4414 	} else {
4415 		rhost = rdc_set->primary.intf;
4416 		addrp = &rdc_set->primary.addr;
4417 	}
4418 
4419 	if (options & RDC_OPT_ASYNC)
4420 		rdc_set_flags(urdc, RDC_ASYNC);
4421 
4422 	svp = rdc_create_svinfo(rhost, addrp, urdc->netconfig);
4423 	if (svp == NULL) {
4424 		spcs_s_add(kstatus, ENOMEM);
4425 		rc = ENOMEM;
4426 		goto fail;
4427 	}
4428 
4429 	urdc->netconfig = NULL;		/* This will be no good soon */
4430 
4431 	/* Don't set krdc->intf here */
4432 	rdc_kstat_create(index);
4433 
4434 	/* if the bitmap resume isn't clean, it will clear queuing flag */
4435 
4436 	(void) rdc_resume_bitmap(krdc);
4437 
4438 	if (RDC_IS_DISKQ(krdc->group)) {
4439 		disk_queue *q = &krdc->group->diskq;
4440 		if ((rc1 == RDC_EQNOADD) ||
4441 		    IS_QSTATE(q, RDC_QBADRESUME)) {
4442 			rdc_clr_flags(urdc, RDC_QUEUING);
4443 			RDC_ZERO_BITREF(krdc);
4444 		}
4445 	}
4446 
4447 	if (krdc->lsrv == NULL)
4448 		krdc->lsrv = svp;
4449 	else {
4450 #ifdef DEBUG
4451 		cmn_err(CE_WARN, "!_rdc_resume: krdc->lsrv already set: %p",
4452 		    (void *) krdc->lsrv);
4453 #endif
4454 		rdc_destroy_svinfo(svp);
4455 	}
4456 	svp = NULL;
4457 
4458 	/* Configured but not enabled */
4459 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4460 
4461 	/* And finally */
4462 
4463 	krdc->remote_index = -1;
4464 
4465 	/* Should we set the whole group logging? */
4466 	rdc_set_flags(urdc, RDC_ENABLED | RDC_LOGGING);
4467 
4468 	rdc_group_exit(krdc);
4469 
4470 	if (rdc_intercept(krdc) != 0) {
4471 		rdc_group_enter(krdc);
4472 		rdc_clr_flags(urdc, RDC_ENABLED);
4473 		if (options & RDC_OPT_PRIMARY)
4474 			spcs_s_add(kstatus, RDC_EREGISTER, urdc->primary.file);
4475 		else
4476 			spcs_s_add(kstatus, RDC_EREGISTER,
4477 			    urdc->secondary.file);
4478 #ifdef DEBUG
4479 		cmn_err(CE_NOTE, "!nsc_register_path failed %s",
4480 		    urdc->primary.file);
4481 #endif
4482 		rc = RDC_EREGISTER;
4483 		goto bmpfail;
4484 	}
4485 #ifdef DEBUG
4486 	cmn_err(CE_NOTE, "!SNDR: resumed %s %s", urdc->primary.file,
4487 	    urdc->secondary.file);
4488 #endif
4489 
4490 	rdc_write_state(urdc);
4491 
4492 	mutex_enter(&rdc_conf_lock);
4493 	wakeup_busy(krdc);
4494 	mutex_exit(&rdc_conf_lock);
4495 
4496 	return (0);
4497 
4498 bmpfail:
4499 	if (options & RDC_OPT_PRIMARY)
4500 		spcs_s_add(kstatus, RDC_EBITMAP, urdc->primary.bitmap);
4501 	else
4502 		spcs_s_add(kstatus, RDC_EBITMAP, urdc->secondary.bitmap);
4503 	rc = RDC_EBITMAP;
4504 	if (rdc_get_vflags(urdc) & RDC_ENABLED) {
4505 		rdc_group_exit(krdc);
4506 		(void) rdc_unintercept(krdc);
4507 		rdc_group_enter(krdc);
4508 	}
4509 
4510 fail:
4511 	rdc_kstat_delete(index);
4512 	/* Don't unset krdc->intf here, unlike _rdc_enable */
4513 
4514 	/* Configured but not enabled */
4515 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4516 
4517 	rdc_dev_close(krdc);
4518 	rdc_close_direct(krdc);
4519 	rdc_destroy_svinfo(svp);
4520 
4521 	/* Configured but not enabled */
4522 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4523 
4524 	rdc_group_exit(krdc);
4525 
4526 	mutex_enter(&rdc_conf_lock);
4527 
4528 	/* Configured but not enabled */
4529 	ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4530 
4531 	remove_from_group(krdc);
4532 
4533 	if (IS_MANY(krdc) || IS_MULTI(krdc))
4534 		remove_from_many(krdc);
4535 
4536 	rdc_u_init(urdc);
4537 
4538 	ASSERT(krdc->type_flag & RDC_CONFIGURED);
4539 	krdc->type_flag = 0;
4540 	wakeup_busy(krdc);
4541 
4542 	mutex_exit(&rdc_conf_lock);
4543 
4544 	return (rc);
4545 }
4546 
4547 static int
rdc_resume(rdc_config_t * uparms,spcs_s_info_t kstatus)4548 rdc_resume(rdc_config_t *uparms, spcs_s_info_t kstatus)
4549 {
4550 	char itmp[10];
4551 	int rc;
4552 
4553 	if (!(uparms->options & RDC_OPT_SYNC) &&
4554 	    !(uparms->options & RDC_OPT_ASYNC)) {
4555 		(void) spcs_s_inttostring(
4556 		    uparms->options, itmp, sizeof (itmp), 1);
4557 		spcs_s_add(kstatus, RDC_EEINVAL, itmp);
4558 		rc = RDC_EEINVAL;
4559 		goto done;
4560 	}
4561 
4562 	if (!(uparms->options & RDC_OPT_PRIMARY) &&
4563 	    !(uparms->options & RDC_OPT_SECONDARY)) {
4564 		(void) spcs_s_inttostring(
4565 		    uparms->options, itmp, sizeof (itmp), 1);
4566 		spcs_s_add(kstatus, RDC_EEINVAL, itmp);
4567 		rc = RDC_EEINVAL;
4568 		goto done;
4569 	}
4570 
4571 	rc = _rdc_resume(uparms->rdc_set, uparms->options, kstatus);
4572 done:
4573 	return (rc);
4574 }
4575 
4576 /*
4577  * if rdc_group_log is called because a volume has failed,
4578  * we must disgard the queue to preserve write ordering.
4579  * later perhaps, we can keep queuing, but we would have to
4580  * rewrite the i/o path to acommodate that. currently, if there
4581  * is a volume failure, the buffers are satisfied remotely and
4582  * there is no way to satisfy them from the current diskq config
4583  * phew, if we do that.. it will be difficult
4584  */
4585 int
rdc_can_queue(rdc_k_info_t * krdc)4586 rdc_can_queue(rdc_k_info_t *krdc)
4587 {
4588 	rdc_k_info_t *p;
4589 	rdc_u_info_t *q;
4590 
4591 	for (p = krdc->group_next; ; p = p->group_next) {
4592 		q = &rdc_u_info[p->index];
4593 		if (IS_STATE(q, RDC_VOL_FAILED))
4594 			return (0);
4595 		if (p == krdc)
4596 			break;
4597 	}
4598 	return (1);
4599 }
4600 
4601 /*
4602  * wait here, until all in flight async i/o's have either
4603  * finished or failed. Avoid the race with r_net_state()
4604  * which tells remote end to log.
4605  */
4606 void
rdc_inflwait(rdc_group_t * grp)4607 rdc_inflwait(rdc_group_t *grp)
4608 {
4609 	int bail = RDC_CLNT_TMOUT * 2; /* to include retries */
4610 	volatile int *inflitems;
4611 
4612 	if (RDC_IS_DISKQ(grp))
4613 		inflitems = (&(grp->diskq.inflitems));
4614 	else
4615 		inflitems = (&(grp->ra_queue.inflitems));
4616 
4617 	while (*inflitems && (--bail > 0))
4618 		delay(HZ);
4619 }
4620 
4621 void
rdc_group_log(rdc_k_info_t * krdc,int flag,char * why)4622 rdc_group_log(rdc_k_info_t *krdc, int flag, char *why)
4623 {
4624 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
4625 	rdc_k_info_t *p;
4626 	rdc_u_info_t *q;
4627 	int do_group;
4628 	int sm, um, md;
4629 	disk_queue *dq;
4630 
4631 	void (*flag_op)(rdc_u_info_t *urdc, int flag);
4632 
4633 	ASSERT(MUTEX_HELD(&krdc->group->lock));
4634 
4635 	if (!IS_ENABLED(urdc))
4636 		return;
4637 
4638 	rdc_many_enter(krdc);
4639 
4640 	if ((flag & RDC_QUEUING) && (!IS_STATE(urdc, RDC_SYNCING)) &&
4641 	    (rdc_can_queue(krdc))) {
4642 		flag_op = rdc_set_flags; /* keep queuing, link error */
4643 		flag &= ~RDC_FLUSH;
4644 	} else {
4645 		flag_op = rdc_clr_flags; /* stop queuing, user request */
4646 	}
4647 
4648 	do_group = 1;
4649 	if (!(rdc_get_vflags(urdc) & RDC_PRIMARY))
4650 		do_group = 0;
4651 	else if ((urdc->group_name[0] == 0) ||
4652 	    (rdc_get_vflags(urdc) & RDC_LOGGING) ||
4653 	    (rdc_get_vflags(urdc) & RDC_SYNCING))
4654 		do_group = 0;
4655 	if (do_group) {
4656 		for (p = krdc->group_next; p != krdc; p = p->group_next) {
4657 			q = &rdc_u_info[p->index];
4658 			if (!IS_ENABLED(q))
4659 				continue;
4660 			if ((rdc_get_vflags(q) & RDC_LOGGING) ||
4661 			    (rdc_get_vflags(q) & RDC_SYNCING)) {
4662 				do_group = 0;
4663 				break;
4664 			}
4665 		}
4666 	}
4667 	if (!do_group && (flag & RDC_FORCE_GROUP))
4668 		do_group = 1;
4669 
4670 	rdc_many_exit(krdc);
4671 	dq = &krdc->group->diskq;
4672 	if (do_group) {
4673 #ifdef DEBUG
4674 		cmn_err(CE_NOTE, "!SNDR:Group point-in-time for grp: %s %s:%s",
4675 		    urdc->group_name, urdc->primary.intf, urdc->secondary.intf);
4676 #endif
4677 		DTRACE_PROBE(rdc_diskq_group_PIT);
4678 
4679 		/* Set group logging at the same PIT under rdc_many_lock */
4680 		rdc_many_enter(krdc);
4681 		rdc_set_flags_log(urdc, RDC_LOGGING, why);
4682 		if (RDC_IS_DISKQ(krdc->group))
4683 			flag_op(urdc, RDC_QUEUING);
4684 		for (p = krdc->group_next; p != krdc; p = p->group_next) {
4685 			q = &rdc_u_info[p->index];
4686 			if (!IS_ENABLED(q))
4687 				continue;
4688 			rdc_set_flags_log(q, RDC_LOGGING,
4689 			    "consistency group member following leader");
4690 			if (RDC_IS_DISKQ(p->group))
4691 				flag_op(q, RDC_QUEUING);
4692 		}
4693 
4694 		rdc_many_exit(krdc);
4695 
4696 		/*
4697 		 * This can cause the async threads to fail,
4698 		 * which in turn will call rdc_group_log()
4699 		 * again. Release the lock and re-aquire.
4700 		 */
4701 		rdc_group_exit(krdc);
4702 
4703 		while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
4704 			delay(2);
4705 		if (!RDC_IS_DISKQ(krdc->group))
4706 			RDC_ZERO_BITREF(krdc);
4707 
4708 		rdc_inflwait(krdc->group);
4709 
4710 		/*
4711 		 * a little lazy, but neat. recall dump_alloc_bufs to
4712 		 * ensure that the queue pointers & seq are reset properly
4713 		 * after we have waited for inflight stuff
4714 		 */
4715 		while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
4716 			delay(2);
4717 
4718 		rdc_group_enter(krdc);
4719 		if (RDC_IS_DISKQ(krdc->group) && (!(flag & RDC_QUEUING))) {
4720 			/* fail or user request */
4721 			RDC_ZERO_BITREF(krdc);
4722 			mutex_enter(&krdc->group->diskq.disk_qlock);
4723 			rdc_init_diskq_header(krdc->group,
4724 			    &krdc->group->diskq.disk_hdr);
4725 			SET_QNXTIO(dq, QHEAD(dq));
4726 			mutex_exit(&krdc->group->diskq.disk_qlock);
4727 		}
4728 
4729 		if (flag & RDC_ALLREMOTE) {
4730 			/* Tell other node to start logging */
4731 			if (krdc->lsrv && krdc->intf && !krdc->intf->if_down)
4732 				(void) rdc_net_state(krdc->index,
4733 				    CCIO_ENABLELOG);
4734 		}
4735 
4736 		if (flag & (RDC_ALLREMOTE | RDC_OTHERREMOTE)) {
4737 			rdc_many_enter(krdc);
4738 			for (p = krdc->group_next; p != krdc;
4739 			    p = p->group_next) {
4740 				if (p->lsrv && krdc->intf &&
4741 				    !krdc->intf->if_down) {
4742 					(void) rdc_net_state(p->index,
4743 					    CCIO_ENABLELOG);
4744 				}
4745 			}
4746 			rdc_many_exit(krdc);
4747 		}
4748 
4749 		rdc_write_state(urdc);
4750 		for (p = krdc->group_next; p != krdc; p = p->group_next) {
4751 			q = &rdc_u_info[p->index];
4752 			if (!IS_ENABLED(q))
4753 				continue;
4754 			rdc_write_state(q);
4755 		}
4756 	} else {
4757 		/* No point in time is possible, just deal with single set */
4758 
4759 		if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
4760 			halt_sync(krdc);
4761 		} else {
4762 			if (rdc_net_getstate(krdc, &sm, &um, &md, TRUE) < 0) {
4763 				rdc_clr_flags(urdc, RDC_SYNCING);
4764 				rdc_set_flags_log(urdc, RDC_LOGGING,
4765 				    "failed to read remote state");
4766 
4767 				rdc_write_state(urdc);
4768 				while (rdc_dump_alloc_bufs_cd(krdc->index)
4769 				    == EAGAIN)
4770 					delay(2);
4771 				if ((RDC_IS_DISKQ(krdc->group)) &&
4772 				    (!(flag & RDC_QUEUING))) { /* fail! */
4773 					mutex_enter(QLOCK(dq));
4774 					rdc_init_diskq_header(krdc->group,
4775 					    &krdc->group->diskq.disk_hdr);
4776 					SET_QNXTIO(dq, QHEAD(dq));
4777 					mutex_exit(QLOCK(dq));
4778 				}
4779 
4780 				return;
4781 			}
4782 		}
4783 
4784 		if (rdc_get_vflags(urdc) & RDC_SYNCING)
4785 			return;
4786 
4787 		if (RDC_IS_DISKQ(krdc->group))
4788 			flag_op(urdc, RDC_QUEUING);
4789 
4790 		if ((RDC_IS_DISKQ(krdc->group)) &&
4791 		    (!(flag & RDC_QUEUING))) { /* fail! */
4792 			RDC_ZERO_BITREF(krdc);
4793 			mutex_enter(QLOCK(dq));
4794 			rdc_init_diskq_header(krdc->group,
4795 			    &krdc->group->diskq.disk_hdr);
4796 			SET_QNXTIO(dq, QHEAD(dq));
4797 			mutex_exit(QLOCK(dq));
4798 		}
4799 
4800 		if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) {
4801 			rdc_set_flags_log(urdc, RDC_LOGGING, why);
4802 
4803 			rdc_write_state(urdc);
4804 
4805 			while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
4806 				delay(2);
4807 			if (!RDC_IS_DISKQ(krdc->group))
4808 				RDC_ZERO_BITREF(krdc);
4809 
4810 			rdc_inflwait(krdc->group);
4811 			/*
4812 			 * a little lazy, but neat. recall dump_alloc_bufs to
4813 			 * ensure that the queue pointers & seq are reset
4814 			 * properly after we have waited for inflight stuff
4815 			 */
4816 			while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
4817 				delay(2);
4818 
4819 			if (flag & RDC_ALLREMOTE) {
4820 				/* Tell other node to start logging */
4821 				if (krdc->lsrv && krdc->intf &&
4822 				    !krdc->intf->if_down) {
4823 					(void) rdc_net_state(krdc->index,
4824 					    CCIO_ENABLELOG);
4825 				}
4826 			}
4827 		}
4828 	}
4829 	/*
4830 	 * just in case any threads were in flight during log cleanup
4831 	 */
4832 	if (RDC_IS_DISKQ(krdc->group)) {
4833 		mutex_enter(QLOCK(dq));
4834 		cv_broadcast(&dq->qfullcv);
4835 		mutex_exit(QLOCK(dq));
4836 	}
4837 }
4838 
4839 static int
_rdc_log(rdc_k_info_t * krdc,rdc_set_t * rdc_set,spcs_s_info_t kstatus)4840 _rdc_log(rdc_k_info_t *krdc, rdc_set_t *rdc_set, spcs_s_info_t kstatus)
4841 {
4842 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
4843 	rdc_srv_t *svp;
4844 
4845 	rdc_group_enter(krdc);
4846 	if (rdc_check(krdc, rdc_set)) {
4847 		rdc_group_exit(krdc);
4848 		spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
4849 		    rdc_set->secondary.file);
4850 		return (RDC_EALREADY);
4851 	}
4852 
4853 	svp = krdc->lsrv;
4854 	if (rdc_get_vflags(urdc) & RDC_PRIMARY)
4855 		krdc->intf = rdc_add_to_if(svp, &(urdc->primary.addr),
4856 		    &(urdc->secondary.addr), 1);
4857 	else
4858 		krdc->intf = rdc_add_to_if(svp, &(urdc->secondary.addr),
4859 		    &(urdc->primary.addr), 0);
4860 
4861 	if (!krdc->intf) {
4862 		rdc_group_exit(krdc);
4863 		spcs_s_add(kstatus, RDC_EADDTOIF, urdc->primary.intf,
4864 		    urdc->secondary.intf);
4865 		return (RDC_EADDTOIF);
4866 	}
4867 
4868 	rdc_group_log(krdc, RDC_FLUSH | RDC_ALLREMOTE, NULL);
4869 
4870 	if (rdc_get_vflags(urdc) & RDC_SYNCING) {
4871 		rdc_group_exit(krdc);
4872 		spcs_s_add(kstatus, RDC_ESYNCING, urdc->primary.file);
4873 		return (RDC_ESYNCING);
4874 	}
4875 
4876 	rdc_group_exit(krdc);
4877 
4878 	return (0);
4879 }
4880 
4881 static int
rdc_log(rdc_config_t * uparms,spcs_s_info_t kstatus)4882 rdc_log(rdc_config_t *uparms, spcs_s_info_t kstatus)
4883 {
4884 	rdc_k_info_t *krdc;
4885 	int rc = 0;
4886 	int index;
4887 
4888 	mutex_enter(&rdc_conf_lock);
4889 	index = rdc_lookup_byname(uparms->rdc_set);
4890 	if (index >= 0)
4891 		krdc = &rdc_k_info[index];
4892 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
4893 		mutex_exit(&rdc_conf_lock);
4894 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4895 		    uparms->rdc_set->secondary.file);
4896 		return (RDC_EALREADY);
4897 	}
4898 
4899 	set_busy(krdc);
4900 	if (krdc->type_flag == 0) {
4901 		/* A resume or enable failed */
4902 		wakeup_busy(krdc);
4903 		mutex_exit(&rdc_conf_lock);
4904 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4905 		    uparms->rdc_set->secondary.file);
4906 		return (RDC_EALREADY);
4907 	}
4908 	mutex_exit(&rdc_conf_lock);
4909 
4910 	rc = _rdc_log(krdc, uparms->rdc_set, kstatus);
4911 
4912 	mutex_enter(&rdc_conf_lock);
4913 	wakeup_busy(krdc);
4914 	mutex_exit(&rdc_conf_lock);
4915 
4916 	return (rc);
4917 }
4918 
4919 
4920 static int
rdc_wait(rdc_config_t * uparms,spcs_s_info_t kstatus)4921 rdc_wait(rdc_config_t *uparms, spcs_s_info_t kstatus)
4922 {
4923 	rdc_k_info_t *krdc;
4924 	rdc_u_info_t *urdc;
4925 	int index;
4926 	int need_check = 0;
4927 
4928 	mutex_enter(&rdc_conf_lock);
4929 	index = rdc_lookup_byname(uparms->rdc_set);
4930 	if (index >= 0)
4931 		krdc = &rdc_k_info[index];
4932 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
4933 		mutex_exit(&rdc_conf_lock);
4934 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4935 		    uparms->rdc_set->secondary.file);
4936 		return (RDC_EALREADY);
4937 	}
4938 
4939 	urdc = &rdc_u_info[index];
4940 	if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) {
4941 		mutex_exit(&rdc_conf_lock);
4942 		return (0);
4943 	}
4944 
4945 	set_busy(krdc);
4946 	if (krdc->type_flag == 0) {
4947 		/* A resume or enable failed */
4948 		wakeup_busy(krdc);
4949 		mutex_exit(&rdc_conf_lock);
4950 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4951 		    uparms->rdc_set->secondary.file);
4952 		return (RDC_EALREADY);
4953 	}
4954 	mutex_exit(&rdc_conf_lock);
4955 
4956 	rdc_group_enter(krdc);
4957 	if (rdc_check(krdc, uparms->rdc_set)) {
4958 		rdc_group_exit(krdc);
4959 		mutex_enter(&rdc_conf_lock);
4960 		wakeup_busy(krdc);
4961 		mutex_exit(&rdc_conf_lock);
4962 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4963 		    uparms->rdc_set->secondary.file);
4964 		return (RDC_EALREADY);
4965 	}
4966 
4967 	if ((rdc_get_vflags(urdc) & (RDC_SYNCING | RDC_PRIMARY)) !=
4968 	    (RDC_SYNCING | RDC_PRIMARY)) {
4969 		rdc_group_exit(krdc);
4970 		mutex_enter(&rdc_conf_lock);
4971 		wakeup_busy(krdc);
4972 		mutex_exit(&rdc_conf_lock);
4973 		return (0);
4974 	}
4975 	if (rdc_get_vflags(urdc) & RDC_SYNCING) {
4976 		need_check = 1;
4977 	}
4978 	rdc_group_exit(krdc);
4979 
4980 	mutex_enter(&net_blk_lock);
4981 
4982 	mutex_enter(&rdc_conf_lock);
4983 	wakeup_busy(krdc);
4984 	mutex_exit(&rdc_conf_lock);
4985 
4986 	(void) cv_wait_sig(&krdc->synccv, &net_blk_lock);
4987 
4988 	mutex_exit(&net_blk_lock);
4989 	if (need_check) {
4990 		if (krdc->sync_done == RDC_COMPLETED) {
4991 			return (0);
4992 		} else if (krdc->sync_done == RDC_FAILED) {
4993 			return (EIO);
4994 		}
4995 	}
4996 	return (0);
4997 }
4998 
4999 
5000 static int
rdc_health(rdc_config_t * uparms,spcs_s_info_t kstatus,int * rvp)5001 rdc_health(rdc_config_t *uparms, spcs_s_info_t kstatus, int *rvp)
5002 {
5003 	rdc_k_info_t *krdc;
5004 	rdc_u_info_t *urdc;
5005 	int rc = 0;
5006 	int index;
5007 
5008 	mutex_enter(&rdc_conf_lock);
5009 	index = rdc_lookup_byname(uparms->rdc_set);
5010 	if (index >= 0)
5011 		krdc = &rdc_k_info[index];
5012 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5013 		mutex_exit(&rdc_conf_lock);
5014 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5015 		    uparms->rdc_set->secondary.file);
5016 		return (RDC_EALREADY);
5017 	}
5018 
5019 	set_busy(krdc);
5020 	if (krdc->type_flag == 0) {
5021 		/* A resume or enable failed */
5022 		wakeup_busy(krdc);
5023 		mutex_exit(&rdc_conf_lock);
5024 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5025 		    uparms->rdc_set->secondary.file);
5026 		return (RDC_EALREADY);
5027 	}
5028 
5029 	mutex_exit(&rdc_conf_lock);
5030 
5031 	rdc_group_enter(krdc);
5032 	if (rdc_check(krdc, uparms->rdc_set)) {
5033 		rdc_group_exit(krdc);
5034 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5035 		    uparms->rdc_set->secondary.file);
5036 		rc = RDC_EALREADY;
5037 		goto done;
5038 	}
5039 
5040 	urdc = &rdc_u_info[index];
5041 	if (rdc_isactive_if(&(urdc->primary.addr), &(urdc->secondary.addr)))
5042 		*rvp = RDC_ACTIVE;
5043 	else
5044 		*rvp = RDC_INACTIVE;
5045 
5046 	rdc_group_exit(krdc);
5047 
5048 done:
5049 	mutex_enter(&rdc_conf_lock);
5050 	wakeup_busy(krdc);
5051 	mutex_exit(&rdc_conf_lock);
5052 
5053 	return (rc);
5054 }
5055 
5056 
5057 static int
rdc_reconfig(rdc_config_t * uparms,spcs_s_info_t kstatus)5058 rdc_reconfig(rdc_config_t *uparms, spcs_s_info_t kstatus)
5059 {
5060 	rdc_k_info_t *krdc;
5061 	rdc_u_info_t *urdc;
5062 	int rc = -2;
5063 	int index;
5064 
5065 	mutex_enter(&rdc_conf_lock);
5066 	index = rdc_lookup_byname(uparms->rdc_set);
5067 	if (index >= 0)
5068 		krdc = &rdc_k_info[index];
5069 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5070 		mutex_exit(&rdc_conf_lock);
5071 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5072 		    uparms->rdc_set->secondary.file);
5073 		return (RDC_EALREADY);
5074 	}
5075 
5076 	urdc = &rdc_u_info[index];
5077 	set_busy(krdc);
5078 	if (krdc->type_flag == 0) {
5079 		/* A resume or enable failed */
5080 		wakeup_busy(krdc);
5081 		mutex_exit(&rdc_conf_lock);
5082 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5083 		    uparms->rdc_set->secondary.file);
5084 		return (RDC_EALREADY);
5085 	}
5086 
5087 	mutex_exit(&rdc_conf_lock);
5088 
5089 	rdc_group_enter(krdc);
5090 	if (rdc_check(krdc, uparms->rdc_set)) {
5091 		rdc_group_exit(krdc);
5092 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5093 		    uparms->rdc_set->secondary.file);
5094 		rc = RDC_EALREADY;
5095 		goto done;
5096 	}
5097 	if ((rdc_get_vflags(urdc) & RDC_BMP_FAILED) && (krdc->bitmapfd))
5098 		(void) rdc_reset_bitmap(krdc);
5099 
5100 	/* Move to a new bitmap if necessary */
5101 	if (strncmp(urdc->primary.bitmap, uparms->rdc_set->primary.bitmap,
5102 	    NSC_MAXPATH) != 0) {
5103 		if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
5104 			rc = rdc_move_bitmap(krdc,
5105 			    uparms->rdc_set->primary.bitmap);
5106 		} else {
5107 			(void) strncpy(urdc->primary.bitmap,
5108 			    uparms->rdc_set->primary.bitmap, NSC_MAXPATH);
5109 			/* simulate a succesful rdc_move_bitmap */
5110 			rc = 0;
5111 		}
5112 	}
5113 	if (strncmp(urdc->secondary.bitmap, uparms->rdc_set->secondary.bitmap,
5114 	    NSC_MAXPATH) != 0) {
5115 		if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
5116 			(void) strncpy(urdc->secondary.bitmap,
5117 			    uparms->rdc_set->secondary.bitmap, NSC_MAXPATH);
5118 			/* simulate a succesful rdc_move_bitmap */
5119 			rc = 0;
5120 		} else {
5121 			rc = rdc_move_bitmap(krdc,
5122 			    uparms->rdc_set->secondary.bitmap);
5123 		}
5124 	}
5125 	if (rc == -1) {
5126 		rdc_group_exit(krdc);
5127 		spcs_s_add(kstatus, RDC_EBMPRECONFIG,
5128 		    uparms->rdc_set->secondary.intf,
5129 		    uparms->rdc_set->secondary.file);
5130 		rc = RDC_EBMPRECONFIG;
5131 		goto done;
5132 	}
5133 
5134 	/*
5135 	 * At this point we fail any other type of reconfig
5136 	 * if not in logging mode and we did not do a bitmap reconfig
5137 	 */
5138 
5139 	if (!(rdc_get_vflags(urdc) & RDC_LOGGING) && rc == -2) {
5140 		/* no other changes possible unless logging */
5141 		rdc_group_exit(krdc);
5142 		spcs_s_add(kstatus, RDC_ENOTLOGGING,
5143 		    uparms->rdc_set->primary.intf,
5144 		    uparms->rdc_set->primary.file,
5145 		    uparms->rdc_set->secondary.intf,
5146 		    uparms->rdc_set->secondary.file);
5147 		rc = RDC_ENOTLOGGING;
5148 		goto done;
5149 	}
5150 	rc = 0;
5151 	/* Change direct file if necessary */
5152 	if ((rdc_get_vflags(urdc) & RDC_PRIMARY) &&
5153 	    strncmp(urdc->direct_file, uparms->rdc_set->direct_file,
5154 	    NSC_MAXPATH)) {
5155 		if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) {
5156 			rdc_group_exit(krdc);
5157 			goto notlogging;
5158 		}
5159 		rdc_close_direct(krdc);
5160 		(void) strncpy(urdc->direct_file, uparms->rdc_set->direct_file,
5161 		    NSC_MAXPATH);
5162 
5163 		if (urdc->direct_file[0]) {
5164 			if (rdc_open_direct(krdc) == NULL)
5165 				rdc_set_flags(urdc, RDC_FCAL_FAILED);
5166 			else
5167 				rdc_clr_flags(urdc, RDC_FCAL_FAILED);
5168 		}
5169 	}
5170 
5171 	rdc_group_exit(krdc);
5172 
5173 	/* Change group if necessary */
5174 	if (strncmp(urdc->group_name, uparms->rdc_set->group_name,
5175 	    NSC_MAXPATH) != 0) {
5176 		char orig_group[NSC_MAXPATH];
5177 		if (!(rdc_get_vflags(urdc) & RDC_LOGGING))
5178 			goto notlogging;
5179 		mutex_enter(&rdc_conf_lock);
5180 
5181 		(void) strncpy(orig_group, urdc->group_name, NSC_MAXPATH);
5182 		(void) strncpy(urdc->group_name, uparms->rdc_set->group_name,
5183 		    NSC_MAXPATH);
5184 
5185 		rc = change_group(krdc, uparms->options);
5186 		if (rc == RDC_EQNOADD) {
5187 			mutex_exit(&rdc_conf_lock);
5188 			spcs_s_add(kstatus, RDC_EQNOADD,
5189 			    uparms->rdc_set->disk_queue);
5190 			goto done;
5191 		} else if (rc < 0) {
5192 			(void) strncpy(urdc->group_name, orig_group,
5193 			    NSC_MAXPATH);
5194 			mutex_exit(&rdc_conf_lock);
5195 			spcs_s_add(kstatus, RDC_EGROUP,
5196 			    urdc->primary.intf, urdc->primary.file,
5197 			    urdc->secondary.intf, urdc->secondary.file,
5198 			    uparms->rdc_set->group_name);
5199 			rc = RDC_EGROUP;
5200 			goto done;
5201 		}
5202 
5203 		mutex_exit(&rdc_conf_lock);
5204 
5205 		if (rc >= 0) {
5206 			if (!(rdc_get_vflags(urdc) & RDC_LOGGING))
5207 				goto notlogging;
5208 			if (uparms->options & RDC_OPT_ASYNC) {
5209 				mutex_enter(&rdc_conf_lock);
5210 				krdc->type_flag |= RDC_ASYNCMODE;
5211 				mutex_exit(&rdc_conf_lock);
5212 				if (uparms->options & RDC_OPT_PRIMARY)
5213 					krdc->bitmap_ref =
5214 					    (uchar_t *)kmem_zalloc(
5215 					    (krdc->bitmap_size * BITS_IN_BYTE *
5216 					    BMAP_REF_PREF_SIZE), KM_SLEEP);
5217 				rdc_group_enter(krdc);
5218 				rdc_set_flags(urdc, RDC_ASYNC);
5219 				rdc_group_exit(krdc);
5220 			} else {
5221 				mutex_enter(&rdc_conf_lock);
5222 				krdc->type_flag &= ~RDC_ASYNCMODE;
5223 				mutex_exit(&rdc_conf_lock);
5224 				rdc_group_enter(krdc);
5225 				rdc_clr_flags(urdc, RDC_ASYNC);
5226 				rdc_group_exit(krdc);
5227 				if (krdc->bitmap_ref) {
5228 					kmem_free(krdc->bitmap_ref,
5229 					    (krdc->bitmap_size * BITS_IN_BYTE *
5230 					    BMAP_REF_PREF_SIZE));
5231 					krdc->bitmap_ref = NULL;
5232 				}
5233 			}
5234 		}
5235 	} else {
5236 		if ((((uparms->options & RDC_OPT_ASYNC) == 0) &&
5237 		    ((krdc->type_flag & RDC_ASYNCMODE) != 0)) ||
5238 		    (((uparms->options & RDC_OPT_ASYNC) != 0) &&
5239 		    ((krdc->type_flag & RDC_ASYNCMODE) == 0))) {
5240 			if (!(rdc_get_vflags(urdc) & RDC_LOGGING))
5241 				goto notlogging;
5242 
5243 			if (krdc->group->count > 1) {
5244 				spcs_s_add(kstatus, RDC_EGROUPMODE);
5245 				rc = RDC_EGROUPMODE;
5246 				goto done;
5247 			}
5248 		}
5249 
5250 		/* Switch sync/async if necessary */
5251 		if (krdc->group->count == 1) {
5252 			/* Only member of group. Can change sync/async */
5253 			if (((uparms->options & RDC_OPT_ASYNC) == 0) &&
5254 			    ((krdc->type_flag & RDC_ASYNCMODE) != 0)) {
5255 				if (!(rdc_get_vflags(urdc) & RDC_LOGGING))
5256 					goto notlogging;
5257 				/* switch to sync */
5258 				mutex_enter(&rdc_conf_lock);
5259 				krdc->type_flag &= ~RDC_ASYNCMODE;
5260 				if (RDC_IS_DISKQ(krdc->group)) {
5261 					krdc->group->flags &= ~RDC_DISKQUE;
5262 					krdc->group->flags |= RDC_MEMQUE;
5263 					rdc_unintercept_diskq(krdc->group);
5264 					mutex_enter(&krdc->group->diskqmutex);
5265 					rdc_close_diskq(krdc->group);
5266 					mutex_exit(&krdc->group->diskqmutex);
5267 					bzero(&urdc->disk_queue,
5268 					    sizeof (urdc->disk_queue));
5269 				}
5270 				mutex_exit(&rdc_conf_lock);
5271 				rdc_group_enter(krdc);
5272 				rdc_clr_flags(urdc, RDC_ASYNC);
5273 				rdc_group_exit(krdc);
5274 				if (krdc->bitmap_ref) {
5275 					kmem_free(krdc->bitmap_ref,
5276 					    (krdc->bitmap_size * BITS_IN_BYTE *
5277 					    BMAP_REF_PREF_SIZE));
5278 					krdc->bitmap_ref = NULL;
5279 				}
5280 			} else if (((uparms->options & RDC_OPT_ASYNC) != 0) &&
5281 			    ((krdc->type_flag & RDC_ASYNCMODE) == 0)) {
5282 				if (!(rdc_get_vflags(urdc) & RDC_LOGGING))
5283 					goto notlogging;
5284 				/* switch to async */
5285 				mutex_enter(&rdc_conf_lock);
5286 				krdc->type_flag |= RDC_ASYNCMODE;
5287 				mutex_exit(&rdc_conf_lock);
5288 				if (uparms->options & RDC_OPT_PRIMARY)
5289 					krdc->bitmap_ref =
5290 					    (uchar_t *)kmem_zalloc(
5291 					    (krdc->bitmap_size * BITS_IN_BYTE *
5292 					    BMAP_REF_PREF_SIZE), KM_SLEEP);
5293 				rdc_group_enter(krdc);
5294 				rdc_set_flags(urdc, RDC_ASYNC);
5295 				rdc_group_exit(krdc);
5296 			}
5297 		}
5298 	}
5299 	/* Reverse concept of primary and secondary */
5300 	if ((uparms->options & RDC_OPT_REVERSE_ROLE) != 0) {
5301 		rdc_set_t rdc_set;
5302 		struct netbuf paddr, saddr;
5303 
5304 		mutex_enter(&rdc_conf_lock);
5305 
5306 		/*
5307 		 * Disallow role reversal for advanced configurations
5308 		 */
5309 
5310 		if (IS_MANY(krdc) || IS_MULTI(krdc)) {
5311 			mutex_exit(&rdc_conf_lock);
5312 			spcs_s_add(kstatus, RDC_EMASTER, urdc->primary.intf,
5313 			    urdc->primary.file, urdc->secondary.intf,
5314 			    urdc->secondary.file);
5315 			return (RDC_EMASTER);
5316 		}
5317 		bzero((void *) &rdc_set, sizeof (rdc_set_t));
5318 		dup_rdc_netbuf(&urdc->primary.addr, &saddr);
5319 		dup_rdc_netbuf(&urdc->secondary.addr, &paddr);
5320 		free_rdc_netbuf(&urdc->primary.addr);
5321 		free_rdc_netbuf(&urdc->secondary.addr);
5322 		dup_rdc_netbuf(&saddr, &urdc->secondary.addr);
5323 		dup_rdc_netbuf(&paddr, &urdc->primary.addr);
5324 		free_rdc_netbuf(&paddr);
5325 		free_rdc_netbuf(&saddr);
5326 		/* copy primary parts of urdc to rdc_set field by field */
5327 		(void) strncpy(rdc_set.primary.intf, urdc->primary.intf,
5328 		    MAX_RDC_HOST_SIZE);
5329 		(void) strncpy(rdc_set.primary.file, urdc->primary.file,
5330 		    NSC_MAXPATH);
5331 		(void) strncpy(rdc_set.primary.bitmap, urdc->primary.bitmap,
5332 		    NSC_MAXPATH);
5333 
5334 		/* Now overwrite urdc primary */
5335 		(void) strncpy(urdc->primary.intf, urdc->secondary.intf,
5336 		    MAX_RDC_HOST_SIZE);
5337 		(void) strncpy(urdc->primary.file, urdc->secondary.file,
5338 		    NSC_MAXPATH);
5339 		(void) strncpy(urdc->primary.bitmap, urdc->secondary.bitmap,
5340 		    NSC_MAXPATH);
5341 
5342 		/* Now ovwewrite urdc secondary */
5343 		(void) strncpy(urdc->secondary.intf, rdc_set.primary.intf,
5344 		    MAX_RDC_HOST_SIZE);
5345 		(void) strncpy(urdc->secondary.file, rdc_set.primary.file,
5346 		    NSC_MAXPATH);
5347 		(void) strncpy(urdc->secondary.bitmap, rdc_set.primary.bitmap,
5348 		    NSC_MAXPATH);
5349 
5350 		if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
5351 			rdc_clr_flags(urdc, RDC_PRIMARY);
5352 			if (krdc->intf) {
5353 				krdc->intf->issecondary = 1;
5354 				krdc->intf->isprimary = 0;
5355 				krdc->intf->if_down = 1;
5356 			}
5357 		} else {
5358 			rdc_set_flags(urdc, RDC_PRIMARY);
5359 			if (krdc->intf) {
5360 				krdc->intf->issecondary = 0;
5361 				krdc->intf->isprimary = 1;
5362 				krdc->intf->if_down = 1;
5363 			}
5364 		}
5365 
5366 		if ((rdc_get_vflags(urdc) & RDC_PRIMARY) &&
5367 		    ((krdc->type_flag & RDC_ASYNCMODE) != 0)) {
5368 			if (!krdc->bitmap_ref)
5369 				krdc->bitmap_ref =
5370 				    (uchar_t *)kmem_zalloc((krdc->bitmap_size *
5371 				    BITS_IN_BYTE * BMAP_REF_PREF_SIZE),
5372 				    KM_SLEEP);
5373 			if (krdc->bitmap_ref == NULL) {
5374 				cmn_err(CE_WARN,
5375 				    "!rdc_reconfig: bitmap_ref alloc %"
5376 				    NSC_SZFMT " failed",
5377 				    krdc->bitmap_size * BITS_IN_BYTE *
5378 				    BMAP_REF_PREF_SIZE);
5379 				mutex_exit(&rdc_conf_lock);
5380 				return (-1);
5381 			}
5382 		}
5383 
5384 		if ((rdc_get_vflags(urdc) & RDC_PRIMARY) &&
5385 		    (rdc_get_vflags(urdc) & RDC_SYNC_NEEDED)) {
5386 			/* Primary, so reverse sync needed */
5387 			rdc_many_enter(krdc);
5388 			rdc_clr_flags(urdc, RDC_SYNC_NEEDED);
5389 			rdc_set_mflags(urdc, RDC_RSYNC_NEEDED);
5390 			rdc_many_exit(krdc);
5391 		} else if (rdc_get_vflags(urdc) & RDC_RSYNC_NEEDED) {
5392 			/* Secondary, so forward sync needed */
5393 			rdc_many_enter(krdc);
5394 			rdc_clr_flags(urdc, RDC_RSYNC_NEEDED);
5395 			rdc_set_flags(urdc, RDC_SYNC_NEEDED);
5396 			rdc_many_exit(krdc);
5397 		}
5398 
5399 		/*
5400 		 * rewrite bitmap header
5401 		 */
5402 		rdc_write_state(urdc);
5403 		mutex_exit(&rdc_conf_lock);
5404 	}
5405 
5406 done:
5407 	mutex_enter(&rdc_conf_lock);
5408 	wakeup_busy(krdc);
5409 	mutex_exit(&rdc_conf_lock);
5410 
5411 	return (rc);
5412 
5413 notlogging:
5414 	/* no other changes possible unless logging */
5415 	mutex_enter(&rdc_conf_lock);
5416 	wakeup_busy(krdc);
5417 	mutex_exit(&rdc_conf_lock);
5418 	spcs_s_add(kstatus, RDC_ENOTLOGGING, urdc->primary.intf,
5419 	    urdc->primary.file, urdc->secondary.intf,
5420 	    urdc->secondary.file);
5421 	return (RDC_ENOTLOGGING);
5422 }
5423 
5424 static int
rdc_reset(rdc_config_t * uparms,spcs_s_info_t kstatus)5425 rdc_reset(rdc_config_t *uparms, spcs_s_info_t kstatus)
5426 {
5427 	rdc_k_info_t *krdc;
5428 	rdc_u_info_t *urdc;
5429 	int rc = 0;
5430 	int index;
5431 	int cleared_error = 0;
5432 
5433 	mutex_enter(&rdc_conf_lock);
5434 	index = rdc_lookup_byname(uparms->rdc_set);
5435 	if (index >= 0)
5436 		krdc = &rdc_k_info[index];
5437 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5438 		mutex_exit(&rdc_conf_lock);
5439 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5440 		    uparms->rdc_set->secondary.file);
5441 		return (RDC_EALREADY);
5442 	}
5443 
5444 	urdc = &rdc_u_info[index];
5445 	set_busy(krdc);
5446 	if (krdc->type_flag == 0) {
5447 		/* A resume or enable failed */
5448 		wakeup_busy(krdc);
5449 		mutex_exit(&rdc_conf_lock);
5450 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5451 		    uparms->rdc_set->secondary.file);
5452 		return (RDC_EALREADY);
5453 	}
5454 
5455 	mutex_exit(&rdc_conf_lock);
5456 
5457 	rdc_group_enter(krdc);
5458 	if (rdc_check(krdc, uparms->rdc_set)) {
5459 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5460 		    uparms->rdc_set->secondary.file);
5461 		rc = RDC_EALREADY;
5462 		goto done;
5463 	}
5464 
5465 	if ((rdc_get_vflags(urdc) & RDC_BMP_FAILED) && (krdc->bitmapfd)) {
5466 		if (rdc_reset_bitmap(krdc) == 0)
5467 			cleared_error++;
5468 	}
5469 
5470 	/* Fix direct file if necessary */
5471 	if ((rdc_get_vflags(urdc) & RDC_PRIMARY) && urdc->direct_file[0]) {
5472 		if (rdc_open_direct(krdc) == NULL)
5473 			rdc_set_flags(urdc, RDC_FCAL_FAILED);
5474 		else {
5475 			rdc_clr_flags(urdc, RDC_FCAL_FAILED);
5476 			cleared_error++;
5477 		}
5478 	}
5479 
5480 	if ((rdc_get_vflags(urdc) & RDC_VOL_FAILED)) {
5481 		rdc_many_enter(krdc);
5482 		rdc_clr_flags(urdc, RDC_VOL_FAILED);
5483 		cleared_error++;
5484 		rdc_many_exit(krdc);
5485 	}
5486 
5487 	if (cleared_error) {
5488 		/* cleared an error so we should be in logging mode */
5489 		rdc_set_flags_log(urdc, RDC_LOGGING, "set reset");
5490 	}
5491 	rdc_group_exit(krdc);
5492 
5493 	if ((rdc_get_vflags(urdc) & RDC_DISKQ_FAILED))
5494 		rdc_unfail_diskq(krdc);
5495 
5496 done:
5497 	mutex_enter(&rdc_conf_lock);
5498 	wakeup_busy(krdc);
5499 	mutex_exit(&rdc_conf_lock);
5500 
5501 	return (rc);
5502 }
5503 
5504 
5505 static int
rdc_tunable(rdc_config_t * uparms,spcs_s_info_t kstatus)5506 rdc_tunable(rdc_config_t *uparms, spcs_s_info_t kstatus)
5507 {
5508 	rdc_k_info_t *krdc;
5509 	rdc_u_info_t *urdc;
5510 	rdc_k_info_t *p;
5511 	rdc_u_info_t *q;
5512 	int rc = 0;
5513 	int index;
5514 
5515 	mutex_enter(&rdc_conf_lock);
5516 	index = rdc_lookup_byname(uparms->rdc_set);
5517 	if (index >= 0)
5518 		krdc = &rdc_k_info[index];
5519 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5520 		mutex_exit(&rdc_conf_lock);
5521 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5522 		    uparms->rdc_set->secondary.file);
5523 		return (RDC_EALREADY);
5524 	}
5525 
5526 	urdc = &rdc_u_info[index];
5527 	set_busy(krdc);
5528 	if (krdc->type_flag == 0) {
5529 		/* A resume or enable failed */
5530 		wakeup_busy(krdc);
5531 		mutex_exit(&rdc_conf_lock);
5532 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5533 		    uparms->rdc_set->secondary.file);
5534 		return (RDC_EALREADY);
5535 	}
5536 
5537 	mutex_exit(&rdc_conf_lock);
5538 
5539 	rdc_group_enter(krdc);
5540 	if (rdc_check(krdc, uparms->rdc_set)) {
5541 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5542 		    uparms->rdc_set->secondary.file);
5543 		rc = RDC_EALREADY;
5544 		goto done;
5545 	}
5546 
5547 	if (uparms->rdc_set->maxqfbas > 0) {
5548 		urdc->maxqfbas = uparms->rdc_set->maxqfbas;
5549 		rdc_write_state(urdc);
5550 		for (p = krdc->group_next; p != krdc; p = p->group_next) {
5551 			q = &rdc_u_info[p->index];
5552 			q->maxqfbas = urdc->maxqfbas;
5553 			rdc_write_state(q);
5554 		}
5555 	}
5556 
5557 	if (uparms->rdc_set->maxqitems > 0) {
5558 		urdc->maxqitems = uparms->rdc_set->maxqitems;
5559 		rdc_write_state(urdc);
5560 		for (p = krdc->group_next; p != krdc; p = p->group_next) {
5561 			q = &rdc_u_info[p->index];
5562 			q->maxqitems = urdc->maxqitems;
5563 			rdc_write_state(q);
5564 		}
5565 	}
5566 
5567 	if (uparms->options & RDC_OPT_SET_QNOBLOCK) {
5568 		disk_queue *que;
5569 
5570 		if (!RDC_IS_DISKQ(krdc->group)) {
5571 			spcs_s_add(kstatus, RDC_EQNOQUEUE, urdc->primary.intf,
5572 			    urdc->primary.file, urdc->secondary.intf,
5573 			    urdc->secondary.file);
5574 			rc = RDC_EQNOQUEUE;
5575 			goto done;
5576 		}
5577 
5578 		que = &krdc->group->diskq;
5579 		mutex_enter(QLOCK(que));
5580 		SET_QSTATE(que, RDC_QNOBLOCK);
5581 		/* queue will fail if this fails */
5582 		(void) rdc_stamp_diskq(krdc, 0, RDC_GROUP_LOCKED);
5583 		mutex_exit(QLOCK(que));
5584 
5585 	}
5586 
5587 	if (uparms->options & RDC_OPT_CLR_QNOBLOCK) {
5588 		disk_queue *que;
5589 
5590 		if (!RDC_IS_DISKQ(krdc->group)) {
5591 			spcs_s_add(kstatus, RDC_EQNOQUEUE, urdc->primary.intf,
5592 			    urdc->primary.file, urdc->secondary.intf,
5593 			    urdc->secondary.file);
5594 			rc = RDC_EQNOQUEUE;
5595 			goto done;
5596 		}
5597 		que = &krdc->group->diskq;
5598 		mutex_enter(QLOCK(que));
5599 		CLR_QSTATE(que, RDC_QNOBLOCK);
5600 		/* queue will fail if this fails */
5601 		(void) rdc_stamp_diskq(krdc, 0, RDC_GROUP_LOCKED);
5602 		mutex_exit(QLOCK(que));
5603 
5604 	}
5605 	if (uparms->rdc_set->asyncthr > 0) {
5606 		urdc->asyncthr = uparms->rdc_set->asyncthr;
5607 		rdc_write_state(urdc);
5608 		for (p = krdc->group_next; p != krdc; p = p->group_next) {
5609 			q = &rdc_u_info[p->index];
5610 			q->asyncthr = urdc->asyncthr;
5611 			rdc_write_state(q);
5612 		}
5613 	}
5614 
5615 	if (uparms->rdc_set->autosync >= 0) {
5616 		if (uparms->rdc_set->autosync == 0)
5617 			urdc->autosync = 0;
5618 		else
5619 			urdc->autosync = 1;
5620 
5621 		rdc_write_state(urdc);
5622 
5623 		/* Changed autosync, so update rest of the group */
5624 
5625 		for (p = krdc->group_next; p != krdc; p = p->group_next) {
5626 			q = &rdc_u_info[p->index];
5627 			q->autosync = urdc->autosync;
5628 			rdc_write_state(q);
5629 		}
5630 	}
5631 
5632 done:
5633 	rdc_group_exit(krdc);
5634 
5635 	mutex_enter(&rdc_conf_lock);
5636 	wakeup_busy(krdc);
5637 	mutex_exit(&rdc_conf_lock);
5638 
5639 	return (rc);
5640 }
5641 
5642 /*
5643  * Yet another standard thing that is not standard ...
5644  */
5645 #ifndef offsetof
5646 #define	offsetof(s, m)	((size_t)(&((s *)0)->m))
5647 #endif
5648 
5649 static int
rdc_status(void * arg,int mode,rdc_config_t * uparms,spcs_s_info_t kstatus)5650 rdc_status(void *arg, int mode, rdc_config_t *uparms, spcs_s_info_t kstatus)
5651 {
5652 	rdc_k_info_t *krdc;
5653 	rdc_u_info_t *urdc;
5654 	disk_queue *dqp;
5655 	int rc = 0;
5656 	int index;
5657 	char *ptr;
5658 	extern int rdc_status_copy32(const void *, void *, size_t, int);
5659 
5660 	mutex_enter(&rdc_conf_lock);
5661 	index = rdc_lookup_byname(uparms->rdc_set);
5662 	if (index >= 0)
5663 		krdc = &rdc_k_info[index];
5664 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5665 		mutex_exit(&rdc_conf_lock);
5666 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5667 		    uparms->rdc_set->secondary.file);
5668 		return (RDC_EALREADY);
5669 	}
5670 
5671 	set_busy(krdc);
5672 	if (krdc->type_flag == 0) {
5673 		/* A resume or enable failed */
5674 		wakeup_busy(krdc);
5675 		mutex_exit(&rdc_conf_lock);
5676 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5677 		    uparms->rdc_set->secondary.file);
5678 		return (RDC_EALREADY);
5679 	}
5680 
5681 	mutex_exit(&rdc_conf_lock);
5682 
5683 	rdc_group_enter(krdc);
5684 	if (rdc_check(krdc, uparms->rdc_set)) {
5685 		rdc_group_exit(krdc);
5686 		spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5687 		    uparms->rdc_set->secondary.file);
5688 		rc = RDC_EALREADY;
5689 		goto done;
5690 	}
5691 
5692 	urdc = &rdc_u_info[index];
5693 
5694 	/*
5695 	 * sneak out qstate in urdc->flags
5696 	 * this is harmless because it's value is not used
5697 	 * in urdc->flags. the real qstate is kept in
5698 	 * group->diskq->disk_hdr.h.state
5699 	 */
5700 	if (RDC_IS_DISKQ(krdc->group)) {
5701 		dqp = &krdc->group->diskq;
5702 		if (IS_QSTATE(dqp, RDC_QNOBLOCK))
5703 		urdc->flags |= RDC_QNOBLOCK;
5704 	}
5705 
5706 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
5707 		ptr = (char *)arg + offsetof(struct rdc_config32, rdc_set);
5708 		rc = rdc_status_copy32(urdc, ptr, sizeof (struct rdc_set32),
5709 		    mode);
5710 	} else {
5711 		ptr = (char *)arg + offsetof(struct rdc_config, rdc_set);
5712 		rc = ddi_copyout(urdc, ptr, sizeof (struct rdc_set), mode);
5713 	}
5714 	/* clear out qstate from flags */
5715 	urdc->flags &= ~RDC_QNOBLOCK;
5716 
5717 	if (rc)
5718 		rc = EFAULT;
5719 
5720 	rdc_group_exit(krdc);
5721 done:
5722 	mutex_enter(&rdc_conf_lock);
5723 	wakeup_busy(krdc);
5724 	mutex_exit(&rdc_conf_lock);
5725 
5726 	return (rc);
5727 }
5728 
5729 /*
5730  * Overwrite the bitmap with one supplied by the
5731  * user.
5732  * Copy into all bitmaps that are tracking this volume.
5733  */
5734 
5735 int
rdc_bitmapset(int op,char * sechost,char * secdev,void * bmapaddr,int bmapsz,nsc_off_t off,int mode)5736 rdc_bitmapset(int op, char *sechost, char *secdev, void *bmapaddr, int bmapsz,
5737     nsc_off_t off, int mode)
5738 {
5739 	int rc;
5740 	rdc_k_info_t *krdc;
5741 	int *indexvec;
5742 	int index;
5743 	int indexit;
5744 	kmutex_t **grouplocks;
5745 	int i;
5746 	int groupind;
5747 
5748 	if (off % FBA_SIZE(1)) {
5749 		/* Must be modulo FBA */
5750 		cmn_err(CE_WARN, "!bitmapset: Offset is not on an FBA "
5751 		    "boundary %llu", (unsigned long long)off);
5752 		return (EINVAL);
5753 	}
5754 	if (bmapsz % FBA_SIZE(1)) {
5755 		/* Must be modulo FBA */
5756 		cmn_err(CE_WARN, "!bitmapset: Size is not on an FBA "
5757 		    "boundary %d", bmapsz);
5758 		return (EINVAL);
5759 	}
5760 
5761 	mutex_enter(&rdc_conf_lock);
5762 	index = rdc_lookup_byhostdev(sechost, secdev);
5763 	if (index >= 0) {
5764 		krdc = &rdc_k_info[index];
5765 	}
5766 	if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5767 		rc = ENODEV;
5768 		mutex_exit(&rdc_conf_lock);
5769 		return (rc);
5770 	}
5771 	indexvec = kmem_alloc(rdc_max_sets * sizeof (int), KM_SLEEP);
5772 	grouplocks = kmem_alloc(rdc_max_sets * sizeof (kmutex_t *), KM_SLEEP);
5773 
5774 	/*
5775 	 * I now have this set, and I want to take the group
5776 	 * lock on it, and all the group locks of all the
5777 	 * sets on the many and multi-hop links.
5778 	 * I have to take the many lock while traversing the
5779 	 * many/multi links.
5780 	 * I think I also need to set the busy count on this
5781 	 * set, otherwise when I drop the conf_lock, what
5782 	 * will stop some other process from coming in and
5783 	 * issuing a disable?
5784 	 */
5785 	set_busy(krdc);
5786 	mutex_exit(&rdc_conf_lock);
5787 
5788 retrylock:
5789 	groupind = 0;
5790 	indexit = 0;
5791 	rdc_many_enter(krdc);
5792 	/*
5793 	 * Take this initial sets group lock first.
5794 	 */
5795 	if (!mutex_tryenter(&krdc->group->lock)) {
5796 		rdc_many_exit(krdc);
5797 		goto retrylock;
5798 	}
5799 
5800 	grouplocks[groupind] = &krdc->group->lock;
5801 	groupind++;
5802 
5803 	rc = rdc_checkforbitmap(index, off + bmapsz);
5804 	if (rc) {
5805 		goto done;
5806 	}
5807 	indexvec[indexit] = index;
5808 	indexit++;
5809 	if (IS_MANY(krdc)) {
5810 		rdc_k_info_t *ktmp;
5811 
5812 		for (ktmp = krdc->many_next; ktmp != krdc;
5813 		    ktmp =  ktmp->many_next) {
5814 			/*
5815 			 * attempt to take the group lock,
5816 			 * if we don't already have it.
5817 			 */
5818 			if (ktmp->group == NULL) {
5819 				rc = ENODEV;
5820 				goto done;
5821 			}
5822 			for (i = 0; i < groupind; i++) {
5823 				if (grouplocks[i] == &ktmp->group->lock)
5824 					/* already have the group lock */
5825 					break;
5826 			}
5827 			/*
5828 			 * didn't find our lock in our collection,
5829 			 * attempt to take group lock.
5830 			 */
5831 			if (i >= groupind) {
5832 				if (!mutex_tryenter(&ktmp->group->lock)) {
5833 					for (i = 0; i < groupind; i++) {
5834 						mutex_exit(grouplocks[i]);
5835 					}
5836 					rdc_many_exit(krdc);
5837 					goto retrylock;
5838 				}
5839 				grouplocks[groupind] = &ktmp->group->lock;
5840 				groupind++;
5841 			}
5842 			rc = rdc_checkforbitmap(ktmp->index, off + bmapsz);
5843 			if (rc == 0) {
5844 				indexvec[indexit] = ktmp->index;
5845 				indexit++;
5846 			} else {
5847 				goto done;
5848 			}
5849 		}
5850 	}
5851 	if (IS_MULTI(krdc)) {
5852 		rdc_k_info_t *kmulti = krdc->multi_next;
5853 
5854 		if (kmulti->group == NULL) {
5855 			rc = ENODEV;
5856 			goto done;
5857 		}
5858 		/*
5859 		 * This can't be in our group already.
5860 		 */
5861 		if (!mutex_tryenter(&kmulti->group->lock)) {
5862 			for (i = 0; i < groupind; i++) {
5863 				mutex_exit(grouplocks[i]);
5864 			}
5865 			rdc_many_exit(krdc);
5866 			goto retrylock;
5867 		}
5868 		grouplocks[groupind] = &kmulti->group->lock;
5869 		groupind++;
5870 
5871 		rc = rdc_checkforbitmap(kmulti->index, off + bmapsz);
5872 		if (rc == 0) {
5873 			indexvec[indexit] = kmulti->index;
5874 			indexit++;
5875 		} else {
5876 			goto done;
5877 		}
5878 	}
5879 	rc = rdc_installbitmap(op, bmapaddr, bmapsz, off, mode, indexvec,
5880 	    indexit);
5881 done:
5882 	for (i = 0; i < groupind; i++) {
5883 		mutex_exit(grouplocks[i]);
5884 	}
5885 	rdc_many_exit(krdc);
5886 	mutex_enter(&rdc_conf_lock);
5887 	wakeup_busy(krdc);
5888 	mutex_exit(&rdc_conf_lock);
5889 	kmem_free(indexvec, rdc_max_sets * sizeof (int));
5890 	kmem_free(grouplocks, rdc_max_sets * sizeof (kmutex_t *));
5891 	return (rc);
5892 }
5893 
5894 static int
rdc_checkforbitmap(int index,nsc_off_t limit)5895 rdc_checkforbitmap(int index, nsc_off_t limit)
5896 {
5897 	rdc_k_info_t *krdc;
5898 	rdc_u_info_t *urdc;
5899 
5900 	krdc = &rdc_k_info[index];
5901 	urdc = &rdc_u_info[index];
5902 
5903 	if (!IS_ENABLED(urdc)) {
5904 		return (EIO);
5905 	}
5906 	if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) {
5907 		return (ENXIO);
5908 	}
5909 	if (krdc->dcio_bitmap == NULL) {
5910 		cmn_err(CE_WARN, "!checkforbitmap: No bitmap for set (%s:%s)",
5911 		    urdc->secondary.intf, urdc->secondary.file);
5912 		return (ENOENT);
5913 	}
5914 	if (limit > krdc->bitmap_size) {
5915 		cmn_err(CE_WARN, "!checkbitmap: Bitmap exceeded, "
5916 		    "incore %" NSC_SZFMT " user supplied %" NSC_SZFMT
5917 		    " for set (%s:%s)", krdc->bitmap_size,
5918 		    limit, urdc->secondary.intf, urdc->secondary.file);
5919 		return (ENOSPC);
5920 	}
5921 	return (0);
5922 }
5923 
5924 
5925 
5926 /*
5927  * Copy the user supplied bitmap to this set.
5928  */
5929 static int
rdc_installbitmap(int op,void * bmapaddr,int bmapsz,nsc_off_t off,int mode,int * vec,int veccnt)5930 rdc_installbitmap(int op, void *bmapaddr, int bmapsz,
5931     nsc_off_t off, int mode, int *vec, int veccnt)
5932 {
5933 	int rc;
5934 	nsc_off_t sfba;
5935 	nsc_off_t efba;
5936 	nsc_off_t fba;
5937 	void *ormem = NULL;
5938 	int len;
5939 	int left;
5940 	int copied;
5941 	int index;
5942 	rdc_k_info_t *krdc;
5943 	rdc_u_info_t *urdc;
5944 
5945 	rc = 0;
5946 	ormem = kmem_alloc(RDC_MAXDATA, KM_SLEEP);
5947 	left = bmapsz;
5948 	copied = 0;
5949 	while (left > 0) {
5950 		if (left > RDC_MAXDATA) {
5951 			len = RDC_MAXDATA;
5952 		} else {
5953 			len = left;
5954 		}
5955 		if (ddi_copyin((char *)bmapaddr + copied, ormem,
5956 		    len, mode)) {
5957 			cmn_err(CE_WARN, "!installbitmap: Copyin failed");
5958 			rc = EFAULT;
5959 			goto out;
5960 		}
5961 		sfba = FBA_NUM(off + copied);
5962 		efba = FBA_NUM(off + copied + len);
5963 		for (index = 0; index < veccnt; index++) {
5964 			krdc = &rdc_k_info[vec[index]];
5965 			urdc = &rdc_u_info[vec[index]];
5966 
5967 			mutex_enter(&krdc->bmapmutex);
5968 			if (op == RDC_BITMAPSET) {
5969 				bcopy(ormem, krdc->dcio_bitmap + off + copied,
5970 				    len);
5971 			} else {
5972 				rdc_lor(ormem,
5973 				    krdc->dcio_bitmap + off + copied, len);
5974 			}
5975 			/*
5976 			 * Maybe this should be just done once outside of
5977 			 * the the loop? (Less work, but leaves a window
5978 			 * where the bits_set doesn't match the bitmap).
5979 			 */
5980 			urdc->bits_set = RDC_COUNT_BITMAP(krdc);
5981 			mutex_exit(&krdc->bmapmutex);
5982 			if (krdc->bitmap_write > 0) {
5983 				for (fba = sfba; fba < efba; fba++) {
5984 					if (rc = rdc_write_bitmap_fba(krdc,
5985 					    fba)) {
5986 
5987 						cmn_err(CE_WARN,
5988 						    "!installbitmap: "
5989 						    "write_bitmap_fba failed "
5990 						    "on fba number %" NSC_SZFMT
5991 						    " set %s:%s", fba,
5992 						    urdc->secondary.intf,
5993 						    urdc->secondary.file);
5994 						goto out;
5995 					}
5996 				}
5997 			}
5998 		}
5999 		copied += len;
6000 		left -= len;
6001 	}
6002 out:
6003 	kmem_free(ormem, RDC_MAXDATA);
6004 	return (rc);
6005 }
6006 
6007 /*
6008  * _rdc_config
6009  */
6010 int
_rdc_config(void * arg,int mode,spcs_s_info_t kstatus,int * rvp)6011 _rdc_config(void *arg, int mode, spcs_s_info_t kstatus, int *rvp)
6012 {
6013 	int rc = 0;
6014 	struct netbuf fsvaddr, tsvaddr;
6015 	struct knetconfig *knconf;
6016 	char *p = NULL, *pf = NULL;
6017 	struct rdc_config *uap;
6018 	STRUCT_DECL(knetconfig, knconf_tmp);
6019 	STRUCT_DECL(rdc_config, uparms);
6020 	int enable, disable;
6021 	int cmd;
6022 
6023 
6024 	STRUCT_HANDLE(rdc_set, rs);
6025 	STRUCT_HANDLE(rdc_addr, pa);
6026 	STRUCT_HANDLE(rdc_addr, sa);
6027 
6028 	STRUCT_INIT(uparms, mode);
6029 
6030 	bzero(STRUCT_BUF(uparms), STRUCT_SIZE(uparms));
6031 	bzero(&fsvaddr, sizeof (fsvaddr));
6032 	bzero(&tsvaddr, sizeof (tsvaddr));
6033 
6034 	knconf = NULL;
6035 
6036 	if (ddi_copyin(arg, STRUCT_BUF(uparms), STRUCT_SIZE(uparms), mode)) {
6037 		return (EFAULT);
6038 	}
6039 
6040 	STRUCT_SET_HANDLE(rs, mode, STRUCT_FGETP(uparms, rdc_set));
6041 	STRUCT_SET_HANDLE(pa, mode, STRUCT_FADDR(rs, primary));
6042 	STRUCT_SET_HANDLE(sa, mode, STRUCT_FADDR(rs, secondary));
6043 	cmd = STRUCT_FGET(uparms, command);
6044 	if (cmd == RDC_CMD_ENABLE || cmd == RDC_CMD_RESUME) {
6045 		fsvaddr.len = STRUCT_FGET(pa, addr.len);
6046 		fsvaddr.maxlen = STRUCT_FGET(pa, addr.maxlen);
6047 		fsvaddr.buf =  kmem_zalloc(fsvaddr.len, KM_SLEEP);
6048 
6049 		if (ddi_copyin(STRUCT_FGETP(pa, addr.buf),
6050 		    fsvaddr.buf, fsvaddr.len, mode)) {
6051 			kmem_free(fsvaddr.buf, fsvaddr.len);
6052 #ifdef DEBUG
6053 			cmn_err(CE_WARN, "!copyin failed primary.addr 2");
6054 #endif
6055 			return (EFAULT);
6056 		}
6057 
6058 
6059 		tsvaddr.len = STRUCT_FGET(sa, addr.len);
6060 		tsvaddr.maxlen = STRUCT_FGET(sa, addr.maxlen);
6061 		tsvaddr.buf =  kmem_zalloc(tsvaddr.len, KM_SLEEP);
6062 
6063 		if (ddi_copyin(STRUCT_FGETP(sa, addr.buf),
6064 		    tsvaddr.buf, tsvaddr.len, mode)) {
6065 #ifdef DEBUG
6066 			cmn_err(CE_WARN, "!copyin failed secondary addr");
6067 #endif
6068 			kmem_free(fsvaddr.buf, fsvaddr.len);
6069 			kmem_free(tsvaddr.buf, tsvaddr.len);
6070 			return (EFAULT);
6071 		}
6072 	} else {
6073 		fsvaddr.len = 0;
6074 		fsvaddr.maxlen = 0;
6075 		fsvaddr.buf =  kmem_zalloc(fsvaddr.len, KM_SLEEP);
6076 		tsvaddr.len = 0;
6077 		tsvaddr.maxlen = 0;
6078 		tsvaddr.buf =  kmem_zalloc(tsvaddr.len, KM_SLEEP);
6079 	}
6080 
6081 	if (STRUCT_FGETP(uparms, rdc_set->netconfig) != NULL) {
6082 		STRUCT_INIT(knconf_tmp, mode);
6083 		knconf = kmem_zalloc(sizeof (*knconf), KM_SLEEP);
6084 		if (ddi_copyin(STRUCT_FGETP(uparms, rdc_set->netconfig),
6085 		    STRUCT_BUF(knconf_tmp), STRUCT_SIZE(knconf_tmp), mode)) {
6086 #ifdef DEBUG
6087 			cmn_err(CE_WARN, "!copyin failed netconfig");
6088 #endif
6089 			kmem_free(fsvaddr.buf, fsvaddr.len);
6090 			kmem_free(tsvaddr.buf, tsvaddr.len);
6091 			kmem_free(knconf, sizeof (*knconf));
6092 			return (EFAULT);
6093 		}
6094 
6095 		knconf->knc_semantics = STRUCT_FGET(knconf_tmp, knc_semantics);
6096 		knconf->knc_protofmly = STRUCT_FGETP(knconf_tmp, knc_protofmly);
6097 		knconf->knc_proto = STRUCT_FGETP(knconf_tmp, knc_proto);
6098 
6099 #ifndef _SunOS_5_6
6100 		if ((mode & DATAMODEL_LP64) == 0) {
6101 			knconf->knc_rdev =
6102 			    expldev(STRUCT_FGET(knconf_tmp, knc_rdev));
6103 		} else {
6104 #endif
6105 			knconf->knc_rdev = STRUCT_FGET(knconf_tmp, knc_rdev);
6106 #ifndef _SunOS_5_6
6107 		}
6108 #endif
6109 
6110 		pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
6111 		p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
6112 		rc = ddi_copyin(knconf->knc_protofmly, pf, KNC_STRSIZE, mode);
6113 		if (rc) {
6114 #ifdef DEBUG
6115 			cmn_err(CE_WARN, "!copyin failed parms protofmly");
6116 #endif
6117 			rc = EFAULT;
6118 			goto out;
6119 		}
6120 		rc = ddi_copyin(knconf->knc_proto, p, KNC_STRSIZE, mode);
6121 		if (rc) {
6122 #ifdef DEBUG
6123 			cmn_err(CE_WARN, "!copyin failed parms proto");
6124 #endif
6125 			rc = EFAULT;
6126 			goto out;
6127 		}
6128 		knconf->knc_protofmly = pf;
6129 		knconf->knc_proto = p;
6130 	} /* !NULL netconfig */
6131 
6132 	uap = kmem_alloc(sizeof (*uap), KM_SLEEP);
6133 
6134 	/* copy relevant parts of rdc_config to uap field by field */
6135 
6136 	(void) strncpy(uap->rdc_set[0].primary.intf, STRUCT_FGETP(pa, intf),
6137 	    MAX_RDC_HOST_SIZE);
6138 	(void) strncpy(uap->rdc_set[0].primary.file, STRUCT_FGETP(pa, file),
6139 	    NSC_MAXPATH);
6140 	(void) strncpy(uap->rdc_set[0].primary.bitmap, STRUCT_FGETP(pa, bitmap),
6141 	    NSC_MAXPATH);
6142 	uap->rdc_set[0].netconfig = knconf;
6143 	uap->rdc_set[0].flags = STRUCT_FGET(uparms, rdc_set->flags);
6144 	uap->rdc_set[0].index = STRUCT_FGET(uparms, rdc_set->index);
6145 	uap->rdc_set[0].setid = STRUCT_FGET(uparms, rdc_set->setid);
6146 	uap->rdc_set[0].sync_pos = STRUCT_FGET(uparms, rdc_set->sync_pos);
6147 	uap->rdc_set[0].volume_size = STRUCT_FGET(uparms, rdc_set->volume_size);
6148 	uap->rdc_set[0].bits_set = STRUCT_FGET(uparms, rdc_set->bits_set);
6149 	uap->rdc_set[0].autosync = STRUCT_FGET(uparms, rdc_set->autosync);
6150 	uap->rdc_set[0].maxqfbas = STRUCT_FGET(uparms, rdc_set->maxqfbas);
6151 	uap->rdc_set[0].maxqitems = STRUCT_FGET(uparms, rdc_set->maxqitems);
6152 	uap->rdc_set[0].asyncthr = STRUCT_FGET(uparms, rdc_set->asyncthr);
6153 	uap->rdc_set[0].syshostid = STRUCT_FGET(uparms, rdc_set->syshostid);
6154 	uap->rdc_set[0].primary.addr = fsvaddr;		/* struct copy */
6155 	uap->rdc_set[0].secondary.addr = tsvaddr;	/* struct copy */
6156 
6157 	(void) strncpy(uap->rdc_set[0].secondary.intf, STRUCT_FGETP(sa, intf),
6158 	    MAX_RDC_HOST_SIZE);
6159 	(void) strncpy(uap->rdc_set[0].secondary.file, STRUCT_FGETP(sa, file),
6160 	    NSC_MAXPATH);
6161 	(void) strncpy(uap->rdc_set[0].secondary.bitmap,
6162 	    STRUCT_FGETP(sa, bitmap), NSC_MAXPATH);
6163 
6164 	(void) strncpy(uap->rdc_set[0].direct_file,
6165 	    STRUCT_FGETP(rs, direct_file), NSC_MAXPATH);
6166 
6167 	(void) strncpy(uap->rdc_set[0].group_name, STRUCT_FGETP(rs, group_name),
6168 	    NSC_MAXPATH);
6169 
6170 	(void) strncpy(uap->rdc_set[0].disk_queue, STRUCT_FGETP(rs, disk_queue),
6171 	    NSC_MAXPATH);
6172 
6173 	uap->command = STRUCT_FGET(uparms, command);
6174 	uap->options = STRUCT_FGET(uparms, options);
6175 
6176 	enable = (uap->command == RDC_CMD_ENABLE ||
6177 	    uap->command == RDC_CMD_RESUME);
6178 	disable = (uap->command == RDC_CMD_DISABLE ||
6179 	    uap->command == RDC_CMD_SUSPEND);
6180 
6181 	/*
6182 	 * Initialise the threadset if it has not already been done.
6183 	 *
6184 	 * This has to be done now, not in rdcattach(), because
6185 	 * rdcattach() can be called before nskernd is running (eg.
6186 	 * boot -r) in which case the nst_init() would fail and hence
6187 	 * the attach would fail.
6188 	 *
6189 	 * Threadset creation is locked by the rdc_conf_lock,
6190 	 * destruction is inherently single threaded as it is done in
6191 	 * _rdc_unload() which must be the last thing performed by
6192 	 * rdcdetach().
6193 	 */
6194 
6195 	if (enable && _rdc_ioset == NULL) {
6196 		mutex_enter(&rdc_conf_lock);
6197 
6198 		if (_rdc_ioset == NULL) {
6199 			rc = rdc_thread_configure();
6200 		}
6201 
6202 		mutex_exit(&rdc_conf_lock);
6203 
6204 		if (rc || _rdc_ioset == NULL) {
6205 			spcs_s_add(kstatus, RDC_ENOTHREADS);
6206 			rc = RDC_ENOTHREADS;
6207 			goto outuap;
6208 		}
6209 	}
6210 	switch (uap->command) {
6211 	case RDC_CMD_ENABLE:
6212 		rc = rdc_enable(uap, kstatus);
6213 		break;
6214 	case RDC_CMD_DISABLE:
6215 		rc = rdc_disable(uap, kstatus);
6216 		break;
6217 	case RDC_CMD_COPY:
6218 		rc = rdc_sync(uap, kstatus);
6219 		break;
6220 	case RDC_CMD_LOG:
6221 		rc = rdc_log(uap, kstatus);
6222 		break;
6223 	case RDC_CMD_RECONFIG:
6224 		rc = rdc_reconfig(uap, kstatus);
6225 		break;
6226 	case RDC_CMD_RESUME:
6227 		rc = rdc_resume(uap, kstatus);
6228 		break;
6229 	case RDC_CMD_SUSPEND:
6230 		rc = rdc_suspend(uap, kstatus);
6231 		break;
6232 	case RDC_CMD_TUNABLE:
6233 		rc = rdc_tunable(uap, kstatus);
6234 		break;
6235 	case RDC_CMD_WAIT:
6236 		rc = rdc_wait(uap, kstatus);
6237 		break;
6238 	case RDC_CMD_HEALTH:
6239 		rc = rdc_health(uap, kstatus, rvp);
6240 		break;
6241 	case RDC_CMD_STATUS:
6242 		rc = rdc_status(arg, mode, uap, kstatus);
6243 		break;
6244 	case RDC_CMD_RESET:
6245 		rc = rdc_reset(uap, kstatus);
6246 		break;
6247 	case RDC_CMD_ADDQ:
6248 		rc = rdc_add_diskq(uap, kstatus);
6249 		break;
6250 	case RDC_CMD_REMQ:
6251 		if ((rc = rdc_rem_diskq(uap, kstatus)) != 0)
6252 			break;
6253 		/* FALLTHRU */
6254 	case RDC_CMD_KILLQ:
6255 		rc = rdc_kill_diskq(uap, kstatus);
6256 		break;
6257 	case RDC_CMD_INITQ:
6258 		rc = rdc_init_diskq(uap, kstatus);
6259 		break;
6260 
6261 	default:
6262 		rc = EINVAL;
6263 		break;
6264 	}
6265 
6266 	/*
6267 	 * Tune the threadset size after a successful rdc_set addition
6268 	 * or removal.
6269 	 */
6270 	if ((enable || disable) && rc == 0) {
6271 		mutex_enter(&rdc_conf_lock);
6272 		rdc_thread_tune(enable ? 2 : -2);
6273 		mutex_exit(&rdc_conf_lock);
6274 	}
6275 outuap:
6276 	kmem_free(uap, sizeof (*uap));
6277 out:
6278 	kmem_free(fsvaddr.buf, fsvaddr.len);
6279 	kmem_free(tsvaddr.buf, tsvaddr.len);
6280 	if (pf)
6281 		kmem_free(pf, KNC_STRSIZE);
6282 	if (p)
6283 		kmem_free(p, KNC_STRSIZE);
6284 	if (knconf)
6285 		kmem_free(knconf, sizeof (*knconf));
6286 	return (rc);
6287 }
6288 
6289 
6290 /*
6291  * krdc->group->lock held on entry to halt_sync()
6292  */
6293 static void
halt_sync(rdc_k_info_t * krdc)6294 halt_sync(rdc_k_info_t *krdc)
6295 {
6296 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
6297 
6298 	ASSERT(MUTEX_HELD(&krdc->group->lock));
6299 	ASSERT(IS_ENABLED(urdc));
6300 
6301 	/*
6302 	 * If a sync is in progress, halt it
6303 	 */
6304 	if ((rdc_get_vflags(urdc) & RDC_PRIMARY) &&
6305 	    (krdc->aux_state & RDC_AUXSYNCIP)) {
6306 		krdc->disk_status = 1;
6307 
6308 		while (krdc->disk_status == 1) {
6309 			if (cv_wait_sig(&krdc->haltcv, &krdc->group->lock) == 0)
6310 				break;
6311 		}
6312 	}
6313 }
6314 
6315 /*
6316  * return size in blocks
6317  */
6318 uint64_t
mirror_getsize(int index)6319 mirror_getsize(int index)
6320 {
6321 	rdc_k_info_t *krdc;
6322 	rdc_u_info_t *urdc;
6323 	int rc, rs;
6324 	nsc_size_t size;
6325 
6326 	krdc = &rdc_k_info[index];
6327 	urdc = &rdc_u_info[index];
6328 
6329 	rc = _rdc_rsrv_devs(krdc, RDC_RAW, RDC_INTERNAL);
6330 	rs = nsc_partsize(RDC_U_FD(krdc), &size);
6331 	urdc->volume_size = size;
6332 	if (rc == 0)
6333 		_rdc_rlse_devs(krdc, RDC_RAW);
6334 
6335 	return (rs == 0 ? urdc->volume_size : 0);
6336 }
6337 
6338 
6339 /*
6340  * Create a new dataset for this transfer, and add it to the list
6341  * of datasets via the net_dataset pointer in the krdc.
6342  */
6343 rdc_net_dataset_t *
rdc_net_add_set(int index)6344 rdc_net_add_set(int index)
6345 {
6346 	rdc_k_info_t *krdc;
6347 	rdc_u_info_t *urdc;
6348 	rdc_net_dataset_t *dset;
6349 
6350 	if (index >= rdc_max_sets) {
6351 		cmn_err(CE_NOTE, "!rdc_net_add_set: bad index %d", index);
6352 		return (NULL);
6353 	}
6354 	krdc = &rdc_k_info[index];
6355 	urdc = &rdc_u_info[index];
6356 
6357 	dset = kmem_alloc(sizeof (*dset), KM_NOSLEEP);
6358 	if (dset == NULL) {
6359 		cmn_err(CE_NOTE, "!rdc_net_add_set: kmem_alloc failed");
6360 		return (NULL);
6361 	}
6362 	RDC_DSMEMUSE(sizeof (*dset));
6363 	dset->inuse = 1;
6364 	dset->nitems = 0;
6365 	dset->delpend = 0;
6366 	dset->head = NULL;
6367 	dset->tail = NULL;
6368 	mutex_enter(&krdc->dc_sleep);
6369 
6370 	if (!IS_ENABLED(urdc)) {
6371 		/* raced with a disable command */
6372 		kmem_free(dset, sizeof (*dset));
6373 		RDC_DSMEMUSE(-sizeof (*dset));
6374 		mutex_exit(&krdc->dc_sleep);
6375 		return (NULL);
6376 	}
6377 	/*
6378 	 * Shared the id generator, (and the locks).
6379 	 */
6380 	mutex_enter(&rdc_net_hnd_id_lock);
6381 	if (++rdc_net_hnd_id == 0)
6382 		rdc_net_hnd_id = 1;
6383 	dset->id = rdc_net_hnd_id;
6384 	mutex_exit(&rdc_net_hnd_id_lock);
6385 
6386 #ifdef DEBUG
6387 	if (krdc->net_dataset != NULL) {
6388 		rdc_net_dataset_t *dset2;
6389 		for (dset2 = krdc->net_dataset; dset2; dset2 = dset2->next) {
6390 			if (dset2->id == dset->id) {
6391 				cmn_err(CE_PANIC,
6392 				    "rdc_net_add_set duplicate id %p:%d %p:%d",
6393 				    (void *)dset, dset->id,
6394 				    (void *)dset2, dset2->id);
6395 			}
6396 		}
6397 	}
6398 #endif
6399 	dset->next = krdc->net_dataset;
6400 	krdc->net_dataset = dset;
6401 	mutex_exit(&krdc->dc_sleep);
6402 
6403 	return (dset);
6404 }
6405 
6406 /*
6407  * fetch the previously added dataset.
6408  */
6409 rdc_net_dataset_t *
rdc_net_get_set(int index,int id)6410 rdc_net_get_set(int index, int id)
6411 {
6412 	rdc_k_info_t *krdc;
6413 	rdc_net_dataset_t *dset;
6414 
6415 	if (index >= rdc_max_sets) {
6416 		cmn_err(CE_NOTE, "!rdc_net_get_set: bad index %d", index);
6417 		return (NULL);
6418 	}
6419 	krdc = &rdc_k_info[index];
6420 
6421 	mutex_enter(&krdc->dc_sleep);
6422 
6423 	dset = krdc->net_dataset;
6424 	while (dset && (dset->id != id))
6425 		dset = dset->next;
6426 
6427 	if (dset) {
6428 		dset->inuse++;
6429 	}
6430 
6431 	mutex_exit(&krdc->dc_sleep);
6432 	return (dset);
6433 }
6434 
6435 /*
6436  * Decrement the inuse counter. Data may be freed.
6437  */
6438 void
rdc_net_put_set(int index,rdc_net_dataset_t * dset)6439 rdc_net_put_set(int index, rdc_net_dataset_t *dset)
6440 {
6441 	rdc_k_info_t *krdc;
6442 
6443 	if (index >= rdc_max_sets) {
6444 		cmn_err(CE_NOTE, "!rdc_net_put_set: bad index %d", index);
6445 		return;
6446 	}
6447 	krdc = &rdc_k_info[index];
6448 
6449 	mutex_enter(&krdc->dc_sleep);
6450 	dset->inuse--;
6451 	ASSERT(dset->inuse >= 0);
6452 	if ((dset->inuse == 0) && (dset->delpend)) {
6453 		rdc_net_free_set(krdc, dset);
6454 	}
6455 	mutex_exit(&krdc->dc_sleep);
6456 }
6457 
6458 /*
6459  * Mark that we are finished with this set. Decrement inuse
6460  * counter, mark as needing deletion, and
6461  * remove from linked list.
6462  */
6463 void
rdc_net_del_set(int index,rdc_net_dataset_t * dset)6464 rdc_net_del_set(int index, rdc_net_dataset_t *dset)
6465 {
6466 	rdc_k_info_t *krdc;
6467 
6468 	if (index >= rdc_max_sets) {
6469 		cmn_err(CE_NOTE, "!rdc_net_del_set: bad index %d", index);
6470 		return;
6471 	}
6472 	krdc = &rdc_k_info[index];
6473 
6474 	mutex_enter(&krdc->dc_sleep);
6475 	dset->inuse--;
6476 	ASSERT(dset->inuse >= 0);
6477 	dset->delpend = 1;
6478 	if (dset->inuse == 0) {
6479 		rdc_net_free_set(krdc, dset);
6480 	}
6481 	mutex_exit(&krdc->dc_sleep);
6482 }
6483 
6484 /*
6485  * free all the memory associated with this set, and remove from
6486  * list.
6487  * Enters and exits with dc_sleep lock held.
6488  */
6489 
6490 void
rdc_net_free_set(rdc_k_info_t * krdc,rdc_net_dataset_t * dset)6491 rdc_net_free_set(rdc_k_info_t *krdc, rdc_net_dataset_t *dset)
6492 {
6493 	rdc_net_dataset_t **dsetp;
6494 #ifdef DEBUG
6495 	int found = 0;
6496 #endif
6497 
6498 	ASSERT(MUTEX_HELD(&krdc->dc_sleep));
6499 	ASSERT(dset);
6500 	for (dsetp = &krdc->net_dataset; *dsetp; dsetp = &((*dsetp)->next)) {
6501 		if (*dsetp == dset) {
6502 			*dsetp = dset->next;
6503 #ifdef DEBUG
6504 			found = 1;
6505 #endif
6506 			break;
6507 		}
6508 	}
6509 
6510 #ifdef DEBUG
6511 	if (found == 0) {
6512 		cmn_err(CE_WARN, "!rdc_net_free_set: Unable to find "
6513 		    "dataset 0x%p in krdc list", (void *)dset);
6514 	}
6515 #endif
6516 	/*
6517 	 * unlinked from list. Free all the data
6518 	 */
6519 	rdc_ditemsfree(dset);
6520 	/*
6521 	 * free my core.
6522 	 */
6523 	kmem_free(dset, sizeof (*dset));
6524 	RDC_DSMEMUSE(-sizeof (*dset));
6525 }
6526 
6527 
6528 /*
6529  * Free all the dataitems and the data it points to.
6530  */
6531 static void
rdc_ditemsfree(rdc_net_dataset_t * dset)6532 rdc_ditemsfree(rdc_net_dataset_t *dset)
6533 {
6534 	rdc_net_dataitem_t *ditem;
6535 	rdc_net_dataitem_t *nitem;
6536 
6537 	ditem = dset->head;
6538 
6539 	while (ditem) {
6540 		nitem = ditem->next;
6541 		kmem_free(ditem->dptr, ditem->mlen);
6542 		RDC_DSMEMUSE(-ditem->mlen);
6543 		dset->nitems--;
6544 		kmem_free(ditem, sizeof (*ditem));
6545 		RDC_DSMEMUSE(-sizeof (*ditem));
6546 		ditem = nitem;
6547 	}
6548 	ASSERT(dset->nitems == 0);
6549 }
6550 
6551 /*
6552  * allocate and initialize a rdc_aio_t
6553  */
6554 rdc_aio_t *
rdc_aio_tbuf_get(void * n,void * h,int pos,int len,int flag,int index,int s)6555 rdc_aio_tbuf_get(void *n, void *h, int pos, int len, int flag, int index, int s)
6556 {
6557 	rdc_aio_t *p;
6558 
6559 	p = kmem_zalloc(sizeof (rdc_aio_t), KM_NOSLEEP);
6560 	if (p == NULL) {
6561 #ifdef DEBUG
6562 		cmn_err(CE_NOTE, "!_rdcaiotbufget: kmem_alloc failed bp aio");
6563 #endif
6564 		return (NULL);
6565 	} else {
6566 		p->next = n; /* overload */
6567 		p->handle = h;
6568 		p->pos = pos;
6569 		p->qpos = -1;
6570 		p->len = len;
6571 		p->flag = flag;
6572 		p->index = index;
6573 		p->iostatus = s; /* overload */
6574 		/* set up seq later, in case thr create fails */
6575 	}
6576 	return (p);
6577 }
6578 
6579 /*
6580  * rdc_aio_buf_get
6581  * get an aio_buf
6582  */
6583 aio_buf_t *
rdc_aio_buf_get(rdc_buf_t * h,int index)6584 rdc_aio_buf_get(rdc_buf_t *h, int index)
6585 {
6586 	aio_buf_t *p;
6587 
6588 	if (index >= rdc_max_sets) {
6589 		cmn_err(CE_NOTE, "!rdc: rdc_aio_buf_get bad index %x", index);
6590 		return (NULL);
6591 	}
6592 
6593 	mutex_enter(&h->aio_lock);
6594 
6595 	p = h->rdc_anon;
6596 	while (p && (p->kindex != index))
6597 		p = p->next;
6598 
6599 	mutex_exit(&h->aio_lock);
6600 	return (p);
6601 }
6602 
6603 /*
6604  * rdc_aio_buf_del
6605  * delete a aio_buf
6606  */
6607 void
rdc_aio_buf_del(rdc_buf_t * h,rdc_k_info_t * krdc)6608 rdc_aio_buf_del(rdc_buf_t *h, rdc_k_info_t *krdc)
6609 {
6610 	aio_buf_t *p, **pp;
6611 
6612 	mutex_enter(&h->aio_lock);
6613 
6614 	p = NULL;
6615 	for (pp = &h->rdc_anon; *pp; pp = &((*pp)->next)) {
6616 		if ((*pp)->kindex == krdc->index) {
6617 			p = *pp;
6618 			break;
6619 		}
6620 	}
6621 
6622 	if (p) {
6623 		*pp = p->next;
6624 		kmem_free(p, sizeof (*p));
6625 	}
6626 	mutex_exit(&h->aio_lock);
6627 }
6628 
6629 /*
6630  * rdc_aio_buf_add
6631  * Add a aio_buf.
6632  */
6633 aio_buf_t *
rdc_aio_buf_add(int index,rdc_buf_t * h)6634 rdc_aio_buf_add(int index, rdc_buf_t *h)
6635 {
6636 	aio_buf_t *p;
6637 
6638 	p = kmem_zalloc(sizeof (*p), KM_NOSLEEP);
6639 	if (p == NULL) {
6640 		cmn_err(CE_NOTE, "!rdc_aio_buf_add: kmem_alloc failed");
6641 		return (NULL);
6642 	}
6643 
6644 	p->rdc_abufp = NULL;
6645 	p->kindex = index;
6646 
6647 	mutex_enter(&h->aio_lock);
6648 	p->next = h->rdc_anon;
6649 	h->rdc_anon = p;
6650 	mutex_exit(&h->aio_lock);
6651 	return (p);
6652 }
6653 
6654 /*
6655  * kmemalloc a new group structure and setup the common
6656  * fields.
6657  */
6658 static rdc_group_t *
rdc_newgroup()6659 rdc_newgroup()
6660 {
6661 	rdc_group_t *group;
6662 
6663 	group = kmem_zalloc(sizeof (rdc_group_t), KM_SLEEP);
6664 	group->diskq.lastio = kmem_zalloc(sizeof (rdc_aio_t), KM_SLEEP);
6665 	group->count = 1;
6666 	group->seq = RDC_NEWSEQ;
6667 	group->seqack = RDC_NEWSEQ;
6668 	mutex_init(&group->lock, NULL, MUTEX_DRIVER, NULL);
6669 	mutex_init(&group->ra_queue.net_qlock, NULL, MUTEX_DRIVER, NULL);
6670 	mutex_init(&group->diskqmutex, NULL, MUTEX_DRIVER, NULL);
6671 	mutex_init(&group->diskq.disk_qlock, NULL, MUTEX_DRIVER, NULL);
6672 	mutex_init(&group->diskq.head_lock, NULL, MUTEX_DRIVER, NULL);
6673 	mutex_init(&group->addthrnumlk, NULL, MUTEX_DRIVER, NULL);
6674 	cv_init(&group->unregistercv, NULL, CV_DRIVER, NULL);
6675 	cv_init(&group->asyncqcv, NULL, CV_DRIVER, NULL);
6676 	cv_init(&group->diskq.busycv, NULL, CV_DRIVER, NULL);
6677 	cv_init(&group->diskq.qfullcv, NULL, CV_DRIVER, NULL);
6678 	cv_init(&group->ra_queue.qfcv, NULL, CV_DRIVER, NULL);
6679 	group->ra_queue.qfill_sleeping = RDC_QFILL_DEAD;
6680 	group->diskq.busycnt = 0;
6681 	ASSERT(group->synccount == 0);		/* group was kmem_zalloc'ed */
6682 
6683 	/*
6684 	 * add default number of threads to the flusher thread set, plus
6685 	 * one extra thread for the disk queue flusher
6686 	 */
6687 	if (nst_add_thread(_rdc_flset, 3) != 3)
6688 		cmn_err(CE_NOTE, "!rdc_newgroup: nst_add_thread failed");
6689 
6690 	return (group);
6691 }
6692 
6693 void
rdc_delgroup(rdc_group_t * group)6694 rdc_delgroup(rdc_group_t *group)
6695 {
6696 
6697 	ASSERT(group->asyncstall == 0);
6698 	ASSERT(group->rdc_thrnum == 0);
6699 	ASSERT(group->count == 0);
6700 	ASSERT(MUTEX_HELD(&rdc_many_lock));
6701 
6702 	mutex_enter(&group->ra_queue.net_qlock);
6703 	rdc_sleepqdiscard(group);
6704 	mutex_exit(&group->ra_queue.net_qlock);
6705 
6706 	/* try to remove flusher threads that this group added to _rdc_flset */
6707 	if (nst_del_thread(_rdc_flset, group->rdc_addthrnum + 3) !=
6708 	    group->rdc_addthrnum + 3)
6709 		cmn_err(CE_NOTE, "!rdc_delgroup: nst_del_thread failed");
6710 
6711 	mutex_destroy(&group->lock);
6712 	mutex_destroy(&group->ra_queue.net_qlock);
6713 	mutex_destroy(&group->diskqmutex);
6714 	mutex_destroy(&group->diskq.disk_qlock);
6715 	mutex_destroy(&group->diskq.head_lock);
6716 	mutex_destroy(&group->addthrnumlk);
6717 	cv_destroy(&group->unregistercv);
6718 	cv_destroy(&group->asyncqcv);
6719 	cv_destroy(&group->diskq.busycv);
6720 	cv_destroy(&group->diskq.qfullcv);
6721 	cv_destroy(&group->ra_queue.qfcv);
6722 	kmem_free(group->diskq.lastio, sizeof (rdc_aio_t));
6723 	kmem_free(group, sizeof (rdc_group_t));
6724 }
6725