summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/lvm/mdvar.h
blob: c03847efb5a0f560c91bbd0beaca1b14b866a4b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_SYS_MDVAR_H
#define	_SYS_MDVAR_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/mkdev.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/t_lock.h>
#include <sys/open.h>
#include <sys/devops.h>
#include <sys/modctl.h>
#ifdef	DEBUG
#include <sys/thread.h>
#endif
#include <sys/kstat.h>
#include <sys/efi_partition.h>
#include <sys/byteorder.h>
#include <sys/door.h>

#include <sys/lvm/mdmn_commd.h>
#include <sys/lvm/mdio.h>
#include <sys/lvm/md_mdiox.h>
#include <sys/lvm/md_mddb.h>
#include <sys/lvm/md_notify.h>

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * defaults
 */
#define	NMD_DEFAULT		128	/* number of metadevices */
#define	MD_NOPS			25	/* number of misc modules */
#define	MAXBOOTLIST		64

/*
 * Needed for backwards-compatibility with metadevices created under
 * 2.6 or earlier.  Back then, a krwlock_t was twelve bytes.  More
 * recently, it's four bytes.  Since these get included in structures
 * written out to disk, we have to make sure we're using the largest
 * size.  Things will get interesting if krwlock_t ever gets bigger
 * than twelve bytes.
 */

typedef union _md_krwlock {
	krwlock_t	lock;
	struct {
		void	*_opaque[3];
	} xx;
} md_krwlock_t;

typedef struct {
	kmutex_t	md_io_mx;		/* counter mutex */
	kcondvar_t	md_io_cv;		/* ioctl wait on if draining */
	long		io_cnt;			/* number of I/Os */
	long		io_state;		/* !0 if waiting on zero */
} md_set_io_t;

typedef enum set_iostate {
	MD_SET_ACTIVE = 1,
	MD_SET_RELEASE = 2
}set_iostate_t;

/*
 * for md_dev64_t translation
 */
struct md_xlate_table {
	dev32_t		mini_devt;
	dev32_t		targ_devt;
};

extern struct md_xlate_table	*md_tuple_table;

/*
 * for major number translation
 */

struct md_xlate_major_table {
	char		*drv_name;
	major_t		targ_maj;
};

extern struct md_xlate_major_table *md_major_tuple_table;

extern int	md_tuple_length;
extern uint_t	md_majortab_len;
extern int	md_in_upgrade;

extern md_mn_nodeid_t	md_mn_mynode_id;

#define	MD_UPGRADE (md_in_upgrade == 1)

/*
 * Flags used during upgrade:
 *
 * md_keep_repl_state flag means that mddb should be kept in the format
 *   that was found on disk (non-device id format vs. device id format).
 *   This is used during the upgrade process when install is probing
 *   for root disks so that the user can choose the one to be upgraded.
 *
 * md_devid_destroy flag is used to destroy device ids stored in the
 *   metadevice state database (mddb).
 *
 *   The md_devid_destroy flag is to be used only in a catastrophic failure
 *   case. An example of this would be if a user upgrades firmware on all
 *   disks where this causes the disks to now have different device id's.
 *   The user would not be able to boot a mirror'd root filesystem since the
 *   system would recognize none of the device id's stored in the mddb.
 *   This flag would destroy all device id information stored in the mddb and
 *   if the md_keep_repl_state flag was not set, the mddb would be reconverted
 *   to device id format on SLVM startup and all of the device id
 *   information would be regenerated.
 *
 *   If the md_devid_destroy flag is set and the md_keep_repl_state flag is
 *   set, the mddb's would have their device id information destroyed and
 *   would be left in non-devid format since the device id information would
 *   not be regenerated.
 *
 *   This flag is not documented anywhere and is only to be used as a last
 *   resort as in the described case or if a device driver has a bug where
 *   device id's are found to not be unique.  If device id's aren't unique,
 *   the user could run without device id's until a patch is released for
 *   that driver.
 */
extern int	md_keep_repl_state;
extern int	md_devid_destroy;
extern int	mdmn_door_did;
#ifdef _KERNEL
extern door_handle_t	mdmn_door_handle;
#endif /* _KERNEL */

/*
 * An io_lock mechanism for raid, the MD_UL_XXXX bits are used for
 * convenience.
 */
typedef struct md_io_lock {
	ulong_t		io_readercnt;	/* number of unit readers */
	ulong_t		io_wanabecnt;	/* # pending on becoming unit writer */
	ulong_t		io_lock;
	void		*io_list_front;
	void		*io_list_back;
	kmutex_t	io_mx;
	kcondvar_t	io_cv;
	kmutex_t	io_list_mutex;	/* list of waiting io */
	kthread_id_t	io_owner;	/* writer thread */
} md_io_lock_t;

/*
 * The following flags are in un_flag field of mdc_unit struct.
 */
#define	MD_LABELED	0x1	/* First sector of the metadevice is a label */
#define	MD_EFILABEL	0x2	/* This md has an EFI label and no vtoc */

/*
 * This is the number of bytes a DKIOCGETEFI ioctl returns
 * For now it's one time the header and once the size for a partition info
 */
#define	MD_EFI_LABEL_SIZE (sizeof (efi_gpt_t) + sizeof (efi_gpe_t))

/* This is the number of bytes consumed by efi_gpe_PartitionName */
#define	MD_EFI_PARTNAME_BYTES (EFI_PART_NAME_LEN * sizeof (ushort_t))

typedef enum hs_cmds {
	HS_GET, HS_FREE, HS_BAD, HSP_INCREF, HSP_DECREF, HS_MKDEV
} hs_cmds_t;

typedef struct md_link {
	struct md_link	*ln_next;
	set_t		ln_setno;
	uint_t		ln_id;
} md_link_t;

typedef struct mdi_unit {
	md_link_t	ui_link;
	ulong_t		ui_readercnt;	/* number of unit readers */
	ulong_t		ui_wanabecnt;	/* # pending on becoming unit writer */
	ulong_t		ui_lock;
	kmutex_t	ui_mx;
	kcondvar_t	ui_cv;
	int		ui_opsindex;
	uint_t		ui_ocnt[OTYPCNT]; /* open counts */
	md_io_lock_t	*ui_io_lock;	/* pointer to io lock */
	kstat_t		*ui_kstat;	/* kernel statistics */
	kthread_id_t	ui_owner;	/* writer thread */
	uint_t		ui_tstate;	/* transient state bits */
	uint_t		ui_capab;	/* Capability bits supported */
} mdi_unit_t;

/*
 * Following are used with ui_lock
 * which is in the unit incore structure.
 */
#define	MD_UL_WRITER		0x0001 /* Stall all new strategy calls */
#define	MD_UL_WANABEWRITER	0x0002
#define	MD_UL_OPENORCLOSE	0x0004

#define	MD_UL_OPEN		0x0008	/* unit is open */
#define	MD_UL_EXCL		0x0010	/* unit is open exclusively */

/*
 * The softpart open code may do an I/O to validate the watermarks
 * and should hold no open locks during this I/O.  So, mark the unit
 * as OPENINPROGRESS and drop the locks.  This will keep any other
 * softpart open's waiting until the validate has completed.
 */
#define	MD_UL_OPENINPROGRESS	0x0020	/* Open in Progress */

/*
 * Following are used with ui_tstate to specify any transient states which
 * occur during metadevice operation. These are not written to the metadb as
 * they do not represent a failure of the underlying metadevice.
 * Transient errors are stored in the lower 16 bits and other transient
 * state is stored in the upper 16 bits.
 * MD_NOTOPENABLE should contain all the states that are set prior to an
 * open (by snarf) and that indicate that a metadevice cannot be opened.
 */
#define	MD_DEV_ERRORED		0x0000ffff /* ui_tstate error bits */
#define	MD_EOF_METADEVICE	0x00000001 /* EOF'd metadevice */
#define	MD_64MD_ON_32KERNEL	0x00000002 /* 64bit metadev on 32bit kernel */
#define	MD_INACCESSIBLE		0x00000004 /* metadevice unavailable */
#define	MD_RETRYING		0x00010000 /* retrying errored failfast I/O */
#define	MD_OPENLOCKED		0x00020000 /* MN: open locked before removing */
#define	MD_ERR_PENDING		0x00040000 /* MN: error pending */
#define	MD_ABR_CAP		0x00080000 /* MN: Application Based Recovery */
#define	MD_DMR_CAP		0x00100000 /* MN: Directed Mirror Read */
#define	MD_RELEASE_IOERR_DONE	0x00200000 /* ioerr console message done */
#define	MD_RESYNC_NOT_DONE	0x00400000 /* resync not done yet */

/* A metadevice cannot be opened when these states are set */
#define	MD_NOTOPENABLE		(MD_EOF_METADEVICE|MD_64MD_ON_32KERNEL)

typedef struct md_ioctl_lock {
	int		l_flags;	/* locks held */
	mdi_unit_t	*l_ui;		/* unit for which lock is held */
} md_ioctl_lock_t;

#define	MD_MASTER_DROPPED	0x0001
#define	MD_READER_HELD		0x0002
#define	MD_WRITER_HELD		0x0004
#define	MD_IO_HELD		0x0008
#define	MD_ARRAY_READER		0x0010
#define	MD_ARRAY_WRITER		0x0020
#define	STALE_OK		0x0100
#define	NO_OLD			0x0200
#define	NO_LOCK			0x0400
#define	MD_MT_IOCTL		0x80000 /* MD_GBL_IOCTL_LOCK not set */
#define	IOLOCK	md_ioctl_lock_t

#define	WR_LOCK			MD_WRITER_HELD
#define	RD_LOCK			MD_READER_HELD | STALE_OK
#define	ARRAY_WRITER		MD_ARRAY_WRITER
#define	ARRAY_READER		MD_ARRAY_READER
#define	WRITERS			MD_WRITER_HELD | MD_IO_HELD | MD_ARRAY_WRITER
#define	READERS			RD_LOCK | MD_ARRAY_READER

#define	IOLOCK_RETURN_IOCTLEND(code, lock) \
	md_ioctl_lock_exit((code), (lock)->l_flags, (lock)->l_ui, TRUE)

#define	IOLOCK_RETURN(code, lock) \
	md_ioctl_lock_exit((code), (lock)->l_flags, (lock)->l_ui, FALSE)

#define	IOLOCK_RETURN_RELEASE(code, lock) \
	md_ioctl_releaselocks((code), (lock)->l_flags, (lock)->l_ui)

#define	IOLOCK_RETURN_REACQUIRE(lock) \
	md_ioctl_reacquirelocks((lock)->l_flags, (lock)->l_ui)

#define	IOLOCK_INIT(lock)	bzero((caddr_t)(lock), sizeof (*(lock)))
/*
 * checks to be sure locks are held
 */
#define	UNIT_WRITER_HELD(un) \
	(MDI_UNIT(MD_SID(un))->ui_lock & MD_UL_WRITER)
#define	UNIT_READER_HELD(un) \
	(MDI_UNIT(MD_SID(un))->ui_readercnt != 0)
#define	IO_WRITER_HELD(un) \
	(MDI_UNIT(MD_SID(un))->ui_io_lock->io_lock & MD_UL_WRITER)
#define	IO_READER_HELD(un) \
	(MDI_UNIT(MD_SID(un))->ui_io_lock->io_readercnt != 0)

#ifdef  DEBUG
#define	STAT_INC(statvar)		\
	statvar++
#define	STAT_DEC(statvar)		\
	statvar--
#define	STAT_ZERO(statvar)		\
	statvar = 0;
#define	STAT_MAX(statmax, statvar)	\
	{				\
	statvar++;			\
	if (statvar > statmax)		\
		statmax = statvar;	\
	}
#define	STAT_CHECK(statvar, value)	\
	{				\
	if (value)			\
		statvar++;		\
	}
#else
#define	STAT_INC(statvar)
#define	STAT_DEC(statvar)
#define	STAT_ZERO(statvar)
#define	STAT_MAX(statmax, statvar)
#define	STAT_CHECK(statvar, value)
#endif
/*
 * bit map related macros
 */
#define	setbit(a, i)	((a)[(i)/NBBY] |= 1<<((i)%NBBY))
#define	clrbit(a, i)	((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
#define	isset(a, i)	((a)[(i)/NBBY] & (1<<((i)%NBBY)))
#define	isclr(a, i)	(((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)

typedef struct daemon_queue {
	int	maxq_len;
	int	qlen;
	int	treqs;		/* total number of requests */
	struct daemon_queue	*dq_next;
	struct daemon_queue	*dq_prev;
	void			(*dq_call)();
} daemon_queue_t;

#define	DAEMON_QUEUE daemon_queue_t	dq;

#ifdef _KERNEL
#include	<sys/buf.h>
#include	<sys/dkio.h>
#include	<sys/vtoc.h>

#define	MD_DEV2SET(d)	(MD_MIN2SET(md_getminor(d)))

#define	MD_UNIT(m)	(md_set[MD_MIN2SET(m)].s_un[MD_MIN2UNIT(m)])
#define	MDI_UNIT(m)	((mdi_unit_t *) \
			    md_set[MD_MIN2SET(m)].s_ui[MD_MIN2UNIT(m)])
#define	MD_VOIDUNIT(m)	(md_set[MD_MIN2SET(m)].s_un[MD_MIN2UNIT(m)])
#define	MDI_VOIDUNIT(m)	(md_set[MD_MIN2SET(m)].s_ui[MD_MIN2UNIT(m)])

/*
 * This is the current maximum number of real disks per Virtual Disk.
 */
extern	uint_t	md_mdelay;	/* md_mirror timeout delay */

#define	MD_ADM_MINOR		L_MAXMIN32 /* the minor number for md_admin */
#define	MD_MDELAY		(md_mdelay)
#define	NUM_USEC_IN_SEC		1000000 /* 1 million usec in a second */

#define	ANY_SERVICE		-1	/* md_get_named_service() wild card */

/*
 * daemon threads are used in multiple places in md. The following set of
 * structures and routines allow a common way to create and initialize them.
 *
 * md_requestq_entry_t - entry of creating request queues.
 * struct mdq_anchor - request queue header
 *
 * Functions associated with request queues:
 *
 * int init_requestq_entry -
 * void daemon_request - put a request on the queue.
 */

typedef struct md_requestq_entry {
	struct mdq_anchor	*dispq_headp;
	int		*num_threadsp; /* threads servicing the queue */
} md_requestq_entry_t;

#define	NULL_REQUESTQ_ENTRY(rqp)\
		((rqp)->dispq_headp == NULL || (rqp)->num_threadsp == NULL)

/* this typedef is used to differentiate between the two call styles */
typedef enum callstyle {
	REQ_OLD,
	REQ_NEW
} callstyle_t;


#define	daemon_request_new daemon_request

typedef struct mdq_anchor {
	DAEMON_QUEUE
	kcondvar_t	 a_cv;		/* Request has been put on queue */
	kmutex_t	 a_mx;
} mdq_anchor_t;

typedef struct daemon_request {
	DAEMON_QUEUE
	kmutex_t	dr_mx;
	int		dr_pending;
	timeout_id_t	dr_timeout_id;
} daemon_request_t;

typedef struct sv_dev {
	set_t	setno;
	side_t	side;
	mdkey_t	key;
} sv_dev_t;

/*
 * Types of device probes
 */


typedef struct probe_req {
	DAEMON_QUEUE
	minor_t mnum;			/* mnum of the metadevice to probe */
	void   *private_handle;		/* private handle */
	intptr_t (*probe_fcn)();	/* type of probeing to be done */
} probe_req_t;

/* Global flags */
#define	MD_NO_GBL_LOCKS_HELD	0x0000	/* currently holding no global locks */
#define	MD_GBL_DAEMONS_LIVE	0x0001	/* master daemon has been started. */
#define	MD_GBL_DAEMONS_DIE	0x0002
#define	MD_GBL_HALTED		0x0004	/* driver is shut down */

/* Available bit was GBL_STALE	0x0008	*/

#define	MD_GBL_IOCTL_LOCK	0x0010	/* single-threads ioctls */
#define	MD_GBL_HS_LOCK		0x0020	/* single-threads hotspares */
#define	MD_GBL_OPEN		0x0040	/* admin is open */
#define	MD_GBL_EXCL		0x0080	/* admin is open exclusively */

#define	MD_OFLG_NULL		0x0000	/* Null flag */
#define	MD_OFLG_CONT_ERRS	0x0001	/* Continue on open errors */
#define	MD_OFLG_PROBEDEV	0x0002  /* force a simulated open */
#define	MD_OFLG_ISINIT		0x0004  /* raid initialization */
#define	MD_OFLG_FROMIOCTL	0x0008  /* Called from an ioctl handler */


typedef struct md_named_services {

	intptr_t	(*md_service)();
	char		*md_name;
} md_named_services_t;

typedef enum md_snarfcmd {MD_SNARF_CLEANUP, MD_SNARF_DOIT} md_snarfcmd_t;

typedef struct md_ops {
	int	(*md_open)(
		    dev_t		*devp,
		    int			flag,
		    int			otyp,
		    cred_t		*credp,
		    int			md_oflags);
	int	(*md_close)(
		    dev_t		dev,
		    int			flag,
		    int			otyp,
		    cred_t		*credp,
		    int			md_oflags);
	void	(*md_strategy)(
		    buf_t		*bufp,
		    int			flag,
		    void		*private);
	int	(*md_print)();		/* unused now */
	int	(*md_dump)(
		    dev_t		dev,
		    caddr_t		addr,
		    daddr_t		blkno,
		    int			nblk);
	int	(*md_read)(
		    dev_t		dev,
		    struct uio		*uiop,
		    cred_t		*credp);
	int	(*md_write)(
		    dev_t		dev,
		    struct uio		*uiop,
		    cred_t		*credp);
	int	(*md_ioctl)(
		    dev_t		dev,
		    int			cmd,
		    void		*data,
		    int			mode,
		    IOLOCK		*lockp);
	int	(*md_snarf)(
		    md_snarfcmd_t	cmd,
		    set_t		setno);
	int	(*md_halt)();
	int	(*md_aread)(
		    dev_t		dev,
		    struct aio_req	*aiop,
		    cred_t		*credp);
	int	(*md_awrite)(
		    dev_t		dev,
		    struct aio_req	*aiop,
		    cred_t		*credp);
	int	(*md_imp_set)(
		    set_t		setno);
	md_named_services_t	*md_services;
	md_krwlock_t		md_link_rw;
	md_link_t		*md_head;
	/*
	 * NOTE: when TSlvm s10/onnv compatibility is not an issue:
	 *	o md_modid and md_locked should be deleted.
	 *	o md_mod should be added
	 *		ddi_modhandle_t		md_mod;
	 *	  and used instead of the md_mods array (md_mods should
	 *	  be deleted).
	 */
	int			md_modid;
	int			md_locked;
	int			md_selfindex;
	struct md_ops		*md_next;
	md_driver_t		md_driver;
	/* NOTE: TSlvm depends on offsets in and sizeof this structure */
} md_ops_t;

/* macro to generate linkage for a md misc plugin module */
#define	md_noop
#define	MD_PLUGIN_MISC_MODULE(desc, init_init, fini_uninit)		\
	static struct modlmisc		modlmisc = {			\
		&mod_miscops, "Solaris Volume Manager " desc		\
	};								\
	static struct modlinkage	modlinkage = {			\
		MODREV_1, (void *)&modlmisc, NULL			\
	};								\
	int								\
	_init(void)							\
	{								\
		int	i;						\
		init_init;						\
		if ((i = mod_install(&modlinkage)) != 0) {		\
			fini_uninit;					\
		}							\
		return (i);						\
	}								\
	int								\
	_fini()								\
	{								\
		int	i;                                              \
		if ((i = mod_remove(&modlinkage)) == 0) {		\
			fini_uninit;					\
		}							\
		return (i);						\
	}								\
	int								\
	_info(struct modinfo *modinfop)					\
	{								\
		return (mod_info(&modlinkage, modinfop));		\
	}

typedef enum md_haltcmd {MD_HALT_ALL, MD_HALT_CHECK, MD_HALT_DOIT,
			MD_HALT_CLOSE, MD_HALT_OPEN, MD_HALT_UNLOAD
} md_haltcmd_t;

/*
 * To support cpr (Energy Star) we need to know when the resync threads are
 * running to not allow suspention.
 */
typedef struct md_resync_thds_cnt {
	int md_raid_resync;	/* count of active raid resync threads */
	int md_mirror_resync;	/* count of active mirror resync threads */
	kmutex_t md_resync_mutex;	/* protects both resync counts */
} md_resync_t;

/*
 * flags used with call to individual strategy routines
 */
#define	MD_STR_PASSEDON 0x0000ffff
#define	MD_STR_NOTTOP	0x00000001
#define	MD_STR_MAPPED	0x00000002	/* set when buf_t is mapped in	*/
#define	MD_STR_ABR	0x00000004	/* use ABR to handle any recovery */
#define	MD_STR_WMUPDATE	0x00000008	/* set if updating watermarks for sp */
#define	MD_IO_COUNTED	0x00000400	/* io has been counted */
#define	MD_NOBLOCK	0x00000800	/* do not block io durring release */

#define	MD_STR_WAR	0x00010000	/* this write is write after read */
#define	MD_STR_WOW	0x00020000	/* handling a write-on-write */
#define	MD_STR_DMR	0x00040000	/* Directed Read request */
#define	MD_STR_DIRTY_RD	0x00080000	/* Read of a dirty block */
#define	MD_STR_FLAG_ERR	0x00100000	/* Flag any write error on this i/o */

/*
 * Bits for return value of md_getdevnum
 */
#define	MD_TRUST_DEVT	1
#define	MD_NOTRUST_DEVT	0

/* Flag for drivers to pass to kmem_cache_alloc() */
#define	MD_ALLOCFLAGS   (KM_PUSHPAGE | KM_SLEEP)

/* Named services */
#define	MD_CHECK_OFFLINE	"check_offline"
#define	MD_INC_ABR_COUNT	"inc abr count"
#define	MD_DEC_ABR_COUNT	"dec abr count"

/* Externals from md.c */
extern int	md_snarf_db_set(set_t setno, md_error_t *ep);
extern void	get_info(struct dk_cinfo *, minor_t);
extern void	get_minfo(struct dk_minfo *, minor_t);
extern int	mdstrategy(buf_t *);
extern int	md_create_minor_node(set_t, minor_t);


/* External from md_subr.c */
extern int	md_inc_iocount(set_t);
extern void	md_inc_iocount_noblock(set_t);
extern void	md_dec_iocount(set_t);
extern int	md_isblock_setio(set_t);
extern int	md_block_setio(set_t);
extern void	md_clearblock_setio(set_t);
extern void	md_unblock_setio(set_t);
extern int	md_tas_block_setio(set_t);
extern void	md_biodone(struct buf *);
extern void	md_bioreset(struct buf *);
extern md_dev64_t md_xlate_targ_2_mini(md_dev64_t);
extern md_dev64_t md_xlate_mini_2_targ(md_dev64_t);
extern void	md_xlate_free(int);
extern major_t	md_targ_name_to_major(char *);
extern char	*md_targ_major_to_name(major_t);
extern void	md_majortab_free();
extern void	md_set_status(int);
extern void	md_clr_status(int);
extern int	md_get_status(void);
extern void	md_set_setstatus(set_t, int);
extern void	md_clr_setstatus(set_t, int);
extern uint_t	md_get_setstatus(set_t);
extern void	*md_unit_readerlock(mdi_unit_t *);
extern void	*md_unit_writerlock(mdi_unit_t *);
extern void	md_unit_readerexit(mdi_unit_t *);
extern void	md_unit_writerexit(mdi_unit_t *);
extern void	md_ioctl_releaselocks(int, int, mdi_unit_t *);
extern void	md_ioctl_reacquirelocks(int, mdi_unit_t *);
extern int	md_ioctl_lock_exit(int, int, mdi_unit_t *, int);
extern int	md_ioctl_lock_enter(void);
extern void	*md_ioctl_readerlock(IOLOCK *, mdi_unit_t *);
extern void	md_ioctl_readerexit(IOLOCK *);
extern void	*md_ioctl_writerlock(IOLOCK *, mdi_unit_t *);
extern void	md_ioctl_writerexit(IOLOCK *);
extern void	md_ioctl_io_exit(IOLOCK *);
extern void	*md_ioctl_io_lock(IOLOCK *, mdi_unit_t *);
extern void	md_ioctl_droplocks(IOLOCK *);
extern void	md_array_writer(IOLOCK *);
extern void	md_array_reader(IOLOCK *);
extern void	*md_ioctl_openclose_enter(IOLOCK *, mdi_unit_t *);
extern void	md_ioctl_openclose_exit(IOLOCK *);
extern void	md_ioctl_openclose_exit_lh(IOLOCK *);
extern void	*md_unit_openclose_enter(mdi_unit_t *);
extern void	md_unit_openclose_exit(mdi_unit_t *);
extern void	md_unit_openclose_exit_lh(mdi_unit_t *);
extern int	md_unit_isopen(mdi_unit_t *ui);
extern int	md_unit_incopen(minor_t mnum, int flag, int otyp);
extern int	md_unit_decopen(minor_t mnum, int otyp);
extern void	*md_io_readerlock(mdi_unit_t *);
extern void	*md_io_writerlock(mdi_unit_t *);
extern void	md_io_readerexit(mdi_unit_t *);
extern void	md_io_writerexit(mdi_unit_t *);
extern intptr_t	(*md_get_named_service())();
extern int	init_requestq(md_requestq_entry_t *, void (*)(),
						caddr_t, int, int);
extern void	daemon_request(mdq_anchor_t *, void(*)(),
				daemon_queue_t *, callstyle_t);
extern void	md_daemon(int, mdq_anchor_t *);
extern void	mddb_commitrec_wrapper(mddb_recid_t);
extern void	mddb_commitrecs_wrapper(mddb_recid_t *);
extern void	mddb_deleterec_wrapper(mddb_recid_t);
extern void	md_holdset_enter(set_t setno);
extern void	md_holdset_exit(set_t setno);
extern int	md_holdset_testandenter(set_t setno);
extern void	md_haltsnarf_enter(set_t setno);
extern void	md_haltsnarf_exit(set_t setno);
extern void	md_haltsnarf_wait(set_t setno);
extern int	md_halt_set(set_t setno, enum md_haltcmd cmd);
extern int	md_halt(int global_lock_flag);
extern int	md_layered_open(minor_t, md_dev64_t *, int);
extern void	md_layered_close(md_dev64_t, int);
extern char	*md_get_device_name(md_dev64_t);
extern int	errdone(mdi_unit_t *, struct buf *, int);
extern int	md_checkbuf(mdi_unit_t *, md_unit_t *, buf_t *);
extern int	md_start_daemons(int init_queues);
extern int	md_loadsubmod(set_t, char *, int);
extern int	md_getmodindex(md_driver_t *, int, int);
extern void	md_call_strategy(buf_t *, int, void *);
extern int	md_call_ioctl(md_dev64_t, int, void *, int, IOLOCK *);
extern void	md_rem_link(set_t, int, krwlock_t *, md_link_t **);
extern int	md_dev_exists(md_dev64_t);
extern md_parent_t md_get_parent(md_dev64_t);
extern void	md_set_parent(md_dev64_t, md_parent_t);
extern void	md_reset_parent(md_dev64_t);
extern struct hot_spare_pool *find_hot_spare_pool(set_t, int);
extern int	md_hot_spare_ifc(hs_cmds_t, mddb_recid_t, u_longlong_t, int,
		    mddb_recid_t *, mdkey_t *, md_dev64_t *, diskaddr_t *);
extern int	md_notify_interface(md_event_cmds_t cmd, md_tags_t type,
		set_t set, md_dev64_t dev, md_event_type_t event);
extern void	svm_gen_sysevent(char *se_class, char *se_subclass,
		    uint32_t tag, set_t setno, md_dev64_t devid);
extern void	md_create_unit_incore(minor_t, md_ops_t *, int);
extern void	md_destroy_unit_incore(minor_t, md_ops_t *);
extern void	md_rem_names(sv_dev_t *, int);
struct uio;
extern int	md_chk_uio(struct uio *);
extern char	*md_shortname(minor_t mnum);
extern char	*md_devname(set_t setno, md_dev64_t dev, char *buf,
		size_t size);
extern void	md_minphys(buf_t *);
extern void	md_kstat_init(minor_t mnum);
extern void	md_kstat_init_ui(minor_t mnum, mdi_unit_t *ui);
extern void	md_kstat_destroy(minor_t mnum);
extern void	md_kstat_destroy_ui(mdi_unit_t *ui);
extern void	md_kstat_waitq_enter(mdi_unit_t *ui);
extern void	md_kstat_waitq_to_runq(mdi_unit_t *ui);
extern void	md_kstat_waitq_exit(mdi_unit_t *ui);
extern void	md_kstat_runq_enter(mdi_unit_t *ui);
extern void	md_kstat_runq_exit(mdi_unit_t *ui);
extern void	md_kstat_done(mdi_unit_t *ui, buf_t *bp, int war);
extern pid_t	md_getpid(void);
extern proc_t	*md_getproc(void);
extern int	md_checkpid(pid_t pid, proc_t *proc);
extern char	*md_strdup(char *cp);
extern void	freestr(char *cp);
extern int	md_check_ioctl_against_efi(int, ushort_t);
extern mddb_recid_t md_vtoc_to_efi_record(mddb_recid_t, set_t);

extern int	mdmn_ksend_message(set_t, md_mn_msgtype_t, uint_t, char *, int,
		    md_mn_kresult_t *);
extern void	mdmn_ksend_show_error(int, md_mn_kresult_t *, const char *);
extern int	mdmn_send_capability_message(minor_t, volcap_t, IOLOCK *);
extern void	mdmn_clear_all_capabilities(minor_t);
extern int	md_init_probereq(struct md_probedev_impl *p,
		    daemon_queue_t **hdrpp);
extern boolean_t callb_md_mrs_cpr(void *, int);
extern void	md_upd_set_unnext(set_t, unit_t);
extern int	md_rem_selfname(minor_t);
extern void	md_rem_hspname(set_t, mdkey_t);

/* Externals from md_ioctl.c */
extern int	md_mn_is_commd_present(void);
extern void	md_mn_clear_commd_present(void);
extern int	md_admin_ioctl(md_dev64_t, int, caddr_t, int, IOLOCK *lockp);
extern void	md_get_geom(md_unit_t *, struct dk_geom *);
extern void	md_get_vtoc(md_unit_t *, struct vtoc *);
extern int	md_set_vtoc(md_unit_t *, struct vtoc *);
extern void	md_get_cgapart(md_unit_t *, struct dk_map *);
extern void	md_get_efi(md_unit_t *, char *);
extern int	md_set_efi(md_unit_t *, char *);
extern int	md_dkiocgetefi(minor_t, void *, int);
extern int	md_dkiocsetefi(minor_t, void *, int);
extern int	md_dkiocpartition(minor_t, void *, int);
extern void	md_remove_minor_node(minor_t);


/* Externals from md_names.c */
extern mdkey_t	md_setdevname(set_t, side_t, mdkey_t, char *, minor_t, char *,
		    int imp_flag, ddi_devid_t devid, char *minorname,
			set_t, md_error_t *);
extern int	md_getdevname(set_t, side_t, mdkey_t, md_dev64_t, char *,
		    size_t);
extern int	md_gethspinfo(set_t, side_t, mdkey_t, char *, hsp_t *,
		    char *);
extern int	md_getkeyfromdev(set_t, side_t, md_dev64_t, mdkey_t *, int *);
extern int	md_devid_found(set_t, side_t, mdkey_t);
extern int	md_getnment(set_t, side_t, mdkey_t, md_dev64_t,
		    char *, uint_t, major_t *, minor_t *, mdkey_t *);
extern md_dev64_t md_getdevnum(set_t, side_t, mdkey_t, int);
extern mdkey_t	md_getnextkey(set_t, side_t, mdkey_t, uint_t *);
extern int	md_remdevname(set_t, side_t, mdkey_t);
extern mdkey_t	md_setshared_name(set_t, char *, int);
extern char	*md_getshared_name(set_t, mdkey_t);
extern int	md_remshared_name(set_t, mdkey_t);
extern mdkey_t	md_getshared_key(set_t, char *);
extern int	md_setshared_data(set_t, uint_t, caddr_t);
extern caddr_t	md_getshared_data(set_t, uint_t);
extern int	md_load_namespace(set_t, md_error_t *ep, int);
extern void	md_unload_namespace(set_t, int);
extern int	md_nm_did_chkspace(set_t);
extern void	md_bioinit();
extern buf_t	*md_bioclone(buf_t *, off_t, size_t, dev_t, diskaddr_t,
		    int (*)(buf_t *), buf_t *, int);
extern int	md_getdevid(set_t setno, side_t side, mdkey_t key,
		    ddi_devid_t devid, ushort_t *did_size);
extern int	md_getdevidminor(set_t setno, side_t side, mdkey_t key,
		    char *minorname, size_t minorname_len);
extern int	md_update_namespace(set_t setno, side_t side, mdkey_t key,
		    caddr_t devname, caddr_t pathname, minor_t mnum);
extern int	md_update_locator_namespace(set_t setno, side_t side,
		    caddr_t devname, caddr_t pathname, md_dev64_t devt);
extern int	md_update_namespace_did(set_t setno, side_t side, mdkey_t key,
		    md_error_t *ep);
extern int	md_validate_devid(set_t setno, side_t side, int *maxsz);
extern int	md_get_invdid(set_t setno, side_t side, int cnt, int maxsz,
		    void *didptr);
extern md_dev64_t md_resolve_bydevid(minor_t, md_dev64_t, mdkey_t key);
extern md_dev64_t md_expldev(md_dev64_t);
extern dev32_t	md_cmpldev(md_dev64_t);
extern dev_t	md_dev64_to_dev(md_dev64_t);
extern md_dev64_t md_makedevice(major_t, minor_t);
extern major_t	md_getmajor(md_dev64_t);
extern minor_t	md_getminor(md_dev64_t);
extern void	md_timeval(md_timeval32_t *);
extern int	md_imp_snarf_set(mddb_config_t *);

/* externals from md_mddb.c */
extern int	mddb_reread_rr(set_t, mddb_recid_t);
extern int	mddb_setowner(mddb_recid_t id, md_mn_nodeid_t owner);
extern int	mddb_parse(mddb_parse_parm_t *mpp);
extern int	mddb_block(mddb_block_parm_t *mpp);
extern int	mddb_optrecfix(mddb_optrec_parm_t *mop);
extern int	mddb_check_write_ioctl(mddb_config_t *info);
extern int	mddb_setflags_ioctl(mddb_setflags_config_t *info);
extern struct nm_next_hdr	*get_first_record(set_t, int, int);
extern void	*lookup_entry(struct nm_next_hdr *, set_t,
			side_t, mdkey_t, md_dev64_t, int);
extern void	*lookup_shared_entry(struct nm_next_hdr *,
		    mdkey_t key, char *, mddb_recid_t *, int);
extern int	remove_shared_entry(struct nm_next_hdr *, mdkey_t key,
		    char *, int);
extern void	*alloc_entry(struct nm_next_hdr *, mddb_recid_t, size_t, int,
		    mddb_recid_t *);
extern void	*getshared_name(set_t, mdkey_t, int);

#endif	/* _KERNEL */


/* externals from md_revchk.c */
extern int	revchk(uint_t my_rev, uint_t data);


#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_MDVAR_H */