10205780bSrralphs /*
20205780bSrralphs  * CDDL HEADER START
30205780bSrralphs  *
40205780bSrralphs  * The contents of this file are subject to the terms of the
50205780bSrralphs  * Common Development and Distribution License (the "License").
60205780bSrralphs  * You may not use this file except in compliance with the License.
70205780bSrralphs  *
80205780bSrralphs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90205780bSrralphs  * or http://www.opensolaris.org/os/licensing.
100205780bSrralphs  * See the License for the specific language governing permissions
110205780bSrralphs  * and limitations under the License.
120205780bSrralphs  *
130205780bSrralphs  * When distributing Covered Code, include this CDDL HEADER in each
140205780bSrralphs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150205780bSrralphs  * If applicable, add the following below this CDDL HEADER, with the
160205780bSrralphs  * fields enclosed by brackets "[]" replaced with your own identifying
170205780bSrralphs  * information: Portions Copyright [yyyy] [name of copyright owner]
180205780bSrralphs  *
190205780bSrralphs  * CDDL HEADER END
200205780bSrralphs  */
210205780bSrralphs /*
22*dd64cd44SRandall Ralphs  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230205780bSrralphs  * Use is subject to license terms.
240205780bSrralphs  */
250205780bSrralphs 
260205780bSrralphs /*
270205780bSrralphs  * Implementation of "scsi_vhci_f_tpgs_tape" T10 standard based failover_ops.
280205780bSrralphs  *
290205780bSrralphs  * NOTE: for sequential devices only.
300205780bSrralphs  */
310205780bSrralphs 
320205780bSrralphs #include <sys/conf.h>
330205780bSrralphs #include <sys/file.h>
340205780bSrralphs #include <sys/ddi.h>
350205780bSrralphs #include <sys/sunddi.h>
360205780bSrralphs #include <sys/scsi/scsi.h>
370205780bSrralphs #include <sys/scsi/adapters/scsi_vhci.h>
380205780bSrralphs #include <sys/scsi/adapters/scsi_vhci_tpgs.h>
390205780bSrralphs 
400205780bSrralphs /* Supported device table entries.  */
410205780bSrralphs char *tpgs_tape_dev_table[] = { NULL };
420205780bSrralphs static void tpgs_tape_init(void);
430205780bSrralphs static int tpgs_tape_device_probe(struct scsi_device *sd,
440205780bSrralphs     struct scsi_inquiry *inq, void **ctpriv);
450205780bSrralphs 
460205780bSrralphs /* Failover module plumbing. */
470205780bSrralphs #ifdef	lint
480205780bSrralphs #define	scsi_vhci_failover_ops	scsi_vhci_failover_ops_f_tpgs_tape
490205780bSrralphs #endif	/* lint */
500205780bSrralphs struct scsi_failover_ops scsi_vhci_failover_ops = {
510205780bSrralphs 	SFO_REV,
520205780bSrralphs 	"f_tpgs_tape",
530205780bSrralphs 	tpgs_tape_dev_table,
540205780bSrralphs 	tpgs_tape_init,
550205780bSrralphs 	tpgs_tape_device_probe,
560205780bSrralphs 	/* The rest of the implementation comes from SFO_NAME_TPGS import  */
570205780bSrralphs };
580205780bSrralphs 
590205780bSrralphs static struct modlmisc modlmisc = {
6039b361b2SRichard Bean 	&mod_miscops, "f_tpgs_tape"
610205780bSrralphs };
620205780bSrralphs 
630205780bSrralphs static struct modlinkage modlinkage = {
640205780bSrralphs 	MODREV_1, (void *)&modlmisc, NULL
650205780bSrralphs };
660205780bSrralphs 
670205780bSrralphs 
680205780bSrralphs 
690205780bSrralphs /*
700205780bSrralphs  * External function definitions
710205780bSrralphs  */
720205780bSrralphs extern struct scsi_failover_ops	*vhci_failover_ops_by_name(char *);
730205780bSrralphs 
740205780bSrralphs int
_init()750205780bSrralphs _init()
760205780bSrralphs {
770205780bSrralphs 	return (mod_install(&modlinkage));
780205780bSrralphs }
790205780bSrralphs 
800205780bSrralphs int
_fini()810205780bSrralphs _fini()
820205780bSrralphs {
830205780bSrralphs 	return (mod_remove(&modlinkage));
840205780bSrralphs }
850205780bSrralphs 
860205780bSrralphs int
_info(struct modinfo * modinfop)870205780bSrralphs _info(struct modinfo *modinfop)
880205780bSrralphs {
890205780bSrralphs 	return (mod_info(&modlinkage, modinfop));
900205780bSrralphs }
910205780bSrralphs 
920205780bSrralphs 
930205780bSrralphs 
940205780bSrralphs /* ARGSUSED */
950205780bSrralphs static int
tpgs_tape_device_probe(struct scsi_device * sd,struct scsi_inquiry * inq,void ** ctpriv)960205780bSrralphs tpgs_tape_device_probe(struct scsi_device *sd, struct scsi_inquiry *inq,
970205780bSrralphs     void **ctpriv)
980205780bSrralphs {
99*dd64cd44SRandall Ralphs 	int mode;
100*dd64cd44SRandall Ralphs 	int state;
101*dd64cd44SRandall Ralphs 	int xlf;
102*dd64cd44SRandall Ralphs 	int preferred = 0;
103*dd64cd44SRandall Ralphs 	int support;
1040205780bSrralphs 
1050205780bSrralphs 	VHCI_DEBUG(6, (CE_NOTE, NULL, "tpgs_tape_device_probe: vidpid %s\n",
1060205780bSrralphs 	    inq->inq_vid));
1070205780bSrralphs 
108d91393a8SChris Horne 	if (inq->inq_tpgs == TPGS_FAILOVER_NONE) {
1090205780bSrralphs 		VHCI_DEBUG(4, (CE_WARN, NULL,
1100205780bSrralphs 		    "!tpgs_tape_device_probe: not a standard tpgs device"));
111*dd64cd44SRandall Ralphs 		support = SFO_DEVICE_PROBE_PHCI;
112*dd64cd44SRandall Ralphs 	} else if (inq->inq_dtype != DTYPE_SEQUENTIAL) {
1130205780bSrralphs 		VHCI_DEBUG(4, (CE_NOTE, NULL,
1140205780bSrralphs 		    "!tpgs_tape_device_probe: Detected a "
1150205780bSrralphs 		    "Standard Asymmetric device "
1160205780bSrralphs 		    "not yet supported\n"));
117*dd64cd44SRandall Ralphs 		support = SFO_DEVICE_PROBE_PHCI;
118*dd64cd44SRandall Ralphs 	} else if (vhci_tpgs_get_target_fo_mode(sd, &mode, &state, &xlf,
119*dd64cd44SRandall Ralphs 	    &preferred)) {
1200205780bSrralphs 		VHCI_DEBUG(4, (CE_WARN, NULL, "!unable to fetch fo "
1210205780bSrralphs 		    "mode: sd(%p)", (void *) sd));
122*dd64cd44SRandall Ralphs 		support = SFO_DEVICE_PROBE_PHCI;
123*dd64cd44SRandall Ralphs 	} else if (inq->inq_tpgs == TPGS_FAILOVER_IMPLICIT) {
1240205780bSrralphs 		VHCI_DEBUG(1, (CE_NOTE, NULL,
1250205780bSrralphs 		    "!tpgs_tape_device_probe: Detected a "
1260205780bSrralphs 		    "Standard Asymmetric device "
1270205780bSrralphs 		    "with implicit failover\n"));
128*dd64cd44SRandall Ralphs 		support = SFO_DEVICE_PROBE_VHCI;
129*dd64cd44SRandall Ralphs 	} else if (inq->inq_tpgs == TPGS_FAILOVER_EXPLICIT) {
1300205780bSrralphs 		VHCI_DEBUG(1, (CE_NOTE, NULL,
1310205780bSrralphs 		    "!tpgs_tape_device_probe: Detected a "
1320205780bSrralphs 		    "Standard Asymmetric device "
1330205780bSrralphs 		    "with explicit failover\n"));
134*dd64cd44SRandall Ralphs 		support = SFO_DEVICE_PROBE_VHCI;
135*dd64cd44SRandall Ralphs 	} else if (inq->inq_tpgs == TPGS_FAILOVER_BOTH) {
1360205780bSrralphs 		VHCI_DEBUG(1, (CE_NOTE, NULL,
1370205780bSrralphs 		    "!tpgs_tape_device_probe: Detected a "
1380205780bSrralphs 		    "Standard Asymmetric device "
1390205780bSrralphs 		    "which supports both implicit and explicit failover\n"));
140*dd64cd44SRandall Ralphs 		support = SFO_DEVICE_PROBE_VHCI;
141*dd64cd44SRandall Ralphs 	} else {
142*dd64cd44SRandall Ralphs 		VHCI_DEBUG(1, (CE_WARN, NULL,
143*dd64cd44SRandall Ralphs 		    "!tpgs_tape_device_probe: "
144*dd64cd44SRandall Ralphs 		    "Unknown tpgs_bits: %x", inq->inq_tpgs));
145*dd64cd44SRandall Ralphs 		support = SFO_DEVICE_PROBE_PHCI;
146*dd64cd44SRandall Ralphs 	}
147*dd64cd44SRandall Ralphs 
148*dd64cd44SRandall Ralphs 	if (support == SFO_DEVICE_PROBE_VHCI) {
149*dd64cd44SRandall Ralphs 		/*
150*dd64cd44SRandall Ralphs 		 * Policy only applies to 'client' probe, not
151*dd64cd44SRandall Ralphs 		 * vhci_is_dev_supported() pHCI probe. Detect difference
152*dd64cd44SRandall Ralphs 		 * based on ctpriv.
153*dd64cd44SRandall Ralphs 		 */
154*dd64cd44SRandall Ralphs 		if (ctpriv &&
155*dd64cd44SRandall Ralphs 		    (mdi_set_lb_policy(sd->sd_dev, LOAD_BALANCE_NONE) !=
156*dd64cd44SRandall Ralphs 		    MDI_SUCCESS)) {
157*dd64cd44SRandall Ralphs 			VHCI_DEBUG(6, (CE_NOTE, NULL, "!fail load balance none"
158*dd64cd44SRandall Ralphs 			    ": %s\n", inq->inq_vid));
159*dd64cd44SRandall Ralphs 			support = SFO_DEVICE_PROBE_PHCI;
160*dd64cd44SRandall Ralphs 		}
1610205780bSrralphs 	}
162*dd64cd44SRandall Ralphs 	return (support);
1630205780bSrralphs }
1640205780bSrralphs 
1650205780bSrralphs static void
tpgs_tape_init(void)1660205780bSrralphs tpgs_tape_init(void)
1670205780bSrralphs {
1680205780bSrralphs 	struct scsi_failover_ops	*sfo, *ssfo, clone;
1690205780bSrralphs 
1700205780bSrralphs 	/* clone SFO_NAME_SYM implementation for most things */
1710205780bSrralphs 	ssfo = vhci_failover_ops_by_name(SFO_NAME_TPGS);
1720205780bSrralphs 	if (ssfo == NULL) {
1730205780bSrralphs 		VHCI_DEBUG(4, (CE_NOTE, NULL, "!tpgs_tape: "
1740205780bSrralphs 		    "can't import " SFO_NAME_SYM "\n"));
1750205780bSrralphs 		return;
1760205780bSrralphs 	}
1770205780bSrralphs 	sfo			= &scsi_vhci_failover_ops;
1780205780bSrralphs 	clone			= *ssfo;
1790205780bSrralphs 	clone.sfo_rev		= sfo->sfo_rev;
1800205780bSrralphs 	clone.sfo_name		= sfo->sfo_name;
1810205780bSrralphs 	clone.sfo_devices	= sfo->sfo_devices;
1820205780bSrralphs 	clone.sfo_init		= sfo->sfo_init;
1830205780bSrralphs 	clone.sfo_device_probe	= sfo->sfo_device_probe;
1840205780bSrralphs 	*sfo			= clone;
1850205780bSrralphs }
186