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 #pragma ident "%Z%%M% %I% %E% SMI" 26 27 /* 28 * Implementation of "scsi_vhci_f_tpgs_tape" T10 standard based failover_ops. 29 * 30 * NOTE: for sequential devices only. 31 */ 32 33 #include <sys/conf.h> 34 #include <sys/file.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/scsi/scsi.h> 38 #include <sys/scsi/adapters/scsi_vhci.h> 39 #include <sys/scsi/adapters/scsi_vhci_tpgs.h> 40 41 /* Supported device table entries. */ 42 char *tpgs_tape_dev_table[] = { NULL }; 43 static void tpgs_tape_init(void); 44 static int tpgs_tape_device_probe(struct scsi_device *sd, 45 struct scsi_inquiry *inq, void **ctpriv); 46 47 /* Failover module plumbing. */ 48 #ifdef lint 49 #define scsi_vhci_failover_ops scsi_vhci_failover_ops_f_tpgs_tape 50 #endif /* lint */ 51 struct scsi_failover_ops scsi_vhci_failover_ops = { 52 SFO_REV, 53 "f_tpgs_tape", 54 tpgs_tape_dev_table, 55 tpgs_tape_init, 56 tpgs_tape_device_probe, 57 /* The rest of the implementation comes from SFO_NAME_TPGS import */ 58 }; 59 60 static struct modlmisc modlmisc = { 61 &mod_miscops, "f_tpgs_tape %I%" 62 }; 63 64 static struct modlinkage modlinkage = { 65 MODREV_1, (void *)&modlmisc, NULL 66 }; 67 68 69 70 /* 71 * External function definitions 72 */ 73 extern struct scsi_failover_ops *vhci_failover_ops_by_name(char *); 74 75 int 76 _init() 77 { 78 return (mod_install(&modlinkage)); 79 } 80 81 int 82 _fini() 83 { 84 return (mod_remove(&modlinkage)); 85 } 86 87 int 88 _info(struct modinfo *modinfop) 89 { 90 return (mod_info(&modlinkage, modinfop)); 91 } 92 93 94 95 /* ARGSUSED */ 96 static int 97 tpgs_tape_device_probe(struct scsi_device *sd, struct scsi_inquiry *inq, 98 void **ctpriv) 99 { 100 int mode, state, xlf, preferred = 0; 101 102 VHCI_DEBUG(6, (CE_NOTE, NULL, "tpgs_tape_device_probe: vidpid %s\n", 103 inq->inq_vid)); 104 105 if (inq->inq_tpgs == 0) { 106 VHCI_DEBUG(4, (CE_WARN, NULL, 107 "!tpgs_tape_device_probe: not a standard tpgs device")); 108 return (SFO_DEVICE_PROBE_PHCI); 109 } 110 111 if (inq->inq_dtype != DTYPE_SEQUENTIAL) { 112 VHCI_DEBUG(4, (CE_NOTE, NULL, 113 "!tpgs_tape_device_probe: Detected a " 114 "Standard Asymmetric device " 115 "not yet supported\n")); 116 return (SFO_DEVICE_PROBE_PHCI); 117 } 118 119 if (vhci_tpgs_get_target_fo_mode(sd, &mode, &state, &xlf, &preferred)) { 120 VHCI_DEBUG(4, (CE_WARN, NULL, "!unable to fetch fo " 121 "mode: sd(%p)", (void *) sd)); 122 return (SFO_DEVICE_PROBE_PHCI); 123 } 124 125 if (inq->inq_tpgs == SCSI_IMPLICIT_FAILOVER) { 126 VHCI_DEBUG(1, (CE_NOTE, NULL, 127 "!tpgs_tape_device_probe: Detected a " 128 "Standard Asymmetric device " 129 "with implicit failover\n")); 130 return (SFO_DEVICE_PROBE_VHCI); 131 } 132 if (inq->inq_tpgs == SCSI_EXPLICIT_FAILOVER) { 133 VHCI_DEBUG(1, (CE_NOTE, NULL, 134 "!tpgs_tape_device_probe: Detected a " 135 "Standard Asymmetric device " 136 "with explicit failover\n")); 137 return (SFO_DEVICE_PROBE_VHCI); 138 } 139 if (inq->inq_tpgs == SCSI_BOTH_FAILOVER) { 140 VHCI_DEBUG(1, (CE_NOTE, NULL, 141 "!tpgs_tape_device_probe: Detected a " 142 "Standard Asymmetric device " 143 "which supports both implicit and explicit failover\n")); 144 return (SFO_DEVICE_PROBE_VHCI); 145 } 146 VHCI_DEBUG(1, (CE_WARN, NULL, 147 "!tpgs_tape_device_probe: " 148 "Unknown tpgs_bits: %x", inq->inq_tpgs)); 149 return (SFO_DEVICE_PROBE_PHCI); 150 } 151 152 static void 153 tpgs_tape_init(void) 154 { 155 struct scsi_failover_ops *sfo, *ssfo, clone; 156 157 /* clone SFO_NAME_SYM implementation for most things */ 158 ssfo = vhci_failover_ops_by_name(SFO_NAME_TPGS); 159 if (ssfo == NULL) { 160 VHCI_DEBUG(4, (CE_NOTE, NULL, "!tpgs_tape: " 161 "can't import " SFO_NAME_SYM "\n")); 162 return; 163 } 164 sfo = &scsi_vhci_failover_ops; 165 clone = *ssfo; 166 clone.sfo_rev = sfo->sfo_rev; 167 clone.sfo_name = sfo->sfo_name; 168 clone.sfo_devices = sfo->sfo_devices; 169 clone.sfo_init = sfo->sfo_init; 170 clone.sfo_device_probe = sfo->sfo_device_probe; 171 *sfo = clone; 172 } 173