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 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Implementation of "scsi_vhci_f_tape" tape failover_ops.
29 *
30 * This file was historically meant for only tape implementation.  It has
31 * been extended to manage SUN "supported" tape controllers. The supported
32 * VID/PID shall be listed in the tape_dev_table.
33 */
34
35#include <sys/conf.h>
36#include <sys/file.h>
37#include <sys/ddi.h>
38#include <sys/sunddi.h>
39#include <sys/scsi/scsi.h>
40#include <sys/scsi/adapters/scsi_vhci.h>
41
42/* Supported device table entries.  */
43static char *tape_dev_table[] = {
44/*	"                  111111" */
45/*	"012345670123456789012345" */
46/*	"|-VID--||-----PID------|" */
47	"IBM     ULTRIUM-TD3",
48	"IBM     ULTRIUM-TD4",
49	NULL
50};
51
52/* Failover module plumbing. */
53SCSI_FAILOVER_OP("f_tape", tape);
54
55/* ARGSUSED */
56static int
57tape_device_probe(struct scsi_device *sd, struct scsi_inquiry *inquiry,
58    void **ctpriv)
59{
60	int i;
61	int rval = SFO_DEVICE_PROBE_PHCI;
62
63	VHCI_DEBUG(6, (CE_NOTE, NULL, "!tape_device_probe: inquiry string %s\n",
64	    inquiry->inq_vid));
65	/*
66	 * See if this a device type that we want to care about.
67	 */
68	switch (inquiry->inq_dtype & DTYPE_MASK) {
69	case DTYPE_SEQUENTIAL:
70		break;
71	case DTYPE_CHANGER:
72		rval = SFO_DEVICE_PROBE_VHCI;
73		goto done;
74	default:
75		/*
76		 * Not interested.
77		 */
78		return (rval);
79	}
80
81	/*
82	 * If it reports that it supports tpgs and it got here it may have
83	 * failed the tpgs commands. It might or might not support dual port
84	 * but we'll go with it.
85	 */
86	if (inquiry->inq_tpgs) {
87		VHCI_DEBUG(6, (CE_NOTE, NULL, "!has tpgs bits: %s\n",
88		    inquiry->inq_vid));
89		rval = SFO_DEVICE_PROBE_VHCI;
90	} else if (inquiry->inq_dualp) {
91		/*
92		 * Looks like it claims to have more then one port.
93		 */
94		VHCI_DEBUG(6, (CE_NOTE, NULL, "!has dual port bits: %s\n",
95		    inquiry->inq_vid));
96		rval = SFO_DEVICE_PROBE_VHCI;
97	} else {
98
99		/*
100		 * See if this device is on the list.
101		 */
102		for (i = 0; tape_dev_table[i]; i++) {
103
104			if (strncmp(inquiry->inq_vid, tape_dev_table[i],
105			    strlen(tape_dev_table[i])) == 0) {
106				VHCI_DEBUG(6, (CE_NOTE, NULL,
107				    "!was on the list: %s\n",
108				    inquiry->inq_vid));
109				rval = SFO_DEVICE_PROBE_VHCI;
110				break;
111			}
112		}
113	}
114done:
115	if (rval == SFO_DEVICE_PROBE_VHCI) {
116		/*
117		 * Policy only applies to 'client' probe, not
118		 * vhci_is_dev_supported() pHCI probe.  Detect difference
119		 * based on ctpriv.
120		 */
121		if (ctpriv &&
122		    (mdi_set_lb_policy(sd->sd_dev, LOAD_BALANCE_NONE) !=
123		    MDI_SUCCESS)) {
124			VHCI_DEBUG(6, (CE_NOTE, NULL, "!fail load balance none"
125			    ": %s\n", inquiry->inq_vid));
126			return (SFO_DEVICE_PROBE_PHCI);
127		}
128
129	}
130	return (rval);
131}
132
133/* ARGSUSED */
134static void
135tape_device_unprobe(struct scsi_device *sd, void *ctpriv)
136{
137	/*
138	 * NO OP for tape.
139	 */
140
141}
142
143/* ARGSUSED */
144static int
145tape_path_activate(struct scsi_device *sd, char *pathclass, void *ctpriv)
146{
147	return (0);
148}
149
150/* ARGSUSED */
151static int
152tape_path_deactivate(struct scsi_device *sd, char *pathclass, void *ctpriv)
153{
154	return (0);
155}
156
157/* ARGSUSED */
158static int
159tape_path_get_opinfo(struct scsi_device *sd, struct scsi_path_opinfo *opinfo,
160    void *ctpriv)
161{
162	opinfo->opinfo_rev = OPINFO_REV;
163	(void) strcpy(opinfo->opinfo_path_attr, PCLASS_PRIMARY);
164	opinfo->opinfo_path_state  = SCSI_PATH_ACTIVE;
165	opinfo->opinfo_pswtch_best = 0;		/* N/A */
166	opinfo->opinfo_pswtch_worst = 0;	/* N/A */
167	opinfo->opinfo_xlf_capable = 0;
168	opinfo->opinfo_mode = SCSI_NO_FAILOVER;
169	opinfo->opinfo_preferred = 1;
170
171	return (0);
172}
173
174/* ARGSUSED */
175static int
176tape_path_ping(struct scsi_device *sd, void *ctpriv)
177{
178	return (1);
179}
180
181/* ARGSUSED */
182static int
183tape_analyze_sense(struct scsi_device *sd, uint8_t *sense,
184    void *ctpriv)
185{
186	uint8_t skey, asc, ascq;
187
188	skey = scsi_sense_key(sense);
189	asc = scsi_sense_asc(sense);
190	ascq = scsi_sense_ascq(sense);
191
192	if (skey == KEY_ABORTED_COMMAND &&
193	    asc == 0x4b &&
194	    ascq == 0x83) {
195		return (SCSI_SENSE_INACTIVE);
196	}
197	if (skey == KEY_NOT_READY &&
198	    asc == 0x4 &&
199	    ascq == 0x1) {
200		return (SCSI_SENSE_NOT_READY);
201	}
202	return (SCSI_SENSE_NOFAILOVER);
203}
204
205/* ARGSUSED */
206static int
207tape_pathclass_next(char *cur, char **nxt, void *ctpriv)
208{
209	if (cur == NULL) {
210		*nxt = PCLASS_PRIMARY;
211		return (0);
212	} else if (strcmp(cur, PCLASS_PRIMARY) == 0) {
213		return (ENOENT);
214	}
215	return (EINVAL);
216}
217