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