Mercurial > illumos > illumos-gate
changeset 6941:c5d83acec1bc
6459247 scsi_vhci does not return correct value for dma-max property
6475502 device specific load-balance setting not displayed by mpathadm
6621014 Support multipathing to tape devices
6646241 Error in MTFSR using MTIOCLTOP to space 5000000010 blocks
6683730 st is not warlock clean
6684754 scsi_vhci pgr out getting 4B 90 FCP_DL field not sufficient to complete the transfer
6693116 st when reading to EOD where there is no filemark at EOD system asserts as blkno > lgclblkno
6693591 Recovery of write command is issuing Read Position with invalid bit set
6695072 st uscsi write of zero bytes hits assert nblks != 0
6695099 st uscsi read/write that gets error returned asserts new_lastop != ST_OP_NIL
6695128 st_recov_cb does not handle TRAN_ERR status.
6698800 Driver does not recover jammed load command
6704414 read errors encountered during fault test
line wrap: on
line diff
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c Mon Jun 23 13:41:43 2008 -0700 @@ -134,10 +134,8 @@ * As per SPC-3, Revision 23, Section 6.23 */ switch ((cdb[1] & 0x1f)) { - /* SCMD_REPORT_SUPPORTED_OPERATION_CODES */ - case 0x0c: - /* SCMD_REPORT_SUPPORTED_MANAGEMENT_FUNCTIONS */ - case 0x0d: + case SSVC_ACTION_GET_SUPPORTED_OPERATIONS: + case SSVC_SCTION_GET_SUPPORTED_MANAGEMENT: conflict = True; break; @@ -149,10 +147,10 @@ * SPC-3, Revision 23, Section 6.29 */ switch ((cdb[1] & 0x1F)) { - case SCMD_SET_DEVICE_IDENTIFIER: - case SCMD_SET_PRIORITY: - case SCMD_SET_TARGET_PORT_GROUPS: - case SCMD_SET_TIMESTAMP: + case SSVC_ACTION_SET_DEVICE_IDENTIFIER: + case SSVC_ACTION_SET_PRIORITY: + case SSVC_ACTION_SET_TARGET_PORT_GROUPS: + case SSVC_ACTION_SET_TIMESTAMP: conflict = True; break; }
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386 Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/pkgdefs/SUNWckr/prototype_i386 Mon Jun 23 13:41:43 2008 -0700 @@ -182,6 +182,8 @@ f none kernel/misc/scsi_vhci/scsi_vhci_f_sym_emc 755 root sys f none kernel/misc/scsi_vhci/scsi_vhci_f_sym_hds 755 root sys f none kernel/misc/scsi_vhci/scsi_vhci_f_tpgs 755 root sys +f none kernel/misc/scsi_vhci/scsi_vhci_f_tape 755 root sys +f none kernel/misc/scsi_vhci/scsi_vhci_f_tpgs_tape 755 root sys f none kernel/misc/acpica 755 root sys f none kernel/misc/agpmaster 755 root sys f none kernel/misc/bignum 755 root sys @@ -385,6 +387,8 @@ f none kernel/misc/scsi_vhci/amd64/scsi_vhci_f_sym_emc 755 root sys f none kernel/misc/scsi_vhci/amd64/scsi_vhci_f_sym_hds 755 root sys f none kernel/misc/scsi_vhci/amd64/scsi_vhci_f_tpgs 755 root sys +f none kernel/misc/scsi_vhci/amd64/scsi_vhci_f_tape 755 root sys +f none kernel/misc/scsi_vhci/amd64/scsi_vhci_f_tpgs_tape 755 root sys d none kernel/misc/amd64 755 root sys f none kernel/misc/amd64/acpica 755 root sys
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc Mon Jun 23 13:41:43 2008 -0700 @@ -179,6 +179,8 @@ f none kernel/misc/scsi_vhci/sparcv9/scsi_vhci_f_sym_emc 755 root sys f none kernel/misc/scsi_vhci/sparcv9/scsi_vhci_f_sym_hds 755 root sys f none kernel/misc/scsi_vhci/sparcv9/scsi_vhci_f_tpgs 755 root sys +f none kernel/misc/scsi_vhci/sparcv9/scsi_vhci_f_tape 755 root sys +f none kernel/misc/scsi_vhci/sparcv9/scsi_vhci_f_tpgs_tape 755 root sys d none kernel/misc/sparcv9 755 root sys f none kernel/misc/sparcv9/busra 755 root sys f none kernel/misc/sparcv9/cardbus 755 root sys
--- a/usr/src/pkgdefs/common_files/i.scsivhciconf Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/pkgdefs/common_files/i.scsivhciconf Mon Jun 23 13:41:43 2008 -0700 @@ -136,6 +136,8 @@ "misc/scsi_vhci/scsi_vhci_f_sym_emc", "misc/scsi_vhci/scsi_vhci_f_sym_hds", "misc/scsi_vhci/scsi_vhci_f_sym", +# "misc/scsi_vhci/scsi_vhci_f_tpgs_tape", +# "misc/scsi_vhci/scsi_vhci_f_tape", "misc/scsi_vhci/scsi_vhci_f_tpgs"; #
--- a/usr/src/uts/common/Makefile.files Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/Makefile.files Mon Jun 23 13:41:43 2008 -0700 @@ -676,7 +676,7 @@ scsi_resource.o scsi_subr.o scsi_transport.o scsi_watch.o \ sas_transport.o -SCSI_VHCI_OBJS += scsi_vhci.o mpapi_impl.o +SCSI_VHCI_OBJS += scsi_vhci.o mpapi_impl.o scsi_vhci_tpgs.o SCSI_VHCI_F_SYM_OBJS += sym.o @@ -686,6 +686,10 @@ SCSI_VHCI_F_SYM_HDS_OBJS += sym_hds.o +SCSI_VHCI_F_TAPE_OBJS += tape.o + +SCSI_VHCI_F_TPGS_TAPE_OBJS += tpgs_tape.o + SGEN_OBJS += sgen.o SMP_OBJS += smp.o
--- a/usr/src/uts/common/io/scsi/adapters/scsi_vhci/fops/sym_hds.c Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/fops/sym_hds.c Mon Jun 23 13:41:43 2008 -0700 @@ -82,7 +82,7 @@ }; static struct modlmisc modlmisc = { - &mod_miscops, "f_sym_hds 1.1" + &mod_miscops, "f_sym_hds %I%" }; static struct modlinkage modlinkage = { @@ -142,7 +142,7 @@ /* ARGSUSED */ static int hds_sym_device_probe(struct scsi_device *sd, struct scsi_inquiry *stdinq, -void **ctpriv) + void **ctpriv) { char **dt; char *dftype;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/fops/tape.c Mon Jun 23 13:41:43 2008 -0700 @@ -0,0 +1,204 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Implementation of "scsi_vhci_f_tape" tape failover_ops. + * + * This file was historically meant for only tape implementation. It has + * been extended to manage SUN "supported" tape controllers. The supported + * VID/PID shall be listed in the tape_dev_table. + */ + +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/scsi/scsi.h> +#include <sys/scsi/adapters/scsi_vhci.h> + +/* Supported device table entries. */ +static char *tape_dev_table[] = { +/* " 111111" */ +/* "012345670123456789012345" */ +/* "|-VID--||-----PID------|" */ + "IBM ULTRIUM-TD3", + "IBM ULTRIUM-TD4", + NULL +}; + +/* Failover module plumbing. */ +SCSI_FAILOVER_OP("f_tape", tape, "%I%"); + +/* ARGSUSED */ +static int +tape_device_probe(struct scsi_device *sd, struct scsi_inquiry *inquiry, + void **ctpriv) +{ + int i; + int rval = SFO_DEVICE_PROBE_PHCI; + + VHCI_DEBUG(6, (CE_NOTE, NULL, "!tape_device_probe: inquiry string %s\n", + inquiry->inq_vid)); + /* + * See if this a device type that we want to care about. + */ + switch (inquiry->inq_dtype & DTYPE_MASK) { + case DTYPE_SEQUENTIAL: + break; + case DTYPE_CHANGER: + rval = SFO_DEVICE_PROBE_VHCI; + goto done; + default: + /* + * Not interested. + */ + return (rval); + } + + /* + * If it reports that it supports tpgs and it got here it may have + * failed the tpgs commands. It might or might not support dual port + * but we'll go with it. + */ + if (inquiry->inq_tpgs) { + VHCI_DEBUG(6, (CE_NOTE, NULL, "!has tpgs bits: %s\n", + inquiry->inq_vid)); + rval = SFO_DEVICE_PROBE_VHCI; + } else if (inquiry->inq_dualp) { + /* + * Looks like it claims to have more then one port. + */ + VHCI_DEBUG(6, (CE_NOTE, NULL, "!has dual port bits: %s\n", + inquiry->inq_vid)); + rval = SFO_DEVICE_PROBE_VHCI; + } else { + + /* + * See if this device is on the list. + */ + for (i = 0; tape_dev_table[i]; i++) { + + if (strncmp(inquiry->inq_vid, tape_dev_table[i], + strlen(tape_dev_table[i])) == 0) { + VHCI_DEBUG(6, (CE_NOTE, NULL, + "!was on the list: %s\n", + inquiry->inq_vid)); + rval = SFO_DEVICE_PROBE_VHCI; + break; + } + } + } +done: + if (rval == SFO_DEVICE_PROBE_VHCI) { + if (mdi_set_lb_policy(sd->sd_dev, LOAD_BALANCE_NONE) != + MDI_SUCCESS) { + VHCI_DEBUG(6, (CE_NOTE, NULL, "!fail load balance none" + ": %s\n", inquiry->inq_vid)); + return (SFO_DEVICE_PROBE_PHCI); + } + + } + return (rval); +} + +/* ARGSUSED */ +static void +tape_device_unprobe(struct scsi_device *sd, void *ctpriv) +{ + /* + * NO OP for tape. + */ + +} + +/* ARGSUSED */ +static int +tape_path_activate(struct scsi_device *sd, char *pathclass, void *ctpriv) +{ + return (0); +} + +/* ARGSUSED */ +static int +tape_path_deactivate(struct scsi_device *sd, char *pathclass, void *ctpriv) +{ + return (0); +} + +/* ARGSUSED */ +static int +tape_path_get_opinfo(struct scsi_device *sd, struct scsi_path_opinfo *opinfo, + void *ctpriv) +{ + opinfo->opinfo_rev = OPINFO_REV; + (void) strcpy(opinfo->opinfo_path_attr, PCLASS_PRIMARY); + opinfo->opinfo_path_state = SCSI_PATH_ACTIVE; + opinfo->opinfo_pswtch_best = 0; /* N/A */ + opinfo->opinfo_pswtch_worst = 0; /* N/A */ + opinfo->opinfo_xlf_capable = 0; + opinfo->opinfo_mode = SCSI_NO_FAILOVER; + opinfo->opinfo_preferred = 1; + + return (0); +} + +/* ARGSUSED */ +static int +tape_path_ping(struct scsi_device *sd, void *ctpriv) +{ + return (1); +} + +/* ARGSUSED */ +static int +tape_analyze_sense(struct scsi_device *sd, struct scsi_extended_sense *sense, + void *ctpriv) +{ + if (sense->es_key == KEY_ABORTED_COMMAND && + sense->es_add_code == 0x4b && + sense->es_qual_code == 0x83) { + return (SCSI_SENSE_INACTIVE); + } + if (sense->es_key == KEY_NOT_READY && + sense->es_add_code == 0x4 && + sense->es_qual_code == 0x1) { + return (SCSI_SENSE_NOT_READY); + } + return (SCSI_SENSE_NOFAILOVER); +} + +/* ARGSUSED */ +static int +tape_pathclass_next(char *cur, char **nxt, void *ctpriv) +{ + if (cur == NULL) { + *nxt = PCLASS_PRIMARY; + return (0); + } else if (strcmp(cur, PCLASS_PRIMARY) == 0) { + return (ENOENT); + } + return (EINVAL); +}
--- a/usr/src/uts/common/io/scsi/adapters/scsi_vhci/fops/tpgs.c Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/fops/tpgs.c Mon Jun 23 13:41:43 2008 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -36,6 +36,7 @@ #include <sys/sunddi.h> #include <sys/scsi/scsi.h> #include <sys/scsi/adapters/scsi_vhci.h> +#include <sys/scsi/adapters/scsi_vhci_tpgs.h> /* Supported device table entries. */ char *std_dev_table[] = { NULL }; @@ -43,8 +44,6 @@ /* Failover module plumbing. */ SCSI_FAILOVER_OP(SFO_NAME_TPGS, std, "%I%"); -#define STD_SCSI_CMD_LEN 0xff - #define STD_FO_CMD_RETRY_DELAY 1000000 /* 1 seconds */ #define STD_FO_RETRY_DELAY 2000000 /* 2 seconds */ /* @@ -54,68 +53,24 @@ */ #define STD_FO_MAX_RETRIES (3*60*1000000)/STD_FO_RETRY_DELAY -/* - * max number of retries for std failover to complete where the ping - * command is failing due to transport errors or commands being rejected by - * std. - * STD_FO_MAX_RETRIES takes into account the case where CMD_CMPLTs but - * std takes time to complete the failover. - */ -#define STD_FO_MAX_CMD_RETRIES 3 - -#define STD_ACTIVE_OPTIMIZED 0x0 -#define STD_ACTIVE_NONOPTIMIZED 0x1 -#define STD_STANDBY 0x2 -#define STD_UNAVAILABLE 0x3 -#define STD_TRANSITIONING 0xf - -#define STD_SCSI_ASC_STATE_TRANS 0x04 -#define STD_SCSI_ASCQ_STATE_TRANS_FAIL 0x0A -#define STD_SCSI_ASC_STATE_CHG 0x2A -#define STD_SCSI_ASCQ_STATE_CHG_SUCC 0x06 -#define STD_SCSI_ASCQ_STATE_CHG_FAILED 0x07 -#define STD_SCSI_ASC_INVAL_PARAM_LIST 0x26 -#define STD_SCSI_ASC_INVAL_CMD_OPCODE 0x20 -#define STD_LOGICAL_UNIT_NOT_ACCESSIBLE 0x04 -#define STD_TGT_PORT_UNAVAILABLE 0x0C - - -/* Special exported for direct use by MP-API */ -int std_set_target_groups(struct scsi_address *, int, int); - -/* - * External function definitions - */ -extern void vhci_mpapi_update_tpg_data(struct scsi_address *, char *); - -static int std_get_fo_mode(struct scsi_device *, - int *, int *, int *, int *); -static int std_report_target_groups(struct scsi_address *, struct buf *, - int, int, int *, int *); /* ARGSUSED */ static int std_device_probe(struct scsi_device *sd, struct scsi_inquiry *inq, -void **ctpriv) + void **ctpriv) { - unsigned int tpgs_bits; - unsigned char *inqbuf = (unsigned char *)inq; - unsigned char dtype = (inq->inq_dtype & DTYPE_MASK); - int mode, state, xlf, preferred = 0; VHCI_DEBUG(6, (CE_NOTE, NULL, "std_device_probe: vidpid %s\n", inq->inq_vid)); - tpgs_bits = ((inqbuf[5] & 0x30) >> 4); - - if (tpgs_bits == 0) { + if (inq->inq_tpgs == 0) { VHCI_DEBUG(4, (CE_WARN, NULL, "!std_device_probe: not a standard tpgs device")); return (SFO_DEVICE_PROBE_PHCI); } - if (dtype == DTYPE_SEQUENTIAL) { + if (inq->inq_dtype == DTYPE_SEQUENTIAL) { VHCI_DEBUG(4, (CE_NOTE, NULL, "!std_device_probe: Detected a " "Standard Asymmetric device " @@ -123,27 +78,27 @@ return (SFO_DEVICE_PROBE_PHCI); } - if (std_get_fo_mode(sd, &mode, &state, &xlf, &preferred)) { + 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)); return (SFO_DEVICE_PROBE_PHCI); } - if (tpgs_bits == SCSI_IMPLICIT_FAILOVER) { + if (inq->inq_tpgs == SCSI_IMPLICIT_FAILOVER) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_device_probe: Detected a " "Standard Asymmetric device " "with implicit failover\n")); return (SFO_DEVICE_PROBE_VHCI); } - if (tpgs_bits == SCSI_EXPLICIT_FAILOVER) { + if (inq->inq_tpgs == SCSI_EXPLICIT_FAILOVER) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_device_probe: Detected a " "Standard Asymmetric device " "with explicit failover\n")); return (SFO_DEVICE_PROBE_VHCI); } - if (tpgs_bits == SCSI_BOTH_FAILOVER) { + if (inq->inq_tpgs == SCSI_BOTH_FAILOVER) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_device_probe: Detected a " "Standard Asymmetric device " @@ -152,7 +107,7 @@ } VHCI_DEBUG(1, (CE_WARN, NULL, "!std_device_probe: " - "Unknown tpgs_bits: %x", tpgs_bits)); + "Unknown tpgs_bits: %x", inq->inq_tpgs)); return (SFO_DEVICE_PROBE_PHCI); } @@ -165,412 +120,12 @@ */ } -static int -std_inquiry(struct scsi_address *ap, struct buf *bp, int *mode) -{ - struct scsi_pkt *pkt; - char buf[STD_SCSI_CMD_LEN]; - int buf_size = sizeof (buf); - unsigned int tpgs_bits; - int retval; - - *mode = 0; - bp->b_un.b_addr = (caddr_t)&buf; - bp->b_flags = B_READ; - bp->b_bcount = buf_size; - bp->b_resid = 0; - - pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP0, - sizeof (struct scsi_arq_status), 0, 0, SLEEP_FUNC, NULL); - pkt->pkt_cdbp[0] = SCMD_INQUIRY; - pkt->pkt_cdbp[4] = (unsigned char)buf_size; - pkt->pkt_time = 60; - - retval = vhci_do_scsi_cmd(pkt); - scsi_destroy_pkt(pkt); - if (retval == 0) { - VHCI_DEBUG(1, (CE_WARN, NULL, - "!std_inquiry: Failure returned from vhci_do_scsi_cmd")); - return (1); - } - - tpgs_bits = ((buf[5] & 0x30) >> 4); - if (tpgs_bits == 0) { - VHCI_DEBUG(1, (CE_WARN, NULL, - "!std_inquiry: zero tpgs_bits")); - return (1); - } - retval = 0; - if (tpgs_bits == SCSI_IMPLICIT_FAILOVER) { - *mode = SCSI_IMPLICIT_FAILOVER; - } else if (tpgs_bits == SCSI_EXPLICIT_FAILOVER) { - *mode = SCSI_EXPLICIT_FAILOVER; - } else if (tpgs_bits == SCSI_BOTH_FAILOVER) { - *mode = SCSI_BOTH_FAILOVER; - } else { - VHCI_DEBUG(1, (CE_WARN, NULL, - "!std_inquiry: Illegal mode returned: %x mode: %x", - tpgs_bits, *mode)); - retval = 1; - } - - return (retval); -} - -static int -std_page83(struct scsi_address *ap, struct buf *bp, - int *rel_tgt_port, int *tgt_port, int *lu) -{ - char *ptr, *end; - struct scsi_pkt *pkt; - char *bufp; - unsigned int buf_len, rx_bsize; - - /* - * lets start the buf size with 512 bytes. If this - * if found to be insufficient, we can allocate - * appropriate size in the next iteration. - */ - buf_len = 512; - -once_again: - bufp = kmem_zalloc(buf_len, KM_NOSLEEP); - if (bufp == NULL) { - VHCI_DEBUG(1, (CE_WARN, NULL, "!std_page83: " - "request packet allocation for %d failed....", - buf_len)); - return (1); - } - - - bp->b_un.b_addr = bufp; - bp->b_flags = B_READ; - bp->b_bcount = buf_len; - bp->b_resid = 0; - - pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP0, - sizeof (struct scsi_arq_status), 0, 0, NULL, NULL); - if (pkt == NULL) { - VHCI_DEBUG(1, (CE_WARN, NULL, - "!std_page83: Failure returned from scsi_init_pkt")); - kmem_free((void *)bufp, buf_len); - return (1); - } - - pkt->pkt_cdbp[0] = SCMD_INQUIRY; - pkt->pkt_cdbp[1] = 0x1; - pkt->pkt_cdbp[2] = 0x83; - pkt->pkt_cdbp[3] = (unsigned char)((buf_len >> 8) & 0xff); - pkt->pkt_cdbp[4] = (unsigned char)(buf_len & 0xff); - pkt->pkt_time = 90; - - if (vhci_do_scsi_cmd(pkt) == 0) { - VHCI_DEBUG(1, (CE_NOTE, NULL, - "!std_page83: vhci_do_scsi_cmd failed\n")); - kmem_free((void *)bufp, buf_len); - scsi_destroy_pkt(pkt); - return (1); - } - - /* - * Now lets check if the size that was provided was - * sufficient. If not, allocate the appropriate size - * and retry the command again. - */ - rx_bsize = (((bufp[2] & 0xff) << 8) | (bufp[3] & 0xff)); - rx_bsize += 4; - if (rx_bsize > buf_len) { - /* - * Need to allocate more buf and retry again - */ - VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_page83: " - "bufsize: %d greater than allocated buf: %d\n", - rx_bsize, buf_len)); - VHCI_DEBUG(1, (CE_NOTE, NULL, "Retrying for size %d\n", - rx_bsize)); - kmem_free((void *)bufp, buf_len); - buf_len = (unsigned int)(rx_bsize); - goto once_again; - } - - ptr = bufp; - ptr += 4; /* identification descriptor 0 */ - end = bufp + rx_bsize; - while (ptr < end) { - VHCI_DEBUG(1, (CE_NOTE, NULL, "std_page83: desc[1/4/5/6/7]:" - "%x %x %x %x %x\n", - ptr[1], ptr[4], ptr[5], ptr[6], ptr[7])); - if ((ptr[1] & 0x0f) == 0x04) { - *rel_tgt_port = 0; - *rel_tgt_port |= ((ptr[6] & 0xff) << 8); - *rel_tgt_port |= (ptr[7] & 0xff); - VHCI_DEBUG(1, (CE_NOTE, NULL, - "!std_page83: relative target port: %x\n", - *rel_tgt_port)); - } else if ((ptr[1] & 0x0f) == 0x05) { - *tgt_port = 0; - *tgt_port = ((ptr[6] & 0xff) << 8); - *tgt_port |= (ptr[7] & 0xff); - VHCI_DEBUG(1, (CE_NOTE, NULL, - "!std_page83: target port: %x\n", *tgt_port)); - } else if ((ptr[1] & 0x0f) == 0x06) { - *lu = 0; - *lu |= ((ptr[6] & 0xff)<< 8); - *lu |= (ptr[7] & 0xff); - VHCI_DEBUG(1, (CE_NOTE, NULL, - "!std_page83: logical unit: %x\n", *lu)); - } - ptr += ptr[3] + 4; /* next identification descriptor */ - } - kmem_free((void *)bufp, buf_len); - scsi_destroy_pkt(pkt); - return (0); -} - -#ifdef DEBUG -static void -print_buf(char *buf, int buf_size) -{ - int i = 0, j; - int loop, left; - - loop = buf_size / 8; - left = buf_size % 8; - - VHCI_DEBUG(4, (CE_NOTE, NULL, "!buf_size: %x loop: %x left: %x", - buf_size, loop, left)); - - for (j = 0; j < loop; j++) { - VHCI_DEBUG(4, (CE_NOTE, NULL, - "!buf[%d-%d]: %x %x %x %x %x %x %x %x", - i, i + 7, buf[i], buf[i+1], buf[i+2], buf[i+3], - buf[i+4], buf[i+5], buf[i+6], buf[i+7])); - i += 8; - } - - if (left) { - VHCI_DEBUG(4, (CE_CONT, NULL, - "NOTICE: buf[%d-%d]:", i, i + left)); - for (j = 0; j < left; j++) { - VHCI_DEBUG(4, (CE_CONT, NULL, " %x", buf[i + j])); - } - VHCI_DEBUG(4, (CE_CONT, NULL, "\n")); - } -} -#endif - -static int -std_report_target_groups(struct scsi_address *ap, struct buf *bp, - int rel_tgt_port, int tgt_port, int *pstate, int *preferred) -{ - struct scsi_pkt *pkt; - char *ptr, *end, *bufp, *mpapi_ptr; - unsigned int rtpg_len = 0; - unsigned int l_tgt_port = 0, tpgs_state = 0; - unsigned int tgt_port_cnt = 0, lr_tgt_port = 0; - int i, len; - - /* - * Start with buffer size of 512. - * If this is found to be insufficient, required size - * will be allocated and the command will be retried. - */ - len = 512; - -try_again: - bufp = kmem_zalloc(len, KM_NOSLEEP); - if (bufp == NULL) { - VHCI_DEBUG(1, (CE_WARN, NULL, "!std_report_target_groups: " - "request packet allocation for %d failed....", - len)); - return (1); - } - - bp->b_un.b_addr = bufp; - bp->b_flags = B_READ; - bp->b_bcount = len; - bp->b_resid = 0; - - pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP5, - sizeof (struct scsi_arq_status), 0, 0, NULL, NULL); - - if (pkt == NULL) { - VHCI_DEBUG(1, (CE_NOTE, NULL, - "!std_report_target_groups: scsi_init_pkt error\n")); - kmem_free((void *)bufp, len); - return (1); - } - - pkt->pkt_cdbp[0] = SCMD_MAINTENANCE_IN; - pkt->pkt_cdbp[1] = SCMD_SET_TARGET_PORT_GROUPS; - pkt->pkt_cdbp[6] = ((len >> 24) & 0xff); - pkt->pkt_cdbp[7] = ((len >> 16) & 0xff); - pkt->pkt_cdbp[8] = ((len >> 8) & 0xff); - pkt->pkt_cdbp[9] = len & 0xff; - pkt->pkt_time = 90; - - VHCI_DEBUG(6, (CE_NOTE, NULL, - "!std_report_target_groups: sending target port group:" - " cdb[6/7/8/9]: %x/%x/%x/%x\n", pkt->pkt_cdbp[6], - pkt->pkt_cdbp[7], pkt->pkt_cdbp[8], pkt->pkt_cdbp[9])); - if (vhci_do_scsi_cmd(pkt) == 0) { - VHCI_DEBUG(4, (CE_NOTE, NULL, "!std_report_target_groups:" - " vhci_do_scsi_cmd failed\n")); - kmem_free((void *)bufp, len); - scsi_destroy_pkt(pkt); - return (1); - } - ptr = bufp; - VHCI_DEBUG(6, (CE_NOTE, NULL, "!std_report_target_groups:" - " returned from target" - " port group: buf[0/1/2/3]: %x/%x/%x/%x\n", - ptr[0], ptr[1], ptr[2], ptr[3])); - rtpg_len = (unsigned int)((0xff & ptr[0]) << 24); - rtpg_len |= (unsigned int)((0xff & ptr[1]) << 16); - rtpg_len |= (unsigned int)((0xff & ptr[2]) << 8); - rtpg_len |= (unsigned int)(0xff & ptr[3]); - rtpg_len += 4; - if (rtpg_len > len) { - VHCI_DEBUG(4, (CE_NOTE, NULL, "!std_report_target_groups: " - "bufsize: %d greater than allocated buf: %d\n", - rtpg_len, len)); - VHCI_DEBUG(4, (CE_NOTE, NULL, "Retrying for size %d\n", - rtpg_len)); - kmem_free((void *)bufp, len); - len = (unsigned int)(rtpg_len + 1); - goto try_again; - } -#ifdef DEBUG - print_buf(bufp, rtpg_len); -#endif - end = ptr + rtpg_len; - ptr += 4; - while (ptr < end) { - mpapi_ptr = ptr; - l_tgt_port = ((ptr[2] & 0xff) << 8) + (ptr[3] & 0xff); - tpgs_state = ptr[0] & 0x0f; - tgt_port_cnt = (ptr[7] & 0xff); - VHCI_DEBUG(4, (CE_NOTE, NULL, "!std_report_tgt_groups:" - " tpgs state: %x" - " tgt_group: %x count: %x\n", tpgs_state, - l_tgt_port, tgt_port_cnt)); - ptr += 8; - for (i = 0; i < tgt_port_cnt; i++) { - lr_tgt_port = 0; - lr_tgt_port |= ((ptr[2] & 0Xff) << 8); - lr_tgt_port |= (ptr[3] & 0xff); - - if ((lr_tgt_port == rel_tgt_port) && - (l_tgt_port == tgt_port)) { - VHCI_DEBUG(4, (CE_NOTE, NULL, - "!std_report_tgt_groups:" - " found tgt_port: %x rel_tgt_port:%x" - " tpgs_state: %x\n", tgt_port, rel_tgt_port, - tpgs_state)); - /* - * once we have the preferred flag - * and a non-optimized state flag - * we will get preferred flag from the - * report target groups - */ - if (tpgs_state == STD_ACTIVE_OPTIMIZED) { - *pstate = STD_ACTIVE_OPTIMIZED; - *preferred = PCLASS_PREFERRED; - } else if (tpgs_state == - STD_ACTIVE_NONOPTIMIZED) { - *pstate = STD_ACTIVE_NONOPTIMIZED; - *preferred = PCLASS_NONPREFERRED; - } else if (tpgs_state == STD_STANDBY) { - *pstate = STD_STANDBY; - *preferred = PCLASS_NONPREFERRED; - } else { - *pstate = STD_UNAVAILABLE; - *preferred = PCLASS_NONPREFERRED; - } - vhci_mpapi_update_tpg_data(ap, mpapi_ptr); - kmem_free((void *)bufp, len); - scsi_destroy_pkt(pkt); - return (0); - } - VHCI_DEBUG(4, (CE_NOTE, NULL, "!std_report_tgt_groups:" - " tgt_port: %x rel_tgt_port:%x\n", tgt_port, - rel_tgt_port)); - ptr += 4; - } - } - *pstate = SCSI_PATH_INACTIVE; - *preferred = PCLASS_NONPREFERRED; - VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_report_tgt_groups: " - "NO rel_TGTPRT MATCH!!! Assigning Default: state: %x " - "preferred: %d\n", *pstate, *preferred)); - kmem_free((void *)bufp, len); - scsi_destroy_pkt(pkt); - return (1); -} - -/* - * get the failover mode, ownership and if it has extended failover - * capability. The mode(bits5-4/byte5) is defined as implicit, explicit, or - * both. The state is defined as online-optimized(0h), - * online-nonoptimized(1h), standby(2h), offline(3h), - * and transitioning(fh). Currently, there is online, - * standby, and offline(defined in sunmdi.h). - * Online-nonoptimized will be a mode of secondary - * and an ownership of online. Thought about using a different mode but - * it appears the states are really for the states for secondary mode. - * We currently have IS_ONLINING, IS_OFFLINING - should we have TRANSITIONING - * to mean from online-optimized to online-nonoptimized or does onlining - * cover this? - */ -/* ARGSUSED */ -static int -std_get_fo_mode(struct scsi_device *sd, int *mode, - int *state, int *xlf_capable, int *preferred) -{ - int retval = 0; - struct buf *bp; - struct scsi_address *ap; - int lu = 0, rel_tgt_port = 0, tgt_port = 0x0; - - VHCI_DEBUG(6, (CE_NOTE, NULL, "!std_get_fo_mode: enter\n")); - *mode = *state = *xlf_capable = 0; - bp = getrbuf(KM_NOSLEEP); - if (bp == NULL) { - VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_get_fo_mode: " - " failed getrbuf\n")); - return (1); - } - - ap = &sd->sd_address; - if (std_inquiry(ap, bp, mode)) { - VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_get_fo_mode: " - " failed std_inquiry\n")); - retval = 1; - } else if (std_page83(ap, bp, &rel_tgt_port, &tgt_port, &lu)) { - VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_get_fo_mode: " - " failed std_page83\n")); - retval = 1; - } else if (std_report_target_groups(ap, bp, rel_tgt_port, tgt_port, - state, preferred)) { - VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_get_fo_mode: " - " failed std_report_target_groups\n")); - retval = 1; - } - - freerbuf(bp); - if (retval == 0) { - VHCI_DEBUG(6, (CE_NOTE, NULL, "!std_get_fo_mode: " - "SUCCESS\n")); - } - return (retval); -} - /* ARGSUSED */ static int std_activate_explicit(struct scsi_device *sd, int xlf_capable) { cmn_err(CE_NOTE, "Explicit Activation is done by " - "std_set_target_groups() call from MPAPI"); + "vhci_tpgs_set_target_groups() call from MPAPI"); return (1); } @@ -580,7 +135,7 @@ */ static int std_process_cmplt_pkt(struct scsi_device *sd, struct scsi_pkt *pkt, - int *retry_cnt) + int *retry_cnt) { struct scsi_extended_sense *sns; @@ -666,7 +221,7 @@ /* ARGSUSED */ static int std_path_activate(struct scsi_device *sd, char *pathclass, -void *ctpriv) + void *ctpriv) { struct buf *bp; struct scsi_pkt *pkt; @@ -678,9 +233,9 @@ mode = state = 0; - if (std_get_fo_mode(sd, &mode, &state, &xlf, &preferred)) { + if (vhci_tpgs_get_target_fo_mode(sd, &mode, &state, &xlf, &preferred)) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_path_activate:" - " failed std_get_fo_mode\n")); + " failed vhci_tpgs_get_target_fo_mode\n")); return (1); } if ((state == STD_ACTIVE_OPTIMIZED) || @@ -797,23 +352,23 @@ /* ARGSUSED */ static int std_path_deactivate(struct scsi_device *sd, char *pathclass, -void *ctpriv) + void *ctpriv) { return (0); } /* ARGSUSED */ static int -std_path_get_opinfo(struct scsi_device *sd, struct scsi_path_opinfo -*opinfo, void *ctpriv) +std_path_get_opinfo(struct scsi_device *sd, struct scsi_path_opinfo *opinfo, + void *ctpriv) { int mode, preferred, state, xlf; opinfo->opinfo_rev = OPINFO_REV; - if (std_get_fo_mode(sd, &mode, &state, &xlf, &preferred)) { + if (vhci_tpgs_get_target_fo_mode(sd, &mode, &state, &xlf, &preferred)) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_path_getopinfo:" - " failed std_get_fo_mode\n")); + " failed vhci_tpgs_get_target_fo_mode\n")); return (1); } @@ -858,8 +413,8 @@ */ /* ARGSUSED */ static int -std_analyze_sense(struct scsi_device *sd, struct scsi_extended_sense -*sense, void *ctpriv) +std_analyze_sense(struct scsi_device *sd, struct scsi_extended_sense *sense, + void *ctpriv) { int rval = SCSI_SENSE_UNKNOWN; @@ -931,130 +486,3 @@ return (EINVAL); } } - -int -std_set_target_groups(struct scsi_address *ap, int set_state, int tpg_id) -{ - struct scsi_pkt *pkt; - struct buf *bp; - int len, rval, ss = SCSI_SENSE_UNKNOWN; - char *bufp; - struct scsi_extended_sense *sns; - - len = 8; - - bp = getrbuf(KM_NOSLEEP); - if (bp == NULL) { - VHCI_DEBUG(1, (CE_WARN, NULL, "!std_set_target_groups: " - " failed getrbuf")); - return (1); - } - - bufp = kmem_zalloc(len, KM_NOSLEEP); - if (bufp == NULL) { - VHCI_DEBUG(1, (CE_WARN, NULL, "!std_set_target_groups: " - "request packet allocation for %d failed....", len)); - freerbuf(bp); - return (1); - } - - bp->b_un.b_addr = bufp; - bp->b_flags = B_READ; - bp->b_bcount = len; - bp->b_resid = 0; - - bufp[4] = (0x0f & set_state); - bufp[6] = (0xff00 & tpg_id) >> 8; - bufp[7] = (0x00ff & tpg_id); - - pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP5, - sizeof (struct scsi_arq_status), 0, 0, NULL, NULL); - - if (pkt == NULL) { - VHCI_DEBUG(1, (CE_NOTE, NULL, - "!std_set_target_groups: scsi_init_pkt error\n")); - freerbuf(bp); - kmem_free((void *)bufp, len); - return (1); - } - - /* - * Sends 1 TPG descriptor only. Hence Parameter list length pkt_cdbp[9] - * is set to 8 bytes - Refer SPC3 for details. - */ - pkt->pkt_cdbp[0] = SCMD_MAINTENANCE_OUT; - pkt->pkt_cdbp[1] = SCMD_SET_TARGET_PORT_GROUPS; - pkt->pkt_cdbp[9] = 8; - pkt->pkt_time = 90; - - VHCI_DEBUG(1, (CE_NOTE, NULL, - "!std_set_target_groups: sending set target port group:" - " cdb[0/1/6/7/8/9]: %x/%x/%x/%x/%x/%x\n", pkt->pkt_cdbp[0], - pkt->pkt_cdbp[1], pkt->pkt_cdbp[6], pkt->pkt_cdbp[7], - pkt->pkt_cdbp[8], pkt->pkt_cdbp[9])); - -#ifdef DEBUG - print_buf(bufp, len); -#endif - rval = vhci_do_scsi_cmd(pkt); - - if (rval == 0) { - VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_set_target_groups:" - " vhci_do_scsi_cmd failed\n")); - freerbuf(bp); - kmem_free((void *)bufp, len); - scsi_destroy_pkt(pkt); - return (-1); - } else if ((pkt->pkt_reason == CMD_CMPLT) && - (SCBP_C(pkt) == STATUS_CHECK) && - (pkt->pkt_state & STATE_ARQ_DONE)) { - sns = &(((struct scsi_arq_status *)(uintptr_t) - (pkt->pkt_scbp))->sts_sensedata); - - if ((sns->es_key == KEY_UNIT_ATTENTION) && - (sns->es_add_code == STD_SCSI_ASC_STATE_CHG) && - (sns->es_qual_code == STD_SCSI_ASCQ_STATE_CHG_SUCC)) { - ss = SCSI_SENSE_STATE_CHANGED; - VHCI_DEBUG(4, (CE_NOTE, NULL, "!std_set_target_groups:" - " sense:%x, add_code: %x, qual_code:%x" - " sense:%x\n", sns->es_key, sns->es_add_code, - sns->es_qual_code, ss)); - } else if ((sns->es_key == KEY_ILLEGAL_REQUEST) && - (sns->es_add_code == STD_SCSI_ASC_INVAL_PARAM_LIST)) { - ss = SCSI_SENSE_NOFAILOVER; - VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_set_target_groups:" - " sense:%x, add_code: %x, qual_code:%x" - " sense:%x\n", sns->es_key, sns->es_add_code, - sns->es_qual_code, ss)); - } else if ((sns->es_key == KEY_ILLEGAL_REQUEST) && - (sns->es_add_code == STD_SCSI_ASC_INVAL_CMD_OPCODE)) { - ss = SCSI_SENSE_NOFAILOVER; - VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_set_target_groups:" - " sense_key:%x, add_code: %x, qual_code:%x" - " sense:%x\n", sns->es_key, sns->es_add_code, - sns->es_qual_code, rval)); - } else { - /* - * At this point sns data may be for power-on-reset - * UNIT ATTN hardware errors, vendor unqiue sense etc. - * For all these cases, sense is unknown. - */ - ss = SCSI_SENSE_NOFAILOVER; - VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_set_target_groups: " - " sense UNKNOWN: sense key:%x, ASC:%x, ASCQ:%x\n", - sns->es_key, sns->es_add_code, sns->es_qual_code)); - } - - if (ss == SCSI_SENSE_STATE_CHANGED) { - freerbuf(bp); - kmem_free((void *)bufp, len); - scsi_destroy_pkt(pkt); - return (0); - } - } - - freerbuf(bp); - kmem_free((void *)bufp, len); - scsi_destroy_pkt(pkt); - return (1); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/fops/tpgs_tape.c Mon Jun 23 13:41:43 2008 -0700 @@ -0,0 +1,172 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Implementation of "scsi_vhci_f_tpgs_tape" T10 standard based failover_ops. + * + * NOTE: for sequential devices only. + */ + +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/scsi/scsi.h> +#include <sys/scsi/adapters/scsi_vhci.h> +#include <sys/scsi/adapters/scsi_vhci_tpgs.h> + +/* 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 %I%" +}; + +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, state, xlf, preferred = 0; + + VHCI_DEBUG(6, (CE_NOTE, NULL, "tpgs_tape_device_probe: vidpid %s\n", + inq->inq_vid)); + + if (inq->inq_tpgs == 0) { + VHCI_DEBUG(4, (CE_WARN, NULL, + "!tpgs_tape_device_probe: not a standard tpgs device")); + return (SFO_DEVICE_PROBE_PHCI); + } + + 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")); + return (SFO_DEVICE_PROBE_PHCI); + } + + 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)); + return (SFO_DEVICE_PROBE_PHCI); + } + + if (inq->inq_tpgs == SCSI_IMPLICIT_FAILOVER) { + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!tpgs_tape_device_probe: Detected a " + "Standard Asymmetric device " + "with implicit failover\n")); + return (SFO_DEVICE_PROBE_VHCI); + } + if (inq->inq_tpgs == SCSI_EXPLICIT_FAILOVER) { + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!tpgs_tape_device_probe: Detected a " + "Standard Asymmetric device " + "with explicit failover\n")); + return (SFO_DEVICE_PROBE_VHCI); + } + if (inq->inq_tpgs == SCSI_BOTH_FAILOVER) { + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!tpgs_tape_device_probe: Detected a " + "Standard Asymmetric device " + "which supports both implicit and explicit failover\n")); + return (SFO_DEVICE_PROBE_VHCI); + } + VHCI_DEBUG(1, (CE_WARN, NULL, + "!tpgs_tape_device_probe: " + "Unknown tpgs_bits: %x", inq->inq_tpgs)); + return (SFO_DEVICE_PROBE_PHCI); +} + +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; +}
--- a/usr/src/uts/common/io/scsi/adapters/scsi_vhci/mpapi_impl.c Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/mpapi_impl.c Mon Jun 23 13:41:43 2008 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -151,7 +151,8 @@ */ extern void *vhci_softstate; extern char vhci_version_name[]; -extern int (*tpgs_set_target_groups)(struct scsi_address *, int, int); +extern int vhci_tpgs_set_target_groups(struct scsi_address *, int, int); + extern void mdi_vhci_walk_phcis(dev_info_t *, int (*)(dev_info_t *, void *), void *); @@ -1572,8 +1573,8 @@ ap = &svp->svp_psd->sd_address; ASSERT(ap != NULL); - retval = (*tpgs_set_target_groups) - (ap, desired_state, t10_tpgid); + retval = vhci_tpgs_set_target_groups(ap, desired_state, + t10_tpgid); if (retval != 0) { VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_" "state:(ALUA) FAILOVER FAILED: %x", retval));
--- a/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c Mon Jun 23 13:41:43 2008 -0700 @@ -34,6 +34,7 @@ #include <sys/sunddi.h> #include <sys/scsi/scsi.h> #include <sys/scsi/impl/scsi_reset_notify.h> +#include <sys/scsi/impl/services.h> #include <sys/sunmdi.h> #include <sys/mdi_impldefs.h> #include <sys/scsi/adapters/scsi_vhci.h> @@ -196,7 +197,7 @@ static void vhci_intr(struct scsi_pkt *); static int vhci_do_prout(scsi_vhci_priv_t *); static void vhci_run_cmd(void *); -static int vhci_do_prin(struct vhci_pkt **); +static int vhci_do_prin(struct vhci_pkt *); static struct scsi_pkt *vhci_create_retry_pkt(struct vhci_pkt *); static struct vhci_pkt *vhci_sync_retry_pkt(struct vhci_pkt *); static struct scsi_vhci_lun *vhci_lun_lookup(dev_info_t *); @@ -209,6 +210,10 @@ #ifdef DEBUG static void vhci_print_prin_keys(vhci_prin_readkeys_t *, int); #endif +static void vhci_print_cdb(dev_info_t *dip, uint_t level, + char *title, uchar_t *cdb); +static void vhci_clean_print(dev_info_t *dev, uint_t level, + char *title, uchar_t *data, int len); static void vhci_print_prout_keys(scsi_vhci_lun_t *, char *); static void vhci_uscsi_iodone(struct scsi_pkt *pkt); @@ -226,10 +231,7 @@ extern int vhci_mpapi_update_tpg_acc_state_for_lu(struct scsi_vhci *, scsi_vhci_lun_t *); -/* Special export to MP-API of tpgs non-'fops' entry point */ -int (*tpgs_set_target_groups)(struct scsi_address *, int, int); - -#define VHCI_DMA_MAX_XFER_CAP 0xffffffffULL +#define VHCI_DMA_MAX_XFER_CAP INT_MAX #define VHCI_MAX_PGR_RETRIES 3 @@ -480,23 +482,6 @@ /* register vid/pid of devices supported with mpapi */ for (dt = sf->sf_sfo->sfo_devices; *dt; dt++) vhci_mpapi_add_dev_prod(vhci, *dt); - - /* - * Special processing for SFO_NAME_TPGS module, which contains - * the `tpgs_set_target_groups` implementation needed by the - * MP-API code. - */ - if (strcmp(sf->sf_sfo->sfo_name, SFO_NAME_TPGS) == 0) { - tpgs_set_target_groups = - (int (*)(struct scsi_address *, int, int)) - ddi_modsym(sf->sf_mod, "std_set_target_groups", &e); - if (tpgs_set_target_groups == NULL) { - cmn_err(CE_WARN, "scsi_vhci: " - "unable to import 'std_set_target_groups' " - "from '%s', error %d", module[i], e); - } - } - sf++; } @@ -513,7 +498,7 @@ /* call sfo_init for modules that need it */ for (sf = scsi_failover_table; sf->sf_mod; sf++) { if (sf->sf_sfo && sf->sf_sfo->sfo_init) - (*sf->sf_sfo->sfo_init)(); + sf->sf_sfo->sfo_init(); } ddi_prop_free(module); @@ -1231,8 +1216,7 @@ * is reading PR keys which requires filtering on completion. * Data cache sync must be guaranteed. */ - if ((pkt->pkt_cdbp[0] == SCMD_PRIN) && - (pkt->pkt_cdbp[1] == 0) && + if ((pkt->pkt_cdbp[0] == SCMD_PRIN) && (pkt->pkt_cdbp[1] == 0) && (vpkt->vpkt_org_vpkt == NULL)) { vpkt->vpkt_tgt_init_pkt_flags |= PKT_CONSISTENT; } @@ -1283,8 +1267,7 @@ } } - svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private( - vpkt->vpkt_path); + svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(vpkt->vpkt_path); if (svp == NULL || reserve_failed) { if (pkt_reserve_cmd) { VHCI_DEBUG(6, (CE_WARN, vhci->vhci_dip, @@ -1305,8 +1288,7 @@ } if ((pkt->pkt_cdbp[0] == SCMD_PROUT) && (((pkt->pkt_cdbp[1] & 0x1f) == VHCI_PROUT_REGISTER) || - ((pkt->pkt_cdbp[1] & 0x1f) == - VHCI_PROUT_R_AND_IGNORE))) { + ((pkt->pkt_cdbp[1] & 0x1f) == VHCI_PROUT_R_AND_IGNORE))) { sema_v(&vlun->svl_pgr_sema); } return (TRAN_BUSY); @@ -1343,8 +1325,7 @@ mutex_exit(&vlun->svl_mutex); if ((pkt->pkt_cdbp[0] == SCMD_PROUT) && (((pkt->pkt_cdbp[1] & 0x1f) == VHCI_PROUT_REGISTER) || - ((pkt->pkt_cdbp[1] & 0x1f) == - VHCI_PROUT_R_AND_IGNORE))) { + ((pkt->pkt_cdbp[1] & 0x1f) == VHCI_PROUT_R_AND_IGNORE))) { if (rval = vhci_pgr_register_start(vlun, pkt)) { /* an error */ sema_v(&vlun->svl_pgr_sema); @@ -1404,7 +1385,7 @@ */ ASSERT(vpkt->vpkt_org_vpkt == NULL); if (tpkt->pkt_comp) { - (*tpkt->pkt_comp)(tpkt); + tpkt->pkt_comp(tpkt); } } return (rval); @@ -1544,7 +1525,7 @@ if (level == RESET_LUN) { hba = ap->a_hba_tran; ASSERT(hba != NULL); - return ((*hba->tran_reset)(ap, RESET_LUN)); + return (hba->tran_reset(ap, RESET_LUN)); } return (scsi_reset(ap, level)); } @@ -1585,7 +1566,7 @@ ASSERT(hba != NULL); if (hba->tran_reset != NULL) { - if ((*hba->tran_reset)(pap, level) == 0) { + if (hba->tran_reset(pap, level) == 0) { pdip = mdi_pi_get_phci(pip); vhci_log(CE_WARN, vdip, "!(%s%d):" " path (%s%d), reset %d failed", @@ -1722,6 +1703,10 @@ */ switch (cidx) { case SCSI_CAP_DMA_MAX: + /* + * For X86 this capability is caught in scsi_ifgetcap(). + * XXX Should this be getting the value from the pHCI? + */ rval = (int)VHCI_DMA_MAX_XFER_CAP; break; @@ -1765,6 +1750,18 @@ mutex_exit(&vlun->svl_mutex); break; + case SCSI_CAP_CDB_LEN: + rval = VHCI_SCSI_CDB_SIZE; + break; + + case SCSI_CAP_DMA_MAX_ARCH: + /* + * For X86 this capability is caught in scsi_ifgetcap(). + * XXX Should this be getting the value from the pHCI? + */ + rval = 0; + break; + default: VHCI_DEBUG(6, (CE_WARN, vhci->vhci_dip, "!vhci_getcap: unsupported %d", cidx)); @@ -2028,7 +2025,7 @@ */ static int vhci_scsi_reset_notify(struct scsi_address *ap, int flag, - void (*callback)(caddr_t), caddr_t arg) + void (*callback)(caddr_t), caddr_t arg) { struct scsi_vhci *vhci = ADDR2VHCI(ap); return (scsi_hba_reset_notify_setup(ap, flag, callback, arg, @@ -2408,8 +2405,7 @@ if (pkt == NULL || (vpkt->vpkt_flags & CFLAG_DMA_PARTIAL)) { pkt = scsi_init_pkt(address, pkt, vpkt->vpkt_tgt_init_bp, vpkt->vpkt_tgt_init_cdblen, - vpkt->vpkt_tgt_init_scblen, - 0, flags, func, NULL); + vpkt->vpkt_tgt_init_scblen, 0, flags, func, NULL); if (pkt == NULL) { VHCI_DEBUG(4, (CE_NOTE, NULL, @@ -2461,16 +2457,17 @@ struct scsi_pkt *new_pkt; struct buf *bp; - scsi_vhci_lun_t *vlun; + scsi_vhci_lun_t *vlun = svp->svp_svl; int rval, retry, nr_retry, ua_retry; struct scsi_extended_sense *sns; bp = getrbuf(KM_SLEEP); bp->b_flags = B_WRITE; bp->b_resid = 0; + bp->b_un.b_addr = (caddr_t)&vlun->svl_prout; + bp->b_bcount = vlun->svl_bcount; VHCI_INCR_PATH_CMDCOUNT(svp); - vlun = svp->svp_svl; new_pkt = scsi_init_pkt(&svp->svp_psd->sd_address, NULL, bp, CDB_GROUP1, sizeof (struct scsi_arq_status), 0, 0, @@ -2504,9 +2501,8 @@ int max_retry; struct scsi_failover_ops *fops; fops = vlun->svl_fops; - rval = (*fops->sfo_analyze_sense) - (svp->svp_psd, sns, - vlun->svl_fops_ctpriv); + rval = fops->sfo_analyze_sense(svp->svp_psd, + sns, vlun->svl_fops_ctpriv); if (rval == SCSI_SENSE_NOT_READY) { max_retry = vhci_prout_not_ready_retry; retry = nr_retry++; @@ -2604,8 +2600,7 @@ vlun->svl_cdb[1] |= VHCI_PROUT_R_AND_IGNORE; do { - nsvp = (scsi_vhci_priv_t *) - mdi_pi_get_vhci_private(npip); + nsvp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(npip); if (nsvp == NULL) { VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_run_cmd: no " @@ -2707,14 +2702,14 @@ * keys to be returned. */ static int -vhci_do_prin(struct vhci_pkt **vpkt) +vhci_do_prin(struct vhci_pkt *vpkt) { scsi_vhci_priv_t *svp = (scsi_vhci_priv_t *) - mdi_pi_get_vhci_private((*vpkt)->vpkt_path); + mdi_pi_get_vhci_private(vpkt->vpkt_path); vhci_prin_readkeys_t *prin; scsi_vhci_lun_t *vlun = svp->svp_svl; struct scsi_vhci *vhci = - ADDR2VHCI(&((*vpkt)->vpkt_tgt_pkt->pkt_address)); + ADDR2VHCI(&(vpkt->vpkt_tgt_pkt->pkt_address)); struct buf *new_bp = NULL; struct scsi_pkt *new_pkt = NULL; @@ -2725,7 +2720,7 @@ uint32_t svl_prin_length = 0; prin = (vhci_prin_readkeys_t *) - bp_mapin_common((*vpkt)->vpkt_tgt_init_bp, VM_NOSLEEP); + bp_mapin_common(vpkt->vpkt_tgt_init_bp, VM_NOSLEEP); if (prin != NULL) { prin_length = BE_32(prin->length); @@ -2763,10 +2758,10 @@ * allocated to get all of the available registered keys. */ if (rval != VHCI_CMD_ERROR) { - if (((*vpkt)->vpkt_tgt_init_bp->b_bcount - hdr_len) < + if ((vpkt->vpkt_tgt_init_bp->b_bcount - hdr_len) < prin_length) { - if ((*vpkt)->vpkt_org_vpkt == NULL) { - new_pkt = vhci_create_retry_pkt(*vpkt); + if (vpkt->vpkt_org_vpkt == NULL) { + new_pkt = vhci_create_retry_pkt(vpkt); if (new_pkt != NULL) { new_vpkt = TGTPKT2VHCIPKT(new_pkt); @@ -2778,7 +2773,7 @@ new_bp = scsi_alloc_consistent_buf( &svp->svp_psd->sd_address, NULL, (prin_length + hdr_len), - ((*vpkt)->vpkt_tgt_init_bp-> + (vpkt->vpkt_tgt_init_bp-> b_flags & (B_READ | B_WRITE)), NULL_FUNC, NULL); if (new_bp != NULL) { @@ -2820,9 +2815,9 @@ * this command is sent down. This allows the normal bind * transport mechanism to be used. */ - if ((*vpkt)->vpkt_path != NULL) { - mdi_rele_path((*vpkt)->vpkt_path); - (*vpkt)->vpkt_path = NULL; + if (vpkt->vpkt_path != NULL) { + mdi_rele_path(vpkt->vpkt_path); + vpkt->vpkt_path = NULL; } /* @@ -2902,12 +2897,12 @@ * that we put everything back the way it originally was so * that the target driver can complete the command correctly. */ - if ((*vpkt)->vpkt_org_vpkt != NULL) { - new_bp = (*vpkt)->vpkt_tgt_init_bp; + if (vpkt->vpkt_org_vpkt != NULL) { + new_bp = vpkt->vpkt_tgt_init_bp; scsi_free_consistent_buf(new_bp); - *vpkt = vhci_sync_retry_pkt(*vpkt); + vpkt = vhci_sync_retry_pkt(vpkt); /* * Make sure the original buffer is mapped into kernel @@ -2915,7 +2910,7 @@ * it. */ prin = (vhci_prin_readkeys_t *)bp_mapin_common( - (*vpkt)->vpkt_tgt_init_bp, VM_NOSLEEP); + vpkt->vpkt_tgt_init_bp, VM_NOSLEEP); } /* @@ -2923,7 +2918,7 @@ * target buffer. */ if (svl_prin_length <= - ((*vpkt)->vpkt_tgt_init_bp->b_bcount - hdr_len)) { + (vpkt->vpkt_tgt_init_bp->b_bcount - hdr_len)) { /* * It is safe to return all of the available unique * keys @@ -2935,7 +2930,7 @@ * original command. */ bcopy(&vlun->svl_prin, prin, - (*vpkt)->vpkt_tgt_init_bp->b_bcount); + vpkt->vpkt_tgt_init_bp->b_bcount); } #ifdef DEBUG VHCI_DEBUG(5, (CE_NOTE, NULL, @@ -2957,14 +2952,14 @@ * complete the command correctly. */ - if ((*vpkt)->vpkt_org_vpkt != NULL) { - new_bp = (*vpkt)->vpkt_tgt_init_bp; + if (vpkt->vpkt_org_vpkt != NULL) { + new_bp = vpkt->vpkt_tgt_init_bp; if (new_bp != NULL) { scsi_free_consistent_buf(new_bp); } - new_vpkt = *vpkt; - *vpkt = (*vpkt)->vpkt_org_vpkt; + new_vpkt = vpkt; + vpkt = vpkt->vpkt_org_vpkt; vhci_scsi_destroy_pkt(&svp->svp_psd->sd_address, new_vpkt->vpkt_tgt_pkt); @@ -2975,8 +2970,8 @@ * ssd will retry the command. */ - (*vpkt)->vpkt_tgt_pkt->pkt_reason = CMD_ABORTED; - (*vpkt)->vpkt_tgt_pkt->pkt_statistics |= STAT_ABORTED; + vpkt->vpkt_tgt_pkt->pkt_reason = CMD_ABORTED; + vpkt->vpkt_tgt_pkt->pkt_statistics |= STAT_ABORTED; rval = VHCI_CMD_CMPLT; } @@ -3096,8 +3091,8 @@ vpkt->vpkt_tgt_init_scblen); break; } - rval = (*fops->sfo_analyze_sense) - (svp->svp_psd, sns, vlun->svl_fops_ctpriv); + rval = fops->sfo_analyze_sense(svp->svp_psd, + sns, vlun->svl_fops_ctpriv); if ((rval == SCSI_SENSE_NOFAILOVER) || (rval == SCSI_SENSE_UNKNOWN) || (rval == SCSI_SENSE_NOT_READY)) { @@ -3208,8 +3203,7 @@ */ if ((pkt->pkt_cdbp[0] == SCMD_PROUT) && (((pkt->pkt_cdbp[1] & 0x1f) == VHCI_PROUT_REGISTER) || - ((pkt->pkt_cdbp[1] & 0x1f) == - VHCI_PROUT_R_AND_IGNORE))) { + ((pkt->pkt_cdbp[1] & 0x1f) == VHCI_PROUT_R_AND_IGNORE))) { if (SCBP_C(pkt) == STATUS_GOOD) { ASSERT(vlun->svl_taskq); svp->svp_last_pkt_reason = pkt->pkt_reason; @@ -3219,8 +3213,7 @@ } } if ((SCBP_C(pkt) == STATUS_GOOD) && - (pkt->pkt_cdbp[0] == SCMD_PRIN) && - vpkt->vpkt_tgt_init_bp) { + (pkt->pkt_cdbp[0] == SCMD_PRIN) && vpkt->vpkt_tgt_init_bp) { /* * If the action (value in byte 1 of the cdb) is zero, * we're reading keys, and that's the only condition @@ -3257,7 +3250,7 @@ * vpkt will contain the address of the * original vpkt */ - if (vhci_do_prin(&vpkt) == VHCI_CMD_RETRY) { + if (vhci_do_prin(vpkt) == VHCI_CMD_RETRY) { /* * The command has been resent to get * all the keys from the device. Don't @@ -3309,6 +3302,8 @@ break; case CMD_DEV_GONE: + VHCI_DEBUG(1, (CE_NOTE, NULL, "vhci_intr received " + "cmd_dev_gone\n")); tpkt->pkt_reason = CMD_CMPLT; tpkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD | @@ -3523,8 +3518,8 @@ return (0); } if (*((unsigned char *)statusp) == STATUS_CHECK) { - rval = (*(vlun->svl_fops->sfo_analyze_sense)) - (svp->svp_psd, sensep, vlun->svl_fops_ctpriv); + rval = vlun->svl_fops->sfo_analyze_sense(svp->svp_psd, sensep, + vlun->svl_fops_ctpriv); switch (rval) { /* * Only update path states in case path is definitely @@ -3654,7 +3649,7 @@ pip = npip; svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip); psd = svp->svp_psd; - if ((*fo->sfo_path_get_opinfo)(psd, &opinfo, + if (fo->sfo_path_get_opinfo(psd, &opinfo, vlun->svl_fops_ctpriv) != 0) { sps = mdi_select_path(dip, NULL, (MDI_SELECT_ONLINE_PATH | MDI_SELECT_STANDBY_PATH), @@ -4161,8 +4156,8 @@ * path-class with class */ fo = vlun->svl_fops; - (*fo->sfo_pathclass_next)(NULL, - &best_pclass, + (void) fo->sfo_pathclass_next( + NULL, &best_pclass, vlun->svl_fops_ctpriv); pclass = NULL; rv = mdi_prop_lookup_string(pip, @@ -4514,8 +4509,7 @@ struct scsi_path_opinfo opinfo; char *pclass, *best_pclass; - if ((*fo->sfo_path_get_opinfo)(psd, &opinfo, - vlun->svl_fops_ctpriv) != 0) { + if (fo->sfo_path_get_opinfo(psd, &opinfo, vlun->svl_fops_ctpriv) != 0) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_update_pathinfo: " "Failed to get operation info for path:%p\n", (void *)pip)); return (MDI_FAILURE); @@ -4647,7 +4641,7 @@ * initiate auto-failback as the next IO shall take care of. * this. See comment above. */ - (*fo->sfo_pathclass_next)(NULL, &best_pclass, + (void) fo->sfo_pathclass_next(NULL, &best_pclass, vlun->svl_fops_ctpriv); if (((vhci->vhci_conf_flags & VHCI_CONF_FLAGS_AUTO_FAILBACK) == VHCI_CONF_FLAGS_AUTO_FAILBACK) && @@ -4934,9 +4928,8 @@ /* NULL: default: select based on sfo_device_probe results */ for (sf = scsi_failover_table; sf->sf_mod; sf++) { if ((sf->sf_sfo == NULL) || - ((*sf->sf_sfo->sfo_device_probe) (psd, - psd->sd_inq, &vlun->svl_fops_ctpriv) == - SFO_DEVICE_PROBE_PHCI)) + sf->sf_sfo->sfo_device_probe(psd, psd->sd_inq, + &vlun->svl_fops_ctpriv) == SFO_DEVICE_PROBE_PHCI) continue; /* found failover module, supported under scsi_vhci */ @@ -4945,7 +4938,7 @@ i_ddi_strdup(sfo->sfo_name, KM_SLEEP); break; } - } else if (strcmp(override, "NONE") && strcmp(override, "none")) { + } else if (strcasecmp(override, "NONE")) { /* !"NONE": select based on driver.conf specified name */ for (sf = scsi_failover_table, sfo = NULL; sf->sf_mod; sf++) { if ((sf->sf_sfo == NULL) || @@ -4988,6 +4981,12 @@ vhci_get_device_type_mpxio_options(vdip, tgt_dip, psd); /* + * The device probe or options in conf file may have set/changed the + * lb policy, save the current value. + */ + vlun->svl_lb_policy_save = mdi_get_lb_policy(tgt_dip); + + /* * if PGR is active, revalidate key and register on this path also, * if key is still valid */ @@ -5695,7 +5694,7 @@ * arguments it accepts are PRIMARY and SECONDARY. */ fo = vlun->svl_fops; - if ((*fo->sfo_pathclass_next)(PCLASS_PRIMARY, &pclass, + if (fo->sfo_pathclass_next(PCLASS_PRIMARY, &pclass, vlun->svl_fops_ctpriv)) { retval = ENOTSUP; break; @@ -6717,7 +6716,7 @@ next_pathclass: - rval = (*sfo->sfo_pathclass_next)(pclass1, &pclass2, + rval = sfo->sfo_pathclass_next(pclass1, &pclass2, vlun->svl_fops_ctpriv); if (rval == ENOENT) { if (s_pclass == NULL) { @@ -6725,7 +6724,7 @@ "failed, no more pathclasses\n", guid)); goto done; } else { - (*sfo->sfo_pathclass_next)(NULL, &pclass2, + (void) sfo->sfo_pathclass_next(NULL, &pclass2, vlun->svl_fops_ctpriv); } } else if (rval == EINVAL) { @@ -6863,7 +6862,7 @@ VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_failover(6)(%s): " "activating path 0x%p(psd:%p)\n", guid, (void *)npip, (void *)svp->svp_psd)); - if ((*sfo->sfo_path_activate)(svp->svp_psd, pclass2, + if (sfo->sfo_path_activate(svp->svp_psd, pclass2, vlun->svl_fops_ctpriv) == 0) { activation_done = 1; mdi_rele_path(npip); @@ -6920,7 +6919,7 @@ "!vhci_failover(8)(%s): " "pinging path 0x%p\n", guid, (void *)npip)); - if ((*sfo->sfo_path_ping)(svp->svp_psd, + if (sfo->sfo_path_ping(svp->svp_psd, vlun->svl_fops_ctpriv) == 1) { mdi_pi_set_state(npip, MDI_PATHINFO_STATE_ONLINE); @@ -7201,6 +7200,11 @@ int retry_cnt = 0; struct scsi_extended_sense *sns; +#ifdef DEBUG + vhci_print_cdb(pkt->pkt_address.a_hba_tran->tran_hba_dip, CE_WARN, + "Vhci command", pkt->pkt_cdbp); +#endif + retry: err = scsi_poll(pkt); if (err) { @@ -7395,8 +7399,7 @@ success = 0; /* Save the res key */ - bcopy((const void *)prout->res_key, - (void *)temp_res_key, MHIOC_RESV_KEY_SIZE); + bcopy(prout->res_key, temp_res_key, MHIOC_RESV_KEY_SIZE); /* * Sometimes CDB from application can be a Register_And_Ignore. @@ -7408,8 +7411,7 @@ vlun->svl_cdb[1] &= 0xe0; do { - osvp = (scsi_vhci_priv_t *) - mdi_pi_get_vhci_private(npip); + osvp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(npip); if (osvp == NULL) { VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_pgr_validate_and_register: no " @@ -7433,8 +7435,7 @@ (void *)curthread, vlun->svl_cdb[1])); vhci_print_prout_keys(vlun, "v_pgr_val_reg: before bcopy:"); - bcopy((const void *)prout->service_key, - (void *)prout->res_key, MHIOC_RESV_KEY_SIZE); + bcopy(prout->service_key, prout->res_key, MHIOC_RESV_KEY_SIZE); VHCI_DEBUG(4, (CE_WARN, NULL, "vlun 0x%p After bcopy", (void *)vlun)); @@ -7472,8 +7473,7 @@ vlun->svl_cdb[1] = cdb_1; /* Restore the res_key */ - bcopy((const void *)temp_res_key, - (void *)prout->res_key, MHIOC_RESV_KEY_SIZE); + bcopy(temp_res_key, prout->res_key, MHIOC_RESV_KEY_SIZE); /* * If key could not be registered on any path for the first time, @@ -7495,10 +7495,9 @@ vhci_print_prout_keys(vlun, "v_pgr_val_reg: keys before bcopy: "); - bcopy((const void *)prout->active_service_key, - (void *)prout->service_key, MHIOC_RESV_KEY_SIZE); - bcopy((const void *)prout->active_res_key, - (void *)prout->res_key, MHIOC_RESV_KEY_SIZE); + bcopy(prout->active_service_key, prout->service_key, + MHIOC_RESV_KEY_SIZE); + bcopy(prout->active_res_key, prout->res_key, MHIOC_RESV_KEY_SIZE); vhci_print_prout_keys(vlun, "v_pgr_val_reg:keys after bcopy: "); @@ -7564,8 +7563,7 @@ (void *)osvp, (void *)vlun, vlun->svl_cdb[1])); vhci_print_prout_keys(vlun, "v_pgr_val_reg: before bcopy: "); - bcopy((const void *)prout->service_key, - (void *)prout->res_key, MHIOC_RESV_KEY_SIZE); + bcopy(prout->service_key, prout->res_key, MHIOC_RESV_KEY_SIZE); vhci_print_prout_keys(vlun, "v_pgr_val_reg: after bcopy: "); @@ -7616,9 +7614,8 @@ " svp 0x%p being done\n", (void *)svp)); vhci_print_prout_keys(vlun, "v_pgr_val_reg: before bcopy: "); - bcopy((const void *)prout->service_key, (void *)prout->res_key, - MHIOC_RESV_KEY_SIZE); - bzero((void *)prout->service_key, MHIOC_RESV_KEY_SIZE); + bcopy(prout->service_key, prout->res_key, MHIOC_RESV_KEY_SIZE); + bzero(prout->service_key, MHIOC_RESV_KEY_SIZE); vhci_print_prout_keys(vlun, "v_pgr_val_reg: before bcopy: "); @@ -7673,9 +7670,9 @@ static void vhci_dispatch_scsi_start(void *arg) { - struct vhci_pkt *vpkt = (struct vhci_pkt *)arg; - struct scsi_pkt *tpkt = vpkt->vpkt_tgt_pkt; - int rval = TRAN_BUSY; + struct vhci_pkt *vpkt = (struct vhci_pkt *)arg; + struct scsi_pkt *tpkt = vpkt->vpkt_tgt_pkt; + int rval = TRAN_BUSY; VHCI_DEBUG(6, (CE_NOTE, NULL, "!vhci_dispatch_scsi_start: sending" " scsi-2 reserve for 0x%p\n", @@ -7745,7 +7742,7 @@ } if (tpkt->pkt_comp) { - (*tpkt->pkt_comp)(tpkt); + tpkt->pkt_comp(tpkt); } } @@ -7777,7 +7774,7 @@ fo = vlun->svl_fops; - (*fo->sfo_pathclass_next)(NULL, &best_pclass, + (void) fo->sfo_pathclass_next(NULL, &best_pclass, vlun->svl_fops_ctpriv); if (strcmp(vlun->svl_active_pclass, best_pclass) == 0) { mutex_exit(&vlun->svl_mutex); @@ -7806,19 +7803,8 @@ static void vhci_print_prin_keys(vhci_prin_readkeys_t *prin, int numkeys) { - uchar_t index = 0; - char buf[100]; - - VHCI_DEBUG(5, (CE_NOTE, NULL, "num keys %d\n", numkeys)); - - while (index < numkeys) { - bcopy(&prin->keylist[index], buf, MHIOC_RESV_KEY_SIZE); - VHCI_DEBUG(5, (CE_NOTE, NULL, - "%02x%02x%02x%02x%02x%02x%02x%02x\t", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], - buf[7])); - index++; - } + vhci_clean_print(NULL, 5, "Current PGR Keys", + (uchar_t *)prin, numkeys * 8); } #endif @@ -8041,9 +8027,7 @@ */ pkt = vhci_scsi_init_pkt(&svp->svp_psd->sd_address, pkt, vpkt->vpkt_tgt_init_bp, vpkt->vpkt_tgt_init_cdblen, - vpkt->vpkt_tgt_init_scblen, 0, - PKT_CONSISTENT, - NULL_FUNC, NULL); + vpkt->vpkt_tgt_init_scblen, 0, PKT_CONSISTENT, NULL_FUNC, NULL); if (pkt != NULL) { new_vpkt = TGTPKT2VHCIPKT(pkt); @@ -8443,3 +8427,69 @@ "vhci_uscsi_iostart: exit: rval: %d", rval)); return (rval); } + +#ifdef DEBUG + +extern struct scsi_key_strings scsi_cmds[]; + +static char * +vhci_print_scsi_cmd(char cmd) +{ + char tmp[64]; + char *cpnt; + + cpnt = scsi_cmd_name(cmd, scsi_cmds, tmp); + /* tmp goes out of scope on return and caller sees garbage */ + if (cpnt == tmp) { + cpnt = "Unknown Command"; + } + return (cpnt); +} + +extern uchar_t scsi_cdb_size[]; + +static void +vhci_print_cdb(dev_info_t *dip, uint_t level, char *title, uchar_t *cdb) +{ + int len = scsi_cdb_size[CDB_GROUPID(cdb[0])]; + char buf[256]; + + if (level == CE_NOTE) { + vhci_log(level, dip, "path cmd %s\n", + vhci_print_scsi_cmd(*cdb)); + return; + } + + (void) sprintf(buf, "%s for cmd(%s)", title, vhci_print_scsi_cmd(*cdb)); + vhci_clean_print(dip, level, buf, cdb, len); +} + +static void +vhci_clean_print(dev_info_t *dev, uint_t level, char *title, uchar_t *data, + int len) +{ + int i; + int c; + char *format; + char buf[256]; + uchar_t byte; + + (void) sprintf(buf, "%s:\n", title); + vhci_log(level, dev, "%s", buf); + level = CE_CONT; + for (i = 0; i < len; ) { + buf[0] = 0; + for (c = 0; c < 8 && i < len; c++, i++) { + byte = (uchar_t)data[i]; + if (byte < 0x10) + format = "0x0%x "; + else + format = "0x%x "; + (void) sprintf(&buf[(int)strlen(buf)], format, byte); + } + (void) sprintf(&buf[(int)strlen(buf)], "\n"); + + vhci_log(level, dev, "%s\n", buf); + } +} +#endif
--- a/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.conf Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.conf Mon Jun 23 13:41:43 2008 -0700 @@ -57,6 +57,8 @@ "misc/scsi_vhci/scsi_vhci_f_sym_emc", "misc/scsi_vhci/scsi_vhci_f_sym_hds", "misc/scsi_vhci/scsi_vhci_f_sym", +# "misc/scsi_vhci/scsi_vhci_f_tpgs_tape", +# "misc/scsi_vhci/scsi_vhci_f_tape", "misc/scsi_vhci/scsi_vhci_f_tpgs"; #
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci_tpgs.c Mon Jun 23 13:41:43 2008 -0700 @@ -0,0 +1,579 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/scsi/scsi.h> +#include <sys/scsi/adapters/scsi_vhci.h> +#include <sys/scsi/adapters/scsi_vhci_tpgs.h> + +/* + * External function definitions + */ +extern void vhci_mpapi_update_tpg_data(struct scsi_address *, char *); + + + +static int vhci_tpgs_inquiry(struct scsi_address *ap, struct buf *bp, + int *mode); +static int vhci_tpgs_page83(struct scsi_address *ap, struct buf *bp, + int *rel_tgt_port, int *tgt_port, int *lu); +static void print_buf(char *buf, int buf_size); +static int vhci_tpgs_report_target_groups(struct scsi_address *ap, + struct buf *bp, int rel_tgt_port, int tgt_port, int *pstate, + int *preferred); + +int +vhci_tpgs_set_target_groups(struct scsi_address *ap, int set_state, + int tpg_id) +{ + struct scsi_pkt *pkt; + struct buf *bp; + int len, rval, ss = SCSI_SENSE_UNKNOWN; + char *bufp; + struct scsi_extended_sense *sns; + + len = 8; + + bp = getrbuf(KM_NOSLEEP); + if (bp == NULL) { + VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_set_target_groups: " + " failed getrbuf")); + return (1); + } + + bufp = kmem_zalloc(len, KM_NOSLEEP); + if (bufp == NULL) { + VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_set_target_groups: " + "request packet allocation for %d failed....", len)); + freerbuf(bp); + return (1); + } + + bp->b_un.b_addr = bufp; + bp->b_flags = B_READ; + bp->b_bcount = len; + bp->b_resid = 0; + + bufp[4] = (0x0f & set_state); + bufp[6] = (0xff00 & tpg_id) >> 8; + bufp[7] = (0x00ff & tpg_id); + + pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP5, + sizeof (struct scsi_arq_status), 0, 0, NULL, NULL); + + if (pkt == NULL) { + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!vhci_tpgs_set_target_groups: scsi_init_pkt error\n")); + freerbuf(bp); + kmem_free((void *)bufp, len); + return (1); + } + + /* + * Sends 1 TPG descriptor only. Hence Parameter list length pkt_cdbp[9] + * is set to 8 bytes - Refer SPC3 for details. + */ + pkt->pkt_cdbp[0] = SCMD_MAINTENANCE_OUT; + pkt->pkt_cdbp[1] = SSVC_ACTION_SET_TARGET_PORT_GROUPS; + pkt->pkt_cdbp[9] = 8; + pkt->pkt_time = 90; + + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!vhci_tpgs_set_target_groups: sending set target port group:" + " cdb[0/1/6/7/8/9]: %x/%x/%x/%x/%x/%x\n", pkt->pkt_cdbp[0], + pkt->pkt_cdbp[1], pkt->pkt_cdbp[6], pkt->pkt_cdbp[7], + pkt->pkt_cdbp[8], pkt->pkt_cdbp[9])); + +#ifdef DEBUG + print_buf(bufp, len); +#endif + rval = vhci_do_scsi_cmd(pkt); + + if (rval == 0) { + VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_set_target_groups:" + " vhci_do_scsi_cmd failed\n")); + freerbuf(bp); + kmem_free((void *)bufp, len); + scsi_destroy_pkt(pkt); + return (-1); + } else if ((pkt->pkt_reason == CMD_CMPLT) && + (SCBP_C(pkt) == STATUS_CHECK) && + (pkt->pkt_state & STATE_ARQ_DONE)) { + sns = &(((struct scsi_arq_status *)(uintptr_t) + (pkt->pkt_scbp))->sts_sensedata); + + if ((sns->es_key == KEY_UNIT_ATTENTION) && + (sns->es_add_code == STD_SCSI_ASC_STATE_CHG) && + (sns->es_qual_code == STD_SCSI_ASCQ_STATE_CHG_SUCC)) { + ss = SCSI_SENSE_STATE_CHANGED; + VHCI_DEBUG(4, (CE_NOTE, NULL, + "!vhci_tpgs_set_target_groups:" + " sense:%x, add_code: %x, qual_code:%x" + " sense:%x\n", sns->es_key, sns->es_add_code, + sns->es_qual_code, ss)); + } else if ((sns->es_key == KEY_ILLEGAL_REQUEST) && + (sns->es_add_code == STD_SCSI_ASC_INVAL_PARAM_LIST)) { + ss = SCSI_SENSE_NOFAILOVER; + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!vhci_tpgs_set_target_groups:" + " sense:%x, add_code: %x, qual_code:%x" + " sense:%x\n", sns->es_key, sns->es_add_code, + sns->es_qual_code, ss)); + } else if ((sns->es_key == KEY_ILLEGAL_REQUEST) && + (sns->es_add_code == STD_SCSI_ASC_INVAL_CMD_OPCODE)) { + ss = SCSI_SENSE_NOFAILOVER; + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!vhci_tpgs_set_target_groups:" + " sense_key:%x, add_code: %x, qual_code:%x" + " sense:%x\n", sns->es_key, sns->es_add_code, + sns->es_qual_code, rval)); + } else { + /* + * At this point sns data may be for power-on-reset + * UNIT ATTN hardware errors, vendor unqiue sense etc. + * For all these cases, sense is unknown. + */ + ss = SCSI_SENSE_NOFAILOVER; + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!vhci_tpgs_set_target_groups: " + " sense UNKNOWN: sense key:%x, ASC:%x, ASCQ:%x\n", + sns->es_key, sns->es_add_code, sns->es_qual_code)); + } + + if (ss == SCSI_SENSE_STATE_CHANGED) { + freerbuf(bp); + kmem_free((void *)bufp, len); + scsi_destroy_pkt(pkt); + return (0); + } + } + + freerbuf(bp); + kmem_free((void *)bufp, len); + scsi_destroy_pkt(pkt); + return (1); +} + +/* + * get the failover mode, ownership and if it has extended failover + * capability. The mode(bits5-4/byte5) is defined as implicit, explicit, or + * both. The state is defined as online-optimized(0h), + * online-nonoptimized(1h), standby(2h), offline(3h), + * and transitioning(fh). Currently, there is online, + * standby, and offline(defined in sunmdi.h). + * Online-nonoptimized will be a mode of secondary + * and an ownership of online. Thought about using a different mode but + * it appears the states are really for the states for secondary mode. + * We currently have IS_ONLINING, IS_OFFLINING - should we have TRANSITIONING + * to mean from online-optimized to online-nonoptimized or does onlining + * cover this? + */ +/* ARGSUSED */ +int +vhci_tpgs_get_target_fo_mode(struct scsi_device *sd, int *mode, + int *state, int *xlf_capable, int *preferred) +{ + int retval = 0; + struct buf *bp; + struct scsi_address *ap; + int lu = 0, rel_tgt_port = 0, tgt_port = 0x0; + + VHCI_DEBUG(6, (CE_NOTE, NULL, + "!vhci_tpgs_get_target_fo_mode: enter\n")); + *mode = *state = *xlf_capable = 0; + bp = getrbuf(KM_NOSLEEP); + if (bp == NULL) { + VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_get_target_fo_mode: " + " failed getrbuf\n")); + return (1); + } + + ap = &sd->sd_address; + if (vhci_tpgs_inquiry(ap, bp, mode)) { + VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_get_target_fo_mode: " + " failed vhci_tpgs_inquiry\n")); + retval = 1; + } else if (vhci_tpgs_page83(ap, bp, &rel_tgt_port, &tgt_port, &lu)) { + VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_get_target_fo_mode: " + " failed vhci_tpgs_page83\n")); + retval = 1; + } else if (vhci_tpgs_report_target_groups(ap, bp, rel_tgt_port, + tgt_port, state, preferred)) { + VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_get_target_fo_mode: " + " failed vhci_tpgs_report_target_groups\n")); + retval = 1; + } + + freerbuf(bp); + if (retval == 0) { + VHCI_DEBUG(6, (CE_NOTE, NULL, "!vhci_tpgs_get_target_fo_mode: " + "SUCCESS\n")); + } + return (retval); +} + +static int +vhci_tpgs_inquiry(struct scsi_address *ap, struct buf *bp, int *mode) +{ + struct scsi_pkt *pkt; + struct scsi_inquiry inq; + int retval; + + *mode = 0; + bp->b_un.b_addr = (caddr_t)&inq; + bp->b_flags = B_READ; + bp->b_bcount = sizeof (inq); + bp->b_resid = 0; + + pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP0, + sizeof (struct scsi_arq_status), 0, 0, SLEEP_FUNC, NULL); + pkt->pkt_cdbp[0] = SCMD_INQUIRY; + pkt->pkt_cdbp[4] = sizeof (inq); + pkt->pkt_time = 60; + + retval = vhci_do_scsi_cmd(pkt); + scsi_destroy_pkt(pkt); + if (retval == 0) { + VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_inquiry: Failure" + " returned from vhci_do_scsi_cmd")); + return (1); + } + + if (inq.inq_tpgs == 0) { + VHCI_DEBUG(1, (CE_WARN, NULL, + "!vhci_tpgs_inquiry: zero tpgs_bits")); + return (1); + } + retval = 0; + if (inq.inq_tpgs == SCSI_IMPLICIT_FAILOVER) { + *mode = SCSI_IMPLICIT_FAILOVER; + } else if (inq.inq_tpgs == SCSI_EXPLICIT_FAILOVER) { + *mode = SCSI_EXPLICIT_FAILOVER; + } else if (inq.inq_tpgs == SCSI_BOTH_FAILOVER) { + *mode = SCSI_BOTH_FAILOVER; + } else { + VHCI_DEBUG(1, (CE_WARN, NULL, + "!vhci_tpgs_inquiry: Illegal mode returned: %x mode: %x", + inq.inq_tpgs, *mode)); + retval = 1; + } + + return (retval); +} + +static int +vhci_tpgs_page83(struct scsi_address *ap, struct buf *bp, + int *rel_tgt_port, int *tgt_port, int *lu) +{ + char *ptr, *end; + struct scsi_pkt *pkt; + char *bufp; + unsigned int buf_len, rx_bsize; + + /* + * lets start the buf size with 512 bytes. If this + * if found to be insufficient, we can allocate + * appropriate size in the next iteration. + */ + buf_len = 512; + +once_again: + bufp = kmem_zalloc(buf_len, KM_NOSLEEP); + if (bufp == NULL) { + VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_page83: " + "request packet allocation for %d failed....", + buf_len)); + return (1); + } + + + bp->b_un.b_addr = bufp; + bp->b_flags = B_READ; + bp->b_bcount = buf_len; + bp->b_resid = 0; + + pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP0, + sizeof (struct scsi_arq_status), 0, 0, NULL, NULL); + if (pkt == NULL) { + VHCI_DEBUG(1, (CE_WARN, NULL, + "!vhci_tpgs_page83: Failure returned from scsi_init_pkt")); + kmem_free((void *)bufp, buf_len); + return (1); + } + + pkt->pkt_cdbp[0] = SCMD_INQUIRY; + pkt->pkt_cdbp[1] = 0x1; + pkt->pkt_cdbp[2] = 0x83; + pkt->pkt_cdbp[3] = (unsigned char)((buf_len >> 8) & 0xff); + pkt->pkt_cdbp[4] = (unsigned char)(buf_len & 0xff); + pkt->pkt_time = 90; + + if (vhci_do_scsi_cmd(pkt) == 0) { + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!vhci_tpgs_page83: vhci_do_scsi_cmd failed\n")); + kmem_free((void *)bufp, buf_len); + scsi_destroy_pkt(pkt); + return (1); + } + + /* + * Now lets check if the size that was provided was + * sufficient. If not, allocate the appropriate size + * and retry the command again. + */ + rx_bsize = (((bufp[2] & 0xff) << 8) | (bufp[3] & 0xff)); + rx_bsize += 4; + if (rx_bsize > buf_len) { + /* + * Need to allocate more buf and retry again + */ + VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_page83: " + "bufsize: %d greater than allocated buf: %d\n", + rx_bsize, buf_len)); + VHCI_DEBUG(1, (CE_NOTE, NULL, "Retrying for size %d\n", + rx_bsize)); + kmem_free((void *)bufp, buf_len); + buf_len = (unsigned int)(rx_bsize); + goto once_again; + } + + ptr = bufp; + ptr += 4; /* identification descriptor 0 */ + end = bufp + rx_bsize; + while (ptr < end) { + VHCI_DEBUG(1, (CE_NOTE, NULL, "vhci_tpgs_page83: " + "desc[1/4/5/6/7]:%x %x %x %x %x\n", + ptr[1], ptr[4], ptr[5], ptr[6], ptr[7])); + if ((ptr[1] & 0x0f) == 0x04) { + *rel_tgt_port = 0; + *rel_tgt_port |= ((ptr[6] & 0xff) << 8); + *rel_tgt_port |= (ptr[7] & 0xff); + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!vhci_tpgs_page83: relative target port: %x\n", + *rel_tgt_port)); + } else if ((ptr[1] & 0x0f) == 0x05) { + *tgt_port = 0; + *tgt_port = ((ptr[6] & 0xff) << 8); + *tgt_port |= (ptr[7] & 0xff); + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!vhci_tpgs_page83: target port: %x\n", *tgt_port)); + } else if ((ptr[1] & 0x0f) == 0x06) { + *lu = 0; + *lu |= ((ptr[6] & 0xff)<< 8); + *lu |= (ptr[7] & 0xff); + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!vhci_tpgs_page83: logical unit: %x\n", *lu)); + } + ptr += ptr[3] + 4; /* next identification descriptor */ + } + kmem_free((void *)bufp, buf_len); + scsi_destroy_pkt(pkt); + return (0); +} + +#ifdef DEBUG +static void +print_buf(char *buf, int buf_size) +{ + int i = 0, j; + int loop, left; + + loop = buf_size / 8; + left = buf_size % 8; + + VHCI_DEBUG(4, (CE_NOTE, NULL, "!buf_size: %x loop: %x left: %x", + buf_size, loop, left)); + + for (j = 0; j < loop; j++) { + VHCI_DEBUG(4, (CE_NOTE, NULL, + "!buf[%d-%d]: %x %x %x %x %x %x %x %x", + i, i + 7, buf[i], buf[i+1], buf[i+2], buf[i+3], + buf[i+4], buf[i+5], buf[i+6], buf[i+7])); + i += 8; + } + + if (left) { + VHCI_DEBUG(4, (CE_CONT, NULL, + "NOTICE: buf[%d-%d]:", i, i + left)); + for (j = 0; j < left; j++) { + VHCI_DEBUG(4, (CE_CONT, NULL, " %x", buf[i + j])); + } + VHCI_DEBUG(4, (CE_CONT, NULL, "\n")); + } +} +#endif + +static int +vhci_tpgs_report_target_groups(struct scsi_address *ap, struct buf *bp, + int rel_tgt_port, int tgt_port, int *pstate, int *preferred) +{ + struct scsi_pkt *pkt; + char *ptr, *end, *bufp, *mpapi_ptr; + unsigned int rtpg_len = 0; + unsigned int l_tgt_port = 0, tpgs_state = 0; + unsigned int tgt_port_cnt = 0, lr_tgt_port = 0; + int i, len; + + /* + * Start with buffer size of 512. + * If this is found to be insufficient, required size + * will be allocated and the command will be retried. + */ + len = 512; + +try_again: + bufp = kmem_zalloc(len, KM_NOSLEEP); + if (bufp == NULL) { + VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_report_target_groups:" + " request packet allocation for %d failed....", len)); + return (1); + } + + bp->b_un.b_addr = bufp; + bp->b_flags = B_READ; + bp->b_bcount = len; + bp->b_resid = 0; + + pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP5, + sizeof (struct scsi_arq_status), 0, 0, NULL, NULL); + + if (pkt == NULL) { + VHCI_DEBUG(1, (CE_NOTE, NULL, + "!vhci_tpgs_report_target_groups: scsi_init_pkt error\n")); + kmem_free((void *)bufp, len); + return (1); + } + + pkt->pkt_cdbp[0] = SCMD_MAINTENANCE_IN; + pkt->pkt_cdbp[1] = SSVC_ACTION_GET_TARGET_PORT_GROUPS; + pkt->pkt_cdbp[6] = ((len >> 24) & 0xff); + pkt->pkt_cdbp[7] = ((len >> 16) & 0xff); + pkt->pkt_cdbp[8] = ((len >> 8) & 0xff); + pkt->pkt_cdbp[9] = len & 0xff; + pkt->pkt_time = 90; + + VHCI_DEBUG(6, (CE_NOTE, NULL, + "!vhci_tpgs_report_target_groups: sending target port group:" + " cdb[6/7/8/9]: %x/%x/%x/%x\n", pkt->pkt_cdbp[6], + pkt->pkt_cdbp[7], pkt->pkt_cdbp[8], pkt->pkt_cdbp[9])); + if (vhci_do_scsi_cmd(pkt) == 0) { + VHCI_DEBUG(4, (CE_NOTE, NULL, "!vhci_tpgs_report_target_groups:" + " vhci_do_scsi_cmd failed\n")); + kmem_free((void *)bufp, len); + scsi_destroy_pkt(pkt); + return (1); + } + ptr = bufp; + VHCI_DEBUG(6, (CE_NOTE, NULL, "!vhci_tpgs_report_target_groups:" + " returned from target" + " port group: buf[0/1/2/3]: %x/%x/%x/%x\n", + ptr[0], ptr[1], ptr[2], ptr[3])); + rtpg_len = (unsigned int)((0xff & ptr[0]) << 24); + rtpg_len |= (unsigned int)((0xff & ptr[1]) << 16); + rtpg_len |= (unsigned int)((0xff & ptr[2]) << 8); + rtpg_len |= (unsigned int)(0xff & ptr[3]); + rtpg_len += 4; + if (rtpg_len > len) { + VHCI_DEBUG(4, (CE_NOTE, NULL, "!vhci_tpgs_report_target_groups:" + " bufsize: %d greater than allocated buf: %d\n", + rtpg_len, len)); + VHCI_DEBUG(4, (CE_NOTE, NULL, "Retrying for size %d\n", + rtpg_len)); + kmem_free((void *)bufp, len); + len = (unsigned int)(rtpg_len + 1); + goto try_again; + } +#ifdef DEBUG + print_buf(bufp, rtpg_len); +#endif + end = ptr + rtpg_len; + ptr += 4; + while (ptr < end) { + mpapi_ptr = ptr; + l_tgt_port = ((ptr[2] & 0xff) << 8) + (ptr[3] & 0xff); + tpgs_state = ptr[0] & 0x0f; + tgt_port_cnt = (ptr[7] & 0xff); + VHCI_DEBUG(4, (CE_NOTE, NULL, "!vhci_tpgs_report_tgt_groups:" + " tpgs state: %x" + " tgt_group: %x count: %x\n", tpgs_state, + l_tgt_port, tgt_port_cnt)); + ptr += 8; + for (i = 0; i < tgt_port_cnt; i++) { + lr_tgt_port = 0; + lr_tgt_port |= ((ptr[2] & 0Xff) << 8); + lr_tgt_port |= (ptr[3] & 0xff); + + if ((lr_tgt_port == rel_tgt_port) && + (l_tgt_port == tgt_port)) { + VHCI_DEBUG(4, (CE_NOTE, NULL, + "!vhci_tpgs_report_tgt_groups:" + " found tgt_port: %x rel_tgt_port:%x" + " tpgs_state: %x\n", tgt_port, rel_tgt_port, + tpgs_state)); + /* + * once we have the preferred flag + * and a non-optimized state flag + * we will get preferred flag from the + * report target groups + */ + if (tpgs_state == STD_ACTIVE_OPTIMIZED) { + *pstate = STD_ACTIVE_OPTIMIZED; + *preferred = PCLASS_PREFERRED; + } else if (tpgs_state == + STD_ACTIVE_NONOPTIMIZED) { + *pstate = STD_ACTIVE_NONOPTIMIZED; + *preferred = PCLASS_NONPREFERRED; + } else if (tpgs_state == STD_STANDBY) { + *pstate = STD_STANDBY; + *preferred = PCLASS_NONPREFERRED; + } else { + *pstate = STD_UNAVAILABLE; + *preferred = PCLASS_NONPREFERRED; + } + vhci_mpapi_update_tpg_data(ap, mpapi_ptr); + kmem_free((void *)bufp, len); + scsi_destroy_pkt(pkt); + return (0); + } + VHCI_DEBUG(4, (CE_NOTE, NULL, + "!vhci_tpgs_report_tgt_groups:" + " tgt_port: %x rel_tgt_port:%x\n", tgt_port, + rel_tgt_port)); + ptr += 4; + } + } + *pstate = SCSI_PATH_INACTIVE; + *preferred = PCLASS_NONPREFERRED; + VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_report_tgt_groups: " + "NO rel_TGTPRT MATCH!!! Assigning Default: state: %x " + "preferred: %d\n", *pstate, *preferred)); + kmem_free((void *)bufp, len); + scsi_destroy_pkt(pkt); + return (1); +}
--- a/usr/src/uts/common/io/scsi/targets/st.c Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/io/scsi/targets/st.c Mon Jun 23 13:41:43 2008 -0700 @@ -111,6 +111,14 @@ #define ONE_K 1024 +#define MAX_SPACE_CNT(cnt) if (cnt >= 0) { \ + if (cnt > MIN(SP_CNT_MASK, INT32_MAX)) \ + return (EINVAL); \ + } else { \ + if (-(cnt) > MIN(SP_CNT_MASK, INT32_MAX)) \ + return (EINVAL); \ + } \ + /* * Global External Data Definitions */ @@ -122,8 +130,11 @@ */ static void *st_state; static char *const st_label = "st"; -static volatile dev_info_t *st_lastdev; static volatile int st_recov_sz = sizeof (recov_info); +static const char mp_misconf[] = { + "St Tape is misconfigured, MPxIO enabled and " + "tape-command-recovery-disable set in st.conf\n" +}; #ifdef __x86 /* @@ -241,6 +252,8 @@ #ifdef STDEBUG static int st_soft_error_report_debug = 0; volatile int st_debug = 0; +static volatile dev_info_t *st_lastdev; +static kmutex_t st_debug_mutex; #endif #define ST_MT02_NAME "Emulex MT02 QIC-11/24 " @@ -317,6 +330,23 @@ "load and hold" /* LD_LOAD | LD_HOLD 9 */ }; +static const char *errstatenames[] = { + "COMMAND_DONE", + "COMMAND_DONE_ERROR", + "COMMAND_DONE_ERROR_RECOVERED", + "QUE_COMMAND", + "QUE_BUSY_COMMAND", + "QUE_SENSE", + "JUST_RETURN", + "COMMAND_DONE_EACCES", + "QUE_LAST_COMMAND", + "COMMAND_TIMEOUT", + "PATH_FAILED", + "DEVICE_RESET", + "DEVICE_TAMPER", + "ATTEMPT_RETRY" +}; + const char *bogusID = "Unknown Media ID"; /* default density offsets in the table above */ @@ -523,7 +553,7 @@ struct scsi_arq_status *cmd); static void st_empty_error_stack(struct scsi_tape *un); static errstate st_decode_sense(struct scsi_tape *un, struct buf *bp, int amt, - struct scsi_status *, tapepos_t *); + struct scsi_arq_status *, tapepos_t *); static int st_report_soft_errors(dev_t dev, int flag); static void st_delayed_cv_broadcast(void *arg); static int st_check_media(dev_t dev, enum mtio_state state); @@ -556,7 +586,7 @@ static int st_check_cdb_for_need_to_reserve(struct scsi_tape *un, uchar_t *cdb); static int st_check_cmd_for_need_to_reserve(struct scsi_tape *un, uchar_t cmd, int count); -static int st_take_ownership(struct scsi_tape *un); +static int st_take_ownership(struct scsi_tape *un, ubufunc_t ubf); static int st_check_asc_ascq(struct scsi_tape *un); static int st_check_clean_bit(struct scsi_tape *un); static int st_check_alert_flags(struct scsi_tape *un); @@ -576,20 +606,20 @@ static int st_get_read_pos(struct scsi_tape *un, buf_t *bp); static int st_logical_block_locate(struct scsi_tape *un, ubufunc_t ubf, tapepos_t *pos, uint64_t lblk, uchar_t partition); -static int st_mtfsf_ioctl(struct scsi_tape *un, int files); -static int st_mtfsr_ioctl(struct scsi_tape *un, int count); -static int st_mtbsf_ioctl(struct scsi_tape *un, int files); -static int st_mtnbsf_ioctl(struct scsi_tape *un, int count); -static int st_mtbsr_ioctl(struct scsi_tape *un, int num); -static int st_mtfsfm_ioctl(struct scsi_tape *un, int cnt); -static int st_mtbsfm_ioctl(struct scsi_tape *un, int cnt); -static int st_backward_space_files(struct scsi_tape *un, int count, +static int st_mtfsf_ioctl(struct scsi_tape *un, int64_t files); +static int st_mtfsr_ioctl(struct scsi_tape *un, int64_t count); +static int st_mtbsf_ioctl(struct scsi_tape *un, int64_t files); +static int st_mtnbsf_ioctl(struct scsi_tape *un, int64_t count); +static int st_mtbsr_ioctl(struct scsi_tape *un, int64_t num); +static int st_mtfsfm_ioctl(struct scsi_tape *un, int64_t cnt); +static int st_mtbsfm_ioctl(struct scsi_tape *un, int64_t cnt); +static int st_backward_space_files(struct scsi_tape *un, int64_t count, int infront); -static int st_forward_space_files(struct scsi_tape *un, int files); +static int st_forward_space_files(struct scsi_tape *un, int64_t files); static int st_scenic_route_to_begining_of_file(struct scsi_tape *un, int32_t fileno); static int st_space_to_begining_of_file(struct scsi_tape *un); -static int st_space_records(struct scsi_tape *un, int records); +static int st_space_records(struct scsi_tape *un, int64_t records); static int st_get_media_identification(struct scsi_tape *un, ubufunc_t bufunc); static errstate st_command_recovery(struct scsi_tape *un, struct scsi_pkt *pkt, errstate onentry); @@ -639,13 +669,14 @@ #ifdef STDEBUG static void st_debug_cmds(struct scsi_tape *un, int com, int count, int wait); +#endif /* STDEBUG */ static char *st_dev_name(dev_t dev); -#endif /* STDEBUG */ #if !defined(lint) _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt buf uio scsi_cdb uscsi_cmd)) _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_extended_sense scsi_status)) +_NOTE(SCHEME_PROTECTS_DATA("unique per pkt", recov_info)) _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device)) _NOTE(DATA_READABLE_WITHOUT_LOCK(st_drivetype scsi_address)) #endif @@ -705,20 +736,24 @@ if ((e = mod_install(&modlinkage)) != 0) { ddi_soft_state_fini(&st_state); - } + } else { +#ifdef STDEBUG + mutex_init(&st_debug_mutex, NULL, MUTEX_DRIVER, NULL); +#endif #if defined(__x86) - /* set the max physical address for iob allocs on x86 */ - st_alloc_attr.dma_attr_addr_hi = st_max_phys_addr; - - /* - * set the sgllen for iob allocs on x86. If this is set less than - * the number of pages the buffer will take (taking into account - * alignment), it would force the allocator to try and allocate - * contiguous pages. - */ - st_alloc_attr.dma_attr_sgllen = st_sgl_size; + /* set the max physical address for iob allocs on x86 */ + st_alloc_attr.dma_attr_addr_hi = st_max_phys_addr; + + /* + * set the sgllen for iob allocs on x86. If this is set less + * than the number of pages the buffer will take + * (taking into account alignment), it would force the + * allocator to try and allocate contiguous pages. + */ + st_alloc_attr.dma_attr_sgllen = st_sgl_size; #endif + } return (e); } @@ -732,6 +767,10 @@ return (e); } +#ifdef STDEBUG + mutex_destroy(&st_debug_mutex); +#endif + ddi_soft_state_fini(&st_state); return (e); @@ -1055,6 +1094,12 @@ un->un_max_cdb_sz = CDB_GROUP4; /* optimistic default */ } + if (strcmp(ddi_driver_name(ddi_get_parent(ST_DEVINFO)), "scsi_vhci")) { + un->un_multipath = 0; + } else { + un->un_multipath = 1; + } + un->un_maxbsize = MAXBSIZE_UNKNOWN; un->un_mediastate = MTIO_NONE; @@ -1169,7 +1214,8 @@ static int st_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) { - int instance; + int instance; + int result; struct scsi_device *devp; struct scsi_tape *un; clock_t wait_cmds_complete; @@ -1207,6 +1253,7 @@ (void *)un); if (((un->un_dp->options & ST_UNLOADABLE) == 0) || + ((un->un_rsvd_status & ST_APPLICATION_RESERVATIONS) != 0) || (un->un_ncmds != 0) || (un->un_quef != NULL) || (un->un_state != ST_STATE_CLOSED)) { /* @@ -1216,6 +1263,7 @@ */ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG, "cannot unload instance %x\n", instance); + un->un_unit_attention_flags |= 4; return (DDI_FAILURE); } @@ -1243,7 +1291,7 @@ * to fail the detach till a user command fails * where after the detach will succead. */ - (void) st_cmd(un, SCMD_TEST_UNIT_READY, 0, SYNC_CMD); + result = st_cmd(un, SCMD_TEST_UNIT_READY, 0, SYNC_CMD); /* * After TUR un_state may be set to non-closed, * so reset it back. @@ -1260,6 +1308,7 @@ * if we are not at BOT then it is not safe to unload */ if ((un->un_dev) && /* Been opened since attach */ + (result != EACCES) && /* drive is use by somebody */ (((un->un_pos.pmode == legacy) && (un->un_pos.fileno > 0) || /* Known position not rewound */ (un->un_pos.blkno != 0)) || /* Or within first file */ @@ -1271,6 +1320,7 @@ " lgclblkno=0x%"PRIx64"\n", un->un_pos.pmode, un->un_pos.fileno, un->un_pos.blkno, un->un_pos.lgclblkno); + un->un_unit_attention_flags |= 4; return (DDI_FAILURE); } @@ -1684,6 +1734,8 @@ un->un_suspend_pos.pmode = invalid; + st_add_recovery_info_to_pkt(un, un->un_rqs_bp, un->un_rqs); + #ifdef __x86 if (ddi_dma_alloc_handle(ST_DEVINFO, &st_contig_mem_dma_attr, DDI_DMA_SLEEP, NULL, &un->un_contig_mem_hdl) != DDI_SUCCESS) { @@ -1863,7 +1915,7 @@ (void) st_reserve_release(un, reserved, st_uscsi_cmd); } - un->un_unit_attention_flags = 1; + un->un_unit_attention_flags |= 1; scsi_log(ST_DEVINFO, st_label, CE_NOTE, "?<%s>\n", dp->name); @@ -2715,11 +2767,9 @@ */ mutex_enter(ST_MUTEX); -#ifdef STDEBUG ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG, "st_open(node = %s dev = 0x%lx, flag = %d, otyp = %d)\n", st_dev_name(dev), *dev_p, flag, otyp); -#endif /* * All device accesss go thru st_strategy() where we check @@ -2856,7 +2906,6 @@ } un->un_err_resid = 0; un->un_retry_ct = 0; - un->un_tran_retry_ct = 0; } busy: ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG, @@ -3349,6 +3398,8 @@ */ if (((minor & (MT_BSD | MT_NOREWIND)) == MT_NOREWIND) && (flag & FREAD) && /* reading or at least asked to */ + (un->un_mediastate == MTIO_INSERTED) && /* tape loaded */ + (un->un_pos.pmode != invalid) && /* XXX position known */ ((un->un_pos.blkno != 0) && /* inside a file */ (un->un_lastop != ST_OP_WRITE) && /* Didn't just write */ (un->un_lastop != ST_OP_WEOF))) { /* or write filemarks */ @@ -3369,7 +3420,7 @@ SCSI_DEBUG, "st_close : EIO can't space\n"); err = EIO; - break; + goto error_out; } if (un->un_pos.eof >= ST_EOF_PENDING) { un->un_pos.eof = ST_EOT_PENDING; @@ -3382,6 +3433,7 @@ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG, "st_close: EIO can't space #2\n"); err = EIO; + goto error_out; } else { ST_DEBUG6(ST_DEVINFO, st_label, SCSI_DEBUG, "st_close2: fileno=%x,blkno=%x,eof=%x\n", @@ -3401,10 +3453,11 @@ case ST_EOT: case ST_EOT_PENDING: + case ST_EOM: /* nothing to do */ break; default: - scsi_log(ST_DEVINFO, st_label, CE_PANIC, + ST_DEBUG(ST_DEVINFO, st_label, CE_PANIC, "Undefined state 0x%x", un->un_pos.eof); } @@ -3441,6 +3494,7 @@ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG, "st_close: EIO can't space #3\n"); err = EIO; + goto error_out; } else { un->un_pos.blkno = 0; un->un_pos.eof = ST_EOT; @@ -3483,6 +3537,7 @@ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG, "st_close : EIO can't wfm\n"); err = EIO; + goto error_out; } if ((un->un_dp->options & ST_REEL) && (minor & MT_NOREWIND)) { @@ -3491,6 +3546,7 @@ SCSI_DEBUG, "st_close : EIO space fmk(-1)\n"); err = EIO; + goto error_out; } un->un_pos.eof = ST_NO_EOF; /* fix up block number */ @@ -3519,7 +3575,10 @@ if (st_report_soft_errors_on_close && (un->un_dp->options & ST_SOFT_ERROR_REPORTING) && (last_state != ST_STATE_OFFLINE)) { - (void) st_report_soft_errors(dev, flag); + if (st_report_soft_errors(dev, flag)) { + err = EIO; + goto error_out; + } } @@ -3559,11 +3618,32 @@ * the problems described above. */ if (un->un_sd->sd_inq->inq_ansi < 2) { - (void) st_cmd(un, SCMD_REWIND, 0, SYNC_CMD); + if (st_cmd(un, SCMD_REWIND, 0, SYNC_CMD)) { + err = EIO; + } } else { /* flush data for older drives per scsi spec. */ - (void) st_cmd(un, SCMD_WRITE_FILE_MARK, 0, SYNC_CMD); - (void) st_cmd(un, SCMD_REWIND, 1, ASYNC_CMD); + if (st_cmd(un, SCMD_WRITE_FILE_MARK, 0, SYNC_CMD)) { + err = EIO; + } else if (st_cmd(un, SCMD_REWIND, 1, ASYNC_CMD)) { + err = EIO; + } + } + /* + * Setting positions invalid in case the rewind doesn't + * happen. Drives don't like to rewind if resets happen + * they will tend to move back to where the rewind was + * issued if a reset or something happens so that if a + * write happens the data doesn't get clobbered. + * + * Not a big deal if the position is invalid when the + * open occures it will do a read position. + */ + un->un_pos.pmode = invalid; + un->un_running.pmode = invalid; + + if (err == EIO) { + goto error_out; } } @@ -3575,6 +3655,8 @@ if (st_cmd(un, SCMD_LOAD, LD_UNLOAD, SYNC_CMD)) { ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG, "st_close : can't unload tape\n"); + err = EIO; + goto error_out; } else { ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG, "st_close : tape unloaded \n"); @@ -3590,7 +3672,7 @@ (ST_RESERVE | ST_PRESERVE_RESERVE)) == ST_RESERVE) { (void) st_reserve_release(un, ST_RELEASE, st_uscsi_cmd); } - +error_out: /* * clear up state */ @@ -3599,7 +3681,6 @@ un->un_lastop = ST_OP_NIL; un->un_throttle = 1; /* assume one request at time, for now */ un->un_retry_ct = 0; - un->un_tran_retry_ct = 0; un->un_errno = 0; un->un_swr_token = (opaque_t)NULL; un->un_rsvd_status &= ~(ST_INIT_RESERVE); @@ -3829,6 +3910,11 @@ rval = EINVAL; } + if (st_recov_sz != sizeof (recov_info) && un->un_multipath) { + scsi_log(ST_DEVINFO, st_label, CE_WARN, mp_misconf); + rval = EFAULT; + } + if (rval != 0) { un->un_errno = rval; mutex_exit(ST_MUTEX); @@ -3916,6 +4002,11 @@ rval = EINVAL; } + if (st_recov_sz != sizeof (recov_info) && un->un_multipath) { + scsi_log(ST_DEVINFO, st_label, CE_WARN, mp_misconf); + rval = EFAULT; + } + if (rval != 0) { un->un_errno = rval; mutex_exit(ST_MUTEX); @@ -4061,7 +4152,7 @@ un->un_pos.pmode = invalid; goto b_done_err; } - /* WTF un_restore_pos make invalid */ + /* un_restore_pos make invalid */ un->un_state = ST_STATE_OPEN_PENDING_IO; un->un_restore_pos = 0; } @@ -4373,14 +4464,15 @@ * this routine spaces forward over filemarks */ static int -st_space_fmks(struct scsi_tape *un, long count) +st_space_fmks(struct scsi_tape *un, int64_t count) { int rval = 0; ST_FUNC(ST_DEVINFO, st_space_fmks); ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG, - "st_space_fmks(dev = 0x%lx, count = %ld)\n", un->un_dev, count); + "st_space_fmks(dev = 0x%lx, count = %"PRIx64")\n", + un->un_dev, count); ASSERT(mutex_owned(ST_MUTEX)); @@ -4735,6 +4827,8 @@ mutex_enter(ST_MUTEX); + ASSERT(un->un_recov_buf_busy == 0); + ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG, "st_ioctl(): fileno=%x, blkno=%x, eof=%x, state = %d, " "pe_flag = %d\n", @@ -4897,6 +4991,15 @@ * persistense. Fake the answer based on previous info. */ if (un->un_persistence) { + rval = 0; + } else { + rval = st_check_clean_bit(un); + } + if (rval == 0) { + /* + * If zero is returned or in persistent mode, + * use the old data. + */ if ((un->un_HeadClean & (TAPE_ALERT_SUPPORTED | TAPE_SEQUENTIAL_SUPPORTED|TAPE_ALERT_NOT_SUPPORTED)) != TAPE_ALERT_NOT_SUPPORTED) { @@ -4906,13 +5009,6 @@ TAPE_ALERT_STILL_DIRTY)) { mtget->mt_flags |= MTF_TAPE_HEAD_DIRTY; } - rval = 0; - } else { - rval = st_check_clean_bit(un); - } - if (rval == -1) { - rval = EIO; - goto exit; } else { mtget->mt_flags |= (ushort_t)rval; rval = 0; @@ -5239,7 +5335,7 @@ */ (void) st_reserve_release(un, ST_RESERVE, st_uscsi_cmd); - rval = st_take_ownership(un); + rval = st_take_ownership(un, st_uscsi_cmd); break; } @@ -5914,30 +6010,37 @@ break; case MTFSF: + MAX_SPACE_CNT(mtop->mt_count); rval = st_mtfsf_ioctl(un, mtop->mt_count); break; case MTFSR: + MAX_SPACE_CNT(mtop->mt_count); rval = st_mtfsr_ioctl(un, mtop->mt_count); break; case MTBSF: + MAX_SPACE_CNT(mtop->mt_count); rval = st_mtbsf_ioctl(un, mtop->mt_count); break; case MTNBSF: + MAX_SPACE_CNT(mtop->mt_count); rval = st_mtnbsf_ioctl(un, mtop->mt_count); break; case MTBSR: + MAX_SPACE_CNT(mtop->mt_count); rval = st_mtbsr_ioctl(un, mtop->mt_count); break; case MTBSSF: + MAX_SPACE_CNT(mtop->mt_count); rval = st_mtbsfm_ioctl(un, mtop->mt_count); break; case MTFSSF: + MAX_SPACE_CNT(mtop->mt_count); rval = st_mtfsfm_ioctl(un, mtop->mt_count); break; @@ -6346,6 +6449,7 @@ "Sending delayed start to st_runout()\n"); mutex_exit(ST_MUTEX); (void) timeout(fnc, un, drv_usectohz(1000000)); + mutex_enter(ST_MUTEX); } return; } @@ -6452,39 +6556,54 @@ if (status != TRAN_ACCEPT) { ST_DO_KSTATS(bp, kstat_runq_back_to_waitq); - mutex_exit(ST_MUTEX); + ST_DEBUG(ST_DEVINFO, st_label, CE_WARN, + "Unhappy transport packet status 0x%x\n", status); if (status == TRAN_BUSY) { - /* if too many retries, fail the transport */ - if (st_handle_start_busy(un, bp, - ST_TRAN_BUSY_TIMEOUT, queued) == 0) - goto done; + pkt_info *pkti = BP_PKT(bp)->pkt_private; + + /* + * If command recovery is enabled and this isn't + * a recovery command try command recovery. + */ + if (pkti->privatelen == sizeof (recov_info) && + bp != un->un_recov_buf) { + ST_RECOV(ST_DEVINFO, st_label, CE_WARN, + "Command Recovery called on busy send\n"); + if (st_command_recovery(un, BP_PKT(bp), + ATTEMPT_RETRY) == JUST_RETURN) { + return; + } + } else { + mutex_exit(ST_MUTEX); + if (st_handle_start_busy(un, bp, + ST_TRAN_BUSY_TIMEOUT, queued) == 0) { + mutex_enter(ST_MUTEX); + return; + } + /* + * if too many retries, fail the transport + */ + mutex_enter(ST_MUTEX); + } } scsi_log(ST_DEVINFO, st_label, CE_WARN, "transport rejected %d\n", status); bp->b_resid = bp->b_bcount; - -#ifndef __lock_lint - /* - * warlock doesn't understand this potential - * recursion? - */ - mutex_enter(ST_MUTEX); ST_DO_KSTATS(bp, kstat_waitq_exit); ST_DO_ERRSTATS(un, st_transerrs); - st_bioerror(bp, EIO); - st_set_pe_flag(un); + if ((bp == un->un_recov_buf) && (status == TRAN_BUSY)) { + st_bioerror(bp, EBUSY); + } else { + st_bioerror(bp, EIO); + st_set_pe_flag(un); + } st_done_and_mutex_exit(un, bp); -#endif - } else { - un->un_tran_retry_ct = 0; - mutex_exit(ST_MUTEX); - } - -done: - - mutex_enter(ST_MUTEX); + mutex_enter(ST_MUTEX); + } + + ASSERT(mutex_owned(ST_MUTEX)); } /* @@ -6495,6 +6614,8 @@ clock_t timeout_interval, int queued) { + pkt_info *pktinfo = BP_PKT(bp)->pkt_private; + ST_FUNC(ST_DEVINFO, st_handle_start_busy); mutex_enter(ST_MUTEX); @@ -6507,7 +6628,7 @@ * making sure this is the last on the runq, if it is not, we have * to fail */ - if (((int)un->un_tran_retry_ct++ > st_retry_count) || + if ((pktinfo->str_retry_cnt++ > st_retry_count) || ((queued) && (un->un_runql != bp))) { mutex_exit(ST_MUTEX); return (-1); @@ -6647,7 +6768,9 @@ static void st_done_and_mutex_exit(struct scsi_tape *un, struct buf *bp) { - int pe_flagged = 0; + int pe_flagged = 0; + struct scsi_pkt *pkt = BP_PKT(bp); + pkt_info *pktinfo = pkt->pkt_private; ASSERT(MUTEX_HELD(&un->un_sd->sd_mutex)); #if !defined(lint) @@ -6665,7 +6788,7 @@ ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG, "st_done_and_mutex_exit(): cmd=0x%x count=%ld resid=%ld flags=" - "0x%x\n", (uchar_t)*((caddr_t)(BP_PKT(bp))->pkt_cdbp), bp->b_bcount, + "0x%x\n", pkt->pkt_cdbp[0], bp->b_bcount, bp->b_resid, bp->b_flags); @@ -6701,22 +6824,24 @@ st_start(un); } + un->un_retry_ct = max(pktinfo->pkt_retry_cnt, pktinfo->str_retry_cnt); + if (bp == un->un_sbufp && (bp->b_flags & B_ASYNC)) { /* * Since we marked this ourselves as ASYNC, * there isn't anybody around waiting for * completion any more. */ - uchar_t *cdb = (uchar_t *)bp->b_forw; - if (*cdb == SCMD_READ || *cdb == SCMD_WRITE) { + uchar_t *cmd = pkt->pkt_cdbp; + if (*cmd == SCMD_READ || *cmd == SCMD_WRITE) { bp->b_un.b_addr = (caddr_t)0; } - scsi_log(ST_DEVINFO, st_label, CE_NOTE, + ST_DEBUG(ST_DEVINFO, st_label, CE_NOTE, "st_done_and_mutex_exit(async): freeing pkt\n"); st_print_cdb(ST_DEVINFO, st_label, CE_NOTE, - "CDB sent with B_ASYNC", (caddr_t)cdb); - if (BP_PKT(bp)) { - scsi_destroy_pkt(BP_PKT(bp)); + "CDB sent with B_ASYNC", (caddr_t)cmd); + if (pkt) { + scsi_destroy_pkt(pkt); } un->un_sbuf_busy = 0; cv_signal(&un->un_sbuf_cv); @@ -6751,8 +6876,8 @@ ST_DEBUG6(ST_DEVINFO, st_label, SCSI_DEBUG, "st_done_and_mutex_exit: freeing pkt\n"); - if (BP_PKT(bp)) { - scsi_destroy_pkt(BP_PKT(bp)); + if (pkt) { + scsi_destroy_pkt(pkt); } biodone(bp); @@ -7120,8 +7245,6 @@ ST_FUNC(ST_DEVINFO, st_get_density); - ST_FUNC(ST_DEVINFO, st_get_density); - ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG, "st_get_density(un = 0x%p)\n", (void*)un); @@ -8128,6 +8251,7 @@ int r; char cdb[CDB_GROUP0]; struct uscsi_cmd *com; + struct scsi_arq_status status; ST_FUNC(ST_DEVINFO, st_gen_mode_sense); @@ -8142,8 +8266,10 @@ com->uscsi_cdblen = CDB_GROUP0; com->uscsi_bufaddr = (caddr_t)page_data; com->uscsi_buflen = page_size; + com->uscsi_rqlen = sizeof (status); + com->uscsi_rqbuf = (caddr_t)&status; com->uscsi_timeout = un->un_dp->non_motion_timeout; - com->uscsi_flags = USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ; + com->uscsi_flags = USCSI_DIAGNOSE | USCSI_RQENABLE | USCSI_READ; r = ubf(un, com, FKIOCTL); kmem_free(com, sizeof (*com)); @@ -8163,6 +8289,7 @@ int r; char cdb[CDB_GROUP0]; struct uscsi_cmd *com; + struct scsi_arq_status status; ST_FUNC(ST_DEVINFO, st_gen_mode_select); @@ -8193,8 +8320,10 @@ com->uscsi_cdblen = CDB_GROUP0; com->uscsi_bufaddr = (caddr_t)page_data; com->uscsi_buflen = page_size; + com->uscsi_rqlen = sizeof (status); + com->uscsi_rqbuf = (caddr_t)&status; com->uscsi_timeout = un->un_dp->non_motion_timeout; - com->uscsi_flags = USCSI_DIAGNOSE | USCSI_SILENT | USCSI_WRITE; + com->uscsi_flags = USCSI_DIAGNOSE | USCSI_RQENABLE | USCSI_WRITE; r = ubf(un, com, FKIOCTL); @@ -8208,6 +8337,7 @@ int rval; char cdb[CDB_GROUP0]; struct uscsi_cmd *com; + struct scsi_arq_status status; ST_FUNC(ST_DEVINFO, st_read_block_limits); @@ -8220,8 +8350,10 @@ com->uscsi_cdblen = CDB_GROUP0; com->uscsi_bufaddr = (caddr_t)read_blk; com->uscsi_buflen = sizeof (struct read_blklim); + com->uscsi_rqlen = sizeof (status); + com->uscsi_rqbuf = (caddr_t)&status; com->uscsi_timeout = un->un_dp->non_motion_timeout; - com->uscsi_flags = USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ; + com->uscsi_flags = USCSI_DIAGNOSE | USCSI_RQENABLE | USCSI_READ; rval = st_uscsi_cmd(un, com, FKIOCTL); if (com->uscsi_status || com->uscsi_resid) { @@ -8239,6 +8371,7 @@ int rval; char cdb[CDB_GROUP1]; struct uscsi_cmd *com; + struct scsi_arq_status status; ST_FUNC(ST_DEVINFO, st_report_density_support); @@ -8253,8 +8386,10 @@ com->uscsi_cdblen = CDB_GROUP1; com->uscsi_bufaddr = (caddr_t)density_data; com->uscsi_buflen = buflen; + com->uscsi_rqlen = sizeof (status); + com->uscsi_rqbuf = (caddr_t)&status; com->uscsi_timeout = un->un_dp->non_motion_timeout; - com->uscsi_flags = USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ; + com->uscsi_flags = USCSI_DIAGNOSE | USCSI_RQENABLE | USCSI_READ; rval = st_uscsi_cmd(un, com, FKIOCTL); if (com->uscsi_status || com->uscsi_resid) { @@ -8272,6 +8407,7 @@ int rval; char cdb[CDB_GROUP5]; struct uscsi_cmd *com; + struct scsi_arq_status status; uint32_t allo_length; ST_FUNC(ST_DEVINFO, st_report_supported_operation); @@ -8282,7 +8418,7 @@ bzero(cdb, CDB_GROUP5); cdb[0] = (char)SCMD_MAINTENANCE_IN; - cdb[1] = 0x0c; /* service action */ + cdb[1] = SSVC_ACTION_GET_SUPPORTED_OPERATIONS; if (service_action) { cdb[2] = (char)(ONE_COMMAND_DATA_FORMAT | 0x80); /* RCTD */ cdb[4] = (service_action & 0xff00) >> 8; @@ -8301,8 +8437,10 @@ com->uscsi_cdblen = CDB_GROUP5; com->uscsi_bufaddr = (caddr_t)oper_data; com->uscsi_buflen = allo_length; + com->uscsi_rqlen = sizeof (status); + com->uscsi_rqbuf = (caddr_t)&status; com->uscsi_timeout = un->un_dp->non_motion_timeout; - com->uscsi_flags = USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ; + com->uscsi_flags = USCSI_DIAGNOSE | USCSI_RQENABLE | USCSI_READ; rval = st_uscsi_cmd(un, com, FKIOCTL); if (com->uscsi_status) { @@ -8326,8 +8464,6 @@ ST_FUNC(ST_DEVINFO, st_change_block_size); - ST_FUNC(ST_DEVINFO, st_change_block_size); - current = kmem_zalloc(MSIZE, KM_SLEEP); /* @@ -8425,13 +8561,16 @@ struct uscsi_cmd *ucmd; recov_info *ri; int tval = 0; - uint64_t count; - uint32_t additional; + int64_t count; + uint32_t additional = 0; + uint32_t address = 0; + union scsi_cdb *ucdb; int flags = 0; int cdb_len = CDB_GROUP0; /* default */ uchar_t com; char fixbit; char short_fm = 0; + optype prev_op = un->un_lastop; int stat_size = (un->un_arq_enabled ? sizeof (struct scsi_arq_status) : 1); @@ -8586,7 +8725,22 @@ case SCMD_SPACE_G4: cdb_len = CDB_GROUP4; - case SCMD_SPACE: /* FALL THROUGH */ + fixbit = SPACE_TYPE(bp->b_bcount); + count = SPACE_CNT(bp->b_bcount); + ST_DEBUG6(ST_DEVINFO, st_label, CE_WARN, + " %s space %s %"PRId64" from file %d blk %d\n", + bp->b_bcount & SP_BACKSP ? "backward" : "forward", + space_strs[fixbit & 7], count, + un->un_pos.fileno, un->un_pos.blkno); + address = (count >> 48) & 0x1fff; + additional = (count >> 16) & 0xffffffff; + count &= 0xffff; + count <<= 16; + un->un_lastop = ST_OP_CTL; + tval = un->un_dp->space_timeout; + break; + + case SCMD_SPACE: fixbit = SPACE_TYPE(bp->b_bcount); count = SPACE_CNT(bp->b_bcount); ST_DEBUG6(ST_DEVINFO, st_label, SCSI_DEBUG, @@ -8594,7 +8748,6 @@ bp->b_bcount & SP_BACKSP ? "backward" : "forward", space_strs[fixbit & 7], count, un->un_pos.fileno, un->un_pos.blkno); - additional = count >> 32; count &= 0xffffffff; un->un_lastop = ST_OP_CTL; tval = un->un_dp->space_timeout; @@ -8729,6 +8882,7 @@ "Unhandled scsi command 0x%x in st_make_cmd()\n", com); } + pkt = scsi_init_pkt(ROUTE, NULL, allocbp, cdb_len, stat_size, st_recov_sz, 0, func, (caddr_t)un); if (pkt == NULL) { @@ -8750,15 +8904,15 @@ } - - (void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp, - com, 0, (uint_t)count, additional); + ucdb = (union scsi_cdb *)pkt->pkt_cdbp; + + (void) scsi_setup_cdb(ucdb, com, address, (uint_t)count, additional); FILL_SCSI1_LUN(un->un_sd, pkt); /* * Initialize the SILI/Fixed bits of the byte 1 of cdb. */ - ((union scsi_cdb *)(pkt->pkt_cdbp))->t_code = fixbit; - ((union scsi_cdb *)pkt->pkt_cdbp)->g0_vu_1 = short_fm; + ucdb->t_code = fixbit; + ucdb->g0_vu_1 = short_fm; pkt->pkt_flags = flags; ASSERT(tval); @@ -8771,6 +8925,24 @@ st_add_recovery_info_to_pkt(un, bp, pkt); + /* + * If we just write data to tape and did a command that doesn't + * change position, we still need to write a filemark. + */ + if ((prev_op == ST_OP_WRITE) || (prev_op == ST_OP_WEOF)) { + recov_info *rcvi = pkt->pkt_private; + cmd_attribute const *atrib; + + if (rcvi->privatelen == sizeof (recov_info)) { + atrib = rcvi->cmd_attrib; + } else { + atrib = st_lookup_cmd_attribute(com); + } + if (atrib->chg_tape_direction == DIR_NONE) { + un->un_lastop = prev_op; + } + } + exit: ASSERT(mutex_owned(ST_MUTEX)); } @@ -8913,7 +9085,6 @@ * not good, we don't want to requeue something after * another. */ - mutex_exit(ST_MUTEX); goto done_error; } else { un->un_runqf = bp; @@ -8930,46 +9101,52 @@ if (status != TRAN_ACCEPT) { ST_DO_KSTATS(bp, kstat_runq_back_to_waitq); - mutex_exit(ST_MUTEX); if (status == TRAN_BUSY) { + pkt_info *pkti = BP_PKT(bp)->pkt_private; + + if (pkti->privatelen == sizeof (recov_info) && + un->un_unit_attention_flags && + bp != un->un_recov_buf) { + un->un_unit_attention_flags = 0; + ST_RECOV(ST_DEVINFO, st_label, CE_WARN, + "Command Recovery called on busy resend\n"); + if (st_command_recovery(un, BP_PKT(bp), + ATTEMPT_RETRY) == JUST_RETURN) { + mutex_exit(ST_MUTEX); + return; + } + } + mutex_exit(ST_MUTEX); if (st_handle_intr_busy(un, bp, ST_TRAN_BUSY_TIMEOUT) == 0) return; /* timeout is setup again */ - } - - } else { - un->un_tran_retry_ct = 0; + mutex_enter(ST_MUTEX); + } + +done_error: + ST_DEBUG6(ST_DEVINFO, st_label, CE_WARN, + "restart transport rejected\n"); + bp->b_resid = bp->b_bcount; + + if (un->un_last_throttle) { + un->un_throttle = un->un_last_throttle; + } + if (status != TRAN_ACCEPT) { + ST_DO_ERRSTATS(un, st_transerrs); + } + ST_DO_KSTATS(bp, kstat_waitq_exit); + ST_DEBUG6(ST_DEVINFO, st_label, CE_WARN, + "busy restart aborted\n"); + st_set_pe_flag(un); + st_bioerror(bp, EIO); + st_done_and_mutex_exit(un, bp); + } else { if (un->un_last_throttle) { un->un_throttle = un->un_last_throttle; } mutex_exit(ST_MUTEX); - return; - } - -done_error: - ST_DEBUG6(ST_DEVINFO, st_label, CE_WARN, - "restart transport rejected\n"); - bp->b_resid = bp->b_bcount; - -#ifndef __lock_lint - /* - * warlock doesn't understand this potential - * recursion? - */ - mutex_enter(ST_MUTEX); - if (un->un_last_throttle) { - un->un_throttle = un->un_last_throttle; - } - if (status != TRAN_ACCEPT) - ST_DO_ERRSTATS(un, st_transerrs); - ST_DO_KSTATS(bp, kstat_waitq_exit); - st_set_pe_flag(un); - st_bioerror(bp, EIO); - st_done_and_mutex_exit(un, bp); -#endif - ST_DEBUG6(ST_DEVINFO, st_label, CE_WARN, - "busy restart aborted\n"); + } } /* @@ -9377,8 +9554,7 @@ ASSERT(pkt == un->un_rqs); ASSERT(un->un_state == ST_STATE_SENSING); un->un_state = un->un_laststate; - ((recov_info *)un->un_rqs->pkt_private)->cmd_bp = - un->un_rqs_bp; + rcv->cmd_bp = un->un_rqs_bp; ST_DO_ERRSTATS(un, st_transerrs); action = COMMAND_DONE_ERROR; } else { @@ -9406,8 +9582,7 @@ * to requeue it */ pkt = BP_PKT(bp); - ((recov_info *)un->un_rqs->pkt_private)->cmd_bp = - un->un_rqs_bp; + rcv->cmd_bp = un->un_rqs_bp; /* * some actions are based on un_state, hence * restore the state st was in before ST_STATE_SENSING. @@ -9456,6 +9631,22 @@ } /* + * check for undetected path failover. + */ + if ((un->un_multipath) && + (un->un_last_path_instance != pkt->pkt_path_instance)) { + if (un->un_state > ST_STATE_OPENING) { + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, + "Failover detected, action is %s\n", + errstatenames[action]); + if (action == COMMAND_DONE) { + action = PATH_FAILED; + } + } + un->un_last_path_instance = pkt->pkt_path_instance; + } + + /* * Restore old state if we were sensing. */ if (un->un_state == ST_STATE_SENSING && action != QUE_SENSE) { @@ -9463,8 +9654,8 @@ } ST_DEBUG6(ST_DEVINFO, st_label, SCSI_DEBUG, - "st_intr: pkt=%p, bp=%p, action=%x, status=%x\n", - (void *)pkt, (void *)bp, action, SCBP_C(pkt)); + "st_intr: pkt=%p, bp=%p, action=%s, status=%x\n", + (void *)pkt, (void *)bp, errstatenames[action], SCBP_C(pkt)); again: switch (action) { @@ -9628,6 +9819,10 @@ case DEVICE_RESET: case DEVICE_TAMPER: case ATTEMPT_RETRY: + case PATH_FAILED: + ST_RECOV(ST_DEVINFO, st_label, CE_WARN, + "Command Recovery called on %s status\n", + errstatenames[action]); action = st_command_recovery(un, pkt, action); goto again; @@ -9688,8 +9883,8 @@ * reduce probe time for nonexistant devices. */ if ((un->un_laststate > ST_STATE_OPENING) && - ((int)un->un_retry_ct < st_selection_retry_count)) { -/* XXX check retriable? */ + (rinfo->pkt_retry_cnt < st_selection_retry_count)) { + /* XXX check retriable? */ rval = QUE_COMMAND; } ST_DO_ERRSTATS(un, st_transerrs); @@ -9773,7 +9968,7 @@ } - if ((int)un->un_retry_ct++ < st_retry_count) { + if (rinfo->pkt_retry_cnt++ < st_retry_count) { if (un->un_pwr_mgmt == ST_PWR_SUSPENDED) { rval = QUE_COMMAND; } else if (bp == un->un_sbufp) { @@ -9824,6 +10019,7 @@ int queued; int rval = 0; + pkt_info *pktinfo = BP_PKT(bp)->pkt_private; mutex_enter(ST_MUTEX); @@ -9846,7 +10042,7 @@ * is the last we are in trouble anyway, as we are in the interrupt * context here. */ - if (((int)un->un_tran_retry_ct++ > st_retry_count) || + if ((pktinfo->str_retry_cnt++ > st_retry_count) || ((un->un_runqf != bp) && (un->un_runql != bp) && (queued))) { rval = -1; goto exit; @@ -10188,6 +10384,7 @@ struct scsi_pkt *pkt = BP_PKT(bp); struct scsi_pkt *rqpkt = un->un_rqs; struct scsi_arq_status arqstat; + recov_info *rcif = pkt->pkt_private; errstate rval = COMMAND_DONE_ERROR; int amt; @@ -10200,9 +10397,13 @@ "st_handle_sense()\n"); if (SCBP(rqpkt)->sts_busy) { - ST_DEBUG4(ST_DEVINFO, st_label, CE_WARN, - "busy unit on request sense\n"); - if ((int)un->un_retry_ct++ < st_retry_count) { + if (rcif->privatelen == sizeof (recov_info)) { + ST_RECOV(ST_DEVINFO, st_label, CE_WARN, + "Attempt recovery of busy unit on request sense\n"); + rval = ATTEMPT_RETRY; + } else if (rcif->pkt_retry_cnt++ < st_retry_count) { + ST_DEBUG4(ST_DEVINFO, st_label, CE_WARN, + "Retry busy unit on request sense\n"); rval = QUE_BUSY_COMMAND; } return (rval); @@ -10212,6 +10413,15 @@ return (rval); } + /* + * Make sure there is sense data to look at. + */ + if ((rqpkt->pkt_state & (STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS)) != (STATE_GOT_BUS | + STATE_GOT_TARGET | STATE_SENT_CMD | STATE_GOT_STATUS)) { + return (rval); + } + /* was there enough data? */ amt = (int)MAX_SENSE_LENGTH - rqpkt->pkt_resid; if ((rqpkt->pkt_state & STATE_XFERRED_DATA) == 0 || @@ -10235,7 +10445,7 @@ * copy one arqstat entry in the sense data buffer */ st_update_error_stack(un, pkt, &arqstat); - return (st_decode_sense(un, bp, amt, SCBP(rqpkt), pos)); + return (st_decode_sense(un, bp, amt, &arqstat, pos)); } static errstate @@ -10312,15 +10522,15 @@ */ st_update_error_stack(un, pkt, arqstat); - return (st_decode_sense(un, bp, amt, &arqstat->sts_rqpkt_status, pos)); + return (st_decode_sense(un, bp, amt, arqstat, pos)); } static errstate st_decode_sense(struct scsi_tape *un, struct buf *bp, int amt, - struct scsi_status *statusp, tapepos_t *pos) + struct scsi_arq_status *statusp, tapepos_t *pos) { struct scsi_pkt *pkt = BP_PKT(bp); - recov_info *ri = (recov_info *)pkt->pkt_private; + recov_info *ri = pkt->pkt_private; errstate rval = COMMAND_DONE_ERROR; cmd_attribute const *attrib; long resid; @@ -10372,8 +10582,8 @@ ST_CDB(ST_DEVINFO, "st_decode_sense failed CDB", (caddr_t)&CDBP(pkt)->scc_cmd); - ST_SENSE(ST_DEVINFO, "st_decode_sense sense data", (caddr_t)sensep, - sizeof (*sensep)); + ST_SENSE(ST_DEVINFO, "st_decode_sense sense data", (caddr_t)statusp, + sizeof (*statusp)); /* for normal I/O check extract the resid values. */ if (bp != un->un_sbufp && bp != un->un_recov_buf) { @@ -10417,6 +10627,7 @@ (CDBP(pkt)->scc_cmd == SCMD_LOCATE) || (CDBP(pkt)->scc_cmd == SCMD_LOCATE_G4) || (CDBP(pkt)->scc_cmd == SCMD_SPACE) || + (CDBP(pkt)->scc_cmd == SCMD_SPACE_G4) || (CDBP(pkt)->scc_cmd == SCMD_WRITE_FILE_MARK)) { resid = (sensep->es_info_1 << 24) | @@ -10593,14 +10804,6 @@ case KEY_MEDIUM_ERROR: ST_DO_ERRSTATS(un, st_harderrs); severity = SCSI_ERR_FATAL; - - /* - * for (buffered) writes, a medium error must be fatal - */ - if (CDBP(pkt)->scc_cmd != SCMD_WRITE) { - rval = COMMAND_DONE_ERROR_RECOVERED; - } - check_keys: /* * attempt to process the keys in the presence of @@ -10676,6 +10879,7 @@ un->un_status = SUN_KEY_EOT; pos->eof = ST_EOT; rval = COMMAND_DONE_ERROR; + un->un_running.pmode = invalid; st_set_pe_flag(un); goto check_keys; } else if (bp != un->un_sbufp && @@ -10724,7 +10928,7 @@ ST_DEBUG6(ST_DEVINFO, st_label, CE_WARN, "KEY_UNIT_ATTENTION : un_state = %d\n", un->un_state); - un->un_unit_attention_flags = 1; + un->un_unit_attention_flags |= 1; /* * If we have detected a Bus Reset and the tape * drive has been reserved. @@ -10746,7 +10950,7 @@ if (bp == un->un_recov_buf) { severity = SCSI_ERR_INFO; if (attrib->retriable && - (int)un->un_retry_ct++ < st_retry_count) { + ri->pkt_retry_cnt++ < st_retry_count) { rval = QUE_COMMAND; } else { rval = COMMAND_DONE_ERROR; @@ -10764,11 +10968,18 @@ */ if ((un->un_rsvd_status & ST_APPLICATION_RESERVATIONS) != 0) { + /* + * RESERVATIONS PREEMPTED + * With MPxIO this could be a fail over? XXX + */ if (ST_RQSENSE->es_add_code == 0x2a && ST_RQSENSE->es_qual_code == 0x03) { severity = SCSI_ERR_INFO; rval = COMMAND_DONE_ERROR; pos->pmode = invalid; + /* + * RESERVATIONS RELEASED + */ } else if (ST_RQSENSE->es_add_code == 0x2a && ST_RQSENSE->es_qual_code == 0x04) { rval = COMMAND_DONE; @@ -10793,7 +11004,7 @@ } if (attrib->retriable && - (int)un->un_retry_ct++ < st_retry_count) { + ri->pkt_retry_cnt++ < st_retry_count) { rval = QUE_COMMAND; } else if (rval == DEVICE_RESET) { break; @@ -10805,7 +11016,8 @@ * This is the result of a reset clearing settings or * another initiator changing what we set. */ - } else if (ST_RQSENSE->es_add_code == 0x2a) { + } + if (ST_RQSENSE->es_add_code == 0x2a) { if (ST_RQSENSE->es_qual_code == 0x1) { /* Error recovery will modeselect and retry. */ rval = DEVICE_TAMPER; @@ -10867,7 +11079,7 @@ */ if (sensep->es_add_code == 0x04 && sensep->es_qual_code == 0x01 && - un->un_retry_ct++ < st_retry_count) { + ri->pkt_retry_cnt++ < st_retry_count) { rval = QUE_COMMAND; severity = SCSI_ERR_INFO; } else { @@ -10901,7 +11113,7 @@ /* XXX Do drives return this when they see a lost light? */ /* Testing would say yes */ - if (un->un_retry_ct++ < st_retry_count) { + if (ri->pkt_retry_cnt++ < st_retry_count) { rval = ATTEMPT_RETRY; severity = SCSI_ERR_RETRYABLE; goto check_keys; @@ -10973,6 +11185,7 @@ st_handle_intr_retry_lcmd(struct scsi_tape *un, struct buf *bp) { int status = TRAN_ACCEPT; + pkt_info *pktinfo = BP_PKT(bp)->pkt_private; mutex_enter(ST_MUTEX); @@ -10989,7 +11202,7 @@ * is the last we are in trouble anyway, as we are in the interrupt * context here. */ - if (((int)un->un_retry_ct > st_retry_count) || + if ((pktinfo->pkt_retry_cnt > st_retry_count) || ((un->un_runqf != bp) && (un->un_runql != bp))) { goto exit; } @@ -11010,7 +11223,6 @@ status = st_transport(un, BP_PKT(bp)); if (status == TRAN_ACCEPT) { - un->un_tran_retry_ct = 0; if (un->un_last_throttle) { un->un_throttle = un->un_last_throttle; } @@ -11090,6 +11302,9 @@ st_check_error(struct scsi_tape *un, struct scsi_pkt *pkt) { errstate action; + recov_info *rcvi = pkt->pkt_private; + buf_t *bp = rcvi->cmd_bp; + struct scsi_arq_status *stat = (struct scsi_arq_status *)pkt->pkt_scbp; ST_FUNC(ST_DEVINFO, st_check_error); @@ -11097,12 +11312,47 @@ ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG, "st_check_error()\n"); - if (SCBP_C(pkt) == STATUS_RESERVATION_CONFLICT) { - action = COMMAND_DONE_EACCES; - un->un_rsvd_status |= ST_RESERVATION_CONFLICT; - } else if (SCBP(pkt)->sts_busy) { + switch (SCBP_C(pkt)) { + case STATUS_RESERVATION_CONFLICT: + /* + * Command recovery is enabled, not just opening, + * we had the drive reserved and we thing its ours. + * Call recovery to attempt to take it back. + */ + if ((rcvi->privatelen == sizeof (recov_info)) && + (bp != un->un_recov_buf) && + (un->un_state > ST_STATE_OPEN_PENDING_IO) && + ((un->un_rsvd_status & (ST_RESERVE | + ST_APPLICATION_RESERVATIONS)) != 0)) { + action = ATTEMPT_RETRY; + un->un_rsvd_status |= ST_LOST_RESERVE; + } else { + action = COMMAND_DONE_EACCES; + un->un_rsvd_status |= ST_RESERVATION_CONFLICT; + } + break; + + case STATUS_BUSY: ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, "unit busy\n"); - if ((int)un->un_retry_ct++ < st_retry_count) { + if (rcvi->privatelen == sizeof (recov_info) && + un->un_multipath && (pkt->pkt_state == (STATE_GOT_BUS | + STATE_GOT_TARGET | STATE_SENT_CMD | STATE_GOT_STATUS))) { + /* + * Status returned by scsi_vhci indicating path + * has failed over. + */ + action = PATH_FAILED; + break; + } + /* FALLTHRU */ + case STATUS_QFULL: + if (rcvi->privatelen == sizeof (recov_info)) { + /* + * If recovery is inabled use it instead of + * blind reties. + */ + action = ATTEMPT_RETRY; + } else if (rcvi->pkt_retry_cnt++ < st_retry_count) { action = QUE_BUSY_COMMAND; } else if ((un->un_rsvd_status & (ST_RESERVE | ST_APPLICATION_RESERVATIONS)) == 0) { @@ -11117,21 +11367,45 @@ (void) st_reset(un, RESET_ALL); action = COMMAND_DONE_ERROR; } - } else if (SCBP(pkt)->sts_chk) { + break; + + case STATUS_CHECK: + case STATUS_TERMINATED: /* * we should only get here if the auto rqsense failed * thru a uscsi cmd without autorequest sense * so we just try again */ - action = QUE_SENSE; - } else if (SCBP(pkt)->sts_vu7) { + if (un->un_arq_enabled && + stat->sts_rqpkt_reason == CMD_CMPLT && + (stat->sts_rqpkt_state & (STATE_GOT_BUS | + STATE_GOT_TARGET | STATE_SENT_CMD | STATE_GOT_STATUS)) == + (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD | + STATE_GOT_STATUS)) { + + ST_DEBUG2(ST_DEVINFO, st_label, CE_WARN, + "Really got sense data\n"); + action = st_decode_sense(un, bp, MAX_SENSE_LENGTH - + pkt->pkt_resid, stat, &un->un_pos); + } else { + ST_DEBUG2(ST_DEVINFO, st_label, CE_WARN, + "Trying to queue sense command\n"); + action = QUE_SENSE; + } + break; + + case STATUS_TASK_ABORT: /* * This is an aborted task. This can be a reset on the other * port of a multiport drive. Lets try and recover it. */ action = DEVICE_RESET; - } else { + break; + + default: action = COMMAND_DONE; + ST_DEBUG(ST_DEVINFO, st_label, CE_PANIC, + "Unexpected scsi status byte 0x%x\n", SCBP_C(pkt)); } return (action); } @@ -11140,8 +11414,9 @@ st_calc_bnum(struct scsi_tape *un, struct buf *bp, struct scsi_pkt *pkt) { int nblks; + int nfiles; long count; - recov_info *ri = (recov_info *)pkt->pkt_private; + recov_info *ri = pkt->pkt_private; cmd_attribute const *attrib; ST_FUNC(ST_DEVINFO, st_calc_bnum); @@ -11159,13 +11434,45 @@ count = bp->b_bcount - bp->b_resid; - /* If variable block mode */ - if (un->un_bsize == 0) { - nblks = ((count == 0) ? 0 : 1); - un->un_kbytes_xferred += (count / ONE_K); - } else { - nblks = (count / un->un_bsize); - un->un_kbytes_xferred += (nblks * un->un_bsize) / ONE_K; + /* Command reads or writes data */ + if (attrib->transfers_data != TRAN_NONE) { + if (count == 0) { + /* failed writes should not make it here */ + ASSERT(attrib->transfers_data == TRAN_READ); + nblks = 0; + nfiles = 1; + } else if (un->un_bsize == 0) { + /* + * If variable block mode. + * Fixed bit in CBD should be zero. + */ + ASSERT((pkt->pkt_cdbp[1] & 1) == 0); + nblks = 1; + un->un_kbytes_xferred += (count / ONE_K); + nfiles = 0; + } else { + /* + * If fixed block mode. + * Fixed bit in CBD should be one. + */ + ASSERT((pkt->pkt_cdbp[1] & 1) == 1); + nblks = (count / un->un_bsize); + un->un_kbytes_xferred += (nblks * un->un_bsize) / ONE_K; + nfiles = 0; + } + /* + * So its possable to read some blocks and hit a filemark. + * Example reading in fixed block mode where more then one + * block at a time is requested. In this case because the + * filemark is hit something less then the requesed number + * of blocks is read. + */ + if (un->un_pos.eof == ST_EOF_PENDING && bp->b_resid) { + nfiles = 1; + } + } else { + nblks = 0; + nfiles = count; } /* @@ -11179,9 +11486,11 @@ if (attrib->chg_tape_direction == DIR_FORW) { un->un_pos.blkno += nblks; un->un_pos.lgclblkno += nblks; + un->un_pos.lgclblkno += nfiles; } else if (attrib->chg_tape_direction == DIR_REVC) { un->un_pos.blkno -= nblks; un->un_pos.lgclblkno -= nblks; + un->un_pos.lgclblkno -= nfiles; } else { ASSERT(0); } @@ -11196,7 +11505,7 @@ * If we didn't just read a filemark. */ if (un->un_pos.eof != ST_EOF_PENDING) { - ASSERT(nblks != 0); + ASSERT(nblks != 0 && nfiles == 0); /* * If Previously calulated expected position does not match * debug the expected position. @@ -11213,7 +11522,7 @@ un->un_running.pmode = invalid; } } else { - ASSERT(nblks == 0); + ASSERT(nfiles != 0); if (un->un_running.pmode != invalid) { /* * blkno and lgclblkno already counted in @@ -11278,19 +11587,17 @@ un->un_throttle = un->un_max_throttle; } } else { - optype new_lastop; + optype new_lastop = ST_OP_NIL; uchar_t cmd = (uchar_t)(intptr_t)bp->b_forw; - un->un_lastop = ST_OP_CTL; - switch (cmd) { case SCMD_WRITE: case SCMD_WRITE_G4: bp->b_resid = sp->pkt_resid; + new_lastop = ST_OP_WRITE; if (geterror(bp) == EIO) { break; } - new_lastop = ST_OP_WRITE; st_calc_bnum(un, bp, sp); if (un->un_dp->options & ST_REEL) { un->un_fmneeded = 2; @@ -11301,10 +11608,10 @@ case SCMD_READ: case SCMD_READ_G4: bp->b_resid = sp->pkt_resid; + new_lastop = ST_OP_READ; if (geterror(bp) == EIO) { break; } - new_lastop = ST_OP_READ; st_calc_bnum(un, bp, sp); un->un_fmneeded = 0; break; @@ -11352,7 +11659,7 @@ int64_t resid; int64_t done; cmd_attribute const *attrib; - recov_info *ri = (recov_info *)sp->pkt_private; + recov_info *ri = sp->pkt_private; if (ri->privatelen == sizeof (recov_info)) { attrib = ri->cmd_attrib; @@ -11375,7 +11682,7 @@ new_lastop = ST_OP_CTL; } - ST_SPAC(ST_DEVINFO, st_label, SCSI_DEBUG, + ST_SPAC(ST_DEVINFO, st_label, CE_WARN, "space cmd: cdb[1] = %s\n" "space data: = 0x%lx\n" "space count: = %"PRId64"\n" @@ -11469,6 +11776,16 @@ } else { un->un_state = ST_STATE_OFFLINE; un->un_pos.pmode = invalid; + + } + /* + * If we are loading or unloading we expect the media id + * to change. Lets make it unknown. + */ + if (un->un_media_id != bogusID && un->un_media_id_len) { + kmem_free(un->un_media_id, un->un_media_id_len); + un->un_media_id = NULL; + un->un_media_id_len = 0; } un->un_density_known = 0; un->un_pos.eof = ST_NO_EOF; @@ -11489,7 +11806,7 @@ un->un_rsvd_status &= ~(ST_RELEASE | ST_LOST_RESERVE | ST_RESERVATION_CONFLICT | ST_INITIATED_RESET); - new_lastop = un->un_lastop; + new_lastop = ST_OP_CTL; break; case SCMD_RELEASE: un->un_rsvd_status |= ST_RELEASE; @@ -11501,6 +11818,7 @@ case SCMD_PERSISTENT_RESERVE_IN: ST_DEBUG6(ST_DEVINFO, st_label, CE_WARN, "PGR_IN command\n"); + new_lastop = ST_OP_CTL; break; case SCMD_PERSISTENT_RESERVE_OUT: switch (sp->pkt_cdbp[1] & ST_SA_MASK) { @@ -11508,20 +11826,34 @@ case ST_SA_SCSI3_PREEMPT: case ST_SA_SCSI3_PREEMPTANDABORT: un->un_rsvd_status |= - ST_APPLICATION_RESERVATIONS; + (ST_APPLICATION_RESERVATIONS | ST_RESERVE); + un->un_rsvd_status &= ~(ST_RELEASE | + ST_LOST_RESERVE | ST_RESERVATION_CONFLICT | + ST_INITIATED_RESET); ST_DEBUG6(ST_DEVINFO, st_label, CE_WARN, "PGR Reserve and set: entering" " ST_APPLICATION_RESERVATIONS mode"); break; - case ST_SA_SCSI3_RELEASE: + case ST_SA_SCSI3_REGISTER: + ST_DEBUG6(ST_DEVINFO, st_label, CE_WARN, + "PGR Reserve register key"); + un->un_rsvd_status |= ST_INIT_RESERVE; + break; case ST_SA_SCSI3_CLEAR: + un->un_rsvd_status &= ~ST_INIT_RESERVE; + /* FALLTHROUGH */ + case ST_SA_SCSI3_RELEASE: un->un_rsvd_status &= - ~ST_APPLICATION_RESERVATIONS; + ~(ST_APPLICATION_RESERVATIONS | ST_RESERVE | + ST_LOST_RESERVE | ST_RESERVATION_CONFLICT | + ST_INITIATED_RESET); + un->un_rsvd_status |= ST_RELEASE; ST_DEBUG6(ST_DEVINFO, st_label, CE_WARN, "PGR Release and reset: exiting" " ST_APPLICATION_RESERVATIONS mode"); break; } + new_lastop = ST_OP_CTL; break; case SCMD_TEST_UNIT_READY: case SCMD_READ_BLKLIM: @@ -11558,6 +11890,16 @@ /* Locate makes position mode no longer legacy */ un->un_lastop = new_lastop = ST_OP_CTL; break; + case SCMD_MAINTENANCE_IN: + switch (sp->pkt_cdbp[1]) { + case SSVC_ACTION_GET_SUPPORTED_OPERATIONS: + case SSVC_ACTION_SET_TARGET_PORT_GROUPS: + new_lastop = ST_OP_CTL; + break; + } + if (new_lastop != ST_OP_NIL) { + break; + } default: /* * Unknown command, If was USCSI and USCSI_SILENT @@ -11569,6 +11911,12 @@ "unknown cmd 0x%X caused loss of state\n", cmd); } else { + /* + * keep the old agreement to allow unknown + * commands with the USCSI_SILENT set. + * This prevents ASSERT below. + */ + new_lastop = ST_OP_CTL; break; } /* FALLTHROUGH */ @@ -11604,7 +11952,6 @@ */ un->un_err_resid = bp->b_resid; COPY_POS(&un->un_err_pos, &un->un_pos); - un->un_retry_ct = 0; /* @@ -11781,15 +12128,21 @@ ST_FUNC(dip, st_print_cdb); -#ifdef STDEBUG + /* force one line output so repeated commands are printed once */ if ((st_debug & 0x180) == 0x100) { scsi_log(dip, label, level, "node %s cmd %s\n", st_dev_name(un->un_dev), st_print_scsi_cmd(*cdb)); return; } -#endif - (void) sprintf(buf, "%s for cmd(%s)", title, st_print_scsi_cmd(*cdb)); - st_clean_print(dip, label, level, buf, cdb, len); + + /* force one line output so repeated CDB's are printed once */ + if ((st_debug & 0x180) == 0x80) { + st_clean_print(dip, label, level, NULL, cdb, len); + } else { + (void) sprintf(buf, "%s for cmd(%s)", title, + st_print_scsi_cmd(*cdb)); + st_clean_print(dip, label, level, buf, cdb, len); + } } static void @@ -11805,9 +12158,12 @@ ST_FUNC(dev, st_clean_print); - (void) sprintf(buf, "%s:\n", title); - scsi_log(dev, label, level, "%s", buf); - level = CE_CONT; + if (title) { + (void) sprintf(buf, "%s:\n", title); + scsi_log(dev, label, level, "%s", buf); + level = CE_CONT; + } + for (i = 0; i < len; ) { buf[0] = 0; for (c = 0; c < 8 && i < len; c++, i++) { @@ -11821,6 +12177,7 @@ (void) sprintf(&buf[(int)strlen(buf)], "\n"); scsi_log(dev, label, level, "%s\n", buf); + level = CE_CONT; } } @@ -11841,6 +12198,7 @@ count, count, wait == ASYNC_CMD ? "a" : ""); } +#endif /* STDEBUG */ /* * Returns pointer to name of minor node name of device 'dev'. @@ -11877,7 +12235,6 @@ return (name); } -#endif /* STDEBUG */ /* * Soft error reporting, so far unique to each drive @@ -12020,6 +12377,7 @@ int rval = 0; char cdb[CDB_GROUP1], *c = cdb; struct uscsi_cmd *com; + struct scsi_arq_status status; GET_SOFT_STATE(dev); @@ -12047,7 +12405,9 @@ com->uscsi_cdblen = CDB_GROUP1; com->uscsi_bufaddr = (caddr_t)sensep; com->uscsi_buflen = LOG_SENSE_LENGTH; - com->uscsi_flags = USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ; + com->uscsi_rqlen = sizeof (status); + com->uscsi_rqbuf = (caddr_t)&status; + com->uscsi_flags = USCSI_DIAGNOSE | USCSI_RQENABLE | USCSI_READ; com->uscsi_timeout = un->un_dp->non_motion_timeout; rval = st_uscsi_cmd(un, com, FKIOCTL); if (rval) { @@ -12330,6 +12690,7 @@ st_do_reserve(struct scsi_tape *un) { int rval; + int was_lost = un->un_rsvd_status & ST_LOST_RESERVE; ST_FUNC(ST_DEVINFO, st_do_reserve); @@ -12360,6 +12721,9 @@ if (rval == 0) { un->un_rsvd_status |= ST_INIT_RESERVE; } + if (was_lost) { + un->un_running.pmode = invalid; + } return (rval); } @@ -12522,7 +12886,7 @@ } static int -st_take_ownership(struct scsi_tape *un) +st_take_ownership(struct scsi_tape *un, ubufunc_t ubf) { int rval; @@ -12534,7 +12898,7 @@ "st_take_ownership: Entering ...\n"); - rval = st_reserve_release(un, ST_RESERVE, st_uscsi_cmd); + rval = st_reserve_release(un, ST_RESERVE, ubf); /* * XXX -> Should reset be done only if we get EACCES. * . @@ -12552,10 +12916,10 @@ /* * remove the check condition. */ - (void) st_reserve_release(un, ST_RESERVE, st_uscsi_cmd); - rval = st_reserve_release(un, ST_RESERVE, st_uscsi_cmd); + (void) st_reserve_release(un, ST_RESERVE, ubf); + rval = st_reserve_release(un, ST_RESERVE, ubf); if (rval != 0) { - if ((st_reserve_release(un, ST_RESERVE, st_uscsi_cmd)) + if ((st_reserve_release(un, ST_RESERVE, ubf)) != 0) { rval = (un->un_rsvd_status & ST_RESERVATION_CONFLICT) ? EACCES : EIO; @@ -12795,6 +13159,7 @@ uchar_t *sp, *sensep; unsigned length; struct uscsi_cmd *com; + struct scsi_arq_status status; int rval; char cdb[CDB_GROUP1] = { SCMD_LOG_SENSE_G1, @@ -12820,8 +13185,10 @@ com->uscsi_cdblen = CDB_GROUP1; com->uscsi_bufaddr = (caddr_t)sensep; com->uscsi_buflen = LOG_SENSE_LENGTH; + com->uscsi_rqlen = sizeof (status); + com->uscsi_rqbuf = (caddr_t)&status; com->uscsi_flags = - USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ; + USCSI_DIAGNOSE | USCSI_RQENABLE | USCSI_READ; com->uscsi_timeout = un->un_dp->non_motion_timeout; rval = st_uscsi_cmd(un, com, FKIOCTL); if (rval || com->uscsi_status) { @@ -12879,12 +13246,18 @@ if (un->un_HeadClean == TAPE_ALERT_SUPPORT_UNKNOWN) { rval = st_logpage_supported(un, TAPE_SEQUENTIAL_PAGE); + if (rval == -1) { + return (0); + } if (rval == 1) { un->un_HeadClean |= TAPE_SEQUENTIAL_SUPPORTED; } rval = st_logpage_supported(un, TAPE_ALERT_PAGE); + if (rval == -1) { + return (0); + } if (rval == 1) { un->un_HeadClean |= TAPE_ALERT_SUPPORTED; @@ -12901,20 +13274,25 @@ if (un->un_HeadClean & TAPE_SEQUENTIAL_SUPPORTED) { rval = st_check_sequential_clean_bit(un); - } - - if ((rval <= 0) && (un->un_HeadClean & TAPE_ALERT_SUPPORTED)) { + if (rval == -1) { + return (0); + } + } + + if ((rval == 0) && (un->un_HeadClean & TAPE_ALERT_SUPPORTED)) { rval = st_check_alert_flags(un); - } - - if ((rval <= 0) && (un->un_dp->options & ST_CLN_MASK)) { + if (rval == -1) { + return (0); + } + } + + if ((rval == 0) && (un->un_dp->options & ST_CLN_MASK)) { rval = st_check_sense_clean_bit(un); - } - - if (rval < 0) { - return (rval); + if (rval == -1) { + return (0); + } } /* @@ -12958,6 +13336,7 @@ struct uscsi_cmd *cmd; struct log_sequential_page *sp; struct log_sequential_page_parameter *prm; + struct scsi_arq_status status; char cdb[CDB_GROUP1] = { SCMD_LOG_SENSE_G1, 0, @@ -12977,12 +13356,14 @@ sp = kmem_zalloc(sizeof (struct log_sequential_page), KM_SLEEP); cmd->uscsi_flags = - USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ; + USCSI_DIAGNOSE | USCSI_RQENABLE | USCSI_READ; cmd->uscsi_timeout = un->un_dp->non_motion_timeout; cmd->uscsi_cdb = cdb; cmd->uscsi_cdblen = CDB_GROUP1; cmd->uscsi_bufaddr = (caddr_t)sp; cmd->uscsi_buflen = sizeof (struct log_sequential_page); + cmd->uscsi_rqlen = sizeof (status); + cmd->uscsi_rqbuf = (caddr_t)&status; rval = st_uscsi_cmd(un, cmd, FKIOCTL); @@ -13032,6 +13413,7 @@ { struct st_tape_alert *ta; struct uscsi_cmd *com; + struct scsi_arq_status status; unsigned ix, length; int rval; tape_alert_flags flag; @@ -13057,8 +13439,10 @@ com->uscsi_cdblen = CDB_GROUP1; com->uscsi_bufaddr = (caddr_t)ta; com->uscsi_buflen = sizeof (struct st_tape_alert); + com->uscsi_rqlen = sizeof (status); + com->uscsi_rqbuf = (caddr_t)&status; com->uscsi_flags = - USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ; + USCSI_DIAGNOSE | USCSI_RQENABLE | USCSI_READ; com->uscsi_timeout = un->un_dp->non_motion_timeout; rval = st_uscsi_cmd(un, com, FKIOCTL); @@ -13857,6 +14241,8 @@ char cdb[CDB_GROUP4]; int result; struct uscsi_cmd *cmd; + struct scsi_arq_status status; + caddr_t buf = (caddr_t)pnt; ST_FUNC(ST_DEVINFO, st_read_attributes); @@ -13885,12 +14271,14 @@ cdb[15] = 0; - cmd->uscsi_flags = USCSI_READ | USCSI_DIAGNOSE; + cmd->uscsi_flags = USCSI_READ | USCSI_RQENABLE | USCSI_DIAGNOSE; cmd->uscsi_timeout = un->un_dp->non_motion_timeout; cmd->uscsi_cdb = &cdb[0]; cmd->uscsi_bufaddr = (caddr_t)buf; cmd->uscsi_buflen = size; cmd->uscsi_cdblen = sizeof (cdb); + cmd->uscsi_rqlen = sizeof (status); + cmd->uscsi_rqbuf = (caddr_t)&status; result = bufunc(un, cmd, FKIOCTL); @@ -14547,7 +14935,7 @@ rval = EIO; } - if ((flag > 1) && (rval == 0)) { + if ((flag > 1) && (rval == 0) && (org.pmode != invalid)) { st_print_position(ST_DEVINFO, st_label, CE_NOTE, "position read in", &org); st_print_position(ST_DEVINFO, st_label, CE_NOTE, @@ -14569,7 +14957,7 @@ ST_FUNC(ST_DEVINFO, st_logical_block_locate); /* - * WTF Not sure what to do when doing recovery and not wanting + * Not sure what to do when doing recovery and not wanting * to update un_pos */ @@ -14677,7 +15065,7 @@ /* Worked as requested */ pos->lgclblkno = lblk; - } else if (((cmd->uscsi_status & STATUS_MASK) == STATUS_CHECK) && + } else if (((cmd->uscsi_status & ST_STATUS_MASK) == STATUS_CHECK) && (cmd->uscsi_resid != 0)) { /* Got part way there but wasn't enough blocks on tape */ pos->lgclblkno = lblk - cmd->uscsi_resid; @@ -14707,7 +15095,7 @@ } static int -st_mtfsf_ioctl(struct scsi_tape *un, int files) +st_mtfsf_ioctl(struct scsi_tape *un, int64_t files) { int rval; @@ -14715,7 +15103,7 @@ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "st_mtfsf_ioctl: count=%x, eof=%x\n", files, un->un_pos.eof); + "st_mtfsf_ioctl: count=%"PRIx64", eof=%x\n", files, un->un_pos.eof); #if 0 if ((IN_EOF(un->un_pos)) && (files == 1)) { un->un_pos.fileno++; @@ -14783,14 +15171,14 @@ } static int -st_forward_space_files(struct scsi_tape *un, int count) +st_forward_space_files(struct scsi_tape *un, int64_t count) { int rval; ST_FUNC(ST_DEVINFO, st_forward_space_files); ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "fspace: count=%x, eof=%x\n", count, un->un_pos.eof); + "fspace: count=%"PRIx64", eof=%x\n", count, un->un_pos.eof); ASSERT(count >= 0); ASSERT(un->un_pos.pmode != invalid); @@ -14936,7 +15324,7 @@ } static int -st_mtfsr_ioctl(struct scsi_tape *un, int count) +st_mtfsr_ioctl(struct scsi_tape *un, int64_t count) { ST_FUNC(ST_DEVINFO, st_mtfsr_ioctl); @@ -14947,7 +15335,7 @@ */ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "st_ioctl_fsr: count=%x, eof=%x\n", count, un->un_pos.eof); + "st_ioctl_fsr: count=%"PRIx64", eof=%x\n", count, un->un_pos.eof); if (un->un_pos.pmode == legacy) { /* @@ -15008,15 +15396,16 @@ } static int -st_space_records(struct scsi_tape *un, int count) -{ - int dblk; +st_space_records(struct scsi_tape *un, int64_t count) +{ + int64_t dblk; int rval = 0; ST_FUNC(ST_DEVINFO, st_space_records); ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "st_space_records: count=%x, eof=%x\n", count, un->un_pos.eof); + "st_space_records: count=%"PRIx64", eof=%x\n", + count, un->un_pos.eof); if (un->un_pos.pmode == logical) { rval = st_cmd(un, SCMD_SPACE, Blk(count), SYNC_CMD); @@ -15026,7 +15415,7 @@ return (rval); } - dblk = un->un_pos.blkno + count; + dblk = count + un->un_pos.blkno; /* Already there */ if (dblk == un->un_pos.blkno) { @@ -15124,12 +15513,12 @@ } static int -st_mtbsf_ioctl(struct scsi_tape *un, int files) +st_mtbsf_ioctl(struct scsi_tape *un, int64_t files) { ST_FUNC(ST_DEVINFO, st_mtbsf_ioctl); ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "st_mtbsf_ioctl: count=%x, eof=%x\n", files, un->un_pos.eof); + "st_mtbsf_ioctl: count=%"PRIx64", eof=%x\n", files, un->un_pos.eof); /* * backward space of file filemark (1/2" and 8mm) * tape position will end on the beginning of tape side @@ -15163,7 +15552,7 @@ un->un_pos.blkno = 0; files++; ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "st_mtbsf_ioctl in eof: count=%d, op=%x\n", + "st_mtbsf_ioctl in eof: count=%"PRIx64", op=%x\n", files, MTBSF); } @@ -15187,16 +15576,16 @@ } static int -st_backward_space_files(struct scsi_tape *un, int count, int infront) -{ - int end_fileno; - int skip_cnt; +st_backward_space_files(struct scsi_tape *un, int64_t count, int infront) +{ + int64_t end_fileno; + int64_t skip_cnt; int rval = 0; ST_FUNC(ST_DEVINFO, st_backward_space_files); ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "st_backward_space_files: count=%x eof=%x\n", + "st_backward_space_files: count=%"PRIx64" eof=%x\n", count, un->un_pos.eof); /* * Backspace files (MTNBSF): infront == 0 @@ -15224,7 +15613,7 @@ if (un->un_pos.pmode == logical) { ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "st_backward_space_files: mt_op=%x count=%x" + "st_backward_space_files: mt_op=%x count=%"PRIx64 "lgclblkno=%"PRIx64"\n", infront?MTBSF:MTNBSF, count, un->un_pos.lgclblkno); @@ -15248,7 +15637,8 @@ } ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "st_backward_space_files: mt_op=%x count=%x fileno=%x blkno=%x\n", + "st_backward_space_files: mt_op=%x count=%"PRIx64 + "fileno=%x blkno=%x\n", infront?MTBSF:MTNBSF, count, un->un_pos.fileno, un->un_pos.blkno); @@ -15301,7 +15691,8 @@ */ end_fileno = -(count + skip_cnt); ST_DEBUG6(ST_DEVINFO, st_label, SCSI_DEBUG, - "skip_cnt=%x, tmp=%x\n", skip_cnt, end_fileno); + "skip_cnt=%"PRIx64", tmp=%"PRIx64"\n", + skip_cnt, end_fileno); if (st_cmd(un, SCMD_SPACE, Fmk(end_fileno), SYNC_CMD)) { ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG, "st_backward_space_files:EIO:back space fm failed"); @@ -15319,7 +15710,7 @@ * If we have to space forward, do so... */ ST_DEBUG6(ST_DEVINFO, st_label, SCSI_DEBUG, - "space forward skip_cnt=%x, rval=%x\n", skip_cnt, rval); + "space forward skip_cnt=%"PRIx64", rval=%x\n", skip_cnt, rval); if (rval == 0 && skip_cnt) { if (st_cmd(un, SCMD_SPACE, Fmk(skip_cnt), SYNC_CMD)) { @@ -15350,14 +15741,14 @@ } static int -st_mtnbsf_ioctl(struct scsi_tape *un, int count) +st_mtnbsf_ioctl(struct scsi_tape *un, int64_t count) { int rval; ST_FUNC(ST_DEVINFO, st_mtnbsf_ioctl); ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "nbsf: count=%x, eof=%x\n", count, un->un_pos.eof); + "nbsf: count=%"PRIx64", eof=%x\n", count, un->un_pos.eof); if (un->un_pos.pmode == legacy) { /* @@ -15393,7 +15784,7 @@ } ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "mtnbsf: count=%x, eof=%x\n", count, un->un_pos.eof); + "mtnbsf: count=%"PRIx64", eof=%x\n", count, un->un_pos.eof); if (count <= 0) { rval = st_forward_space_files(un, -count); @@ -15404,12 +15795,12 @@ } static int -st_mtbsr_ioctl(struct scsi_tape *un, int num) +st_mtbsr_ioctl(struct scsi_tape *un, int64_t num) { ST_FUNC(ST_DEVINFO, st_mtbsr_ioctl); ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG, - "bsr: count=%x, eof=%x\n", num, un->un_pos.eof); + "bsr: count=%"PRIx64", eof=%x\n", num, un->un_pos.eof); if (un->un_pos.pmode == legacy) { /* @@ -15474,7 +15865,7 @@ } static int -st_mtfsfm_ioctl(struct scsi_tape *un, int cnt) +st_mtfsfm_ioctl(struct scsi_tape *un, int64_t cnt) { int rval; @@ -15500,7 +15891,7 @@ } static int -st_mtbsfm_ioctl(struct scsi_tape *un, int cnt) +st_mtbsfm_ioctl(struct scsi_tape *un, int64_t cnt) { int rval; @@ -15938,18 +16329,18 @@ st_handle_hex_media_id(struct scsi_tape *un, void *pnt, int size) { int result; - int newsize = (size + 1) << 1; + int newsize = (size << 1) + 3; /* extra for leading 0x and null term */ int i; - char byte; + uchar_t byte; char *format; - char *data = (char *)pnt; + uchar_t *data = (uchar_t *)pnt; char *buf = kmem_alloc(newsize, KM_SLEEP); ST_FUNC(ST_DEVINFO, st_handle_hex_media_id); (void) sprintf(buf, "0x"); for (i = 0; i < size; i++) { - byte = (uchar_t)data[i]; + byte = data[i]; if (byte < 0x10) format = "0%x"; else @@ -16035,7 +16426,7 @@ buf = kmem_alloc(size, KM_SLEEP); cdb[0] = (char)SCMD_SVC_ACTION_IN_G5; - cdb[1] = 1; /* READ MEDIA SERIAL NUMBER */ + cdb[1] = SSVC_ACTION_READ_MEDIA_SERIAL; cdb[2] = 0; cdb[3] = 0; cdb[4] = 0; @@ -16224,6 +16615,7 @@ return (JUST_RETURN); /* release calling thread */ } + static void st_recov_ret(struct scsi_tape *un, st_err_info *errinfo, errstate err) { @@ -16234,6 +16626,9 @@ ST_FUNC(ST_DEVINFO, st_recov_ret); ASSERT(MUTEX_HELD(&un->un_sd->sd_mutex)); +#if !defined(lint) + _NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(&un->un_sd->sd_mutex)) +#endif bp = errinfo->ei_failing_bp; kmem_free(errinfo, ST_ERR_INFO_SIZE); @@ -16262,10 +16657,12 @@ break; } + st_bioerror(bp, error_number); st_done_and_mutex_exit(un, bp); } + static void st_recover(void *arg) { @@ -16303,9 +16700,12 @@ rval = st_test_path_to_device(un); + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, + "st_recover called with %s, TUR returned %d\n", + errstatenames[errinfo->ei_error_type], rval); /* * If the drive responed to the TUR lets try and get it to sync - * any data it have in the buffer. + * any data it might have in the buffer. */ if (rval == 0 && rcv->cmd_attrib->chg_tape_data) { (void) st_rcmd(un, SCMD_WRITE_FILE_MARK, 0, SYNC_CMD); @@ -16313,49 +16713,63 @@ switch (errinfo->ei_error_type) { case ATTEMPT_RETRY: case COMMAND_TIMEOUT: - ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, - "st_recover called with COMMAND_TIMEOUT, TUR returned %d\n", - rval); - if (rval != 0) { - /* ping failed, we're done. */ + case DEVICE_RESET: + case PATH_FAILED: + /* + * For now if we can't talk to the device we are done. + * If the drive is reserved we can try to get it back. + */ + if (rval != 0 && rval != EACCES) { st_recov_ret(un, errinfo, COMMAND_DONE_ERROR); return; } /* - * If a reset occured fall through. - */ - if (un->un_unit_attention_flags == 0) { - break; - } - /* FALLTHROUGH */ - case DEVICE_RESET: - ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, - "st_recover called with DEVICE_RESET, TUR returned %d\n", - rval); - /* - * For now if we can't talk to the device we are done. - */ + * If scsi II lost reserve try and get it back. + */ + if ((((un->un_rsvd_status & + (ST_LOST_RESERVE | ST_APPLICATION_RESERVATIONS)) == + ST_LOST_RESERVE)) && + (errinfo->ei_failed_pkt.pkt_cdbp[0] != SCMD_RELEASE)) { + rval = st_reserve_release(un, ST_RESERVE, + st_uscsi_rcmd); + if (rval != 0) { + if (st_take_ownership(un, st_uscsi_rcmd) != 0) { + st_recov_ret(un, errinfo, + COMMAND_DONE_EACCES); + return; + } + } + un->un_rsvd_status |= ST_RESERVE; + un->un_rsvd_status &= ~(ST_RELEASE | ST_LOST_RESERVE | + ST_RESERVATION_CONFLICT | ST_INITIATED_RESET); + } + rval = st_check_mode_for_change(un, st_uscsi_rcmd); + if (rval) { + rval = st_gen_mode_select(un, st_uscsi_rcmd, + un->un_mspl, sizeof (struct seq_mode)); + } if (rval) { st_recov_ret(un, errinfo, COMMAND_DONE_ERROR); return; } - - if ((un->un_rsvd_status & ST_LOST_RESERVE) && - (errinfo->ei_failed_pkt.pkt_cdbp[0] != SCMD_RELEASE)) { - rval = st_reserve_release(un, ST_RESERVE, - st_uscsi_rcmd); - if (rval == 0) { - un->un_rsvd_status |= ST_RESERVE; - un->un_rsvd_status &= ~(ST_RELEASE | - ST_LOST_RESERVE | ST_RESERVATION_CONFLICT | - ST_INITIATED_RESET); - } else { - st_recov_ret(un, errinfo, COMMAND_DONE_EACCES); - return; - } + break; + case DEVICE_TAMPER: + /* + * Check if the ASC/ASCQ says mode data has changed. + */ + if ((errinfo->ei_failing_status.sts_sensedata.es_add_code == + 0x2a) && + (errinfo->ei_failing_status.sts_sensedata.es_qual_code == + 0x01)) { + /* + * See if mode sense changed. + */ rval = st_check_mode_for_change(un, st_uscsi_rcmd); if (rval) { + /* + * If so change it back. + */ rval = st_gen_mode_select(un, st_uscsi_rcmd, un->un_mspl, sizeof (struct seq_mode)); } @@ -16364,51 +16778,6 @@ return; } } - break; - case PATH_FAILED: - ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, - "st_recover called with PATH_FAILED, TUR returned %d\n", - rval); - if (rval != 0) { - /* ping failed, we're done. */ - st_recov_ret(un, errinfo, COMMAND_DONE_ERROR); - return; - } - break; - case DEVICE_TAMPER: - ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, - "st_recover called with DEVICE_TAMPER, TUR returned %d\n", - rval); - /* - * Check if the ASC/ASCQ says mode data has changed. - */ - if (errinfo->ei_failing_status.sts_sensedata.es_add_code == - 0x2a && - errinfo->ei_failing_status.sts_sensedata.es_qual_code == - 0x01) { - /* - * See if mode sense changed. - */ - rval = st_check_mode_for_change(un, st_uscsi_rcmd); - /* - * if not cross your fingers and go for it. - */ - if (rval == 0) { - st_recov_ret(un, errinfo, COMMAND_DONE); - return; - } - /* - * If so change it back. - */ - rval = st_gen_mode_select(un, st_uscsi_rcmd, - un->un_mspl, sizeof (struct seq_mode)); - if (rval) { - st_recov_ret(un, errinfo, COMMAND_DONE_ERROR); - } else { - st_recov_ret(un, errinfo, COMMAND_DONE); - } - return; - } /* * if we have a media id and its not bogus. * Check to see if it the same. @@ -16423,13 +16792,24 @@ break; default: ST_DEBUG(ST_DEVINFO, st_label, CE_PANIC, - "Unhandled error type 0x%x in st_recover()\n", com); - } - - /* - * if command is retriable retry it - */ - if (rcv->cmd_attrib->retriable) { + "Unhandled error type %s in st_recover() 0x%x\n", + errstatenames[errinfo->ei_error_type], com); + } + + /* + * if command is retriable retry it. + * Special case here. The command attribute for SCMD_REQUEST_SENSE + * does not say that it is retriable. That because if you reissue a + * request sense and the target responds the sense data will have + * been consumed and no long be valid. If we get a busy status on + * request sense while the state is ST_STATE_SENSING this will + * reissue that pkt. + * + * XXX If this request sense gets sent to a different port then + * the original command that failed was sent on it will not get + * valid sense data for that command. + */ + if (rcv->cmd_attrib->retriable || un->un_rqs_bp == bp) { status = st_recover_reissue_pkt(un, &errinfo->ei_failed_pkt); /* @@ -16472,7 +16852,7 @@ struct scsi_tape *un; struct buf *bp; recov_info *rcv; - errstate action = COMMAND_DONE; + errstate action = COMMAND_DONE_ERROR; int timout = ST_TRAN_BUSY_TIMEOUT; /* short (default) timeout */ /* @@ -16499,13 +16879,20 @@ case CMD_CMPLT: if (un->un_arq_enabled && pkt->pkt_state & STATE_ARQ_DONE) { action = st_handle_autosense(un, bp, &rcv->pos); - } else if (*pkt->pkt_scbp & (STATUS_BUSY | STATUS_CHECK)) { + } else if ((SCBP(pkt)->sts_busy) || + (SCBP(pkt)->sts_chk) || + (SCBP(pkt)->sts_vu7)) { action = st_check_error(un, pkt); + } else { + action = COMMAND_DONE; } break; case CMD_TIMEOUT: action = COMMAND_TIMEOUT; break; + case CMD_TRAN_ERR: + action = QUE_COMMAND; + break; default: ST_DEBUG(ST_DEVINFO, st_label, CE_PANIC, "pkt_reason not handled yet %s", @@ -16513,6 +16900,23 @@ action = COMMAND_DONE_ERROR; } + /* + * check for undetected path failover. + */ + if ((un->un_multipath) && + (un->un_last_path_instance != pkt->pkt_path_instance)) { + if (un->un_state > ST_STATE_OPENING) { + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, + "Failover detected in recovery, action is %s\n", + errstatenames[action]); + } + un->un_last_path_instance = pkt->pkt_path_instance; + } + + ST_RECOV(ST_DEVINFO, st_label, CE_WARN, + "Recovery call back got %s status on %s\n", + errstatenames[action], st_print_scsi_cmd(pkt->pkt_cdbp[0])); + switch (action) { case COMMAND_DONE: break; @@ -16521,6 +16925,10 @@ bioerror(bp, EACCES); break; + case COMMAND_DONE_ERROR_RECOVERED: /* XXX maybe wrong */ + ASSERT(0); + break; + case COMMAND_TIMEOUT: case COMMAND_DONE_ERROR: bioerror(bp, EIO); @@ -16528,6 +16936,7 @@ case DEVICE_RESET: case QUE_BUSY_COMMAND: + case PATH_FAILED: /* longish timeout */ timout = ST_STATUS_BUSY_TIMEOUT; /* FALLTHRU */ @@ -16972,7 +17381,8 @@ static int st_test_path_to_device(struct scsi_tape *un) { - int rval; + int rval = 0; + int limit = st_retry_count; ST_FUNC(ST_DEVINFO, st_test_path_to_device); @@ -16980,8 +17390,19 @@ * XXX Newer drives may not RESEVATION CONFLICT a TUR. */ do { + if (rval != 0) { + mutex_exit(ST_MUTEX); + delay(drv_usectohz(1000000)); + mutex_enter(ST_MUTEX); + } rval = st_rcmd(un, SCMD_TEST_UNIT_READY, 0, SYNC_CMD); - } while (rval == DEVICE_RESET); + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, + "ping TUR returned 0x%x", rval); + limit--; + } while (((rval == EACCES) || (rval == EBUSY)) && limit); + + if (un->un_status == KEY_NOT_READY || un->un_mediastate == MTIO_EJECTED) + rval = 0; return (rval); } @@ -16996,6 +17417,7 @@ { int rval; struct uscsi_cmd cmd; + struct scsi_arq_status status; char cdb[CDB_GROUP1]; ST_FUNC(ST_DEVINFO, st_recovery_read_pos); @@ -17009,13 +17431,15 @@ cdb[5] = 0; cdb[6] = 0; cdb[7] = 0; - cdb[8] = (type == EXT_POS) ? 28 : 0; + cdb[8] = (type == EXT_POS) ? 28 : 0; cdb[9] = 0; - cmd.uscsi_flags = USCSI_READ; + cmd.uscsi_flags = USCSI_READ | USCSI_RQENABLE; cmd.uscsi_timeout = un->un_dp->non_motion_timeout; cmd.uscsi_cdb = cdb; cmd.uscsi_cdblen = sizeof (cdb); + cmd.uscsi_rqlen = sizeof (status); + cmd.uscsi_rqbuf = (caddr_t)&status; cmd.uscsi_bufaddr = (caddr_t)raw; switch (type) { case SHORT_POS: @@ -17047,13 +17471,39 @@ ST_FUNC(ST_DEVINFO, st_recovery_get_position); - rval = st_recovery_read_pos(un, type, raw); - if (rval != 0) { - return (rval); - } - rval = st_interpret_read_pos(un, read, type, sizeof (read_pos_data_t), - (caddr_t)raw, 1); - + do { + rval = st_recovery_read_pos(un, type, raw); + if (rval != 0) { + switch (type) { + case SHORT_POS: + type = NO_POS; + break; + + case LONG_POS: + type = EXT_POS; + break; + + case EXT_POS: + type = SHORT_POS; + break; + + default: + type = LONG_POS; + break; + + } + } else { + if (type != un->un_read_pos_type) { + un->un_read_pos_type = type; + } + break; + } + } while (type != NO_POS); + + if (rval == 0) { + rval = st_interpret_read_pos(un, read, type, + sizeof (read_pos_data_t), (caddr_t)raw, 1); + } return (rval); } @@ -17104,26 +17554,54 @@ if (cmd_att->recov_pos_type == POS_EXPECTED) { uint32_t count; int64_t difference; - - /* At expected? */ - if (read->lgclblkno == ei->ei_expected_pos.lgclblkno) { - ST_RECOV(ST_DEVINFO, st_label, SCSI_DEBUG, - "Found drive to be at expected position\n"); - return (0); /* Good */ - } + uchar_t reposition = 0; + ASSERT(cmd_att->get_cnt); count = cmd_att->get_cnt(ei->ei_failed_pkt.pkt_cdbp); - ST_RECOV(ST_DEVINFO, st_label, SCSI_DEBUG, + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, "Got count from CDB and it was %d\n", count); + + /* + * At expected? + */ + if (read->lgclblkno == ei->ei_expected_pos.lgclblkno) { + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, + "Found drive to be at expected position\n"); + + /* + * If the command should move tape and it got a busy + * it shouldn't be in the expected position. + */ + if (ei->ei_failing_status.sts_status.sts_busy != 0) { + reposition = 1; + + /* + * If the command doesn't transfer data should be good. + */ + } else if (cmd_att->transfers_data == TRAN_NONE) { + return (0); /* Good */ + + /* + * Command transfers data, should have done so. + */ + } else if (ei->ei_failed_pkt.pkt_state & + STATE_XFERRED_DATA) { + return (0); /* Good */ + } else { + reposition = 1; + } + } + if (cmd_att->chg_tape_direction == DIR_FORW) { difference = ei->ei_expected_pos.lgclblkno - read->lgclblkno; - ST_RECOV(ST_DEVINFO, st_label, SCSI_DEBUG, + + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, "difference between expected and actual is %" PRId64"\n", difference); - if (count == difference) { - ST_RECOV(ST_DEVINFO, st_label, SCSI_DEBUG, + if (count == difference && reposition == 0) { + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, "Found failed FORW command, retrying\n"); return (EAGAIN); } @@ -17142,20 +17620,24 @@ ei->ei_expected_pos.partition); if (rval == 0) { ST_RECOV(ST_DEVINFO, st_label, - SCSI_DEBUG, "reestablished FORW" + CE_NOTE, "reestablished FORW" " command retrying\n"); return (EAGAIN); } - /* This handles flushed read ahead on the drive */ + /* + * This handles flushed read ahead on the drive or + * an aborted read that presents as a busy and advanced + * the tape position. + */ } else if ((cmd_att->transfers_data == TRAN_READ) && - (difference < 0)) { + ((difference < 0) || (reposition == 1))) { rval = st_logical_block_locate(un, st_uscsi_rcmd, read, ei->ei_expected_pos.lgclblkno - count, ei->ei_expected_pos.partition); if (rval == 0) { ST_RECOV(ST_DEVINFO, st_label, - SCSI_DEBUG, "reestablished FORW" + CE_NOTE, "reestablished FORW" " read command retrying\n"); return (EAGAIN); } @@ -17168,23 +17650,23 @@ * The plot thickens. Now I am attempting to cover a * count of 1 and a differance of 2 on a write. */ - } else if (difference > count) { + } else if ((difference > count) || (reposition == 1)) { rval = st_logical_block_locate(un, st_uscsi_rcmd, read, ei->ei_expected_pos.lgclblkno - count, ei->ei_expected_pos.partition); if (rval == 0) { ST_RECOV(ST_DEVINFO, st_label, - SCSI_DEBUG, "reestablished FORW" + CE_NOTE, "reestablished FORW" " write command retrying\n"); return (EAGAIN); } - scsi_log(ST_DEVINFO, st_label, CE_NOTE, + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, "Seek to block %"PRId64" returned %d\n", ei->ei_expected_pos.lgclblkno - count, rval); } else { - scsi_log(ST_DEVINFO, st_label, CE_NOTE, + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, "Not expected transfers_data = %d " "difference = %"PRId64, cmd_att->transfers_data, difference); @@ -17197,11 +17679,11 @@ ASSERT(cmd_att->transfers_data != TRAN_WRTE); difference = read->lgclblkno - ei->ei_expected_pos.lgclblkno; - ST_RECOV(ST_DEVINFO, st_label, SCSI_DEBUG, + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, "difference between expected and actual is %" PRId64"\n", difference); - if (count == difference) { - ST_RECOV(ST_DEVINFO, st_label, SCSI_DEBUG, + if (count == difference && reposition == 0) { + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, "Found failed REVC command, retrying\n"); return (EAGAIN); } @@ -17213,25 +17695,25 @@ ei->ei_expected_pos.partition); if (rval == 0) { ST_RECOV(ST_DEVINFO, st_label, - SCSI_DEBUG, "reestablished REVC" + CE_NOTE, "reestablished REVC" " command retrying\n"); return (EAGAIN); } /* This handles read ahead in reverse direction */ } else if ((cmd_att->transfers_data == TRAN_READ) && - (difference < 0)) { + (difference < 0) || (reposition == 1)) { rval = st_logical_block_locate(un, st_uscsi_rcmd, read, ei->ei_expected_pos.lgclblkno - count, ei->ei_expected_pos.partition); if (rval == 0) { ST_RECOV(ST_DEVINFO, st_label, - SCSI_DEBUG, "reestablished REVC" + CE_NOTE, "reestablished REVC" " read command retrying\n"); return (EAGAIN); } } else { - scsi_log(ST_DEVINFO, st_label, CE_NOTE, + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, "Not expected transfers_data = %d " "difference = %"PRId64, cmd_att->transfers_data, difference); @@ -17246,7 +17728,7 @@ */ ASSERT(0); } - scsi_log(ST_DEVINFO, st_label, CE_NOTE, + ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, "Didn't find a recoverable position, Failing\n"); /* @@ -17302,7 +17784,9 @@ cmd_attribute const *attrib; recov_info *rcv = oldpkt->pkt_private; uint_t cdblen; + int queued = 0; int rval; + int flags = 0; int stat_size = (un->un_arq_enabled ? sizeof (struct scsi_arq_status) : 1); @@ -17328,6 +17812,7 @@ } else { pkt_bp = bp; } + /* * if this is a queued command make sure it the only one in the * run queue. @@ -17335,12 +17820,18 @@ if (bp != un->un_sbufp && bp != un->un_recov_buf) { ASSERT(un->un_runqf == un->un_runql); ASSERT(un->un_runqf == bp); + queued = 1; } cdblen = scsi_cdb_size[CDB_GROUPID(oldpkt->pkt_cdbp[0])]; + if (pkt_bp == un->un_rqs_bp) { + flags |= PKT_CONSISTENT; + stat_size = 1; + } + newpkt = scsi_init_pkt(ROUTE, NULL, pkt_bp, cdblen, - stat_size, rcv->privatelen, 0, NULL_FUNC, NULL); + stat_size, rcv->privatelen, flags, NULL_FUNC, NULL); if (newpkt == NULL) { ST_RECOV(ST_DEVINFO, st_label, CE_NOTE, "Reissue pkt scsi_init_pkt() failure\n"); @@ -17363,8 +17854,17 @@ newpkt->pkt_state = 0; newpkt->pkt_statistics = 0; + /* + * oldpkt passed in was a copy of the original. + * to distroy we need the address of the original. + */ oldpkt = BP_PKT(bp); + if (oldpkt == un->un_rqs) { + ASSERT(bp == un->un_rqs_bp); + un->un_rqs = newpkt; + } + SET_BP_PKT(bp, newpkt); scsi_destroy_pkt(oldpkt); @@ -17379,7 +17879,7 @@ return (COMMAND_DONE_ERROR); } mutex_exit(ST_MUTEX); - rval = st_handle_start_busy(un, bp, ST_TRAN_BUSY_TIMEOUT, 0); + rval = st_handle_start_busy(un, bp, ST_TRAN_BUSY_TIMEOUT, queued); mutex_enter(ST_MUTEX); if (rval) { return (COMMAND_DONE_ERROR); @@ -17594,6 +18094,12 @@ } static const cmd_attribute cmd_attributes[] = { + { SCMD_READ, + 1, 0, 1, 0, 0, DIR_FORW, TRAN_READ, POS_EXPECTED, + 0, 0, 0, st_get_cdb_g0_rw_count }, + { SCMD_WRITE, + 1, 0, 1, 1, 0, DIR_FORW, TRAN_WRTE, POS_EXPECTED, + 0, 0, 0, st_get_cdb_g0_rw_count }, { SCMD_TEST_UNIT_READY, 0, 1, 0, 0, 0, DIR_NONE, TRAN_NONE, POS_EXPECTED, 0, 0, 0 }, @@ -17606,12 +18112,6 @@ { SCMD_READ_BLKLIM, 0, 1, 0, 0, 0, DIR_NONE, TRAN_READ, POS_EXPECTED, 0, 0, 0 }, - { SCMD_READ, - 1, 0, 1, 0, 0, DIR_FORW, TRAN_READ, POS_EXPECTED, - 0, 0, 0, st_get_cdb_g0_rw_count }, - { SCMD_WRITE, - 1, 0, 1, 1, 0, DIR_FORW, TRAN_WRTE, POS_EXPECTED, - 0, 0, 0, st_get_cdb_g0_rw_count }, { SCMD_READ_G4, 1, 0, 1, 0, 1, DIR_FORW, TRAN_READ, POS_EXPECTED, 0, 0, 0, st_get_cdb_g5_rw_cnt, st_get_cdb_g4g5_cnt }, @@ -17791,7 +18291,7 @@ ST_FUNC(ST_DEVINFO, st_reset_notification); mutex_enter(ST_MUTEX); - un->un_unit_attention_flags = 2; + un->un_unit_attention_flags |= 2; if ((un->un_rsvd_status & (ST_RESERVE | ST_APPLICATION_RESERVATIONS)) == ST_RESERVE) { un->un_rsvd_status |= ST_LOST_RESERVE;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/sys/scsi/adapters/scsi_vhci_tpgs.h Mon Jun 23 13:41:43 2008 -0700 @@ -0,0 +1,58 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#ifndef _SYS_SCSI_ADAPTERS_SCSI_VHCI_TPGS_H +#define _SYS_SCSI_ADAPTERS_SCSI_VHCI_TPGS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * max number of retries for std failover to complete where the ping + * command is failing due to transport errors or commands being rejected by + * std. + * STD_FO_MAX_RETRIES takes into account the case where CMD_CMPLTs but + * std takes time to complete the failover. + */ +#define STD_FO_MAX_CMD_RETRIES 3 + +#define STD_ACTIVE_OPTIMIZED 0x0 +#define STD_ACTIVE_NONOPTIMIZED 0x1 +#define STD_STANDBY 0x2 +#define STD_UNAVAILABLE 0x3 +#define STD_TRANSITIONING 0xf + +#define STD_SCSI_ASC_STATE_TRANS 0x04 +#define STD_SCSI_ASCQ_STATE_TRANS_FAIL 0x0A +#define STD_SCSI_ASC_STATE_CHG 0x2A +#define STD_SCSI_ASCQ_STATE_CHG_SUCC 0x06 +#define STD_SCSI_ASCQ_STATE_CHG_FAILED 0x07 +#define STD_SCSI_ASC_INVAL_PARAM_LIST 0x26 +#define STD_SCSI_ASC_INVAL_CMD_OPCODE 0x20 +#define STD_LOGICAL_UNIT_NOT_ACCESSIBLE 0x04 +#define STD_TGT_PORT_UNAVAILABLE 0x0C + +extern int vhci_tpgs_get_target_fo_mode(struct scsi_device *sd, int *mode, + int *state, int *xlf_capable, int *preferred); + +#endif /* _SYS_SCSI_ADAPTERS_SCSI_VHCI_TPGS_H */
--- a/usr/src/uts/common/sys/scsi/generic/commands.h Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/sys/scsi/generic/commands.h Mon Jun 23 13:41:43 2008 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -330,17 +330,13 @@ #define SCMD_LOCATE_G4 0x92 /* - * Define for Group 5 command. + * Group 5 commands. */ #define SCMD_GROUP5 0xA0 #define SCMD_REPORT_LUNS 0xA0 #define SCMD_SECURITY_PROTO_IN 0xA2 #define SCMD_MAINTENANCE_IN 0xA3 #define SCMD_MAINTENANCE_OUT 0xA4 -#define SCMD_SET_DEVICE_IDENTIFIER 0x06 -#define SCMD_SET_PRIORITY 0x0e -#define SCMD_SET_TARGET_PORT_GROUPS 0x0a -#define SCMD_SET_TIMESTAMP 0x0f #define SCMD_READ_G5 0xA8 #define SCMD_WRITE_G5 0xAA #define SCMD_SVC_ACTION_OUT_G5 0xA9 @@ -349,8 +345,27 @@ #define SCMD_VERIFY_G5 0xAF #define SCMD_SECURITY_PROTO_OUT 0xB5 +/* + * Group 5 Service Actions for Maintenance In (12) + */ +#define SSVC_ACTION_GET_TARGET_PORT_GROUPS 0x0a +#define SSVC_ACTION_GET_SUPPORTED_OPERATIONS 0x0c +#define SSVC_SCTION_GET_SUPPORTED_MANAGEMENT 0x0d +#define SSVC_ACTION_GET_TIMESTAMP 0x0f /* + * Group 5 Service Actions for Maintenance Out (12) + */ +#define SSVC_ACTION_SET_DEVICE_IDENTIFIER 0x06 +#define SSVC_ACTION_SET_PRIORITY 0x0e +#define SSVC_ACTION_SET_TARGET_PORT_GROUPS 0x0a +#define SSVC_ACTION_SET_TIMESTAMP 0x0f + +/* + * Group 5 Service Actions for Service Action In (12) + */ +#define SSVC_ACTION_READ_MEDIA_SERIAL 0x01 +/* * scsi_key_strings for SCMD_ definitions * NOTE: see SCSI_CMDS_KEY_STRINGS_CDIO in cdio.h for additional * command-to-string translations.
--- a/usr/src/uts/common/sys/scsi/generic/inquiry.h Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/sys/scsi/generic/inquiry.h Mon Jun 23 13:41:43 2008 -0700 @@ -73,8 +73,8 @@ uchar_t inq_len; /* additional length */ uchar_t : 4, /* reserved */ - inq_tpgs : 1, /* supports Target Port Group set */ - : 3; + inq_tpgs : 2, /* supports Target Port Group set */ + : 2; uchar_t inq_addr16 : 1, /* supports 16 bit wide SCSI addr */ inq_addr32 : 1, /* supports 32 bit wide SCSI addr */ inq_ackqreqq : 1, /* data tranfer on Q cable */ @@ -149,8 +149,8 @@ uchar_t inq_len; /* additional length */ - uchar_t : 3, /* reserved */ - inq_tpgs : 1, /* supports Target Port Group Set */ + uchar_t : 2, /* reserved */ + inq_tpgs : 2, /* supports Target Port Group Set */ : 4; uchar_t inq_bque : 1, /* combined with cmdque */
--- a/usr/src/uts/common/sys/scsi/generic/status.h Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/sys/scsi/generic/status.h Mon Jun 23 13:41:43 2008 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1996-1998 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _SYS_SCSI_GENERIC_STATUS_H @@ -99,6 +98,7 @@ #define STATUS_TERMINATED 0x22 #define STATUS_QFULL 0x28 #define STATUS_ACA_ACTIVE 0x30 +#define STATUS_TASK_ABORT 0x40 #ifdef __cplusplus }
--- a/usr/src/uts/common/sys/scsi/targets/stdef.h Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/common/sys/scsi/targets/stdef.h Mon Jun 23 13:41:43 2008 -0700 @@ -873,11 +873,15 @@ typedef struct { buf_t *cmd_bp; size_t privatelen; + int str_retry_cnt; + int pkt_retry_cnt; }pkt_info; typedef struct { buf_t *cmd_bp; size_t privatelen; + int str_retry_cnt; + int pkt_retry_cnt; tapepos_t pos; const cmd_attribute *cmd_attrib; }recov_info; @@ -963,7 +967,6 @@ st_states un_state; /* current state */ uchar_t un_status; /* status from last sense */ uchar_t un_retry_ct; /* retry count */ - uchar_t un_tran_retry_ct; /* transport retry count */ writablity un_read_only; /* RDWR, RDONLY, WORM, RDWORM */ uchar_t un_test_append; /* check writing at end of tape */ uchar_t un_arq_enabled; /* auto request sense enabled */ @@ -1045,6 +1048,8 @@ #endif tapepos_t un_running; uchar_t un_unit_attention_flags; + uchar_t un_multipath; + ulong_t un_last_path_instance; }; typedef int (*bufunc_t)(struct scsi_tape *, int, int64_t, int); @@ -1269,7 +1274,7 @@ * 10 seconds is what we'll wait if we get a Busy Status back */ #define ST_STATUS_BUSY_TIMEOUT 10*hz /* seconds Busy Waiting */ -#define ST_TRAN_BUSY_TIMEOUT 1*hz /* seconds retry on TRAN_BSY */ +#define ST_TRAN_BUSY_TIMEOUT 4*hz /* seconds retry on TRAN_BSY */ #define ST_INTERRUPT_CONTEXT 1 #define ST_START_CONTEXT 2 @@ -1325,8 +1330,9 @@ #define BSD_BEHAVIOR (getminor(un->un_dev) & MT_BSD) #define SVR4_BEHAVIOR ((getminor(un->un_dev) & MT_BSD) == 0) +#define ST_STATUS_MASK (STATUS_MASK | STATUS_TASK_ABORT) #define SCBP(pkt) ((struct scsi_status *)(pkt)->pkt_scbp) -#define SCBP_C(pkt) ((*(pkt)->pkt_scbp) & STATUS_MASK) +#define SCBP_C(pkt) ((*(pkt)->pkt_scbp) & ST_STATUS_MASK) #define CDBP(pkt) ((union scsi_cdb *)(pkt)->pkt_cdbp) #define BP_PKT(bp) ((struct scsi_pkt *)(bp)->av_back) #define SET_BP_PKT(bp, pkt) ((bp)->av_back = (struct buf *)(pkt)) @@ -1355,7 +1361,16 @@ * carried in the next 2 bits. The remaining bits a signed count of * how many of that direction and type to do. */ -#if (SIZE_MAX < UINT64_MAX) + +#if (defined(__lock_lint)) +/* + * This is a workaround for warlock not being able to parse an #ULL constant. + */ +#undef UINT64_MAX +#define UINT64_MAX (18446744073709551615UL) +#endif /* __lock_lint */ + +#if (defined(__lock_lint) || (SIZE_MAX < UINT64_MAX)) #define SP_BLK UINT32_C(0x00000000) #define SP_FLM UINT32_C(0x20000000) @@ -1424,7 +1439,11 @@ #define DEBUGGING\ ((scsi_options & SCSI_DEBUG_TGT) || (st_debug & 0x7)) -#define ST_DARGS(d) st_label, ((d == st_lastdev || d == 0) ?CE_CONT:CE_NOTE) +#define DEBLOCK(d) int lev = CE_NOTE; mutex_enter(&st_debug_mutex); \ + if (d == st_lastdev || d == 0) lev = CE_CONT; mutex_exit(&st_debug_mutex); + +#define DEBUNLOCK(d) mutex_enter(&st_debug_mutex); \ + if (d != 0 && d != st_lastdev) st_lastdev = d; mutex_exit(&st_debug_mutex); /* initialization */ #define ST_DEBUG1 if ((st_debug & 0x7) >= 1) scsi_log @@ -1448,30 +1467,27 @@ #define ST_RECOV if (st_debug & 0x8) scsi_log /* Entry Point Functions */ -#define ST_ENTR(d, fn)\ - if (st_debug & 0x10) { scsi_log(d, ST_DARGS(d), #fn);\ - if (d != 0 && d != st_lastdev) st_lastdev = d; } +#define ST_ENTR(d, fn) if (st_debug & 0x10) { DEBLOCK(d) \ + scsi_log(d, st_label, lev, #fn); DEBUNLOCK(d) } /* Non-Entry Point Functions */ -#define ST_FUNC(d, fn)\ - if (st_debug & 0x20) { scsi_log(d, ST_DARGS(d), #fn);\ - if (d != 0 && d != st_lastdev) st_lastdev = d; } +#define ST_FUNC(d, fn) if (st_debug & 0x20) { DEBLOCK(d) \ + scsi_log(d, st_label, lev, #fn); DEBUNLOCK(d) } /* Space Information */ #define ST_SPAC if (st_debug & 0x40) scsi_log /* CDB's sent */ -#define ST_CDB(d, cmnt, cdb) if (st_debug & 0x180) { \ - st_print_cdb(d, ST_DARGS(d), cmnt, cdb);\ - if (d != 0 && d != st_lastdev) st_lastdev = d; } +#define ST_CDB(d, cmnt, cdb) if (st_debug & 0x180) { DEBLOCK(d) \ + st_print_cdb(d, st_label, lev, cmnt, cdb); DEBUNLOCK(d) } + /* sense data */ -#define ST_SENSE(d, cmnt, sense, size) if (st_debug & 0x200) { \ - st_clean_print(d, ST_DARGS(d), cmnt, sense, size);\ - if (d != 0 && d != st_lastdev) st_lastdev = d; } +#define ST_SENSE(d, cmnt, sense, size) if (st_debug & 0x200) { DEBLOCK(d) \ + st_clean_print(d, st_label, lev, cmnt, sense, size); DEBUNLOCK(d) } + /* position data */ -#define ST_POS(d, cmnt, pdata) if (st_debug & 0x400) { \ - st_print_position(d, ST_DARGS(d), cmnt, pdata);\ - if (d != 0 && d != st_lastdev) st_lastdev = d; } +#define ST_POS(d, cmnt, pdata) if (st_debug & 0x400) { DEBLOCK(d) \ + st_print_position(d, st_label, lev, cmnt, pdata); DEBUNLOCK(d) } #else
--- a/usr/src/uts/intel/Makefile.intel.shared Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/intel/Makefile.intel.shared Mon Jun 23 13:41:43 2008 -0700 @@ -573,6 +573,8 @@ MISC_KMODS += scsi_vhci_f_sym MISC_KMODS += scsi_vhci_f_tpgs MISC_KMODS += scsi_vhci_f_asym_sun +MISC_KMODS += scsi_vhci_f_tape +MISC_KMODS += scsi_vhci_f_tpgs_tape $(CLOSED_BUILD)CLOSED_MISC_KMODS += amsrc1 $(CLOSED_BUILD)CLOSED_MISC_KMODS += klmmod klmops
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/scsi_vhci_f_tape/Makefile Mon Jun 23 13:41:43 2008 -0700 @@ -0,0 +1,88 @@ +# +# 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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of misc/scsi_vhci/scsi_vhci_f_tape +# intel architecture dependent +# + +# +# Paths to the base of the uts directory trees +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = scsi_vhci_f_tape +OBJECTS = $(SCSI_VHCI_F_TAPE_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SCSI_VHCI_F_TAPE_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_SCSI_VHCI_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets. +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Note dependancy on misc/scsi. +# +LDFLAGS += -dy -N"misc/scsi" -N"drv/scsi_vhci" + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/scsi_vhci_f_tpgs_tape/Makefile Mon Jun 23 13:41:43 2008 -0700 @@ -0,0 +1,88 @@ +# +# 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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of misc/scsi_vhci/scsi_vhci_f_tpgs_tape +# intel architecture dependent +# + +# +# Paths to the base of the uts directory trees +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = scsi_vhci_f_tpgs_tape +OBJECTS = $(SCSI_VHCI_F_TPGS_TAPE_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SCSI_VHCI_F_TPGS_TAPE_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_SCSI_VHCI_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets. +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Note dependancy on misc/scsi. +# +LDFLAGS += -dy -N"misc/scsi" -N"drv/scsi_vhci" + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/sparc/Makefile.sparc.shared Mon Jun 23 13:16:14 2008 -0700 +++ b/usr/src/uts/sparc/Makefile.sparc.shared Mon Jun 23 13:41:43 2008 -0700 @@ -390,6 +390,7 @@ MISC_KMODS += pcicfg.e fcodem fcpci MISC_KMODS += scsi_vhci_f_sym scsi_vhci_f_tpgs scsi_vhci_f_asym_sun MISC_KMODS += scsi_vhci_f_sym_hds +MISC_KMODS += scsi_vhci_f_tape scsi_vhci_f_tpgs_tape $(CLOSED_BUILD)CLOSED_MISC_KMODS += amsrc1 $(CLOSED_BUILD)CLOSED_MISC_KMODS += klmmod klmops
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sparc/scsi_vhci_f_tape/Makefile Mon Jun 23 13:41:43 2008 -0700 @@ -0,0 +1,88 @@ +# +# 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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of misc/scsi_vhci/scsi_vhci_f_tape +# sparc architecture dependent +# + +# +# Paths to the base of the uts directory trees +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = scsi_vhci_f_tape +OBJECTS = $(SCSI_VHCI_F_TAPE_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SCSI_VHCI_F_TAPE_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_SCSI_VHCI_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +# +# Define targets. +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Note dependancy on misc/scsi. +# +LDFLAGS += -dy -N"misc/scsi" -N"drv/scsi_vhci" + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sparc/scsi_vhci_f_tpgs_tape/Makefile Mon Jun 23 13:41:43 2008 -0700 @@ -0,0 +1,88 @@ +# +# 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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of misc/scsi_vhci/scsi_vhci_f_tpgs_tape +# sparc architecture dependent +# + +# +# Paths to the base of the uts directory trees +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = scsi_vhci_f_tpgs_tape +OBJECTS = $(SCSI_VHCI_F_TPGS_TAPE_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SCSI_VHCI_F_TPGS_TAPE_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_SCSI_VHCI_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +# +# Define targets. +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Note dependancy on misc/scsi. +# +LDFLAGS += -dy -N"misc/scsi" -N"drv/scsi_vhci" + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ