/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Implementation of "scsi_vhci_f_tpgs_tape" T10 standard based failover_ops. * * NOTE: for sequential devices only. */ #include #include #include #include #include #include #include /* Supported device table entries. */ char *tpgs_tape_dev_table[] = { NULL }; static void tpgs_tape_init(void); static int tpgs_tape_device_probe(struct scsi_device *sd, struct scsi_inquiry *inq, void **ctpriv); /* Failover module plumbing. */ #ifdef lint #define scsi_vhci_failover_ops scsi_vhci_failover_ops_f_tpgs_tape #endif /* lint */ struct scsi_failover_ops scsi_vhci_failover_ops = { SFO_REV, "f_tpgs_tape", tpgs_tape_dev_table, tpgs_tape_init, tpgs_tape_device_probe, /* The rest of the implementation comes from SFO_NAME_TPGS import */ }; static struct modlmisc modlmisc = { &mod_miscops, "f_tpgs_tape" }; static struct modlinkage modlinkage = { MODREV_1, (void *)&modlmisc, NULL }; /* * External function definitions */ extern struct scsi_failover_ops *vhci_failover_ops_by_name(char *); int _init() { return (mod_install(&modlinkage)); } int _fini() { return (mod_remove(&modlinkage)); } int _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } /* ARGSUSED */ static int tpgs_tape_device_probe(struct scsi_device *sd, struct scsi_inquiry *inq, void **ctpriv) { int mode; int state; int xlf; int preferred = 0; int support; VHCI_DEBUG(6, (CE_NOTE, NULL, "tpgs_tape_device_probe: vidpid %s\n", inq->inq_vid)); if (inq->inq_tpgs == TPGS_FAILOVER_NONE) { VHCI_DEBUG(4, (CE_WARN, NULL, "!tpgs_tape_device_probe: not a standard tpgs device")); support = SFO_DEVICE_PROBE_PHCI; } else if (inq->inq_dtype != DTYPE_SEQUENTIAL) { VHCI_DEBUG(4, (CE_NOTE, NULL, "!tpgs_tape_device_probe: Detected a " "Standard Asymmetric device " "not yet supported\n")); support = SFO_DEVICE_PROBE_PHCI; } else if (vhci_tpgs_get_target_fo_mode(sd, &mode, &state, &xlf, &preferred)) { VHCI_DEBUG(4, (CE_WARN, NULL, "!unable to fetch fo " "mode: sd(%p)", (void *) sd)); support = SFO_DEVICE_PROBE_PHCI; } else if (inq->inq_tpgs == TPGS_FAILOVER_IMPLICIT) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!tpgs_tape_device_probe: Detected a " "Standard Asymmetric device " "with implicit failover\n")); support = SFO_DEVICE_PROBE_VHCI; } else if (inq->inq_tpgs == TPGS_FAILOVER_EXPLICIT) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!tpgs_tape_device_probe: Detected a " "Standard Asymmetric device " "with explicit failover\n")); support = SFO_DEVICE_PROBE_VHCI; } else if (inq->inq_tpgs == TPGS_FAILOVER_BOTH) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!tpgs_tape_device_probe: Detected a " "Standard Asymmetric device " "which supports both implicit and explicit failover\n")); support = SFO_DEVICE_PROBE_VHCI; } else { VHCI_DEBUG(1, (CE_WARN, NULL, "!tpgs_tape_device_probe: " "Unknown tpgs_bits: %x", inq->inq_tpgs)); support = SFO_DEVICE_PROBE_PHCI; } if (support == SFO_DEVICE_PROBE_VHCI) { /* * Policy only applies to 'client' probe, not * vhci_is_dev_supported() pHCI probe. Detect difference * based on ctpriv. */ if (ctpriv && (mdi_set_lb_policy(sd->sd_dev, LOAD_BALANCE_NONE) != MDI_SUCCESS)) { VHCI_DEBUG(6, (CE_NOTE, NULL, "!fail load balance none" ": %s\n", inq->inq_vid)); support = SFO_DEVICE_PROBE_PHCI; } } return (support); } static void tpgs_tape_init(void) { struct scsi_failover_ops *sfo, *ssfo, clone; /* clone SFO_NAME_SYM implementation for most things */ ssfo = vhci_failover_ops_by_name(SFO_NAME_TPGS); if (ssfo == NULL) { VHCI_DEBUG(4, (CE_NOTE, NULL, "!tpgs_tape: " "can't import " SFO_NAME_SYM "\n")); return; } sfo = &scsi_vhci_failover_ops; clone = *ssfo; clone.sfo_rev = sfo->sfo_rev; clone.sfo_name = sfo->sfo_name; clone.sfo_devices = sfo->sfo_devices; clone.sfo_init = sfo->sfo_init; clone.sfo_device_probe = sfo->sfo_device_probe; *sfo = clone; }