diff options
author | David Zhang - Sun Microsystems - Beijing China <David.Zhang@Sun.COM> | 2008-09-12 17:58:24 +0800 |
---|---|---|
committer | David Zhang - Sun Microsystems - Beijing China <David.Zhang@Sun.COM> | 2008-09-12 17:58:24 +0800 |
commit | 9e1c849eae563842996c64c805047e840c75fc79 (patch) | |
tree | 2075c2b16fad3b62391bdd18f6e36a04a133d067 /usr/src | |
parent | cdc64593cc1046229f4ac4daf5ead688b5efe6eb (diff) | |
download | illumos-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.dict | 5 | ||||
-rw-r--r-- | usr/src/cmd/fm/dicts/DISK.po | 35 | ||||
-rw-r--r-- | usr/src/cmd/fm/eversholt/files/common/disk.esc | 124 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWhea/prototype_com | 3 | ||||
-rw-r--r-- | usr/src/uts/common/Makefile.files | 2 | ||||
-rw-r--r-- | usr/src/uts/common/io/scsi/impl/scsi_fm.c | 137 | ||||
-rw-r--r-- | usr/src/uts/common/io/scsi/impl/scsi_subr.c | 203 | ||||
-rw-r--r-- | usr/src/uts/common/io/scsi/targets/sd.c | 2600 | ||||
-rw-r--r-- | usr/src/uts/common/sys/Makefile | 1 | ||||
-rw-r--r-- | usr/src/uts/common/sys/scsi/impl/services.h | 14 | ||||
-rw-r--r-- | usr/src/uts/common/sys/scsi/impl/uscsi.h | 8 | ||||
-rw-r--r-- | usr/src/uts/common/sys/scsi/scsi_fm.h | 49 | ||||
-rw-r--r-- | usr/src/uts/common/sys/scsi/scsi_types.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/sys/scsi/targets/sddef.h | 191 |
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 *)®); + 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 |