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