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