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