summaryrefslogtreecommitdiff
path: root/usr/src/uts/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r--usr/src/uts/common/Makefile.files8
-rw-r--r--usr/src/uts/common/io/1394/targets/scsa1394/hba.c6
-rw-r--r--usr/src/uts/common/io/devinfo.c48
-rw-r--r--usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c69
-rw-r--r--usr/src/uts/common/io/scsi/conf/scsi_confdata.c14
-rw-r--r--usr/src/uts/common/io/scsi/conf/scsi_confsubr.c9
-rw-r--r--usr/src/uts/common/io/scsi/impl/scsi_hba.c308
-rw-r--r--usr/src/uts/common/io/scsi/impl/scsi_resource.c1
-rw-r--r--usr/src/uts/common/io/scsi/impl/scsi_subr.c145
-rw-r--r--usr/src/uts/common/io/scsi/impl/scsi_transport.c57
-rw-r--r--usr/src/uts/common/io/scsi/targets/sd.c6
-rw-r--r--usr/src/uts/common/io/scsi/targets/sgen.c20
-rw-r--r--usr/src/uts/common/io/scsi/targets/st.c8
-rw-r--r--usr/src/uts/common/os/ddifm.c319
-rw-r--r--usr/src/uts/common/os/devcfg.c9
-rw-r--r--usr/src/uts/common/os/modsubr.c3
-rw-r--r--usr/src/uts/common/os/sunddi.c26
-rw-r--r--usr/src/uts/common/os/sunmdi.c175
-rw-r--r--usr/src/uts/common/sys/1394/targets/scsa1394/cmd.h13
-rw-r--r--usr/src/uts/common/sys/autoconf.h3
-rw-r--r--usr/src/uts/common/sys/ddi_impldefs.h6
-rw-r--r--usr/src/uts/common/sys/ddifm.h10
-rw-r--r--usr/src/uts/common/sys/devinfo_impl.h8
-rw-r--r--usr/src/uts/common/sys/mdi_impldefs.h20
-rw-r--r--usr/src/uts/common/sys/nvpair.h13
-rw-r--r--usr/src/uts/common/sys/scsi/conf/autoconf.h8
-rw-r--r--usr/src/uts/common/sys/scsi/conf/device.h24
-rw-r--r--usr/src/uts/common/sys/scsi/impl/transport.h24
-rw-r--r--usr/src/uts/common/sys/scsi/impl/uscsi.h58
-rw-r--r--usr/src/uts/common/sys/scsi/scsi_pkt.h71
-rw-r--r--usr/src/uts/common/sys/scsi/scsi_resource.h23
-rw-r--r--usr/src/uts/common/sys/scsi/scsi_types.h8
-rw-r--r--usr/src/uts/common/sys/scsi/targets/stdef.h13
-rw-r--r--usr/src/uts/common/sys/sunmdi.h5
34 files changed, 1141 insertions, 397 deletions
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 8439e9fb3e..87c9be72de 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -673,10 +673,10 @@ USBSPRL_OBJS += usbser_pl2303.o pl2303_dsd.o
WC_OBJS += wscons.o
-SCSI_OBJS += scsi_capabilities.o scsi_control.o scsi_watch.o \
- scsi_data.o scsi_resource.o scsi_subr.o \
- scsi_hba.o scsi_transport.o scsi_confsubr.o \
- scsi_reset_notify.o sas_transport.o
+SCSI_OBJS += scsi_capabilities.o scsi_confsubr.o scsi_control.o \
+ scsi_data.o scsi_hba.o scsi_reset_notify.o \
+ scsi_resource.o scsi_subr.o scsi_transport.o scsi_watch.o \
+ sas_transport.o
SCSI_VHCI_OBJS += scsi_vhci.o mpapi_impl.o
diff --git a/usr/src/uts/common/io/1394/targets/scsa1394/hba.c b/usr/src/uts/common/io/1394/targets/scsa1394/hba.c
index 20addb89d9..6399e3c79c 100644
--- a/usr/src/uts/common/io/1394/targets/scsa1394/hba.c
+++ b/usr/src/uts/common/io/1394/targets/scsa1394/hba.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -508,7 +508,7 @@ scsa1394_create_cmd_cache(scsa1394_state_t *sp)
(void) sprintf(name, "scsa1394%d_cache", sp->s_instance);
sp->s_cmd_cache = kmem_cache_create(name,
- sizeof (scsa1394_cmd_t), sizeof (void *),
+ SCSA1394_CMD_SIZE, sizeof (void *),
scsa1394_cmd_cache_constructor, scsa1394_cmd_cache_destructor,
NULL, (void *)sp, NULL, 0);
@@ -1316,7 +1316,7 @@ scsa1394_cmd_cache_constructor(void *buf, void *cdrarg, int kf)
{
scsa1394_cmd_t *cmd = buf;
- bzero(buf, sizeof (scsa1394_cmd_t));
+ bzero(buf, SCSA1394_CMD_SIZE);
cmd->sc_task.ts_drv_priv = cmd;
return (0);
diff --git a/usr/src/uts/common/io/devinfo.c b/usr/src/uts/common/io/devinfo.c
index 79279b4e31..25bc639c64 100644
--- a/usr/src/uts/common/io/devinfo.c
+++ b/usr/src/uts/common/io/devinfo.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1685,9 +1685,9 @@ di_copytree(struct dev_info *root, di_off_t *off_p, struct di_state *st)
static di_off_t
di_copynode(struct di_stack *dsp, struct di_state *st)
{
- di_off_t off;
- struct di_node *me;
- struct dev_info *node;
+ di_off_t off;
+ struct di_node *me;
+ struct dev_info *node;
dcmn_err2((CE_CONT, "di_copynode: depth = %x\n", dsp->depth));
@@ -1751,35 +1751,25 @@ di_copynode(struct di_stack *dsp, struct di_state *st)
#ifdef DEVID_COMPATIBILITY
/* check for devid as property marker */
- if (node->devi_devid) {
+ if (node->devi_devid_str) {
ddi_devid_t devid;
- char *devidstr;
int devid_size;
/*
- * The devid is now represented as a property.
- * For micro release compatibility with di_devid interface
- * in libdevinfo we must return it as a binary structure in'
- * the snapshot. When di_devid is removed from libdevinfo
- * in a future release (and devi_devid is deleted) then
- * code related to DEVID_COMPATIBILITY can be removed.
+ * The devid is now represented as a property. For
+ * compatibility with di_devid() interface in libdevinfo we
+ * must return it as a binary structure in the snapshot. When
+ * (if) di_devid() is removed from libdevinfo then the code
+ * related to DEVID_COMPATIBILITY can be removed.
*/
- ASSERT(node->devi_devid == DEVID_COMPATIBILITY);
-/* XXX should be DDI_DEV_T_NONE! */
- if (ddi_prop_lookup_string(DDI_DEV_T_ANY, (dev_info_t *)node,
- DDI_PROP_DONTPASS, DEVID_PROP_NAME, &devidstr) ==
- DDI_PROP_SUCCESS) {
- if (ddi_devid_str_decode(devidstr, &devid, NULL) ==
- DDI_SUCCESS) {
- devid_size = ddi_devid_sizeof(devid);
- off = di_checkmem(st, off, devid_size);
- me->devid = off;
- bcopy(devid,
- di_mem_addr(st, off), devid_size);
- off += devid_size;
- ddi_devid_free(devid);
- }
- ddi_prop_free(devidstr);
+ if (ddi_devid_str_decode(node->devi_devid_str, &devid, NULL) ==
+ DDI_SUCCESS) {
+ devid_size = ddi_devid_sizeof(devid);
+ off = di_checkmem(st, off, devid_size);
+ me->devid = off;
+ bcopy(devid, di_mem_addr(st, off), devid_size);
+ off += devid_size;
+ ddi_devid_free(devid);
}
}
#endif /* DEVID_COMPATIBILITY */
@@ -2870,6 +2860,8 @@ di_getpath_data(dev_info_t *dip, di_off_t *poff_p, di_off_t noff,
state = mdi_pi_get_state(pip);
me->path_state = path_state_convert(state);
+ me->path_instance = mdi_pi_get_path_instance(pip);
+
/*
* Get intermediate addressing info.
*/
diff --git a/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c
index ef21a261e0..47a62af903 100644
--- a/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c
+++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c
@@ -68,7 +68,7 @@ int vhci_prout_not_ready_retry = 180;
/*
* Version Macros
*/
-#define VHCI_NAME_VERSION "SCSI VHCI Driver 1.68"
+#define VHCI_NAME_VERSION "SCSI VHCI Driver %I%"
char vhci_version_name[] = VHCI_NAME_VERSION;
int vhci_first_time = 0;
@@ -1347,6 +1347,17 @@ pkt_cleanup:
* If this changes it needs to be handled for the polled scenario.
*/
flags = vpkt->vpkt_hba_pkt->pkt_flags;
+
+ /*
+ * Set the path_instance *before* sending the scsi_pkt down the path
+ * to mpxio's pHCI so that additional path abstractions at a pHCI
+ * level (like maybe iSCSI at some point in the future) can update
+ * the path_instance.
+ */
+ if (scsi_pkt_allocated_correctly(vpkt->vpkt_hba_pkt))
+ vpkt->vpkt_hba_pkt->pkt_path_instance =
+ mdi_pi_get_path_instance(vpkt->vpkt_path);
+
rval = scsi_transport(vpkt->vpkt_hba_pkt);
if (rval == TRAN_ACCEPT) {
if (flags & FLAG_NOINTR) {
@@ -2101,6 +2112,7 @@ vhci_bind_transport(struct scsi_address *ap, struct vhci_pkt *vpkt, int flags,
int mps_flag = MDI_SELECT_ONLINE_PATH;
struct scsi_vhci_lun *vlun;
time_t tnow;
+ int path_instance;
vlun = ADDR2VLUN(ap);
ASSERT(vlun != 0);
@@ -2171,6 +2183,17 @@ vhci_bind_transport(struct scsi_address *ap, struct vhci_pkt *vpkt, int flags,
}
/*
+ * Get path_instance. Non-zero indicates that mdi_select_path should
+ * be called to select a specific instance.
+ *
+ * NB: Condition pkt_path_instance reference on proper allocation.
+ */
+ if (scsi_pkt_allocated_correctly(vpkt->vpkt_tgt_pkt))
+ path_instance = vpkt->vpkt_tgt_pkt->pkt_path_instance;
+ else
+ path_instance = 0;
+
+ /*
* If reservation is active bind the transport directly to the pip
* with the reservation.
*/
@@ -2190,8 +2213,9 @@ vhci_bind_transport(struct scsi_address *ap, struct vhci_pkt *vpkt, int flags,
}
}
try_again:
- rval = mdi_select_path(cdip, vpkt->vpkt_tgt_init_bp, 0, NULL,
- &pip);
+ rval = mdi_select_path(cdip, vpkt->vpkt_tgt_init_bp,
+ path_instance ? MDI_SELECT_PATH_INSTANCE : 0,
+ (void *)(intptr_t)path_instance, &pip);
if (rval == MDI_BUSY) {
if (pgr_sema_held) {
sema_v(&vlun->svl_pgr_sema);
@@ -2352,6 +2376,10 @@ bind_path:
address = &pkt->pkt_address;
}
+ /* Verify match of specified path_instance and selected path_instance */
+ ASSERT((path_instance == 0) ||
+ (path_instance == mdi_pi_get_path_instance(vpkt->vpkt_path)));
+
/*
* For PKT_PARTIAL_DMA case, call pHCI's scsi_init_pkt whenever
* target driver calls vhci_scsi_init_pkt.
@@ -2988,6 +3016,21 @@ vhci_intr(struct scsi_pkt *pkt)
tpkt->pkt_statistics = pkt->pkt_statistics;
tpkt->pkt_reason = pkt->pkt_reason;
+ /* Return path_instance information back to the target driver. */
+ if (scsi_pkt_allocated_correctly(tpkt)) {
+ if (scsi_pkt_allocated_correctly(pkt)) {
+ /*
+ * If both packets were correctly allocated,
+ * return path returned by pHCI.
+ */
+ tpkt->pkt_path_instance = pkt->pkt_path_instance;
+ } else {
+ /* Otherwise return path of pHCI we used */
+ tpkt->pkt_path_instance =
+ mdi_pi_get_path_instance(lpath);
+ }
+ }
+
if (pkt->pkt_cdbp[0] == SCMD_PROUT &&
((pkt->pkt_cdbp[1] & 0x1f) == VHCI_PROUT_REGISTER) ||
((pkt->pkt_cdbp[1] & 0x1f) == VHCI_PROUT_R_AND_IGNORE)) {
@@ -3699,6 +3742,9 @@ vhci_update_pathstates(void *arg)
SCMD_READ, 1, 1, 0);
pkt->pkt_time = 3*30;
pkt->pkt_flags = FLAG_NOINTR;
+ pkt->pkt_path_instance =
+ mdi_pi_get_path_instance(pip);
+
if ((scsi_transport(pkt) ==
TRAN_ACCEPT) && (pkt->pkt_reason
== CMD_CMPLT) && (SCBP_C(pkt) ==
@@ -6741,7 +6787,9 @@ next_pathclass:
pkt->pkt_cdbp, SCMD_READ, 1, 1, 0);
pkt->pkt_flags = FLAG_NOINTR;
check_path_again:
+ pkt->pkt_path_instance = mdi_pi_get_path_instance(npip);
pkt->pkt_time = 3*30;
+
if (scsi_transport(pkt) == TRAN_ACCEPT) {
switch (pkt->pkt_reason) {
case CMD_CMPLT:
@@ -7110,7 +7158,6 @@ vhci_lun_free(dev_info_t *tgt_dip)
}
dvlp->svl_lun_wwn = NULL;
-
if (dvlp->svl_fops_name) {
kmem_free(dvlp->svl_fops_name, strlen(dvlp->svl_fops_name)+1);
}
@@ -8115,6 +8162,13 @@ vhci_uscsi_send_sense(struct scsi_pkt *pkt, mp_uscsi_cmd_t *mp_uscmdp)
rqpkt->pkt_comp = vhci_uscsi_iodone;
rqpkt->pkt_private = mp_uscmdp;
+ /*
+ * NOTE: This code path is related to MPAPI uscsi(7I), so path
+ * selection is not based on path_instance.
+ */
+ if (scsi_pkt_allocated_correctly(rqpkt))
+ rqpkt->pkt_path_instance = 0;
+
/* get her done */
switch (scsi_transport(rqpkt)) {
case TRAN_ACCEPT:
@@ -8340,6 +8394,13 @@ vhci_uscsi_iostart(struct buf *bp)
(void *)uscmdp, (void *)uscmdp->uscsi_cdb, pkt->pkt_cdblen,
(void *)bp, bp->b_bcount, (void *)mp_uscmdp->pip, stat_size));
+ /*
+ * NOTE: This code path is related to MPAPI uscsi(7I), so path
+ * selection is not based on path_instance.
+ */
+ if (scsi_pkt_allocated_correctly(pkt))
+ pkt->pkt_path_instance = 0;
+
while (((rval = scsi_transport(pkt)) == TRAN_BUSY) &&
retry < vhci_uscsi_retry_count) {
delay(drv_usectohz(vhci_uscsi_delay));
diff --git a/usr/src/uts/common/io/scsi/conf/scsi_confdata.c b/usr/src/uts/common/io/scsi/conf/scsi_confdata.c
index 0633d3180b..d171b7d53f 100644
--- a/usr/src/uts/common/io/scsi/conf/scsi_confdata.c
+++ b/usr/src/uts/common/io/scsi/conf/scsi_confdata.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1998,2002 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -28,7 +27,7 @@
#ifdef _KERNEL
-#include <sys/scsi/conf/autoconf.h>
+#include <sys/scsi/scsi_types.h>
/*
* Autoconfiguration Dependent Data
@@ -94,4 +93,9 @@ int scsi_tag_age_limit = 2;
*/
int scsi_watchdog_tick = 10;
+/*
+ * default scsi target driver "fm-capable" property value
+ */
+int scsi_fm_capable = DDI_FM_EREPORT_CAPABLE;
+
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/io/scsi/conf/scsi_confsubr.c b/usr/src/uts/common/io/scsi/conf/scsi_confsubr.c
index a3da2b7cef..9a42f48ef3 100644
--- a/usr/src/uts/common/io/scsi/conf/scsi_confsubr.c
+++ b/usr/src/uts/common/io/scsi/conf/scsi_confsubr.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -36,6 +36,7 @@
#include <sys/scsi/scsi.h>
#include <sys/modctl.h>
+#include <sys/bitmap.h>
/*
* macro for filling in lun value for scsi-1 support
@@ -174,6 +175,7 @@ uint64_t scsi_max_phys_addr = 0xFFFFFFFFull;
int scsi_sgl_size = 0xFF;
#endif
+ulong_t *scsi_pkt_bad_alloc_bitmap;
int
_init()
@@ -194,6 +196,9 @@ _init()
scsi_alloc_attr.dma_attr_sgllen = scsi_sgl_size;
#endif
+ /* bitmap to limit scsi_pkt allocation violation messages */
+ scsi_pkt_bad_alloc_bitmap = kmem_zalloc(BT_SIZEOFMAP(devcnt), KM_SLEEP);
+
return (mod_install(&modlinkage));
}
@@ -706,7 +711,7 @@ done:
out:
/*
* If lun > 0 we need to figure out if this is a scsi-1 device where
- * the "real" lun needs to be embeded into the cdb.
+ * the "real" lun needs to be embedded into the cdb.
*/
if ((rval == SCSIPROBE_EXISTS) && (pass == 1) &&
(devp->sd_address.a_lun > 0) && (devp->sd_inq->inq_ansi == 0x1)) {
diff --git a/usr/src/uts/common/io/scsi/impl/scsi_hba.c b/usr/src/uts/common/io/scsi/impl/scsi_hba.c
index 546ed02424..13b404ac0e 100644
--- a/usr/src/uts/common/io/scsi/impl/scsi_hba.c
+++ b/usr/src/uts/common/io/scsi/impl/scsi_hba.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -54,6 +54,9 @@ extern void scsi_sync_cache_pkt(struct scsi_address *,
*/
#define ROUNDUP(x) (((x) + 0x07) & ~0x07)
+/* Magic number to track correct allocations in wrappers */
+#define PKT_WRAPPER_MAGIC 0xa110ced /* alloced correctly */
+
static kmutex_t scsi_hba_mutex;
kmutex_t scsi_log_mutex;
@@ -132,7 +135,8 @@ static int scsi_hba_bus_config(dev_info_t *parent, uint_t flag,
ddi_bus_config_op_t op, void *arg, dev_info_t **childp);
static int scsi_hba_bus_unconfig(dev_info_t *parent, uint_t flag,
ddi_bus_config_op_t op, void *arg);
-
+static int scsi_hba_fm_init_child(dev_info_t *self, dev_info_t *child,
+ int cap, ddi_iblock_cookie_t *ibc);
static int scsi_hba_bus_power(dev_info_t *parent, void *impl_arg,
pm_bus_power_op_t op, void *arg, void *result);
@@ -163,7 +167,7 @@ static struct bus_ops scsi_hba_busops = {
NULL, /* bus_intr_ctl */
scsi_hba_bus_config, /* bus_config */
scsi_hba_bus_unconfig, /* bus_unconfig */
- NULL, /* bus_fm_init */
+ scsi_hba_fm_init_child, /* bus_fm_init */
NULL, /* bus_fm_fini */
NULL, /* bus_fm_access_enter */
NULL, /* bus_fm_access_exit */
@@ -222,13 +226,12 @@ scsi_uninitialize_hba_interface()
int
scsi_hba_pkt_constructor(void *buf, void *arg, int kmflag)
{
+ struct scsi_pkt_cache_wrapper *pktw;
struct scsi_pkt *pkt;
scsi_hba_tran_t *tran = (scsi_hba_tran_t *)arg;
int pkt_len;
char *ptr;
- pkt = &((struct scsi_pkt_cache_wrapper *)buf)->pcw_pkt;
-
/*
* allocate a chunk of memory for the following:
* scsi_pkt
@@ -244,15 +247,20 @@ scsi_hba_pkt_constructor(void *buf, void *arg, int kmflag)
if (tran->tran_hba_flags & SCSI_HBA_TRAN_SCB)
pkt_len += DEFAULT_SCBLEN;
bzero(buf, pkt_len);
+
ptr = buf;
+ pktw = buf;
ptr += sizeof (struct scsi_pkt_cache_wrapper);
+ pkt = &(pktw->pcw_pkt);
pkt->pkt_ha_private = (opaque_t)ptr;
+
+ pktw->pcw_magic = PKT_WRAPPER_MAGIC; /* alloced correctly */
/*
* keep track of the granularity at the time this handle was
* allocated
*/
- ((struct scsi_pkt_cache_wrapper *)buf)->pcw_granular =
- tran->tran_dma_attr.dma_attr_granular;
+ pktw->pcw_granular = tran->tran_dma_attr.dma_attr_granular;
+
if (ddi_dma_alloc_handle(tran->tran_hba_dip,
&tran->tran_dma_attr,
kmflag == KM_SLEEP ? SLEEP_FUNC: NULL_FUNC, NULL,
@@ -283,6 +291,7 @@ scsi_hba_pkt_destructor(void *buf, void *arg)
struct scsi_pkt *pkt = &(pktw->pcw_pkt);
scsi_hba_tran_t *tran = (scsi_hba_tran_t *)arg;
+ ASSERT(pktw->pcw_magic == PKT_WRAPPER_MAGIC);
ASSERT((pktw->pcw_flags & PCW_BOUND) == 0);
if (tran->tran_pkt_destructor)
(*tran->tran_pkt_destructor)(pkt, arg);
@@ -293,8 +302,8 @@ scsi_hba_pkt_destructor(void *buf, void *arg)
ASSERT(((tran->tran_hba_flags & SCSI_HBA_TRAN_SCB) == 0) ||
(pkt->pkt_scbp == (opaque_t)((char *)pkt +
tran->tran_hba_len +
- (((tran->tran_hba_flags & SCSI_HBA_TRAN_CDB) == 0)
- ? 0 : DEFAULT_CDBLEN) +
+ (((tran->tran_hba_flags & SCSI_HBA_TRAN_CDB) == 0) ?
+ 0 : DEFAULT_CDBLEN) +
DEFAULT_PRIVLEN + sizeof (struct scsi_pkt_cache_wrapper))));
ASSERT(((tran->tran_hba_flags & SCSI_HBA_TRAN_CDB) == 0) ||
(pkt->pkt_cdbp == (opaque_t)((char *)pkt +
@@ -382,7 +391,8 @@ scsi_hba_attach_setup(
int len;
char *prop_name;
const char *prop_value;
- char *errmsg =
+ int capable;
+ static char *errmsg =
"scsi_hba_attach: cannot create property '%s' for %s%d\n";
static const char *interconnect[] = INTERCONNECT_TYPE_ASCII;
@@ -467,7 +477,7 @@ scsi_hba_attach_setup(
if (ddi_prop_update_int(DDI_MAJOR_T_UNKNOWN, dip,
prop_name, value) != DDI_PROP_SUCCESS) {
cmn_err(CE_CONT, errmsg, prop_name,
- ddi_get_name(dip), ddi_get_instance(dip));
+ ddi_driver_name(dip), ddi_get_instance(dip));
}
}
@@ -479,7 +489,7 @@ scsi_hba_attach_setup(
if (ddi_prop_update_int(DDI_MAJOR_T_UNKNOWN, dip,
prop_name, value) != DDI_PROP_SUCCESS) {
cmn_err(CE_CONT, errmsg, prop_name,
- ddi_get_name(dip), ddi_get_instance(dip));
+ ddi_driver_name(dip), ddi_get_instance(dip));
}
}
@@ -491,7 +501,7 @@ scsi_hba_attach_setup(
if (ddi_prop_update_int(DDI_MAJOR_T_UNKNOWN, dip,
prop_name, value) != DDI_PROP_SUCCESS) {
cmn_err(CE_CONT, errmsg, prop_name,
- ddi_get_name(dip), ddi_get_instance(dip));
+ ddi_driver_name(dip), ddi_get_instance(dip));
}
}
@@ -503,7 +513,7 @@ scsi_hba_attach_setup(
if (ddi_prop_update_int(DDI_MAJOR_T_UNKNOWN, dip,
prop_name, value) != DDI_PROP_SUCCESS) {
cmn_err(CE_CONT, errmsg, prop_name,
- ddi_get_name(dip), ddi_get_instance(dip));
+ ddi_driver_name(dip), ddi_get_instance(dip));
}
}
@@ -515,7 +525,7 @@ scsi_hba_attach_setup(
if (ddi_prop_update_int(DDI_MAJOR_T_UNKNOWN, dip,
prop_name, value) != DDI_PROP_SUCCESS) {
cmn_err(CE_CONT, errmsg, prop_name,
- ddi_get_name(dip), ddi_get_instance(dip));
+ ddi_driver_name(dip), ddi_get_instance(dip));
}
}
if ((hba_tran->tran_hba_flags & SCSI_HBA_TRAN_ALLOC) &&
@@ -531,7 +541,8 @@ scsi_hba_attach_setup(
prop_name, (char *)prop_value)
!= DDI_PROP_SUCCESS) {
cmn_err(CE_CONT, errmsg, prop_name,
- ddi_get_name(dip), ddi_get_instance(dip));
+ ddi_driver_name(dip),
+ ddi_get_instance(dip));
}
}
}
@@ -565,10 +576,56 @@ scsi_hba_attach_setup(
}
}
+ /*
+ * NOTE: SCSA maintains an 'fm-capable' domain, in tran_fm_capable,
+ * that is not dependent (limited by) the capabilities of its parents.
+ * For example a dip in a branch that is not DDI_FM_EREPORT_CAPABLE
+ * may report as capable, via tran_fm_capable, to its scsi_device
+ * children.
+ *
+ * Get 'fm-capable' property from driver.conf, if present. If not
+ * present, default to the scsi_fm_capable global (which has
+ * DDI_FM_EREPORT_CAPABLE set by default).
+ */
+ if (hba_tran->tran_fm_capable == DDI_FM_NOT_CAPABLE)
+ hba_tran->tran_fm_capable = ddi_getprop(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP | DDI_PROP_NOTPROM,
+ "fm-capable", scsi_fm_capable);
+
+ /*
+ * If an HBA is *not* doing its own fma support by calling
+ * ddi_fm_init() prior to scsi_hba_attach_setup(), we provide a
+ * minimal common SCSA implementation so that scsi_device children
+ * can generate ereports via scsi_fm_ereport_post(). We use
+ * ddi_fm_capable() to detect an HBA calling ddi_fm_init() prior to
+ * scsi_hba_attach_setup().
+ */
+ if (hba_tran->tran_fm_capable &&
+ (ddi_fm_capable(dip) == DDI_FM_NOT_CAPABLE)) {
+ /*
+ * We are capable of something, pass our capabilities up
+ * the tree, but use a local variable so our parent can't
+ * limit our capabilities (we don't want our parent to
+ * clear DDI_FM_EREPORT_CAPABLE).
+ *
+ * NOTE: iblock cookies are not important because scsi
+ * HBAs always interrupt below LOCK_LEVEL.
+ */
+ capable = hba_tran->tran_fm_capable;
+ ddi_fm_init(dip, &capable, NULL);
+
+ /*
+ * Set SCSI_HBA_TRAN_FMSCSA bit to mark us as usiung the
+ * common minimal SCSA fm implementation - we called
+ * ddi_fm_init(), so we are responsible for calling
+ * ddi_fm_fini() in scsi_hba_detach().
+ */
+ hba_tran->tran_hba_flags |= SCSI_HBA_TRAN_FMSCSA;
+ }
+
return (DDI_SUCCESS);
}
-
/*
* Called by an HBA to detach an instance of the driver
*/
@@ -585,6 +642,14 @@ scsi_hba_detach(dev_info_t *dip)
ASSERT(hba != NULL);
ASSERT(hba->tran_open_flag == 0);
+ /*
+ * If we are taking care of mininal default fma implementation,
+ * call ddi_fm_fini(9F).
+ */
+ if (hba->tran_hba_flags & SCSI_HBA_TRAN_FMSCSA) {
+ ddi_fm_fini(dip);
+ }
+
hba_dev_ops = ddi_get_driver(dip);
ASSERT(hba_dev_ops != NULL);
if (hba_dev_ops->devo_cb_ops->cb_open == scsi_hba_open) {
@@ -680,8 +745,8 @@ smp_ctlops_reportdev(dev_info_t *dip, dev_info_t *rdip)
ASSERT(hba != NULL);
if (ddi_prop_lookup_string(DDI_DEV_T_ANY, rdip,
- DDI_PROP_DONTPASS, SMP_WWN, &smp_wwn)
- != DDI_SUCCESS) {
+ DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP | DDI_PROP_NOTPROM,
+ SMP_WWN, &smp_wwn) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
cmn_err(CE_CONT,
@@ -729,8 +794,8 @@ smp_ctlops_initchild(dev_info_t *dip, dev_info_t *rdip)
smp->smp_addr.a_hba_tran = hba;
if (ddi_prop_lookup_string(DDI_DEV_T_ANY, rdip,
- DDI_PROP_DONTPASS, SMP_WWN, &smp_wwn)
- != DDI_SUCCESS) {
+ DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP | DDI_PROP_NOTPROM,
+ SMP_WWN, &smp_wwn) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
@@ -816,7 +881,8 @@ scsi_hba_bus_ctl(
hba = ddi_get_driver_private(dip);
ASSERT(hba != NULL);
- if (ddi_prop_exists(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
+ if (ddi_prop_exists(DDI_DEV_T_ANY, rdip,
+ DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP | DDI_PROP_NOTPROM,
SMP_PROP)) {
return (smp_ctlops_reportdev(dip, rdip));
}
@@ -883,7 +949,8 @@ scsi_hba_bus_ctl(
scsi_hba_tran_t *hba;
dev_info_t *ndip;
- if (ddi_prop_exists(DDI_DEV_T_ANY, child_dip, DDI_PROP_DONTPASS,
+ if (ddi_prop_exists(DDI_DEV_T_ANY, child_dip,
+ DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP | DDI_PROP_NOTPROM,
SMP_PROP)) {
return (smp_ctlops_initchild(dip, child_dip));
}
@@ -931,7 +998,8 @@ scsi_hba_bus_ctl(
cmn_err(CE_CONT,
"%s%d: should support both or none of "
"tran_get_name and tran_get_bus_addr\n",
- ddi_get_name(dip), ddi_get_instance(dip));
+ ddi_driver_name(dip),
+ ddi_get_instance(dip));
goto failure;
}
}
@@ -1059,7 +1127,8 @@ failure:
dev_info_t *child_dip = (dev_info_t *)arg;
scsi_hba_tran_t *hba;
- if (ddi_prop_exists(DDI_DEV_T_ANY, child_dip, DDI_PROP_DONTPASS,
+ if (ddi_prop_exists(DDI_DEV_T_ANY, child_dip,
+ DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP | DDI_PROP_NOTPROM,
SMP_PROP)) {
return (smp_ctlops_uninitchild(dip, child_dip));
}
@@ -1122,8 +1191,8 @@ failure:
case DDI_CTLOPS_POKE:
case DDI_CTLOPS_PEEK:
cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
- ddi_get_name(dip), ddi_get_instance(dip),
- op, ddi_get_name(rdip), ddi_get_instance(rdip));
+ ddi_driver_name(dip), ddi_get_instance(dip),
+ op, ddi_driver_name(rdip), ddi_get_instance(rdip));
return (DDI_FAILURE);
/*
@@ -1194,13 +1263,12 @@ scsi_hba_tran_free(
kmem_free(hba_tran, sizeof (scsi_hba_tran_t));
}
-
-
/*
* Private wrapper for scsi_pkt's allocated via scsi_hba_pkt_alloc()
*/
struct scsi_pkt_wrapper {
struct scsi_pkt scsi_pkt;
+ int pkt_wrapper_magic;
int pkt_wrapper_len;
};
@@ -1227,6 +1295,7 @@ scsi_hba_pkt_alloc(
struct scsi_pkt *pkt;
struct scsi_pkt_wrapper *hba_pkt;
caddr_t p;
+ int acmdlen, astatuslen, atgtlen, ahbalen;
int pktlen;
/*
@@ -1240,12 +1309,12 @@ scsi_hba_pkt_alloc(
/*
* Round up so everything gets allocated on long-word boundaries
*/
- cmdlen = ROUNDUP(cmdlen);
- tgtlen = ROUNDUP(tgtlen);
- hbalen = ROUNDUP(hbalen);
- statuslen = ROUNDUP(statuslen);
- pktlen = sizeof (struct scsi_pkt_wrapper)
- + cmdlen + tgtlen + hbalen + statuslen;
+ acmdlen = ROUNDUP(cmdlen);
+ astatuslen = ROUNDUP(statuslen);
+ atgtlen = ROUNDUP(tgtlen);
+ ahbalen = ROUNDUP(hbalen);
+ pktlen = sizeof (struct scsi_pkt_wrapper) +
+ acmdlen + astatuslen + atgtlen + ahbalen;
hba_pkt = kmem_zalloc(pktlen,
(callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP);
@@ -1258,23 +1327,24 @@ scsi_hba_pkt_alloc(
* Set up our private info on this pkt
*/
hba_pkt->pkt_wrapper_len = pktlen;
+ hba_pkt->pkt_wrapper_magic = PKT_WRAPPER_MAGIC; /* alloced correctly */
pkt = &hba_pkt->scsi_pkt;
- p = (caddr_t)(hba_pkt + 1);
/*
* Set up pointers to private data areas, cdb, and status.
*/
+ p = (caddr_t)(hba_pkt + 1);
if (hbalen > 0) {
pkt->pkt_ha_private = (opaque_t)p;
- p += hbalen;
+ p += ahbalen;
}
if (tgtlen > 0) {
pkt->pkt_private = (opaque_t)p;
- p += tgtlen;
+ p += atgtlen;
}
if (statuslen > 0) {
pkt->pkt_scbp = (uchar_t *)p;
- p += statuslen;
+ p += astatuslen;
}
if (cmdlen > 0) {
pkt->pkt_cdbp = (uchar_t *)p;
@@ -1285,10 +1355,18 @@ scsi_hba_pkt_alloc(
*/
pkt->pkt_address = *ap;
+ /*
+ * NB: It may not be safe for drivers, esp target drivers, to depend
+ * on the following fields being set until all the scsi_pkt
+ * allocation violations discussed in scsi_pkt.h are all resolved.
+ */
+ pkt->pkt_cdblen = cmdlen;
+ pkt->pkt_tgtlen = tgtlen;
+ pkt->pkt_scblen = statuslen;
+
return (pkt);
}
-
/*
* Called by an HBA to free a scsi_pkt
*/
@@ -1301,6 +1379,146 @@ scsi_hba_pkt_free(
kmem_free(pkt, ((struct scsi_pkt_wrapper *)pkt)->pkt_wrapper_len);
}
+/*
+ * Return 1 if the scsi_pkt used a proper allocator.
+ *
+ * The DDI does not allow a driver to allocate it's own scsi_pkt(9S), a
+ * driver should not have *any* compiled in dependencies on "sizeof (struct
+ * scsi_pkt)". While this has been the case for many years, a number of
+ * drivers have still not been fixed. This function can be used to detect
+ * improperly allocated scsi_pkt structures, and produce messages identifying
+ * drivers that need to be fixed.
+ *
+ * While drivers in violation are being fixed, this function can also
+ * be used by the framework to detect packets that violated allocation
+ * rules.
+ *
+ * NB: It is possible, but very unlikely, for this code to return a false
+ * positive (finding correct magic, but for wrong reasons). Careful
+ * consideration is needed for callers using this interface to condition
+ * access to newer scsi_pkt fields (those after pkt_reason).
+ *
+ * NB: As an aid to minimizing the amount of work involved in 'fixing' legacy
+ * drivers that violate scsi_*(9S) allocation rules, private
+ * scsi_pkt_size()/scsi_size_clean() functions are available (see their
+ * implementation for details).
+ *
+ * *** Non-legacy use of scsi_pkt_size() is discouraged. ***
+ *
+ * NB: When supporting broken HBA drivers is not longer a concern, this
+ * code should be removed.
+ */
+int
+scsi_pkt_allocated_correctly(struct scsi_pkt *pkt)
+{
+ struct scsi_pkt_wrapper *hba_pkt = (struct scsi_pkt_wrapper *)pkt;
+ int magic;
+ major_t major;
+#ifdef DEBUG
+ int *pspwm, *pspcwm;
+
+ /*
+ * We are getting scsi packets from two 'correct' wrapper schemes,
+ * make sure we are looking at the same place in both to detect
+ * proper allocation.
+ */
+ pspwm = &((struct scsi_pkt_wrapper *)0)->pkt_wrapper_magic;
+ pspcwm = &((struct scsi_pkt_cache_wrapper *)0)->pcw_magic;
+ ASSERT(pspwm == pspcwm);
+#endif /* DEBUG */
+
+
+ /*
+ * Check to see if driver is scsi_size_clean(), assume it
+ * is using the scsi_pkt_size() interface everywhere it needs to
+ * if the driver indicates it is scsi_size_clean().
+ */
+ major = ddi_driver_major(P_TO_TRAN(pkt)->tran_hba_dip);
+ if (devnamesp[major].dn_flags & DN_SCSI_SIZE_CLEAN)
+ return (1); /* ok */
+
+ /*
+ * Special case crossing a page boundary. If the scsi_pkt was not
+ * allocated correctly, then accross a page boundary we have a
+ * fault hazzard.
+ */
+ if ((((uintptr_t)(&hba_pkt->scsi_pkt)) & MMU_PAGEMASK) ==
+ (((uintptr_t)(&hba_pkt->pkt_wrapper_magic)) & MMU_PAGEMASK)) {
+ /* fastpath, no cross-page hazzard */
+ magic = hba_pkt->pkt_wrapper_magic;
+ } else {
+ /* add protection for cross-page hazzard */
+ if (ddi_peek32((dev_info_t *)NULL,
+ &hba_pkt->pkt_wrapper_magic, &magic) == DDI_FAILURE) {
+ return (0); /* violation */
+ }
+ }
+
+ /* properly allocated packet always has correct magic */
+ return ((magic == PKT_WRAPPER_MAGIC) ? 1 : 0);
+}
+
+/*
+ * Private interfaces to simplify conversion of legacy drivers so they don't
+ * depend on scsi_*(9S) size. Instead of using these private interface, HBA
+ * drivers should use DDI sanctioned allocation methods:
+ *
+ * scsi_pkt Use scsi_hba_pkt_alloc(9F), or implement
+ * tran_setup_pkt(9E).
+ *
+ * scsi_device You are doing something strange/special, a scsi_device
+ * structure should only be allocated by scsi_hba.c
+ * initchild code or scsi_vhci.c code.
+ *
+ * scsi_hba_tran Use scsi_hba_tran_alloc(9F).
+ */
+size_t
+scsi_pkt_size()
+{
+ return (sizeof (struct scsi_pkt));
+}
+
+size_t
+scsi_hba_tran_size()
+{
+ return (sizeof (scsi_hba_tran_t));
+}
+
+size_t
+scsi_device_size()
+{
+ return (sizeof (struct scsi_device));
+}
+
+/*
+ * Legacy compliance to scsi_pkt(9S) allocation rules through use of
+ * scsi_pkt_size() is detected by the 'scsi-size-clean' driver.conf property
+ * or an HBA driver calling to scsi_size_clean() from attach(9E). A driver
+ * developer should only indicate that a legacy driver is clean after using
+ * SCSI_SIZE_CLEAN_VERIFY to ensure compliance (see scsi_pkt.h).
+ */
+void
+scsi_size_clean(dev_info_t *dip)
+{
+ major_t major;
+ struct devnames *dnp;
+
+ ASSERT(dip);
+ major = ddi_driver_major(dip);
+ ASSERT(major < devcnt);
+ if (major >= devcnt) {
+ cmn_err(CE_WARN, "scsi_pkt_size: bogus major: %d", major);
+ return;
+ }
+
+ /* Set DN_SCSI_SIZE_CLEAN flag in dn_flags. */
+ dnp = &devnamesp[major];
+ if ((dnp->dn_flags & DN_SCSI_SIZE_CLEAN) == 0) {
+ LOCK_DEV_OPS(&dnp->dn_lock);
+ dnp->dn_flags |= DN_SCSI_SIZE_CLEAN;
+ UNLOCK_DEV_OPS(&dnp->dn_lock);
+ }
+}
/*
@@ -2448,6 +2666,16 @@ scsi_hba_nodename_compatible_free(char *nodename, char **compatible)
(NCOMPAT * COMPAT_LONGEST));
}
+/*ARGSUSED*/
+static int
+scsi_hba_fm_init_child(dev_info_t *self, dev_info_t *child, int cap,
+ ddi_iblock_cookie_t *ibc)
+{
+ scsi_hba_tran_t *hba = ddi_get_driver_private(self);
+
+ return (hba ? hba->tran_fm_capable : scsi_fm_capable);
+}
+
static int
scsi_hba_bus_power(dev_info_t *parent, void *impl_arg, pm_bus_power_op_t op,
void *arg, void *result)
diff --git a/usr/src/uts/common/io/scsi/impl/scsi_resource.c b/usr/src/uts/common/io/scsi/impl/scsi_resource.c
index b7e49e8295..15397d539c 100644
--- a/usr/src/uts/common/io/scsi/impl/scsi_resource.c
+++ b/usr/src/uts/common/io/scsi/impl/scsi_resource.c
@@ -309,6 +309,7 @@ scsi_init_cache_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp,
in_pktp->pkt_dma_offset = 0;
in_pktp->pkt_dma_len = 0;
in_pktp->pkt_dma_flags = 0;
+ in_pktp->pkt_path_instance = 0;
ASSERT(in_pktp->pkt_numcookies == 0);
pktw->pcw_curwin = 0;
pktw->pcw_totalwin = 0;
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 8cf17cc898..145e431b9d 100644
--- a/usr/src/uts/common/io/scsi/impl/scsi_subr.c
+++ b/usr/src/uts/common/io/scsi/impl/scsi_subr.c
@@ -1968,22 +1968,23 @@ scsi_uscsi_mincnt(struct buf *bp)
}
/*
- * Function: scsi_uscsi_alloc_and_copyin
+ * Function: scsi_uscsi_alloc_and_copyin
*
* Description: Target drivers call this function to allocate memeory,
- * copy in, and convert ILP32/LP64 to make preparations for handling
- * uscsi commands.
+ * copy in, and convert ILP32/LP64 to make preparations for handling
+ * uscsi commands.
*
- * Arguments: arg - pointer to the caller's uscsi command struct
- * flag - mode, corresponds to ioctl(9e) 'mode'
- * ap - SCSI address structure
- * uscmdp - pointer to the converted uscsi command
+ * Arguments:
+ * arg - pointer to the caller's uscsi command struct
+ * flag - mode, corresponds to ioctl(9e) 'mode'
+ * ap - SCSI address structure
+ * uscmdp - pointer to the converted uscsi command
*
* Return code: 0
- * EFAULT
- * EINVAL
+ * EFAULT
+ * EINVAL
*
- * Context: Never called at interrupt context.
+ * Context: Never called at interrupt context.
*/
int
@@ -2000,8 +2001,9 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
#endif /* _MULTI_DATAMODEL */
struct uscsi_i_cmd *uicmd;
struct uscsi_cmd *uscmd;
- int max_hba_cdb;
- int rval;
+ int max_hba_cdb;
+ int rval;
+ extern dev_info_t *scsi_vhci_dip;
/*
* In order to not worry about where the uscsi structure came
@@ -2063,6 +2065,16 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
}
/*
+ * Currently, USCSI_PATH_INSTANCE is only valid when directed
+ * to scsi_vhci.
+ */
+ if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) &&
+ (A_TO_TRAN(ap)->tran_hba_dip != scsi_vhci_dip)) {
+ rval = EFAULT;
+ goto done;
+ }
+
+ /*
* Perfunctory sanity checks. Get the maximum hba supported
* cdb length first.
*/
@@ -2082,6 +2094,15 @@ scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
}
/*
+ * To extend uscsi_cmd in the future, we need to ensure current
+ * reserved bits remain unused (zero).
+ */
+ if (uscmd->uscsi_flags & USCSI_RESERVED) {
+ rval = EINVAL;
+ goto done;
+ }
+
+ /*
* Now we get some space for the CDB, and copy the given CDB into
* it. Use ddi_copyin() in case the data is in user space.
*/
@@ -2141,26 +2162,27 @@ done:
}
/*
- * Function: scsi_uscsi_handle_cmd
+ * Function: scsi_uscsi_handle_cmd
*
* Description: Target drivers call this function to handle uscsi commands.
*
- * Arguments: dev - device number
- * dataspace - UIO_USERSPACE or UIO_SYSSPACE
- * uscmd - pointer to the converted uscsi command
- * strat - pointer to the driver's strategy routine
- * bp - buf struct ptr
- * private_data - pointer to bp->b_private
+ * Arguments:
+ * dev - device number
+ * dataspace - UIO_USERSPACE or UIO_SYSSPACE
+ * uscmd - pointer to the converted uscsi command
+ * strat - pointer to the driver's strategy routine
+ * bp - buf struct ptr
+ * private_data - pointer to bp->b_private
*
* Return code: 0
- * EIO - scsi_reset() failed, or see biowait()/physio() codes.
+ * EIO - scsi_reset() failed, or see biowait()/physio() codes.
* EINVAL
* return code of biowait(9F) or physio(9F):
- * EIO - IO error
+ * EIO - IO error
* ENXIO
- * EACCES - reservation conflict
+ * EACCES - reservation conflict
*
- * Context: Never called at interrupt context.
+ * Context: Never called at interrupt context.
*/
int
@@ -2272,6 +2294,82 @@ scsi_uscsi_handle_cmd(dev_t dev, enum uio_seg dataspace,
}
/*
+ * Function: scsi_uscsi_pktinit
+ *
+ * Description: Target drivers call this function to transfer uscsi_cmd
+ * information into a scsi_pkt before sending the scsi_pkt.
+ *
+ * NB: At this point the implementation is limited to path_instance.
+ * At some point more code could be removed from the target driver by
+ * enhancing this function - with the added benifit of making the uscsi
+ * implementation more consistent accross all drivers.
+ *
+ * Arguments:
+ * uscmd - pointer to the uscsi command
+ * pkt - pointer to the scsi_pkt
+ *
+ * Return code: 1 on successfull transfer, 0 on failure.
+ */
+int
+scsi_uscsi_pktinit(struct uscsi_cmd *uscmd, struct scsi_pkt *pkt)
+{
+ int path_instance;
+
+ /* get path_instance from uscsi_cmd */
+ path_instance = (uscmd->uscsi_flags & USCSI_PATH_INSTANCE) ?
+ uscmd->uscsi_path_instance : 0;
+
+ /*
+ * Check to make sure the scsi_pkt was allocated correctly before
+ * transferring uscsi(7i) path_instance to scsi_pkt(9S).
+ */
+ if (!scsi_pkt_allocated_correctly(pkt)) {
+ /* If path_instance is zero, pretend success */
+ if (path_instance == 0)
+ return (1); /* pretend success */
+
+ return (0); /* failure */
+ }
+
+ pkt->pkt_path_instance = path_instance;
+ return (1); /* success */
+}
+
+/*
+ * Function: scsi_uscsi_pktfini
+ *
+ * Description: Target drivers call this function to transfer completed
+ * scsi_pkt information back into uscsi_cmd.
+ *
+ * NB: At this point the implementation is limited to path_instance.
+ * At some point more code could be removed from the target driver by
+ * enhancing this function - with the added benifit of making the uscsi
+ * implementation more consistent accross all drivers.
+ *
+ * Arguments:
+ * pkt - pointer to the scsi_pkt
+ * uscmd - pointer to the uscsi command
+ *
+ * Return code: 1 on successfull transfer, 0 on failure.
+ */
+int
+scsi_uscsi_pktfini(struct scsi_pkt *pkt, struct uscsi_cmd *uscmd)
+{
+ /*
+ * Check to make sure the scsi_pkt was allocated correctly before
+ * transferring scsi_pkt(9S) path_instance to uscsi(7i).
+ */
+ if (!scsi_pkt_allocated_correctly(pkt)) {
+ uscmd->uscsi_path_instance = 0;
+ return (0); /* failure */
+ }
+
+ uscmd->uscsi_path_instance = pkt->pkt_path_instance;
+ pkt->pkt_path_instance = 0;
+ return (1); /* success */
+}
+
+/*
* Function: scsi_uscsi_copyout_and_free
*
* Description: Target drivers call this function to undo what was done by
@@ -2285,7 +2383,6 @@ scsi_uscsi_handle_cmd(dev_t dev, enum uio_seg dataspace,
*
* Context: Never called at interrupt context.
*/
-
int
scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd)
{
diff --git a/usr/src/uts/common/io/scsi/impl/scsi_transport.c b/usr/src/uts/common/io/scsi/impl/scsi_transport.c
index eec642408f..0ba3f94fb9 100644
--- a/usr/src/uts/common/io/scsi/impl/scsi_transport.c
+++ b/usr/src/uts/common/io/scsi/impl/scsi_transport.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,6 +30,7 @@
*/
#include <sys/scsi/scsi.h>
#include <sys/thread.h>
+#include <sys/bitmap.h>
#define A_TO_TRAN(ap) ((ap)->a_hba_tran)
#define P_TO_TRAN(pkt) ((pkt)->pkt_address.a_hba_tran)
@@ -44,9 +45,13 @@ int scsi_poll_user;
int scsi_poll_intr;
#endif
+int scsi_pkt_bad_alloc_msg = 1;
+extern ulong_t *scsi_pkt_bad_alloc_bitmap;
extern kmutex_t scsi_flag_nointr_mutex;
extern kcondvar_t scsi_flag_nointr_cv;
+extern int do_polled_io;
+
/*
* we used to set the callback_done value to NULL after the callback
* but this interfered with esp/fas drivers that also set the callback
@@ -75,7 +80,7 @@ static void
scsi_consistent_comp(struct scsi_pkt *pkt)
{
struct scsi_pkt_cache_wrapper *pcw =
- (struct scsi_pkt_cache_wrapper *)pkt;
+ (struct scsi_pkt_cache_wrapper *)pkt;
pkt->pkt_comp = pcw->pcw_orig_comp;
scsi_sync_pkt(pkt);
@@ -96,18 +101,54 @@ int
scsi_transport(struct scsi_pkt *pkt)
{
struct scsi_address *ap = P_TO_ADDR(pkt);
- extern int do_polled_io;
- int rval = TRAN_ACCEPT;
+ int rval = TRAN_ACCEPT;
+ major_t major;
+
+ /*
+ * The DDI does not allow drivers to allocate their own scsi_pkt(9S),
+ * a driver can't have *any* compiled in dependencies on the
+ * "sizeof (struct scsi_pkt)". While this has been the case for years,
+ * many drivers have still not been fixed (or have regressed - tempted
+ * by kmem_cache_alloc()). The correct way to allocate a scsi_pkt
+ * is by calling scsi_hba_pkt_alloc(9F), or by implementing the
+ * tran_setup_pkt(9E) interfaces.
+ *
+ * The code below will identify drivers that violate this rule, and
+ * print a message. The message will identify broken drivers, and
+ * encourage getting these drivers fixed - after which this code
+ * can be removed. Getting HBA drivers fixed is important because
+ * broken drivers are an impediment to SCSA enhancement.
+ *
+ * We use the scsi_pkt_allocated_correctly() to determine if the
+ * scsi_pkt we are about to start was correctly allocated. The
+ * scsi_pkt_bad_alloc_bitmap is used to limit messages to one per
+ * driver per reboot, and with non-debug code we only check the
+ * first scsi_pkt.
+ */
+ if (scsi_pkt_bad_alloc_msg) {
+ major = ddi_driver_major(P_TO_TRAN(pkt)->tran_hba_dip);
+ if (!BT_TEST(scsi_pkt_bad_alloc_bitmap, major) &&
+ !scsi_pkt_allocated_correctly(pkt)) {
+ BT_SET(scsi_pkt_bad_alloc_bitmap, major);
+ cmn_err(CE_WARN, "%s: violates DDI scsi_pkt(9S) "
+ "allocation rules",
+ ddi_driver_name(P_TO_TRAN(pkt)->tran_hba_dip));
+ }
+#ifndef DEBUG
+ /* On non-debug kernel, only check the first packet */
+ BT_SET(scsi_pkt_bad_alloc_bitmap, major);
+#endif /* DEBUG */
+ }
/* determine if we need to sync the data on the HBA's behalf */
if ((pkt->pkt_dma_flags & DDI_DMA_CONSISTENT) &&
((pkt->pkt_comp) != NULL) &&
((P_TO_TRAN(pkt)->tran_setup_pkt) != NULL)) {
struct scsi_pkt_cache_wrapper *pcw =
- (struct scsi_pkt_cache_wrapper *)pkt;
+ (struct scsi_pkt_cache_wrapper *)pkt;
_NOTE(SCHEME_PROTECTS_DATA("unique per pkt", \
- scsi_pkt_cache_wrapper::pcw_orig_comp));
+ scsi_pkt_cache_wrapper::pcw_orig_comp));
pcw->pcw_orig_comp = pkt->pkt_comp;
pkt->pkt_comp = scsi_consistent_comp;
@@ -192,11 +233,11 @@ scsi_transport(struct scsi_pkt *pkt)
pkt->pkt_flags |= FLAG_IMMEDIATE_CB;
if ((status = (*A_TO_TRAN(ap)->tran_start)(ap, pkt)) ==
- TRAN_ACCEPT) {
+ TRAN_ACCEPT) {
mutex_enter(&scsi_flag_nointr_mutex);
while (pkt->pkt_comp != CALLBACK_DONE) {
cv_wait(&scsi_flag_nointr_cv,
- &scsi_flag_nointr_mutex);
+ &scsi_flag_nointr_mutex);
}
mutex_exit(&scsi_flag_nointr_mutex);
}
diff --git a/usr/src/uts/common/io/scsi/targets/sd.c b/usr/src/uts/common/io/scsi/targets/sd.c
index 976494be61..3b62d3f24b 100644
--- a/usr/src/uts/common/io/scsi/targets/sd.c
+++ b/usr/src/uts/common/io/scsi/targets/sd.c
@@ -12369,6 +12369,9 @@ sd_initpkt_for_uscsi(struct buf *bp, struct scsi_pkt **pktpp)
pktp->pkt_flags = flags;
+ /* Transfer uscsi information to scsi_pkt */
+ (void) scsi_uscsi_pktinit(uscmd, pktp);
+
/* Copy the caller's CDB into the pkt... */
bcopy(uscmd->uscsi_cdb, pktp->pkt_cdbp, uscmd->uscsi_cdblen);
@@ -12432,6 +12435,9 @@ sd_destroypkt_for_uscsi(struct buf *bp)
uscmd->uscsi_status = ((*(pktp)->pkt_scbp) & STATUS_MASK);
uscmd->uscsi_resid = bp->b_resid;
+ /* Transfer scsi_pkt information to uscsi */
+ (void) scsi_uscsi_pktfini(pktp, uscmd);
+
/*
* If enabled, copy any saved sense data into the area specified
* by the uscsi command.
diff --git a/usr/src/uts/common/io/scsi/targets/sgen.c b/usr/src/uts/common/io/scsi/targets/sgen.c
index e4d9640aa3..3003e5412c 100644
--- a/usr/src/uts/common/io/scsi/targets/sgen.c
+++ b/usr/src/uts/common/io/scsi/targets/sgen.c
@@ -142,7 +142,7 @@ static int sgen_handle_autosense(sgen_state_t *, struct scsi_pkt *);
static int sgen_handle_sense(sgen_state_t *);
static int sgen_handle_incomplete(sgen_state_t *, struct scsi_pkt *);
static int sgen_check_error(sgen_state_t *, struct buf *);
-static int sgen_initiate_sense(sgen_state_t *);
+static int sgen_initiate_sense(sgen_state_t *, int);
static int sgen_scsi_transport(struct scsi_pkt *);
static int sgen_tur(dev_t);
@@ -1506,6 +1506,9 @@ sgen_make_uscsi_cmd(sgen_state_t *sg_state, struct buf *bp)
pkt->pkt_flags |= FLAG_RENEGOTIATE_WIDE_SYNC;
}
+ /* Transfer uscsi information to scsi_pkt */
+ (void) scsi_uscsi_pktinit(ucmd, pkt);
+
sgen_log(sg_state, SGEN_DIAG2, "done sgen_make_uscsi_cmd()");
return (0);
}
@@ -1560,6 +1563,7 @@ static void
sgen_callback(struct scsi_pkt *pkt)
{
sgen_state_t *sg_state;
+ struct uscsi_cmd *ucmd;
struct buf *bp;
int action;
@@ -1580,10 +1584,14 @@ sgen_callback(struct scsi_pkt *pkt)
sgen_log(sg_state, SGEN_DIAG2,
"in sgen_callback() (command completion callback)");
}
+ ucmd = (struct uscsi_cmd *)bp->b_private;
sgen_log(sg_state, SGEN_DIAG3, "sgen_callback: reason=0x%x resid=%ld "
"state=0x%x", pkt->pkt_reason, pkt->pkt_resid, pkt->pkt_state);
+ /* Transfer scsi_pkt information to uscsi */
+ (void) scsi_uscsi_pktfini(pkt, ucmd);
+
if (pkt->pkt_reason != CMD_CMPLT) {
/*
* The command did not complete.
@@ -1628,7 +1636,9 @@ sgen_callback(struct scsi_pkt *pkt)
* If there is sense to fetch, break out to prevent biodone'ing
* until the sense fetch is complete.
*/
- if (sgen_initiate_sense(sg_state) == 0)
+ if (sgen_initiate_sense(sg_state,
+ scsi_pkt_allocated_correctly(pkt) ?
+ pkt->pkt_path_instance : 0) == 0)
break;
/*FALLTHROUGH*/
case COMMAND_DONE_ERROR:
@@ -1651,8 +1661,12 @@ sgen_callback(struct scsi_pkt *pkt)
* Send the sgen_rqspkt to the target, thereby requesting sense data.
*/
static int
-sgen_initiate_sense(sgen_state_t *sg_state)
+sgen_initiate_sense(sgen_state_t *sg_state, int path_instance)
{
+ /* use same path_instance as command */
+ if (scsi_pkt_allocated_correctly(sg_state->sgen_rqspkt))
+ sg_state->sgen_rqspkt->pkt_path_instance = path_instance;
+
switch (sgen_scsi_transport(sg_state->sgen_rqspkt)) {
case TRAN_ACCEPT:
sgen_log(sg_state, SGEN_DIAG3, "sgen_initiate_sense: "
diff --git a/usr/src/uts/common/io/scsi/targets/st.c b/usr/src/uts/common/io/scsi/targets/st.c
index c021413f69..65fc94f01f 100644
--- a/usr/src/uts/common/io/scsi/targets/st.c
+++ b/usr/src/uts/common/io/scsi/targets/st.c
@@ -16203,7 +16203,7 @@ st_command_recovery(struct scsi_tape *un, struct scsi_pkt *pkt,
/*
* Create structure to hold all error state info.
*/
- errinfo = kmem_zalloc(sizeof (st_err_info), KM_SLEEP);
+ errinfo = kmem_zalloc(ST_ERR_INFO_SIZE, KM_SLEEP);
errinfo->ei_error_type = onentry;
errinfo->ei_failing_bp = ri->cmd_bp;
COPY_POS(&errinfo->ei_expected_pos, &ri->pos);
@@ -16212,13 +16212,13 @@ st_command_recovery(struct scsi_tape *un, struct scsi_pkt *pkt,
return (COMMAND_DONE_ERROR);
}
- bcopy(pkt, &errinfo->ei_failed_pkt, sizeof (struct scsi_pkt));
+ bcopy(pkt, &errinfo->ei_failed_pkt, scsi_pkt_size());
bcopy(pkt->pkt_scbp, &errinfo->ei_failing_status, SECMDS_STATUS_SIZE);
ret = ddi_taskq_dispatch(un->un_recov_taskq, st_recover, errinfo,
DDI_NOSLEEP);
ASSERT(ret == DDI_SUCCESS);
if (ret != DDI_SUCCESS) {
- kmem_free(errinfo, sizeof (st_err_info));
+ kmem_free(errinfo, ST_ERR_INFO_SIZE);
return (COMMAND_DONE_ERROR);
}
return (JUST_RETURN); /* release calling thread */
@@ -16236,7 +16236,7 @@ st_recov_ret(struct scsi_tape *un, st_err_info *errinfo, errstate err)
ASSERT(MUTEX_HELD(&un->un_sd->sd_mutex));
bp = errinfo->ei_failing_bp;
- kmem_free(errinfo, sizeof (st_err_info));
+ kmem_free(errinfo, ST_ERR_INFO_SIZE);
switch (err) {
case JUST_RETURN:
diff --git a/usr/src/uts/common/os/ddifm.c b/usr/src/uts/common/os/ddifm.c
index a111620eae..20a8cf99cc 100644
--- a/usr/src/uts/common/os/ddifm.c
+++ b/usr/src/uts/common/os/ddifm.c
@@ -212,119 +212,6 @@ ddi_fm_service_impact(dev_info_t *dip, int svc_impact)
mutex_exit(&(DEVI(dip)->devi_lock));
}
-static int
-erpt_post_sleep(dev_info_t *dip, const char *error_class, uint64_t ena,
- uint8_t version, va_list ap)
-{
- char *devid, *name;
- char device_path[MAXPATHLEN];
- char ddi_error_class[ERPT_CLASS_SZ];
- nvlist_t *ereport, *detector = NULL;
-
- /*
- * Driver defect - should not call with DDI_SLEEP while
- * in interrupt context
- */
- if (servicing_interrupt()) {
- i_ddi_drv_ereport_post(dip, DVR_ECONTEXT, NULL, DDI_NOSLEEP);
- return (1);
- }
-
- if ((ereport = fm_nvlist_create(NULL)) == NULL)
- return (1);
-
- /*
- * Use the dev_path/devid for this device instance.
- */
- detector = fm_nvlist_create(NULL);
- if (dip == ddi_root_node()) {
- device_path[0] = '/';
- device_path[1] = '\0';
- } else {
- (void) ddi_pathname(dip, device_path);
- }
-
- if (ddi_prop_lookup_string(DDI_DEV_T_NONE, dip,
- DDI_PROP_DONTPASS, DEVID_PROP_NAME, &devid) == DDI_SUCCESS) {
- fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
- device_path, devid);
- ddi_prop_free(devid);
- } else {
- fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
- device_path, NULL);
- }
-
- if (ena == 0)
- ena = fm_ena_generate(0, FM_ENA_FMT1);
-
- (void) snprintf(ddi_error_class, ERPT_CLASS_SZ, "%s.%s",
- DDI_IO_CLASS, error_class);
-
- fm_ereport_set(ereport, version, ddi_error_class,
- ena, detector, NULL);
-
- name = va_arg(ap, char *);
- (void) i_fm_payload_set(ereport, name, ap);
-
- fm_ereport_post(ereport, EVCH_SLEEP);
- fm_nvlist_destroy(ereport, FM_NVA_FREE);
- fm_nvlist_destroy(detector, FM_NVA_FREE);
-
- return (0);
-}
-
-static int
-erpt_post_nosleep(dev_info_t *dip, struct i_ddi_fmhdl *fmhdl,
- const char *error_class, uint64_t ena, uint8_t version, va_list ap)
-{
- char *name;
- char device_path[MAXPATHLEN];
- char ddi_error_class[ERPT_CLASS_SZ];
- nvlist_t *ereport, *detector;
- nv_alloc_t *nva;
- errorq_elem_t *eqep;
-
- eqep = errorq_reserve(fmhdl->fh_errorq);
- if (eqep == NULL)
- return (1);
-
- ereport = errorq_elem_nvl(fmhdl->fh_errorq, eqep);
- nva = errorq_elem_nva(fmhdl->fh_errorq, eqep);
-
- ASSERT(ereport);
- ASSERT(nva);
-
- /*
- * Use the dev_path/devid for this device instance.
- */
- detector = fm_nvlist_create(nva);
- if (dip == ddi_root_node()) {
- device_path[0] = '/';
- device_path[1] = '\0';
- } else {
- (void) ddi_pathname(dip, device_path);
- }
-
- fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
- device_path, NULL);
-
- if (ena == 0)
- ena = fm_ena_generate(0, FM_ENA_FMT1);
-
- (void) snprintf(ddi_error_class, ERPT_CLASS_SZ, "%s.%s",
- DDI_IO_CLASS, error_class);
-
- fm_ereport_set(ereport, version, ddi_error_class,
- ena, detector, NULL);
-
- name = va_arg(ap, char *);
- (void) i_fm_payload_set(ereport, name, ap);
-
- errorq_commit(fmhdl->fh_errorq, eqep, ERRORQ_ASYNC);
-
- return (0);
-}
-
void
i_ddi_drv_ereport_post(dev_info_t *dip, const char *error_class,
nvlist_t *errp, int sflag)
@@ -404,54 +291,198 @@ i_ddi_drv_ereport_post(dev_info_t *dip, const char *error_class,
}
/*
- * Generate an error report for consumption by the Solaris Fault Manager,
- * fmd(1M). Valid ereport classes are defined in /usr/include/sys/fm/io. The
- * ENA should be set if this error is a result of an error status returned
- * from ddi_dma_err_check() or ddi_acc_err_check(). Otherwise, an ENA
- * value of 0 is appropriate.
- *
- * If sflag == DDI_NOSLEEP, ddi_fm_ereport_post () may be called
- * from user, kernel, interrupt or high-interrupt context. Otherwise,
- * ddi_fm_ereport_post() must be called from user or kernel context.
+ * fm_dev_ereport_postv: Common consolidation private interface to
+ * post a device tree oriented dev_scheme ereport. The device tree is
+ * composed of the following entities: devinfo nodes, minor nodes, and
+ * pathinfo nodes. All entities are associated with some devinfo node,
+ * either directly or indirectly. The intended devinfo node association
+ * for the ereport is communicated by the 'dip' argument. A minor node,
+ * an entity below 'dip', is represented by a non-null 'minor_name'
+ * argument. An application specific caller, like scsi_fm_ereport_post,
+ * can override the devinfo path with a pathinfo path via a non-null
+ * 'devpath' argument - in this case 'dip' is the MPXIO client node and
+ * devpath should be the path through the pHCI devinfo node to the
+ * pathinfo node.
+ *
+ * This interface also allows the caller to decide if the error being
+ * reported is know to be associated with a specific device identity
+ * via the 'devid' argument. The caller needs to control wether the
+ * devid appears as an authority in the FMRI because for some types of
+ * errors, like transport errors, the identity of the device on the
+ * other end of the transport is not guaranteed to be the current
+ * identity of the dip. For transport errors the caller should specify
+ * a NULL devid, even when there is a valid devid associated with the dip.
+ *
+ * The ddi_fm_ereport_post() implementation calls this interface with
+ * just a dip: devpath, minor_name, and devid are all NULL. The
+ * scsi_fm_ereport_post() implementation may call this interface with
+ * non-null devpath, minor_name, and devid arguments depending on
+ * wether MPXIO is enabled, and wether a transport or non-transport
+ * error is being posted.
*/
void
-ddi_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena,
- int sflag, ...)
+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)
{
- int ret;
- char *name;
- data_type_t type;
- uint8_t version;
- va_list ap;
- struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
+ struct i_ddi_fmhdl *fmhdl;
+ errorq_elem_t *eqep;
+ nv_alloc_t *nva;
+ nvlist_t *ereport = NULL;
+ nvlist_t *detector = NULL;
+ char *name;
+ data_type_t type;
+ uint8_t version;
+ char class[ERPT_CLASS_SZ];
+ char path[MAXPATHLEN];
+
+ ASSERT(dip && eqdip && error_class);
- if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)))
- return;
+ /*
+ * This interface should be called with a fm_capable eqdip. The
+ * ddi_fm_ereport_post* interfaces call with eqdip == dip,
+ * ndi_fm_ereport_post* interfaces call with eqdip == ddi_parent(dip).
+ */
+ if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(eqdip)))
+ goto err;
- ASSERT(fmhdl);
+ /* get ereport nvlist handle */
+ if ((sflag == DDI_SLEEP) && !panicstr) {
+ /*
+ * Driver defect - should not call with DDI_SLEEP while in
+ * interrupt context.
+ */
+ if (servicing_interrupt()) {
+ i_ddi_drv_ereport_post(dip, DVR_ECONTEXT, NULL, sflag);
+ goto err;
+ }
- va_start(ap, sflag);
+ /* Use normal interfaces to allocate memory. */
+ if ((ereport = fm_nvlist_create(NULL)) == NULL)
+ goto err;
+ nva = NULL;
+ } else {
+ /* Use errorq interfaces to avoid memory allocation. */
+ fmhdl = DEVI(eqdip)->devi_fmhdl;
+ ASSERT(fmhdl);
+ eqep = errorq_reserve(fmhdl->fh_errorq);
+ if (eqep == NULL)
+ goto err;
+
+ ereport = errorq_elem_nvl(fmhdl->fh_errorq, eqep);
+ nva = errorq_elem_nva(fmhdl->fh_errorq, eqep);
+ ASSERT(nva);
+ }
+ ASSERT(ereport);
- /* First payload tuple should be the version */
+ /*
+ * Form parts of an ereport:
+ * A: version
+ * B: error_class
+ * C: ena
+ * D: detector (path and optional devid authority)
+ * E: payload
+ *
+ * A: ereport version: first payload tuple must be the version.
+ */
name = va_arg(ap, char *);
type = va_arg(ap, data_type_t);
version = va_arg(ap, uint_t);
- if (strcmp(name, FM_VERSION) != 0 && type != DATA_TYPE_UINT8) {
- va_end(ap);
+ if ((strcmp(name, FM_VERSION) != 0) || (type != DATA_TYPE_UINT8)) {
i_ddi_drv_ereport_post(dip, DVR_EVER, NULL, sflag);
- return;
+ goto err;
+ }
+
+ /* B: ereport error_class: add "io." prefix to class. */
+ (void) snprintf(class, ERPT_CLASS_SZ, "%s.%s",
+ DDI_IO_CLASS, error_class);
+
+ /* C: ereport ena: if not passed in, generate new ena. */
+ if (ena == 0)
+ ena = fm_ena_generate(0, FM_ENA_FMT1);
+
+ /* D: detector: form dev scheme fmri with path and devid. */
+ if (devpath) {
+ (void) strlcpy(path, devpath, sizeof (path));
+ } else {
+ /* derive devpath from dip */
+ if (dip == ddi_root_node())
+ (void) strcpy(path, "/");
+ else
+ (void) ddi_pathname(dip, path);
+ }
+ if (minor_name) {
+ (void) strlcat(path, ":", sizeof (path));
+ (void) strlcat(path, minor_name, sizeof (path));
}
+ detector = fm_nvlist_create(nva);
+ fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, path, devid);
+
+ /* Pull parts of ereport together into ereport. */
+ fm_ereport_set(ereport, version, class, ena, detector, NULL);
+
+ /* Add the payload to ereport. */
+ name = va_arg(ap, char *);
+ (void) i_fm_payload_set(ereport, name, ap);
- if (sflag == DDI_SLEEP)
- ret = erpt_post_sleep(dip, error_class, ena, version, ap);
+ /* Post the ereport. */
+ if (nva)
+ errorq_commit(fmhdl->fh_errorq, eqep, ERRORQ_ASYNC);
else
- ret = erpt_post_nosleep(dip, fmhdl, error_class, ena, version,
- ap);
- va_end(ap);
+ fm_ereport_post(ereport, EVCH_SLEEP);
+ goto out;
- if (ret != 0)
+ /* Count errors as drops. */
+err: if (fmhdl)
atomic_add_64(&fmhdl->fh_kstat.fek_erpt_dropped.value.ui64, 1);
+out: if (ereport && (nva == NULL))
+ fm_nvlist_destroy(ereport, FM_NVA_FREE);
+ if (detector && (nva == NULL))
+ fm_nvlist_destroy(detector, FM_NVA_FREE);
+}
+
+/*
+ * Generate an error report for consumption by the Solaris Fault Manager,
+ * fmd(1M). Valid ereport classes are defined in /usr/include/sys/fm/io.
+ *
+ * The ENA should be set if this error is a result of an error status
+ * returned from ddi_dma_err_check() or ddi_acc_err_check(). Otherwise,
+ * an ENA value of 0 is appropriate.
+ *
+ * If sflag == DDI_NOSLEEP, ddi_fm_ereport_post () may be called
+ * from user, kernel, interrupt or high-interrupt context. Otherwise,
+ * ddi_fm_ereport_post() must be called from user or kernel context.
+ *
+ * The ndi_interfaces are provided for use by nexus drivers to post
+ * ereports about children who may not themselves be fm_capable.
+ *
+ * All interfaces end up in the common fm_dev_ereport_postv code above.
+ */
+void
+ddi_fm_ereport_post(dev_info_t *dip,
+ const char *error_class, uint64_t ena, int sflag, ...)
+{
+ va_list ap;
+
+ ASSERT(dip && error_class);
+ va_start(ap, sflag);
+ fm_dev_ereport_postv(dip, dip, NULL, NULL, NULL,
+ error_class, ena, sflag, ap);
+ va_end(ap);
+}
+
+void
+ndi_fm_ereport_post(dev_info_t *dip,
+ const char *error_class, uint64_t ena, int sflag, ...)
+{
+ va_list ap;
+
+ ASSERT(dip && error_class && (sflag == DDI_SLEEP));
+ va_start(ap, sflag);
+ fm_dev_ereport_postv(dip, ddi_get_parent(dip), NULL, NULL, NULL,
+ error_class, ena, sflag, ap);
+ va_end(ap);
}
/*
diff --git a/usr/src/uts/common/os/devcfg.c b/usr/src/uts/common/os/devcfg.c
index ff837895fb..80492cb39c 100644
--- a/usr/src/uts/common/os/devcfg.c
+++ b/usr/src/uts/common/os/devcfg.c
@@ -401,6 +401,9 @@ i_ddi_free_node(dev_info_t *dip)
if (devi->devi_hw_prop_ptr)
i_ddi_prop_list_delete(devi->devi_hw_prop_ptr);
+ if (DEVI(dip)->devi_devid_str)
+ ddi_devid_str_free(DEVI(dip)->devi_devid_str);
+
i_ddi_set_node_state(dip, DS_INVAL);
da_log_enter(dip);
if (devi->devi_audit) {
@@ -1211,8 +1214,7 @@ attach_node(dev_info_t *dip)
if (DEVI(dip)->devi_flags & DEVI_REGISTERED_DEVID) {
DEVI(dip)->devi_flags &= ~DEVI_REGISTERED_DEVID;
mutex_exit(&DEVI(dip)->devi_lock);
-
- e_devid_cache_unregister(dip);
+ ddi_devid_unregister(dip);
} else
mutex_exit(&DEVI(dip)->devi_lock);
@@ -1319,8 +1321,7 @@ detach_node(dev_info_t *dip, uint_t flag)
if (DEVI(dip)->devi_flags & DEVI_REGISTERED_DEVID) {
DEVI(dip)->devi_flags &= ~DEVI_REGISTERED_DEVID;
mutex_exit(&DEVI(dip)->devi_lock);
-
- e_devid_cache_unregister(dip);
+ ddi_devid_unregister(dip);
} else
mutex_exit(&DEVI(dip)->devi_lock);
diff --git a/usr/src/uts/common/os/modsubr.c b/usr/src/uts/common/os/modsubr.c
index 19954a6cf8..31d5501999 100644
--- a/usr/src/uts/common/os/modsubr.c
+++ b/usr/src/uts/common/os/modsubr.c
@@ -400,6 +400,9 @@ impl_make_parlist(major_t major)
if (i_ddi_prop_search(DDI_DEV_T_ANY, DDI_OPEN_RETURNS_EINTR,
DDI_PROP_TYPE_INT, &props))
dnp->dn_flags |= DN_OPEN_RETURNS_EINTR;
+ if (i_ddi_prop_search(DDI_DEV_T_ANY, "scsi-size-clean",
+ DDI_PROP_TYPE_INT, &props))
+ dnp->dn_flags |= DN_SCSI_SIZE_CLEAN;
}
if (i_ddi_prop_search(DDI_DEV_T_ANY, DDI_VHCI_CLASS,
diff --git a/usr/src/uts/common/os/sunddi.c b/usr/src/uts/common/os/sunddi.c
index e919e8b846..8619288779 100644
--- a/usr/src/uts/common/os/sunddi.c
+++ b/usr/src/uts/common/os/sunddi.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -7559,15 +7559,10 @@ i_ddi_devid_register(dev_info_t *dip, ddi_devid_t devid)
return (DDI_FAILURE);
}
- ddi_devid_str_free(devid_str);
-
-#ifdef DEVID_COMPATIBILITY
- /*
- * marker for devinfo snapshot compatibility.
- * This code gets deleted when di_devid is gone from libdevid
- */
- DEVI(dip)->devi_devid = DEVID_COMPATIBILITY;
-#endif /* DEVID_COMPATIBILITY */
+ /* keep pointer to devid string for interrupt context fma code */
+ if (DEVI(dip)->devi_devid_str)
+ ddi_devid_str_free(DEVI(dip)->devi_devid_str);
+ DEVI(dip)->devi_devid_str = devid_str;
return (DDI_SUCCESS);
}
@@ -7603,13 +7598,10 @@ ddi_devid_register(dev_info_t *dip, ddi_devid_t devid)
static void
i_ddi_devid_unregister(dev_info_t *dip)
{
-#ifdef DEVID_COMPATIBILITY
- /*
- * marker for micro release devinfo snapshot compatibility.
- * This code gets deleted for the minor release.
- */
- DEVI(dip)->devi_devid = NULL; /* unset DEVID_PROP */
-#endif /* DEVID_COMPATIBILITY */
+ if (DEVI(dip)->devi_devid_str) {
+ ddi_devid_str_free(DEVI(dip)->devi_devid_str);
+ DEVI(dip)->devi_devid_str = NULL;
+ }
/* remove the devid property */
(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, DEVID_PROP_NAME);
diff --git a/usr/src/uts/common/os/sunmdi.c b/usr/src/uts/common/os/sunmdi.c
index d83be4e8c5..91e00cf82e 100644
--- a/usr/src/uts/common/os/sunmdi.c
+++ b/usr/src/uts/common/os/sunmdi.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -157,6 +157,19 @@ static int mdi_bus_config_cache_hash_size = 256;
static int mdi_mtc_off = 0;
/*
+ * The "path" to a pathinfo node is identical to the /devices path to a
+ * devinfo node had the device been enumerated under a pHCI instead of
+ * a vHCI. This pathinfo "path" is associated with a 'path_instance'.
+ * This association persists across create/delete of the pathinfo nodes,
+ * but not across reboot.
+ */
+static uint_t mdi_pathmap_instance = 1; /* 0 -> any path */
+static int mdi_pathmap_hash_size = 256;
+static kmutex_t mdi_pathmap_mutex;
+static mod_hash_t *mdi_pathmap_bypath; /* "path"->instance */
+static mod_hash_t *mdi_pathmap_byinstance; /* instance->"path" */
+
+/*
* MDI component property name/value string definitions
*/
const char *mdi_component_prop = "mpxio-component";
@@ -306,13 +319,21 @@ i_mdi_init()
initialized = 1;
mutex_init(&mdi_mutex, NULL, MUTEX_DEFAULT, NULL);
- /*
- * Create our taskq resources
- */
+
+ /* Create our taskq resources */
mdi_taskq = taskq_create("mdi_taskq", mdi_taskq_n_threads,
MDI_TASKQ_PRI, MDI_TASKQ_MINALLOC, MDI_TASKQ_MAXALLOC,
TASKQ_PREPOPULATE | TASKQ_CPR_SAFE);
ASSERT(mdi_taskq != NULL); /* taskq_create never fails */
+
+ /* Allocate ['path_instance' <-> "path"] maps */
+ mutex_init(&mdi_pathmap_mutex, NULL, MUTEX_DRIVER, NULL);
+ mdi_pathmap_bypath = mod_hash_create_strhash(
+ "mdi_pathmap_bypath", mdi_pathmap_hash_size,
+ mod_hash_null_valdtor);
+ mdi_pathmap_byinstance = mod_hash_create_idhash(
+ "mdi_pathmap_byinstance", mdi_pathmap_hash_size,
+ mod_hash_null_valdtor);
}
/*
@@ -1915,11 +1936,15 @@ i_mdi_lba_lb(mdi_client_t *ct, mdi_pathinfo_t **ret_pip, struct buf *bp)
* through vHCI drivers configuration file (driver.conf).
*
* vHCI drivers may override this default behavior by specifying
- * appropriate flags. If start_pip is specified (non NULL) is
- * used as start point to walk and find the next appropriate path.
- * The following values are currently defined:
- * MDI_SELECT_ONLINE_PATH (to select an ONLINE path) and/or
- * MDI_SELECT_STANDBY_PATH (to select an STANDBY path).
+ * appropriate flags. The meaning of the thrid argument depends
+ * on the flags specified. If MDI_SELECT_PATH_INSTANCE is set
+ * then the argument is the "path instance" of the path to select.
+ * If MDI_SELECT_PATH_INSTANCE is not set then the argument is
+ * "start_pip". A non NULL "start_pip" is the starting point to
+ * walk and find the next appropriate path. The following values
+ * are currently defined: MDI_SELECT_ONLINE_PATH (to select an
+ * ONLINE path) and/or MDI_SELECT_STANDBY_PATH (to select an
+ * STANDBY path).
*
* The non-standard behavior is used by the scsi_vhci driver,
* whenever it has to use a STANDBY/FAULTED path. Eg. during
@@ -1945,7 +1970,7 @@ i_mdi_lba_lb(mdi_client_t *ct, mdi_pathinfo_t **ret_pip, struct buf *bp)
/*ARGSUSED*/
int
mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags,
- mdi_pathinfo_t *start_pip, mdi_pathinfo_t **ret_pip)
+ void *arg, mdi_pathinfo_t **ret_pip)
{
mdi_client_t *ct;
mdi_pathinfo_t *pip;
@@ -1957,6 +1982,18 @@ mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags,
int preferred = 1; /* preferred path */
int cond, cont = 1;
int retry = 0;
+ mdi_pathinfo_t *start_pip; /* request starting pathinfo */
+ int path_instance; /* request specific path instance */
+
+ /* determine type of arg based on flags */
+ if (flags & MDI_SELECT_PATH_INSTANCE) {
+ flags &= ~MDI_SELECT_PATH_INSTANCE;
+ path_instance = (int)(intptr_t)arg;
+ start_pip = NULL;
+ } else {
+ path_instance = 0;
+ start_pip = (mdi_pathinfo_t *)arg;
+ }
if (flags != 0) {
/*
@@ -2021,6 +2058,40 @@ mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags,
return (MDI_NOPATH);
}
+ /* Caller is specifying a specific pathinfo path by path_instance */
+ if (path_instance) {
+ /* search for pathinfo with correct path_instance */
+ for (pip = head;
+ pip && (mdi_pi_get_path_instance(pip) != path_instance);
+ pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link)
+ ;
+
+ /* If path can't be selected then MDI_FAILURE is returned. */
+ if (pip == NULL) {
+ MDI_CLIENT_UNLOCK(ct);
+ return (MDI_FAILURE);
+ }
+
+ /* verify state of path */
+ MDI_PI_LOCK(pip);
+ if (MDI_PI(pip)->pi_state != MDI_PATHINFO_STATE_ONLINE) {
+ MDI_PI_UNLOCK(pip);
+ MDI_CLIENT_UNLOCK(ct);
+ return (MDI_FAILURE);
+ }
+
+ /*
+ * Return the path in hold state. Caller should release the
+ * lock by calling mdi_rele_path()
+ */
+ MDI_PI_HOLD(pip);
+ MDI_PI_UNLOCK(pip);
+ ct->ct_path_last = pip;
+ *ret_pip = pip;
+ MDI_CLIENT_UNLOCK(ct);
+ return (MDI_SUCCESS);
+ }
+
/*
* for non default behavior, bypass current
* load balancing policy and always use LOAD_BALANCE_RR
@@ -2753,8 +2824,12 @@ i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct)
mdi_pathinfo_t *pip;
int ct_circular;
int ph_circular;
+ static char path[MAXPATHLEN];
+ char *path_persistent;
+ int path_instance;
int se_flag;
int kmem_flag;
+ mod_hash_val_t hv;
ASSERT(MDI_VHCI_CLIENT_LOCKED(ph->ph_vhci));
@@ -2778,6 +2853,36 @@ i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct)
MDI_PI(pip)->pi_phci = ph;
MDI_PI(pip)->pi_addr = kmem_alloc(strlen(paddr) + 1, KM_SLEEP);
(void) strcpy(MDI_PI(pip)->pi_addr, paddr);
+
+ /*
+ * We form the "path" to the pathinfo node, and see if we have
+ * already allocated a 'path_instance' for that "path". If so,
+ * we use the already allocated 'path_instance'. If not, we
+ * allocate a new 'path_instance' and associate it with a copy of
+ * the "path" string (which is never freed). The association
+ * between a 'path_instance' this "path" string persists until
+ * reboot.
+ */
+ mutex_enter(&mdi_pathmap_mutex);
+ (void) ddi_pathname(ph->ph_dip, path);
+ (void) sprintf(path + strlen(path), "/%s@%s",
+ ddi_node_name(ct->ct_dip), MDI_PI(pip)->pi_addr);
+ if (mod_hash_find(mdi_pathmap_bypath, (mod_hash_key_t)path, &hv) == 0) {
+ path_instance = (uint_t)(intptr_t)hv;
+ } else {
+ /* allocate a new 'path_instance' and persistent "path" */
+ path_instance = mdi_pathmap_instance++;
+ path_persistent = i_ddi_strdup(path, KM_SLEEP);
+ (void) mod_hash_insert(mdi_pathmap_bypath,
+ (mod_hash_key_t)path_persistent,
+ (mod_hash_val_t)(intptr_t)path_instance);
+ (void) mod_hash_insert(mdi_pathmap_byinstance,
+ (mod_hash_key_t)(intptr_t)path_instance,
+ (mod_hash_val_t)path_persistent);
+ }
+ mutex_exit(&mdi_pathmap_mutex);
+ MDI_PI(pip)->pi_path_instance = path_instance;
+
(void) nvlist_alloc(&MDI_PI(pip)->pi_prop, NV_UNIQUE_NAME, KM_SLEEP);
ASSERT(MDI_PI(pip)->pi_prop != NULL);
MDI_PI(pip)->pi_pprivate = NULL;
@@ -2817,6 +2922,28 @@ i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct)
}
/*
+ * mdi_pi_pathname_by_instance():
+ * Lookup of "path" by 'path_instance'. Return "path".
+ * NOTE: returned "path" remains valid forever (until reboot).
+ */
+char *
+mdi_pi_pathname_by_instance(int path_instance)
+{
+ char *path;
+ mod_hash_val_t hv;
+
+ /* mdi_pathmap lookup of "path" by 'path_instance' */
+ mutex_enter(&mdi_pathmap_mutex);
+ if (mod_hash_find(mdi_pathmap_byinstance,
+ (mod_hash_key_t)(intptr_t)path_instance, &hv) == 0)
+ path = (char *)hv;
+ else
+ path = NULL;
+ mutex_exit(&mdi_pathmap_mutex);
+ return (path);
+}
+
+/*
* i_mdi_phci_add_path():
* Add a mdi_pathinfo node to pHCI list.
* Notes:
@@ -3725,6 +3852,34 @@ mdi_pi_get_addr(mdi_pathinfo_t *pip)
}
/*
+ * mdi_pi_get_path_instance():
+ * Get the 'path_instance' of a mdi_pathinfo node
+ *
+ * Return Values:
+ * path_instance
+ */
+int
+mdi_pi_get_path_instance(mdi_pathinfo_t *pip)
+{
+ if (pip == NULL)
+ return (0);
+
+ return (MDI_PI(pip)->pi_path_instance);
+}
+
+/*
+ * mdi_pi_pathname():
+ * Return pointer to path to pathinfo node.
+ */
+char *
+mdi_pi_pathname(mdi_pathinfo_t *pip)
+{
+ if (pip == NULL)
+ return (NULL);
+ return (mdi_pi_pathname_by_instance(mdi_pi_get_path_instance(pip)));
+}
+
+/*
* mdi_pi_get_client():
* Get the client devinfo associated with a mdi_pathinfo node
*
diff --git a/usr/src/uts/common/sys/1394/targets/scsa1394/cmd.h b/usr/src/uts/common/sys/1394/targets/scsa1394/cmd.h
index b26c546f9f..f13059169e 100644
--- a/usr/src/uts/common/sys/1394/targets/scsa1394/cmd.h
+++ b/usr/src/uts/common/sys/1394/targets/scsa1394/cmd.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -111,8 +110,12 @@ typedef struct scsa1394_cmd {
size_t sc_total_blks; /* total xfer blocks */
size_t sc_resid_blks; /* blocks left */
- struct scsi_pkt sc_scsi_pkt; /* embedded SCSI packet */
+ struct scsi_pkt sc_scsi_pkt; /* must be last */
+ /* embedded SCSI packet */
+ /* ... scsi_pkt_size() */
} scsa1394_cmd_t;
+#define SCSA1394_CMD_SIZE (sizeof (struct scsa1394_cmd) - \
+ sizeof (struct scsi_pkt) + scsi_pkt_size())
_NOTE(SCHEME_PROTECTS_DATA("unique per task", { scsa1394_cmd scsa1394_cmd_seg
scsi_pkt scsi_inquiry scsi_extended_sense scsi_cdb scsi_arq_status }))
diff --git a/usr/src/uts/common/sys/autoconf.h b/usr/src/uts/common/sys/autoconf.h
index e7fbd33267..dcf45a48e0 100644
--- a/usr/src/uts/common/sys/autoconf.h
+++ b/usr/src/uts/common/sys/autoconf.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -86,6 +86,7 @@ struct devnames {
#define DN_GLDV3_DRIVER 0x1000 /* gldv3 (Nemo) driver */
#define DN_PHCI_DRIVER 0x2000 /* pHCI driver */
#define DN_OPEN_RETURNS_EINTR 0x4000 /* DDI_OPEN_RETURNS_EINTR prop */
+#define DN_SCSI_SIZE_CLEAN 0x8000 /* driver is scsi_size_clean() */
#ifdef _KERNEL
diff --git a/usr/src/uts/common/sys/ddi_impldefs.h b/usr/src/uts/common/sys/ddi_impldefs.h
index 2cc473236c..d1c31b318f 100644
--- a/usr/src/uts/common/sys/ddi_impldefs.h
+++ b/usr/src/uts/common/sys/ddi_impldefs.h
@@ -143,9 +143,8 @@ struct dev_info {
int (*devi_bus_dma_unbindfunc)(dev_info_t *, dev_info_t *,
ddi_dma_handle_t);
-#ifdef DEVID_COMPATIBILITY
- ddi_devid_t devi_devid; /* registered device id */
-#endif /* DEVID_COMPATIBILITY */
+ char *devi_devid_str; /* registered device id */
+
/*
* power management entries
* components exist even if the device is not currently power managed
@@ -210,6 +209,7 @@ struct dev_info {
char *devi_addr_buf; /* buffer for devi_addr */
char *devi_rebinding_name; /* binding_name of rebind */
+
/* For device contracts that have this dip's minor node as resource */
kmutex_t devi_ct_lock; /* contract lock */
kcondvar_t devi_ct_cv; /* contract cv */
diff --git a/usr/src/uts/common/sys/ddifm.h b/usr/src/uts/common/sys/ddifm.h
index 9fe6036d61..07fc00754f 100644
--- a/usr/src/uts/common/sys/ddifm.h
+++ b/usr/src/uts/common/sys/ddifm.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -33,6 +33,7 @@ extern "C" {
#endif
#include <sys/dditypes.h>
+#include <sys/va_list.h>
extern int ddi_system_fmcap;
@@ -89,10 +90,15 @@ typedef int (*ddi_err_func_t)(dev_info_t *, ddi_fm_error_t *, const void *);
* DDI for error handling and ereport generation
*/
-/* ereporting and service changes */
+/*
+ * ereport generation: [ddi|ndi]_fm_ereport_post
+ */
extern void ddi_fm_ereport_post(dev_info_t *, const char *, uint64_t, int, ...);
+extern void ndi_fm_ereport_post(dev_info_t *, const char *, uint64_t, int, ...);
/*
+ * service changes:
+ *
* After a hardened driver raises an ereport (or after pci_ereport_post() has
* raised an ereport for an event which implecated one of a driver's access or
* dma handles), the driver should always determine the service impact and
diff --git a/usr/src/uts/common/sys/devinfo_impl.h b/usr/src/uts/common/sys/devinfo_impl.h
index 1b78a5412c..5cc9705bad 100644
--- a/usr/src/uts/common/sys/devinfo_impl.h
+++ b/usr/src/uts/common/sys/devinfo_impl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -53,9 +53,9 @@ extern "C" {
#define DINFOSUBTREE (DIIOC | 0x01) /* include subtree */
#define DINFOMINOR (DIIOC | 0x02) /* include minor data */
#define DINFOPROP (DIIOC | 0x04) /* include properties */
+#define DINFOPATH (DIIOC | 0x08) /* include i/o pathing information */
/* private bits */
-#define DINFOPATH (DIIOC | 0x08) /* include i/o pathing information */
#define DINFOPRIVDATA (DIIOC | 0x10) /* include private data */
#define DINFOFORCE (DIIOC | 0x20) /* force load all drivers */
#define DINFOCACHE (DIIOC | 0x100000) /* use cached data */
@@ -322,7 +322,9 @@ struct di_path {
di_off_t path_prop; /* property list */
di_off_t path_addr; /* path addressing information */
di_path_state_t path_state; /* path state */
- uint_t path_snap_state; /* describes valid fields */
+ uint_t path_snap_state; /* describes valid fields */
+ int path_instance; /* path instance */
+ uint64_t user_private_data;
};
/*
diff --git a/usr/src/uts/common/sys/mdi_impldefs.h b/usr/src/uts/common/sys/mdi_impldefs.h
index 4838c1ca7b..4d913bb0c5 100644
--- a/usr/src/uts/common/sys/mdi_impldefs.h
+++ b/usr/src/uts/common/sys/mdi_impldefs.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -712,6 +712,7 @@ struct mdi_pathinfo {
/* protected by MDI_VHCI_CLIENT_LOCK vh_client_mutex... */
char *pi_addr; /* path unit address */
+ int pi_path_instance; /* path instance */
/* protected by MDI_PI_LOCK pi_mutex... */
kmutex_t pi_mutex; /* per path mutex */
@@ -1123,19 +1124,23 @@ dev_info_t *mdi_phci_path2devinfo(dev_info_t *, caddr_t);
* starting point; it starts walking from there to find the next appropriate
* path.
*
- * The following values for 'flags' are currently defined:
+ * The following values for 'flags' are currently defined, the third argument
+ * to mdi_select_path depends on the flags used.
*
- * MDI_SELECT_ONLINE_PATH: select an ONLINE path
- * MDI_SELECT_STANDBY_PATH: select a STANDBY path
- * MDI_SELECT_USER_DISABLE_PATH: select user disable for failover and
- * auto_failback
+ * <none>: default, arg is pip
+ * MDI_SELECT_ONLINE_PATH: select an ONLINE path, arg is pip
+ * MDI_SELECT_STANDBY_PATH: select a STANDBY path, arg is pip
+ * MDI_SELECT_USER_DISABLE_PATH: select user disable for failover and
+ * auto_failback
+ * MDI_SELECT_PATH_INSTANCE: select a specific path, arg is
+ * path instance
*
* The selected paths are returned in an mdi_hold_path() state (pi_ref_cnt),
* caller should release the hold by calling mdi_rele_path() at the end of
* operation.
*/
int mdi_select_path(dev_info_t *, struct buf *, int,
- mdi_pathinfo_t *, mdi_pathinfo_t **);
+ void *, mdi_pathinfo_t **);
int mdi_set_lb_policy(dev_info_t *, client_lb_t);
int mdi_set_lb_region_size(dev_info_t *, int);
client_lb_t mdi_get_lb_policy(dev_info_t *);
@@ -1146,6 +1151,7 @@ client_lb_t mdi_get_lb_policy(dev_info_t *);
#define MDI_SELECT_ONLINE_PATH 0x0001
#define MDI_SELECT_STANDBY_PATH 0x0002
#define MDI_SELECT_USER_DISABLE_PATH 0x0004
+#define MDI_SELECT_PATH_INSTANCE 0x0008
/*
* MDI client device utility functions
diff --git a/usr/src/uts/common/sys/nvpair.h b/usr/src/uts/common/sys/nvpair.h
index 0675d1365a..701b8370a2 100644
--- a/usr/src/uts/common/sys/nvpair.h
+++ b/usr/src/uts/common/sys/nvpair.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -220,15 +220,18 @@ int nvlist_lookup_string_array(nvlist_t *, const char *, char ***, uint_t *);
int nvlist_lookup_nvlist_array(nvlist_t *, const char *,
nvlist_t ***, uint_t *);
int nvlist_lookup_hrtime(nvlist_t *, const char *, hrtime_t *);
-int nvlist_lookup_pairs(nvlist_t *nvl, int, ...);
+int nvlist_lookup_pairs(nvlist_t *, int, ...);
-int nvlist_lookup_nvpair(nvlist_t *nvl, const char *, nvpair_t **);
-boolean_t nvlist_exists(nvlist_t *nvl, const char *);
+int nvlist_lookup_nvpair(nvlist_t *, const char *, nvpair_t **);
+int nvlist_lookup_nvpair_embedded_index(nvlist_t *, const char *, nvpair_t **,
+ int *, char **);
+boolean_t nvlist_exists(nvlist_t *, const char *);
/* processing nvpair */
-nvpair_t *nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *);
+nvpair_t *nvlist_next_nvpair(nvlist_t *, nvpair_t *);
char *nvpair_name(nvpair_t *);
data_type_t nvpair_type(nvpair_t *);
+int nvpair_type_is_array(nvpair_t *);
int nvpair_value_boolean_value(nvpair_t *, boolean_t *);
int nvpair_value_byte(nvpair_t *, uchar_t *);
int nvpair_value_int8(nvpair_t *, int8_t *);
diff --git a/usr/src/uts/common/sys/scsi/conf/autoconf.h b/usr/src/uts/common/sys/scsi/conf/autoconf.h
index 4d382e8445..757732cb09 100644
--- a/usr/src/uts/common/sys/scsi/conf/autoconf.h
+++ b/usr/src/uts/common/sys/scsi/conf/autoconf.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -167,6 +166,7 @@ extern int scsi_tag_age_limit;
extern int scsi_watchdog_tick;
extern int scsi_selection_timeout; /* specified in milli seconds */
extern int scsi_host_id;
+extern int scsi_fm_capable;
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/scsi/conf/device.h b/usr/src/uts/common/sys/scsi/conf/device.h
index 1f281b797c..9e68a0d675 100644
--- a/usr/src/uts/common/sys/scsi/conf/device.h
+++ b/usr/src/uts/common/sys/scsi/conf/device.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -99,6 +98,22 @@ struct scsi_device {
* attach(9E), and freed in the target driver detach(9E).
*/
caddr_t sd_private;
+
+
+ /*
+ * FMA capabilities of scsi_device.
+ */
+ int sd_fm_capable;
+
+#ifdef SCSI_SIZE_CLEAN_VERIFY
+ /*
+ * Must be last: Building a driver with-and-without
+ * -DSCSI_SIZE_CLEAN_VERIFY, and checking driver modules for
+ * differences with a tools like 'wsdiff' allows a developer to verify
+ * that their driver has no dependencies on scsi*(9S) size.
+ */
+ int _pad[8];
+#endif /* SCSI_SIZE_CLEAN_VERIFY */
};
#ifdef _KERNEL
@@ -106,6 +121,7 @@ int scsi_slave(struct scsi_device *devp, int (*callback)(void));
int scsi_probe(struct scsi_device *devp, int (*callback)(void));
void scsi_unslave(struct scsi_device *devp);
void scsi_unprobe(struct scsi_device *devp);
+size_t scsi_device_size(); /* private */
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/scsi/impl/transport.h b/usr/src/uts/common/sys/scsi/impl/transport.h
index fb1e2c89cd..23c74392a3 100644
--- a/usr/src/uts/common/sys/scsi/impl/transport.h
+++ b/usr/src/uts/common/sys/scsi/impl/transport.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -254,6 +254,8 @@ struct scsi_hba_tran {
* usr/src/uts/common/sys/scsi/impl/services.h
*/
int tran_interconnect_type;
+
+ /* tran_setup_pkt(9E) related scsi_pkt fields */
int (*tran_pkt_constructor)(
struct scsi_pkt *pkt,
scsi_hba_tran_t *tran,
@@ -262,7 +264,6 @@ struct scsi_hba_tran {
struct scsi_pkt *pkt,
scsi_hba_tran_t *tran);
kmem_cache_t *tran_pkt_cache_ptr;
-
uint_t tran_hba_len;
int (*tran_setup_pkt)(
struct scsi_pkt *pkt,
@@ -274,7 +275,24 @@ struct scsi_hba_tran {
ddi_dma_attr_t tran_dma_attr;
void *tran_extension;
+ /*
+ * An fm_capable HBA driver can set tran_fm_capable prior to
+ * scsi_hba_attach_setup(). If not set, SCSA provides a default
+ * implementation.
+ */
+ int tran_fm_capable;
+
+#ifdef SCSI_SIZE_CLEAN_VERIFY
+ /*
+ * Must be last: Building a driver with-and-without
+ * -DSCSI_SIZE_CLEAN_VERIFY, and checking driver modules for
+ * differences with a tools like 'wsdiff' allows a developer to verify
+ * that their driver has no dependencies on scsi*(9S) size.
+ */
+ int _pad[8];
+#endif /* SCSI_SIZE_CLEAN_VERIFY */
};
+size_t scsi_hba_tran_size(); /* private */
#ifdef __lock_lint
@@ -425,6 +443,7 @@ extern int scsi_hba_prop_update_inqstring(
/* is called */
#define SCSI_HBA_TRAN_CDB 0x04 /* allocate cdb */
#define SCSI_HBA_TRAN_SCB 0x08 /* allocate sense */
+#define SCSI_HBA_TRAN_FMSCSA 0x10 /* using common ddi_fm_* */
/*
* Flags for scsi_hba allocation functions
@@ -452,7 +471,6 @@ extern int scsi_hba_prop_update_inqstring(
#define INST2SCSI(x) (((x) << INST_MINOR_SHIFT) | SCSI_MINOR)
#define MINOR2INST(x) ((x) >> INST_MINOR_SHIFT)
-
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/sys/scsi/impl/uscsi.h b/usr/src/uts/common/sys/scsi/impl/uscsi.h
index cb70632204..80e424d6aa 100644
--- a/usr/src/uts/common/sys/scsi/impl/uscsi.h
+++ b/usr/src/uts/common/sys/scsi/impl/uscsi.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -52,7 +52,7 @@ struct uscsi_cmd {
uchar_t uscsi_rqstatus; /* status of request sense cmd */
uchar_t uscsi_rqresid; /* resid of request sense cmd */
caddr_t uscsi_rqbuf; /* request sense buffer */
- void *uscsi_reserved_5; /* Reserved for Future Use */
+ ulong_t uscsi_path_instance; /* private: hardware path */
};
#if defined(_SYSCALL32)
@@ -69,7 +69,7 @@ struct uscsi_cmd32 {
uchar_t uscsi_rqstatus; /* status of request sense cmd */
uchar_t uscsi_rqresid; /* resid of request sense cmd */
caddr32_t uscsi_rqbuf; /* request sense buffer */
- caddr32_t uscsi_reserved_5; /* Reserved for Future Use */
+ uint32_t uscsi_path_instance; /* private: hardware path */
};
#define uscsi_cmd32touscsi_cmd(u32, ucmd) \
@@ -85,7 +85,7 @@ struct uscsi_cmd32 {
ucmd->uscsi_rqstatus = u32->uscsi_rqstatus; \
ucmd->uscsi_rqresid = u32->uscsi_rqresid; \
ucmd->uscsi_rqbuf = (caddr_t)(uintptr_t)u32->uscsi_rqbuf; \
- ucmd->uscsi_reserved_5 = (void *)(uintptr_t)u32->uscsi_reserved_5;
+ ucmd->uscsi_path_instance = (ulong_t)u32->uscsi_path_instance;
#define uscsi_cmdtouscsi_cmd32(ucmd, u32) \
@@ -101,7 +101,7 @@ struct uscsi_cmd32 {
u32->uscsi_rqstatus = ucmd->uscsi_rqstatus; \
u32->uscsi_rqresid = ucmd->uscsi_rqresid; \
u32->uscsi_rqbuf = (caddr32_t)(uintptr_t)ucmd->uscsi_rqbuf; \
- u32->uscsi_reserved_5 = (caddr32_t)(uintptr_t)ucmd->uscsi_reserved_5;
+ u32->uscsi_path_instance = (uint32_t)ucmd->uscsi_path_instance;
#endif /* _SYSCALL32 */
@@ -112,23 +112,27 @@ struct uscsi_cmd32 {
/*
* generic flags
*/
-#define USCSI_WRITE 0x00000 /* send data to device */
-#define USCSI_SILENT 0x00001 /* no error messages */
-#define USCSI_DIAGNOSE 0x00002 /* fail if any error occurs */
-#define USCSI_ISOLATE 0x00004 /* isolate from normal commands */
-#define USCSI_READ 0x00008 /* get data from device */
-#define USCSI_RESET_LUN 0x40000 /* Reset logical unit */
-#define USCSI_RESET 0x04000 /* Reset target */
-#define USCSI_RESET_TARGET USCSI_RESET /* Reset target */
-#define USCSI_RESET_ALL 0x08000 /* Reset all targets */
-#define USCSI_RQENABLE 0x10000 /* Enable Request Sense extensions */
-#define USCSI_RENEGOT 0x20000 /* renegotiate wide/sync on next I/O */
+#define USCSI_SILENT 0x00000001 /* no error messages */
+#define USCSI_DIAGNOSE 0x00000002 /* fail if any error occurs */
+#define USCSI_ISOLATE 0x00000004 /* isolate from normal commands */
+#define USCSI_READ 0x00000008 /* get data from device */
+#define USCSI_WRITE 0x00000000 /* send data to device */
+
+#define USCSI_RESET 0x00004000 /* Reset target */
+#define USCSI_RESET_TARGET \
+ USCSI_RESET /* Reset target */
+#define USCSI_RESET_ALL 0x00008000 /* Reset all targets */
+#define USCSI_RQENABLE 0x00010000 /* Enable Request Sense extensions */
+#define USCSI_RENEGOT 0x00020000 /* renegotiate wide/sync on next I/O */
+#define USCSI_RESET_LUN 0x00040000 /* Reset logical unit */
+#define USCSI_PATH_INSTANCE \
+ 0x00080000 /* use path instance for transport */
/*
* suitable for parallel SCSI bus only
*/
-#define USCSI_ASYNC 0x01000 /* Set bus to asynchronous mode */
-#define USCSI_SYNC 0x02000 /* Return bus to sync mode if possible */
+#define USCSI_ASYNC 0x00001000 /* Set bus to asynchronous mode */
+#define USCSI_SYNC 0x00002000 /* Set bus to sync mode if possible */
/*
* the following flags should not be used at user level but may
@@ -137,20 +141,20 @@ struct uscsi_cmd32 {
/*
* generic flags
*/
-#define USCSI_NOINTR 0x00040 /* No interrupts, NEVER to use this flag */
-#define USCSI_NOTAG 0x00100 /* Disable tagged queueing */
-#define USCSI_OTAG 0x00200 /* ORDERED QUEUE tagged cmd */
-#define USCSI_HTAG 0x00400 /* HEAD OF QUEUE tagged cmd */
-#define USCSI_HEAD 0x00800 /* Head of HA queue */
+#define USCSI_NOINTR 0x00000040 /* No interrupts, NEVER use this flag */
+#define USCSI_NOTAG 0x00000100 /* Disable tagged queueing */
+#define USCSI_OTAG 0x00000200 /* ORDERED QUEUE tagged cmd */
+#define USCSI_HTAG 0x00000400 /* HEAD OF QUEUE tagged cmd */
+#define USCSI_HEAD 0x00000800 /* Head of HA queue */
/*
* suitable for parallel SCSI bus only
*/
-#define USCSI_NOPARITY 0x00010 /* run command without parity */
-#define USCSI_NODISCON 0x00020 /* run command without disconnects */
+#define USCSI_NOPARITY 0x00000010 /* run command without parity */
+#define USCSI_NODISCON 0x00000020 /* run command without disconnects */
-#define USCSI_RESERVED 0xfffc0000 /* Reserved Bits, must be zero */
+#define USCSI_RESERVED 0xfff00000 /* Reserved Bits, must be zero */
struct uscsi_rqs {
int rqs_flags; /* see below */
@@ -188,9 +192,11 @@ struct uscsi_rqs32 {
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_and_free(intptr_t, struct uscsi_cmd *);
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/sys/scsi/scsi_pkt.h b/usr/src/uts/common/sys/scsi/scsi_pkt.h
index 9196cc7b28..3a8b533e88 100644
--- a/usr/src/uts/common/sys/scsi/scsi_pkt.h
+++ b/usr/src/uts/common/sys/scsi/scsi_pkt.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -61,15 +61,60 @@ struct scsi_pkt {
uint_t pkt_state; /* state of command */
uint_t pkt_statistics; /* statistics */
uchar_t pkt_reason; /* reason completion called */
- uint_t pkt_cdblen;
- uint_t pkt_tgtlen;
- uint_t pkt_scblen;
- ddi_dma_handle_t pkt_handle;
- uint_t pkt_numcookies;
- off_t pkt_dma_offset;
- size_t pkt_dma_len;
- uint_t pkt_dma_flags;
- ddi_dma_cookie_t *pkt_cookies;
+
+ /*
+ * The DDI does not allow a driver to allocate it's own scsi_pkt(9S),
+ * a driver should not have *any* compiled in dependencies on
+ * "sizeof (struct scsi_pkt)". If the driver has such dependencies, it
+ * limits SCSA's ability to evolve. The proper way for an HBA to
+ * allocate a scsi_pkt is via scsi_hba_pkt_alloc(9F), or the newer
+ * tran_setup_pkt(9E) interfaces. Allocation rules have been in place
+ * for many years, unfortunately a significant number of drivers
+ * are still broken.
+ *
+ * NB: Until we can trust drivers to follow DDI scsi_pkt(9S) allocation
+ * rules, access to all fields below require special consideration.
+ * Access to these fields is limited to code paths that 'know' correct
+ * scsi_pkt allocation interfaces must have been used. This means that
+ * any target driver access to these fields is suspect, since a target
+ * knows nothing about how an HBA drivers performs scsi_pkt allocation.
+ *
+ * NB: A private scsi_pkt_size() interface has been added to simplify
+ * 'fixing' legacy HBA drivers. Use of scsi_pkt_size() is only
+ * appropriate when the effort/cost of fixing a legacy driver to use
+ * proper DDI scsi_pkt allocation interfaces is too great given the
+ * remaining driver life. New HBA drivers should *not* use
+ * scsi_pkt_size().
+ *
+ * NB: While HBA drivers with violations are being fixed, in
+ * rare cases access conditioned by scsi_pkt_allocated_correctly() is
+ * permitted.
+ */
+ /* HBA driver only, iff scsi_hba_pkt_alloc(9F)|tran_seup_pkt(9E) used */
+ uint_t pkt_cdblen; /* length of pkt_cdbp */
+ uint_t pkt_tgtlen; /* length of pkt_private */
+ uint_t pkt_scblen; /* lenght of pkt_scbp */
+
+ /* HBA driver only, iff tran_seup_pkt(9E) used */
+ ddi_dma_handle_t pkt_handle; /* private */
+ uint_t pkt_numcookies; /* number of DMA cookies */
+ off_t pkt_dma_offset; /* private */
+ size_t pkt_dma_len; /* private */
+ uint_t pkt_dma_flags; /* DMA flags */
+ ddi_dma_cookie_t *pkt_cookies; /* array of DMA cookies */
+
+ /* private: iff scsi_pkt_allocated_correctly() */
+ int pkt_path_instance; /* pHCI transport path */
+
+#ifdef SCSI_SIZE_CLEAN_VERIFY
+ /*
+ * Must be last: Building a driver with-and-without
+ * -DSCSI_SIZE_CLEAN_VERIFY, and checking driver modules for
+ * differences with a tools like 'wsdiff' allows a developer to verify
+ * that their driver has no dependencies on scsi*(9S) size.
+ */
+ int i_pkt_pad[8];
+#endif /* SCSI_SIZE_CLEAN_VERIFY */
};
#endif /* _KERNEL */
@@ -112,9 +157,9 @@ struct scsi_pkt {
/*
* Following defines are for USCSI options.
*/
-#define FLAG_SILENT 0x00010000
-#define FLAG_DIAGNOSE 0x00020000
-#define FLAG_ISOLATE 0x00040000
+#define FLAG_SILENT 0x00010000
+#define FLAG_DIAGNOSE 0x00020000
+#define FLAG_ISOLATE 0x00040000
/*
* Following define is for scsi_vhci.
diff --git a/usr/src/uts/common/sys/scsi/scsi_resource.h b/usr/src/uts/common/sys/scsi/scsi_resource.h
index f5c31ac948..d95527e951 100644
--- a/usr/src/uts/common/sys/scsi/scsi_resource.h
+++ b/usr/src/uts/common/sys/scsi/scsi_resource.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -71,19 +71,17 @@ struct scsi_pkt *scsi_init_pkt(struct scsi_address *,
int (*)(caddr_t), caddr_t);
void scsi_destroy_pkt(struct scsi_pkt *);
void scsi_free_consistent_buf(struct buf *);
-struct scsi_pkt *scsi_resalloc(struct scsi_address *, int,
- int, opaque_t, int (*)(void));
-struct scsi_pkt *scsi_pktalloc(struct scsi_address *, int, int, int (*)(void));
+int scsi_pkt_allocated_correctly(struct scsi_pkt *);
struct scsi_pkt *scsi_dmaget(struct scsi_pkt *, opaque_t, int (*)(void));
void scsi_dmafree(struct scsi_pkt *);
void scsi_sync_pkt(struct scsi_pkt *);
-void scsi_resfree(struct scsi_pkt *);
/*
* Private wrapper for scsi_pkt's allocated via scsi_init_cache_pkt()
*/
struct scsi_pkt_cache_wrapper {
struct scsi_pkt pcw_pkt;
+ int pcw_magic;
uint_t pcw_total_xfer;
uint_t pcw_curwin;
uint_t pcw_totalwin;
@@ -112,12 +110,15 @@ struct buf *scsi_pkt2bp(struct scsi_pkt *);
#define DEFAULT_PRIVLEN 0
#define DEFAULT_SCBLEN (sizeof (struct scsi_arq_status))
-/*
- * Preliminary version of the SCSA specification
- * mentioned a routine called scsi_pktfree, which
- * turned out to be semantically equivialent to
- * scsi_resfree.
- */
+/* Private functions */
+size_t scsi_pkt_size();
+void scsi_size_clean(dev_info_t *);
+
+/* Obsolete kernel functions: */
+struct scsi_pkt *scsi_pktalloc(struct scsi_address *, int, int, int (*)(void));
+struct scsi_pkt *scsi_resalloc(struct scsi_address *, int,
+ int, opaque_t, int (*)(void));
+void scsi_resfree(struct scsi_pkt *);
#define scsi_pktfree scsi_resfree
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/sys/scsi/scsi_types.h b/usr/src/uts/common/sys/scsi/scsi_types.h
index ab2f7d4e79..0ec842f2dd 100644
--- a/usr/src/uts/common/sys/scsi/scsi_types.h
+++ b/usr/src/uts/common/sys/scsi/scsi_types.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -103,6 +102,7 @@ typedef void *opaque_t;
#include <sys/stat.h>
#include <sys/sunndi.h>
#include <sys/devctl.h>
+#include <sys/ddifm.h>
#endif /* _KERNEL */
#endif /* _SYS_SCSI_SCSI_TYPES_H */
diff --git a/usr/src/uts/common/sys/scsi/targets/stdef.h b/usr/src/uts/common/sys/scsi/targets/stdef.h
index 8d1179f906..0fcfa60a3a 100644
--- a/usr/src/uts/common/sys/scsi/targets/stdef.h
+++ b/usr/src/uts/common/sys/scsi/targets/stdef.h
@@ -1195,12 +1195,15 @@ typedef enum {
}errstate;
#ifdef _KERNEL
typedef struct {
- struct scsi_pkt ei_failed_pkt;
- struct scsi_arq_status ei_failing_status;
- tapepos_t ei_expected_pos;
- errstate ei_error_type;
- buf_t *ei_failing_bp;
+ struct scsi_arq_status ei_failing_status;
+ tapepos_t ei_expected_pos;
+ errstate ei_error_type;
+ buf_t *ei_failing_bp;
+ struct scsi_pkt ei_failed_pkt; /* must be last */
+ /* ...scsi_pkt_size() */
} st_err_info;
+#define ST_ERR_INFO_SIZE (sizeof (st_err_info) - \
+ sizeof (struct scsi_pkt) + scsi_pkt_size())
#endif
diff --git a/usr/src/uts/common/sys/sunmdi.h b/usr/src/uts/common/sys/sunmdi.h
index c4a42633be..6b0dc9a5ea 100644
--- a/usr/src/uts/common/sys/sunmdi.h
+++ b/usr/src/uts/common/sys/sunmdi.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -228,6 +228,9 @@ dev_info_t *mdi_pi_get_client(mdi_pathinfo_t *);
dev_info_t *mdi_pi_get_phci(mdi_pathinfo_t *);
char *mdi_pi_get_addr(mdi_pathinfo_t *);
mdi_pathinfo_state_t mdi_pi_get_state(mdi_pathinfo_t *);
+int mdi_pi_get_path_instance(mdi_pathinfo_t *);
+char *mdi_pi_pathname_by_instance(int path_instance);
+char *mdi_pi_pathname(mdi_pathinfo_t *);
/*
* mdi_pathinfo Property handling functions