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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 /*
28  * Implementation of "scsi_vhci_f_tpgs_tape" T10 standard based failover_ops.
29  *
30  * NOTE: for sequential devices only.
31  */
32 
33 #include <sys/conf.h>
34 #include <sys/file.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/scsi/scsi.h>
38 #include <sys/scsi/adapters/scsi_vhci.h>
39 #include <sys/scsi/adapters/scsi_vhci_tpgs.h>
40 
41 /* Supported device table entries.  */
42 char *tpgs_tape_dev_table[] = { NULL };
43 static void tpgs_tape_init(void);
44 static int tpgs_tape_device_probe(struct scsi_device *sd,
45     struct scsi_inquiry *inq, void **ctpriv);
46 
47 /* Failover module plumbing. */
48 #ifdef	lint
49 #define	scsi_vhci_failover_ops	scsi_vhci_failover_ops_f_tpgs_tape
50 #endif	/* lint */
51 struct scsi_failover_ops scsi_vhci_failover_ops = {
52 	SFO_REV,
53 	"f_tpgs_tape",
54 	tpgs_tape_dev_table,
55 	tpgs_tape_init,
56 	tpgs_tape_device_probe,
57 	/* The rest of the implementation comes from SFO_NAME_TPGS import  */
58 };
59 
60 static struct modlmisc modlmisc = {
61 	&mod_miscops, "f_tpgs_tape %I%"
62 };
63 
64 static struct modlinkage modlinkage = {
65 	MODREV_1, (void *)&modlmisc, NULL
66 };
67 
68 
69 
70 /*
71  * External function definitions
72  */
73 extern struct scsi_failover_ops	*vhci_failover_ops_by_name(char *);
74 
75 int
76 _init()
77 {
78 	return (mod_install(&modlinkage));
79 }
80 
81 int
82 _fini()
83 {
84 	return (mod_remove(&modlinkage));
85 }
86 
87 int
88 _info(struct modinfo *modinfop)
89 {
90 	return (mod_info(&modlinkage, modinfop));
91 }
92 
93 
94 
95 /* ARGSUSED */
96 static int
97 tpgs_tape_device_probe(struct scsi_device *sd, struct scsi_inquiry *inq,
98     void **ctpriv)
99 {
100 	int		mode, state, xlf, preferred = 0;
101 
102 	VHCI_DEBUG(6, (CE_NOTE, NULL, "tpgs_tape_device_probe: vidpid %s\n",
103 	    inq->inq_vid));
104 
105 	if (inq->inq_tpgs == 0) {
106 		VHCI_DEBUG(4, (CE_WARN, NULL,
107 		    "!tpgs_tape_device_probe: not a standard tpgs device"));
108 		return (SFO_DEVICE_PROBE_PHCI);
109 	}
110 
111 	if (inq->inq_dtype != DTYPE_SEQUENTIAL) {
112 		VHCI_DEBUG(4, (CE_NOTE, NULL,
113 		    "!tpgs_tape_device_probe: Detected a "
114 		    "Standard Asymmetric device "
115 		    "not yet supported\n"));
116 		return (SFO_DEVICE_PROBE_PHCI);
117 	}
118 
119 	if (vhci_tpgs_get_target_fo_mode(sd, &mode, &state, &xlf, &preferred)) {
120 		VHCI_DEBUG(4, (CE_WARN, NULL, "!unable to fetch fo "
121 		    "mode: sd(%p)", (void *) sd));
122 		return (SFO_DEVICE_PROBE_PHCI);
123 	}
124 
125 	if (inq->inq_tpgs == SCSI_IMPLICIT_FAILOVER) {
126 		VHCI_DEBUG(1, (CE_NOTE, NULL,
127 		    "!tpgs_tape_device_probe: Detected a "
128 		    "Standard Asymmetric device "
129 		    "with implicit failover\n"));
130 		return (SFO_DEVICE_PROBE_VHCI);
131 	}
132 	if (inq->inq_tpgs == SCSI_EXPLICIT_FAILOVER) {
133 		VHCI_DEBUG(1, (CE_NOTE, NULL,
134 		    "!tpgs_tape_device_probe: Detected a "
135 		    "Standard Asymmetric device "
136 		    "with explicit failover\n"));
137 		return (SFO_DEVICE_PROBE_VHCI);
138 	}
139 	if (inq->inq_tpgs == SCSI_BOTH_FAILOVER) {
140 		VHCI_DEBUG(1, (CE_NOTE, NULL,
141 		    "!tpgs_tape_device_probe: Detected a "
142 		    "Standard Asymmetric device "
143 		    "which supports both implicit and explicit failover\n"));
144 		return (SFO_DEVICE_PROBE_VHCI);
145 	}
146 	VHCI_DEBUG(1, (CE_WARN, NULL,
147 	    "!tpgs_tape_device_probe: "
148 	    "Unknown tpgs_bits: %x", inq->inq_tpgs));
149 	return (SFO_DEVICE_PROBE_PHCI);
150 }
151 
152 static void
153 tpgs_tape_init(void)
154 {
155 	struct scsi_failover_ops	*sfo, *ssfo, clone;
156 
157 	/* clone SFO_NAME_SYM implementation for most things */
158 	ssfo = vhci_failover_ops_by_name(SFO_NAME_TPGS);
159 	if (ssfo == NULL) {
160 		VHCI_DEBUG(4, (CE_NOTE, NULL, "!tpgs_tape: "
161 		    "can't import " SFO_NAME_SYM "\n"));
162 		return;
163 	}
164 	sfo			= &scsi_vhci_failover_ops;
165 	clone			= *ssfo;
166 	clone.sfo_rev		= sfo->sfo_rev;
167 	clone.sfo_name		= sfo->sfo_name;
168 	clone.sfo_devices	= sfo->sfo_devices;
169 	clone.sfo_init		= sfo->sfo_init;
170 	clone.sfo_device_probe	= sfo->sfo_device_probe;
171 	*sfo			= clone;
172 }
173