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 _DSW_
27
28 #include <sys/types.h>
29 #include <sys/ksynch.h>
30 #include <sys/kmem.h>
31 #include <sys/errno.h>
32 #include <sys/conf.h>
33 #include <sys/cmn_err.h>
34 #include <sys/modctl.h>
35 #include <sys/cred.h>
36 #include <sys/file.h>
37 #include <sys/ddi.h>
38 #include <sys/unistat/spcs_s.h>
39 #include <sys/dkio.h>
40
41 #ifdef DS_DDICT
42 #include "../contract.h"
43 #endif
44
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 "dsw.h"
51 #include "dsw_dev.h"
52
53 #define DIDINIT 0x01
54 #define DIDNODES 0x02
55
56
57 static int iiopen(dev_t *devp, int flag, int otyp, cred_t *crp);
58 static int iiclose(dev_t dev, int flag, int otyp, cred_t *crp);
59 static int iiprint(dev_t dev, char *str);
60 static int iiioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp,
61 int *rvp);
62 static int iiprobe(dev_info_t *dip);
63 static int iiattach(dev_info_t *dip, ddi_attach_cmd_t cmd);
64 static int iidetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
65 static int iistrat(struct buf *);
66 static int iiread();
67
68
69 static kstat_t *ii_gkstat = NULL;
70 iigkstat_t iigkstat = {
71 { "ii_debug", KSTAT_DATA_ULONG },
72 { "ii_bitmap", KSTAT_DATA_ULONG },
73 { "ii_throttle_unit", KSTAT_DATA_ULONG },
74 { "ii_throttle_delay", KSTAT_DATA_ULONG },
75 { "ii_copy_direct", KSTAT_DATA_ULONG },
76 { "num-sets", KSTAT_DATA_ULONG },
77 { "assoc-over", KSTAT_DATA_ULONG },
78 { "spilled-over", KSTAT_DATA_ULONG },
79 };
80
81 static struct cb_ops ii_cb_ops = {
82 iiopen,
83 iiclose,
84 iistrat, /* dummy strategy */
85 iiprint,
86 nodev, /* no dump */
87 iiread, /* dummy read */
88 nodev, /* no write */
89 iiioctl,
90 nodev, /* no devmap */
91 nodev, /* no mmap */
92 nodev, /* no segmap */
93 nochpoll,
94 ddi_prop_op,
95 NULL, /* not STREAMS */
96 D_NEW | D_MP
97 };
98
99 static struct dev_ops ii_ops = {
100 DEVO_REV,
101 0,
102 nodev, /* no getinfo */
103 nulldev,
104 iiprobe,
105 iiattach,
106 iidetach,
107 nodev, /* no reset */
108 &ii_cb_ops,
109 (struct bus_ops *)NULL
110 };
111
112 static struct modldrv ii_ldrv = {
113 &mod_driverops,
114 "nws:Point-in-Time:" ISS_VERSION_STR,
115 &ii_ops
116 };
117
118 static struct modlinkage ii_modlinkage = {
119 MODREV_1,
120 { &ii_ldrv, NULL }
121 };
122
123 struct ii_state {
124 dev_info_t *dip;
125 int instance;
126 };
127
128 /* used for logging sysevent, gets set in _ii_attach */
129 dev_info_t *ii_dip = NULL;
130
131 extern _ii_info_t *_ii_info_top;
132 extern _ii_lsthead_t *_ii_cluster_top;
133 extern _ii_lsthead_t *_ii_group_top;
134 extern kmutex_t _ii_cluster_mutex;
135 extern kmutex_t _ii_group_mutex;
136
137 const int dsw_major_rev = ISS_VERSION_MAJ; /* Major release number */
138 const int dsw_minor_rev = ISS_VERSION_MIN; /* Minor release number */
139 const int dsw_micro_rev = ISS_VERSION_MIC; /* Micro release number */
140 const int dsw_baseline_rev = ISS_VERSION_NUM; /* Baseline revision */
141 static void *ii_statep;
142
143 extern int _ii_init_dev();
144 extern void _ii_deinit_dev();
145 extern int _ii_config(intptr_t arg, int ilp32, int *rvp, int iflags);
146 extern int _ii_disable(intptr_t arg, int ilp32, int *rvp);
147 extern int _ii_suspend(intptr_t arg, int ilp32, int *rvp);
148 extern int _ii_bitmap(intptr_t arg, int ilp32, int *rvp);
149 extern int _ii_segment(intptr_t arg, int ilp32, int *rvp);
150 extern int _ii_abort(intptr_t arg, int ilp32, int *rvp);
151 extern int _ii_acopy(intptr_t arg, int ilp32, int *rvp);
152 extern int _ii_copy(intptr_t arg, int ilp32, int *rvp);
153 extern int _ii_shutdown(intptr_t arg, int *rvp);
154 extern int _ii_stat(intptr_t arg, int ilp32, int *rvp);
155 extern int _ii_version(intptr_t arg, int ilp32, int *rvp);
156 extern int _ii_wait(intptr_t arg, int ilp32, int *rvp);
157 extern int _ii_reset(intptr_t arg, int ilp32, int *rvp);
158 extern int _ii_offline(intptr_t arg, int ilp32, int *rvp);
159 extern int _ii_list(intptr_t arg, int ilp32, int *rvp);
160 extern int _ii_listlen(int cmd, int ilp32, int *rvp);
161 extern int _ii_export(intptr_t arg, int ilp32, int *rvp);
162 extern int _ii_join(intptr_t arg, int ilp32, int *rvp);
163 extern int _ii_copyparm(intptr_t arg, int ilp32, int *rvp);
164 extern int _ii_ocreate(intptr_t arg, int ilp32, int *rvp);
165 extern int _ii_oattach(intptr_t arg, int ilp32, int *rvp);
166 extern int _ii_odetach(intptr_t arg, int ilp32, int *rvp);
167 extern int _ii_olist(intptr_t arg, int ilp32, int *rvp);
168 extern int _ii_ostat(intptr_t arg, int ilp32, int *rvp, int is_iost_2);
169 extern int _ii_bitsset(intptr_t arg, int ilp32, int cmd, int *rvp);
170 extern int _ii_gc_list(intptr_t, int, int *, kmutex_t *, _ii_lsthead_t *);
171 extern int _ii_clist(intptr_t arg, int ilp32, int *rvp);
172 extern int _ii_move_grp(intptr_t arg, int ilp32, int *rvp);
173 extern int _ii_change_tag(intptr_t arg, int ilp32, int *rvp);
174 extern int ii_debug;
175 extern int ii_throttle_unit;
176 extern int ii_throttle_delay;
177 extern int ii_copy_direct;
178 extern int ii_bitmap;
179
180 int
181 _init(void)
182 {
183 int error;
184
185 error = ddi_soft_state_init(&ii_statep, sizeof (struct ii_state), 1);
186 if (!error) {
187 error = mod_install(&ii_modlinkage);
188 if (error)
189 ddi_soft_state_fini(&ii_statep);
190 }
191
192 return (error);
193 }
194
195 int
196 _fini(void)
197 {
198 int error;
199
200 error = mod_remove(&ii_modlinkage);
201 if (!error)
202 ddi_soft_state_fini(&ii_statep);
203
204 return (error);
205 }
206
207 int
208 _info(struct modinfo *modinfop)
209 {
210 int rc;
211
212 rc = mod_info(&ii_modlinkage, modinfop);
213
214 return (rc);
215 }
216
217 /* ARGSUSED */
218
219 static int
220 iiprobe(dev_info_t *dip)
221 {
222 return (DDI_PROBE_SUCCESS);
223 }
224
225 /*ARGSUSED*/
226 static int
227 ii_stats_update(kstat_t *ksp, int rw)
228 {
229 if (KSTAT_WRITE == rw) {
230 return (EACCES);
231 }
232
233 /*
234 * We do nothing here for now -- the kstat structure is
235 * updated in-place
236 */
237
238 return (0);
239 }
240
241 static void
242 ii_create_kstats()
243 {
244 /* create global info structure */
245 if (!ii_gkstat) {
246 ii_gkstat = kstat_create("ii", 0, "global", "StorEdge",
247 KSTAT_TYPE_NAMED,
248 sizeof (iigkstat) / sizeof (kstat_named_t),
249 KSTAT_FLAG_VIRTUAL);
250 if (ii_gkstat) {
251 ii_gkstat->ks_data = &iigkstat;
252 ii_gkstat->ks_update = ii_stats_update;
253 ii_gkstat->ks_private = 0;
254 kstat_install(ii_gkstat);
255
256 /* fill in immutable values */
257 iigkstat.ii_debug.value.ul = ii_debug;
258 iigkstat.ii_bitmap.value.ul = ii_bitmap;
259 iigkstat.ii_throttle_unit.value.ul = ii_throttle_unit;
260 iigkstat.ii_throttle_delay.value.ul =
261 ii_throttle_delay;
262 iigkstat.ii_copy_direct.value.ul = ii_copy_direct;
263 } else {
264 cmn_err(CE_WARN, "!Unable to create II global stats");
265 }
266 }
267 }
268
269 static int
270 iiattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
271 {
272 struct ii_state *xsp;
273 int instance;
274 int i;
275 intptr_t flags;
276
277 if (cmd != DDI_ATTACH) {
278 return (DDI_FAILURE);
279 }
280 /* save the dev_info_t to be used in logging using ddi_log_sysevent */
281 ii_dip = dip;
282
283 instance = ddi_get_instance(dip);
284 if (ddi_soft_state_zalloc(ii_statep, instance) != 0) {
285 cmn_err(CE_WARN, "!ii: no memory for instance %d state.",
286 instance);
287 return (DDI_FAILURE);
288 }
289
290 flags = 0;
291 xsp = ddi_get_soft_state(ii_statep, instance);
292 if (xsp == NULL) {
293 cmn_err(CE_WARN,
294 "!ii: attach: could not get state for instance %d.",
295 instance);
296 goto out;
297 }
298
299 ii_debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
300 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ii_debug", 0);
301 if (ii_debug != 0) {
302 #ifdef DEBUG
303 cmn_err(CE_NOTE, "!ii: initializing ii version %d.%d.%d.%d",
304 dsw_major_rev, dsw_minor_rev,
305 dsw_micro_rev, dsw_baseline_rev);
306 #else
307 if (dsw_micro_rev) {
308 cmn_err(CE_NOTE, "!ii: initializing ii vers %d.%d.%d",
309 dsw_major_rev, dsw_minor_rev, dsw_micro_rev);
310 } else {
311 cmn_err(CE_NOTE, "!ii: initializing ii version %d.%d",
312 dsw_major_rev, dsw_minor_rev);
313 }
314 #endif
315 switch (ii_debug) {
316 case 1:
317 case 2: cmn_err(CE_NOTE,
318 "!ii: ii_debug=%d is enabled.", ii_debug);
319 break;
320 default:
321 cmn_err(CE_WARN,
322 "!ii: Value of ii_debug=%d is not 0,1 or 2.",
323 ii_debug);
324 }
325 }
326
327 ii_bitmap = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
328 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ii_bitmap", II_WTHRU);
329 switch (ii_bitmap) {
330 case II_KMEM:
331 if (ii_debug > 0)
332 cmn_err(CE_NOTE, "!ii: ii_bitmap is in memory");
333 break;
334 case II_FWC:
335 if (ii_debug > 0)
336 cmn_err(CE_NOTE, "!ii: ii_bitmap is on disk,"
337 " no FWC");
338 break;
339 case II_WTHRU:
340 if (ii_debug > 0)
341 cmn_err(CE_NOTE, "!ii: ii_bitmap is on disk");
342 break;
343 default:
344 cmn_err(CE_NOTE,
345 "!ii: ii_bitmap=%d out of range; "
346 "defaulting WTHRU(%d)", ii_bitmap, II_WTHRU);
347 ii_bitmap = II_WTHRU;
348 }
349
350 /* pick up these values if in ii.conf, otherwise leave alone */
351 i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
352 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ii_throttle_unit", 0);
353 if (i > 0) {
354 ii_throttle_unit = i;
355 if ((ii_throttle_unit < MIN_THROTTLE_UNIT) ||
356 (ii_throttle_unit > MAX_THROTTLE_UNIT) ||
357 (ii_debug > 0))
358 cmn_err(CE_NOTE,
359 "!ii: ii_throttle_unit=%d", ii_throttle_unit);
360 }
361
362 i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
363 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ii_throttle_delay", 0);
364 if (i > 0) {
365 ii_throttle_delay = i;
366 if ((ii_throttle_delay < MIN_THROTTLE_DELAY) ||
367 (ii_throttle_delay > MIN_THROTTLE_DELAY) ||
368 (ii_debug > 0))
369 cmn_err(CE_NOTE,
370 "!ii: ii_throttle_delay=%d", ii_throttle_delay);
371 }
372
373 ii_copy_direct = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
374 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ii_copy_direct", 1);
375 if (i > 0) {
376 ii_copy_direct = i;
377 if ((ii_copy_direct < 0) || (ii_copy_direct > 1))
378 cmn_err(CE_NOTE,
379 "!ii: ii_copy_direct=%d", ii_copy_direct);
380 }
381
382 if (_ii_init_dev()) {
383 cmn_err(CE_WARN, "!ii: _ii_init_dev failed");
384 goto out;
385 }
386 flags |= DIDINIT;
387
388 xsp->dip = dip;
389 xsp->instance = instance;
390
391 if (ddi_create_minor_node(dip, "ii", S_IFCHR, instance, DDI_PSEUDO, 0)
392 != DDI_SUCCESS) {
393 cmn_err(CE_WARN, "!ii: could not create node.");
394 goto out;
395 }
396 flags |= DIDNODES;
397
398 ddi_set_driver_private(dip, (caddr_t)flags);
399 ddi_report_dev(dip);
400
401 ii_create_kstats();
402
403 return (DDI_SUCCESS);
404
405 out:
406 ddi_set_driver_private(dip, (caddr_t)flags);
407 (void) iidetach(dip, DDI_DETACH);
408
409 return (DDI_FAILURE);
410 }
411
412 static int
413 iidetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
414 {
415 struct ii_state *xsp;
416 int instance;
417 intptr_t flags;
418
419 if (cmd != DDI_DETACH) {
420 return (DDI_FAILURE);
421 }
422
423 if (_ii_info_top) {
424 return (DDI_FAILURE); /* busy */
425 }
426
427 instance = ddi_get_instance(dip);
428 xsp = ddi_get_soft_state(ii_statep, instance);
429 if (xsp == NULL) {
430 cmn_err(CE_WARN,
431 "!ii: detach: could not get state for instance %d.",
432 instance);
433 return (DDI_FAILURE);
434 }
435
436 flags = (intptr_t)ddi_get_driver_private(dip);
437 if (flags & DIDNODES)
438 ddi_remove_minor_node(dip, NULL);
439 if (flags & DIDINIT)
440 _ii_deinit_dev();
441
442 ddi_soft_state_free(ii_statep, instance);
443
444 if (ii_gkstat) {
445 kstat_delete(ii_gkstat);
446 ii_gkstat = NULL;
447 }
448
449 return (DDI_SUCCESS);
450 }
451
452
453 /* ARGSUSED */
454
455 static int
456 iiopen(dev_t *devp, int flag, int otyp, cred_t *crp)
457 {
458 int error;
459
460 error = drv_priv(crp);
461
462 return (error);
463 }
464
465
466 /* ARGSUSED */
467
468 static int
469 iiclose(dev_t dev, int flag, int otyp, cred_t *crp)
470 {
471 return (0);
472 }
473
474 /* ARGSUSED */
475
476 static int
477 iiprint(dev_t dev, char *str)
478 {
479 int instance = 0;
480
481 cmn_err(CE_WARN, "!ii%d: %s", instance, str);
482 return (0);
483 }
484
485 /* ARGSUSED */
486
487 static int
488 iiioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp, int *rvp)
489 {
490 int rc;
491 int ilp32;
492
493 ilp32 = (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32);
494
495
496 switch (cmd) {
497 case DSWIOC_WAIT:
498 rc = _ii_wait(arg, ilp32, rvp);
499 break;
500
501 case DSWIOC_RESET:
502 rc = _ii_reset(arg, ilp32, rvp);
503 break;
504
505 case DSWIOC_VERSION:
506 rc = _ii_version(arg, ilp32, rvp);
507 break;
508
509 case DSWIOC_ENABLE:
510 rc = _ii_config(arg, ilp32, rvp, 0);
511 break;
512
513 case DSWIOC_RESUME:
514 rc = _ii_config(arg, ilp32, rvp, II_EXISTING);
515 break;
516
517 case DSWIOC_DISABLE:
518 rc = _ii_disable(arg, ilp32, rvp);
519 break;
520
521 case DSWIOC_SUSPEND:
522 rc = _ii_suspend(arg, ilp32, rvp);
523 break;
524
525 case DSWIOC_ACOPY:
526 rc = _ii_acopy(arg, ilp32, rvp);
527 break;
528
529 case DSWIOC_COPY:
530 rc = _ii_copy(arg, ilp32, rvp);
531 break;
532
533 case DSWIOC_SHUTDOWN:
534 rc = _ii_shutdown(arg, rvp);
535 break;
536
537 case DSWIOC_STAT:
538 rc = _ii_stat(arg, ilp32, rvp);
539 break;
540
541 case DSWIOC_BITMAP:
542 rc = _ii_bitmap(arg, ilp32, rvp);
543 break;
544
545 case DSWIOC_SEGMENT:
546 rc = _ii_segment(arg, ilp32, rvp);
547 break;
548
549 case DSWIOC_ABORT:
550 rc = _ii_abort(arg, ilp32, rvp);
551 break;
552
553 case DSWIOC_OFFLINE:
554 rc = _ii_offline(arg, ilp32, rvp);
555 break;
556
557 case DSWIOC_LIST:
558 rc = _ii_list(arg, ilp32, rvp);
559 break;
560
561 case DSWIOC_LISTLEN:
562 case DSWIOC_OLISTLEN:
563 rc = _ii_listlen(cmd, ilp32, rvp);
564 break;
565
566 case DSWIOC_EXPORT:
567 rc = _ii_export(arg, ilp32, rvp);
568 break;
569
570 case DSWIOC_IMPORT:
571 rc = _ii_config(arg, ilp32, rvp, II_IMPORT);
572 break;
573
574 case DSWIOC_JOIN:
575 rc = _ii_join(arg, ilp32, rvp);
576 break;
577
578 case DSWIOC_COPYP:
579 rc = _ii_copyparm(arg, ilp32, rvp);
580 break;
581
582 case DSWIOC_OCREAT:
583 rc = _ii_ocreate(arg, ilp32, rvp);
584 break;
585
586 case DSWIOC_OATTACH:
587 rc = _ii_oattach(arg, ilp32, rvp);
588 break;
589
590 case DSWIOC_ODETACH:
591 rc = _ii_odetach(arg, ilp32, rvp);
592 break;
593
594 case DSWIOC_OLIST:
595 rc = _ii_olist(arg, ilp32, rvp);
596 break;
597
598 case DSWIOC_OSTAT:
599 rc = _ii_ostat(arg, ilp32, rvp, FALSE);
600 break;
601
602 case DSWIOC_OSTAT2:
603 rc = _ii_ostat(arg, ilp32, rvp, TRUE);
604 break;
605
606 case DSWIOC_SBITSSET:
607 case DSWIOC_CBITSSET:
608 rc = _ii_bitsset(arg, ilp32, cmd, rvp);
609 break;
610
611 case DSWIOC_CLIST:
612 rc = _ii_gc_list(arg, ilp32, rvp, &_ii_cluster_mutex,
613 _ii_cluster_top);
614 break;
615
616 case DSWIOC_GLIST:
617 rc = _ii_gc_list(arg, ilp32, rvp, &_ii_group_mutex,
618 _ii_group_top);
619 break;
620
621 case DSWIOC_MOVEGRP:
622 rc = _ii_move_grp(arg, ilp32, rvp);
623 break;
624
625 case DSWIOC_CHANGETAG:
626 rc = _ii_change_tag(arg, ilp32, rvp);
627 break;
628
629 default:
630 rc = EINVAL;
631 break;
632 }
633
634 return (rc);
635 }
636
637 /*
638 * dummy function
639 */
640
641 static int
642 iistrat(struct buf *bp)
643 {
644 bp->b_error = EIO;
645 biodone(bp);
646
647 return (0);
648 }
649
650 static int
651 iiread()
652 {
653 return (EIO);
654 }