summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorDavid Zhang - Sun Microsystems - Beijing China <David.Zhang@Sun.COM>2008-09-12 17:58:24 +0800
committerDavid Zhang - Sun Microsystems - Beijing China <David.Zhang@Sun.COM>2008-09-12 17:58:24 +0800
commit9e1c849eae563842996c64c805047e840c75fc79 (patch)
tree2075c2b16fad3b62391bdd18f6e36a04a133d067 /usr/src
parentcdc64593cc1046229f4ac4daf5ead688b5efe6eb (diff)
downloadillumos-gate-9e1c849eae563842996c64c805047e840c75fc79.tar.gz
PSARC 2008/558 SCSI Disk Device-as-Detector Diagnosis (phase3)
6660663 SD driver need to be hardened for serial SCSI interface 6701036 FMA telemetry in SD target drivers 6627579 sd: USCSI_SILENT during attach/open filters all device failure information
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fm/dicts/DISK.dict5
-rw-r--r--usr/src/cmd/fm/dicts/DISK.po35
-rw-r--r--usr/src/cmd/fm/eversholt/files/common/disk.esc124
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_com3
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/io/scsi/impl/scsi_fm.c137
-rw-r--r--usr/src/uts/common/io/scsi/impl/scsi_subr.c203
-rw-r--r--usr/src/uts/common/io/scsi/targets/sd.c2600
-rw-r--r--usr/src/uts/common/sys/Makefile1
-rw-r--r--usr/src/uts/common/sys/scsi/impl/services.h14
-rw-r--r--usr/src/uts/common/sys/scsi/impl/uscsi.h8
-rw-r--r--usr/src/uts/common/sys/scsi/scsi_fm.h49
-rw-r--r--usr/src/uts/common/sys/scsi/scsi_types.h2
-rw-r--r--usr/src/uts/common/sys/scsi/targets/sddef.h191
14 files changed, 2882 insertions, 492 deletions
diff --git a/usr/src/cmd/fm/dicts/DISK.dict b/usr/src/cmd/fm/dicts/DISK.dict
index 8c760cb238..93df523b9a 100644
--- a/usr/src/cmd/fm/dicts/DISK.dict
+++ b/usr/src/cmd/fm/dicts/DISK.dict
@@ -1,5 +1,5 @@
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
@@ -21,7 +21,6 @@
#
# CDDL HEADER END
#
-#ident "%Z%%M% %I% %E% SMI"
#
# DO NOT EDIT -- this file is generated by the Event Registry.
#
@@ -31,3 +30,5 @@ FMDICT: name=DISK version=1 maxkey=1 dictid=0x534b
fault.io.disk.predictive-failure=0
fault.io.disk.over-temperature=1
fault.io.disk.self-test-failure=2
+fault.io.scsi.cmd.disk.dev.rqs.derr=3
+fault.io.scsi.cmd.disk.dev.rqs.merr=4
diff --git a/usr/src/cmd/fm/dicts/DISK.po b/usr/src/cmd/fm/dicts/DISK.po
index 33c7b22af7..504285915b 100644
--- a/usr/src/cmd/fm/dicts/DISK.po
+++ b/usr/src/cmd/fm/dicts/DISK.po
@@ -1,5 +1,5 @@
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
@@ -21,7 +21,6 @@
#
# CDDL HEADER END
#
-#ident "%Z%%M% %I% %E% SMI"
#
# DO NOT EDIT -- this file is generated by the Event Registry.
#
@@ -73,3 +72,35 @@ msgid "DISK-8000-2J.impact"
msgstr "The disk has failed.\n"
msgid "DISK-8000-2J.action"
msgstr "Schedule a repair procedure to replace the affected disk.\nUse fmdump -v -u <EVENT_ID> to identify the disk.\n"
+#
+# code: DISK-8000-3E
+# keys: fault.io.scsi.cmd.disk.dev.rqs.derr
+#
+msgid "DISK-8000-3E.type"
+msgstr "Fault"
+msgid "DISK-8000-3E.severity"
+msgstr "Critical"
+msgid "DISK-8000-3E.description"
+msgstr "A non-recoverable hardware failure was detected by the device while performing a command.\n Refer to %s for more information."
+msgid "DISK-8000-3E.response"
+msgstr "The device may be offlined or degraded.\n"
+msgid "DISK-8000-3E.impact"
+msgstr "The device has failed. The service may have been lost or degraded.\n"
+msgid "DISK-8000-3E.action"
+msgstr "Ensure that the latest drivers and patches are installed. Schedule a repair procedure to replace the affected\ndevice. Use 'fmadm faulty' to find the affected disk.\n"
+#
+# code: DISK-8000-4Q
+# keys: fault.io.scsi.cmd.disk.dev.rqs.merr
+#
+msgid "DISK-8000-4Q.type"
+msgstr "Fault"
+msgid "DISK-8000-4Q.severity"
+msgstr "Critical"
+msgid "DISK-8000-4Q.description"
+msgstr "The command was terminated with a non-recovered error condition that may have been caused by a flaw in the media or an error in the recorded data. \n Refer to %s for more information."
+msgid "DISK-8000-4Q.response"
+msgstr "The device may be offlined or degraded.\n"
+msgid "DISK-8000-4Q.impact"
+msgstr "It is likely that continued operation will result in data corruption, which may eventually cause the loss of service or the service degradation.\n"
+msgid "DISK-8000-4Q.action"
+msgstr "Schedule a repair procedure to replace the affected device. Use 'fmadm faulty' to find the affected disk.\n"
diff --git a/usr/src/cmd/fm/eversholt/files/common/disk.esc b/usr/src/cmd/fm/eversholt/files/common/disk.esc
index 6316f1d9de..823c605690 100644
--- a/usr/src/cmd/fm/eversholt/files/common/disk.esc
+++ b/usr/src/cmd/fm/eversholt/files/common/disk.esc
@@ -19,17 +19,10 @@
* 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"
-
-/*
- * The disk DE provides a very simple 1-to-1 mapping between SCSI disk events
- * generated by the disk-transport fmd module, and the resulting faults.
- */
-
#pragma dictionary "DISK"
#define P disk
@@ -38,6 +31,121 @@ fru P;
asru P;
/*
+ * disk-as-detector: The disk-as-detector DE provides the mapping between
+ * ereports generated by a kernel disk driver sd(7D) and resulting faults.
+ */
+
+/*
+ * disk-as-detector: fault events.
+ */
+event fault.io.scsi.cmd.disk.dev.rqs.derr@P;
+event fault.io.scsi.cmd.disk.dev.rqs.merr@P;
+/*
+ * The uderr fault will be defined at some future time.
+ * event fault.io.scsi.cmd.disk.dev.uderr@P;
+ */
+
+/*
+ * disk-as-detector: upset events.
+ * NOTE: For now we define an upset to implement discard.
+ */
+event upset.io.scsi.cmd.disk.dev.rqs.derr@P;
+event upset.io.scsi.cmd.disk.dev.rqs.merr@P;
+event upset.io.scsi.cmd.disk.dev.uderr@P;
+event upset.io.scsi.cmd.disk.dev.serr@P;
+event upset.io.scsi.cmd.disk.tran@P;
+event upset.io.scsi.cmd.disk.recovered@P;
+
+/*
+ * disk-as-detector: ereports from the kernel.
+ *
+ * We don't know the topology for all scsi disks, but the kernel will always
+ * generate ereport telemetry assuming that we do. We define these ereports
+ * with 'discard_if_config_unknown=1', which permits ereports against things
+ * with unknown topology to be silently discarded. The ereport data is logged
+ * in either case, and can be viewed via 'fmdump -eV'.
+ */
+event ereport.io.scsi.cmd.disk.dev.rqs.derr@P, discard_if_config_unknown=1;
+event ereport.io.scsi.cmd.disk.dev.rqs.merr@P, discard_if_config_unknown=1;
+event ereport.io.scsi.cmd.disk.dev.serr@P, discard_if_config_unknown=1;
+event ereport.io.scsi.cmd.disk.dev.uderr@P, discard_if_config_unknown=1;
+event ereport.io.scsi.cmd.disk.recovered@P, discard_if_config_unknown=1;
+event ereport.io.scsi.cmd.disk.tran@P, discard_if_config_unknown=1;
+
+/*
+ * For some ereports we let the 'driver-assessment', communicated as part of
+ * the ereport payload, determine fault .vs. upset via propagation constraints.
+ */
+#define DRIVER_ASSESSMENT_FATAL \
+ (payloadprop_contains("driver-assessment", "fatal"))
+#define DRIVER_ASSESSMENT_NONFATAL (!DRIVER_ASSESSMENT_FATAL)
+
+/*
+ * disk-as-detector: propagations from faults(based on
+ * DRIVER_ASSESSMENT_FATAL).
+ * We need to set additional fault payloads to indicate fault details.
+ * The payload we may need are listed as following:
+ * fault.io.scsi.cmd.disk.dev.rqs.derr
+ * op_code, key, asc, ascq
+ * fault.io.scsi.cmd.disk.dev.rqs.merr
+ * op_code, key, asc, ascq, lba
+ */
+prop fault.io.scsi.cmd.disk.dev.rqs.derr@P->
+ ereport.io.scsi.cmd.disk.dev.rqs.derr@P{ DRIVER_ASSESSMENT_FATAL &&
+ setpayloadprop("key", payloadprop("key")) &&
+ setpayloadprop("asc", payloadprop("asc")) &&
+ setpayloadprop("ascq", payloadprop("ascq"))};
+
+prop fault.io.scsi.cmd.disk.dev.rqs.merr@P->
+ ereport.io.scsi.cmd.disk.dev.rqs.merr@P{ DRIVER_ASSESSMENT_FATAL &&
+ setpayloadprop("key", payloadprop("key")) &&
+ setpayloadprop("asc", payloadprop("asc")) &&
+ setpayloadprop("ascq", payloadprop("ascq")) &&
+ setpayloadprop("lba", payloadprop("lba"))};
+
+/*
+ * The uderr fault will be propagated at some future time.
+ * prop fault.io.scsi.cmd.disk.dev.uderr@P->
+ * ereport.io.scsi.cmd.disk.dev.uderr@P{ DRIVER_ASSESSMENT_FATAL };
+ */
+
+/*
+ * disk-as-detector: propagations from upsets(based on
+ * DRIVER_ASSESSMENT_NONFATAL).
+ */
+prop upset.io.scsi.cmd.disk.dev.rqs.derr@P->
+ ereport.io.scsi.cmd.disk.dev.rqs.derr@P{ DRIVER_ASSESSMENT_NONFATAL };
+
+prop upset.io.scsi.cmd.disk.dev.rqs.merr@P->
+ ereport.io.scsi.cmd.disk.dev.rqs.merr@P{ DRIVER_ASSESSMENT_NONFATAL };
+
+/*
+ * disk-as-detector: propagations from upsets(independent of
+ * driver-assessment)
+ */
+
+prop upset.io.scsi.cmd.disk.dev.serr@P->
+ ereport.io.scsi.cmd.disk.dev.serr@P;
+
+prop upset.io.scsi.cmd.disk.dev.uderr@P->
+ ereport.io.scsi.cmd.disk.dev.uderr@P;
+
+prop upset.io.scsi.cmd.disk.recovered@P->
+ ereport.io.scsi.cmd.disk.recovered@P;
+
+prop upset.io.scsi.cmd.disk.tran@P->
+ ereport.io.scsi.cmd.disk.tran@P;
+
+/*
+ * --------------------------------------
+ * The remainder of this file contains rules associated with the operation of
+ * cmd/fm/modules/common/disk-monitor/disk_monitor.c code.
+ *
+ * The disk DE provides a very simple 1-to-1 mapping between SCSI disk events
+ * generated by the disk-transport fmd module, and the resulting faults.
+ */
+
+/*
* Fault events.
*/
event fault.io.disk.over-temperature@P,
diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com
index cde6aeea56..c708ae29b4 100644
--- a/usr/src/pkgdefs/SUNWhea/prototype_com
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com
@@ -1182,11 +1182,12 @@ f none usr/include/sys/scsi/impl/usmp.h 644 root bin
f none usr/include/sys/scsi/scsi.h 644 root bin
f none usr/include/sys/scsi/scsi_address.h 644 root bin
f none usr/include/sys/scsi/scsi_ctl.h 644 root bin
-f none usr/include/sys/scsi/scsi_watch.h 644 root bin
+f none usr/include/sys/scsi/scsi_fm.h 644 root bin
f none usr/include/sys/scsi/scsi_params.h 644 root bin
f none usr/include/sys/scsi/scsi_pkt.h 644 root bin
f none usr/include/sys/scsi/scsi_resource.h 644 root bin
f none usr/include/sys/scsi/scsi_types.h 644 root bin
+f none usr/include/sys/scsi/scsi_watch.h 644 root bin
d none usr/include/sys/scsi/targets 755 root bin
f none usr/include/sys/scsi/targets/ses.h 644 root bin
f none usr/include/sys/scsi/targets/sesio.h 644 root bin
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 6b0d75c4b4..5da8fe4faa 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -669,7 +669,7 @@ USBSPRL_OBJS += usbser_pl2303.o pl2303_dsd.o
WC_OBJS += wscons.o
SCSI_OBJS += scsi_capabilities.o scsi_confsubr.o scsi_control.o \
- scsi_data.o scsi_hba.o scsi_reset_notify.o \
+ scsi_data.o scsi_fm.o scsi_hba.o scsi_reset_notify.o \
scsi_resource.o scsi_subr.o scsi_transport.o scsi_watch.o \
sas_transport.o
diff --git a/usr/src/uts/common/io/scsi/impl/scsi_fm.c b/usr/src/uts/common/io/scsi/impl/scsi_fm.c
new file mode 100644
index 0000000000..b4dad350f5
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/impl/scsi_fm.c
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+/*
+ * SCSI FMA implementation
+ */
+
+#include <sys/scsi/scsi_types.h>
+#include <sys/sunmdi.h>
+#include <sys/va_list.h>
+
+#include <sys/ddi_impldefs.h>
+
+/* consolidation private interface to generate dev scheme ereport */
+extern void fm_dev_ereport_postv(dev_info_t *dip, dev_info_t *eqdip,
+ const char *devpath, const char *minor_name, const char *devid,
+ const char *error_class, uint64_t ena, int sflag, va_list ap);
+extern char *mdi_pi_pathname_by_instance(int);
+
+#define FM_SCSI_CLASS "scsi"
+#define ERPT_CLASS_SZ sizeof (FM_SCSI_CLASS) + 1 + DDI_MAX_ERPT_CLASS + 1
+
+/*
+ * scsi_fm_init: Initialize fma capabilities and register with IO
+ * fault services.
+ */
+void
+scsi_fm_init(struct scsi_device *sd)
+{
+ dev_info_t *dip = sd->sd_dev;
+
+ /*
+ * fm-capable in driver.conf can be used to set fm_capabilities.
+ * If fm-capable is not defined, then the last argument passed to
+ * ddi_prop_get_int will be returned as the capabilities.
+ *
+ * NOTE: by default scsi_fm_capable sets DDI_FM_EREPORT_CAPABLE.
+ */
+ sd->sd_fm_capable = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fm-capable",
+ scsi_fm_capable);
+
+ /*
+ * Register capabilities with IO Fault Services. The capabilities
+ * set above may not be supported by the parent nexus, in that
+ * case some/all capability bits may be cleared.
+ *
+ * NOTE: iblock cookies are not important because scsi HBAs
+ * always interrupt below LOCK_LEVEL.
+ */
+ if (sd->sd_fm_capable != DDI_FM_NOT_CAPABLE)
+ ddi_fm_init(dip, &sd->sd_fm_capable, NULL);
+}
+
+/*
+ * scsi_fm_fini: un-register with IO fault services.
+ */
+void
+scsi_fm_fini(struct scsi_device *sd)
+{
+ dev_info_t *dip = sd->sd_dev;
+
+ if (sd->sd_fm_capable != DDI_FM_NOT_CAPABLE)
+ ddi_fm_fini(dip);
+}
+
+/*
+ *
+ * scsi_fm_erepot_post - Post an ereport.
+ */
+void
+scsi_fm_ereport_post(struct scsi_device *sd, int path_instance,
+ const char *error_class, uint64_t ena, char *devid, int sflag, ...)
+{
+ char class[ERPT_CLASS_SZ];
+ dev_info_t *dip = sd->sd_dev;
+ char *devpath, *minor_name;
+ va_list ap;
+
+ /* Add "scsi." as a prefix to the class */
+ (void) snprintf(class, ERPT_CLASS_SZ, "%s.%s",
+ FM_SCSI_CLASS, error_class);
+
+ /*
+ * Get the path: If pkt_path_instance is non-zero then the packet was
+ * sent to scsi_vhci. We return the pathinfo path_string associated
+ * with the path_instance path - which refers to the actual hardware.
+ */
+ if (path_instance)
+ devpath = mdi_pi_pathname_by_instance(path_instance);
+ else
+ devpath = NULL;
+
+ /*
+ * Set the minor_name to NULL. The block location of a media error
+ * is described by the 'lba' property. We use the 'lba' instead of
+ * the partition (minor_name) because the defect stays in the same
+ * place even when a repartition operation may result in the defect
+ * showing up in a different partition (minor_name). To support
+ * retire at the block/partition level, the user level retire agent
+ * should map the 'lba' to the current effected partition.
+ */
+ minor_name = NULL;
+
+ /*
+ * NOTE: If there is a 'linked' ena to be had, it should likely come
+ * from the buf structure via the scsi_pkt pkt->pkt_bp.
+ */
+
+ /* Post the ereport */
+ va_start(ap, sflag);
+ fm_dev_ereport_postv(dip, dip, devpath, minor_name, devid,
+ class, ena, sflag, ap);
+ va_end(ap);
+}
diff --git a/usr/src/uts/common/io/scsi/impl/scsi_subr.c b/usr/src/uts/common/io/scsi/impl/scsi_subr.c
index 61ea5690be..a9c0ca2d69 100644
--- a/usr/src/uts/common/io/scsi/impl/scsi_subr.c
+++ b/usr/src/uts/common/io/scsi/impl/scsi_subr.c
@@ -1040,7 +1040,6 @@ scsi_sname(uchar_t sense_key)
/*
* Print a piece of inquiry data- cleaned up for non-printable characters.
*/
-
static void
inq_fill(char *p, int l, char *s)
{
@@ -1103,10 +1102,10 @@ scsi_asc_ascq_name(uint_t asc, uint_t ascq, char *tmpstr,
#define SCSI_ERRMSG_BUF_LEN 256
void
-scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
- int severity, daddr_t blkno, daddr_t err_blkno,
- struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep,
- struct scsi_asq_key_strings *asc_list,
+scsi_generic_errmsg(struct scsi_device *devp, char *label, int severity,
+ daddr_t blkno, daddr_t err_blkno,
+ uchar_t cmd_name, struct scsi_key_strings *cmdlist,
+ uint8_t *sensep, struct scsi_asq_key_strings *asc_list,
char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t))
{
uchar_t com;
@@ -1134,7 +1133,7 @@ scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
}
bzero(buf, 256);
- com = ((union scsi_cdb *)pkt->pkt_cdbp)->scc_cmd;
+ com = cmd_name;
(void) sprintf(buf, "Error for Command: %s",
scsi_cmd_name(com, cmdlist, tmpbuf));
buflen = strlen(buf);
@@ -1181,10 +1180,10 @@ scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
impl_scsi_log(dev, label, CE_CONT, "%s\n", buf);
if (sensep) {
- sense_key = scsi_sense_key((uint8_t *)sensep);
- asc = scsi_sense_asc((uint8_t *)sensep);
- ascq = scsi_sense_ascq((uint8_t *)sensep);
- scsi_ext_sense_fields((uint8_t *)sensep, SENSE_LENGTH,
+ sense_key = scsi_sense_key(sensep);
+ asc = scsi_sense_asc(sensep);
+ ascq = scsi_sense_ascq(sensep);
+ scsi_ext_sense_fields(sensep, SENSE_LENGTH,
NULL, NULL, &fru_code_ptr, NULL, NULL);
fru_code = (fru_code_ptr ? *fru_code_ptr : 0);
@@ -1233,6 +1232,23 @@ scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
}
void
+scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
+ int severity, daddr_t blkno, daddr_t err_blkno,
+ struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep,
+ struct scsi_asq_key_strings *asc_list,
+ char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t))
+{
+ uchar_t com;
+
+ com = ((union scsi_cdb *)pkt->pkt_cdbp)->scc_cmd;
+
+ scsi_generic_errmsg(devp, label, severity, blkno, err_blkno,
+ com, cmdlist, (uint8_t *)sensep, asc_list, decode_fru);
+
+
+}
+
+void
scsi_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
int severity, daddr_t blkno, daddr_t err_blkno,
struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep)
@@ -1991,19 +2007,8 @@ int
scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
struct uscsi_cmd **uscmdp)
{
-#ifdef _MULTI_DATAMODEL
- /*
- * For use when a 32 bit app makes a call into a
- * 64 bit ioctl
- */
- struct uscsi_cmd32 uscsi_cmd_32_for_64;
- struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64;
-#endif /* _MULTI_DATAMODEL */
- struct uscsi_i_cmd *uicmd;
- struct uscsi_cmd *uscmd;
- int max_hba_cdb;
- int rval;
- extern dev_info_t *scsi_vhci_dip;
+ int rval = 0;
+ struct uscsi_cmd *uscmd;
/*
* In order to not worry about where the uscsi structure came
@@ -2016,17 +2021,75 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
* into it. We also save infos of the uscsi command by using
* uicmd to supply referrence for the copyout operation.
*/
+ uscmd = scsi_uscsi_alloc();
+
+ if ((rval = scsi_uscsi_copyin(arg, flag, ap, &uscmd)) != 0) {
+ scsi_uscsi_free(uscmd);
+ *uscmdp = NULL;
+ rval = EFAULT;
+ } else {
+ *uscmdp = uscmd;
+ }
+
+ return (rval);
+}
+
+struct uscsi_cmd *
+scsi_uscsi_alloc()
+{
+ struct uscsi_i_cmd *uicmd;
+
uicmd = (struct uscsi_i_cmd *)
kmem_zalloc(sizeof (struct uscsi_i_cmd), KM_SLEEP);
- *uscmdp = &(uicmd->uic_cmd);
- uscmd = *uscmdp;
+
+ /*
+ * It is supposed that the uscsi_cmd has been alloced correctly,
+ * we need to check is it NULL or mis-created.
+ */
+ ASSERT(uicmd && (offsetof(struct uscsi_i_cmd, uic_cmd) == 0));
+
+ return (&uicmd->uic_cmd);
+}
+
+int
+scsi_uscsi_copyin(intptr_t arg, int flag, struct scsi_address *ap,
+ struct uscsi_cmd **uscmdp)
+{
+#ifdef _MULTI_DATAMODEL
+ /*
+ * For use when a 32 bit app makes a call into a
+ * 64 bit ioctl
+ */
+ struct uscsi_cmd32 uscsi_cmd_32_for_64;
+ struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64;
+#endif /* _MULTI_DATAMODEL */
+ struct uscsi_cmd *uscmd = *uscmdp;
+ struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)(uscmd);
+ int max_hba_cdb;
+ int rval;
+ extern dev_info_t *scsi_vhci_dip;
+
+ ASSERT(uscmd != NULL);
+ ASSERT(uicmd != NULL);
+
+ /*
+ * To be able to issue multiple commands off a single uscmdp
+ * We need to free the original cdb, rqbuf and bzero the uscmdp
+ * if the cdb, rqbuf and uscmdp is not NULL
+ */
+ if (uscmd->uscsi_rqbuf != NULL)
+ kmem_free(uscmd->uscsi_rqbuf, uscmd->uscsi_rqlen);
+ if (uscmd->uscsi_cdb != NULL)
+ kmem_free(uscmd->uscsi_cdb, uscmd->uscsi_cdblen);
+ bzero(uscmd, sizeof (struct uscsi_cmd));
+
#ifdef _MULTI_DATAMODEL
switch (ddi_model_convert_from(flag & FMODELS)) {
case DDI_MODEL_ILP32:
if (ddi_copyin((void *)arg, ucmd32, sizeof (*ucmd32), flag)) {
rval = EFAULT;
- goto done;
+ goto scsi_uscsi_copyin_failed;
}
/*
* Convert the ILP32 uscsi data from the
@@ -2037,17 +2100,26 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
case DDI_MODEL_NONE:
if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) {
rval = EFAULT;
- goto done;
+ goto scsi_uscsi_copyin_failed;
}
break;
+ default:
+ rval = EFAULT;
+ goto scsi_uscsi_copyin_failed;
}
#else /* ! _MULTI_DATAMODEL */
if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) {
rval = EFAULT;
- goto done;
+ goto scsi_uscsi_copyin_failed;
}
#endif /* _MULTI_DATAMODEL */
+ /*
+ * We are going to allocate kernel virtual addresses for
+ * uscsi_rqbuf and uscsi_cdb pointers, so save off the
+ * original, possibly user virtual, uscsi_addresses
+ * in uic_fields
+ */
uicmd->uic_rqbuf = uscmd->uscsi_rqbuf;
uicmd->uic_rqlen = uscmd->uscsi_rqlen;
uicmd->uic_cdb = uscmd->uscsi_cdb;
@@ -2071,7 +2143,7 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) &&
(A_TO_TRAN(ap)->tran_hba_dip != scsi_vhci_dip)) {
rval = EFAULT;
- goto done;
+ goto scsi_uscsi_copyin_failed;
}
/*
@@ -2085,12 +2157,12 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
if (uscmd->uscsi_cdblen < CDB_GROUP0 ||
uscmd->uscsi_cdblen > max_hba_cdb) {
rval = EINVAL;
- goto done;
+ goto scsi_uscsi_copyin_failed;
}
if ((uscmd->uscsi_flags & USCSI_RQENABLE) &&
(uscmd->uscsi_rqlen == 0 || uscmd->uscsi_rqbuf == NULL)) {
rval = EINVAL;
- goto done;
+ goto scsi_uscsi_copyin_failed;
}
/*
@@ -2099,7 +2171,7 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
*/
if (uscmd->uscsi_flags & USCSI_RESERVED) {
rval = EINVAL;
- goto done;
+ goto scsi_uscsi_copyin_failed;
}
/*
@@ -2111,7 +2183,7 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
(uint_t)uscmd->uscsi_cdblen, flag) != 0) {
kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen);
rval = EFAULT;
- goto done;
+ goto scsi_uscsi_copyin_failed;
}
if (uscmd->uscsi_cdb[0] != SCMD_VAR_LEN) {
@@ -2121,14 +2193,14 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
kmem_free(uscmd->uscsi_cdb,
(size_t)uscmd->uscsi_cdblen);
rval = EINVAL;
- goto done;
+ goto scsi_uscsi_copyin_failed;
}
} else {
if ((uscmd->uscsi_cdblen % 4) != 0) {
kmem_free(uscmd->uscsi_cdb,
(size_t)uscmd->uscsi_cdblen);
rval = EINVAL;
- goto done;
+ goto scsi_uscsi_copyin_failed;
}
}
@@ -2163,8 +2235,14 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
}
return (0);
-done:
- kmem_free(uicmd, sizeof (struct uscsi_i_cmd));
+scsi_uscsi_copyin_failed:
+ /*
+ * The uscsi_rqbuf and uscsi_cdb is refering to user-land
+ * address now, no need to free them.
+ */
+ uscmd->uscsi_rqbuf = NULL;
+ uscmd->uscsi_cdb = NULL;
+
return (rval);
}
@@ -2404,6 +2482,18 @@ scsi_uscsi_pktfini(struct scsi_pkt *pkt, struct uscsi_cmd *uscmd)
int
scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd)
{
+ int rval = 0;
+
+ rval = scsi_uscsi_copyout(arg, uscmd);
+
+ scsi_uscsi_free(uscmd);
+
+ return (rval);
+}
+
+int
+scsi_uscsi_copyout(intptr_t arg, struct uscsi_cmd *uscmd)
+{
#ifdef _MULTI_DATAMODEL
/*
* For use when a 32 bit app makes a call into a
@@ -2439,8 +2529,9 @@ scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd)
}
/*
- * Free allocated resources and return, mapout the buf in case it was
- * mapped in by a lower layer.
+ * Restore original uscsi_values, saved in uic_fields for
+ * copyout (so caller does not experience a change in these
+ * fields)
*/
k_rqbuf = uscmd->uscsi_rqbuf;
k_rqlen = uscmd->uscsi_rqlen;
@@ -2468,6 +2559,8 @@ scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd)
rval = EFAULT;
}
break;
+ default:
+ rval = EFAULT;
}
#else /* _MULTI_DATAMODE */
if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd), uicmd->uic_flag)) {
@@ -2475,13 +2568,33 @@ scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd)
}
#endif /* _MULTI_DATAMODE */
- if (k_rqbuf != NULL) {
- kmem_free(k_rqbuf, k_rqlen);
+ /*
+ * Copyout done, restore kernel virtual addresses for further
+ * scsi_uscsi_free().
+ */
+ uscmd->uscsi_rqbuf = k_rqbuf;
+ uscmd->uscsi_rqlen = k_rqlen;
+ uscmd->uscsi_cdb = k_cdb;
+
+ return (rval);
+}
+
+void
+scsi_uscsi_free(struct uscsi_cmd *uscmd)
+{
+ struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd;
+
+ ASSERT(uicmd != NULL);
+
+ if ((uscmd->uscsi_rqbuf != NULL) && (uscmd->uscsi_rqlen != 0)) {
+ kmem_free(uscmd->uscsi_rqbuf, (size_t)uscmd->uscsi_rqlen);
+ uscmd->uscsi_rqbuf = NULL;
}
- if (k_cdb != NULL) {
- kmem_free(k_cdb, (size_t)uscmd->uscsi_cdblen);
+
+ if ((uscmd->uscsi_cdb != NULL) && (uscmd->uscsi_cdblen != 0)) {
+ kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen);
+ uscmd->uscsi_cdb = NULL;
}
- kmem_free(uicmd, sizeof (struct uscsi_i_cmd));
- return (rval);
+ kmem_free(uicmd, sizeof (struct uscsi_i_cmd));
}
diff --git a/usr/src/uts/common/io/scsi/targets/sd.c b/usr/src/uts/common/io/scsi/targets/sd.c
index 64baddee33..799df852ef 100644
--- a/usr/src/uts/common/io/scsi/targets/sd.c
+++ b/usr/src/uts/common/io/scsi/targets/sd.c
@@ -66,6 +66,7 @@
#include <sys/sysevent/eventdefs.h>
#include <sys/sysevent/dev.h>
+#include <sys/fm/protocol.h>
/*
* Loadable module info.
@@ -207,8 +208,17 @@ static char *sd_config_list = "sd-config-list";
#define sd_dtype_optical_bind ssd_dtype_optical_bind
-#endif
+#define sd_ssc_init ssd_ssc_init
+#define sd_ssc_send ssd_ssc_send
+#define sd_ssc_fini ssd_ssc_fini
+#define sd_ssc_assessment ssd_ssc_assessment
+#define sd_ssc_post ssd_ssc_post
+#define sd_ssc_print ssd_ssc_print
+#define sd_ssc_ereport_post ssd_ssc_ereport_post
+#define sd_ssc_set_info ssd_ssc_set_info
+#define sd_ssc_extract_info ssd_ssc_extract_info
+#endif
#ifdef SDDEBUG
int sd_force_pm_supported = 0;
@@ -1117,13 +1127,51 @@ static void sd_scsi_target_lun_fini(void);
static int sd_scsi_get_target_lun_count(dev_info_t *dip, int target);
static void sd_scsi_update_lun_on_target(dev_info_t *dip, int target, int flag);
-static int sd_spin_up_unit(struct sd_lun *un);
+static int sd_spin_up_unit(sd_ssc_t *ssc);
+
+/*
+ * Using sd_ssc_init to establish sd_ssc_t struct
+ * Using sd_ssc_send to send uscsi internal command
+ * Using sd_ssc_fini to free sd_ssc_t struct
+ */
+static sd_ssc_t *sd_ssc_init(struct sd_lun *un);
+static int sd_ssc_send(sd_ssc_t *ssc, struct uscsi_cmd *incmd,
+ int flag, enum uio_seg dataspace, int path_flag);
+static void sd_ssc_fini(sd_ssc_t *ssc);
+
+/*
+ * Using sd_ssc_assessment to set correct type-of-assessment
+ * Using sd_ssc_post to post ereport & system log
+ * sd_ssc_post will call sd_ssc_print to print system log
+ * sd_ssc_post will call sd_ssd_ereport_post to post ereport
+ */
+static void sd_ssc_assessment(sd_ssc_t *ssc,
+ enum sd_type_assessment tp_assess);
+
+static void sd_ssc_post(sd_ssc_t *ssc, enum sd_driver_assessment sd_assess);
+static void sd_ssc_print(sd_ssc_t *ssc, int sd_severity);
+static void sd_ssc_ereport_post(sd_ssc_t *ssc,
+ enum sd_driver_assessment drv_assess);
+
+/*
+ * Using sd_ssc_set_info to mark an un-decodable-data error.
+ * Using sd_ssc_extract_info to transfer information from internal
+ * data structures to sd_ssc_t.
+ */
+static void sd_ssc_set_info(sd_ssc_t *ssc, int ssc_flags,
+ const char *fmt, ...);
+static void sd_ssc_extract_info(sd_ssc_t *ssc, struct sd_lun *un,
+ struct scsi_pkt *pktp, struct buf *bp, struct sd_xbuf *xp);
+
+static int sd_send_scsi_cmd(dev_t dev, struct uscsi_cmd *incmd, int flag,
+ enum uio_seg dataspace, int path_flag);
+
#ifdef _LP64
-static void sd_enable_descr_sense(struct sd_lun *un);
+static void sd_enable_descr_sense(sd_ssc_t *ssc);
static void sd_reenable_dsense_task(void *arg);
#endif /* _LP64 */
-static void sd_set_mmc_caps(struct sd_lun *un);
+static void sd_set_mmc_caps(sd_ssc_t *ssc);
static void sd_read_unit_properties(struct sd_lun *un);
static int sd_process_sdconf_file(struct sd_lun *un);
@@ -1140,15 +1188,15 @@ static int sd_chk_vers1_data(struct sd_lun *un, int flags, int *prop_list,
static void sd_set_vers1_properties(struct sd_lun *un, int flags,
sd_tunables *prop_list);
-static void sd_register_devid(struct sd_lun *un, dev_info_t *devi,
+static void sd_register_devid(sd_ssc_t *ssc, dev_info_t *devi,
int reservation_flag);
-static int sd_get_devid(struct sd_lun *un);
-static ddi_devid_t sd_create_devid(struct sd_lun *un);
-static int sd_write_deviceid(struct sd_lun *un);
+static int sd_get_devid(sd_ssc_t *ssc);
+static ddi_devid_t sd_create_devid(sd_ssc_t *ssc);
+static int sd_write_deviceid(sd_ssc_t *ssc);
static int sd_get_devid_page(struct sd_lun *un, uchar_t *wwn, int *len);
-static int sd_check_vpd_page_support(struct sd_lun *un);
+static int sd_check_vpd_page_support(sd_ssc_t *ssc);
-static void sd_setup_pm(struct sd_lun *un, dev_info_t *devi);
+static void sd_setup_pm(sd_ssc_t *ssc, dev_info_t *devi);
static void sd_create_pm_components(dev_info_t *devi, struct sd_lun *un);
static int sd_ddi_suspend(dev_info_t *devi);
@@ -1188,9 +1236,9 @@ static void sd_event_callback(dev_info_t *, ddi_eventcookie_t, void *, void *);
#define SD_CACHE_DISABLE 0
#define SD_CACHE_NOCHANGE -1
-static int sd_cache_control(struct sd_lun *un, int rcd_flag, int wce_flag);
-static int sd_get_write_cache_enabled(struct sd_lun *un, int *is_enabled);
-static void sd_get_nv_sup(struct sd_lun *un);
+static int sd_cache_control(sd_ssc_t *ssc, int rcd_flag, int wce_flag);
+static int sd_get_write_cache_enabled(sd_ssc_t *ssc, int *is_enabled);
+static void sd_get_nv_sup(sd_ssc_t *ssc);
static dev_t sd_make_device(dev_info_t *devi);
static void sd_update_block_info(struct sd_lun *un, uint32_t lbasize,
@@ -1201,7 +1249,7 @@ static void sd_update_block_info(struct sd_lun *un, uint32_t lbasize,
*/
static int sdopen(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
static int sdclose(dev_t dev, int flag, int otyp, cred_t *cred_p);
-static int sd_ready_and_valid(struct sd_lun *un, int part);
+static int sd_ready_and_valid(sd_ssc_t *ssc, int part);
static void sdmin(struct buf *bp);
static int sdread(dev_t dev, struct uio *uio, cred_t *cred_p);
@@ -1408,43 +1456,43 @@ static void sd_log_lun_expansion_event(struct sd_lun *un, int km_flag);
static void sd_media_change_task(void *arg);
static int sd_handle_mchange(struct sd_lun *un);
-static int sd_send_scsi_DOORLOCK(struct sd_lun *un, int flag, int path_flag);
-static int sd_send_scsi_READ_CAPACITY(struct sd_lun *un, uint64_t *capp,
+static int sd_send_scsi_DOORLOCK(sd_ssc_t *ssc, int flag, int path_flag);
+static int sd_send_scsi_READ_CAPACITY(sd_ssc_t *ssc, uint64_t *capp,
uint32_t *lbap, int path_flag);
-static int sd_send_scsi_READ_CAPACITY_16(struct sd_lun *un, uint64_t *capp,
+static int sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp,
uint32_t *lbap, int path_flag);
-static int sd_send_scsi_START_STOP_UNIT(struct sd_lun *un, int flag,
+static int sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int flag,
int path_flag);
-static int sd_send_scsi_INQUIRY(struct sd_lun *un, uchar_t *bufaddr,
+static int sd_send_scsi_INQUIRY(sd_ssc_t *ssc, uchar_t *bufaddr,
size_t buflen, uchar_t evpd, uchar_t page_code, size_t *residp);
-static int sd_send_scsi_TEST_UNIT_READY(struct sd_lun *un, int flag);
-static int sd_send_scsi_PERSISTENT_RESERVE_IN(struct sd_lun *un,
+static int sd_send_scsi_TEST_UNIT_READY(sd_ssc_t *ssc, int flag);
+static int sd_send_scsi_PERSISTENT_RESERVE_IN(sd_ssc_t *ssc,
uchar_t usr_cmd, uint16_t data_len, uchar_t *data_bufp);
-static int sd_send_scsi_PERSISTENT_RESERVE_OUT(struct sd_lun *un,
+static int sd_send_scsi_PERSISTENT_RESERVE_OUT(sd_ssc_t *ssc,
uchar_t usr_cmd, uchar_t *usr_bufp);
static int sd_send_scsi_SYNCHRONIZE_CACHE(struct sd_lun *un,
struct dk_callback *dkc);
static int sd_send_scsi_SYNCHRONIZE_CACHE_biodone(struct buf *bp);
-static int sd_send_scsi_GET_CONFIGURATION(struct sd_lun *un,
+static int sd_send_scsi_GET_CONFIGURATION(sd_ssc_t *ssc,
struct uscsi_cmd *ucmdbuf, uchar_t *rqbuf, uint_t rqbuflen,
uchar_t *bufaddr, uint_t buflen, int path_flag);
-static int sd_send_scsi_feature_GET_CONFIGURATION(struct sd_lun *un,
+static int sd_send_scsi_feature_GET_CONFIGURATION(sd_ssc_t *ssc,
struct uscsi_cmd *ucmdbuf, uchar_t *rqbuf, uint_t rqbuflen,
uchar_t *bufaddr, uint_t buflen, char feature, int path_flag);
-static int sd_send_scsi_MODE_SENSE(struct sd_lun *un, int cdbsize,
+static int sd_send_scsi_MODE_SENSE(sd_ssc_t *ssc, int cdbsize,
uchar_t *bufaddr, size_t buflen, uchar_t page_code, int path_flag);
-static int sd_send_scsi_MODE_SELECT(struct sd_lun *un, int cdbsize,
+static int sd_send_scsi_MODE_SELECT(sd_ssc_t *ssc, int cdbsize,
uchar_t *bufaddr, size_t buflen, uchar_t save_page, int path_flag);
-static int sd_send_scsi_RDWR(struct sd_lun *un, uchar_t cmd, void *bufaddr,
+static int sd_send_scsi_RDWR(sd_ssc_t *ssc, uchar_t cmd, void *bufaddr,
size_t buflen, daddr_t start_block, int path_flag);
-#define sd_send_scsi_READ(un, bufaddr, buflen, start_block, path_flag) \
- sd_send_scsi_RDWR(un, SCMD_READ, bufaddr, buflen, start_block, \
+#define sd_send_scsi_READ(ssc, bufaddr, buflen, start_block, path_flag) \
+ sd_send_scsi_RDWR(ssc, SCMD_READ, bufaddr, buflen, start_block, \
path_flag)
-#define sd_send_scsi_WRITE(un, bufaddr, buflen, start_block, path_flag) \
- sd_send_scsi_RDWR(un, SCMD_WRITE, bufaddr, buflen, start_block,\
+#define sd_send_scsi_WRITE(ssc, bufaddr, buflen, start_block, path_flag)\
+ sd_send_scsi_RDWR(ssc, SCMD_WRITE, bufaddr, buflen, start_block,\
path_flag)
-static int sd_send_scsi_LOG_SENSE(struct sd_lun *un, uchar_t *bufaddr,
+static int sd_send_scsi_LOG_SENSE(sd_ssc_t *ssc, uchar_t *bufaddr,
uint16_t buflen, uchar_t page_code, uchar_t page_control,
uint16_t param_ptr, int path_flag);
@@ -1514,12 +1562,12 @@ static void sd_delayed_cv_broadcast(void *arg);
static int sr_volume_ctrl(dev_t dev, caddr_t data, int flag);
static int sr_read_sony_session_offset(dev_t dev, caddr_t data, int flag);
-static int sd_log_page_supported(struct sd_lun *un, int log_page);
+static int sd_log_page_supported(sd_ssc_t *ssc, int log_page);
/*
* Function Prototype for the non-512 support (DVDRAM, MO etc.) functions.
*/
-static void sd_check_for_writable_cd(struct sd_lun *un, int path_flag);
+static void sd_check_for_writable_cd(sd_ssc_t *ssc, int path_flag);
static int sd_wm_cache_constructor(void *wm, void *un, int flags);
static void sd_wm_cache_destructor(void *wm, void *un);
static struct sd_w_map *sd_range_lock(struct sd_lun *un, daddr_t startb,
@@ -2925,7 +2973,8 @@ sd_scsi_update_lun_on_target(dev_info_t *dip, int target, int flag)
* Description: Issues the following commands to spin-up the device:
* START STOP UNIT, and INQUIRY.
*
- * Arguments: un - driver soft state (unit) structure
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
*
* Return Code: 0 - success
* EIO - failure
@@ -2935,12 +2984,16 @@ sd_scsi_update_lun_on_target(dev_info_t *dip, int target, int flag)
*/
static int
-sd_spin_up_unit(struct sd_lun *un)
+sd_spin_up_unit(sd_ssc_t *ssc)
{
size_t resid = 0;
int has_conflict = FALSE;
uchar_t *bufaddr;
+ int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
/*
@@ -2952,9 +3005,14 @@ sd_spin_up_unit(struct sd_lun *un)
* we don't want to fail the attach because it may become
* "active" later.
*/
- if (sd_send_scsi_START_STOP_UNIT(un, SD_TARGET_START, SD_PATH_DIRECT)
- == EACCES)
- has_conflict = TRUE;
+ status = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START,
+ SD_PATH_DIRECT);
+
+ if (status != 0) {
+ if (status == EACCES)
+ has_conflict = TRUE;
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
/*
* Send another INQUIRY command to the target. This is necessary for
@@ -2965,8 +3023,11 @@ sd_spin_up_unit(struct sd_lun *un)
* Reservation Conflict is present.
*/
bufaddr = kmem_zalloc(SUN_INQSIZE, KM_SLEEP);
- if (sd_send_scsi_INQUIRY(un, bufaddr, SUN_INQSIZE, 0, 0, &resid) != 0) {
+
+ if (sd_send_scsi_INQUIRY(ssc, bufaddr, SUN_INQSIZE, 0, 0, &resid)
+ != 0) {
kmem_free(bufaddr, SUN_INQSIZE);
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
return (EIO);
}
@@ -3004,18 +3065,25 @@ sd_spin_up_unit(struct sd_lun *un)
* complete sense data for commands that fail with an LBA
* larger than 32 bits.
*
- * Arguments: un - driver soft state (unit) structure
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
*
* Context: Kernel thread context only
*/
static void
-sd_enable_descr_sense(struct sd_lun *un)
+sd_enable_descr_sense(sd_ssc_t *ssc)
{
uchar_t *header;
struct mode_control_scsi3 *ctrl_bufp;
size_t buflen;
size_t bd_len;
+ int status;
+ struct sd_lun *un;
+
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
+ ASSERT(un != NULL);
/*
* Read MODE SENSE page 0xA, Control Mode Page
@@ -3023,8 +3091,11 @@ sd_enable_descr_sense(struct sd_lun *un)
buflen = MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH +
sizeof (struct mode_control_scsi3);
header = kmem_zalloc(buflen, KM_SLEEP);
- if (sd_send_scsi_MODE_SENSE(un, CDB_GROUP0, header, buflen,
- MODEPAGE_CTRL_MODE, SD_PATH_DIRECT) != 0) {
+
+ status = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP0, header, buflen,
+ MODEPAGE_CTRL_MODE, SD_PATH_DIRECT);
+
+ if (status != 0) {
SD_ERROR(SD_LOG_COMMON, un,
"sd_enable_descr_sense: mode sense ctrl page failed\n");
goto eds_exit;
@@ -3064,17 +3135,24 @@ sd_enable_descr_sense(struct sd_lun *un)
*/
ctrl_bufp->d_sense = 1;
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
/*
* Use MODE SELECT to commit the change to the D_SENSE bit
*/
- if (sd_send_scsi_MODE_SELECT(un, CDB_GROUP0, header,
- buflen, SD_DONTSAVE_PAGE, SD_PATH_DIRECT) != 0) {
+ status = sd_send_scsi_MODE_SELECT(ssc, CDB_GROUP0, header,
+ buflen, SD_DONTSAVE_PAGE, SD_PATH_DIRECT);
+
+ if (status != 0) {
SD_INFO(SD_LOG_COMMON, un,
"sd_enable_descr_sense: mode select ctrl page failed\n");
- goto eds_exit;
+ } else {
+ kmem_free(header, buflen);
+ return;
}
eds_exit:
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
kmem_free(header, buflen);
}
@@ -3089,9 +3167,13 @@ static void
sd_reenable_dsense_task(void *arg)
{
struct sd_lun *un = arg;
+ sd_ssc_t *ssc;
ASSERT(un != NULL);
- sd_enable_descr_sense(un);
+
+ ssc = sd_ssc_init(un);
+ sd_enable_descr_sense(ssc);
+ sd_ssc_fini(ssc);
}
#endif /* _LP64 */
@@ -3103,13 +3185,14 @@ sd_reenable_dsense_task(void *arg)
* capabilities mode page. Also checks if the device is a
* dvdram writable device.
*
- * Arguments: un - driver soft state (unit) structure
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
*
* Context: Kernel thread context only
*/
static void
-sd_set_mmc_caps(struct sd_lun *un)
+sd_set_mmc_caps(sd_ssc_t *ssc)
{
struct mode_header_grp2 *sense_mhp;
uchar_t *sense_page;
@@ -3120,7 +3203,10 @@ sd_set_mmc_caps(struct sd_lun *un)
int rtn;
uchar_t *out_data_rw, *out_data_hd;
uchar_t *rqbuf_rw, *rqbuf_hd;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
/*
@@ -3133,9 +3219,11 @@ sd_set_mmc_caps(struct sd_lun *un)
un->un_f_cfg_cdda = FALSE;
buf = kmem_zalloc(BUFLEN_MODE_CDROM_CAP, KM_SLEEP);
- status = sd_send_scsi_MODE_SENSE(un, CDB_GROUP1, (uchar_t *)buf,
+ status = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP1, (uchar_t *)buf,
BUFLEN_MODE_CDROM_CAP, MODEPAGE_CDROM_CAP, SD_PATH_DIRECT);
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
if (status != 0) {
/* command failed; just return */
kmem_free(buf, BUFLEN_MODE_CDROM_CAP);
@@ -3198,9 +3286,12 @@ sd_set_mmc_caps(struct sd_lun *un)
out_data_rw = kmem_zalloc(SD_CURRENT_FEATURE_LEN, KM_SLEEP);
rqbuf_rw = kmem_zalloc(SENSE_LENGTH, KM_SLEEP);
- rtn = sd_send_scsi_feature_GET_CONFIGURATION(un, &com, rqbuf_rw,
+ rtn = sd_send_scsi_feature_GET_CONFIGURATION(ssc, &com, rqbuf_rw,
SENSE_LENGTH, out_data_rw, SD_CURRENT_FEATURE_LEN,
RANDOM_WRITABLE, SD_PATH_STANDARD);
+
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
if (rtn != 0) {
kmem_free(out_data_rw, SD_CURRENT_FEATURE_LEN);
kmem_free(rqbuf_rw, SENSE_LENGTH);
@@ -3210,9 +3301,12 @@ sd_set_mmc_caps(struct sd_lun *un)
out_data_hd = kmem_zalloc(SD_CURRENT_FEATURE_LEN, KM_SLEEP);
rqbuf_hd = kmem_zalloc(SENSE_LENGTH, KM_SLEEP);
- rtn = sd_send_scsi_feature_GET_CONFIGURATION(un, &com, rqbuf_hd,
+ rtn = sd_send_scsi_feature_GET_CONFIGURATION(ssc, &com, rqbuf_hd,
SENSE_LENGTH, out_data_hd, SD_CURRENT_FEATURE_LEN,
HARDWARE_DEFECT_MANAGEMENT, SD_PATH_STANDARD);
+
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
if (rtn == 0) {
/*
* We have good information, check for random writable
@@ -3248,7 +3342,7 @@ sd_set_mmc_caps(struct sd_lun *un)
*/
static void
-sd_check_for_writable_cd(struct sd_lun *un, int path_flag)
+sd_check_for_writable_cd(sd_ssc_t *ssc, int path_flag)
{
struct uscsi_cmd com;
uchar_t *out_data;
@@ -3261,7 +3355,10 @@ sd_check_for_writable_cd(struct sd_lun *un, int path_flag)
caddr_t buf;
int bd_len;
int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(mutex_owned(SD_MUTEX(un)));
@@ -3275,9 +3372,12 @@ sd_check_for_writable_cd(struct sd_lun *un, int path_flag)
out_data = kmem_zalloc(SD_PROFILE_HEADER_LEN, KM_SLEEP);
rqbuf = kmem_zalloc(SENSE_LENGTH, KM_SLEEP);
- rtn = sd_send_scsi_GET_CONFIGURATION(un, &com, rqbuf, SENSE_LENGTH,
+ rtn = sd_send_scsi_GET_CONFIGURATION(ssc, &com, rqbuf, SENSE_LENGTH,
out_data, SD_PROFILE_HEADER_LEN, path_flag);
+ if (rtn != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
mutex_enter(SD_MUTEX(un));
if (rtn == 0) {
/*
@@ -3299,8 +3399,11 @@ sd_check_for_writable_cd(struct sd_lun *un, int path_flag)
*/
mutex_exit(SD_MUTEX(un));
buf = kmem_zalloc(BUFLEN_MODE_CDROM_CAP, KM_SLEEP);
- status = sd_send_scsi_MODE_SENSE(un, CDB_GROUP1, (uchar_t *)buf,
+ status = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP1, (uchar_t *)buf,
BUFLEN_MODE_CDROM_CAP, MODEPAGE_CDROM_CAP, path_flag);
+
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
mutex_enter(SD_MUTEX(un));
if (status != 0) {
/* command failed; just return */
@@ -3344,9 +3447,11 @@ sd_check_for_writable_cd(struct sd_lun *un, int path_flag)
out_data_rw = kmem_zalloc(SD_CURRENT_FEATURE_LEN, KM_SLEEP);
rqbuf_rw = kmem_zalloc(SENSE_LENGTH, KM_SLEEP);
- rtn = sd_send_scsi_feature_GET_CONFIGURATION(un, &com, rqbuf_rw,
+ rtn = sd_send_scsi_feature_GET_CONFIGURATION(ssc, &com, rqbuf_rw,
SENSE_LENGTH, out_data_rw, SD_CURRENT_FEATURE_LEN,
RANDOM_WRITABLE, path_flag);
+
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
if (rtn != 0) {
kmem_free(out_data_rw, SD_CURRENT_FEATURE_LEN);
kmem_free(rqbuf_rw, SENSE_LENGTH);
@@ -3357,9 +3462,11 @@ sd_check_for_writable_cd(struct sd_lun *un, int path_flag)
out_data_hd = kmem_zalloc(SD_CURRENT_FEATURE_LEN, KM_SLEEP);
rqbuf_hd = kmem_zalloc(SENSE_LENGTH, KM_SLEEP);
- rtn = sd_send_scsi_feature_GET_CONFIGURATION(un, &com, rqbuf_hd,
+ rtn = sd_send_scsi_feature_GET_CONFIGURATION(ssc, &com, rqbuf_hd,
SENSE_LENGTH, out_data_hd, SD_CURRENT_FEATURE_LEN,
HARDWARE_DEFECT_MANAGEMENT, path_flag);
+
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
mutex_enter(SD_MUTEX(un));
if (rtn == 0) {
/*
@@ -4528,6 +4635,8 @@ sd_get_physical_geometry(struct sd_lun *un, cmlb_geom_t *pgeom_p,
uchar_t *p4bufp;
int cdbsize;
int ret = EIO;
+ sd_ssc_t *ssc;
+ int status;
ASSERT(un != NULL);
@@ -4555,9 +4664,10 @@ sd_get_physical_geometry(struct sd_lun *un, cmlb_geom_t *pgeom_p,
* Retrieve MODE SENSE page 3 - Format Device Page
*/
p3bufp = kmem_zalloc(SD_MODE_SENSE_PAGE3_LENGTH, KM_SLEEP);
- if (sd_send_scsi_MODE_SENSE(un, cdbsize, p3bufp,
- SD_MODE_SENSE_PAGE3_LENGTH, SD_MODE_SENSE_PAGE3_CODE, path_flag)
- != 0) {
+ ssc = sd_ssc_init(un);
+ status = sd_send_scsi_MODE_SENSE(ssc, cdbsize, p3bufp,
+ SD_MODE_SENSE_PAGE3_LENGTH, SD_MODE_SENSE_PAGE3_CODE, path_flag);
+ if (status != 0) {
SD_ERROR(SD_LOG_COMMON, un,
"sd_get_physical_geometry: mode sense page 3 failed\n");
goto page3_exit;
@@ -4582,6 +4692,10 @@ sd_get_physical_geometry(struct sd_lun *un, cmlb_geom_t *pgeom_p,
if (bd_len > MODE_BLK_DESC_LENGTH) {
SD_ERROR(SD_LOG_COMMON, un, "sd_get_physical_geometry: "
"received unexpected bd_len of %d, page3\n", bd_len);
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_get_physical_geometry: received unexpected "
+ "bd_len of %d, page3", bd_len);
+ status = EIO;
goto page3_exit;
}
@@ -4592,6 +4706,10 @@ sd_get_physical_geometry(struct sd_lun *un, cmlb_geom_t *pgeom_p,
SD_ERROR(SD_LOG_COMMON, un, "sd_get_physical_geometry: "
"mode sense pg3 code mismatch %d\n",
page3p->mode_page.code);
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_get_physical_geometry: mode sense pg3 code "
+ "mismatch %d", page3p->mode_page.code);
+ status = EIO;
goto page3_exit;
}
@@ -4624,14 +4742,15 @@ sd_get_physical_geometry(struct sd_lun *un, cmlb_geom_t *pgeom_p,
BE_16(page3p->track_skew),
BE_16(page3p->cylinder_skew));
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
/*
* Retrieve MODE SENSE page 4 - Rigid Disk Drive Geometry Page
*/
p4bufp = kmem_zalloc(SD_MODE_SENSE_PAGE4_LENGTH, KM_SLEEP);
- if (sd_send_scsi_MODE_SENSE(un, cdbsize, p4bufp,
- SD_MODE_SENSE_PAGE4_LENGTH, SD_MODE_SENSE_PAGE4_CODE, path_flag)
- != 0) {
+ status = sd_send_scsi_MODE_SENSE(ssc, cdbsize, p4bufp,
+ SD_MODE_SENSE_PAGE4_LENGTH, SD_MODE_SENSE_PAGE4_CODE, path_flag);
+ if (status != 0) {
SD_ERROR(SD_LOG_COMMON, un,
"sd_get_physical_geometry: mode sense page 4 failed\n");
goto page4_exit;
@@ -4654,6 +4773,10 @@ sd_get_physical_geometry(struct sd_lun *un, cmlb_geom_t *pgeom_p,
if (bd_len > MODE_BLK_DESC_LENGTH) {
SD_ERROR(SD_LOG_COMMON, un, "sd_get_physical_geometry: "
"received unexpected bd_len of %d, page4\n", bd_len);
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_get_physical_geometry: received unexpected "
+ "bd_len of %d, page4", bd_len);
+ status = EIO;
goto page4_exit;
}
@@ -4664,6 +4787,10 @@ sd_get_physical_geometry(struct sd_lun *un, cmlb_geom_t *pgeom_p,
SD_ERROR(SD_LOG_COMMON, un, "sd_get_physical_geometry: "
"mode sense pg4 code mismatch %d\n",
page4p->mode_page.code);
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_get_physical_geometry: mode sense pg4 code "
+ "mismatch %d", page4p->mode_page.code);
+ status = EIO;
goto page4_exit;
}
@@ -4733,12 +4860,40 @@ sd_get_physical_geometry(struct sd_lun *un, cmlb_geom_t *pgeom_p,
" lbasize: %d; capacity: %ld; intrlv: %d; rpm: %d\n",
pgeom_p->g_secsize, pgeom_p->g_capacity,
pgeom_p->g_intrlv, pgeom_p->g_rpm);
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
page4_exit:
kmem_free(p4bufp, SD_MODE_SENSE_PAGE4_LENGTH);
+
page3_exit:
kmem_free(p3bufp, SD_MODE_SENSE_PAGE3_LENGTH);
+ if (status != 0) {
+ if (status == EIO) {
+ /*
+ * Some disks do not support mode sense(6), we
+ * should ignore this kind of error(sense key is
+ * 0x5 - illegal request).
+ */
+ uint8_t *sensep;
+ int senlen;
+
+ sensep = (uint8_t *)ssc->ssc_uscsi_cmd->uscsi_rqbuf;
+ senlen = (int)(ssc->ssc_uscsi_cmd->uscsi_rqlen -
+ ssc->ssc_uscsi_cmd->uscsi_rqresid);
+
+ if (senlen > 0 &&
+ scsi_sense_key(sensep) == KEY_ILLEGAL_REQUEST) {
+ sd_ssc_assessment(ssc,
+ SD_FMT_IGNORE_COMPROMISE);
+ } else {
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ }
+ } else {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+ }
+ sd_ssc_fini(ssc);
return (ret);
}
@@ -4850,7 +5005,7 @@ sd_update_block_info(struct sd_lun *un, uint32_t lbasize, uint64_t capacity)
* Context: Kernel Thread
*/
static void
-sd_register_devid(struct sd_lun *un, dev_info_t *devi, int reservation_flag)
+sd_register_devid(sd_ssc_t *ssc, dev_info_t *devi, int reservation_flag)
{
int rval = 0;
uchar_t *inq80 = NULL;
@@ -4861,7 +5016,10 @@ sd_register_devid(struct sd_lun *un, dev_info_t *devi, int reservation_flag)
size_t inq83_resid = 0;
int dlen, len;
char *sn;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(mutex_owned(SD_MUTEX(un)));
ASSERT((SD_DEVINFO(un)) == devi);
@@ -4889,13 +5047,13 @@ sd_register_devid(struct sd_lun *un, dev_info_t *devi, int reservation_flag)
* may result in invalid geometry, so check to make sure a
* reservation conflict did not occur during attach.
*/
- if ((sd_get_devid(un) == EINVAL) &&
+ if ((sd_get_devid(ssc) == EINVAL) &&
(reservation_flag != SD_TARGET_IS_RESERVED)) {
/*
* The devid is invalid AND there is no reservation
* conflict. Fabricate a new devid.
*/
- (void) sd_create_devid(un);
+ (void) sd_create_devid(ssc);
}
/* Register the devid if it exists */
@@ -4917,16 +5075,18 @@ sd_register_devid(struct sd_lun *un, dev_info_t *devi, int reservation_flag)
* vid/pid/serial # for Sun qualified disks, or use the ddi framework
* to fabricate a devid for non-Sun qualified disks.
*/
- if (sd_check_vpd_page_support(un) == 0) {
+ if (sd_check_vpd_page_support(ssc) == 0) {
/* collect page 80 data if available */
if (un->un_vpd_page_mask & SD_VPD_UNIT_SERIAL_PG) {
mutex_exit(SD_MUTEX(un));
inq80 = kmem_zalloc(inq80_len, KM_SLEEP);
- rval = sd_send_scsi_INQUIRY(un, inq80, inq80_len,
+
+ rval = sd_send_scsi_INQUIRY(ssc, inq80, inq80_len,
0x01, 0x80, &inq80_resid);
if (rval != 0) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
kmem_free(inq80, inq80_len);
inq80 = NULL;
inq80_len = 0;
@@ -4966,10 +5126,12 @@ sd_register_devid(struct sd_lun *un, dev_info_t *devi, int reservation_flag)
if (un->un_vpd_page_mask & SD_VPD_DEVID_WWN_PG) {
mutex_exit(SD_MUTEX(un));
inq83 = kmem_zalloc(inq83_len, KM_SLEEP);
- rval = sd_send_scsi_INQUIRY(un, inq83, inq83_len,
+
+ rval = sd_send_scsi_INQUIRY(ssc, inq83, inq83_len,
0x01, 0x83, &inq83_resid);
if (rval != 0) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
kmem_free(inq83, inq83_len);
inq83 = NULL;
inq83_len = 0;
@@ -5003,8 +5165,8 @@ sd_register_devid(struct sd_lun *un, dev_info_t *devi, int reservation_flag)
* Create a fabricate devid only if there's no
* fabricate devid existed.
*/
- if (sd_get_devid(un) == EINVAL) {
- (void) sd_create_devid(un);
+ if (sd_get_devid(ssc) == EINVAL) {
+ (void) sd_create_devid(ssc);
}
un->un_f_opt_fab_devid = TRUE;
@@ -5045,7 +5207,7 @@ sd_register_devid(struct sd_lun *un, dev_info_t *devi, int reservation_flag)
*/
static int
-sd_get_devid(struct sd_lun *un)
+sd_get_devid(sd_ssc_t *ssc)
{
struct dk_devid *dkdevid;
ddi_devid_t tmpid;
@@ -5056,7 +5218,10 @@ sd_get_devid(struct sd_lun *un)
int chksum;
int i;
size_t buffer_size;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(mutex_owned(SD_MUTEX(un)));
@@ -5084,9 +5249,11 @@ sd_get_devid(struct sd_lun *un)
buffer_size = SD_REQBYTES2TGTBYTES(un, sizeof (struct dk_devid));
mutex_exit(SD_MUTEX(un));
dkdevid = kmem_alloc(buffer_size, KM_SLEEP);
- status = sd_send_scsi_READ(un, dkdevid, buffer_size, blk,
+ status = sd_send_scsi_READ(ssc, dkdevid, buffer_size, blk,
SD_PATH_DIRECT);
+
if (status != 0) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
goto error;
}
@@ -5154,8 +5321,12 @@ error:
*/
static ddi_devid_t
-sd_create_devid(struct sd_lun *un)
+sd_create_devid(sd_ssc_t *ssc)
{
+ struct sd_lun *un;
+
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
/* Fabricate the devid */
@@ -5165,7 +5336,7 @@ sd_create_devid(struct sd_lun *un)
}
/* Write the devid to disk */
- if (sd_write_deviceid(un) != 0) {
+ if (sd_write_deviceid(ssc) != 0) {
ddi_devid_free(un->un_devid);
un->un_devid = NULL;
}
@@ -5189,14 +5360,18 @@ sd_create_devid(struct sd_lun *un)
*/
static int
-sd_write_deviceid(struct sd_lun *un)
+sd_write_deviceid(sd_ssc_t *ssc)
{
struct dk_devid *dkdevid;
diskaddr_t blk;
uint_t *ip, chksum;
int status;
int i;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
+ ASSERT(un != NULL);
ASSERT(mutex_owned(SD_MUTEX(un)));
mutex_exit(SD_MUTEX(un));
@@ -5232,8 +5407,10 @@ sd_write_deviceid(struct sd_lun *un)
DKD_FORMCHKSUM(chksum, dkdevid);
/* Write the reserved sector */
- status = sd_send_scsi_WRITE(un, dkdevid, un->un_sys_blocksize, blk,
+ status = sd_send_scsi_WRITE(ssc, dkdevid, un->un_sys_blocksize, blk,
SD_PATH_DIRECT);
+ if (status != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
kmem_free(dkdevid, un->un_sys_blocksize);
@@ -5260,7 +5437,7 @@ sd_write_deviceid(struct sd_lun *un)
*/
static int
-sd_check_vpd_page_support(struct sd_lun *un)
+sd_check_vpd_page_support(sd_ssc_t *ssc)
{
uchar_t *page_list = NULL;
uchar_t page_length = 0xff; /* Use max possible length */
@@ -5268,7 +5445,10 @@ sd_check_vpd_page_support(struct sd_lun *un)
uchar_t page_code = 0x00; /* Supported VPD Pages */
int rval = 0;
int counter;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(mutex_owned(SD_MUTEX(un)));
@@ -5280,9 +5460,12 @@ sd_check_vpd_page_support(struct sd_lun *un)
*/
page_list = kmem_zalloc(page_length, KM_SLEEP);
- rval = sd_send_scsi_INQUIRY(un, page_list, page_length, evpd,
+ rval = sd_send_scsi_INQUIRY(ssc, page_list, page_length, evpd,
page_code, NULL);
+ if (rval != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
mutex_enter(SD_MUTEX(un));
/*
@@ -5353,11 +5536,16 @@ sd_check_vpd_page_support(struct sd_lun *un)
*/
static void
-sd_setup_pm(struct sd_lun *un, dev_info_t *devi)
+sd_setup_pm(sd_ssc_t *ssc, dev_info_t *devi)
{
- uint_t log_page_size;
- uchar_t *log_page_data;
- int rval;
+ uint_t log_page_size;
+ uchar_t *log_page_data;
+ int rval = 0;
+ struct sd_lun *un;
+
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
+ ASSERT(un != NULL);
/*
* Since we are called from attach, holding a mutex for
@@ -5389,8 +5577,11 @@ sd_setup_pm(struct sd_lun *un, dev_info_t *devi)
* device has a motor.
*/
un->un_f_start_stop_supported = TRUE;
- if (sd_send_scsi_START_STOP_UNIT(un, SD_TARGET_START,
- SD_PATH_DIRECT) != 0) {
+ rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START,
+ SD_PATH_DIRECT);
+
+ if (rval != 0) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
un->un_f_start_stop_supported = FALSE;
}
@@ -5409,7 +5600,7 @@ sd_setup_pm(struct sd_lun *un, dev_info_t *devi)
return;
}
- rval = sd_log_page_supported(un, START_STOP_CYCLE_PAGE);
+ rval = sd_log_page_supported(ssc, START_STOP_CYCLE_PAGE);
#ifdef SDDEBUG
if (sd_force_pm_supported) {
@@ -5440,7 +5631,7 @@ sd_setup_pm(struct sd_lun *un, dev_info_t *devi)
* START_STOP_CYCLE_PAGE_VU_PAGE (0x31) in older disks. For
* newer disks it is implemented as START_STOP_CYCLE_PAGE (0xE).
*/
- if (sd_log_page_supported(un, START_STOP_CYCLE_VU_PAGE) == 1) {
+ if (sd_log_page_supported(ssc, START_STOP_CYCLE_VU_PAGE) == 1) {
/*
* Page found, use this one.
*/
@@ -5467,9 +5658,14 @@ sd_setup_pm(struct sd_lun *un, dev_info_t *devi)
log_page_size = START_STOP_CYCLE_COUNTER_PAGE_SIZE;
log_page_data = kmem_zalloc(log_page_size, KM_SLEEP);
- rval = sd_send_scsi_LOG_SENSE(un, log_page_data,
+ rval = sd_send_scsi_LOG_SENSE(ssc, log_page_data,
log_page_size, un->un_start_stop_cycle_page,
0x01, 0, SD_PATH_DIRECT);
+
+ if (rval != 0) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+
#ifdef SDDEBUG
if (sd_force_pm_supported) {
/* Force a successful result */
@@ -6062,6 +6258,7 @@ sdpower(dev_info_t *devi, int component, int level)
int sval;
uchar_t state_before_pm;
int got_semaphore_here;
+ sd_ssc_t *ssc;
instance = ddi_get_instance(devi);
@@ -6072,6 +6269,7 @@ sdpower(dev_info_t *devi, int component, int level)
}
dev = sd_make_device(SD_DEVINFO(un));
+ ssc = sd_ssc_init(un);
SD_TRACE(SD_LOG_IO_PM, un, "sdpower: entry, level = %d\n", level);
@@ -6109,7 +6307,8 @@ sdpower(dev_info_t *devi, int component, int level)
}
SD_TRACE(SD_LOG_IO_PM, un,
"sdpower: exit, device has queued cmds.\n");
- return (DDI_FAILURE);
+
+ goto sdpower_failed;
}
/*
@@ -6129,7 +6328,8 @@ sdpower(dev_info_t *devi, int component, int level)
}
SD_TRACE(SD_LOG_IO_PM, un,
"sdpower: exit, device is off-line.\n");
- return (DDI_FAILURE);
+
+ goto sdpower_failed;
}
/*
@@ -6160,8 +6360,16 @@ sdpower(dev_info_t *devi, int component, int level)
log_sense_page = un->un_start_stop_cycle_page;
mutex_exit(SD_MUTEX(un));
- rval = sd_send_scsi_LOG_SENSE(un, log_page_data,
+ rval = sd_send_scsi_LOG_SENSE(ssc, log_page_data,
log_page_size, log_sense_page, 0x01, 0, SD_PATH_DIRECT);
+
+ if (rval != 0) {
+ if (rval == EIO)
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+
#ifdef SDDEBUG
if (sd_force_pm_supported) {
/* Force a successful result */
@@ -6171,6 +6379,7 @@ sdpower(dev_info_t *devi, int component, int level)
if (rval != 0) {
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"Log Sense Failed\n");
+
kmem_free(log_page_data, log_page_size);
/* Cannot support power management on those drives */
@@ -6188,7 +6397,8 @@ sdpower(dev_info_t *devi, int component, int level)
mutex_exit(SD_MUTEX(un));
SD_TRACE(SD_LOG_IO_PM, un,
"sdpower: exit, Log Sense Failed.\n");
- return (DDI_FAILURE);
+
+ goto sdpower_failed;
}
/*
@@ -6280,8 +6490,8 @@ sdpower(dev_info_t *devi, int component, int level)
SD_TRACE(SD_LOG_IO_PM, un, "sdpower: exit, "
"trans check Failed, not ok to power cycle.\n");
- return (DDI_FAILURE);
+ goto sdpower_failed;
case -1:
if (got_semaphore_here != 0) {
sema_v(&un->un_semoclose);
@@ -6297,7 +6507,8 @@ sdpower(dev_info_t *devi, int component, int level)
mutex_exit(SD_MUTEX(un));
SD_TRACE(SD_LOG_IO_PM, un,
"sdpower: exit, trans check command Failed.\n");
- return (DDI_FAILURE);
+
+ goto sdpower_failed;
}
}
@@ -6335,7 +6546,8 @@ sdpower(dev_info_t *devi, int component, int level)
mutex_exit(SD_MUTEX(un));
SD_TRACE(SD_LOG_IO_PM, un,
"sdpower: exit, PM suspend Failed.\n");
- return (DDI_FAILURE);
+
+ goto sdpower_failed;
}
}
@@ -6353,16 +6565,25 @@ sdpower(dev_info_t *devi, int component, int level)
* a deadlock on un_pm_busy_cv will occur.
*/
if (level == SD_SPINDLE_ON) {
- (void) sd_send_scsi_TEST_UNIT_READY(un,
+ sval = sd_send_scsi_TEST_UNIT_READY(ssc,
SD_DONT_RETRY_TUR | SD_BYPASS_PM);
+ if (sval != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
}
SD_TRACE(SD_LOG_IO_PM, un, "sdpower: sending \'%s\' unit\n",
((level == SD_SPINDLE_ON) ? "START" : "STOP"));
- sval = sd_send_scsi_START_STOP_UNIT(un,
+ sval = sd_send_scsi_START_STOP_UNIT(ssc,
((level == SD_SPINDLE_ON) ? SD_TARGET_START : SD_TARGET_STOP),
SD_PATH_DIRECT);
+ if (sval != 0) {
+ if (sval == EIO)
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+
/* Command failed, check for media present. */
if ((sval == ENXIO) && un->un_f_has_removable_media) {
medium_present = FALSE;
@@ -6475,7 +6696,13 @@ sdpower(dev_info_t *devi, int component, int level)
SD_TRACE(SD_LOG_IO_PM, un, "sdpower: exit, status = 0x%x\n", rval);
+ sd_ssc_fini(ssc);
return (rval);
+
+sdpower_failed:
+
+ sd_ssc_fini(ssc);
+ return (DDI_FAILURE);
}
@@ -6599,6 +6826,9 @@ sd_unit_attach(dev_info_t *devi)
dev_info_t *pdip = ddi_get_parent(devi);
int offbyone = 0;
int geom_label_valid = 0;
+ sd_ssc_t *ssc;
+ int status;
+ struct sd_fm_internal *sfip = NULL;
#if defined(__sparc)
int max_xfer_size;
#endif
@@ -7255,6 +7485,20 @@ sd_unit_attach(dev_info_t *devi)
un->un_pkt_flags = 0;
}
+ /* Initialize sd_ssc_t for internal uscsi commands */
+ ssc = sd_ssc_init(un);
+ scsi_fm_init(devp);
+
+ /*
+ * Allocate memory for SCSI FMA stuffs.
+ */
+ un->un_fm_private =
+ kmem_zalloc(sizeof (struct sd_fm_internal), KM_SLEEP);
+ sfip = (struct sd_fm_internal *)un->un_fm_private;
+ sfip->fm_ssc.ssc_uscsi_cmd = &sfip->fm_ucmd;
+ sfip->fm_ssc.ssc_uscsi_info = &sfip->fm_uinfo;
+ sfip->fm_ssc.ssc_un = un;
+
/*
* At this point in the attach, we have enough info in the
* soft state to be able to issue commands to the target.
@@ -7276,8 +7520,11 @@ sd_unit_attach(dev_info_t *devi)
* Pass in flag SD_DONT_RETRY_TUR to prevent the long delays associated
* with attempts at spinning up a device with no media.
*/
- if (sd_send_scsi_TEST_UNIT_READY(un, SD_DONT_RETRY_TUR) == EACCES) {
- reservation_flag = SD_TARGET_IS_RESERVED;
+ status = sd_send_scsi_TEST_UNIT_READY(ssc, SD_DONT_RETRY_TUR);
+ if (status != 0) {
+ if (status == EACCES)
+ reservation_flag = SD_TARGET_IS_RESERVED;
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
}
/*
@@ -7288,7 +7535,8 @@ sd_unit_attach(dev_info_t *devi)
* the attach despite the failure (see below).
*/
if (un->un_f_descr_format_supported) {
- switch (sd_spin_up_unit(un)) {
+
+ switch (sd_spin_up_unit(ssc)) {
case 0:
/*
* Spin-up was successful; now try to read the
@@ -7298,12 +7546,14 @@ sd_unit_attach(dev_info_t *devi)
SD_TRACE(SD_LOG_ATTACH_DETACH, un,
"sd_unit_attach: un:0x%p spin-up successful\n", un);
- switch (sd_send_scsi_READ_CAPACITY(un, &capacity,
- &lbasize, SD_PATH_DIRECT)) {
+ status = sd_send_scsi_READ_CAPACITY(ssc, &capacity,
+ &lbasize, SD_PATH_DIRECT);
+
+ switch (status) {
case 0: {
if (capacity > DK_MAX_BLOCKS) {
#ifdef _LP64
- if (capacity + 1 >
+ if ((capacity + 1) >
SD_GROUP1_MAX_ADDRESS) {
/*
* Enable descriptor format
@@ -7311,7 +7561,7 @@ sd_unit_attach(dev_info_t *devi)
* get 64 bit sense data
* fields.
*/
- sd_enable_descr_sense(un);
+ sd_enable_descr_sense(ssc);
}
#else
/* 32-bit kernels can't handle this */
@@ -7373,6 +7623,8 @@ sd_unit_attach(dev_info_t *devi)
sd_label, CE_WARN,
"disk capacity is too large "
"for current cdb length");
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
goto spinup_failed;
case EACCES:
/*
@@ -7385,6 +7637,7 @@ sd_unit_attach(dev_info_t *devi)
"sd_send_scsi_READ_CAPACITY "
"returned reservation conflict\n", un);
reservation_flag = SD_TARGET_IS_RESERVED;
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
break;
default:
/*
@@ -7392,6 +7645,12 @@ sd_unit_attach(dev_info_t *devi)
* spin-up succeeded. Just continue with
* the attach...
*/
+ if (status == EIO)
+ sd_ssc_assessment(ssc,
+ SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc,
+ SD_FMT_IGNORE);
break;
}
break;
@@ -7412,13 +7671,14 @@ sd_unit_attach(dev_info_t *devi)
"sd_unit_attach: un:0x%p spin-up failed.", un);
goto spinup_failed;
}
+
}
/*
* Check to see if this is a MMC drive
*/
if (ISCD(un)) {
- sd_set_mmc_caps(un);
+ sd_set_mmc_caps(ssc);
}
@@ -7441,7 +7701,7 @@ sd_unit_attach(dev_info_t *devi)
*/
mutex_init(&un->un_pm_mutex, NULL, MUTEX_DRIVER, NULL);
cv_init(&un->un_pm_busy_cv, NULL, CV_DRIVER, NULL);
- sd_setup_pm(un, devi);
+ sd_setup_pm(ssc, devi);
if (un->un_f_pm_is_enabled == FALSE) {
/*
* For performance, point to a jump table that does
@@ -7536,7 +7796,7 @@ sd_unit_attach(dev_info_t *devi)
* Read and initialize the devid for the unit.
*/
if (un->un_f_devid_supported) {
- sd_register_devid(un, devi, reservation_flag);
+ sd_register_devid(ssc, devi, reservation_flag);
}
mutex_exit(SD_MUTEX(un));
@@ -7562,7 +7822,7 @@ sd_unit_attach(dev_info_t *devi)
* Disable both read cache and write cache. This is
* the historic behavior of the keywords in the config file.
*/
- if (sd_cache_control(un, SD_CACHE_DISABLE, SD_CACHE_DISABLE) !=
+ if (sd_cache_control(ssc, SD_CACHE_DISABLE, SD_CACHE_DISABLE) !=
0) {
SD_ERROR(SD_LOG_ATTACH_DETACH, un,
"sd_unit_attach: un:0x%p Could not disable "
@@ -7575,7 +7835,7 @@ sd_unit_attach(dev_info_t *devi)
* Check the value of the WCE bit now and
* set un_f_write_cache_enabled accordingly.
*/
- (void) sd_get_write_cache_enabled(un, &wc_enabled);
+ (void) sd_get_write_cache_enabled(ssc, &wc_enabled);
mutex_enter(SD_MUTEX(un));
un->un_f_write_cache_enabled = (wc_enabled != 0);
mutex_exit(SD_MUTEX(un));
@@ -7584,12 +7844,14 @@ sd_unit_attach(dev_info_t *devi)
* Check the value of the NV_SUP bit and set
* un_f_suppress_cache_flush accordingly.
*/
- sd_get_nv_sup(un);
+ sd_get_nv_sup(ssc);
/*
* Find out what type of reservation this disk supports.
*/
- switch (sd_send_scsi_PERSISTENT_RESERVE_IN(un, SD_READ_KEYS, 0, NULL)) {
+ status = sd_send_scsi_PERSISTENT_RESERVE_IN(ssc, SD_READ_KEYS, 0, NULL);
+
+ switch (status) {
case 0:
/*
* SCSI-3 reservations are supported.
@@ -7606,6 +7868,8 @@ sd_unit_attach(dev_info_t *devi)
SD_INFO(SD_LOG_ATTACH_DETACH, un,
"sd_unit_attach: un:0x%p SCSI-2 reservations\n", un);
un->un_reservation_type = SD_SCSI2_RESERVATION;
+
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
break;
default:
/*
@@ -7614,6 +7878,8 @@ sd_unit_attach(dev_info_t *devi)
SD_INFO(SD_LOG_ATTACH_DETACH, un,
"sd_unit_attach: un:0x%p default SCSI3 reservations\n", un);
un->un_reservation_type = SD_SCSI3_RESERVATION;
+
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
break;
}
@@ -7654,6 +7920,9 @@ sd_unit_attach(dev_info_t *devi)
SD_TRACE(SD_LOG_ATTACH_DETACH, un,
"sd_unit_attach: un:0x%p exit success\n", un);
+ /* Uninitialize sd_ssc_t pointer */
+ sd_ssc_fini(ssc);
+
return (DDI_SUCCESS);
/*
@@ -7687,8 +7956,14 @@ cmlb_attach_failed:
spinup_failed:
+ /* Uninitialize sd_ssc_t pointer */
+ sd_ssc_fini(ssc);
+
mutex_enter(SD_MUTEX(un));
+ /* Deallocate SCSI FMA memory spaces */
+ kmem_free(un->un_fm_private, sizeof (struct sd_fm_internal));
+
/* Cancel callback for SD_PATH_DIRECT_PRIORITY cmd. restart */
if (un->un_direct_priority_timeid != NULL) {
timeout_id_t temp_id = un->un_direct_priority_timeid;
@@ -8149,6 +8424,13 @@ sd_unit_detach(dev_info_t *devi)
* At this point there should be no competing threads anymore.
*/
+ scsi_fm_fini(devp);
+
+ /*
+ * Deallocate memory for SCSI FMA.
+ */
+ kmem_free(un->un_fm_private, sizeof (struct sd_fm_internal));
+
/* Unregister and free device id. */
ddi_devid_unregister(devi);
if (un->un_devid) {
@@ -8582,7 +8864,8 @@ sd_event_callback(dev_info_t *dip, ddi_eventcookie_t event, void *arg,
* enable) and RCD (read cache disable) bits of mode
* page 8 (MODEPAGE_CACHING).
*
- * Arguments: un - driver soft state (unit) structure
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
* rcd_flag - flag for controlling the read cache
* wce_flag - flag for controlling the write cache
*
@@ -8594,7 +8877,7 @@ sd_event_callback(dev_info_t *dip, ddi_eventcookie_t event, void *arg,
*/
static int
-sd_cache_control(struct sd_lun *un, int rcd_flag, int wce_flag)
+sd_cache_control(sd_ssc_t *ssc, int rcd_flag, int wce_flag)
{
struct mode_caching *mode_caching_page;
uchar_t *header;
@@ -8603,14 +8886,20 @@ sd_cache_control(struct sd_lun *un, int rcd_flag, int wce_flag)
int bd_len;
int rval = 0;
struct mode_header_grp2 *mhp;
+ struct sd_lun *un;
+ int status;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
/*
* Do a test unit ready, otherwise a mode sense may not work if this
* is the first command sent to the device after boot.
*/
- (void) sd_send_scsi_TEST_UNIT_READY(un, 0);
+ status = sd_send_scsi_TEST_UNIT_READY(ssc, 0);
+ if (status != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
if (un->un_f_cfg_is_atapi == TRUE) {
hdrlen = MODE_HEADER_LENGTH_GRP2;
@@ -8631,17 +8920,17 @@ sd_cache_control(struct sd_lun *un, int rcd_flag, int wce_flag)
/* Get the information from the device. */
if (un->un_f_cfg_is_atapi == TRUE) {
- rval = sd_send_scsi_MODE_SENSE(un, CDB_GROUP1, header, buflen,
+ rval = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP1, header, buflen,
MODEPAGE_CACHING, SD_PATH_DIRECT);
} else {
- rval = sd_send_scsi_MODE_SENSE(un, CDB_GROUP0, header, buflen,
+ rval = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP0, header, buflen,
MODEPAGE_CACHING, SD_PATH_DIRECT);
}
+
if (rval != 0) {
SD_ERROR(SD_LOG_IOCTL_RMMEDIA, un,
"sd_cache_control: Mode Sense Failed\n");
- kmem_free(header, buflen);
- return (rval);
+ goto mode_sense_failed;
}
/*
@@ -8660,8 +8949,11 @@ sd_cache_control(struct sd_lun *un, int rcd_flag, int wce_flag)
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"sd_cache_control: Mode Sense returned invalid "
"block descriptor length\n");
- kmem_free(header, buflen);
- return (EIO);
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_cache_control: Mode Sense returned invalid "
+ "block descriptor length");
+ rval = EIO;
+ goto mode_sense_failed;
}
mode_caching_page = (struct mode_caching *)(header + hdrlen + bd_len);
@@ -8669,8 +8961,11 @@ sd_cache_control(struct sd_lun *un, int rcd_flag, int wce_flag)
SD_ERROR(SD_LOG_COMMON, un, "sd_cache_control: Mode Sense"
" caching page code mismatch %d\n",
mode_caching_page->mode_page.code);
- kmem_free(header, buflen);
- return (EIO);
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_cache_control: Mode Sense caching page code "
+ "mismatch %d", mode_caching_page->mode_page.code);
+ rval = EIO;
+ goto mode_sense_failed;
}
/* Check the relevant bits on successful mode sense. */
@@ -8727,17 +9022,30 @@ sd_cache_control(struct sd_lun *un, int rcd_flag, int wce_flag)
((struct mode_header *)header)->bdesc_length = bd_len;
}
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
/* Issue mode select to change the cache settings */
if (un->un_f_cfg_is_atapi == TRUE) {
- rval = sd_send_scsi_MODE_SELECT(un, CDB_GROUP1, header,
+ rval = sd_send_scsi_MODE_SELECT(ssc, CDB_GROUP1, header,
sbuflen, save_pg, SD_PATH_DIRECT);
} else {
- rval = sd_send_scsi_MODE_SELECT(un, CDB_GROUP0, header,
+ rval = sd_send_scsi_MODE_SELECT(ssc, CDB_GROUP0, header,
sbuflen, save_pg, SD_PATH_DIRECT);
}
+
}
+
+mode_sense_failed:
+
kmem_free(header, buflen);
+
+ if (rval != 0) {
+ if (rval == EIO)
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
return (rval);
}
@@ -8749,7 +9057,8 @@ sd_cache_control(struct sd_lun *un, int rcd_flag, int wce_flag)
* write caching is enabled. It examines the WCE (write cache
* enable) bits of mode page 8 (MODEPAGE_CACHING).
*
- * Arguments: un - driver soft state (unit) structure
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
* is_enabled - pointer to int where write cache enabled state
* is returned (non-zero -> write cache enabled)
*
@@ -8773,7 +9082,7 @@ sd_cache_control(struct sd_lun *un, int rcd_flag, int wce_flag)
*/
static int
-sd_get_write_cache_enabled(struct sd_lun *un, int *is_enabled)
+sd_get_write_cache_enabled(sd_ssc_t *ssc, int *is_enabled)
{
struct mode_caching *mode_caching_page;
uchar_t *header;
@@ -8781,7 +9090,11 @@ sd_get_write_cache_enabled(struct sd_lun *un, int *is_enabled)
int hdrlen;
int bd_len;
int rval = 0;
+ struct sd_lun *un;
+ int status;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(is_enabled != NULL);
@@ -8792,7 +9105,10 @@ sd_get_write_cache_enabled(struct sd_lun *un, int *is_enabled)
* Do a test unit ready, otherwise a mode sense may not work if this
* is the first command sent to the device after boot.
*/
- (void) sd_send_scsi_TEST_UNIT_READY(un, 0);
+ status = sd_send_scsi_TEST_UNIT_READY(ssc, 0);
+
+ if (status != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
if (un->un_f_cfg_is_atapi == TRUE) {
hdrlen = MODE_HEADER_LENGTH_GRP2;
@@ -8809,17 +9125,17 @@ sd_get_write_cache_enabled(struct sd_lun *un, int *is_enabled)
/* Get the information from the device. */
if (un->un_f_cfg_is_atapi == TRUE) {
- rval = sd_send_scsi_MODE_SENSE(un, CDB_GROUP1, header, buflen,
+ rval = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP1, header, buflen,
MODEPAGE_CACHING, SD_PATH_DIRECT);
} else {
- rval = sd_send_scsi_MODE_SENSE(un, CDB_GROUP0, header, buflen,
+ rval = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP0, header, buflen,
MODEPAGE_CACHING, SD_PATH_DIRECT);
}
+
if (rval != 0) {
SD_ERROR(SD_LOG_IOCTL_RMMEDIA, un,
"sd_get_write_cache_enabled: Mode Sense Failed\n");
- kmem_free(header, buflen);
- return (rval);
+ goto mode_sense_failed;
}
/*
@@ -8839,8 +9155,12 @@ sd_get_write_cache_enabled(struct sd_lun *un, int *is_enabled)
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"sd_get_write_cache_enabled: Mode Sense returned invalid "
"block descriptor length\n");
- kmem_free(header, buflen);
- return (EIO);
+ /* FMA should make upset complain here */
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_get_write_cache_enabled: Mode Sense returned invalid "
+ "block descriptor length %d", bd_len);
+ rval = EIO;
+ goto mode_sense_failed;
}
mode_caching_page = (struct mode_caching *)(header + hdrlen + bd_len);
@@ -8848,13 +9168,42 @@ sd_get_write_cache_enabled(struct sd_lun *un, int *is_enabled)
SD_ERROR(SD_LOG_COMMON, un, "sd_cache_control: Mode Sense"
" caching page code mismatch %d\n",
mode_caching_page->mode_page.code);
- kmem_free(header, buflen);
- return (EIO);
+ /* FMA could make upset complain here */
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_cache_control: Mode Sense caching page code "
+ "mismatch %d", mode_caching_page->mode_page.code);
+ rval = EIO;
+ goto mode_sense_failed;
}
*is_enabled = mode_caching_page->wce;
+mode_sense_failed:
+ if (rval == 0) {
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
+ } else if (rval == EIO) {
+ /*
+ * Some disks do not support mode sense(6), we
+ * should ignore this kind of error(sense key is
+ * 0x5 - illegal request).
+ */
+ uint8_t *sensep;
+ int senlen;
+
+ sensep = (uint8_t *)ssc->ssc_uscsi_cmd->uscsi_rqbuf;
+ senlen = (int)(ssc->ssc_uscsi_cmd->uscsi_rqlen -
+ ssc->ssc_uscsi_cmd->uscsi_rqresid);
+
+ if (senlen > 0 &&
+ scsi_sense_key(sensep) == KEY_ILLEGAL_REQUEST) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE_COMPROMISE);
+ } else {
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ }
+ } else {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
kmem_free(header, buflen);
- return (0);
+ return (rval);
}
/*
@@ -8892,14 +9241,17 @@ sd_get_write_cache_enabled(struct sd_lun *un, int *is_enabled)
*/
static void
-sd_get_nv_sup(struct sd_lun *un)
+sd_get_nv_sup(sd_ssc_t *ssc)
{
int rval = 0;
uchar_t *inq86 = NULL;
size_t inq86_len = MAX_INQUIRY_SIZE;
size_t inq86_resid = 0;
struct dk_callback *dkc;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
mutex_enter(SD_MUTEX(un));
@@ -8921,12 +9273,13 @@ sd_get_nv_sup(struct sd_lun *un)
return;
}
- if (sd_check_vpd_page_support(un) == 0 &&
+ if (sd_check_vpd_page_support(ssc) == 0 &&
un->un_vpd_page_mask & SD_VPD_EXTENDED_DATA_PG) {
mutex_exit(SD_MUTEX(un));
/* collect page 86 data if available */
inq86 = kmem_zalloc(inq86_len, KM_SLEEP);
- rval = sd_send_scsi_INQUIRY(un, inq86, inq86_len,
+
+ rval = sd_send_scsi_INQUIRY(ssc, inq86, inq86_len,
0x01, 0x86, &inq86_resid);
if (rval == 0 && (inq86_len - inq86_resid > 6)) {
@@ -8946,7 +9299,10 @@ sd_get_nv_sup(struct sd_lun *un)
un->un_f_sync_nv_supported = TRUE;
}
mutex_exit(SD_MUTEX(un));
+ } else if (rval != 0) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
}
+
kmem_free(inq86, inq86_len);
} else {
mutex_exit(SD_MUTEX(un));
@@ -8968,7 +9324,9 @@ sd_get_nv_sup(struct sd_lun *un)
* Send a TEST UNIT READY command to the device. This should
* clear any outstanding UNIT ATTENTION that may be present.
*/
- (void) sd_send_scsi_TEST_UNIT_READY(un, SD_DONT_RETRY_TUR);
+ rval = sd_send_scsi_TEST_UNIT_READY(ssc, SD_DONT_RETRY_TUR);
+ if (rval != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
kmem_free(dkc, sizeof (struct dk_callback));
} else {
@@ -9406,8 +9764,12 @@ sdopen(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
* Check if disk is ready and has a valid geometry later.
*/
if (!nodelay) {
+ sd_ssc_t *ssc;
+
mutex_exit(SD_MUTEX(un));
- rval = sd_ready_and_valid(un, part);
+ ssc = sd_ssc_init(un);
+ rval = sd_ready_and_valid(ssc, part);
+ sd_ssc_fini(ssc);
mutex_enter(SD_MUTEX(un));
/*
* Fail if device is not ready or if the number of disk
@@ -9679,8 +10041,15 @@ sdclose(dev_t dev, int flag, int otyp, cred_t *cred_p)
if (un->un_f_doorlock_supported) {
mutex_exit(SD_MUTEX(un));
if (sd_pm_entry(un) == DDI_SUCCESS) {
- rval = sd_send_scsi_DOORLOCK(un,
+ sd_ssc_t *ssc;
+
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_DOORLOCK(ssc,
SD_REMOVAL_ALLOW, SD_PATH_DIRECT);
+ if (rval != 0)
+ sd_ssc_assessment(ssc,
+ SD_FMT_IGNORE);
+ sd_ssc_fini(ssc);
sd_pm_exit(un);
if (ISCD(un) && (rval != 0) &&
@@ -9749,7 +10118,7 @@ sdclose(dev_t dev, int flag, int otyp, cred_t *cred_p)
*
* Description: Test if device is ready and has a valid geometry.
*
- * Arguments: dev - device number
+ * Arguments: ssc - sd_ssc_t will contain un
* un - driver soft state (unit) structure
*
* Return Code: SD_READY_VALID ready and valid label
@@ -9760,7 +10129,7 @@ sdclose(dev_t dev, int flag, int otyp, cred_t *cred_p)
*/
static int
-sd_ready_and_valid(struct sd_lun *un, int part)
+sd_ready_and_valid(sd_ssc_t *ssc, int part)
{
struct sd_errstats *stp;
uint64_t capacity;
@@ -9768,7 +10137,11 @@ sd_ready_and_valid(struct sd_lun *un, int part)
int rval = SD_READY_VALID;
char name_str[48];
int is_valid;
+ struct sd_lun *un;
+ int status;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
@@ -9779,9 +10152,15 @@ sd_ready_and_valid(struct sd_lun *un, int part)
*/
if (un->un_f_has_removable_media) {
mutex_exit(SD_MUTEX(un));
- if (sd_send_scsi_TEST_UNIT_READY(un, 0) != 0) {
+ status = sd_send_scsi_TEST_UNIT_READY(ssc, 0);
+
+ if (status != 0) {
rval = SD_NOT_READY_VALID;
mutex_enter(SD_MUTEX(un));
+
+ /* Ignore all failed status for removalbe media */
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
goto done;
}
@@ -9793,12 +10172,17 @@ sd_ready_and_valid(struct sd_lun *un, int part)
/* capacity has to be read every open. */
mutex_exit(SD_MUTEX(un));
- if (sd_send_scsi_READ_CAPACITY(un, &capacity,
- &lbasize, SD_PATH_DIRECT) != 0) {
+ status = sd_send_scsi_READ_CAPACITY(ssc, &capacity,
+ &lbasize, SD_PATH_DIRECT);
+
+ if (status != 0) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
cmlb_invalidate(un->un_cmlbhandle,
(void *)SD_PATH_DIRECT);
mutex_enter(SD_MUTEX(un));
rval = SD_NOT_READY_VALID;
+
goto done;
} else {
mutex_enter(SD_MUTEX(un));
@@ -9810,7 +10194,7 @@ sd_ready_and_valid(struct sd_lun *un, int part)
* Check if the media in the device is writable or not.
*/
if (!is_valid && ISCD(un)) {
- sd_check_for_writable_cd(un, SD_PATH_DIRECT);
+ sd_check_for_writable_cd(ssc, SD_PATH_DIRECT);
}
} else {
@@ -9819,7 +10203,12 @@ sd_ready_and_valid(struct sd_lun *un, int part)
* devices.
*/
mutex_exit(SD_MUTEX(un));
- (void) sd_send_scsi_TEST_UNIT_READY(un, 0);
+
+ status = sd_send_scsi_TEST_UNIT_READY(ssc, 0);
+ if (status != 0) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+
mutex_enter(SD_MUTEX(un));
}
@@ -9842,8 +10231,8 @@ sd_ready_and_valid(struct sd_lun *un, int part)
sd_wm_cache_destructor, NULL,
(void *)un, NULL, 0);
if (!(un->un_wm_cache)) {
- rval = ENOMEM;
- goto done;
+ rval = ENOMEM;
+ goto done;
}
}
}
@@ -9863,7 +10252,7 @@ sd_ready_and_valid(struct sd_lun *un, int part)
int err;
mutex_exit(SD_MUTEX(un));
- err = sd_send_scsi_TEST_UNIT_READY(un, 0);
+ err = sd_send_scsi_TEST_UNIT_READY(ssc, 0);
mutex_enter(SD_MUTEX(un));
if (err != 0) {
@@ -9875,10 +10264,12 @@ sd_ready_and_valid(struct sd_lun *un, int part)
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"reservation conflict\n");
rval = SD_RESERVED_BY_OTHERS;
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
} else {
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"drive offline\n");
rval = SD_NOT_READY_VALID;
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
}
goto done;
}
@@ -9891,6 +10282,7 @@ sd_ready_and_valid(struct sd_lun *un, int part)
NULL, (void *) SD_PATH_DIRECT) != 0) {
rval = SD_NOT_READY_VALID;
mutex_enter(SD_MUTEX(un));
+
goto done;
}
if (un->un_f_pkstats_enabled) {
@@ -9909,12 +10301,18 @@ sd_ready_and_valid(struct sd_lun *un, int part)
*/
if (un->un_f_doorlock_supported) {
mutex_exit(SD_MUTEX(un));
- if ((sd_send_scsi_DOORLOCK(un, SD_REMOVAL_PREVENT,
- SD_PATH_DIRECT) != 0) && ISCD(un)) {
+ status = sd_send_scsi_DOORLOCK(ssc, SD_REMOVAL_PREVENT,
+ SD_PATH_DIRECT);
+
+ if ((status != 0) && ISCD(un)) {
rval = SD_NOT_READY_VALID;
mutex_enter(SD_MUTEX(un));
+
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
goto done;
- }
+ } else if (status != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
mutex_enter(SD_MUTEX(un));
}
@@ -9996,7 +10394,8 @@ sdread(dev_t dev, struct uio *uio, cred_t *cred_p)
{
struct sd_lun *un = NULL;
int secmask;
- int err;
+ int err = 0;
+ sd_ssc_t *ssc;
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL) {
return (ENXIO);
@@ -10004,6 +10403,7 @@ sdread(dev_t dev, struct uio *uio, cred_t *cred_p)
ASSERT(!mutex_owned(SD_MUTEX(un)));
+
if (!SD_IS_VALID_LABEL(un) && !ISCD(un)) {
mutex_enter(SD_MUTEX(un));
/*
@@ -10017,17 +10417,22 @@ sdread(dev_t dev, struct uio *uio, cred_t *cred_p)
}
un->un_ncmds_in_driver++;
mutex_exit(SD_MUTEX(un));
- if ((sd_ready_and_valid(un, SDPART(dev))) != SD_READY_VALID) {
- mutex_enter(SD_MUTEX(un));
- un->un_ncmds_in_driver--;
- ASSERT(un->un_ncmds_in_driver >= 0);
- mutex_exit(SD_MUTEX(un));
- return (EIO);
+
+ /* Initialize sd_ssc_t for internal uscsi commands */
+ ssc = sd_ssc_init(un);
+ if ((sd_ready_and_valid(ssc, SDPART(dev))) != SD_READY_VALID) {
+ err = EIO;
+ } else {
+ err = 0;
}
+ sd_ssc_fini(ssc);
+
mutex_enter(SD_MUTEX(un));
un->un_ncmds_in_driver--;
ASSERT(un->un_ncmds_in_driver >= 0);
mutex_exit(SD_MUTEX(un));
+ if (err != 0)
+ return (err);
}
/*
@@ -10048,6 +10453,7 @@ sdread(dev_t dev, struct uio *uio, cred_t *cred_p)
} else {
err = physio(sdstrategy, NULL, dev, B_READ, sdmin, uio);
}
+
return (err);
}
@@ -10075,7 +10481,8 @@ sdwrite(dev_t dev, struct uio *uio, cred_t *cred_p)
{
struct sd_lun *un = NULL;
int secmask;
- int err;
+ int err = 0;
+ sd_ssc_t *ssc;
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL) {
return (ENXIO);
@@ -10096,17 +10503,22 @@ sdwrite(dev_t dev, struct uio *uio, cred_t *cred_p)
}
un->un_ncmds_in_driver++;
mutex_exit(SD_MUTEX(un));
- if ((sd_ready_and_valid(un, SDPART(dev))) != SD_READY_VALID) {
- mutex_enter(SD_MUTEX(un));
- un->un_ncmds_in_driver--;
- ASSERT(un->un_ncmds_in_driver >= 0);
- mutex_exit(SD_MUTEX(un));
- return (EIO);
+
+ /* Initialize sd_ssc_t for internal uscsi commands */
+ ssc = sd_ssc_init(un);
+ if ((sd_ready_and_valid(ssc, SDPART(dev))) != SD_READY_VALID) {
+ err = EIO;
+ } else {
+ err = 0;
}
+ sd_ssc_fini(ssc);
+
mutex_enter(SD_MUTEX(un));
un->un_ncmds_in_driver--;
ASSERT(un->un_ncmds_in_driver >= 0);
mutex_exit(SD_MUTEX(un));
+ if (err != 0)
+ return (err);
}
/*
@@ -10127,6 +10539,7 @@ sdwrite(dev_t dev, struct uio *uio, cred_t *cred_p)
} else {
err = physio(sdstrategy, NULL, dev, B_WRITE, sdmin, uio);
}
+
return (err);
}
@@ -10154,7 +10567,8 @@ sdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p)
struct sd_lun *un = NULL;
struct uio *uio = aio->aio_uio;
int secmask;
- int err;
+ int err = 0;
+ sd_ssc_t *ssc;
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL) {
return (ENXIO);
@@ -10175,17 +10589,22 @@ sdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p)
}
un->un_ncmds_in_driver++;
mutex_exit(SD_MUTEX(un));
- if ((sd_ready_and_valid(un, SDPART(dev))) != SD_READY_VALID) {
- mutex_enter(SD_MUTEX(un));
- un->un_ncmds_in_driver--;
- ASSERT(un->un_ncmds_in_driver >= 0);
- mutex_exit(SD_MUTEX(un));
- return (EIO);
+
+ /* Initialize sd_ssc_t for internal uscsi commands */
+ ssc = sd_ssc_init(un);
+ if ((sd_ready_and_valid(ssc, SDPART(dev))) != SD_READY_VALID) {
+ err = EIO;
+ } else {
+ err = 0;
}
+ sd_ssc_fini(ssc);
+
mutex_enter(SD_MUTEX(un));
un->un_ncmds_in_driver--;
ASSERT(un->un_ncmds_in_driver >= 0);
mutex_exit(SD_MUTEX(un));
+ if (err != 0)
+ return (err);
}
/*
@@ -10206,6 +10625,7 @@ sdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p)
} else {
err = aphysio(sdstrategy, anocancel, dev, B_READ, sdmin, aio);
}
+
return (err);
}
@@ -10233,7 +10653,8 @@ sdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p)
struct sd_lun *un = NULL;
struct uio *uio = aio->aio_uio;
int secmask;
- int err;
+ int err = 0;
+ sd_ssc_t *ssc;
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL) {
return (ENXIO);
@@ -10254,17 +10675,22 @@ sdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p)
}
un->un_ncmds_in_driver++;
mutex_exit(SD_MUTEX(un));
- if ((sd_ready_and_valid(un, SDPART(dev))) != SD_READY_VALID) {
- mutex_enter(SD_MUTEX(un));
- un->un_ncmds_in_driver--;
- ASSERT(un->un_ncmds_in_driver >= 0);
- mutex_exit(SD_MUTEX(un));
- return (EIO);
+
+ /* Initialize sd_ssc_t for internal uscsi commands */
+ ssc = sd_ssc_init(un);
+ if ((sd_ready_and_valid(ssc, SDPART(dev))) != SD_READY_VALID) {
+ err = EIO;
+ } else {
+ err = 0;
}
+ sd_ssc_fini(ssc);
+
mutex_enter(SD_MUTEX(un));
un->un_ncmds_in_driver--;
ASSERT(un->un_ncmds_in_driver >= 0);
mutex_exit(SD_MUTEX(un));
+ if (err != 0)
+ return (err);
}
/*
@@ -10285,6 +10711,7 @@ sdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p)
} else {
err = aphysio(sdstrategy, anocancel, dev, B_WRITE, sdmin, aio);
}
+
return (err);
}
@@ -10677,6 +11104,7 @@ sd_xbuf_init(struct sd_lun *un, struct buf *bp, struct sd_xbuf *xp,
xp->xb_sense_status = 0;
xp->xb_sense_state = 0;
xp->xb_sense_resid = 0;
+ xp->xb_ena = 0;
bp->b_private = xp;
bp->b_flags &= ~(B_DONE | B_ERROR);
@@ -10819,37 +11247,218 @@ static int
sd_send_scsi_cmd(dev_t dev, struct uscsi_cmd *incmd, int flag,
enum uio_seg dataspace, int path_flag)
{
- struct sd_uscsi_info *uip;
- struct uscsi_cmd *uscmd;
struct sd_lun *un;
- int format = 0;
- int rval;
+ sd_ssc_t *ssc;
+ int rval;
un = ddi_get_soft_state(sd_state, SDUNIT(dev));
if (un == NULL) {
return (ENXIO);
}
+ /*
+ * Using sd_ssc_send to handle uscsi cmd
+ */
+ ssc = sd_ssc_init(un);
+ rval = sd_ssc_send(ssc, incmd, flag, dataspace, path_flag);
+ sd_ssc_fini(ssc);
+
+ return (rval);
+}
+
+/*
+ * Function: sd_ssc_init
+ *
+ * Description: Uscsi end-user call this function to initialize necessary
+ * fields, such as uscsi_cmd and sd_uscsi_info struct.
+ *
+ * The return value of sd_send_scsi_cmd will be treated as a
+ * fault in various conditions. Even it is not Zero, some
+ * callers may ignore the return value. That is to say, we can
+ * not make an accurate assessment in sdintr, since if a
+ * command is failed in sdintr it does not mean the caller of
+ * sd_send_scsi_cmd will treat it as a real failure.
+ *
+ * To avoid printing too many error logs for a failed uscsi
+ * packet that the caller may not treat it as a failure, the
+ * sd will keep silent for handling all uscsi commands.
+ *
+ * During detach->attach and attach-open, for some types of
+ * problems, the driver should be providing information about
+ * the problem encountered. Device use USCSI_SILENT, which
+ * suppresses all driver information. The result is that no
+ * information about the problem is available. Being
+ * completely silent during this time is inappropriate. The
+ * driver needs a more selective filter than USCSI_SILENT, so
+ * that information related to faults is provided.
+ *
+ * To make the accurate accessment, the caller of
+ * sd_send_scsi_USCSI_CMD should take the ownership and
+ * get necessary information to print error messages.
+ *
+ * If we want to print necessary info of uscsi command, we need to
+ * keep the uscsi_cmd and sd_uscsi_info till we can make the
+ * assessment. We use sd_ssc_init to alloc necessary
+ * structs for sending an uscsi command and we are also
+ * responsible for free the memory by calling
+ * sd_ssc_fini.
+ *
+ * The calling secquences will look like:
+ * sd_ssc_init->
+ *
+ * ...
+ *
+ * sd_send_scsi_USCSI_CMD->
+ * sd_ssc_send-> - - - sdintr
+ * ...
+ *
+ * if we think the return value should be treated as a
+ * failure, we make the accessment here and print out
+ * necessary by retrieving uscsi_cmd and sd_uscsi_info'
+ *
+ * ...
+ *
+ * sd_ssc_fini
+ *
+ *
+ * Arguments: un - pointer to driver soft state (unit) structure for this
+ * target.
+ *
+ * Return code: sd_ssc_t - pointer to allocated sd_ssc_t struct, it contains
+ * uscsi_cmd and sd_uscsi_info.
+ * NULL - if can not alloc memory for sd_ssc_t struct
+ *
+ * Context: Kernel Thread.
+ */
+static sd_ssc_t *
+sd_ssc_init(struct sd_lun *un)
+{
+ sd_ssc_t *ssc;
+ struct uscsi_cmd *ucmdp;
+ struct sd_uscsi_info *uip;
+
+ ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
+ /*
+ * Allocate sd_ssc_t structure
+ */
+ ssc = kmem_zalloc(sizeof (sd_ssc_t), KM_SLEEP);
+
+ /*
+ * Allocate uscsi_cmd by calling scsi_uscsi_alloc common routine
+ */
+ ucmdp = scsi_uscsi_alloc();
+
+ /*
+ * Allocate sd_uscsi_info structure
+ */
+ uip = kmem_zalloc(sizeof (struct sd_uscsi_info), KM_SLEEP);
+
+ ssc->ssc_uscsi_cmd = ucmdp;
+ ssc->ssc_uscsi_info = uip;
+ ssc->ssc_un = un;
+
+ return (ssc);
+}
+
+/*
+ * Function: sd_ssc_fini
+ *
+ * Description: To free sd_ssc_t and it's hanging off
+ *
+ * Arguments: ssc - struct pointer of sd_ssc_t.
+ */
+static void
+sd_ssc_fini(sd_ssc_t *ssc)
+{
+ scsi_uscsi_free(ssc->ssc_uscsi_cmd);
+
+ if (ssc->ssc_uscsi_info != NULL) {
+ kmem_free(ssc->ssc_uscsi_info, sizeof (struct sd_uscsi_info));
+ ssc->ssc_uscsi_info = NULL;
+ }
+
+ kmem_free(ssc, sizeof (sd_ssc_t));
+ ssc = NULL;
+}
+
+/*
+ * Function: sd_ssc_send
+ *
+ * Description: Runs a USCSI command for user when called through sdioctl,
+ * or for the driver.
+ *
+ * Arguments: ssc - the struct of sd_ssc_t will bring uscsi_cmd and
+ * sd_uscsi_info in.
+ * incmd - ptr to a valid uscsi_cmd struct
+ * flag - bit flag, indicating open settings, 32/64 bit type
+ * dataspace - UIO_USERSPACE or UIO_SYSSPACE
+ * path_flag - SD_PATH_DIRECT to use the USCSI "direct" chain and
+ * the normal command waitq, or SD_PATH_DIRECT_PRIORITY
+ * to use the USCSI "direct" chain and bypass the normal
+ * command waitq.
+ *
+ * Return Code: 0 - successful completion of the given command
+ * EIO - scsi_uscsi_handle_command() failed
+ * ENXIO - soft state not found for specified dev
+ * EINVAL
+ * EFAULT - copyin/copyout error
+ * return code of scsi_uscsi_handle_command():
+ * EIO
+ * ENXIO
+ * EACCES
+ *
+ * Context: Kernel Thread;
+ * Waits for command to complete. Can sleep.
+ */
+static int
+sd_ssc_send(sd_ssc_t *ssc, struct uscsi_cmd *incmd, int flag,
+ enum uio_seg dataspace, int path_flag)
+{
+ struct sd_uscsi_info *uip;
+ struct uscsi_cmd *uscmd = ssc->ssc_uscsi_cmd;
+ struct sd_lun *un;
+ dev_t dev;
+
+ int format = 0;
+ int rval;
+
+
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
+ ASSERT(un != NULL);
+ ASSERT(!mutex_owned(SD_MUTEX(un)));
+ ASSERT(!(ssc->ssc_flags & SSC_FLAGS_NEED_ASSESSMENT));
+ /*
+ * We need to make sure sd_ssc_send will have sd_ssc_assessment
+ * followed to avoid missing any point of telemetry.
+ */
+ ssc->ssc_flags |= SSC_FLAGS_NEED_ASSESSMENT;
+
+ if (uscmd == NULL) {
+ return (ENXIO);
+ }
+
+
#ifdef SDDEBUG
switch (dataspace) {
case UIO_USERSPACE:
SD_TRACE(SD_LOG_IO, un,
- "sd_send_scsi_cmd: entry: un:0x%p UIO_USERSPACE\n", un);
+ "sd_ssc_send: entry: un:0x%p UIO_USERSPACE\n", un);
break;
case UIO_SYSSPACE:
SD_TRACE(SD_LOG_IO, un,
- "sd_send_scsi_cmd: entry: un:0x%p UIO_SYSSPACE\n", un);
+ "sd_ssc_send: entry: un:0x%p UIO_SYSSPACE\n", un);
break;
default:
SD_TRACE(SD_LOG_IO, un,
- "sd_send_scsi_cmd: entry: un:0x%p UNEXPECTED SPACE\n", un);
+ "sd_ssc_send: entry: un:0x%p UNEXPECTED SPACE\n", un);
break;
}
#endif
- rval = scsi_uscsi_alloc_and_copyin((intptr_t)incmd, flag,
+ rval = scsi_uscsi_copyin((intptr_t)incmd, flag,
SD_ADDRESS(un), &uscmd);
if (rval != 0) {
SD_TRACE(SD_LOG_IO, un, "sd_sense_scsi_cmd: "
@@ -10873,7 +11482,7 @@ sd_send_scsi_cmd(dev_t dev, struct uscsi_cmd *incmd, int flag,
* need to preserve the prior contents of b_private.
* The sd_uscsi_info struct is also used by sd_uscsi_strategy()
*/
- uip = kmem_zalloc(sizeof (struct sd_uscsi_info), KM_SLEEP);
+ uip = ssc->ssc_uscsi_info;
uip->ui_flags = path_flag;
uip->ui_cmdp = uscmd;
@@ -10886,15 +11495,22 @@ sd_send_scsi_cmd(dev_t dev, struct uscsi_cmd *incmd, int flag,
}
uscmd->uscsi_flags &= ~USCSI_NOINTR;
+ dev = SD_GET_DEV(un);
rval = scsi_uscsi_handle_cmd(dev, dataspace, uscmd,
sd_uscsi_strategy, NULL, uip);
+ /*
+ * mark ssc_flags right after handle_cmd to make sure
+ * the uscsi has been sent
+ */
+ ssc->ssc_flags |= SSC_FLAGS_CMD_ISSUED;
+
#ifdef SDDEBUG
- SD_INFO(SD_LOG_IO, un, "sd_send_scsi_cmd: "
+ SD_INFO(SD_LOG_IO, un, "sd_ssc_send: "
"uscsi_status: 0x%02x uscsi_resid:0x%x\n",
uscmd->uscsi_status, uscmd->uscsi_resid);
if (uscmd->uscsi_bufaddr != NULL) {
- SD_INFO(SD_LOG_IO, un, "sd_send_scsi_cmd: "
+ SD_INFO(SD_LOG_IO, un, "sd_ssc_send: "
"uscmd->uscsi_bufaddr: 0x%p uscmd->uscsi_buflen:%d\n",
uscmd->uscsi_bufaddr, uscmd->uscsi_buflen);
if (dataspace == UIO_SYSSPACE) {
@@ -10911,12 +11527,236 @@ sd_send_scsi_cmd(dev_t dev, struct uscsi_cmd *incmd, int flag,
mutex_exit(SD_MUTEX(un));
}
- (void) scsi_uscsi_copyout_and_free((intptr_t)incmd, uscmd);
- kmem_free(uip, sizeof (struct sd_uscsi_info));
+ (void) scsi_uscsi_copyout((intptr_t)incmd, uscmd);
return (rval);
}
+/*
+ * Function: sd_ssc_print
+ *
+ * Description: Print information available to the console.
+ *
+ * Arguments: ssc - the struct of sd_ssc_t will bring uscsi_cmd and
+ * sd_uscsi_info in.
+ * sd_severity - log level.
+ * Context: Kernel thread or interrupt context.
+ */
+static void
+sd_ssc_print(sd_ssc_t *ssc, int sd_severity)
+{
+ struct uscsi_cmd *ucmdp;
+ struct scsi_device *devp;
+ dev_info_t *devinfo;
+ uchar_t *sensep;
+ int senlen;
+ union scsi_cdb *cdbp;
+ uchar_t com;
+ extern struct scsi_key_strings scsi_cmds[];
+
+ ASSERT(ssc != NULL);
+
+ ucmdp = ssc->ssc_uscsi_cmd;
+ devp = SD_SCSI_DEVP(ssc->ssc_un);
+ devinfo = SD_DEVINFO(ssc->ssc_un);
+ ASSERT(ucmdp != NULL);
+ ASSERT(devp != NULL);
+ ASSERT(devinfo != NULL);
+ sensep = (uint8_t *)ucmdp->uscsi_rqbuf;
+ senlen = ucmdp->uscsi_rqlen - ucmdp->uscsi_rqresid;
+ cdbp = (union scsi_cdb *)ucmdp->uscsi_cdb;
+
+ /* In certain case (like DOORLOCK), the cdb could be NULL. */
+ if (cdbp == NULL)
+ return;
+ /* We don't print log if no sense data available. */
+ if (senlen == 0)
+ sensep = NULL;
+ com = cdbp->scc_cmd;
+ scsi_generic_errmsg(devp, sd_label, sd_severity, 0, 0, com,
+ scsi_cmds, sensep, ssc->ssc_un->un_additional_codes, NULL);
+}
+
+/*
+ * Function: sd_ssc_assessment
+ *
+ * Description: We use this function to make an assessment at the point
+ * where SD driver may encounter a potential error.
+ *
+ * Arguments: ssc - the struct of sd_ssc_t will bring uscsi_cmd and
+ * sd_uscsi_info in.
+ * tp_assess - a hint of strategy for ereport posting.
+ * Possible values of tp_assess include:
+ * SD_FMT_IGNORE - we don't post any ereport because we're
+ * sure that it is ok to ignore the underlying problems.
+ * SD_FMT_IGNORE_COMPROMISE - we don't post any ereport for now
+ * but it might be not correct to ignore the underlying hardware
+ * error.
+ * SD_FMT_STATUS_CHECK - we will post an ereport with the
+ * payload driver-assessment of value "fail" or
+ * "fatal"(depending on what information we have here). This
+ * assessment value is usually set when SD driver think there
+ * is a potential error occurred(Typically, when return value
+ * of the SCSI command is EIO).
+ * SD_FMT_STANDARD - we will post an ereport with the payload
+ * driver-assessment of value "info". This assessment value is
+ * set when the SCSI command returned successfully and with
+ * sense data sent back.
+ *
+ * Context: Kernel thread.
+ */
+static void
+sd_ssc_assessment(sd_ssc_t *ssc, enum sd_type_assessment tp_assess)
+{
+ int senlen = 0;
+ struct uscsi_cmd *ucmdp = NULL;
+ struct sd_lun *un;
+
+ ASSERT(ssc != NULL);
+ ASSERT(ssc->ssc_flags & SSC_FLAGS_NEED_ASSESSMENT);
+
+ ssc->ssc_flags &= ~SSC_FLAGS_NEED_ASSESSMENT;
+ un = ssc->ssc_un;
+ ASSERT(un != NULL);
+
+ /*
+ * We don't handle CD-ROM, and removable media
+ */
+ if (ISCD(un) || un->un_f_has_removable_media) {
+ ssc->ssc_flags &= ~SSC_FLAGS_CMD_ISSUED;
+ ssc->ssc_flags &= ~SSC_FLAGS_INVALID_DATA;
+ return;
+ }
+
+ /*
+ * Only handle an issued command which is waiting for assessment.
+ */
+ if (!(ssc->ssc_flags & SSC_FLAGS_CMD_ISSUED)) {
+ sd_ssc_print(ssc, SCSI_ERR_INFO);
+ return;
+ } else
+ ssc->ssc_flags &= ~SSC_FLAGS_CMD_ISSUED;
+
+ ucmdp = ssc->ssc_uscsi_cmd;
+ ASSERT(ucmdp != NULL);
+
+ /*
+ * We will not deal with non-retryable commands here.
+ */
+ if (ucmdp->uscsi_flags & USCSI_DIAGNOSE) {
+ ssc->ssc_flags &= ~SSC_FLAGS_INVALID_DATA;
+ return;
+ }
+
+ switch (tp_assess) {
+ case SD_FMT_IGNORE:
+ case SD_FMT_IGNORE_COMPROMISE:
+ ssc->ssc_flags &= ~SSC_FLAGS_INVALID_DATA;
+ break;
+ case SD_FMT_STATUS_CHECK:
+ /*
+ * For a failed command(including the succeeded command
+ * with invalid data sent back).
+ */
+ sd_ssc_post(ssc, SD_FM_DRV_FATAL);
+ break;
+ case SD_FMT_STANDARD:
+ /*
+ * Always for the succeeded commands probably with sense
+ * data sent back.
+ * Limitation:
+ * We can only handle a succeeded command with sense
+ * data sent back when auto-request-sense is enabled.
+ */
+ senlen = ssc->ssc_uscsi_cmd->uscsi_rqlen -
+ ssc->ssc_uscsi_cmd->uscsi_rqresid;
+ if ((ssc->ssc_uscsi_info->ui_pkt_state & STATE_ARQ_DONE) &&
+ (un->un_f_arq_enabled == TRUE) &&
+ senlen > 0 &&
+ ssc->ssc_uscsi_cmd->uscsi_rqbuf != NULL) {
+ sd_ssc_post(ssc, SD_FM_DRV_NOTICE);
+ }
+ break;
+ default:
+ /*
+ * Should be an software error.
+ */
+ scsi_log(SD_DEVINFO(un), sd_label, CE_CONT,
+ "sd_ssc_assessment got wrong \
+ sd_type_assessment %d\n", tp_assess);
+ break;
+ }
+}
+
+/*
+ * Function: sd_ssc_post
+ *
+ * Description: 1. read the driver property to get fm-scsi-log flag.
+ * 2. print log if fm_log_capable is non-zero.
+ * 3. call sd_ssc_ereport_post to post ereport if possible.
+ *
+ * Context: May be called from kernel thread or interrupt context.
+ */
+static void
+sd_ssc_post(sd_ssc_t *ssc, enum sd_driver_assessment sd_assess)
+{
+ struct sd_lun *un;
+ int fm_scsi_log = 0;
+ int sd_severity;
+
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
+ ASSERT(un != NULL);
+
+ fm_scsi_log = ddi_prop_get_int(DDI_DEV_T_ANY, SD_DEVINFO(un),
+ DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fm-scsi-log", 0);
+
+ if (fm_scsi_log != 0) {
+ switch (sd_assess) {
+ case SD_FM_DRV_FATAL:
+ sd_severity = SCSI_ERR_FATAL;
+ break;
+ case SD_FM_DRV_RECOVERY:
+ sd_severity = SCSI_ERR_RECOVERED;
+ break;
+ case SD_FM_DRV_RETRY:
+ sd_severity = SCSI_ERR_RETRYABLE;
+ break;
+ case SD_FM_DRV_NOTICE:
+ sd_severity = SCSI_ERR_INFO;
+ break;
+ default:
+ sd_severity = SCSI_ERR_UNKNOWN;
+ }
+ /* print log */
+ sd_ssc_print(ssc, sd_severity);
+ }
+
+ /* always post ereport */
+ sd_ssc_ereport_post(ssc, sd_assess);
+}
+
+/*
+ * Function: sd_ssc_set_info
+ *
+ * Description: Mark ssc_flags and set ssc_info which would be the
+ * payload of uderr ereport. This function will cause
+ * sd_ssc_ereport_post to post uderr ereport only.
+ *
+ * Context: Kernel thread or interrupt context
+ */
+static void
+sd_ssc_set_info(sd_ssc_t *ssc, int ssc_flags, const char *fmt, ...)
+{
+ va_list ap;
+
+ ASSERT(ssc != NULL);
+
+ ssc->ssc_flags |= ssc_flags;
+ va_start(ap, fmt);
+ (void) vsnprintf(ssc->ssc_info, sizeof (ssc->ssc_info), fmt, ap);
+ va_end(ap);
+}
/*
* Function: sd_buf_iodone
@@ -11051,7 +11891,6 @@ sd_mapblockaddr_iostart(int index, struct sd_lun *un, struct buf *bp)
diskaddr_t partition_offset;
struct sd_xbuf *xp;
-
ASSERT(un != NULL);
ASSERT(bp != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
@@ -11070,27 +11909,39 @@ sd_mapblockaddr_iostart(int index, struct sd_lun *un, struct buf *bp)
*/
partition = SDPART(bp->b_edev);
- if (!SD_IS_VALID_LABEL(un) &&
- (sd_ready_and_valid(un, partition) != SD_READY_VALID)) {
+ if (!SD_IS_VALID_LABEL(un)) {
+ sd_ssc_t *ssc;
/*
- * For removable devices it is possible to start an I/O
- * without a media by opening the device in nodelay mode.
- * Also for writable CDs there can be many scenarios where
- * there is no geometry yet but volume manager is trying to
- * issue a read() just because it can see TOC on the CD. So
- * do not print a message for removables.
+ * Initialize sd_ssc_t for internal uscsi commands
+ * In case of potential porformance issue, we need
+ * to alloc memory only if there is invalid label
*/
- if (!un->un_f_has_removable_media) {
- scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
- "i/o to invalid geometry\n");
+ ssc = sd_ssc_init(un);
+
+ if (sd_ready_and_valid(ssc, partition) != SD_READY_VALID) {
+ /*
+ * For removable devices it is possible to start an
+ * I/O without a media by opening the device in nodelay
+ * mode. Also for writable CDs there can be many
+ * scenarios where there is no geometry yet but volume
+ * manager is trying to issue a read() just because
+ * it can see TOC on the CD. So do not print a message
+ * for removables.
+ */
+ if (!un->un_f_has_removable_media) {
+ scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
+ "i/o to invalid geometry\n");
+ }
+ bioerror(bp, EIO);
+ bp->b_resid = bp->b_bcount;
+ SD_BEGIN_IODONE(index, un, bp);
+
+ sd_ssc_fini(ssc);
+ return;
}
- bioerror(bp, EIO);
- bp->b_resid = bp->b_bcount;
- SD_BEGIN_IODONE(index, un, bp);
- return;
+ sd_ssc_fini(ssc);
}
-
nblocks = 0;
(void) cmlb_partinfo(un->un_cmlbhandle, partition,
&nblocks, &partition_offset, NULL, NULL, (void *)SD_PATH_DIRECT);
@@ -12631,6 +13482,7 @@ sd_destroypkt_for_uscsi(struct buf *bp)
struct sd_xbuf *xp;
struct scsi_pkt *pktp;
struct sd_lun *un;
+ struct sd_uscsi_info *suip;
ASSERT(bp != NULL);
xp = SD_GET_XBUF(bp);
@@ -12675,6 +13527,15 @@ sd_destroypkt_for_uscsi(struct buf *bp)
SENSE_LENGTH);
}
}
+ /*
+ * The following assignments are for SCSI FMA.
+ */
+ ASSERT(xp->xb_private != NULL);
+ suip = (struct sd_uscsi_info *)xp->xb_private;
+ suip->ui_pkt_reason = pktp->pkt_reason;
+ suip->ui_pkt_state = pktp->pkt_state;
+ suip->ui_pkt_statistics = pktp->pkt_statistics;
+ suip->ui_lba = (uint64_t)SD_GET_BLKNO(bp);
/* We are done with the scsi_pkt; free it now */
ASSERT(SD_GET_PKTP(bp) != NULL);
@@ -13132,6 +13993,7 @@ sd_start_cmds(struct sd_lun *un, struct buf *immed_bp)
void (*saved_statp)(kstat_io_t *);
#endif
int rval;
+ struct sd_fm_internal *sfip = NULL;
ASSERT(un != NULL);
ASSERT(mutex_owned(SD_MUTEX(un)));
@@ -13659,6 +14521,22 @@ got_pkt:
sd_print_transport_rejected_message(un, xp, rval);
/*
+ * This command will be terminated by SD driver due
+ * to a fatal transport error. We should post
+ * ereport.io.scsi.cmd.disk.tran with driver-assessment
+ * of "fail" for any command to indicate this
+ * situation.
+ */
+ if (xp->xb_ena > 0) {
+ ASSERT(un->un_fm_private != NULL);
+ sfip = un->un_fm_private;
+ sfip->fm_ssc.ssc_flags |= SSC_FLAGS_TRAN_ABORT;
+ sd_ssc_extract_info(&sfip->fm_ssc, un,
+ xp->xb_pktp, bp, xp);
+ sd_ssc_post(&sfip->fm_ssc, SD_FM_DRV_FATAL);
+ }
+
+ /*
* We must use sd_return_failed_command_no_restart() to
* avoid a recursive call back into sd_start_cmds().
* However this also means that we must keep processing
@@ -13704,6 +14582,10 @@ sd_return_command(struct sd_lun *un, struct buf *bp)
{
struct sd_xbuf *xp;
struct scsi_pkt *pktp;
+ struct sd_fm_internal *sfip;
+ int ssc_invalid_flags = SSC_FLAGS_INVALID_PKT_REASON |
+ SSC_FLAGS_INVALID_STATUS |
+ SSC_FLAGS_INVALID_SENSE;
ASSERT(bp != NULL);
ASSERT(un != NULL);
@@ -13713,6 +14595,8 @@ sd_return_command(struct sd_lun *un, struct buf *bp)
ASSERT(xp != NULL);
pktp = SD_GET_PKTP(bp);
+ sfip = (struct sd_fm_internal *)un->un_fm_private;
+ ASSERT(sfip != NULL);
SD_TRACE(SD_LOG_IO_CORE, un, "sd_return_command: entry\n");
@@ -13755,6 +14639,28 @@ sd_return_command(struct sd_lun *un, struct buf *bp)
*/
if (bp->b_error == 0) {
un->un_failfast_state = SD_FAILFAST_INACTIVE;
+ /*
+ * If this is a successful command, but used to be retried,
+ * we will take it as a recovered command and post an
+ * ereport with driver-assessment of "recovered".
+ */
+ if (xp->xb_ena > 0) {
+ sd_ssc_extract_info(&sfip->fm_ssc, un, pktp, bp, xp);
+ sd_ssc_post(&sfip->fm_ssc, SD_FM_DRV_RECOVERY);
+ }
+ } else {
+ /*
+ * If this is a failed non-USCSI command or it is a command
+ * which encountered invalid data(pkt-reason, stat-code,
+ * sense-data) during execution last time, we will post an
+ * ereport with driver-assessment set accordingly("fail" or
+ * "fatal").
+ */
+ if (!(xp->xb_pkt_flags & SD_XB_USCSICMD) ||
+ (sfip->fm_ssc.ssc_flags & ssc_invalid_flags)) {
+ sd_ssc_extract_info(&sfip->fm_ssc, un, pktp, bp, xp);
+ sd_ssc_post(&sfip->fm_ssc, SD_FM_DRV_FATAL);
+ }
}
/*
@@ -13958,6 +14864,10 @@ sd_retry_command(struct sd_lun *un, struct buf *bp, int retry_check_flag,
{
struct sd_xbuf *xp;
struct scsi_pkt *pktp;
+ struct sd_fm_internal *sfip;
+ int ssc_invalid_flags = SSC_FLAGS_INVALID_PKT_REASON |
+ SSC_FLAGS_INVALID_STATUS |
+ SSC_FLAGS_INVALID_SENSE;
ASSERT(un != NULL);
ASSERT(mutex_owned(SD_MUTEX(un)));
@@ -13967,6 +14877,9 @@ sd_retry_command(struct sd_lun *un, struct buf *bp, int retry_check_flag,
pktp = SD_GET_PKTP(bp);
ASSERT(pktp != NULL);
+ sfip = (struct sd_fm_internal *)un->un_fm_private;
+ ASSERT(sfip != NULL);
+
SD_TRACE(SD_LOG_IO | SD_LOG_ERROR, un,
"sd_retry_command: entry: bp:0x%p xp:0x%p\n", bp, xp);
@@ -14203,6 +15116,18 @@ sd_retry_command(struct sd_lun *un, struct buf *bp, int retry_check_flag,
xp->xb_pktp->pkt_flags |= FLAG_HEAD;
/*
+ * If this is a non-USCSI command being retried or it is a command
+ * which encountered invalid data(pkt-reason, stat-code, sense-data)
+ * during execution last time, we should post an ereport with
+ * driver-assessment of the value "retry".
+ */
+ if (!(xp->xb_pkt_flags & SD_XB_USCSICMD) ||
+ (sfip->fm_ssc.ssc_flags & ssc_invalid_flags)) {
+ sd_ssc_extract_info(&sfip->fm_ssc, un, pktp, bp, xp);
+ sd_ssc_post(&sfip->fm_ssc, SD_FM_DRV_RETRY);
+ }
+
+ /*
* If we were given a zero timeout, we must attempt to retry the
* command immediately (ie, without a delay).
*/
@@ -14614,6 +15539,12 @@ sd_mark_rqs_busy(struct sd_lun *un, struct buf *bp)
*/
((SD_GET_XBUF(bp))->xb_pktp)->pkt_flags |= FLAG_SENSING;
+ /* Request sense down same path */
+ if (scsi_pkt_allocated_correctly((SD_GET_XBUF(bp))->xb_pktp) &&
+ ((SD_GET_XBUF(bp))->xb_pktp)->pkt_path_instance)
+ sense_xp->xb_pktp->pkt_path_instance =
+ ((SD_GET_XBUF(bp))->xb_pktp)->pkt_path_instance;
+
sense_xp->xb_retry_count = 0;
sense_xp->xb_victim_retry_count = 0;
sense_xp->xb_ua_retry_count = 0;
@@ -15070,6 +16001,7 @@ sdintr(struct scsi_pkt *pktp)
struct sd_xbuf *xp;
struct sd_lun *un;
size_t actual_len;
+ sd_ssc_t *sscp;
ASSERT(pktp != NULL);
bp = (struct buf *)pktp->pkt_private;
@@ -15094,6 +16026,10 @@ sdintr(struct scsi_pkt *pktp)
mutex_enter(SD_MUTEX(un));
+ ASSERT(un->un_fm_private != NULL);
+ sscp = &((struct sd_fm_internal *)(un->un_fm_private))->fm_ssc;
+ ASSERT(sscp != NULL);
+
/* Reduce the count of the #commands currently in transport */
un->un_ncmds_in_transport--;
ASSERT(un->un_ncmds_in_transport >= 0);
@@ -15386,6 +16322,12 @@ not_successful:
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"Unexpected SCSI status received: 0x%x\n",
SD_GET_PKT_STATUS(pktp));
+ /*
+ * Mark the ssc_flags for detecting invalid status
+ * code.
+ */
+ sd_ssc_set_info(sscp, SSC_FLAGS_INVALID_STATUS,
+ "stat-code");
sd_return_failed_command(un, bp, EIO);
break;
@@ -15393,6 +16335,8 @@ not_successful:
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"Invalid SCSI status received: 0x%x\n",
SD_GET_PKT_STATUS(pktp));
+ sd_ssc_set_info(sscp, SSC_FLAGS_INVALID_STATUS,
+ "stat-code");
sd_return_failed_command(un, bp, EIO);
break;
@@ -15437,6 +16381,11 @@ not_successful:
default:
SD_TRACE(SD_LOG_IO_CORE | SD_LOG_ERROR, un,
"sdintr: default\n");
+ /*
+ * Mark the ssc_flags for detecting invliad pkt_reason.
+ */
+ sd_ssc_set_info(sscp, SSC_FLAGS_INVALID_PKT_REASON,
+ "pkt-reason");
sd_pkt_reason_default(un, bp, xp, pktp);
break;
}
@@ -15819,16 +16768,21 @@ sd_validate_sense_data(struct sd_lun *un, struct buf *bp, struct sd_xbuf *xp,
struct scsi_extended_sense *esp;
struct scsi_pkt *pktp;
char *msgp = NULL;
+ sd_ssc_t *sscp;
ASSERT(un != NULL);
ASSERT(mutex_owned(SD_MUTEX(un)));
ASSERT(bp != NULL);
ASSERT(bp != un->un_rqs_bp);
ASSERT(xp != NULL);
+ ASSERT(un->un_fm_private != NULL);
pktp = SD_GET_PKTP(bp);
ASSERT(pktp != NULL);
+ sscp = &((struct sd_fm_internal *)(un->un_fm_private))->fm_ssc;
+ ASSERT(sscp != NULL);
+
/*
* Check the status of the RQS command (auto or manual).
*/
@@ -15877,6 +16831,9 @@ sd_validate_sense_data(struct sd_lun *un, struct buf *bp, struct sd_xbuf *xp,
if (actual_len < SUN_MIN_SENSE_LENGTH) {
msgp = "Not enough sense information\n";
+ /* Mark the ssc_flags for detecting invalid sense data */
+ sd_ssc_set_info(sscp, SSC_FLAGS_INVALID_SENSE,
+ "sense-data");
goto sense_failed;
}
@@ -15902,6 +16859,11 @@ sd_validate_sense_data(struct sd_lun *un, struct buf *bp, struct sd_xbuf *xp,
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN, buf);
mutex_exit(&sd_sense_mutex);
}
+
+ /* Mark the ssc_flags for detecting invalid sense data */
+ sd_ssc_set_info(sscp, SSC_FLAGS_INVALID_SENSE,
+ "sense-data");
+
/* Note: Legacy behavior, fail the command with no retry */
sd_return_failed_command(un, bp, EIO);
return (SD_SENSE_DATA_IS_INVALID);
@@ -15918,6 +16880,9 @@ sd_validate_sense_data(struct sd_lun *un, struct buf *bp, struct sd_xbuf *xp,
(esp->es_code != CODE_FMT_DESCR_CURRENT) &&
(esp->es_code != CODE_FMT_DESCR_DEFERRED) &&
(esp->es_code != CODE_FMT_VENDOR_SPECIFIC)) {
+ /* Mark the ssc_flags for detecting invalid sense data */
+ sd_ssc_set_info(sscp, SSC_FLAGS_INVALID_SENSE,
+ "sense-data");
goto sense_failed;
}
@@ -15947,8 +16912,6 @@ sense_failed:
return (SD_SENSE_DATA_IS_INVALID);
}
-
-
/*
* Function: sd_decode_sense
*
@@ -16229,7 +17192,6 @@ sd_print_sense_msg(struct sd_lun *un, struct buf *bp, void *arg, int code)
return;
}
}
-
/*
* Check for Sonoma Failover and keep a count of how many failed I/O's
*/
@@ -17786,6 +18748,7 @@ sd_target_change_task(void *arg)
uint64_t capacity;
diskaddr_t label_cap;
uint_t lbasize;
+ sd_ssc_t *ssc;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
@@ -17795,17 +18758,20 @@ sd_target_change_task(void *arg)
return;
}
- if (sd_send_scsi_READ_CAPACITY(un, &capacity,
+ ssc = sd_ssc_init(un);
+
+ if (sd_send_scsi_READ_CAPACITY(ssc, &capacity,
&lbasize, SD_PATH_DIRECT) != 0) {
SD_ERROR(SD_LOG_ERROR, un,
"sd_target_change_task: fail to read capacity\n");
- return;
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ goto task_exit;
}
mutex_enter(SD_MUTEX(un));
if (capacity <= un->un_blockcount) {
mutex_exit(SD_MUTEX(un));
- return;
+ goto task_exit;
}
sd_update_block_info(un, lbasize, capacity);
@@ -17826,6 +18792,9 @@ sd_target_change_task(void *arg)
mutex_exit(SD_MUTEX(un));
}
}
+
+task_exit:
+ sd_ssc_fini(ssc);
}
/*
@@ -17981,14 +18950,17 @@ sd_handle_mchange(struct sd_lun *un)
uint64_t capacity;
uint32_t lbasize;
int rval;
+ sd_ssc_t *ssc;
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT(un->un_f_monitor_media_state);
- if ((rval = sd_send_scsi_READ_CAPACITY(un, &capacity, &lbasize,
- SD_PATH_DIRECT_PRIORITY)) != 0) {
- return (rval);
- }
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_READ_CAPACITY(ssc, &capacity, &lbasize,
+ SD_PATH_DIRECT_PRIORITY);
+
+ if (rval != 0)
+ goto failed;
mutex_enter(SD_MUTEX(un));
sd_update_block_info(un, lbasize, capacity);
@@ -18001,12 +18973,12 @@ sd_handle_mchange(struct sd_lun *un)
(uint64_t)un->un_tgt_blocksize);
}
-
/*
* Check if the media in the device is writable or not
*/
- if (ISCD(un))
- sd_check_for_writable_cd(un, SD_PATH_DIRECT_PRIORITY);
+ if (ISCD(un)) {
+ sd_check_for_writable_cd(ssc, SD_PATH_DIRECT_PRIORITY);
+ }
/*
* Note: Maybe let the strategy/partitioning chain worry about getting
@@ -18018,6 +18990,7 @@ sd_handle_mchange(struct sd_lun *un)
if (cmlb_validate(un->un_cmlbhandle, 0,
(void *)SD_PATH_DIRECT_PRIORITY) != 0) {
+ sd_ssc_fini(ssc);
return (EIO);
} else {
if (un->un_f_pkstats_enabled) {
@@ -18028,12 +19001,16 @@ sd_handle_mchange(struct sd_lun *un)
}
}
-
/*
* Try to lock the door
*/
- return (sd_send_scsi_DOORLOCK(un, SD_REMOVAL_PREVENT,
- SD_PATH_DIRECT_PRIORITY));
+ rval = sd_send_scsi_DOORLOCK(ssc, SD_REMOVAL_PREVENT,
+ SD_PATH_DIRECT_PRIORITY);
+failed:
+ if (rval != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ sd_ssc_fini(ssc);
+ return (rval);
}
@@ -18042,8 +19019,8 @@ sd_handle_mchange(struct sd_lun *un)
*
* Description: Issue the scsi DOOR LOCK command
*
- * Arguments: un - pointer to driver soft state (unit) structure for
- * this target.
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
* flag - SD_REMOVAL_ALLOW
* SD_REMOVAL_PREVENT
* path_flag - SD_PATH_DIRECT to use the USCSI "direct" chain and
@@ -18053,19 +19030,22 @@ sd_handle_mchange(struct sd_lun *un)
* command is issued as part of an error recovery action.
*
* Return Code: 0 - Success
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep.
*/
static int
-sd_send_scsi_DOORLOCK(struct sd_lun *un, int flag, int path_flag)
+sd_send_scsi_DOORLOCK(sd_ssc_t *ssc, int flag, int path_flag)
{
+ struct scsi_extended_sense sense_buf;
union scsi_cdb cdb;
struct uscsi_cmd ucmd_buf;
- struct scsi_extended_sense sense_buf;
int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
@@ -18106,14 +19086,19 @@ sd_send_scsi_DOORLOCK(struct sd_lun *un, int flag, int path_flag)
ucmd_buf.uscsi_timeout = 15;
SD_TRACE(SD_LOG_IO, un,
- "sd_send_scsi_DOORLOCK: returning sd_send_scsi_cmd()\n");
+ "sd_send_scsi_DOORLOCK: returning sd_ssc_send\n");
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, path_flag);
+ if (status == 0)
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
+
if ((status == EIO) && (ucmd_buf.uscsi_status == STATUS_CHECK) &&
(ucmd_buf.uscsi_rqstatus == STATUS_GOOD) &&
(scsi_sense_key((uint8_t *)&sense_buf) == KEY_ILLEGAL_REQUEST)) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
/* fake success and skip subsequent doorlock commands */
un->un_f_doorlock_supported = FALSE;
return (0);
@@ -18133,7 +19118,7 @@ sd_send_scsi_DOORLOCK(struct sd_lun *un, int flag, int path_flag)
* normal READ CAPACITY command and the results of a
* READ CAPACITY 16 will be used instead.
*
- * Arguments: un - ptr to soft state struct for the target
+ * Arguments: ssc - ssc contains ptr to soft state struct for the target
* capp - ptr to unsigned 64-bit variable to receive the
* capacity value from the command.
* lbap - ptr to unsigned 32-bit varaible to receive the
@@ -18148,7 +19133,7 @@ sd_send_scsi_DOORLOCK(struct sd_lun *un, int flag, int path_flag)
* EIO - IO error
* EACCES - Reservation conflict detected
* EAGAIN - Device is becoming ready
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Blocks until command completes.
*/
@@ -18156,7 +19141,7 @@ sd_send_scsi_DOORLOCK(struct sd_lun *un, int flag, int path_flag)
#define SD_CAPACITY_SIZE sizeof (struct scsi_capacity)
static int
-sd_send_scsi_READ_CAPACITY(struct sd_lun *un, uint64_t *capp, uint32_t *lbap,
+sd_send_scsi_READ_CAPACITY(sd_ssc_t *ssc, uint64_t *capp, uint32_t *lbap,
int path_flag)
{
struct scsi_extended_sense sense_buf;
@@ -18166,7 +19151,11 @@ sd_send_scsi_READ_CAPACITY(struct sd_lun *un, uint64_t *capp, uint32_t *lbap,
uint64_t capacity;
uint32_t lbasize;
int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT(capp != NULL);
@@ -18199,13 +19188,16 @@ sd_send_scsi_READ_CAPACITY(struct sd_lun *un, uint64_t *capp, uint32_t *lbap,
ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT;
ucmd_buf.uscsi_timeout = 60;
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, path_flag);
switch (status) {
case 0:
/* Return failure if we did not get valid capacity data. */
if (ucmd_buf.uscsi_resid != 0) {
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_send_scsi_READ_CAPACITY received "
+ "invalid capacity data");
kmem_free(capacity_buf, SD_CAPACITY_SIZE);
return (EIO);
}
@@ -18239,7 +19231,8 @@ sd_send_scsi_READ_CAPACITY(struct sd_lun *un, uint64_t *capp, uint32_t *lbap,
* Reissue the request using READ CAPACITY 16.
*/
if (capacity == 0xffffffff) {
- status = sd_send_scsi_READ_CAPACITY_16(un, &capacity,
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ status = sd_send_scsi_READ_CAPACITY_16(ssc, &capacity,
&lbasize, path_flag);
if (status != 0) {
return (status);
@@ -18310,9 +19303,12 @@ sd_send_scsi_READ_CAPACITY(struct sd_lun *un, uint64_t *capp, uint32_t *lbap,
* failure to the caller. (4203735)
*/
if ((capacity == 0) || (lbasize == 0)) {
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_send_scsi_READ_CAPACITY received invalid value "
+ "capacity %llu lbasize %d", capacity, lbasize);
return (EIO);
}
-
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
return (0);
}
@@ -18327,7 +19323,7 @@ sd_send_scsi_READ_CAPACITY(struct sd_lun *un, uint64_t *capp, uint32_t *lbap,
* sd_send_scsi_READ_CAPACITY which will appy any device
* specific adjustments to capacity and lbasize.
*
- * Arguments: un - ptr to soft state struct for the target
+ * Arguments: ssc - ssc contains ptr to soft state struct for the target
* capp - ptr to unsigned 64-bit variable to receive the
* capacity value from the command.
* lbap - ptr to unsigned 32-bit varaible to receive the
@@ -18343,7 +19339,7 @@ sd_send_scsi_READ_CAPACITY(struct sd_lun *un, uint64_t *capp, uint32_t *lbap,
* EIO - IO error
* EACCES - Reservation conflict detected
* EAGAIN - Device is becoming ready
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Blocks until command completes.
*/
@@ -18351,7 +19347,7 @@ sd_send_scsi_READ_CAPACITY(struct sd_lun *un, uint64_t *capp, uint32_t *lbap,
#define SD_CAPACITY_16_SIZE sizeof (struct scsi_capacity_16)
static int
-sd_send_scsi_READ_CAPACITY_16(struct sd_lun *un, uint64_t *capp,
+sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp,
uint32_t *lbap, int path_flag)
{
struct scsi_extended_sense sense_buf;
@@ -18361,7 +19357,11 @@ sd_send_scsi_READ_CAPACITY_16(struct sd_lun *un, uint64_t *capp,
uint64_t capacity;
uint32_t lbasize;
int status;
+ struct sd_lun *un;
+
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT(capp != NULL);
@@ -18404,13 +19404,16 @@ sd_send_scsi_READ_CAPACITY_16(struct sd_lun *un, uint64_t *capp,
*/
FORMG4COUNT(&cdb, ucmd_buf.uscsi_buflen);
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, path_flag);
switch (status) {
case 0:
/* Return failure if we did not get valid capacity data. */
if (ucmd_buf.uscsi_resid > 20) {
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "sd_send_scsi_READ_CAPACITY_16 received "
+ "invalid capacity data");
kmem_free(capacity16_buf, SD_CAPACITY_16_SIZE);
return (EIO);
}
@@ -18445,6 +19448,8 @@ sd_send_scsi_READ_CAPACITY_16(struct sd_lun *un, uint64_t *capp,
* are not defined by any current T10 standards.
*/
if (capacity == 0xffffffffffffffff) {
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "disk is too large");
return (EIO);
}
break; /* Success! */
@@ -18489,8 +19494,8 @@ sd_send_scsi_READ_CAPACITY_16(struct sd_lun *un, uint64_t *capp,
*
* Description: Issue a scsi START STOP UNIT command to the target.
*
- * Arguments: un - pointer to driver soft state (unit) structure for
- * this target.
+ * Arguments: ssc - ssc contatins pointer to driver soft state (unit)
+ * structure for this target.
* flag - SD_TARGET_START
* SD_TARGET_STOP
* SD_TARGET_EJECT
@@ -18504,19 +19509,22 @@ sd_send_scsi_READ_CAPACITY_16(struct sd_lun *un, uint64_t *capp,
* EIO - IO error
* EACCES - Reservation conflict detected
* ENXIO - Not Ready, medium not present
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep.
*/
static int
-sd_send_scsi_START_STOP_UNIT(struct sd_lun *un, int flag, int path_flag)
+sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int flag, int path_flag)
{
struct scsi_extended_sense sense_buf;
union scsi_cdb cdb;
struct uscsi_cmd ucmd_buf;
int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
@@ -18559,11 +19567,12 @@ sd_send_scsi_START_STOP_UNIT(struct sd_lun *un, int flag, int path_flag)
ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_SILENT;
ucmd_buf.uscsi_timeout = 200;
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, path_flag);
switch (status) {
case 0:
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
break; /* Success! */
case EIO:
switch (ucmd_buf.uscsi_status) {
@@ -18641,6 +19650,8 @@ static void
sd_start_stop_unit_task(void *arg)
{
struct sd_lun *un = arg;
+ sd_ssc_t *ssc;
+ int rval;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
@@ -18665,9 +19676,12 @@ sd_start_stop_unit_task(void *arg)
* using SD_PATH_DIRECT_PRIORITY. It doesn't matter if the spin up
* succeeds or not, we will start I/O after the attempt.
*/
- (void) sd_send_scsi_START_STOP_UNIT(un, SD_TARGET_START,
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START,
SD_PATH_DIRECT_PRIORITY);
-
+ if (rval != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ sd_ssc_fini(ssc);
/*
* The above call blocks until the START_STOP_UNIT command completes.
* Now that it has completed, we must re-try the original IO that
@@ -18708,7 +19722,8 @@ sd_start_stop_unit_task(void *arg)
*
* Description: Issue the scsi INQUIRY command.
*
- * Arguments: un
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
* bufaddr
* buflen
* evpd
@@ -18716,19 +19731,22 @@ sd_start_stop_unit_task(void *arg)
* page_length
*
* Return Code: 0 - Success
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Does not return until command is completed.
*/
static int
-sd_send_scsi_INQUIRY(struct sd_lun *un, uchar_t *bufaddr, size_t buflen,
+sd_send_scsi_INQUIRY(sd_ssc_t *ssc, uchar_t *bufaddr, size_t buflen,
uchar_t evpd, uchar_t page_code, size_t *residp)
{
union scsi_cdb cdb;
struct uscsi_cmd ucmd_buf;
int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT(bufaddr != NULL);
@@ -18753,9 +19771,16 @@ sd_send_scsi_INQUIRY(struct sd_lun *un, uchar_t *bufaddr, size_t buflen,
ucmd_buf.uscsi_flags = USCSI_READ | USCSI_SILENT;
ucmd_buf.uscsi_timeout = 200; /* Excessive legacy value */
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, SD_PATH_DIRECT);
+ /*
+ * Only handle status == 0, the upper-level caller
+ * will put different assessment based on the context.
+ */
+ if (status == 0)
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
+
if ((status == 0) && (residp != NULL)) {
*residp = ucmd_buf.uscsi_resid;
}
@@ -18778,7 +19803,8 @@ sd_send_scsi_INQUIRY(struct sd_lun *un, uchar_t *bufaddr, size_t buflen,
* is for retries to bring a device ready, so use the flag
* with caution.
*
- * Arguments: un
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
* flag: SD_CHECK_FOR_MEDIA: return ENXIO if no media present
* SD_DONT_RETRY_TUR: include uscsi flag USCSI_DIAGNOSE.
* 0: dont check for media present, do retries on cmd.
@@ -18787,19 +19813,22 @@ sd_send_scsi_INQUIRY(struct sd_lun *un, uchar_t *bufaddr, size_t buflen,
* EIO - IO error
* EACCES - Reservation conflict detected
* ENXIO - Not Ready, medium not present
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Does not return until command is completed.
*/
static int
-sd_send_scsi_TEST_UNIT_READY(struct sd_lun *un, int flag)
+sd_send_scsi_TEST_UNIT_READY(sd_ssc_t *ssc, int flag)
{
struct scsi_extended_sense sense_buf;
union scsi_cdb cdb;
struct uscsi_cmd ucmd_buf;
int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
@@ -18845,12 +19874,13 @@ sd_send_scsi_TEST_UNIT_READY(struct sd_lun *un, int flag)
}
ucmd_buf.uscsi_timeout = 60;
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, ((flag & SD_BYPASS_PM) ? SD_PATH_DIRECT :
SD_PATH_STANDARD));
switch (status) {
case 0:
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
break; /* Success! */
case EIO:
switch (ucmd_buf.uscsi_status) {
@@ -18881,24 +19911,24 @@ sd_send_scsi_TEST_UNIT_READY(struct sd_lun *un, int flag)
return (status);
}
-
/*
* Function: sd_send_scsi_PERSISTENT_RESERVE_IN
*
* Description: Issue the scsi PERSISTENT RESERVE IN command.
*
- * Arguments: un
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
*
* Return Code: 0 - Success
* EACCES
* ENOTSUP
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Does not return until command is completed.
*/
static int
-sd_send_scsi_PERSISTENT_RESERVE_IN(struct sd_lun *un, uchar_t usr_cmd,
+sd_send_scsi_PERSISTENT_RESERVE_IN(sd_ssc_t *ssc, uchar_t usr_cmd,
uint16_t data_len, uchar_t *data_bufp)
{
struct scsi_extended_sense sense_buf;
@@ -18906,7 +19936,10 @@ sd_send_scsi_PERSISTENT_RESERVE_IN(struct sd_lun *un, uchar_t usr_cmd,
struct uscsi_cmd ucmd_buf;
int status;
int no_caller_buf = FALSE;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT((usr_cmd == SD_READ_KEYS) || (usr_cmd == SD_READ_RESV));
@@ -18938,11 +19971,13 @@ sd_send_scsi_PERSISTENT_RESERVE_IN(struct sd_lun *un, uchar_t usr_cmd,
ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT;
ucmd_buf.uscsi_timeout = 60;
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, SD_PATH_STANDARD);
switch (status) {
case 0:
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
+
break; /* Success! */
case EIO:
switch (ucmd_buf.uscsi_status) {
@@ -18982,7 +20017,8 @@ sd_send_scsi_PERSISTENT_RESERVE_IN(struct sd_lun *un, uchar_t usr_cmd,
* MHIOCGRP_INRESV) by sending the SCSI-3 PROUT commands to the
* device.
*
- * Arguments: un - Pointer to soft state struct for the target.
+ * Arguments: ssc - ssc contains un - pointer to soft state struct
+ * for the target.
* usr_cmd SCSI-3 reservation facility command (one of
* SD_SCSI3_REGISTER, SD_SCSI3_RESERVE, SD_SCSI3_RELEASE,
* SD_SCSI3_PREEMPTANDABORT)
@@ -18993,13 +20029,13 @@ sd_send_scsi_PERSISTENT_RESERVE_IN(struct sd_lun *un, uchar_t usr_cmd,
* Return Code: 0 - Success
* EACCES
* ENOTSUP
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Does not return until command is completed.
*/
static int
-sd_send_scsi_PERSISTENT_RESERVE_OUT(struct sd_lun *un, uchar_t usr_cmd,
+sd_send_scsi_PERSISTENT_RESERVE_OUT(sd_ssc_t *ssc, uchar_t usr_cmd,
uchar_t *usr_bufp)
{
struct scsi_extended_sense sense_buf;
@@ -19008,7 +20044,10 @@ sd_send_scsi_PERSISTENT_RESERVE_OUT(struct sd_lun *un, uchar_t usr_cmd,
int status;
uchar_t data_len = sizeof (sd_prout_t);
sd_prout_t *prp;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT(data_len == 24); /* required by scsi spec */
@@ -19083,11 +20122,12 @@ sd_send_scsi_PERSISTENT_RESERVE_OUT(struct sd_lun *un, uchar_t usr_cmd,
break;
}
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, SD_PATH_STANDARD);
switch (status) {
case 0:
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
break; /* Success! */
case EIO:
switch (ucmd_buf.uscsi_status) {
@@ -19392,7 +20432,7 @@ done:
* Description: Issues the get configuration command to the device.
* Called from sd_check_for_writable_cd & sd_get_media_info
* caller needs to ensure that buflen = SD_PROFILE_HEADER_LEN
- * Arguments: un
+ * Arguments: ssc
* ucmdbuf
* rqbuf
* rqbuflen
@@ -19401,20 +20441,23 @@ done:
* path_flag
*
* Return Code: 0 - Success
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Does not return until command is completed.
*
*/
static int
-sd_send_scsi_GET_CONFIGURATION(struct sd_lun *un, struct uscsi_cmd *ucmdbuf,
+sd_send_scsi_GET_CONFIGURATION(sd_ssc_t *ssc, struct uscsi_cmd *ucmdbuf,
uchar_t *rqbuf, uint_t rqbuflen, uchar_t *bufaddr, uint_t buflen,
int path_flag)
{
char cdb[CDB_GROUP1];
int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT(bufaddr != NULL);
@@ -19444,11 +20487,12 @@ sd_send_scsi_GET_CONFIGURATION(struct sd_lun *un, struct uscsi_cmd *ucmdbuf,
ucmdbuf->uscsi_rqlen = rqbuflen;
ucmdbuf->uscsi_flags = USCSI_RQENABLE|USCSI_SILENT|USCSI_READ;
- status = sd_send_scsi_cmd(SD_GET_DEV(un), ucmdbuf, FKIOCTL,
+ status = sd_ssc_send(ssc, ucmdbuf, FKIOCTL,
UIO_SYSSPACE, path_flag);
switch (status) {
case 0:
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
break; /* Success! */
case EIO:
switch (ucmdbuf->uscsi_status) {
@@ -19481,7 +20525,7 @@ sd_send_scsi_GET_CONFIGURATION(struct sd_lun *un, struct uscsi_cmd *ucmdbuf,
* Description: Issues the get configuration command to the device to
* retrieve a specific feature. Called from
* sd_check_for_writable_cd & sd_set_mmc_caps.
- * Arguments: un
+ * Arguments: ssc
* ucmdbuf
* rqbuf
* rqbuflen
@@ -19490,19 +20534,22 @@ sd_send_scsi_GET_CONFIGURATION(struct sd_lun *un, struct uscsi_cmd *ucmdbuf,
* feature
*
* Return Code: 0 - Success
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Does not return until command is completed.
*
*/
static int
-sd_send_scsi_feature_GET_CONFIGURATION(struct sd_lun *un,
+sd_send_scsi_feature_GET_CONFIGURATION(sd_ssc_t *ssc,
struct uscsi_cmd *ucmdbuf, uchar_t *rqbuf, uint_t rqbuflen,
uchar_t *bufaddr, uint_t buflen, char feature, int path_flag)
{
char cdb[CDB_GROUP1];
int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT(bufaddr != NULL);
@@ -19533,11 +20580,12 @@ sd_send_scsi_feature_GET_CONFIGURATION(struct sd_lun *un,
ucmdbuf->uscsi_rqlen = rqbuflen;
ucmdbuf->uscsi_flags = USCSI_RQENABLE|USCSI_SILENT|USCSI_READ;
- status = sd_send_scsi_cmd(SD_GET_DEV(un), ucmdbuf, FKIOCTL,
+ status = sd_ssc_send(ssc, ucmdbuf, FKIOCTL,
UIO_SYSSPACE, path_flag);
switch (status) {
case 0:
+
break; /* Success! */
case EIO:
switch (ucmdbuf->uscsi_status) {
@@ -19573,7 +20621,8 @@ sd_send_scsi_feature_GET_CONFIGURATION(struct sd_lun *un,
* Group1, and Group2 commands across all platforms. ATAPI devices
* use Group 1 Read/Write commands and Group 2 Mode Sense/Select
*
- * Arguments: un - pointer to the softstate struct for the target.
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
* cdbsize - size CDB to be used (CDB_GROUP0 (6 byte), or
* CDB_GROUP[1|2] (10 byte).
* bufaddr - buffer for page data retrieved from the target.
@@ -19585,13 +20634,13 @@ sd_send_scsi_feature_GET_CONFIGURATION(struct sd_lun *un,
* command waitq.
*
* Return Code: 0 - Success
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Does not return until command is completed.
*/
static int
-sd_send_scsi_MODE_SENSE(struct sd_lun *un, int cdbsize, uchar_t *bufaddr,
+sd_send_scsi_MODE_SENSE(sd_ssc_t *ssc, int cdbsize, uchar_t *bufaddr,
size_t buflen, uchar_t page_code, int path_flag)
{
struct scsi_extended_sense sense_buf;
@@ -19599,7 +20648,10 @@ sd_send_scsi_MODE_SENSE(struct sd_lun *un, int cdbsize, uchar_t *bufaddr,
struct uscsi_cmd ucmd_buf;
int status;
int headlen;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT(bufaddr != NULL);
@@ -19638,7 +20690,7 @@ sd_send_scsi_MODE_SENSE(struct sd_lun *un, int cdbsize, uchar_t *bufaddr,
ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT;
ucmd_buf.uscsi_timeout = 60;
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, path_flag);
switch (status) {
@@ -19650,8 +20702,11 @@ sd_send_scsi_MODE_SENSE(struct sd_lun *un, int cdbsize, uchar_t *bufaddr,
* this case, make sure that mode page header is returned at
* least.
*/
- if (buflen - ucmd_buf.uscsi_resid < headlen)
+ if (buflen - ucmd_buf.uscsi_resid < headlen) {
status = EIO;
+ sd_ssc_set_info(ssc, SSC_FLAGS_INVALID_DATA,
+ "mode page header is not returned");
+ }
break; /* Success! */
case EIO:
switch (ucmd_buf.uscsi_status) {
@@ -19684,7 +20739,8 @@ sd_send_scsi_MODE_SENSE(struct sd_lun *un, int cdbsize, uchar_t *bufaddr,
* Group1, and Group2 commands across all platforms. ATAPI devices
* use Group 1 Read/Write commands and Group 2 Mode Sense/Select
*
- * Arguments: un - pointer to the softstate struct for the target.
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
* cdbsize - size CDB to be used (CDB_GROUP0 (6 byte), or
* CDB_GROUP[1|2] (10 byte).
* bufaddr - buffer for page data retrieved from the target.
@@ -19696,20 +20752,23 @@ sd_send_scsi_MODE_SENSE(struct sd_lun *un, int cdbsize, uchar_t *bufaddr,
* command waitq.
*
* Return Code: 0 - Success
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Does not return until command is completed.
*/
static int
-sd_send_scsi_MODE_SELECT(struct sd_lun *un, int cdbsize, uchar_t *bufaddr,
+sd_send_scsi_MODE_SELECT(sd_ssc_t *ssc, int cdbsize, uchar_t *bufaddr,
size_t buflen, uchar_t save_page, int path_flag)
{
struct scsi_extended_sense sense_buf;
union scsi_cdb cdb;
struct uscsi_cmd ucmd_buf;
int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT(bufaddr != NULL);
@@ -19750,11 +20809,12 @@ sd_send_scsi_MODE_SELECT(struct sd_lun *un, int cdbsize, uchar_t *bufaddr,
ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_WRITE | USCSI_SILENT;
ucmd_buf.uscsi_timeout = 60;
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, path_flag);
switch (status) {
case 0:
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
break; /* Success! */
case EIO:
switch (ucmd_buf.uscsi_status) {
@@ -19784,7 +20844,8 @@ sd_send_scsi_MODE_SELECT(struct sd_lun *un, int cdbsize, uchar_t *bufaddr,
*
* Description: Issue a scsi READ or WRITE command with the given parameters.
*
- * Arguments: un: Pointer to the sd_lun struct for the target.
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
* cmd: SCMD_READ or SCMD_WRITE
* bufaddr: Address of caller's buffer to receive the RDWR data
* buflen: Length of caller's buffer receive the RDWR data.
@@ -19798,13 +20859,13 @@ sd_send_scsi_MODE_SELECT(struct sd_lun *un, int cdbsize, uchar_t *bufaddr,
* command waitq.
*
* Return Code: 0 - Success
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Does not return until command is completed.
*/
static int
-sd_send_scsi_RDWR(struct sd_lun *un, uchar_t cmd, void *bufaddr,
+sd_send_scsi_RDWR(sd_ssc_t *ssc, uchar_t cmd, void *bufaddr,
size_t buflen, daddr_t start_block, int path_flag)
{
struct scsi_extended_sense sense_buf;
@@ -19814,7 +20875,10 @@ sd_send_scsi_RDWR(struct sd_lun *un, uchar_t cmd, void *bufaddr,
int status;
int cdbsize;
uchar_t flag;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
ASSERT(bufaddr != NULL);
@@ -19882,10 +20946,12 @@ sd_send_scsi_RDWR(struct sd_lun *un, uchar_t cmd, void *bufaddr,
ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense);
ucmd_buf.uscsi_flags = flag | USCSI_RQENABLE | USCSI_SILENT;
ucmd_buf.uscsi_timeout = 60;
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, path_flag);
+
switch (status) {
case 0:
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
break; /* Success! */
case EIO:
switch (ucmd_buf.uscsi_status) {
@@ -19916,25 +20982,29 @@ sd_send_scsi_RDWR(struct sd_lun *un, uchar_t cmd, void *bufaddr,
*
* Description: Issue a scsi LOG_SENSE command with the given parameters.
*
- * Arguments: un: Pointer to the sd_lun struct for the target.
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
*
* Return Code: 0 - Success
- * errno return code from sd_send_scsi_cmd()
+ * errno return code from sd_ssc_send()
*
* Context: Can sleep. Does not return until command is completed.
*/
static int
-sd_send_scsi_LOG_SENSE(struct sd_lun *un, uchar_t *bufaddr, uint16_t buflen,
+sd_send_scsi_LOG_SENSE(sd_ssc_t *ssc, uchar_t *bufaddr, uint16_t buflen,
uchar_t page_code, uchar_t page_control, uint16_t param_ptr,
int path_flag)
{
- struct scsi_extended_sense sense_buf;
+ struct scsi_extended_sense sense_buf;
union scsi_cdb cdb;
struct uscsi_cmd ucmd_buf;
int status;
+ struct sd_lun *un;
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
ASSERT(un != NULL);
ASSERT(!mutex_owned(SD_MUTEX(un)));
@@ -19959,7 +21029,7 @@ sd_send_scsi_LOG_SENSE(struct sd_lun *un, uchar_t *bufaddr, uint16_t buflen,
ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT;
ucmd_buf.uscsi_timeout = 60;
- status = sd_send_scsi_cmd(SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, path_flag);
switch (status) {
@@ -20004,8 +21074,9 @@ sd_send_scsi_LOG_SENSE(struct sd_lun *un, uchar_t *bufaddr, uint16_t buflen,
(char)(page_control << 6) |
un->un_start_stop_cycle_page;
mutex_exit(SD_MUTEX(un));
- status = sd_send_scsi_cmd(
- SD_GET_DEV(un), &ucmd_buf, FKIOCTL,
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ status = sd_ssc_send(
+ ssc, &ucmd_buf, FKIOCTL,
UIO_SYSSPACE, path_flag);
break;
@@ -20026,6 +21097,7 @@ sd_send_scsi_LOG_SENSE(struct sd_lun *un, uchar_t *bufaddr, uint16_t buflen,
}
if (status == 0) {
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
SD_DUMP_MEMORY(un, SD_LOG_IO, "sd_send_scsi_LOG_SENSE: data",
(uchar_t *)bufaddr, buflen, SD_LOG_HEX);
}
@@ -20069,6 +21141,7 @@ sdioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, int *rval_p)
cred_t *cr;
int tmprval = EINVAL;
int is_valid;
+ sd_ssc_t *ssc;
/*
* All device accesses go thru sdstrategy where we check on suspend
@@ -20080,6 +21153,8 @@ sdioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, int *rval_p)
ASSERT(!mutex_owned(SD_MUTEX(un)));
+ /* Initialize sd_ssc_t for internal uscsi commands */
+ ssc = sd_ssc_init(un);
is_valid = SD_IS_VALID_LABEL(un);
@@ -20151,7 +21226,8 @@ sdioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, int *rval_p)
un->un_ncmds_in_driver--;
ASSERT(un->un_ncmds_in_driver >= 0);
mutex_exit(SD_MUTEX(un));
- return (ENOTTY);
+ err = ENOTTY;
+ goto done_without_assess;
}
break;
case FDEJECT:
@@ -20161,18 +21237,20 @@ sdioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, int *rval_p)
un->un_ncmds_in_driver--;
ASSERT(un->un_ncmds_in_driver >= 0);
mutex_exit(SD_MUTEX(un));
- return (ENOTTY);
+ err = ENOTTY;
+ goto done_without_assess;
}
break;
case DKIOCFLUSHWRITECACHE:
mutex_exit(SD_MUTEX(un));
- err = sd_send_scsi_TEST_UNIT_READY(un, 0);
+ err = sd_send_scsi_TEST_UNIT_READY(ssc, 0);
if (err != 0) {
mutex_enter(SD_MUTEX(un));
un->un_ncmds_in_driver--;
ASSERT(un->un_ncmds_in_driver >= 0);
mutex_exit(SD_MUTEX(un));
- return (EIO);
+ err = EIO;
+ goto done_quick_assess;
}
mutex_enter(SD_MUTEX(un));
/* FALLTHROUGH */
@@ -20198,7 +21276,7 @@ sdioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, int *rval_p)
}
mutex_exit(SD_MUTEX(un));
- err = sd_ready_and_valid(un, SDPART(dev));
+ err = sd_ready_and_valid(ssc, SDPART(dev));
mutex_enter(SD_MUTEX(un));
if (err != SD_READY_VALID) {
@@ -20226,7 +21304,8 @@ sdioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, int *rval_p)
un->un_ncmds_in_driver--;
ASSERT(un->un_ncmds_in_driver >= 0);
mutex_exit(SD_MUTEX(un));
- return (err);
+
+ goto done_without_assess;
}
}
}
@@ -20267,13 +21346,14 @@ skip_ready_valid:
/* TUR should spin up */
if (un->un_f_has_removable_media)
- err = sd_send_scsi_TEST_UNIT_READY(un,
+ err = sd_send_scsi_TEST_UNIT_READY(ssc,
SD_CHECK_FOR_MEDIA);
+
else
- err = sd_send_scsi_TEST_UNIT_READY(un, 0);
+ err = sd_send_scsi_TEST_UNIT_READY(ssc, 0);
if (err != 0)
- break;
+ goto done_with_assess;
err = cmlb_ioctl(un->un_cmlbhandle, dev,
cmd, arg, flag, cred_p, rval_p, (void *)SD_PATH_DIRECT);
@@ -20300,7 +21380,7 @@ skip_ready_valid:
if (un->un_f_devid_supported &&
(un->un_f_opt_fab_devid == TRUE)) {
if (un->un_devid == NULL) {
- sd_register_devid(un, SD_DEVINFO(un),
+ sd_register_devid(ssc, SD_DEVINFO(un),
SD_TARGET_IS_UNRESERVED);
} else {
/*
@@ -20310,7 +21390,7 @@ skip_ready_valid:
* by writing it back out to
* disk.
*/
- if (sd_write_deviceid(un) != 0) {
+ if (sd_write_deviceid(ssc) != 0) {
ddi_devid_free(un->un_devid);
un->un_devid = NULL;
}
@@ -20323,15 +21403,15 @@ skip_ready_valid:
case DKIOCLOCK:
SD_TRACE(SD_LOG_IOCTL, un, "DKIOCLOCK\n");
- err = sd_send_scsi_DOORLOCK(un, SD_REMOVAL_PREVENT,
+ err = sd_send_scsi_DOORLOCK(ssc, SD_REMOVAL_PREVENT,
SD_PATH_STANDARD);
- break;
+ goto done_with_assess;
case DKIOCUNLOCK:
SD_TRACE(SD_LOG_IOCTL, un, "DKIOCUNLOCK\n");
- err = sd_send_scsi_DOORLOCK(un, SD_REMOVAL_ALLOW,
+ err = sd_send_scsi_DOORLOCK(ssc, SD_REMOVAL_ALLOW,
SD_PATH_STANDARD);
- break;
+ goto done_with_assess;
case DKIOCSTATE: {
enum dkio_state state;
@@ -20399,17 +21479,18 @@ skip_ready_valid:
case MHIOCSTATUS:
SD_TRACE(SD_LOG_IOCTL, un, "MHIOCSTATUS\n");
if ((err = drv_priv(cred_p)) == 0) {
- switch (sd_send_scsi_TEST_UNIT_READY(un, 0)) {
+ switch (sd_send_scsi_TEST_UNIT_READY(ssc, 0)) {
case 0:
err = 0;
break;
case EACCES:
*rval_p = 1;
err = 0;
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
break;
default:
err = EIO;
- break;
+ goto done_with_assess;
}
}
break;
@@ -20468,8 +21549,10 @@ skip_ready_valid:
} else {
err =
sd_send_scsi_PERSISTENT_RESERVE_OUT(
- un, SD_SCSI3_REGISTER,
+ ssc, SD_SCSI3_REGISTER,
(uchar_t *)&reg);
+ if (err != 0)
+ goto done_with_assess;
}
}
}
@@ -20488,8 +21571,10 @@ skip_ready_valid:
} else {
err =
sd_send_scsi_PERSISTENT_RESERVE_OUT(
- un, SD_SCSI3_RESERVE,
+ ssc, SD_SCSI3_RESERVE,
(uchar_t *)&resv_desc);
+ if (err != 0)
+ goto done_with_assess;
}
}
}
@@ -20509,8 +21594,10 @@ skip_ready_valid:
} else {
err =
sd_send_scsi_PERSISTENT_RESERVE_OUT(
- un, SD_SCSI3_PREEMPTANDABORT,
+ ssc, SD_SCSI3_PREEMPTANDABORT,
(uchar_t *)&preempt_abort);
+ if (err != 0)
+ goto done_with_assess;
}
}
}
@@ -20530,8 +21617,10 @@ skip_ready_valid:
} else {
err =
sd_send_scsi_PERSISTENT_RESERVE_OUT(
- un, SD_SCSI3_REGISTERANDIGNOREKEY,
+ ssc, SD_SCSI3_REGISTERANDIGNOREKEY,
(uchar_t *)&r_and_i);
+ if (err != 0)
+ goto done_with_assess;
}
}
}
@@ -20544,14 +21633,21 @@ skip_ready_valid:
err = EPERM;
} else {
enum uio_seg uioseg;
+
uioseg = (flag & FKIOCTL) ? UIO_SYSSPACE :
UIO_USERSPACE;
if (un->un_f_format_in_progress == TRUE) {
err = EAGAIN;
break;
}
- err = sd_send_scsi_cmd(dev, (struct uscsi_cmd *)arg,
+
+ err = sd_ssc_send(ssc,
+ (struct uscsi_cmd *)arg,
flag, uioseg, SD_PATH_STANDARD);
+ if (err != 0)
+ goto done_with_assess;
+ else
+ sd_ssc_assessment(ssc, SD_FMT_STANDARD);
}
break;
@@ -20613,8 +21709,9 @@ skip_ready_valid:
if (!ISCD(un)) {
err = ENOTTY;
} else {
- err = sd_send_scsi_START_STOP_UNIT(un, SD_TARGET_STOP,
+ err = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_STOP,
SD_PATH_STANDARD);
+ goto done_with_assess;
}
break;
@@ -20623,8 +21720,9 @@ skip_ready_valid:
if (!ISCD(un)) {
err = ENOTTY;
} else {
- err = sd_send_scsi_START_STOP_UNIT(un, SD_TARGET_START,
+ err = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START,
SD_PATH_STANDARD);
+ goto done_with_assess;
}
break;
@@ -20633,8 +21731,9 @@ skip_ready_valid:
if (!ISCD(un)) {
err = ENOTTY;
} else {
- err = sd_send_scsi_START_STOP_UNIT(un, SD_TARGET_CLOSE,
+ err = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_CLOSE,
SD_PATH_STANDARD);
+ goto done_with_assess;
}
break;
@@ -20920,7 +22019,7 @@ skip_ready_valid:
int wce;
- if ((err = sd_get_write_cache_enabled(un, &wce)) != 0) {
+ if ((err = sd_get_write_cache_enabled(ssc, &wce)) != 0) {
break;
}
@@ -20981,7 +22080,7 @@ skip_ready_valid:
*/
if (!un->un_f_suppress_cache_flush) {
mutex_exit(SD_MUTEX(un));
- if ((err = sd_cache_control(un,
+ if ((err = sd_cache_control(ssc,
SD_CACHE_NOCHANGE,
SD_CACHE_DISABLE)) == 0 &&
sync_supported) {
@@ -21013,7 +22112,7 @@ skip_ready_valid:
*/
if (!un->un_f_suppress_cache_flush) {
mutex_exit(SD_MUTEX(un));
- err = sd_cache_control(un, SD_CACHE_NOCHANGE,
+ err = sd_cache_control(ssc, SD_CACHE_NOCHANGE,
SD_CACHE_ENABLE);
} else {
mutex_exit(SD_MUTEX(un));
@@ -21041,6 +22140,25 @@ skip_ready_valid:
ASSERT(un->un_ncmds_in_driver >= 0);
mutex_exit(SD_MUTEX(un));
+
+done_without_assess:
+ sd_ssc_fini(ssc);
+
+ SD_TRACE(SD_LOG_IOCTL, un, "sdioctl: exit: %d\n", err);
+ return (err);
+
+done_with_assess:
+ mutex_enter(SD_MUTEX(un));
+ un->un_ncmds_in_driver--;
+ ASSERT(un->un_ncmds_in_driver >= 0);
+ mutex_exit(SD_MUTEX(un));
+
+done_quick_assess:
+ if (err != 0)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ /* Uninitialize sd_ssc_t pointer */
+ sd_ssc_fini(ssc);
+
SD_TRACE(SD_LOG_IOCTL, un, "sdioctl: exit: %d\n", err);
return (err);
}
@@ -21160,7 +22278,7 @@ sd_get_media_info(dev_t dev, caddr_t arg, int flag)
uchar_t *rqbuf;
int rval = 0;
int rtn;
-
+ sd_ssc_t *ssc;
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL ||
(un->un_state == SD_STATE_OFFLINE)) {
return (ENXIO);
@@ -21172,9 +22290,12 @@ sd_get_media_info(dev_t dev, caddr_t arg, int flag)
rqbuf = kmem_zalloc(SENSE_LENGTH, KM_SLEEP);
/* Issue a TUR to determine if the drive is ready with media present */
- rval = sd_send_scsi_TEST_UNIT_READY(un, SD_CHECK_FOR_MEDIA);
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_TEST_UNIT_READY(ssc, SD_CHECK_FOR_MEDIA);
if (rval == ENXIO) {
goto done;
+ } else if (rval != 0) {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
}
/* Now get configuration data */
@@ -21183,7 +22304,7 @@ sd_get_media_info(dev_t dev, caddr_t arg, int flag)
/* Allow SCMD_GET_CONFIGURATION to MMC devices only */
if (un->un_f_mmc_cap == TRUE) {
- rtn = sd_send_scsi_GET_CONFIGURATION(un, &com, rqbuf,
+ rtn = sd_send_scsi_GET_CONFIGURATION(ssc, &com, rqbuf,
SENSE_LENGTH, out_data, SD_PROFILE_HEADER_LEN,
SD_PATH_STANDARD);
@@ -21200,6 +22321,8 @@ sd_get_media_info(dev_t dev, caddr_t arg, int flag)
goto done;
}
}
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
} else {
/*
* The GET CONFIGURATION command succeeded
@@ -21241,8 +22364,9 @@ sd_get_media_info(dev_t dev, caddr_t arg, int flag)
}
/* Now read the capacity so we can provide the lbasize and capacity */
- switch (sd_send_scsi_READ_CAPACITY(un, &capacity, &lbasize,
- SD_PATH_DIRECT)) {
+ rval = sd_send_scsi_READ_CAPACITY(ssc, &capacity, &lbasize,
+ SD_PATH_DIRECT);
+ switch (rval) {
case 0:
break;
case EACCES:
@@ -21279,9 +22403,17 @@ sd_get_media_info(dev_t dev, caddr_t arg, int flag)
if (ddi_copyout(&media_info, arg, sizeof (struct dk_minfo), flag)) {
rval = EFAULT;
/* Put goto. Anybody might add some code below in future */
- goto done;
+ goto no_assessment;
}
done:
+ if (rval != 0) {
+ if (rval == EIO)
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+no_assessment:
+ sd_ssc_fini(ssc);
kmem_free(out_data, SD_PROFILE_HEADER_LEN);
kmem_free(rqbuf, SENSE_LENGTH);
return (rval);
@@ -21318,6 +22450,7 @@ sd_check_media(dev_t dev, enum dkio_state state)
enum dkio_state prev_state;
opaque_t token = NULL;
int rval = 0;
+ sd_ssc_t *ssc;
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL) {
return (ENXIO);
@@ -21325,6 +22458,8 @@ sd_check_media(dev_t dev, enum dkio_state state)
SD_TRACE(SD_LOG_COMMON, un, "sd_check_media: entry\n");
+ ssc = sd_ssc_init(un);
+
mutex_enter(SD_MUTEX(un));
SD_TRACE(SD_LOG_COMMON, un, "sd_check_media: "
@@ -21429,11 +22564,15 @@ sd_check_media(dev_t dev, enum dkio_state state)
*/
if (sd_pm_entry(un) == DDI_SUCCESS) {
- rval = sd_send_scsi_READ_CAPACITY(un,
- &capacity,
- &lbasize, SD_PATH_DIRECT);
+ rval = sd_send_scsi_READ_CAPACITY(ssc,
+ &capacity, &lbasize, SD_PATH_DIRECT);
if (rval != 0) {
sd_pm_exit(un);
+ if (rval == EIO)
+ sd_ssc_assessment(ssc,
+ SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
mutex_enter(SD_MUTEX(un));
goto done;
}
@@ -21449,8 +22588,9 @@ sd_check_media(dev_t dev, enum dkio_state state)
/*
* Check if the media in the device is writable or not
*/
- if (ISCD(un))
- sd_check_for_writable_cd(un, SD_PATH_DIRECT);
+ if (ISCD(un)) {
+ sd_check_for_writable_cd(ssc, SD_PATH_DIRECT);
+ }
mutex_exit(SD_MUTEX(un));
cmlb_invalidate(un->un_cmlbhandle, (void *)SD_PATH_DIRECT);
@@ -21462,13 +22602,22 @@ sd_check_media(dev_t dev, enum dkio_state state)
"set\n", un);
}
- rval = sd_send_scsi_DOORLOCK(un, SD_REMOVAL_PREVENT,
+ rval = sd_send_scsi_DOORLOCK(ssc, SD_REMOVAL_PREVENT,
SD_PATH_DIRECT);
+
sd_pm_exit(un);
+ if (rval != 0) {
+ if (rval == EIO)
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+
mutex_enter(SD_MUTEX(un));
}
done:
+ sd_ssc_fini(ssc);
un->un_f_watcht_stopped = FALSE;
/*
* Use of this local token and the mutex ensures that we avoid
@@ -21696,11 +22845,13 @@ sd_dkio_get_temp(dev_t dev, caddr_t arg, int flag)
uchar_t *temperature_page;
int rval = 0;
int path_flag = SD_PATH_STANDARD;
+ sd_ssc_t *ssc;
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL) {
return (ENXIO);
}
+ ssc = sd_ssc_init(un);
dktemp = kmem_zalloc(sizeof (struct dk_temperature), KM_SLEEP);
/* copyin the disk temp argument to get the user flags */
@@ -21749,10 +22900,10 @@ sd_dkio_get_temp(dev_t dev, caddr_t arg, int flag)
temperature_page = kmem_zalloc(TEMPERATURE_PAGE_SIZE, KM_SLEEP);
- if ((rval = sd_send_scsi_LOG_SENSE(un, temperature_page,
- TEMPERATURE_PAGE_SIZE, TEMPERATURE_PAGE, 1, 0, path_flag)) != 0) {
+ rval = sd_send_scsi_LOG_SENSE(ssc, temperature_page,
+ TEMPERATURE_PAGE_SIZE, TEMPERATURE_PAGE, 1, 0, path_flag);
+ if (rval != 0)
goto done2;
- }
/*
* For the current temperature verify that the parameter length is 0x02
@@ -21784,15 +22935,24 @@ sd_dkio_get_temp(dev_t dev, caddr_t arg, int flag)
if (ddi_copyout(dktemp, (void *)arg, sizeof (struct dk_temperature),
flag) != 0) {
rval = EFAULT;
+ goto done1;
}
done2:
+ if (rval != 0) {
+ if (rval == EIO)
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+done1:
if (path_flag == SD_PATH_DIRECT) {
sd_pm_exit(un);
}
kmem_free(temperature_page, TEMPERATURE_PAGE_SIZE);
done:
+ sd_ssc_fini(ssc);
if (dktemp != NULL) {
kmem_free(dktemp, sizeof (struct dk_temperature));
}
@@ -21807,7 +22967,8 @@ done:
* Description: This routine uses sd_send_scsi_LOG_SENSE to find the list of
* supported log pages.
*
- * Arguments: un -
+ * Arguments: ssc - ssc contains pointer to driver soft state (unit)
+ * structure for this target.
* log_page -
*
* Return Code: -1 - on error (log sense is optional and may not be supported).
@@ -21816,22 +22977,55 @@ done:
*/
static int
-sd_log_page_supported(struct sd_lun *un, int log_page)
+sd_log_page_supported(sd_ssc_t *ssc, int log_page)
{
uchar_t *log_page_data;
int i;
int match = 0;
int log_size;
+ int status = 0;
+ struct sd_lun *un;
+
+ ASSERT(ssc != NULL);
+ un = ssc->ssc_un;
+ ASSERT(un != NULL);
log_page_data = kmem_zalloc(0xFF, KM_SLEEP);
- if (sd_send_scsi_LOG_SENSE(un, log_page_data, 0xFF, 0, 0x01, 0,
- SD_PATH_DIRECT) != 0) {
+ status = sd_send_scsi_LOG_SENSE(ssc, log_page_data, 0xFF, 0, 0x01, 0,
+ SD_PATH_DIRECT);
+
+ if (status != 0) {
+ if (status == EIO) {
+ /*
+ * Some disks do not support log sense, we
+ * should ignore this kind of error(sense key is
+ * 0x5 - illegal request).
+ */
+ uint8_t *sensep;
+ int senlen;
+
+ sensep = (uint8_t *)ssc->ssc_uscsi_cmd->uscsi_rqbuf;
+ senlen = (int)(ssc->ssc_uscsi_cmd->uscsi_rqlen -
+ ssc->ssc_uscsi_cmd->uscsi_rqresid);
+
+ if (senlen > 0 &&
+ scsi_sense_key(sensep) == KEY_ILLEGAL_REQUEST) {
+ sd_ssc_assessment(ssc,
+ SD_FMT_IGNORE_COMPROMISE);
+ } else {
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ }
+ } else {
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+
SD_ERROR(SD_LOG_COMMON, un,
"sd_log_page_supported: failed log page retrieval\n");
kmem_free(log_page_data, 0xFF);
return (-1);
}
+
log_size = log_page_data[3];
/*
@@ -22065,6 +23259,7 @@ sd_mhdioc_register_devid(dev_t dev)
{
struct sd_lun *un = NULL;
int rval = 0;
+ sd_ssc_t *ssc;
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL) {
return (ENXIO);
@@ -22086,12 +23281,13 @@ sd_mhdioc_register_devid(dev_t dev)
/* Check for reservation conflict */
mutex_exit(SD_MUTEX(un));
- rval = sd_send_scsi_TEST_UNIT_READY(un, 0);
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_TEST_UNIT_READY(ssc, 0);
mutex_enter(SD_MUTEX(un));
switch (rval) {
case 0:
- sd_register_devid(un, SD_DEVINFO(un), SD_TARGET_IS_UNRESERVED);
+ sd_register_devid(ssc, SD_DEVINFO(un), SD_TARGET_IS_UNRESERVED);
break;
case EACCES:
break;
@@ -22100,6 +23296,13 @@ sd_mhdioc_register_devid(dev_t dev)
}
mutex_exit(SD_MUTEX(un));
+ if (rval != 0) {
+ if (rval == EIO)
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+ sd_ssc_fini(ssc);
return (rval);
}
@@ -24005,14 +25208,17 @@ sd_persistent_reservation_in_read_keys(struct sd_lun *un,
mhioc_key_list_t li;
uchar_t *data_bufp;
int data_len;
- int rval;
+ int rval = 0;
size_t copysz;
+ sd_ssc_t *ssc;
if ((ptr = (mhioc_inkeys_t *)usrp) == NULL) {
return (EINVAL);
}
bzero(&li, sizeof (mhioc_key_list_t));
+ ssc = sd_ssc_init(un);
+
/*
* Get the listsize from user
*/
@@ -24059,8 +25265,13 @@ sd_persistent_reservation_in_read_keys(struct sd_lun *un,
data_len += (sizeof (sd_prin_readkeys_t) - sizeof (caddr_t));
data_bufp = kmem_zalloc(data_len, KM_SLEEP);
- if ((rval = sd_send_scsi_PERSISTENT_RESERVE_IN(un, SD_READ_KEYS,
- data_len, data_bufp)) != 0) {
+ rval = sd_send_scsi_PERSISTENT_RESERVE_IN(ssc, SD_READ_KEYS,
+ data_len, data_bufp);
+ if (rval != 0) {
+ if (rval == EIO)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE_COMPROMISE);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
goto done;
}
in = (sd_prin_readkeys_t *)data_bufp;
@@ -24116,6 +25327,7 @@ sd_persistent_reservation_in_read_keys(struct sd_lun *un,
rval = EFAULT;
}
done:
+ sd_ssc_fini(ssc);
kmem_free(data_bufp, data_len);
return (rval);
}
@@ -24157,17 +25369,20 @@ sd_persistent_reservation_in_read_resv(struct sd_lun *un,
sd_readresv_desc_t *readresv_ptr;
mhioc_resv_desc_list_t resvlist;
mhioc_resv_desc_t resvdesc;
- uchar_t *data_bufp;
+ uchar_t *data_bufp = NULL;
int data_len;
- int rval;
+ int rval = 0;
int i;
size_t copysz;
mhioc_resv_desc_t *bufp;
+ sd_ssc_t *ssc;
if ((ptr = usrp) == NULL) {
return (EINVAL);
}
+ ssc = sd_ssc_init(un);
+
/*
* Get the listsize from user
*/
@@ -24212,8 +25427,13 @@ sd_persistent_reservation_in_read_resv(struct sd_lun *un,
data_len += (sizeof (sd_prin_readresv_t) - sizeof (caddr_t));
data_bufp = kmem_zalloc(data_len, KM_SLEEP);
- if ((rval = sd_send_scsi_PERSISTENT_RESERVE_IN(un, SD_READ_RESV,
- data_len, data_bufp)) != 0) {
+ rval = sd_send_scsi_PERSISTENT_RESERVE_IN(ssc, SD_READ_RESV,
+ data_len, data_bufp);
+ if (rval != 0) {
+ if (rval == EIO)
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE_COMPROMISE);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
goto done;
}
in = (sd_prin_readresv_t *)data_bufp;
@@ -24282,7 +25502,11 @@ sd_persistent_reservation_in_read_resv(struct sd_lun *un,
}
}
done:
- kmem_free(data_bufp, data_len);
+ sd_ssc_fini(ssc);
+ /* only if data_bufp is allocated, we need to free it */
+ if (data_bufp) {
+ kmem_free(data_bufp, data_len);
+ }
return (rval);
}
@@ -24323,6 +25547,7 @@ sr_change_blkmode(dev_t dev, int cmd, intptr_t data, int flag)
int rval = EINVAL;
uchar_t *sense = NULL;
uchar_t *select = NULL;
+ sd_ssc_t *ssc;
ASSERT((cmd == CDROMGBLKMODE) || (cmd == CDROMSBLKMODE));
@@ -24339,8 +25564,11 @@ sr_change_blkmode(dev_t dev, int cmd, intptr_t data, int flag)
*/
sense = kmem_zalloc(BUFLEN_CHG_BLK_MODE, KM_SLEEP);
- if ((rval = sd_send_scsi_MODE_SENSE(un, CDB_GROUP0, sense,
- BUFLEN_CHG_BLK_MODE, MODEPAGE_ERR_RECOV, SD_PATH_STANDARD)) != 0) {
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP0, sense,
+ BUFLEN_CHG_BLK_MODE, MODEPAGE_ERR_RECOV, SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+ if (rval != 0) {
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"sr_change_blkmode: Mode Sense Failed\n");
kmem_free(sense, BUFLEN_CHG_BLK_MODE);
@@ -24415,9 +25643,12 @@ sr_change_blkmode(dev_t dev, int cmd, intptr_t data, int flag)
select_desc->blksize_lo = (char)((data) & 0x000000ff);
/* Send the mode select for the requested block size */
- if ((rval = sd_send_scsi_MODE_SELECT(un, CDB_GROUP0,
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_MODE_SELECT(ssc, CDB_GROUP0,
select, BUFLEN_CHG_BLK_MODE, SD_DONTSAVE_PAGE,
- SD_PATH_STANDARD)) != 0) {
+ SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+ if (rval != 0) {
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"sr_change_blkmode: Mode Select Failed\n");
/*
@@ -24429,9 +25660,11 @@ sr_change_blkmode(dev_t dev, int cmd, intptr_t data, int flag)
select_desc->blksize_hi = sense_desc->blksize_hi;
select_desc->blksize_mid = sense_desc->blksize_mid;
select_desc->blksize_lo = sense_desc->blksize_lo;
- (void) sd_send_scsi_MODE_SELECT(un, CDB_GROUP0,
+ ssc = sd_ssc_init(un);
+ (void) sd_send_scsi_MODE_SELECT(ssc, CDB_GROUP0,
select, BUFLEN_CHG_BLK_MODE, SD_DONTSAVE_PAGE,
SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
} else {
ASSERT(!mutex_owned(SD_MUTEX(un)));
mutex_enter(SD_MUTEX(un));
@@ -24501,6 +25734,7 @@ sr_change_speed(dev_t dev, int cmd, intptr_t data, int flag)
int bd_len;
uchar_t *sense = NULL;
uchar_t *select = NULL;
+ sd_ssc_t *ssc;
ASSERT((cmd == CDROMGDRVSPEED) || (cmd == CDROMSDRVSPEED));
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL) {
@@ -24513,9 +25747,12 @@ sr_change_speed(dev_t dev, int cmd, intptr_t data, int flag)
*/
sense = kmem_zalloc(BUFLEN_MODE_CDROM_SPEED, KM_SLEEP);
- if ((rval = sd_send_scsi_MODE_SENSE(un, CDB_GROUP0, sense,
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP0, sense,
BUFLEN_MODE_CDROM_SPEED, CDROM_MODE_SPEED,
- SD_PATH_STANDARD)) != 0) {
+ SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+ if (rval != 0) {
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"sr_change_speed: Mode Sense Failed\n");
kmem_free(sense, BUFLEN_MODE_CDROM_SPEED);
@@ -24589,9 +25826,12 @@ sr_change_speed(dev_t dev, int cmd, intptr_t data, int flag)
select_page->speed = (uchar_t)data;
/* Send the mode select for the requested block size */
- if ((rval = sd_send_scsi_MODE_SELECT(un, CDB_GROUP0, select,
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_MODE_SELECT(ssc, CDB_GROUP0, select,
MODEPAGE_CDROM_SPEED_LEN + MODE_HEADER_LENGTH,
- SD_DONTSAVE_PAGE, SD_PATH_STANDARD)) != 0) {
+ SD_DONTSAVE_PAGE, SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+ if (rval != 0) {
/*
* The mode select failed for the requested drive speed,
* so reset the data for the original drive speed and
@@ -24601,9 +25841,11 @@ sr_change_speed(dev_t dev, int cmd, intptr_t data, int flag)
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"sr_drive_speed: Mode Select Failed\n");
select_page->speed = sense_page->speed;
- (void) sd_send_scsi_MODE_SELECT(un, CDB_GROUP0, select,
+ ssc = sd_ssc_init(un);
+ (void) sd_send_scsi_MODE_SELECT(ssc, CDB_GROUP0, select,
MODEPAGE_CDROM_SPEED_LEN + MODE_HEADER_LENGTH,
SD_DONTSAVE_PAGE, SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
}
break;
default:
@@ -24662,6 +25904,7 @@ sr_atapi_change_speed(dev_t dev, int cmd, intptr_t data, int flag)
int current_speed = 0;
int max_speed = 0;
int rval;
+ sd_ssc_t *ssc;
ASSERT((cmd == CDROMGDRVSPEED) || (cmd == CDROMSDRVSPEED));
@@ -24671,9 +25914,12 @@ sr_atapi_change_speed(dev_t dev, int cmd, intptr_t data, int flag)
sense = kmem_zalloc(BUFLEN_MODE_CDROM_CAP, KM_SLEEP);
- if ((rval = sd_send_scsi_MODE_SENSE(un, CDB_GROUP1, sense,
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP1, sense,
BUFLEN_MODE_CDROM_CAP, MODEPAGE_CDROM_CAP,
- SD_PATH_STANDARD)) != 0) {
+ SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+ if (rval != 0) {
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"sr_atapi_change_speed: Mode Sense Failed\n");
kmem_free(sense, BUFLEN_MODE_CDROM_CAP);
@@ -25498,6 +26744,8 @@ sr_read_mode1(dev_t dev, caddr_t data, int flag)
struct cdrom_read mode1_struct;
struct cdrom_read *mode1 = &mode1_struct;
int rval;
+ sd_ssc_t *ssc;
+
#ifdef _MULTI_DATAMODEL
/* To support ILP32 applications in an LP64 world */
struct cdrom_read32 cdrom_read32;
@@ -25536,8 +26784,10 @@ sr_read_mode1(dev_t dev, caddr_t data, int flag)
}
#endif /* _MULTI_DATAMODEL */
- rval = sd_send_scsi_READ(un, mode1->cdread_bufaddr,
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_READ(ssc, mode1->cdread_bufaddr,
mode1->cdread_buflen, mode1->cdread_lba, SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
SD_TRACE(SD_LOG_ATTACH_DETACH, un,
"sd_read_mode1: exit: un:0x%p\n", un);
@@ -25838,6 +27088,7 @@ sr_sector_mode(dev_t dev, uint32_t blksize)
uchar_t *sense;
uchar_t *select;
int rval;
+ sd_ssc_t *ssc;
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL ||
(un->un_state == SD_STATE_OFFLINE)) {
@@ -25847,8 +27098,11 @@ sr_sector_mode(dev_t dev, uint32_t blksize)
sense = kmem_zalloc(20, KM_SLEEP);
/* Note: This is a vendor specific mode page (0x81) */
- if ((rval = sd_send_scsi_MODE_SENSE(un, CDB_GROUP0, sense, 20, 0x81,
- SD_PATH_STANDARD)) != 0) {
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP0, sense, 20, 0x81,
+ SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+ if (rval != 0) {
SD_ERROR(SD_LOG_IOCTL_RMMEDIA, un,
"sr_sector_mode: Mode Sense failed\n");
kmem_free(sense, 20);
@@ -25866,8 +27120,11 @@ sr_sector_mode(dev_t dev, uint32_t blksize)
select[14] |= 0x01;
}
- if ((rval = sd_send_scsi_MODE_SELECT(un, CDB_GROUP0, select, 20,
- SD_DONTSAVE_PAGE, SD_PATH_STANDARD)) != 0) {
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_MODE_SELECT(ssc, CDB_GROUP0, select, 20,
+ SD_DONTSAVE_PAGE, SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+ if (rval != 0) {
SD_ERROR(SD_LOG_IOCTL_RMMEDIA, un,
"sr_sector_mode: Mode Select failed\n");
} else {
@@ -26220,6 +27477,7 @@ sr_eject(dev_t dev)
{
struct sd_lun *un;
int rval;
+ sd_ssc_t *ssc;
if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL ||
(un->un_state == SD_STATE_OFFLINE)) {
@@ -26243,16 +27501,22 @@ sr_eject(dev_t dev)
un->un_f_ejecting = TRUE;
mutex_exit(SD_MUTEX(un));
- if ((rval = sd_send_scsi_DOORLOCK(un, SD_REMOVAL_ALLOW,
- SD_PATH_STANDARD)) != 0) {
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_DOORLOCK(ssc, SD_REMOVAL_ALLOW,
+ SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+
+ if (rval != 0) {
mutex_enter(SD_MUTEX(un));
un->un_f_ejecting = FALSE;
mutex_exit(SD_MUTEX(un));
return (rval);
}
- rval = sd_send_scsi_START_STOP_UNIT(un, SD_TARGET_EJECT,
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_EJECT,
SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
if (rval == 0) {
mutex_enter(SD_MUTEX(un));
@@ -26311,7 +27575,7 @@ sr_ejected(struct sd_lun *un)
* this routine has been implemented to use 0x3f mode page(request
* for all pages) for all device types.
*
- * Arguments: dev - the device 'dev_t'
+ * Arguments: dev - the device 'dev_t'
*
* Return Code: int indicating if the device is write protected (1) or not (0)
*
@@ -26327,6 +27591,8 @@ sr_check_wp(dev_t dev)
uchar_t *sense;
int hdrlen;
int rval = FALSE;
+ int status;
+ sd_ssc_t *ssc;
/*
* Note: The return codes for this routine should be reworked to
@@ -26343,21 +27609,28 @@ sr_check_wp(dev_t dev)
*/
hdrlen = MODE_HEADER_LENGTH_GRP2;
sense = kmem_zalloc(hdrlen, KM_SLEEP);
- if (sd_send_scsi_MODE_SENSE(un, CDB_GROUP1, sense, hdrlen,
- MODEPAGE_ALLPAGES, SD_PATH_STANDARD) != 0)
+ ssc = sd_ssc_init(un);
+ status = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP1, sense, hdrlen,
+ MODEPAGE_ALLPAGES, SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+ if (status != 0)
goto err_exit;
device_specific =
((struct mode_header_grp2 *)sense)->device_specific;
} else {
hdrlen = MODE_HEADER_LENGTH;
sense = kmem_zalloc(hdrlen, KM_SLEEP);
- if (sd_send_scsi_MODE_SENSE(un, CDB_GROUP0, sense, hdrlen,
- MODEPAGE_ALLPAGES, SD_PATH_STANDARD) != 0)
+ ssc = sd_ssc_init(un);
+ status = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP0, sense, hdrlen,
+ MODEPAGE_ALLPAGES, SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+ if (status != 0)
goto err_exit;
device_specific =
((struct mode_header *)sense)->device_specific;
}
+
/*
* Write protect mode sense failed; not all disks
* understand this query. Return FALSE assuming that
@@ -26403,6 +27676,7 @@ sr_volume_ctrl(dev_t dev, caddr_t data, int flag)
int sense_buflen;
int select_buflen;
int rval;
+ sd_ssc_t *ssc;
if (data == NULL) {
return (EINVAL);
@@ -26427,9 +27701,13 @@ sr_volume_ctrl(dev_t dev, caddr_t data, int flag)
MODEPAGE_AUDIO_CTRL_LEN;
sense = kmem_zalloc(sense_buflen, KM_SLEEP);
select = kmem_zalloc(select_buflen, KM_SLEEP);
- if ((rval = sd_send_scsi_MODE_SENSE(un, CDB_GROUP1, sense,
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP1, sense,
sense_buflen, MODEPAGE_AUDIO_CTRL,
- SD_PATH_STANDARD)) != 0) {
+ SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+
+ if (rval != 0) {
SD_ERROR(SD_LOG_IOCTL_RMMEDIA, un,
"sr_volume_ctrl: Mode Sense Failed\n");
kmem_free(sense, sense_buflen);
@@ -26462,9 +27740,13 @@ sr_volume_ctrl(dev_t dev, caddr_t data, int flag)
select_buflen = MODE_HEADER_LENGTH + MODEPAGE_AUDIO_CTRL_LEN;
sense = kmem_zalloc(sense_buflen, KM_SLEEP);
select = kmem_zalloc(select_buflen, KM_SLEEP);
- if ((rval = sd_send_scsi_MODE_SENSE(un, CDB_GROUP0, sense,
+ ssc = sd_ssc_init(un);
+ rval = sd_send_scsi_MODE_SENSE(ssc, CDB_GROUP0, sense,
sense_buflen, MODEPAGE_AUDIO_CTRL,
- SD_PATH_STANDARD)) != 0) {
+ SD_PATH_STANDARD);
+ sd_ssc_fini(ssc);
+
+ if (rval != 0) {
scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
"sr_volume_ctrl: Mode Sense Failed\n");
kmem_free(sense, sense_buflen);
@@ -26515,13 +27797,15 @@ sr_volume_ctrl(dev_t dev, caddr_t data, int flag)
select_page[14] = sense_page[14];
select_page[15] = sense_page[15];
+ ssc = sd_ssc_init(un);
if ((un->un_f_cfg_is_atapi == TRUE) || (un->un_f_mmc_cap == TRUE)) {
- rval = sd_send_scsi_MODE_SELECT(un, CDB_GROUP1, select,
+ rval = sd_send_scsi_MODE_SELECT(ssc, CDB_GROUP1, select,
select_buflen, SD_DONTSAVE_PAGE, SD_PATH_STANDARD);
} else {
- rval = sd_send_scsi_MODE_SELECT(un, CDB_GROUP0, select,
+ rval = sd_send_scsi_MODE_SELECT(ssc, CDB_GROUP0, select,
select_buflen, SD_DONTSAVE_PAGE, SD_PATH_STANDARD);
}
+ sd_ssc_fini(ssc);
kmem_free(sense, sense_buflen);
kmem_free(select, select_buflen);
@@ -27441,7 +28725,7 @@ static uint_t sd_fault_injection_on = 0;
static void
sd_faultinjection_ioctl(int cmd, intptr_t arg, struct sd_lun *un) {
- uint_t i;
+ uint_t i = 0;
uint_t rval;
SD_TRACE(SD_LOG_IOERR, un, "sd_faultinjection_ioctl: entry\n");
@@ -27791,6 +29075,8 @@ sd_faultinjection(struct scsi_pkt *pktp)
return;
}
+ SD_INFO(SD_LOG_SDTEST, un,
+ "sd_faultinjection: is working for copying\n");
/* take next set off fifo */
i = un->sd_fi_fifo_start % SD_FI_MAX_ERROR;
@@ -27806,18 +29092,19 @@ sd_faultinjection(struct scsi_pkt *pktp)
if (fi_pkt != NULL) {
SD_CONDSET(pktp, pkt, pkt_flags, "pkt_flags");
SD_CONDSET(*pktp, pkt, pkt_scbp, "pkt_scbp");
- SD_CONDSET(*pktp, pkt, pkt_cdbp, "pkt_cdbp");
+ if (fi_pkt->pkt_cdbp != 0xff)
+ SD_CONDSET(*pktp, pkt, pkt_cdbp, "pkt_cdbp");
SD_CONDSET(pktp, pkt, pkt_state, "pkt_state");
SD_CONDSET(pktp, pkt, pkt_statistics, "pkt_statistics");
SD_CONDSET(pktp, pkt, pkt_reason, "pkt_reason");
}
-
/* set xb if it was on fifo */
if (fi_xb != NULL) {
SD_CONDSET(xb, xb, xb_blkno, "xb_blkno");
SD_CONDSET(xb, xb, xb_dma_resid, "xb_dma_resid");
- SD_CONDSET(xb, xb, xb_retry_count, "xb_retry_count");
+ if (fi_xb->xb_retry_count != 0)
+ SD_CONDSET(xb, xb, xb_retry_count, "xb_retry_count");
SD_CONDSET(xb, xb, xb_victim_retry_count,
"xb_victim_retry_count");
SD_CONDSET(xb, xb, xb_sense_status, "xb_sense_status");
@@ -27825,20 +29112,26 @@ sd_faultinjection(struct scsi_pkt *pktp)
SD_CONDSET(xb, xb, xb_sense_resid, "xb_sense_resid");
/* copy in block data from sense */
- if (fi_xb->xb_sense_data[0] != -1) {
- bcopy(fi_xb->xb_sense_data, xb->xb_sense_data,
- SENSE_LENGTH);
- }
+ /*
+ * if (fi_xb->xb_sense_data[0] != -1) {
+ * bcopy(fi_xb->xb_sense_data, xb->xb_sense_data,
+ * SENSE_LENGTH);
+ * }
+ */
+ bcopy(fi_xb->xb_sense_data, xb->xb_sense_data, SENSE_LENGTH);
/* copy in extended sense codes */
- SD_CONDSET(((struct scsi_extended_sense *)xb), xb, es_code,
- "es_code");
- SD_CONDSET(((struct scsi_extended_sense *)xb), xb, es_key,
- "es_key");
- SD_CONDSET(((struct scsi_extended_sense *)xb), xb, es_add_code,
- "es_add_code");
- SD_CONDSET(((struct scsi_extended_sense *)xb), xb,
- es_qual_code, "es_qual_code");
+ SD_CONDSET(((struct scsi_extended_sense *)xb->xb_sense_data),
+ xb, es_code, "es_code");
+ SD_CONDSET(((struct scsi_extended_sense *)xb->xb_sense_data),
+ xb, es_key, "es_key");
+ SD_CONDSET(((struct scsi_extended_sense *)xb->xb_sense_data),
+ xb, es_add_code, "es_add_code");
+ SD_CONDSET(((struct scsi_extended_sense *)xb->xb_sense_data),
+ xb, es_qual_code, "es_qual_code");
+ struct scsi_extended_sense *esp;
+ esp = (struct scsi_extended_sense *)xb->xb_sense_data;
+ esp->es_class = CLASS_EXTENDED_SENSE;
}
/* set un if it was on fifo */
@@ -27890,7 +29183,7 @@ sd_faultinjection(struct scsi_pkt *pktp)
mutex_exit(SD_MUTEX(un));
- SD_TRACE(SD_LOG_SDTEST, un, "sd_faultinjection: exit\n");
+ SD_INFO(SD_LOG_SDTEST, un, "sd_faultinjection: exit\n");
}
#endif /* SD_FAULT_INJECTION */
@@ -28355,9 +29648,10 @@ sd_tg_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr,
diskaddr_t first_byte, end_block;
size_t buffer_size = reqlength;
- int rval;
+ int rval = 0;
diskaddr_t cap;
uint32_t lbasize;
+ sd_ssc_t *ssc;
un = ddi_get_soft_state(sd_state, ddi_get_instance(devi));
if (un == NULL)
@@ -28366,18 +29660,20 @@ sd_tg_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr,
if (cmd != TG_READ && cmd != TG_WRITE)
return (EINVAL);
+ ssc = sd_ssc_init(un);
mutex_enter(SD_MUTEX(un));
if (un->un_f_tgt_blocksize_is_valid == FALSE) {
mutex_exit(SD_MUTEX(un));
- rval = sd_send_scsi_READ_CAPACITY(un, (uint64_t *)&cap,
+ rval = sd_send_scsi_READ_CAPACITY(ssc, (uint64_t *)&cap,
&lbasize, path_flag);
if (rval != 0)
- return (rval);
+ goto done1;
mutex_enter(SD_MUTEX(un));
sd_update_block_info(un, lbasize, cap);
if ((un->un_f_tgt_blocksize_is_valid == FALSE)) {
mutex_exit(SD_MUTEX(un));
- return (EIO);
+ rval = EIO;
+ goto done;
}
}
@@ -28423,29 +29719,37 @@ sd_tg_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr,
mutex_exit(SD_MUTEX(un));
if (cmd == TG_READ) {
- rval = sd_send_scsi_READ(un, (dkl != NULL)? dkl: bufaddr,
+ rval = sd_send_scsi_READ(ssc, (dkl != NULL)? dkl: bufaddr,
buffer_size, real_addr, path_flag);
if (dkl != NULL)
bcopy(dkl + SD_TGTBYTEOFFSET(un, start_block,
real_addr), bufaddr, reqlength);
} else {
if (dkl) {
- rval = sd_send_scsi_READ(un, dkl, buffer_size,
+ rval = sd_send_scsi_READ(ssc, dkl, buffer_size,
real_addr, path_flag);
if (rval) {
- kmem_free(dkl, buffer_size);
- return (rval);
+ goto done1;
}
bcopy(bufaddr, dkl + SD_TGTBYTEOFFSET(un, start_block,
real_addr), reqlength);
}
- rval = sd_send_scsi_WRITE(un, (dkl != NULL)? dkl: bufaddr,
+ rval = sd_send_scsi_WRITE(ssc, (dkl != NULL)? dkl: bufaddr,
buffer_size, real_addr, path_flag);
}
+done1:
if (dkl != NULL)
kmem_free(dkl, buffer_size);
+ if (rval != 0) {
+ if (rval == EIO)
+ sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+ }
+done:
+ sd_ssc_fini(ssc);
return (rval);
}
@@ -28477,11 +29781,22 @@ sd_tg_getinfo(dev_info_t *devi, int cmd, void *arg, void *tg_cookie)
lbasize = un->un_tgt_blocksize;
mutex_exit(SD_MUTEX(un));
} else {
+ sd_ssc_t *ssc;
mutex_exit(SD_MUTEX(un));
- ret = sd_send_scsi_READ_CAPACITY(un, (uint64_t *)&cap,
+ ssc = sd_ssc_init(un);
+ ret = sd_send_scsi_READ_CAPACITY(ssc, (uint64_t *)&cap,
&lbasize, path_flag);
- if (ret != 0)
+ if (ret != 0) {
+ if (ret == EIO)
+ sd_ssc_assessment(ssc,
+ SD_FMT_STATUS_CHECK);
+ else
+ sd_ssc_assessment(ssc,
+ SD_FMT_IGNORE);
+ sd_ssc_fini(ssc);
return (ret);
+ }
+ sd_ssc_fini(ssc);
mutex_enter(SD_MUTEX(un));
sd_update_block_info(un, lbasize, cap);
if ((un->un_f_blockcount_is_valid == FALSE) ||
@@ -28522,5 +29837,460 @@ sd_tg_getinfo(dev_info_t *devi, int cmd, void *arg, void *tg_cookie)
return (ENOTTY);
}
+}
+
+/*
+ * Function: sd_ssc_ereport_post
+ *
+ * Description: Will be called when SD driver need to post an ereport.
+ *
+ * Context: Kernel thread or interrupt context.
+ */
+static void
+sd_ssc_ereport_post(sd_ssc_t *ssc, enum sd_driver_assessment drv_assess)
+{
+ int uscsi_path_instance = 0;
+ uchar_t uscsi_pkt_reason;
+ uint32_t uscsi_pkt_state;
+ uint32_t uscsi_pkt_statistics;
+ uint64_t uscsi_ena;
+ uchar_t op_code;
+ uint8_t *sensep;
+ union scsi_cdb *cdbp;
+ uint_t cdblen = 0;
+ uint_t senlen = 0;
+ struct sd_lun *un;
+ dev_info_t *dip;
+ char *devid;
+ int ssc_invalid_flags = SSC_FLAGS_INVALID_PKT_REASON |
+ SSC_FLAGS_INVALID_STATUS |
+ SSC_FLAGS_INVALID_SENSE |
+ SSC_FLAGS_INVALID_DATA;
+ char assessment[16];
+
+ ASSERT(ssc != NULL);
+ ASSERT(ssc->ssc_uscsi_cmd != NULL);
+ ASSERT(ssc->ssc_uscsi_info != NULL);
+
+ un = ssc->ssc_un;
+ ASSERT(un != NULL);
+ dip = un->un_sd->sd_dev;
+
+ /*
+ * Get the devid:
+ * devid will only be passed to non-transport error reports.
+ */
+ devid = DEVI(dip)->devi_devid_str;
+
+ /*
+ * If we are syncing or dumping, the command will not be executed
+ * so we bypass this situation.
+ */
+ if (ddi_in_panic() || (un->un_state == SD_STATE_SUSPENDED) ||
+ (un->un_state == SD_STATE_DUMPING))
+ return;
+
+ uscsi_pkt_reason = ssc->ssc_uscsi_info->ui_pkt_reason;
+ uscsi_path_instance = ssc->ssc_uscsi_cmd->uscsi_path_instance;
+ uscsi_pkt_state = ssc->ssc_uscsi_info->ui_pkt_state;
+ uscsi_pkt_statistics = ssc->ssc_uscsi_info->ui_pkt_statistics;
+ uscsi_ena = ssc->ssc_uscsi_info->ui_ena;
+
+ sensep = (uint8_t *)ssc->ssc_uscsi_cmd->uscsi_rqbuf;
+ cdbp = (union scsi_cdb *)ssc->ssc_uscsi_cmd->uscsi_cdb;
+
+ /* In rare cases, EG:DOORLOCK, the cdb could be NULL */
+ if (cdbp == NULL) {
+ scsi_log(SD_DEVINFO(un), sd_label, CE_WARN,
+ "sd_ssc_ereport_post meet empty cdb\n");
+ return;
+ }
+
+ op_code = cdbp->scc_cmd;
+
+ cdblen = (int)ssc->ssc_uscsi_cmd->uscsi_cdblen;
+ senlen = (int)(ssc->ssc_uscsi_cmd->uscsi_rqlen -
+ ssc->ssc_uscsi_cmd->uscsi_rqresid);
+
+ if (senlen > 0)
+ ASSERT(sensep != NULL);
+
+ /*
+ * Initialize drv_assess to corresponding values.
+ * SD_FM_DRV_FATAL will be mapped to "fail" or "fatal" depending
+ * on the sense-key returned back.
+ */
+ switch (drv_assess) {
+ case SD_FM_DRV_RECOVERY:
+ (void) sprintf(assessment, "%s", "recovered");
+ break;
+ case SD_FM_DRV_RETRY:
+ (void) sprintf(assessment, "%s", "retry");
+ break;
+ case SD_FM_DRV_NOTICE:
+ (void) sprintf(assessment, "%s", "info");
+ break;
+ case SD_FM_DRV_FATAL:
+ default:
+ (void) sprintf(assessment, "%s", "unknown");
+ }
+ /*
+ * If drv_assess == SD_FM_DRV_RECOVERY, this should be a recovered
+ * command, we will post ereport.io.scsi.cmd.disk.recovered.
+ * driver-assessment will always be "recovered" here.
+ */
+ if (drv_assess == SD_FM_DRV_RECOVERY) {
+ scsi_fm_ereport_post(un->un_sd, uscsi_path_instance,
+ "cmd.disk.recovered", uscsi_ena, devid, DDI_NOSLEEP,
+ FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
+ "driver-assessment", DATA_TYPE_STRING, assessment,
+ "op-code", DATA_TYPE_UINT8, op_code,
+ "cdb", DATA_TYPE_UINT8_ARRAY,
+ cdblen, ssc->ssc_uscsi_cmd->uscsi_cdb,
+ "pkt-reason", DATA_TYPE_UINT8, uscsi_pkt_reason,
+ "pkt-state", DATA_TYPE_UINT32, uscsi_pkt_state,
+ "pkt-stats", DATA_TYPE_UINT32, uscsi_pkt_statistics,
+ NULL);
+ return;
+ }
+
+ /*
+ * If there is un-expected/un-decodable data, we should post
+ * ereport.io.scsi.cmd.disk.dev.uderr.
+ * driver-assessment will be set based on parameter drv_assess.
+ * SSC_FLAGS_INVALID_SENSE - invalid sense data sent back.
+ * SSC_FLAGS_INVALID_PKT_REASON - invalid pkt-reason encountered.
+ * SSC_FLAGS_INVALID_STATUS - invalid stat-code encountered.
+ * SSC_FLAGS_INVALID_DATA - invalid data sent back.
+ */
+ if (ssc->ssc_flags & ssc_invalid_flags) {
+ if (ssc->ssc_flags & SSC_FLAGS_INVALID_SENSE) {
+ scsi_fm_ereport_post(un->un_sd, uscsi_path_instance,
+ "cmd.disk.dev.uderr", uscsi_ena, devid, DDI_NOSLEEP,
+ FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
+ "driver-assessment", DATA_TYPE_STRING,
+ drv_assess == SD_FM_DRV_FATAL ?
+ "fail" : assessment,
+ "op-code", DATA_TYPE_UINT8, op_code,
+ "cdb", DATA_TYPE_UINT8_ARRAY,
+ cdblen, ssc->ssc_uscsi_cmd->uscsi_cdb,
+ "pkt-reason", DATA_TYPE_UINT8, uscsi_pkt_reason,
+ "pkt-state", DATA_TYPE_UINT32, uscsi_pkt_state,
+ "pkt-stats", DATA_TYPE_UINT32,
+ uscsi_pkt_statistics,
+ "stat-code", DATA_TYPE_UINT8,
+ ssc->ssc_uscsi_cmd->uscsi_status,
+ "un-decode-info", DATA_TYPE_STRING,
+ ssc->ssc_info,
+ "un-decode-value", DATA_TYPE_UINT8_ARRAY,
+ senlen, sensep,
+ NULL);
+ } else {
+ /*
+ * For other type of invalid data, the
+ * un-decode-value field would be empty because the
+ * un-decodable content could be seen from upper
+ * level payload or inside un-decode-info.
+ */
+ scsi_fm_ereport_post(un->un_sd, uscsi_path_instance,
+ "cmd.disk.dev.uderr", uscsi_ena, devid, DDI_NOSLEEP,
+ FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
+ "driver-assessment", DATA_TYPE_STRING,
+ drv_assess == SD_FM_DRV_FATAL ?
+ "fail" : assessment,
+ "op-code", DATA_TYPE_UINT8, op_code,
+ "cdb", DATA_TYPE_UINT8_ARRAY,
+ cdblen, ssc->ssc_uscsi_cmd->uscsi_cdb,
+ "pkt-reason", DATA_TYPE_UINT8, uscsi_pkt_reason,
+ "pkt-state", DATA_TYPE_UINT32, uscsi_pkt_state,
+ "pkt-stats", DATA_TYPE_UINT32,
+ uscsi_pkt_statistics,
+ "stat-code", DATA_TYPE_UINT8,
+ ssc->ssc_uscsi_cmd->uscsi_status,
+ "un-decode-info", DATA_TYPE_STRING,
+ ssc->ssc_info,
+ "un-decode-value", DATA_TYPE_UINT8_ARRAY,
+ 0, NULL,
+ NULL);
+ }
+ ssc->ssc_flags &= ~ssc_invalid_flags;
+ return;
+ }
+
+ if (uscsi_pkt_reason != CMD_CMPLT ||
+ (ssc->ssc_flags & SSC_FLAGS_TRAN_ABORT)) {
+ /*
+ * pkt-reason != CMD_CMPLT or SSC_FLAGS_TRAN_ABORT was
+ * set inside sd_start_cmds due to errors(bad packet or
+ * fatal transport error), we should take it as a
+ * transport error, so we post ereport.io.scsi.cmd.disk.tran.
+ * driver-assessment will be set based on drv_assess.
+ * We will set devid to NULL because it is a transport
+ * error.
+ */
+ if (ssc->ssc_flags & SSC_FLAGS_TRAN_ABORT)
+ ssc->ssc_flags &= ~SSC_FLAGS_TRAN_ABORT;
+
+ scsi_fm_ereport_post(un->un_sd, uscsi_path_instance,
+ "cmd.disk.tran", uscsi_ena, NULL, DDI_NOSLEEP, FM_VERSION,
+ DATA_TYPE_UINT8, FM_EREPORT_VERS0,
+ "driver-assessment", DATA_TYPE_STRING,
+ drv_assess == SD_FM_DRV_FATAL ? "fail" : assessment,
+ "op-code", DATA_TYPE_UINT8, op_code,
+ "cdb", DATA_TYPE_UINT8_ARRAY,
+ cdblen, ssc->ssc_uscsi_cmd->uscsi_cdb,
+ "pkt-reason", DATA_TYPE_UINT8, uscsi_pkt_reason,
+ "pkt-state", DATA_TYPE_UINT8, uscsi_pkt_state,
+ "pkt-stats", DATA_TYPE_UINT32, uscsi_pkt_statistics,
+ NULL);
+ } else {
+ /*
+ * If we got here, we have a completed command, and we need
+ * to further investigate the sense data to see what kind
+ * of ereport we should post.
+ * Post ereport.io.scsi.cmd.disk.dev.rqs.merr
+ * if sense-key == 0x3.
+ * Post ereport.io.scsi.cmd.disk.dev.rqs.derr otherwise.
+ * driver-assessment will be set based on the parameter
+ * drv_assess.
+ */
+ if (senlen > 0) {
+ /*
+ * Here we have sense data available.
+ */
+ uint8_t sense_key;
+ sense_key = scsi_sense_key(sensep);
+ if (sense_key == 0x3) {
+ /*
+ * sense-key == 0x3(medium error),
+ * driver-assessment should be "fatal" if
+ * drv_assess is SD_FM_DRV_FATAL.
+ */
+ scsi_fm_ereport_post(un->un_sd,
+ uscsi_path_instance,
+ "cmd.disk.dev.rqs.merr",
+ uscsi_ena, devid, DDI_NOSLEEP, FM_VERSION,
+ DATA_TYPE_UINT8, FM_EREPORT_VERS0,
+ "driver-assessment",
+ DATA_TYPE_STRING,
+ drv_assess == SD_FM_DRV_FATAL ?
+ "fatal" : assessment,
+ "op-code",
+ DATA_TYPE_UINT8, op_code,
+ "cdb",
+ DATA_TYPE_UINT8_ARRAY, cdblen,
+ ssc->ssc_uscsi_cmd->uscsi_cdb,
+ "pkt-reason",
+ DATA_TYPE_UINT8, uscsi_pkt_reason,
+ "pkt-state",
+ DATA_TYPE_UINT8, uscsi_pkt_state,
+ "pkt-stats",
+ DATA_TYPE_UINT32,
+ uscsi_pkt_statistics,
+ "stat-code",
+ DATA_TYPE_UINT8,
+ ssc->ssc_uscsi_cmd->uscsi_status,
+ "key",
+ DATA_TYPE_UINT8,
+ scsi_sense_key(sensep),
+ "asc",
+ DATA_TYPE_UINT8,
+ scsi_sense_asc(sensep),
+ "ascq",
+ DATA_TYPE_UINT8,
+ scsi_sense_ascq(sensep),
+ "sense-data",
+ DATA_TYPE_UINT8_ARRAY,
+ senlen, sensep,
+ "lba",
+ DATA_TYPE_UINT64,
+ ssc->ssc_uscsi_info->ui_lba,
+ NULL);
+ } else {
+ /*
+ * if sense-key == 0x4(hardware
+ * error), driver-assessment should
+ * be "fatal" if drv_assess is
+ * SD_FM_DRV_FATAL.
+ */
+ scsi_fm_ereport_post(un->un_sd,
+ uscsi_path_instance,
+ "cmd.disk.dev.rqs.derr",
+ uscsi_ena, devid, DDI_NOSLEEP,
+ FM_VERSION,
+ DATA_TYPE_UINT8, FM_EREPORT_VERS0,
+ "driver-assessment",
+ DATA_TYPE_STRING,
+ drv_assess == SD_FM_DRV_FATAL ?
+ (sense_key == 0x4 ?
+ "fatal" : "fail") : assessment,
+ "op-code",
+ DATA_TYPE_UINT8, op_code,
+ "cdb",
+ DATA_TYPE_UINT8_ARRAY, cdblen,
+ ssc->ssc_uscsi_cmd->uscsi_cdb,
+ "pkt-reason",
+ DATA_TYPE_UINT8, uscsi_pkt_reason,
+ "pkt-state",
+ DATA_TYPE_UINT8, uscsi_pkt_state,
+ "pkt-stats",
+ DATA_TYPE_UINT32,
+ uscsi_pkt_statistics,
+ "stat-code",
+ DATA_TYPE_UINT8,
+ ssc->ssc_uscsi_cmd->uscsi_status,
+ "key",
+ DATA_TYPE_UINT8,
+ scsi_sense_key(sensep),
+ "asc",
+ DATA_TYPE_UINT8,
+ scsi_sense_asc(sensep),
+ "ascq",
+ DATA_TYPE_UINT8,
+ scsi_sense_ascq(sensep),
+ "sense-data",
+ DATA_TYPE_UINT8_ARRAY,
+ senlen, sensep,
+ NULL);
+ }
+ } else {
+ /*
+ * Post ereport.io.scsi.cmd.disk.dev.serr if we got the
+ * stat-code but with sense data unavailable.
+ * driver-assessment will be set based on parameter
+ * drv_assess.
+ */
+ scsi_fm_ereport_post(un->un_sd,
+ uscsi_path_instance, "cmd.disk.dev.serr", uscsi_ena,
+ devid, DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8,
+ FM_EREPORT_VERS0,
+ "driver-assessment", DATA_TYPE_STRING,
+ drv_assess == SD_FM_DRV_FATAL ? "fail" : assessment,
+ "op-code", DATA_TYPE_UINT8, op_code,
+ "cdb",
+ DATA_TYPE_UINT8_ARRAY,
+ cdblen, ssc->ssc_uscsi_cmd->uscsi_cdb,
+ "pkt-reason",
+ DATA_TYPE_UINT8, uscsi_pkt_reason,
+ "pkt-state",
+ DATA_TYPE_UINT8, uscsi_pkt_state,
+ "pkt-stats",
+ DATA_TYPE_UINT32, uscsi_pkt_statistics,
+ "stat-code",
+ DATA_TYPE_UINT8,
+ ssc->ssc_uscsi_cmd->uscsi_status,
+ NULL);
+ }
+ }
+}
+
+/*
+ * Function: sd_ssc_extract_info
+ *
+ * Description: Extract information available to help generate ereport.
+ *
+ * Context: Kernel thread or interrupt context.
+ */
+static void
+sd_ssc_extract_info(sd_ssc_t *ssc, struct sd_lun *un, struct scsi_pkt *pktp,
+ struct buf *bp, struct sd_xbuf *xp)
+{
+ ASSERT(un != NULL);
+ ASSERT(pktp != NULL);
+ ASSERT(bp != NULL);
+ ASSERT(xp != NULL);
+ ASSERT(ssc != NULL);
+ ASSERT(mutex_owned(SD_MUTEX(un)));
+
+ size_t senlen = 0;
+ union scsi_cdb *cdbp;
+ int path_instance;
+ struct uscsi_cmd *uscmd;
+
+ /*
+ * Need scsi_cdb_size array to determine the cdb length.
+ */
+ extern uchar_t scsi_cdb_size[];
+
+ /*
+ * Transfer the cdb buffer pointer here.
+ */
+ cdbp = (union scsi_cdb *)pktp->pkt_cdbp;
+
+ ssc->ssc_uscsi_cmd->uscsi_cdblen = scsi_cdb_size[GETGROUP(cdbp)];
+ ssc->ssc_uscsi_cmd->uscsi_cdb = (caddr_t)cdbp;
+
+ /*
+ * Transfer the sense data buffer pointer if sense data is available,
+ * calculate the sense data length first.
+ */
+
+ uscmd = (struct uscsi_cmd *)xp->xb_pktinfo;
+ /*
+ * For non-arq case, we will enter this branch.
+ * The algorithm is excerpted from sd_handle_request_sense.
+ */
+ if (!(xp->xb_sense_state & STATE_XARQ_DONE) &&
+ !(xp->xb_sense_state & STATE_ARQ_DONE)) {
+ if (SD_GET_PKT_STATUS(pktp) == STATUS_CHECK &&
+ xp->xb_sense_state == STATE_XFERRED_DATA) {
+ if ((xp->xb_pkt_flags & SD_XB_USCSICMD) &&
+ uscmd->uscsi_rqlen > SENSE_LENGTH)
+ senlen = MAX_SENSE_LENGTH - xp->xb_sense_resid;
+ else
+ senlen = SENSE_LENGTH - xp->xb_sense_resid;
+ }
+ } else {
+ /*
+ * For arq case, we will enter here.
+ * The algorithm is excerpted from
+ * sd_handle_auto_request_sense.
+ */
+ if (xp->xb_sense_state & STATE_XARQ_DONE) {
+ senlen = MAX_SENSE_LENGTH - xp->xb_sense_resid;
+ } else {
+ if (xp->xb_pkt_flags & SD_XB_USCSICMD)
+ senlen = SENSE_LENGTH;
+ else {
+ if (xp->xb_sense_resid > SENSE_LENGTH) {
+ senlen = SENSE_LENGTH;
+ } else {
+ senlen = SENSE_LENGTH -
+ xp->xb_sense_resid;
+ }
+ }
+ }
+ }
+
+ ssc->ssc_uscsi_cmd->uscsi_rqlen = (senlen & 0xff);
+ ssc->ssc_uscsi_cmd->uscsi_rqresid = 0;
+ ssc->ssc_uscsi_cmd->uscsi_rqbuf = (caddr_t)xp->xb_sense_data;
+
+ ssc->ssc_uscsi_cmd->uscsi_status = ((*(pktp)->pkt_scbp) & STATUS_MASK);
+
+ /*
+ * Only transfer path_instance when scsi_pkt was properly allocated.
+ */
+ path_instance = pktp->pkt_path_instance;
+ if (scsi_pkt_allocated_correctly(pktp) && path_instance)
+ ssc->ssc_uscsi_cmd->uscsi_path_instance = path_instance;
+ else
+ ssc->ssc_uscsi_cmd->uscsi_path_instance = 0;
+
+ /*
+ * Copy in the other fields we may need when posting ereport.
+ */
+ ssc->ssc_uscsi_info->ui_pkt_reason = pktp->pkt_reason;
+ ssc->ssc_uscsi_info->ui_pkt_state = pktp->pkt_state;
+ ssc->ssc_uscsi_info->ui_pkt_statistics = pktp->pkt_statistics;
+ ssc->ssc_uscsi_info->ui_lba = (uint64_t)SD_GET_BLKNO(bp);
+
+ /*
+ * To associate ereports of a single command execution flow, we
+ * need a shared ena for a specific command.
+ */
+ if (xp->xb_ena == 0)
+ xp->xb_ena = fm_ena_generate(0, FM_ENA_FMT1);
+ ssc->ssc_uscsi_info->ui_ena = xp->xb_ena;
}
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile
index 300ea34b3e..d8576f83a3 100644
--- a/usr/src/uts/common/sys/Makefile
+++ b/usr/src/uts/common/sys/Makefile
@@ -816,6 +816,7 @@ SCSIHDRS= \
scsi.h \
scsi_address.h \
scsi_ctl.h \
+ scsi_fm.h \
scsi_params.h \
scsi_pkt.h \
scsi_resource.h \
diff --git a/usr/src/uts/common/sys/scsi/impl/services.h b/usr/src/uts/common/sys/scsi/impl/services.h
index 7e2201482c..edebf684f3 100644
--- a/usr/src/uts/common/sys/scsi/impl/services.h
+++ b/usr/src/uts/common/sys/scsi/impl/services.h
@@ -19,14 +19,13 @@
* 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.
*/
#ifndef _SYS_SCSI_IMPL_SERVICES_H
#define _SYS_SCSI_IMPL_SERVICES_H
-#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
@@ -64,6 +63,13 @@ char *scsi_cmd_name(uchar_t cmd, struct scsi_key_strings *cmdlist,
char *scsi_sname(uchar_t sense_key);
char *scsi_esname(uint_t sense_key, char *tmpstr);
char *scsi_asc_name(uint_t asc, uint_t ascq, char *tmpstr);
+
+void scsi_generic_errmsg(struct scsi_device *devp, char *label,
+ int severity, daddr_t blkno, daddr_t err_blkno,
+ uchar_t cmd_name, struct scsi_key_strings *cmdlist,
+ uint8_t *sensep, struct scsi_asq_key_strings *asc_list,
+ char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t));
+
void scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pktp,
char *drv_name, int severity, daddr_t blkno, daddr_t err_blkno,
struct scsi_key_strings *cmdlist,
@@ -74,6 +80,10 @@ void scsi_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt,
char *label, int severity, daddr_t blkno, daddr_t err_blkno,
struct scsi_key_strings *cmdlist,
struct scsi_extended_sense *sensep);
+
+
+
+
/*PRINTFLIKE4*/
void scsi_log(dev_info_t *dev, char *label,
uint_t level, const char *fmt, ...) __KPRINTFLIKE(4);
diff --git a/usr/src/uts/common/sys/scsi/impl/uscsi.h b/usr/src/uts/common/sys/scsi/impl/uscsi.h
index 80e424d6aa..fe6495856a 100644
--- a/usr/src/uts/common/sys/scsi/impl/uscsi.h
+++ b/usr/src/uts/common/sys/scsi/impl/uscsi.h
@@ -30,7 +30,6 @@
#ifndef _SYS_SCSI_IMPL_USCSI_H
#define _SYS_SCSI_IMPL_USCSI_H
-#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
@@ -190,13 +189,20 @@ struct uscsi_rqs32 {
#include <sys/scsi/scsi_types.h>
+struct uscsi_cmd *scsi_uscsi_alloc();
+int scsi_uscsi_copyin(intptr_t, int,
+ struct scsi_address *, struct uscsi_cmd **);
int scsi_uscsi_alloc_and_copyin(intptr_t, int,
struct scsi_address *, struct uscsi_cmd **);
+
int scsi_uscsi_pktinit(struct uscsi_cmd *, struct scsi_pkt *);
int scsi_uscsi_handle_cmd(dev_t, enum uio_seg,
struct uscsi_cmd *, int (*)(struct buf *),
struct buf *, void *);
int scsi_uscsi_pktfini(struct scsi_pkt *, struct uscsi_cmd *);
+
+int scsi_uscsi_copyout(intptr_t, struct uscsi_cmd *);
+void scsi_uscsi_free(struct uscsi_cmd *);
int scsi_uscsi_copyout_and_free(intptr_t, struct uscsi_cmd *);
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/sys/scsi/scsi_fm.h b/usr/src/uts/common/sys/scsi/scsi_fm.h
new file mode 100644
index 0000000000..9001fcb156
--- /dev/null
+++ b/usr/src/uts/common/sys/scsi/scsi_fm.h
@@ -0,0 +1,49 @@
+/*
+ * 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_SCSI_FM_H
+#define _SYS_SCSI_SCSI_FM_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * fault management initialization and clean-up:
+ * do init/fini from initchild/uninitchild?
+ */
+void scsi_fm_init(struct scsi_device *);
+void scsi_fm_fini(struct scsi_device *);
+
+/* ereport generation: */
+void scsi_fm_ereport_post(struct scsi_device *sd, int path_instance,
+ const char *error_class, uint64_t ena, char *devid, int sflag, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SCSI_SCSI_FM_H */
diff --git a/usr/src/uts/common/sys/scsi/scsi_types.h b/usr/src/uts/common/sys/scsi/scsi_types.h
index 0ec842f2dd..82328afbd4 100644
--- a/usr/src/uts/common/sys/scsi/scsi_types.h
+++ b/usr/src/uts/common/sys/scsi/scsi_types.h
@@ -26,7 +26,6 @@
#ifndef _SYS_SCSI_SCSI_TYPES_H
#define _SYS_SCSI_SCSI_TYPES_H
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Types for SCSI subsystems.
@@ -80,6 +79,7 @@ typedef void *opaque_t;
#ifdef _KERNEL
#include <sys/scsi/conf/autoconf.h>
#include <sys/scsi/scsi_watch.h>
+#include <sys/scsi/scsi_fm.h>
#endif /* _KERNEL */
#include <sys/scsi/generic/commands.h>
diff --git a/usr/src/uts/common/sys/scsi/targets/sddef.h b/usr/src/uts/common/sys/scsi/targets/sddef.h
index 25672defd5..8f7ddd9053 100644
--- a/usr/src/uts/common/sys/scsi/targets/sddef.h
+++ b/usr/src/uts/common/sys/scsi/targets/sddef.h
@@ -71,6 +71,9 @@ extern "C" {
* #endif
*/
+#if DEBUG || lint
+#define SD_FAULT_INJECTION
+#endif
#define VERBOSE 1
#define SILENT 0
@@ -525,6 +528,12 @@ struct sd_lun {
#endif
cmlb_handle_t un_cmlbhandle;
+
+ /*
+ * Pointer to internal struct sd_fm_internal in which
+ * will pass necessary information for FMA ereport posting.
+ */
+ void *un_fm_private;
};
#define SD_IS_VALID_LABEL(un) (cmlb_is_valid(un->un_cmlbhandle))
@@ -612,7 +621,8 @@ _NOTE(SCHEME_PROTECTS_DATA("safe sharing",
sd_lun::un_dcvb_timeid
sd_lun::un_f_allow_bus_device_reset
sd_lun::un_sys_blocksize
- sd_lun::un_tgt_blocksize))
+ sd_lun::un_tgt_blocksize
+ sd_lun::un_additional_codes))
_NOTE(SCHEME_PROTECTS_DATA("stable data",
sd_lun::un_reserve_release_time
@@ -1030,16 +1040,17 @@ struct sd_fi_arq {
struct scsi_extended_sense sts_sensedata;
};
-/* Conditional set def */
-#define SD_CONDSET(a, b, c, d) \
- if ((((fi_ ## b)->c) != 0xFF) && \
- (((fi_ ## b)->c) != 0xFFFF) && \
- (((fi_ ## b)->c) != 0xFFFFFFFF)) { \
- a->c = ((fi_ ## b)->c); \
- SD_INFO(SD_LOG_IOERR, un, \
- "sd_fault_injection:" \
- "setting %s to %d\n", \
- d, ((fi_ ## b)->c)); }
+/*
+ * Conditional set def
+ */
+#define SD_CONDSET(a, b, c, d) \
+ { \
+ a->c = ((fi_ ## b)->c); \
+ SD_INFO(SD_LOG_IOERR, un, \
+ "sd_fault_injection:" \
+ "setting %s to %d\n", \
+ d, ((fi_ ## b)->c)); \
+ }
/* SD FaultInjection ioctls */
#define SDIOC ('T'<<8)
@@ -1257,16 +1268,16 @@ if (((pktp)->pkt_reason == CMD_RESET) || \
/*
* xb_pkt_flags defines
- * SD_XB_USCSICMD indicates the scsi request is a uscsi request
* SD_XB_DMA_FREED indicates the scsi_pkt has had its DMA resources freed
* by a call to scsi_dmafree(9F). The resources must be reallocated before
* before a call to scsi_transport can be made again.
+ * SD_XB_USCSICMD indicates the scsi request is a uscsi request
* SD_XB_INITPKT_MASK: since this field is also used to store flags for
* a scsi_init_pkt(9F) call, we need a mask to make sure that we don't
* pass any unintended bits to scsi_init_pkt(9F) (ugly hack).
*/
-#define SD_XB_USCSICMD 0x40000000
#define SD_XB_DMA_FREED 0x20000000
+#define SD_XB_USCSICMD 0x40000000
#define SD_XB_INITPKT_MASK (PKT_CONSISTENT | PKT_DMA_PARTIAL)
/*
@@ -1323,6 +1334,7 @@ struct sd_xbuf {
* the driver owns or is free to modify.
*/
daddr_t xb_blkno; /* Absolute block # on target */
+ uint64_t xb_ena; /* ena for a specific SCSI command */
int xb_chain_iostart; /* iostart side index */
int xb_chain_iodone; /* iodone side index */
@@ -1362,7 +1374,6 @@ _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", sd_xbuf))
#define SD_GET_PKTP(bp) ((SD_GET_XBUF(bp))->xb_pktp)
#define SD_GET_BLKNO(bp) ((SD_GET_XBUF(bp))->xb_blkno)
-
/*
* Special-purpose struct for sd_send_scsi_cmd() to pass command-specific
* data through the layering chains to sd_initpkt_for_uscsi().
@@ -1375,10 +1386,162 @@ struct sd_uscsi_info {
* for async completion notification.
*/
struct dk_callback ui_dkc;
+ /*
+ * The following fields are to be used for FMA ereport generation.
+ */
+ uchar_t ui_pkt_reason;
+ uint32_t ui_pkt_state;
+ uint32_t ui_pkt_statistics;
+ uint64_t ui_lba;
+ uint64_t ui_ena;
};
_NOTE(SCHEME_PROTECTS_DATA("Unshared data", sd_uscsi_info))
+/*
+ * This structure is used to issue 'internal' command sequences from the
+ * driver's attach(9E)/open(9E)/etc entry points. It provides a common context
+ * for issuing command sequences, with the ability to issue a command
+ * and provide expected/unexpected assessment of results at any code
+ * level within the sd_ssc_t scope and preserve the information needed
+ * produce telemetry for the problem, when needed, from a single
+ * outer-most-scope point.
+ *
+ * The sd_ssc_t abstraction should result in well-structured code where
+ * the basic code structure is not jeprodized by future localized improvement.
+ *
+ * o Scope for a sequence of commands.
+ * o Within a scoped sequence of commands, provides a single top-level
+ * location for initiating telementry generation from captured data.
+ * o Provide a common place to capture command execution data and driver
+ * assessment information for delivery to telemetry generation point.
+ * o Mechanism to get device-as-detector (dad) and transport telemetry
+ * information from interrupt context (sdintr) back to the internal
+ * command 'driver-assessment' code.
+ * o Ability to record assessment, and return information back to
+ * top-level telemetry generation code when an unexpected condition
+ * occurs.
+ * o For code paths were an command itself was successful but
+ * the data returned looks suspect, the ability to record
+ * 'unexpected data' conditions.
+ * o Record assessment of issuing the command and interpreting
+ * the returned data for consumption by top-level ereport telemetry
+ * generation code.
+ * o All data required to produce telemetry available off single data
+ * structure.
+ */
+typedef struct {
+ struct sd_lun *ssc_un;
+ struct uscsi_cmd *ssc_uscsi_cmd;
+ struct sd_uscsi_info *ssc_uscsi_info;
+ int ssc_flags; /* Bits for flags */
+ char ssc_info[64]; /* Buffer holding for info */
+} sd_ssc_t;
+
+_NOTE(SCHEME_PROTECTS_DATA("Unshared data", sd_ssc_t))
+
+/*
+ * This struct switch different 'type-of-assessment'
+ * as an input argument for sd_ssc_assessment
+ *
+ *
+ * in sd_send_scsi_XXX or upper-level
+ *
+ * - SD_FMT_IGNORE
+ * when send uscsi command failed, and
+ * the following code check sense data properly.
+ * we use 'ignore' to let sd_ssc_assessment
+ * trust current and do not do additional
+ * checking for the uscsi command.
+ *
+ * - SD_FMT_IGNORE_COMPROMISE
+ * when send uscsi command failed, and
+ * the code does not check sense data or we don't
+ * think the checking is 100% coverage. We mark it
+ * as 'compromise' to indicate that we need to
+ * enhance current code in the future.
+ *
+ * - SD_FMT_STATUS_CHECK
+ * when send uscsi command failed and cause sd entries
+ * failed finally, we need to send out real reason against
+ * status of uscsi command no matter if there is sense back
+ * or not.
+ *
+ * - SD_FMT_STANDARD
+ * when send uscsi command succeeded, and
+ * the code does not check sense data, we need to check
+ * it to make sure there is no 'fault'.
+ */
+enum sd_type_assessment {
+ SD_FMT_IGNORE = 0,
+ SD_FMT_IGNORE_COMPROMISE,
+ SD_FMT_STATUS_CHECK,
+ SD_FMT_STANDARD
+};
+
+/*
+ * The following declaration are used as hints of severities when posting
+ * SCSI FMA ereport.
+ * - SD_FM_DRV_FATAL
+ * When posting ereport with SD_FM_DRV_FATAL, the payload
+ * "driver-assessment" will be "fail" or "fatal" depending on the
+ * sense-key value. If driver-assessment is "fail", it will be
+ * propagated to an upset, otherwise, a fault will be propagated.
+ * - SD_FM_DRV_RETRY
+ * When posting ereport with SD_FM_DRV_RETRY, the payload
+ * "driver-assessment" will be "retry", and it will be propagated to an
+ * upset.
+ * - SD_FM_DRV_RECOVERY
+ * When posting ereport with SD_FM_DRV_RECOVERY, the payload
+ * "driver-assessment" will be "recovered", and it will be propagated to
+ * an upset.
+ * - SD_FM_DRV_NOTICE
+ * When posting ereport with SD_FM_DRV_NOTICE, the payload
+ * "driver-assessment" will be "info", and it will be propagated to an
+ * upset.
+ */
+enum sd_driver_assessment {
+ SD_FM_DRV_FATAL = 0,
+ SD_FM_DRV_RETRY,
+ SD_FM_DRV_RECOVERY,
+ SD_FM_DRV_NOTICE
+};
+
+/*
+ * The following structure is used as a buffer when posting SCSI FMA
+ * ereport for raw i/o. It will be allocated per sd_lun when entering
+ * sd_unit_attach and will be deallocated when entering sd_unit_detach.
+ */
+struct sd_fm_internal {
+ sd_ssc_t fm_ssc;
+ struct uscsi_cmd fm_ucmd;
+ struct sd_uscsi_info fm_uinfo;
+};
+
+/*
+ * Bits in ssc_flags
+ * sd_ssc_init will mark ssc_flags = SSC_FLAGS_UNKNOWN
+ * sd_ssc_send will mark ssc_flags = SSC_FLAGS_CMD_ISSUED &
+ * SSC_FLAGS_NEED_ASSESSMENT
+ * sd_ssc_assessment will clear SSC_FLAGS_CMD_ISSUED and
+ * SSC_FLAGS_NEED_ASSESSMENT bits of ssc_flags.
+ * SSC_FLAGS_CMD_ISSUED is to indicate whether the SCSI command has been
+ * sent out.
+ * SSC_FLAGS_NEED_ASSESSMENT is to guarantee we will not miss any
+ * assessment point.
+ */
+#define SSC_FLAGS_UNKNOWN 0x00000000
+#define SSC_FLAGS_CMD_ISSUED 0x00000001
+#define SSC_FLAGS_NEED_ASSESSMENT 0x00000002
+#define SSC_FLAGS_TRAN_ABORT 0x00000004
+
+/*
+ * The following bits in ssc_flags are for detecting unexpected data.
+ */
+#define SSC_FLAGS_INVALID_PKT_REASON 0x00000010
+#define SSC_FLAGS_INVALID_STATUS 0x00000020
+#define SSC_FLAGS_INVALID_SENSE 0x00000040
+#define SSC_FLAGS_INVALID_DATA 0x00000080
/*
* Macros and definitions for driver kstats and errstats