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 } 186