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 2008 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, state, xlf, preferred = 0; 100 101 VHCI_DEBUG(6, (CE_NOTE, NULL, "tpgs_tape_device_probe: vidpid %s\n", 102 inq->inq_vid)); 103 104 if (inq->inq_tpgs == TPGS_FAILOVER_NONE) { 105 VHCI_DEBUG(4, (CE_WARN, NULL, 106 "!tpgs_tape_device_probe: not a standard tpgs device")); 107 return (SFO_DEVICE_PROBE_PHCI); 108 } 109 110 if (inq->inq_dtype != DTYPE_SEQUENTIAL) { 111 VHCI_DEBUG(4, (CE_NOTE, NULL, 112 "!tpgs_tape_device_probe: Detected a " 113 "Standard Asymmetric device " 114 "not yet supported\n")); 115 return (SFO_DEVICE_PROBE_PHCI); 116 } 117 118 if (vhci_tpgs_get_target_fo_mode(sd, &mode, &state, &xlf, &preferred)) { 119 VHCI_DEBUG(4, (CE_WARN, NULL, "!unable to fetch fo " 120 "mode: sd(%p)", (void *) sd)); 121 return (SFO_DEVICE_PROBE_PHCI); 122 } 123 124 if (inq->inq_tpgs == TPGS_FAILOVER_IMPLICIT) { 125 VHCI_DEBUG(1, (CE_NOTE, NULL, 126 "!tpgs_tape_device_probe: Detected a " 127 "Standard Asymmetric device " 128 "with implicit failover\n")); 129 return (SFO_DEVICE_PROBE_VHCI); 130 } 131 if (inq->inq_tpgs == TPGS_FAILOVER_EXPLICIT) { 132 VHCI_DEBUG(1, (CE_NOTE, NULL, 133 "!tpgs_tape_device_probe: Detected a " 134 "Standard Asymmetric device " 135 "with explicit failover\n")); 136 return (SFO_DEVICE_PROBE_VHCI); 137 } 138 if (inq->inq_tpgs == TPGS_FAILOVER_BOTH) { 139 VHCI_DEBUG(1, (CE_NOTE, NULL, 140 "!tpgs_tape_device_probe: Detected a " 141 "Standard Asymmetric device " 142 "which supports both implicit and explicit failover\n")); 143 return (SFO_DEVICE_PROBE_VHCI); 144 } 145 VHCI_DEBUG(1, (CE_WARN, NULL, 146 "!tpgs_tape_device_probe: " 147 "Unknown tpgs_bits: %x", inq->inq_tpgs)); 148 return (SFO_DEVICE_PROBE_PHCI); 149 } 150 151 static void 152 tpgs_tape_init(void) 153 { 154 struct scsi_failover_ops *sfo, *ssfo, clone; 155 156 /* clone SFO_NAME_SYM implementation for most things */ 157 ssfo = vhci_failover_ops_by_name(SFO_NAME_TPGS); 158 if (ssfo == NULL) { 159 VHCI_DEBUG(4, (CE_NOTE, NULL, "!tpgs_tape: " 160 "can't import " SFO_NAME_SYM "\n")); 161 return; 162 } 163 sfo = &scsi_vhci_failover_ops; 164 clone = *ssfo; 165 clone.sfo_rev = sfo->sfo_rev; 166 clone.sfo_name = sfo->sfo_name; 167 clone.sfo_devices = sfo->sfo_devices; 168 clone.sfo_init = sfo->sfo_init; 169 clone.sfo_device_probe = sfo->sfo_device_probe; 170 *sfo = clone; 171 } 172