xref: /illumos-gate/usr/src/uts/common/sys/scsi/adapters/scsi_vhci.h (revision e419e0b925dd3f5ad1af3e71a7d6d26b816d278c)
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 /*
23  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 /*
26  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
27  * Copyright 2024 RackTop Systems, Inc.
28  */
29 
30 #ifndef	_SYS_SCSI_ADAPTERS_SCSI_VHCI_H
31 #define	_SYS_SCSI_ADAPTERS_SCSI_VHCI_H
32 
33 /*
34  * Multiplexed I/O SCSI vHCI global include
35  */
36 #include <sys/note.h>
37 #include <sys/taskq.h>
38 #include <sys/mhd.h>
39 #include <sys/sunmdi.h>
40 #include <sys/mdi_impldefs.h>
41 #include <sys/scsi/adapters/mpapi_impl.h>
42 #include <sys/scsi/adapters/mpapi_scsi_vhci.h>
43 
44 #ifdef	__cplusplus
45 extern "C" {
46 #endif
47 
48 #if !defined(_BIT_FIELDS_LTOH) && !defined(_BIT_FIELDS_HTOL)
49 #error	One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
50 #endif  /* _BIT_FIELDS_LTOH */
51 
52 #ifdef	_KERNEL
53 
54 #ifdef	UNDEFINED
55 #undef	UNDEFINED
56 #endif
57 #define	UNDEFINED		-1
58 
59 #define	VHCI_STATE_OPEN		0x00000001
60 
61 
62 #define	VH_SLEEP		0x0
63 #define	VH_NOSLEEP		0x1
64 
65 /*
66  * HBA interface macros
67  */
68 
69 #define	TRAN2HBAPRIVATE(tran)	((struct scsi_vhci *)(tran)->tran_hba_private)
70 #define	VHCI_INIT_WAIT_TIMEOUT	60000000
71 #define	VHCI_FOWATCH_INTERVAL	1000000		/* in usecs */
72 #define	VHCI_EXTFO_TIMEOUT	(3 * 60 * NANOSEC)	/* 3 minutes in nsec */
73 
74 #define	SCBP_C(pkt)	((*(pkt)->pkt_scbp) & STATUS_MASK)
75 
76 int vhci_do_scsi_cmd(struct scsi_pkt *);
77 /*PRINTFLIKE3*/
78 void vhci_log(int, dev_info_t *, const char *, ...);
79 
80 size_t vhci_get_blocksize(dev_info_t *);
81 
82 /*
83  * debugging stuff
84  */
85 
86 #ifdef	DEBUG
87 
88 #ifndef VHCI_DEBUG_DEFAULT_VAL
89 #define	VHCI_DEBUG_DEFAULT_VAL		0
90 #endif	/* VHCI_DEBUG_DEFAULT_VAL */
91 
92 extern int vhci_debug;
93 
94 #include <sys/debug.h>
95 
96 #define	VHCI_DEBUG(level, stmnt) \
97 	    if (vhci_debug >= (level)) vhci_log stmnt
98 
99 #else	/* !DEBUG */
100 
101 #define	VHCI_DEBUG(level, stmnt)
102 
103 #endif	/* !DEBUG */
104 
105 
106 
107 #define	VHCI_PKT_PRIV_SIZE		2
108 
109 #define	ADDR2VHCI(ap)	((struct scsi_vhci *) \
110 			((ap)->a_hba_tran->tran_hba_private))
111 #define	ADDR2VLUN(ap)	(scsi_vhci_lun_t *) \
112 			(scsi_device_hba_private_get(scsi_address_device(ap)))
113 #define	ADDR2DIP(ap)	((dev_info_t *)(scsi_address_device(ap)->sd_dev))
114 
115 #define	HBAPKT2VHCIPKT(pkt) (pkt->pkt_private)
116 #define	TGTPKT2VHCIPKT(pkt) (pkt->pkt_ha_private)
117 #define	VHCIPKT2HBAPKT(pkt) (pkt->pkt_hba_pkt)
118 #define	VHCIPKT2TGTPKT(pkt) (pkt->pkt_tgt_pkt)
119 
120 #define	VHCI_DECR_PATH_CMDCOUNT(svp) { \
121 	mutex_enter(&(svp)->svp_mutex); \
122 	(svp)->svp_cmds--; \
123 	if ((svp)->svp_cmds == 0)  \
124 		cv_broadcast(&(svp)->svp_cv); \
125 	mutex_exit(&(svp)->svp_mutex); \
126 }
127 
128 #define	VHCI_INCR_PATH_CMDCOUNT(svp) { \
129 	mutex_enter(&(svp)->svp_mutex); \
130 	(svp)->svp_cmds++; \
131 	mutex_exit(&(svp)->svp_mutex); \
132 }
133 
134 /*
135  * When a LUN is HELD it results in new IOs being returned to the target
136  * driver layer with TRAN_BUSY.  Should be used while performing
137  * operations that require prevention of any new IOs to the LUN and
138  * the LUN should be HELD for the duration of such operations.
139  * f can be VH_SLEEP or VH_NOSLEEP.
140  * h is set to 1 to indicate LUN was successfully HELD.
141  * h is set to 0 when f is VH_NOSLEEP and LUN is already HELD.
142  *
143  * Application examples:
144  *
145  * 1) SCSI-II RESERVE: HOLD LUN until it is quiesced and the load balancing
146  * policy is switched to NONE before proceeding with RESERVE handling.
147  *
148  * 2) Failover: HOLD LUN before initiating failover.
149  *
150  * 3) When an externally initiated failover is detected, HOLD LUN until all
151  * path states have been refreshed to reflect the new value.
152  *
153  */
154 #define	VHCI_HOLD_LUN(vlun, f, h) { \
155 	int sleep = (f); \
156 	mutex_enter(&(vlun)->svl_mutex); \
157 	if ((vlun)->svl_transient == 1) { \
158 		if (sleep == VH_SLEEP) { \
159 			while ((vlun)->svl_transient == 1) \
160 				cv_wait(&(vlun)->svl_cv, &(vlun)->svl_mutex); \
161 			(vlun)->svl_transient = 1; \
162 			(h) = 1; \
163 		} else { \
164 			(h) = 0; \
165 		} \
166 	} else { \
167 		(vlun)->svl_transient = 1; \
168 		(h) = 1; \
169 	} \
170 	sleep = (h); \
171 	mutex_exit(&(vlun)->svl_mutex); \
172 }
173 
174 #define	VHCI_RELEASE_LUN(vlun) { \
175 	mutex_enter(&(vlun)->svl_mutex); \
176 	(vlun)->svl_transient = 0; \
177 	cv_broadcast(&(vlun)->svl_cv); \
178 	mutex_exit(&(vlun)->svl_mutex); \
179 }
180 
181 #define	VHCI_LUN_IS_HELD(vlun)	((vlun)->svl_transient == 1)
182 
183 /*
184  * vhci_pkt states
185  */
186 #define	VHCI_PKT_IDLE			0x01
187 #define	VHCI_PKT_ISSUED			0x02
188 #define	VHCI_PKT_ABORTING		0x04
189 #define	VHCI_PKT_STALE_BINDING		0x08
190 /*
191  * Set the first time taskq is dispatched from scsi_start for
192  * a packet.  To ensure vhci_scsi_start recognizes that the scsi_pkt
193  * is being issued from the taskq and not target driver.
194  */
195 #define	VHCI_PKT_THRU_TASKQ		0x20
196 /*
197  * Set the first time failover is being triggered. To ensure
198  * failover won't be triggered again when the packet is being
199  * retried by target driver.
200  */
201 #define	VHCI_PKT_IN_FAILOVER		0x40
202 
203 #define	VHCI_PKT_TIMEOUT		30		/* seconds */
204 #define	VHCI_PKT_RETRY_CNT		2
205 #define	VHCI_POLL_TIMEOUT		60		/* seconds */
206 
207 /*
208  * define extended scsi cmd pkt
209  */
210 #define	EXTCMDS_STATUS_SIZE		(sizeof (struct scsi_arq_status))
211 
212 #define	CFLAG_NOWAIT		0x1000	/* don't sleep */
213 #define	CFLAG_DMA_PARTIAL	0x2000	/* Support Partial DMA */
214 
215 /*
216  * Maximum size of SCSI cdb in SCSI command
217  */
218 #define	VHCI_SCSI_CDB_SIZE		16
219 #define	VHCI_SCSI_SCB_SIZE		(sizeof (struct scsi_arq_status))
220 
221 /*
222  * OSD specific definitions
223  */
224 #define	VHCI_SCSI_OSD_CDB_SIZE		224
225 #define	VHCI_SCSI_OSD_PKT_FLAGS		0x100000
226 
227 /*
228  * flag to determine failover support
229  */
230 #define	SCSI_NO_FAILOVER	0x0
231 #define	SCSI_IMPLICIT_FAILOVER	0x1
232 #define	SCSI_EXPLICIT_FAILOVER	0x2
233 #define	SCSI_BOTH_FAILOVER \
234 	(SCSI_IMPLICIT_FAILOVER |  SCSI_EXPLICIT_FAILOVER)
235 
236 struct	scsi_vhci_swarg;
237 
238 #define	VHCI_NUM_RESV_KEYS	8
239 
240 typedef struct vhci_prin_readkeys {
241 	uint32_t		generation;
242 	uint32_t		length;
243 	mhioc_resv_key_t	keylist[VHCI_NUM_RESV_KEYS];
244 } vhci_prin_readkeys_t;
245 
246 #define	VHCI_PROUT_SIZE	\
247 	((sizeof (vhci_prout_t) - 2 * (MHIOC_RESV_KEY_SIZE) * sizeof (char)))
248 
249 typedef struct vhci_prout {
250 	/* PGR register parameters start */
251 	uchar_t		res_key[MHIOC_RESV_KEY_SIZE];
252 	uchar_t		service_key[MHIOC_RESV_KEY_SIZE];
253 	uint32_t	scope_address;
254 
255 #if defined(_BIT_FIELDS_LTOH)
256 	uchar_t		aptpl:1,
257 			reserved:7;
258 #else
259 	uchar_t		reserved:7,
260 			aptpl:1;
261 #endif /* _BIT_FIELDS_LTOH */
262 
263 	uchar_t		reserved_1;
264 	uint16_t	ext_len;
265 	/* PGR register parameters end */
266 
267 	/* Update VHCI_PROUT_SIZE if new fields are added here */
268 
269 	uchar_t		active_res_key[MHIOC_RESV_KEY_SIZE];
270 	uchar_t		active_service_key[MHIOC_RESV_KEY_SIZE];
271 } vhci_prout_t;
272 
273 #define	VHCI_PROUT_REGISTER	0x0
274 #define	VHCI_PROUT_RESERVE	0x1
275 #define	VHCI_PROUT_RELEASE	0x2
276 #define	VHCI_PROUT_CLEAR	0x3
277 #define	VHCI_PROUT_PREEMPT	0x4
278 #define	VHCI_PROUT_P_AND_A	0x5
279 #define	VHCI_PROUT_R_AND_IGNORE	0x6
280 
281 struct vhci_pkt {
282 	struct scsi_pkt			*vpkt_tgt_pkt;
283 	mdi_pathinfo_t			*vpkt_path;	/* path pkt bound to */
284 
285 	/*
286 	 * pHCI packet that does the actual work.
287 	 */
288 	struct scsi_pkt			*vpkt_hba_pkt;
289 
290 	uint_t				vpkt_state;
291 	uint_t				vpkt_flags;
292 
293 	/*
294 	 * copy of vhci_scsi_init_pkt args.  Used when we invoke
295 	 * scsi_init_pkt() of the pHCI corresponding to the path that we
296 	 * bind to
297 	 */
298 	int				vpkt_tgt_init_cdblen;
299 	int				vpkt_tgt_init_scblen;
300 	int				vpkt_tgt_init_pkt_flags;
301 	struct buf			*vpkt_tgt_init_bp;
302 
303 	/*
304 	 * Pointer to original struct vhci_pkt for cmd send by ssd.
305 	 * Saved when the command is being retried internally.
306 	 */
307 	struct vhci_pkt			*vpkt_org_vpkt;
308 };
309 
310 typedef struct scsi_vhci_lun {
311 	kmutex_t		svl_mutex;
312 	kcondvar_t		svl_cv;
313 
314 	/*
315 	 * following three fields are under svl_mutex protection
316 	 */
317 	int			svl_transient;
318 
319 	/*
320 	 * to prevent unnecessary failover when a device is
321 	 * is discovered across a passive path and active path
322 	 * is still comng up
323 	 */
324 	int			svl_waiting_for_activepath;
325 	hrtime_t		svl_wfa_time;
326 
327 	/*
328 	 * to keep the failover status in order to return the
329 	 * failure status to target driver when targer driver
330 	 * retries the command which originally triggered the
331 	 * failover.
332 	 */
333 	int			svl_failover_status;
334 
335 	/*
336 	 * for RESERVE/RELEASE support
337 	 */
338 	client_lb_t		svl_lb_policy_save;
339 
340 	/*
341 	 * Failover ops and ops name selected for the lun.
342 	 */
343 	struct scsi_failover_ops	*svl_fops;
344 	char			*svl_fops_name;
345 
346 	void			*svl_fops_ctpriv;
347 
348 	struct scsi_vhci_lun	*svl_hash_next;
349 	char			*svl_lun_wwn;
350 
351 	/*
352 	 * currently active pathclass
353 	 */
354 	char			*svl_active_pclass;
355 
356 	dev_info_t		*svl_dip;
357 	uint32_t		svl_flags;	/* protected by svl_mutex */
358 
359 	/*
360 	 * When SCSI-II reservations are active we set the following pip
361 	 * to point to the path holding the reservation.  As long as
362 	 * the reservation is active this svl_resrv_pip is bound for the
363 	 * transport directly.  We bypass calling mdi_select_path to return
364 	 * a pip.
365 	 * The following pip is only valid when VLUN_RESERVE_ACTIVE_FLG
366 	 * is set.  This pip should not be accessed if this flag is reset.
367 	 */
368 	mdi_pathinfo_t	*svl_resrv_pip;
369 
370 	/*
371 	 * following fields are for PGR support
372 	 */
373 	taskq_t			*svl_taskq;
374 	ksema_t			svl_pgr_sema;	/* PGR serialization */
375 	vhci_prin_readkeys_t	svl_prin;	/* PGR in data */
376 	vhci_prout_t		svl_prout;	/* PGR out data */
377 	uchar_t			svl_cdb[CDB_GROUP4];
378 	int			svl_time;	/* pkt_time */
379 	uint32_t		svl_bcount;	/* amount of data */
380 	int			svl_pgr_active; /* registrations active */
381 	mdi_pathinfo_t		*svl_first_path;
382 
383 	/* external failover */
384 	int			svl_efo_update_path;
385 	struct	scsi_vhci_swarg	*svl_swarg;
386 
387 	uint32_t		svl_support_lun_reset; /* Lun reset support */
388 	int			svl_not_supported;
389 	int			svl_xlf_capable; /* XLF implementation */
390 	int			svl_sector_size;
391 	int			svl_setcap_done;
392 	uint16_t		svl_fo_support;	 /* failover mode */
393 } scsi_vhci_lun_t;
394 
395 #define	VLUN_TASK_D_ALIVE_FLG		0x01
396 
397 /*
398  * This flag is used to monitor the state of SCSI-II RESERVATION on the
399  * lun.  A SCSI-II RESERVE cmd may be accepted by the target on the inactive
400  * path.  This would then cause a subsequent IO to cause the paths to be
401  * updated and be returned with a reservation conflict.  By monitoring this
402  * flag, and sending a reset to the target when needed to clear the reservation,
403  * one can avoid this conflict.
404  */
405 #define	VLUN_RESERVE_ACTIVE_FLG		0x04
406 
407 /*
408  * This flag is set when a SCSI-II RESERVE cmd is received by scsi_vhci
409  * and cleared when the pkt completes in vhci_intr.  It ensures that the
410  * lun remains quiesced for the duration of this pkt.  This is different
411  * from VHCI_HOLD_LUN as this pertains to IOs only.
412  */
413 #define	VLUN_QUIESCED_FLG		0x08
414 
415 /*
416  * This flag is set to tell vhci_update_pathstates to call back
417  * into vhci_mpapi_update_tpg_acc_state.
418  */
419 #define	VLUN_UPDATE_TPG			0x10
420 
421 /*
422  * Various reset recovery depth.
423  */
424 
425 #define	VHCI_DEPTH_ALL		3
426 #define	VHCI_DEPTH_TARGET	2
427 #define	VHCI_DEPTH_LUN		1	/* For the sake completeness */
428 #define	TRUE			(1)
429 #define	FALSE			(0)
430 
431 /*
432  * this is stashed away in the client private area of
433  * pathinfo
434  */
435 typedef struct scsi_vhci_priv {
436 	kmutex_t		svp_mutex;
437 	kcondvar_t		svp_cv;
438 	struct scsi_vhci_lun	*svp_svl;
439 
440 	/*
441 	 * scsi device associated with this
442 	 * pathinfo
443 	 */
444 	struct scsi_device	*svp_psd;
445 
446 	/*
447 	 * number of outstanding commands on this
448 	 * path.  Protected by svp_mutex
449 	 */
450 	int			svp_cmds;
451 
452 	/*
453 	 * following is used to prevent packets completing with the
454 	 * same error reason from flooding the screen
455 	 */
456 	uchar_t			svp_last_pkt_reason;
457 
458 	/* external failover scsi_watch token */
459 	opaque_t		svp_sw_token;
460 
461 	/* any cleanup operations for a newly found path. */
462 	int			svp_new_path;
463 } scsi_vhci_priv_t;
464 
465 /*
466  * argument to scsi_watch callback.  Used for processing
467  * externally initiated failovers
468  */
469 typedef struct scsi_vhci_swarg {
470 	scsi_vhci_priv_t	*svs_svp;
471 	hrtime_t		svs_tos;	/* time of submission */
472 	mdi_pathinfo_t		*svs_pi;	/* pathinfo being "watched" */
473 	int			svs_release_lun;
474 	int			svs_done;
475 } scsi_vhci_swarg_t;
476 
477 /*
478  * scsi_vhci softstate
479  *
480  * vhci_mutex protects
481  *	vhci_state
482  * and	vhci_reset_notify list
483  */
484 struct scsi_vhci {
485 	kmutex_t			vhci_mutex;
486 	dev_info_t			*vhci_dip;
487 	struct scsi_hba_tran		*vhci_tran;
488 	uint32_t			vhci_state;
489 	uint32_t			vhci_instance;
490 	kstat_t				vhci_kstat;
491 	/*
492 	 * This taskq is for general vhci operations like reservations,
493 	 * auto-failback, etc.
494 	 */
495 	taskq_t				*vhci_taskq;
496 	/* Dedicate taskq to handle external failovers */
497 	taskq_t				*vhci_update_pathstates_taskq;
498 	struct scsi_reset_notify_entry	*vhci_reset_notify_listf;
499 	uint16_t			vhci_conf_flags;
500 	mpapi_priv_t			*mp_priv;
501 };
502 
503 /*
504  * vHCI flags for configuration settings, defined in scsi_vhci.conf
505  */
506 #define	VHCI_CONF_FLAGS_AUTO_FAILBACK	0x0001	/* Enables auto failback */
507 
508 typedef enum {
509 	SCSI_PATH_INACTIVE,
510 	SCSI_PATH_ACTIVE,
511 	SCSI_PATH_ACTIVE_NONOPT
512 } scsi_path_state_t;
513 
514 #define	SCSI_MAXPCLASSLEN	25
515 
516 #define	OPINFO_REV	1
517 
518 /*
519  * structure describing operational characteristics of
520  * path
521  */
522 struct scsi_path_opinfo {
523 	int			opinfo_rev;
524 
525 	/*
526 	 * name of pathclass. Eg. "primary", "secondary"
527 	 */
528 	char			opinfo_path_attr[SCSI_MAXPCLASSLEN];
529 
530 	/*
531 	 * path state: ACTIVE/PASSIVE
532 	 */
533 	scsi_path_state_t	opinfo_path_state;
534 
535 	/*
536 	 * the best and worst case time estimates for
537 	 * failover operation to complete
538 	 */
539 	uint_t			opinfo_pswtch_best;
540 	uint_t			opinfo_pswtch_worst;
541 
542 	/* XLF implementation */
543 	int			opinfo_xlf_capable;
544 	uint16_t		opinfo_preferred;
545 	uint16_t		opinfo_mode;
546 
547 };
548 
549 
550 #define	SFO_REV		1
551 
552 /*
553  * vectors for device specific failover related operations
554  */
555 struct scsi_failover_ops {
556 	int	sfo_rev;
557 
558 	/*
559 	 * failover module name, begins with "f_"
560 	 */
561 	char	*sfo_name;
562 
563 	/*
564 	 * devices supported by failover module
565 	 *
566 	 * NOTE: this is an aproximation, sfo_device_probe has the final say.
567 	 */
568 	char	**sfo_devices;
569 
570 	/*
571 	 * initialize the failover module
572 	 */
573 	void	(*sfo_init)();
574 
575 	/*
576 	 * identify device
577 	 */
578 	int	(*sfo_device_probe)(
579 			struct scsi_device	*sd,
580 			struct scsi_inquiry	*stdinq,
581 			void			**ctpriv);
582 
583 	/*
584 	 * housekeeping (free memory etc alloc'ed during probe
585 	 */
586 	void	(*sfo_device_unprobe)(
587 			struct scsi_device	*sd,
588 			void			*ctpriv);
589 
590 	/*
591 	 * bring a path ONLINE (ie make it ACTIVE)
592 	 */
593 	int	(*sfo_path_activate)(
594 			struct scsi_device	*sd,
595 			char			*pathclass,
596 			void			*ctpriv);
597 
598 	/*
599 	 * inverse of above
600 	 */
601 	int	(*sfo_path_deactivate)(
602 			struct scsi_device	*sd,
603 			char			*pathclass,
604 			void			*ctpriv);
605 
606 	/*
607 	 * returns operational characteristics of path
608 	 */
609 	int	(*sfo_path_get_opinfo)(
610 			struct scsi_device	*sd,
611 			struct scsi_path_opinfo *opinfo,
612 			void			*ctpriv);
613 
614 	/*
615 	 * verify path is operational
616 	 */
617 	int	(*sfo_path_ping)(
618 			struct scsi_device	*sd,
619 			void			*ctpriv);
620 
621 	/*
622 	 * analyze SENSE data to detect externally initiated
623 	 * failovers
624 	 */
625 	int	(*sfo_analyze_sense)(
626 			struct scsi_device	*sd,
627 			uint8_t			*sense,
628 			void			*ctpriv);
629 
630 	/*
631 	 * return the next pathclass in order of preference
632 	 * eg. "secondary" comes after "primary"
633 	 */
634 	int	(*sfo_pathclass_next)(
635 			char			*cur,
636 			char			**nxt,
637 			void			*ctpriv);
638 };
639 
640 /*
641  * Names of (too) 'well-known' failover ops.
642  *   NOTE: consumers of these names should look for a better way...
643  */
644 #define	SFO_NAME_SYM		"f_sym"
645 #define	SFO_NAME_TPGS		"f_tpgs"
646 #define	SCSI_FAILOVER_IS_ASYM(svl)	\
647 	((svl) ? ((svl)->svl_fo_support != SCSI_NO_FAILOVER) : 0)
648 #define	SCSI_FAILOVER_IS_TPGS(sfo)	\
649 	((sfo) ? (strcmp((sfo)->sfo_name, SFO_NAME_TPGS) == 0) : 0)
650 
651 /*
652  * Macro to provide plumbing for basic failover module
653  */
654 #define	_SCSI_FAILOVER_OP(sfo_name, local_name, ops_name)		\
655 	static struct modlmisc modlmisc = {				\
656 		&mod_miscops, sfo_name					\
657 	};								\
658 	static struct modlinkage modlinkage = {				\
659 		MODREV_1, (void *)&modlmisc, NULL			\
660 	};								\
661 	int	_init()							\
662 	{								\
663 		return (mod_install(&modlinkage));			\
664 	}								\
665 	int	_fini()							\
666 	{								\
667 		return (mod_remove(&modlinkage));			\
668 	}								\
669 	int	_info(struct modinfo *modinfop)				\
670 	{								\
671 		return (mod_info(&modlinkage, modinfop));		\
672 	}								\
673 	static int	local_name##_device_probe(			\
674 				struct scsi_device *,			\
675 				struct scsi_inquiry *, void **);	\
676 	static void	local_name##_device_unprobe(			\
677 				struct scsi_device *, void *);		\
678 	static int	local_name##_path_activate(			\
679 				struct scsi_device *, char *, void *);	\
680 	static int	local_name##_path_deactivate(			\
681 				struct scsi_device *, char *, void *);	\
682 	static int	local_name##_path_get_opinfo(			\
683 				struct scsi_device *,			\
684 				struct scsi_path_opinfo *, void *);	\
685 	static int	local_name##_path_ping(				\
686 				struct scsi_device *, void *);		\
687 	static int	local_name##_analyze_sense(			\
688 				struct scsi_device *,			\
689 				uint8_t *, void *);			\
690 	static int	local_name##_pathclass_next(			\
691 				char *, char **, void *);		\
692 	struct scsi_failover_ops ops_name##_failover_ops = {		\
693 		SFO_REV,						\
694 		sfo_name,						\
695 		local_name##_dev_table,					\
696 		NULL,							\
697 		local_name##_device_probe,				\
698 		local_name##_device_unprobe,				\
699 		local_name##_path_activate,				\
700 		local_name##_path_deactivate,				\
701 		local_name##_path_get_opinfo,				\
702 		local_name##_path_ping,					\
703 		local_name##_analyze_sense,				\
704 		local_name##_pathclass_next				\
705 	}
706 
707 #ifdef	lint
708 #define	SCSI_FAILOVER_OP(sfo_name, local_name)				\
709 	_SCSI_FAILOVER_OP(sfo_name, local_name, local_name)
710 #else	/* lint */
711 #define	SCSI_FAILOVER_OP(sfo_name, local_name)				\
712 	_SCSI_FAILOVER_OP(sfo_name, local_name, scsi_vhci)
713 #endif	/* lint */
714 
715 /*
716  * Return values for sfo_device_probe
717  */
718 #define	SFO_DEVICE_PROBE_VHCI	1	/* supported under scsi_vhci */
719 #define	SFO_DEVICE_PROBE_PHCI	0	/* not supported under scsi_vhci */
720 
721 /* return values for sfo_analyze_sense() */
722 #define	SCSI_SENSE_NOFAILOVER		0
723 #define	SCSI_SENSE_FAILOVER_INPROG	1
724 #define	SCSI_SENSE_ACT2INACT		2
725 #define	SCSI_SENSE_INACT2ACT		3
726 #define	SCSI_SENSE_INACTIVE		4
727 #define	SCSI_SENSE_UNKNOWN		5
728 #define	SCSI_SENSE_STATE_CHANGED	6
729 #define	SCSI_SENSE_NOT_READY		7
730 
731 /* vhci_intr action codes */
732 #define	JUST_RETURN			0
733 #define	BUSY_RETURN			1
734 #define	PKT_RETURN			2
735 
736 #if	defined(_SYSCALL32)
737 /*
738  * 32 bit variants of sv_path_info_prop_t and sv_path_info_t;
739  * To be used only in the driver and NOT applications
740  */
741 typedef struct sv_path_info_prop32 {
742 	uint32_t	buf_size;	/* user buffer size */
743 	caddr32_t	ret_buf_size;	/* actual buffer needed */
744 	caddr32_t	buf;		/* user space buffer */
745 } sv_path_info_prop32_t;
746 
747 typedef struct sv_path_info32 {
748 	union {
749 		char	ret_ct[MAXPATHLEN];		/* client device */
750 		char	ret_phci[MAXPATHLEN];		/* pHCI device */
751 	} device;
752 
753 	char			ret_addr[MAXNAMELEN];	/* device address */
754 	mdi_pathinfo_state_t	ret_state;		/* state information */
755 	uint32_t		ret_ext_state;		/* Extended State */
756 	sv_path_info_prop32_t	ret_prop;		/* path attributes */
757 } sv_path_info32_t;
758 
759 typedef struct sv_iocdata32 {
760 	caddr32_t	client;		/* client dev devfs path name */
761 	caddr32_t	phci;		/* pHCI dev devfs path name */
762 	caddr32_t	addr;		/* device address */
763 	uint32_t	buf_elem;	/* number of path_info elems */
764 	caddr32_t	ret_buf;	/* addr of array of sv_path_info */
765 	caddr32_t	ret_elem;	/* count of above sv_path_info */
766 } sv_iocdata32_t;
767 
768 typedef struct sv_switch_to_cntlr_iocdata32 {
769 	caddr32_t	client;	/* client device devfs path name */
770 	caddr32_t	class;	/* desired path class to be made active */
771 } sv_switch_to_cntlr_iocdata32_t;
772 
773 #endif	/* _SYSCALL32 */
774 
775 #endif	/* _KERNEL */
776 
777 /*
778  * Userland (Non Kernel) definitions start here.
779  * Multiplexed I/O SCSI vHCI IOCTL Definitions
780  */
781 
782 /*
783  * IOCTL structure for path properties
784  */
785 typedef struct sv_path_info_prop {
786 	uint_t	buf_size;	/* user buffer size */
787 	uint_t	*ret_buf_size;	/* actual buffer needed */
788 	caddr_t	buf;		/* user space buffer */
789 } sv_path_info_prop_t;
790 
791 /*
792  * Max buffer size of getting path properties
793  */
794 #define	SV_PROP_MAX_BUF_SIZE	4096
795 
796 /*
797  * String values for "path-class" property
798  */
799 #define	PCLASS_PRIMARY		"primary"
800 #define	PCLASS_SECONDARY	"secondary"
801 
802 #define	PCLASS_PREFERRED	1
803 #define	PCLASS_NONPREFERRED	0
804 
805 /*
806  * IOCTL structure for path information
807  */
808 typedef struct sv_path_info {
809 	union {
810 		char	ret_ct[MAXPATHLEN];		/* client device */
811 		char	ret_phci[MAXPATHLEN];		/* pHCI device */
812 	} device;
813 
814 	char			ret_addr[MAXNAMELEN];	/* device address */
815 	mdi_pathinfo_state_t	ret_state;		/* state information */
816 	uint32_t		ret_ext_state;		/* Extended State */
817 	sv_path_info_prop_t	ret_prop;		/* path attributes */
818 } sv_path_info_t;
819 
820 /*
821  * IOCTL argument structure
822  */
823 typedef struct sv_iocdata {
824 	caddr_t		client;		/* client dev devfs path name */
825 	caddr_t		phci;		/* pHCI dev devfs path name */
826 	caddr_t		addr;		/* device address */
827 	uint_t		buf_elem;	/* number of path_info elems */
828 	sv_path_info_t	*ret_buf;	/* array of sv_path_info */
829 	uint_t		*ret_elem;	/* count of sv_path_info */
830 } sv_iocdata_t;
831 
832 /*
833  * IOCTL argument structure for switching controllers
834  */
835 typedef struct sv_switch_to_cntlr_iocdata {
836 	caddr_t		client;	/* client device devfs path name */
837 	caddr_t		class;	/* desired path class to be made active */
838 } sv_switch_to_cntlr_iocdata_t;
839 
840 
841 /*
842  * IOCTL definitions
843  */
844 #define	SCSI_VHCI_CTL		('X' << 8)
845 #define	SCSI_VHCI_CTL_CMD	(SCSI_VHCI_CTL | ('S' << 8) | 'P')
846 #define	SCSI_VHCI_CTL_SUB_CMD	('x' << 8)
847 
848 #define	SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO	(SCSI_VHCI_CTL_SUB_CMD + 0x01)
849 #define	SCSI_VHCI_GET_PHCI_MULTIPATH_INFO	(SCSI_VHCI_CTL_SUB_CMD + 0x02)
850 #define	SCSI_VHCI_GET_CLIENT_NAME		(SCSI_VHCI_CTL_SUB_CMD + 0x03)
851 #define	SCSI_VHCI_PATH_ONLINE			(SCSI_VHCI_CTL_SUB_CMD + 0x04)
852 #define	SCSI_VHCI_PATH_OFFLINE			(SCSI_VHCI_CTL_SUB_CMD + 0x05)
853 #define	SCSI_VHCI_PATH_STANDBY			(SCSI_VHCI_CTL_SUB_CMD + 0x06)
854 #define	SCSI_VHCI_PATH_TEST			(SCSI_VHCI_CTL_SUB_CMD + 0x07)
855 #define	SCSI_VHCI_SWITCH_TO_CNTLR		(SCSI_VHCI_CTL_SUB_CMD + 0x08)
856 
857 #ifdef	DEBUG
858 #define	SCSI_VHCI_GET_PHCI_LIST			(SCSI_VHCI_CTL_SUB_CMD + 0x09)
859 #define	SCSI_VHCI_CONFIGURE_PHCI		(SCSI_VHCI_CTL_SUB_CMD + 0x0A)
860 #define	SCSI_VHCI_UNCONFIGURE_PHCI		(SCSI_VHCI_CTL_SUB_CMD + 0x0B)
861 #endif
862 
863 #define	SCSI_VHCI_PATH_DISABLE			(SCSI_VHCI_CTL_SUB_CMD + 0x0C)
864 #define	SCSI_VHCI_PATH_ENABLE			(SCSI_VHCI_CTL_SUB_CMD + 0x0D)
865 #define	SCSI_VHCI_MPAPI				(SCSI_VHCI_CTL_SUB_CMD + 0x0E)
866 
867 #define	SCSI_VHCI_GET_TARGET_LONGNAME		(SCSI_VHCI_CTL_SUB_CMD + 0x0F)
868 
869 #ifdef	__cplusplus
870 }
871 #endif
872 
873 #endif	/* _SYS_SCSI_ADAPTERS_SCSI_VHCI_H */
874