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
  75 _init()
  76 {
  77         return (mod_install(&modlinkage));
  78 }
  79 
  80 int
  81 _fini()
  82 {
  83         return (mod_remove(&modlinkage));
  84 }
  85 
  86 int
  87 _info(struct modinfo *modinfop)
  88 {
  89         return (mod_info(&modlinkage, modinfop));
  90 }
  91 
  92 
  93 
  94 /* ARGSUSED */
  95 static int
  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
 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 }