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 #define _RDC_
27 #include <sys/types.h>
28 #include <sys/ksynch.h>
29 #include <sys/kmem.h>
30 #include <sys/errno.h>
31 #include <sys/conf.h>
32 #include <sys/cmn_err.h>
33 #include <sys/modctl.h>
34 #include <sys/cred.h>
35 #include <sys/ddi.h>
36 #include <sys/unistat/spcs_s.h>
37 #include <sys/unistat/spcs_s_k.h>
38 #include <sys/unistat/spcs_errors.h>
39
40 #include <sys/nsc_thread.h>
41 #ifdef DS_DDICT
42 #include "../contract.h"
43 #endif
44 #include <sys/nsctl/nsctl.h>
45 #include <sys/nsctl/nsvers.h>
46
47 #include <sys/sdt.h> /* dtrace is S10 or later */
48
49 #include "rdc.h"
50 #include "rdc_io.h"
51 #include "rdc_bitmap.h"
52 #include "rdc_ioctl.h"
53 #include "rdcsrv.h"
54 #include "rdc_diskq.h"
55
56 #define DIDINIT 0x01
57 #define DIDNODES 0x02
58 #define DIDCONFIG 0x04
59
60 static int rdcopen(dev_t *devp, int flag, int otyp, cred_t *crp);
61 static int rdcclose(dev_t dev, int flag, int otyp, cred_t *crp);
62 static int rdcprint(dev_t dev, char *str);
63 static int rdcioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp,
64 int *rvp);
65 static int rdcattach(dev_info_t *dip, ddi_attach_cmd_t cmd);
66 static int rdcdetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
67 static int rdcgetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
68 void **result);
69 #ifdef DEBUG
70 static int rdc_clrkstat(void *);
71 #endif
72
73 /*
74 * kstat interface
75 */
76 static kstat_t *sndr_kstats;
77
78 int sndr_info_stats_update(kstat_t *ksp, int rw);
79
80 static sndr_m_stats_t sndr_info_stats = {
81 {RDC_MKSTAT_MAXSETS, KSTAT_DATA_ULONG},
82 {RDC_MKSTAT_MAXFBAS, KSTAT_DATA_ULONG},
83 {RDC_MKSTAT_RPC_TIMEOUT, KSTAT_DATA_ULONG},
84 {RDC_MKSTAT_HEALTH_THRES, KSTAT_DATA_ULONG},
85 {RDC_MKSTAT_BITMAP_WRITES, KSTAT_DATA_ULONG},
86 {RDC_MKSTAT_CLNT_COTS_CALLS, KSTAT_DATA_ULONG},
87 {RDC_MKSTAT_CLNT_CLTS_CALLS, KSTAT_DATA_ULONG},
88 {RDC_MKSTAT_SVC_COTS_CALLS, KSTAT_DATA_ULONG},
89 {RDC_MKSTAT_SVC_CLTS_CALLS, KSTAT_DATA_ULONG},
90 {RDC_MKSTAT_BITMAP_REF_DELAY, KSTAT_DATA_ULONG}
91 };
92
93 int rdc_info_stats_update(kstat_t *ksp, int rw);
94
95 static rdc_info_stats_t rdc_info_stats = {
96 {RDC_IKSTAT_FLAGS, KSTAT_DATA_ULONG},
97 {RDC_IKSTAT_SYNCFLAGS, KSTAT_DATA_ULONG},
98 {RDC_IKSTAT_BMPFLAGS, KSTAT_DATA_ULONG},
99 {RDC_IKSTAT_SYNCPOS, KSTAT_DATA_ULONG},
100 {RDC_IKSTAT_VOLSIZE, KSTAT_DATA_ULONG},
101 {RDC_IKSTAT_BITSSET, KSTAT_DATA_ULONG},
102 {RDC_IKSTAT_AUTOSYNC, KSTAT_DATA_ULONG},
103 {RDC_IKSTAT_MAXQFBAS, KSTAT_DATA_ULONG},
104 {RDC_IKSTAT_MAXQITEMS, KSTAT_DATA_ULONG},
105 {RDC_IKSTAT_FILE, KSTAT_DATA_STRING},
106 {RDC_IKSTAT_SECFILE, KSTAT_DATA_STRING},
107 {RDC_IKSTAT_BITMAP, KSTAT_DATA_STRING},
108 {RDC_IKSTAT_PRIMARY_HOST, KSTAT_DATA_STRING},
109 {RDC_IKSTAT_SECONDARY_HOST, KSTAT_DATA_STRING},
110 {RDC_IKSTAT_TYPE_FLAG, KSTAT_DATA_ULONG},
111 {RDC_IKSTAT_BMP_SIZE, KSTAT_DATA_ULONG},
112 {RDC_IKSTAT_DISK_STATUS, KSTAT_DATA_ULONG},
113 {RDC_IKSTAT_IF_DOWN, KSTAT_DATA_ULONG},
114 {RDC_IKSTAT_IF_RPC_VERSION, KSTAT_DATA_ULONG},
115 {RDC_IKSTAT_ASYNC_BLOCK_HWM, KSTAT_DATA_ULONG},
116 {RDC_IKSTAT_ASYNC_ITEM_HWM, KSTAT_DATA_ULONG},
117 {RDC_IKSTAT_ASYNC_THROTTLE_DELAY, KSTAT_DATA_ULONG},
118 {RDC_IKSTAT_ASYNC_ITEMS, KSTAT_DATA_ULONG},
119 {RDC_IKSTAT_ASYNC_BLOCKS, KSTAT_DATA_ULONG},
120 {RDC_IKSTAT_QUEUE_TYPE, KSTAT_DATA_CHAR}
121 };
122
123 static struct cb_ops rdc_cb_ops = {
124 rdcopen,
125 rdcclose,
126 nulldev, /* no strategy */
127 rdcprint,
128 nodev, /* no dump */
129 nodev, /* no read */
130 nodev, /* no write */
131 rdcioctl,
132 nodev, /* no devmap */
133 nodev, /* no mmap */
134 nodev, /* no segmap */
135 nochpoll,
136 ddi_prop_op,
137 NULL, /* not STREAMS */
138 D_NEW | D_MP | D_64BIT,
139 CB_REV,
140 nodev, /* no aread */
141 nodev, /* no awrite */
142 };
143
144 static struct dev_ops rdc_ops = {
145 DEVO_REV,
146 0,
147 rdcgetinfo,
148 nulldev, /* identify */
149 nulldev, /* probe */
150 rdcattach,
151 rdcdetach,
152 nodev, /* no reset */
153 &rdc_cb_ops,
154 (struct bus_ops *)NULL
155 };
156
157 static struct modldrv rdc_ldrv = {
158 &mod_driverops,
159 "nws:Remote Mirror:" ISS_VERSION_STR,
160 &rdc_ops
161 };
162
163 static struct modlinkage rdc_modlinkage = {
164 MODREV_1,
165 &rdc_ldrv,
166 NULL
167 };
168
169 const int sndr_major_rev = ISS_VERSION_MAJ;
170 const int sndr_minor_rev = ISS_VERSION_MIN;
171 const int sndr_micro_rev = ISS_VERSION_MIC;
172 const int sndr_baseline_rev = ISS_VERSION_NUM;
173 static char sndr_version[16];
174
175 static void *rdc_dip;
176
177 extern int _rdc_init_dev();
178 extern void _rdc_deinit_dev();
179 extern void rdc_link_down_free();
180
181 int rdc_bitmap_mode;
182 int rdc_auto_sync;
183 int rdc_max_sets;
184 extern int rdc_health_thres;
185
186 kmutex_t rdc_sync_mutex;
187 rdc_sync_event_t rdc_sync_event;
188 clock_t rdc_sync_event_timeout;
189
190 static void
rdc_sync_event_init()191 rdc_sync_event_init()
192 {
193 mutex_init(&rdc_sync_mutex, NULL, MUTEX_DRIVER, NULL);
194 mutex_init(&rdc_sync_event.mutex, NULL, MUTEX_DRIVER, NULL);
195 cv_init(&rdc_sync_event.cv, NULL, CV_DRIVER, NULL);
196 cv_init(&rdc_sync_event.done_cv, NULL, CV_DRIVER, NULL);
197 rdc_sync_event.master[0] = 0;
198 rdc_sync_event.lbolt = (clock_t)0;
199 rdc_sync_event_timeout = RDC_SYNC_EVENT_TIMEOUT;
200 }
201
202
203 static void
rdc_sync_event_destroy()204 rdc_sync_event_destroy()
205 {
206 mutex_destroy(&rdc_sync_mutex);
207 mutex_destroy(&rdc_sync_event.mutex);
208 cv_destroy(&rdc_sync_event.cv);
209 cv_destroy(&rdc_sync_event.done_cv);
210 }
211
212
213
214 int
_init(void)215 _init(void)
216 {
217 return (mod_install(&rdc_modlinkage));
218 }
219
220 int
_fini(void)221 _fini(void)
222 {
223 return (mod_remove(&rdc_modlinkage));
224 }
225
226 int
_info(struct modinfo * modinfop)227 _info(struct modinfo *modinfop)
228 {
229 return (mod_info(&rdc_modlinkage, modinfop));
230 }
231
232 static int
rdcattach(dev_info_t * dip,ddi_attach_cmd_t cmd)233 rdcattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
234 {
235 intptr_t flags;
236 int instance;
237 int i;
238
239 /*CONSTCOND*/
240 ASSERT(sizeof (u_longlong_t) == 8);
241
242 if (cmd != DDI_ATTACH)
243 return (DDI_FAILURE);
244
245 (void) strncpy(sndr_version, _VERSION_, sizeof (sndr_version));
246
247 instance = ddi_get_instance(dip);
248 rdc_dip = dip;
249
250 flags = 0;
251
252 rdc_sync_event_init();
253
254 /*
255 * rdc_max_sets must be set before calling _rdc_load().
256 */
257
258 rdc_max_sets = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
259 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "rdc_max_sets", 64);
260
261 if (_rdc_init_dev()) {
262 cmn_err(CE_WARN, "!rdc: _rdc_init_dev failed");
263 goto out;
264 }
265 flags |= DIDINIT;
266
267 if (_rdc_load() != 0) {
268 cmn_err(CE_WARN, "!rdc: _rdc_load failed");
269 goto out;
270 }
271
272 if (_rdc_configure()) {
273 cmn_err(CE_WARN, "!rdc: _rdc_configure failed");
274 goto out;
275 }
276 flags |= DIDCONFIG;
277
278 if (ddi_create_minor_node(dip, "rdc", S_IFCHR, instance, DDI_PSEUDO, 0)
279 != DDI_SUCCESS) {
280 cmn_err(CE_WARN, "!rdc: could not create node.");
281 goto out;
282 }
283 flags |= DIDNODES;
284
285 rdc_bitmap_mode = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
286 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
287 "rdc_bitmap_mode", 0);
288
289 switch (rdc_bitmap_mode) {
290 case RDC_BMP_AUTO: /* 0 */
291 break;
292 case RDC_BMP_ALWAYS: /* 1 */
293 break;
294 case RDC_BMP_NEVER: /* 2 */
295 cmn_err(CE_NOTE, "!SNDR bitmap mode override");
296 cmn_err(CE_CONT,
297 "!SNDR: bitmaps will only be written on shutdown\n");
298 break;
299 default: /* unknown */
300 cmn_err(CE_NOTE,
301 "!SNDR: unknown bitmap mode %d - autodetecting mode",
302 rdc_bitmap_mode);
303 rdc_bitmap_mode = RDC_BMP_AUTO;
304 break;
305 }
306
307 rdc_bitmap_init();
308
309 rdc_auto_sync = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
310 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
311 "rdc_auto_sync", 0);
312
313 i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
314 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
315 "rdc_health_thres", RDC_HEALTH_THRESHOLD);
316 if (i >= RDC_MIN_HEALTH_THRES)
317 rdc_health_thres = i;
318 else
319 cmn_err(CE_WARN, "!value rdc_heath_thres from rdc.conf ignored "
320 "as it is smaller than the min value of %d",
321 RDC_MIN_HEALTH_THRES);
322
323 ddi_set_driver_private(dip, (caddr_t)flags);
324 ddi_report_dev(dip);
325
326 sndr_kstats = kstat_create(RDC_KSTAT_MODULE, 0,
327 RDC_KSTAT_MINFO, RDC_KSTAT_CLASS, KSTAT_TYPE_NAMED,
328 sizeof (sndr_m_stats_t) / sizeof (kstat_named_t),
329 KSTAT_FLAG_VIRTUAL);
330
331 if (sndr_kstats) {
332 sndr_kstats->ks_data = &sndr_info_stats;
333 sndr_kstats->ks_update = sndr_info_stats_update;
334 sndr_kstats->ks_private = &rdc_k_info[0];
335 kstat_install(sndr_kstats);
336 } else
337 cmn_err(CE_WARN, "!SNDR: module kstats failed");
338
339 return (DDI_SUCCESS);
340
341 out:
342 DTRACE_PROBE(rdc_attach_failed);
343 ddi_set_driver_private(dip, (caddr_t)flags);
344 (void) rdcdetach(dip, DDI_DETACH);
345 return (DDI_FAILURE);
346 }
347
348 static int
rdcdetach(dev_info_t * dip,ddi_detach_cmd_t cmd)349 rdcdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
350 {
351 rdc_k_info_t *krdc;
352 rdc_u_info_t *urdc;
353 int rdcd;
354 intptr_t flags;
355
356
357 if (cmd != DDI_DETACH) {
358 DTRACE_PROBE(rdc_detach_unknown_cmd);
359 return (DDI_FAILURE);
360 }
361
362 if (rdc_k_info == NULL || rdc_u_info == NULL)
363 goto cleanup;
364
365 mutex_enter(&rdc_conf_lock);
366
367 for (rdcd = 0; rdcd < rdc_max_sets; rdcd++) {
368 krdc = &rdc_k_info[rdcd];
369 urdc = &rdc_u_info[rdcd];
370
371 if (IS_ENABLED(urdc) || krdc->devices) {
372 #ifdef DEBUG
373 cmn_err(CE_WARN,
374 "!rdc: cannot detach, rdcd %d still in use", rdcd);
375 #endif
376 mutex_exit(&rdc_conf_lock);
377 DTRACE_PROBE(rdc_detach_err_busy);
378 return (DDI_FAILURE);
379 }
380 }
381
382 mutex_exit(&rdc_conf_lock);
383
384 cleanup:
385 flags = (intptr_t)ddi_get_driver_private(dip);
386
387 if (flags & DIDNODES)
388 ddi_remove_minor_node(dip, NULL);
389
390 if (sndr_kstats) {
391 kstat_delete(sndr_kstats);
392 }
393 if (flags & DIDINIT)
394 _rdc_deinit_dev();
395
396 if (flags & DIDCONFIG) {
397 (void) _rdc_deconfigure();
398 (void) _rdc_unload();
399 rdcsrv_unload();
400 }
401
402 rdc_sync_event_destroy();
403 rdc_link_down_free();
404
405 rdc_dip = NULL;
406 return (DDI_SUCCESS);
407 }
408
409 /* ARGSUSED */
410 static int
rdcgetinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)411 rdcgetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
412 {
413 int rc = DDI_FAILURE;
414
415 switch (infocmd) {
416
417 case DDI_INFO_DEVT2DEVINFO:
418 *result = rdc_dip;
419 rc = DDI_SUCCESS;
420 break;
421
422 case DDI_INFO_DEVT2INSTANCE:
423 /* We only have a single instance */
424 *result = 0;
425 rc = DDI_SUCCESS;
426 break;
427
428 default:
429 break;
430 }
431
432 return (rc);
433 }
434
435
436 /* ARGSUSED */
437
438 static int
rdcopen(dev_t * devp,int flag,int otyp,cred_t * crp)439 rdcopen(dev_t *devp, int flag, int otyp, cred_t *crp)
440 {
441 return (0);
442 }
443
444
445 /* ARGSUSED */
446
447 static int
rdcclose(dev_t dev,int flag,int otyp,cred_t * crp)448 rdcclose(dev_t dev, int flag, int otyp, cred_t *crp)
449 {
450 return (0);
451 }
452
453 /* ARGSUSED */
454
455 static int
rdcprint(dev_t dev,char * str)456 rdcprint(dev_t dev, char *str)
457 {
458 int instance = 0;
459
460 cmn_err(CE_WARN, "!rdc%d: %s", instance, str);
461 return (0);
462 }
463
464
465 static int
convert_ioctl_args(int cmd,intptr_t arg,int mode,_rdc_ioctl_t * args)466 convert_ioctl_args(int cmd, intptr_t arg, int mode, _rdc_ioctl_t *args)
467 {
468 _rdc_ioctl32_t args32;
469
470 if (ddi_copyin((void *)arg, &args32, sizeof (_rdc_ioctl32_t), mode))
471 return (EFAULT);
472
473 bzero((void *)args, sizeof (_rdc_ioctl_t));
474
475 switch (cmd) {
476 case RDC_CONFIG:
477 args->arg0 = (uint32_t)args32.arg0; /* _rdc_config_t * */
478 args->arg1 = (uint32_t)args32.arg1; /* pointer */
479 args->arg2 = (uint32_t)args32.arg2; /* size */
480 args->ustatus = (spcs_s_info_t)args32.ustatus;
481 break;
482
483 case RDC_STATUS:
484 args->arg0 = (uint32_t)args32.arg0; /* pointer */
485 args->ustatus = (spcs_s_info_t)args32.ustatus;
486 break;
487
488 case RDC_ENABLE_SVR:
489 args->arg0 = (uint32_t)args32.arg0; /* _rdc_svc_args * */
490 break;
491
492 case RDC_VERSION:
493 args->arg0 = (uint32_t)args32.arg0; /* _rdc_version_t * */
494 args->ustatus = (spcs_s_info_t)args32.ustatus;
495 break;
496
497 case RDC_SYNC_EVENT:
498 args->arg0 = (uint32_t)args32.arg0; /* char * */
499 args->arg1 = (uint32_t)args32.arg1; /* char * */
500 args->ustatus = (spcs_s_info_t)args32.ustatus;
501 break;
502
503 case RDC_LINK_DOWN:
504 args->arg0 = (uint32_t)args32.arg0; /* char * */
505 args->ustatus = (spcs_s_info_t)args32.ustatus;
506 break;
507 case RDC_POOL_CREATE:
508 args->arg0 = (uint32_t)args32.arg0; /* svcpool_args * */
509 break;
510 case RDC_POOL_WAIT:
511 args->arg0 = (uint32_t)args32.arg0; /* int */
512 break;
513 case RDC_POOL_RUN:
514 args->arg0 = (uint32_t)args32.arg0; /* int */
515 break;
516
517 default:
518 return (EINVAL);
519 }
520
521 return (0);
522 }
523
524
525 /*
526 * Yet another standard thing that is not standard ...
527 */
528 #ifndef offsetof
529 #define offsetof(s, m) ((size_t)(&((s *)0)->m))
530 #endif
531
532 /*
533 * Build a 32bit rdc_set structure and copyout to the user level.
534 */
535 int
rdc_status_copy32(const void * arg,void * usetp,size_t size,int mode)536 rdc_status_copy32(const void *arg, void *usetp, size_t size, int mode)
537 {
538 rdc_u_info_t *urdc = (rdc_u_info_t *)arg;
539 struct rdc_set32 set32;
540 size_t tailsize;
541 #ifdef DEBUG
542 size_t tailsize32;
543 #endif
544
545 bzero(&set32, sizeof (set32));
546
547 tailsize = sizeof (struct rdc_addr32) -
548 offsetof(struct rdc_addr32, intf);
549
550 /* primary address structure, avoiding netbuf */
551 bcopy(&urdc->primary.intf[0], &set32.primary.intf[0], tailsize);
552
553 /* secondary address structure, avoiding netbuf */
554 bcopy(&urdc->secondary.intf[0], &set32.secondary.intf[0], tailsize);
555
556 /*
557 * the rest, avoiding netconfig
558 * note: the tail must be the same size in both structures
559 */
560 tailsize = sizeof (struct rdc_set) - offsetof(struct rdc_set, flags);
561 #ifdef DEBUG
562 /*
563 * ASSERT is calling for debug reason, and tailsize32 is only declared
564 * for ASSERT, put them under debug to avoid lint warning.
565 */
566 tailsize32 = sizeof (struct rdc_set32) -
567 offsetof(struct rdc_set32, flags);
568 ASSERT(tailsize == tailsize32);
569 #endif
570
571 bcopy(&urdc->flags, &set32.flags, tailsize);
572
573 /* copyout to user level */
574 return (ddi_copyout(&set32, usetp, size, mode));
575 }
576
577
578 /*
579 * Status ioctl.
580 */
581 static int
rdcstatus(_rdc_ioctl_t * args,int mode)582 rdcstatus(_rdc_ioctl_t *args, int mode)
583 {
584 int (*copyout)(const void *, void *, size_t, int);
585 rdc_u_info_t *urdc;
586 rdc_k_info_t *krdc;
587 disk_queue *dqp;
588 char *usetp; /* pointer to user rdc_set structure */
589 size_t size; /* sizeof user rdc_set structure */
590 int32_t *maxsetsp; /* address of status->maxsets; */
591 int nset, max, i, j;
592
593 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
594 struct rdc_status32 status32;
595
596 if (ddi_copyin((void *)args->arg0, &status32,
597 sizeof (status32), mode)) {
598 return (EFAULT);
599 }
600
601 usetp = ((char *)args->arg0) +
602 offsetof(struct rdc_status32, rdc_set);
603 maxsetsp = (int32_t *)((char *)args->arg0 +
604 offsetof(struct rdc_status32, maxsets));
605 nset = status32.nset;
606
607 size = sizeof (struct rdc_set32);
608 copyout = rdc_status_copy32;
609 } else {
610 struct rdc_status status;
611
612 if (ddi_copyin((void *)args->arg0, &status,
613 sizeof (status), mode)) {
614 return (EFAULT);
615 }
616
617 usetp = ((char *)args->arg0) +
618 offsetof(struct rdc_status, rdc_set);
619 maxsetsp = (int32_t *)((char *)args->arg0 +
620 offsetof(struct rdc_status, maxsets));
621 nset = status.nset;
622
623 size = sizeof (struct rdc_set);
624 copyout = ddi_copyout;
625 }
626
627 max = min(nset, rdc_max_sets);
628
629 for (i = 0, j = 0; i < max; i++) {
630 urdc = &rdc_u_info[i];
631 krdc = &rdc_k_info[i];
632
633 if (!IS_ENABLED(urdc))
634 continue;
635
636 /*
637 * sneak out qstate in urdc->flags
638 * this is harmless because it's value is not used
639 * in urdc->flags. the real qstate is kept in
640 * group->diskq->disk_hdr.h.state
641 */
642 if (RDC_IS_DISKQ(krdc->group)) {
643 dqp = &krdc->group->diskq;
644 if (IS_QSTATE(dqp, RDC_QNOBLOCK))
645 urdc->flags |= RDC_QNOBLOCK;
646 }
647
648 j++;
649 if ((*copyout)(urdc, usetp, size, mode) != 0)
650 return (EFAULT);
651
652 urdc->flags &= ~RDC_QNOBLOCK; /* clear qstate */
653 usetp += size;
654 }
655
656 /* copyout rdc_max_sets value */
657
658 if (ddi_copyout(&rdc_max_sets, maxsetsp, sizeof (*maxsetsp), mode) != 0)
659 return (EFAULT);
660
661 /* copyout number of sets manipulated */
662
663 /*CONSTCOND*/
664 ASSERT(offsetof(struct rdc_status32, nset) == 0);
665 /*CONSTCOND*/
666 ASSERT(offsetof(struct rdc_status, nset) == 0);
667
668 return (ddi_copyout(&j, (void *)args->arg0, sizeof (int), mode));
669 }
670
671
672 /* ARGSUSED */
673
674 static int
rdcioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * crp,int * rvp)675 rdcioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp, int *rvp)
676 {
677 spcs_s_info_t kstatus = NULL;
678 _rdc_ioctl_t args;
679 int error;
680 int rc = 0;
681
682 if (cmd != RDC_STATUS) {
683 if ((error = drv_priv(crp)) != 0)
684 return (error);
685 }
686 #ifdef DEBUG
687 if (cmd == RDC_ASYNC6) {
688 rc = rdc_async6((void *)arg, mode, rvp);
689 return (rc);
690 }
691
692 if (cmd == RDC_CLRKSTAT) {
693 rc = rdc_clrkstat((void *)arg);
694 return (rc);
695 }
696
697 if (cmd == RDC_STALL0) {
698 if (((int)arg > 1) || ((int)arg < 0))
699 return (EINVAL);
700 rdc_stallzero((int)arg);
701 return (0);
702 }
703 if (cmd == RDC_READGEN) {
704 rc = rdc_readgen((void *)arg, mode, rvp);
705 return (rc);
706 }
707 #endif
708 if (cmd == RDC_BITMAPOP) {
709 rdc_bitmap_op_t bmop;
710 rdc_bitmap_op32_t bmop32;
711
712 if (ddi_model_convert_from(mode & FMODELS)
713 == DDI_MODEL_ILP32) {
714 if (ddi_copyin((void *)arg, &bmop32, sizeof (bmop32),
715 mode))
716 return (EFAULT);
717 bmop.offset = bmop32.offset;
718 bmop.op = bmop32.op;
719 (void) strncpy(bmop.sechost, bmop32.sechost,
720 MAX_RDC_HOST_SIZE);
721 (void) strncpy(bmop.secfile, bmop32.secfile,
722 NSC_MAXPATH);
723 bmop.len = bmop32.len;
724 bmop.addr = (unsigned long)bmop32.addr;
725 } else {
726 if (ddi_copyin((void *)arg, &bmop, sizeof (bmop),
727 mode))
728 return (EFAULT);
729 }
730 rc = rdc_bitmapset(bmop.op, bmop.sechost, bmop.secfile,
731 (void *)bmop.addr, bmop.len, bmop.offset, mode);
732 return (rc);
733 }
734
735 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
736 if ((rc = convert_ioctl_args(cmd, arg, mode, &args)) != 0)
737 return (rc);
738 } else {
739 if (ddi_copyin((void *)arg, &args,
740 sizeof (_rdc_ioctl_t), mode)) {
741 return (EFAULT);
742 }
743 }
744
745 kstatus = spcs_s_kcreate();
746 if (!kstatus) {
747 return (ENOMEM);
748 }
749
750
751 switch (cmd) {
752
753 case RDC_POOL_CREATE: {
754 struct svcpool_args p;
755
756 if (ddi_copyin((void *)arg, &p, sizeof (p), mode)) {
757 spcs_s_kfree(kstatus);
758 return (EFAULT);
759 }
760 error = svc_pool_create(&p);
761
762 break;
763 }
764 case RDC_POOL_WAIT: {
765 int id;
766
767 if (ddi_copyin((void *)arg, &id, sizeof (id), mode)) {
768 spcs_s_kfree(kstatus);
769 return (EFAULT);
770 }
771
772 error = svc_wait(id);
773 break;
774 }
775 case RDC_POOL_RUN: {
776 int id;
777
778 if (ddi_copyin((void *)arg, &id, sizeof (id), mode)) {
779 spcs_s_kfree(kstatus);
780 return (EFAULT);
781 }
782 error = svc_do_run(id);
783 break;
784 }
785 case RDC_ENABLE_SVR:
786 {
787 STRUCT_DECL(rdc_svc_args, parms);
788
789 STRUCT_INIT(parms, mode);
790 /* Only used by sndrd which does not use unistat */
791
792 if (ddi_copyin((void *)args.arg0, STRUCT_BUF(parms),
793 STRUCT_SIZE(parms), mode)) {
794 spcs_s_kfree(kstatus);
795 return (EFAULT);
796 }
797 rc = rdc_start_server(STRUCT_BUF(parms), mode);
798 }
799 break;
800
801 case RDC_STATUS:
802 rc = rdcstatus(&args, mode);
803 break;
804
805 case RDC_CONFIG:
806 rc = _rdc_config((void *)args.arg0, mode, kstatus, rvp);
807 spcs_s_copyoutf(&kstatus, args.ustatus);
808 return (rc);
809
810 case RDC_VERSION:
811 {
812 STRUCT_DECL(rdc_version, parms);
813
814 STRUCT_INIT(parms, mode);
815
816 STRUCT_FSET(parms, major, sndr_major_rev);
817 STRUCT_FSET(parms, minor, sndr_minor_rev);
818 STRUCT_FSET(parms, micro, sndr_micro_rev);
819 STRUCT_FSET(parms, baseline, sndr_baseline_rev);
820
821 if (ddi_copyout(STRUCT_BUF(parms), (void *)args.arg0,
822 STRUCT_SIZE(parms), mode)) {
823 spcs_s_kfree(kstatus);
824 return (EFAULT);
825 }
826 break;
827 }
828
829 case RDC_LINK_DOWN:
830 /* char *host from user */
831 rc = _rdc_link_down((void *)args.arg0, mode, kstatus, rvp);
832 spcs_s_copyoutf(&kstatus, args.ustatus);
833
834 return (rc);
835
836 case RDC_SYNC_EVENT:
837 rc = _rdc_sync_event_wait((void *)args.arg0, (void *)args.arg1,
838 mode, kstatus, rvp);
839 spcs_s_copyoutf(&kstatus, args.ustatus);
840
841 return (rc);
842
843
844 default:
845 rc = EINVAL;
846 break;
847 }
848
849 spcs_s_kfree(kstatus);
850 return (rc);
851 }
852
853 int
sndr_info_stats_update(kstat_t * ksp,int rw)854 sndr_info_stats_update(kstat_t *ksp, int rw)
855 {
856 extern int rdc_rpc_tmout;
857 extern int rdc_health_thres;
858 extern int rdc_bitmap_delay;
859 extern long rdc_clnt_count;
860 extern long rdc_svc_count;
861 sndr_m_stats_t *info_stats;
862 rdc_k_info_t *krdc;
863
864 info_stats = (sndr_m_stats_t *)(ksp->ks_data);
865 krdc = (rdc_k_info_t *)(ksp->ks_private);
866
867 /* no writes currently allowed */
868
869 if (rw == KSTAT_WRITE) {
870 return (EACCES);
871 }
872
873 /* default to READ */
874 info_stats->m_maxsets.value.ul = rdc_max_sets;
875 info_stats->m_maxfbas.value.ul = krdc->maxfbas;
876 info_stats->m_rpc_timeout.value.ul = rdc_rpc_tmout;
877 info_stats->m_health_thres.value.ul = rdc_health_thres;
878 info_stats->m_bitmap_writes.value.ul = krdc->bitmap_write;
879 info_stats->m_bitmap_ref_delay.value.ul = rdc_bitmap_delay;
880
881 /* clts counters not implemented yet */
882 info_stats->m_clnt_cots_calls.value.ul = rdc_clnt_count;
883 info_stats->m_clnt_clts_calls.value.ul = 0;
884 info_stats->m_svc_cots_calls.value.ul = rdc_svc_count;
885 info_stats->m_svc_clts_calls.value.ul = 0;
886
887 return (0);
888 }
889
890 /*
891 * copy tailsize-1 bytes of tail of s to s1.
892 */
893 void
rdc_str_tail_cpy(char * s1,char * s,size_t tailsize)894 rdc_str_tail_cpy(char *s1, char *s, size_t tailsize)
895 {
896 /* To avoid un-terminated string, max size is 16 - 1 */
897 ssize_t offset = strlen(s) - (tailsize - 1);
898
899 offset = (offset > 0) ? offset : 0;
900
901 /* ensure it's null terminated */
902 (void) strlcpy(s1, (const char *)(s + offset), tailsize);
903 }
904
905 int
rdc_info_stats_update(kstat_t * ksp,int rw)906 rdc_info_stats_update(kstat_t *ksp, int rw)
907 {
908 rdc_info_stats_t *rdc_info_stats;
909 rdc_k_info_t *krdc;
910 rdc_u_info_t *urdc;
911
912 rdc_info_stats = (rdc_info_stats_t *)(ksp->ks_data);
913 krdc = (rdc_k_info_t *)(ksp->ks_private);
914 urdc = &rdc_u_info[krdc->index];
915
916 /* no writes currently allowed */
917
918 if (rw == KSTAT_WRITE) {
919 return (EACCES);
920 }
921
922 /* default to READ */
923 rdc_info_stats->s_flags.value.ul = urdc->flags;
924 rdc_info_stats->s_syncflags.value.ul =
925 urdc->sync_flags;
926 rdc_info_stats->s_bmpflags.value.ul =
927 urdc->bmap_flags;
928 rdc_info_stats->s_syncpos.value.ul =
929 urdc->sync_pos;
930 rdc_info_stats->s_volsize.value.ul =
931 urdc->volume_size;
932 rdc_info_stats->s_bits_set.value.ul =
933 urdc->bits_set;
934 rdc_info_stats->s_autosync.value.ul =
935 urdc->autosync;
936 rdc_info_stats->s_maxqfbas.value.ul =
937 urdc->maxqfbas;
938 rdc_info_stats->s_maxqitems.value.ul =
939 urdc->maxqitems;
940
941 kstat_named_setstr(&rdc_info_stats->s_primary_vol,
942 urdc->primary.file);
943
944 kstat_named_setstr(&rdc_info_stats->s_secondary_vol,
945 urdc->secondary.file);
946
947 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
948 kstat_named_setstr(&rdc_info_stats->s_bitmap,
949 urdc->primary.bitmap);
950 } else {
951 kstat_named_setstr(&rdc_info_stats->s_bitmap,
952 urdc->secondary.bitmap);
953 }
954
955 kstat_named_setstr(&rdc_info_stats->s_primary_intf,
956 urdc->primary.intf);
957
958 kstat_named_setstr(&rdc_info_stats->s_secondary_intf,
959 urdc->secondary.intf);
960
961 rdc_info_stats->s_type_flag.value.ul = krdc->type_flag;
962 rdc_info_stats->s_bitmap_size.value.ul = krdc->bitmap_size;
963 rdc_info_stats->s_disk_status.value.ul = krdc->disk_status;
964
965 if (krdc->intf) {
966 rdc_info_stats->s_if_if_down.value.ul = krdc->intf->if_down;
967 rdc_info_stats->s_if_rpc_version.value.ul =
968 krdc->intf->rpc_version;
969 }
970
971 /* the type can change without disable/re-enable so... */
972 bzero(rdc_info_stats->s_aqueue_type.value.c, KSTAT_DATA_CHAR_LEN);
973 if (RDC_IS_MEMQ(krdc->group)) {
974 (void) strcpy(rdc_info_stats->s_aqueue_type.value.c, "memory");
975 rdc_info_stats->s_aqueue_blk_hwm.value.ul =
976 krdc->group->ra_queue.blocks_hwm;
977 rdc_info_stats->s_aqueue_itm_hwm.value.ul =
978 krdc->group->ra_queue.nitems_hwm;
979 rdc_info_stats->s_aqueue_throttle.value.ul =
980 krdc->group->ra_queue.throttle_delay;
981 rdc_info_stats->s_aqueue_items.value.ul =
982 krdc->group->ra_queue.nitems;
983 rdc_info_stats->s_aqueue_blocks.value.ul =
984 krdc->group->ra_queue.blocks;
985
986 } else if (RDC_IS_DISKQ(krdc->group)) {
987 disk_queue *q = &krdc->group->diskq;
988 rdc_info_stats->s_aqueue_blk_hwm.value.ul =
989 krdc->group->diskq.blocks_hwm;
990 rdc_info_stats->s_aqueue_itm_hwm.value.ul =
991 krdc->group->diskq.nitems_hwm;
992 rdc_info_stats->s_aqueue_throttle.value.ul =
993 krdc->group->diskq.throttle_delay;
994 rdc_info_stats->s_aqueue_items.value.ul = QNITEMS(q);
995 rdc_info_stats->s_aqueue_blocks.value.ul = QBLOCKS(q);
996 (void) strcpy(rdc_info_stats->s_aqueue_type.value.c, "disk");
997 }
998
999 return (0);
1000 }
1001
1002 void
rdc_kstat_create(int index)1003 rdc_kstat_create(int index)
1004 {
1005 int j = index;
1006 rdc_k_info_t *krdc = &rdc_k_info[index];
1007 rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1008 size_t varsize;
1009
1010 if (!krdc->set_kstats) {
1011 krdc->set_kstats = kstat_create(RDC_KSTAT_MODULE, j,
1012 RDC_KSTAT_INFO, RDC_KSTAT_CLASS, KSTAT_TYPE_NAMED,
1013 sizeof (rdc_info_stats_t) / sizeof (kstat_named_t),
1014 KSTAT_FLAG_VIRTUAL);
1015 #ifdef DEBUG
1016 if (!krdc->set_kstats)
1017 cmn_err(CE_NOTE, "!krdc:u_kstat null");
1018 #endif
1019
1020 if (krdc->set_kstats) {
1021 /* calculate exact size of KSTAT_DATA_STRINGs */
1022 varsize = strlen(urdc->primary.file) + 1
1023 + strlen(urdc->secondary.file) + 1
1024 + strlen(urdc->primary.intf) + 1
1025 + strlen(urdc->secondary.intf) + 1;
1026 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1027 varsize += strlen(urdc->primary.bitmap) + 1;
1028 } else {
1029 varsize += strlen(urdc->secondary.bitmap) + 1;
1030 }
1031
1032 krdc->set_kstats->ks_data_size += varsize;
1033 krdc->set_kstats->ks_data = &rdc_info_stats;
1034 krdc->set_kstats->ks_update = rdc_info_stats_update;
1035 krdc->set_kstats->ks_private = &rdc_k_info[j];
1036 kstat_install(krdc->set_kstats);
1037 } else
1038 cmn_err(CE_WARN, "!SNDR: k-kstats failed");
1039 }
1040
1041 krdc->io_kstats = kstat_create(RDC_KSTAT_MODULE, j, NULL,
1042 "disk", KSTAT_TYPE_IO, 1, 0);
1043 if (krdc->io_kstats) {
1044 krdc->io_kstats->ks_lock = &krdc->kstat_mutex;
1045 kstat_install(krdc->io_kstats);
1046 }
1047 krdc->bmp_kstats = kstat_create("sndrbmp", j, NULL,
1048 "disk", KSTAT_TYPE_IO, 1, 0);
1049 if (krdc->bmp_kstats) {
1050 krdc->bmp_kstats->ks_lock = &krdc->bmp_kstat_mutex;
1051 kstat_install(krdc->bmp_kstats);
1052 }
1053 }
1054
1055 void
rdc_kstat_delete(int index)1056 rdc_kstat_delete(int index)
1057 {
1058 rdc_k_info_t *krdc = &rdc_k_info[index];
1059
1060 if (krdc->set_kstats) {
1061 kstat_delete(krdc->set_kstats);
1062 krdc->set_kstats = NULL;
1063 }
1064
1065 if (krdc->io_kstats) {
1066 kstat_delete(krdc->io_kstats);
1067 krdc->io_kstats = NULL;
1068 }
1069 if (krdc->bmp_kstats) {
1070 kstat_delete(krdc->bmp_kstats);
1071 krdc->bmp_kstats = NULL;
1072 }
1073 }
1074
1075 #ifdef DEBUG
1076 /*
1077 * Reset the io_kstat structure of the krdc specified
1078 * by the arg index.
1079 */
1080 static int
rdc_clrkstat(void * arg)1081 rdc_clrkstat(void *arg)
1082 {
1083 int index;
1084 rdc_k_info_t *krdc;
1085
1086 index = (int)(unsigned long)arg;
1087 if ((index < 0) || (index >= rdc_max_sets)) {
1088 return (EINVAL);
1089 }
1090 krdc = &rdc_k_info[index];
1091 if (krdc->io_kstats) {
1092 kstat_delete(krdc->io_kstats);
1093 krdc->io_kstats = NULL;
1094 } else {
1095 return (EINVAL);
1096 }
1097 krdc->io_kstats = kstat_create(RDC_KSTAT_MODULE, index, NULL,
1098 "disk", KSTAT_TYPE_IO, 1, 0);
1099 if (krdc->io_kstats) {
1100 krdc->io_kstats->ks_lock = &krdc->kstat_mutex;
1101 kstat_install(krdc->io_kstats);
1102 } else {
1103 return (EINVAL);
1104 }
1105 /*
1106 * clear the high water marks and throttle.
1107 */
1108 if (krdc->group) {
1109 krdc->group->ra_queue.nitems_hwm = 0;
1110 krdc->group->ra_queue.blocks_hwm = 0;
1111 krdc->group->ra_queue.throttle_delay = 0;
1112 }
1113 return (0);
1114 }
1115 #endif
1116