summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/biosdev/biosdev.c15
-rw-r--r--usr/src/cmd/fm/eversholt/common/check.c48
-rw-r--r--usr/src/cmd/fm/eversholt/common/literals.h3
-rw-r--r--usr/src/cmd/fm/eversholt/common/tree.c19
-rw-r--r--usr/src/cmd/fm/eversholt/common/tree.h3
-rw-r--r--usr/src/cmd/fm/fmdump/common/fmdump.c72
-rw-r--r--usr/src/cmd/fm/fmtopo/common/fmtopo.c10
-rw-r--r--usr/src/cmd/fm/modules/common/disk-monitor/topo_gather.c14
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/config.c50
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/config.h4
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/eft.c50
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/fme.c43
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/platform.c131
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/devinfo.c3
-rw-r--r--usr/src/cmd/prtconf/pdevinfo.c34
-rw-r--r--usr/src/cmd/rcm_daemon/common/mpxio_rcm.c15
-rw-r--r--usr/src/common/nvpair/nvpair.c236
-rw-r--r--usr/src/lib/fm/libfmd_log/common/fmd_filter.c33
-rw-r--r--usr/src/lib/fm/libfmd_log/common/fmd_log.h15
-rw-r--r--usr/src/lib/fm/libfmd_log/common/mapfile-vers3
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_hc.h2
-rw-r--r--usr/src/lib/fm/topo/maps/Makefile2
-rw-r--r--usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Makefile41
-rw-r--r--usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Sun-Fire-X4200-M2-hc-topology.xmlgen150
-rw-r--r--usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Makefile41
-rw-r--r--usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Sun-Fire-X4200-Server-hc-topology.xmlgen150
-rw-r--r--usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen257
-rw-r--r--usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen258
-rw-r--r--usr/src/lib/fm/topo/modules/Makefile.plugin12
-rw-r--r--usr/src/lib/fm/topo/modules/common/disk/Makefile4
-rw-r--r--usr/src/lib/fm/topo/modules/common/disk/disk.c678
-rw-r--r--usr/src/lib/fm/topo/modules/common/disk/disk.h28
-rw-r--r--usr/src/lib/fm/topo/modules/common/disk/disk_common.c868
-rw-r--r--usr/src/lib/libdevinfo/devinfo.c387
-rw-r--r--usr/src/lib/libdevinfo/libdevinfo.h317
-rw-r--r--usr/src/lib/libdevinfo/mapfile-vers96
-rw-r--r--usr/src/lib/libdiskmgt/common/findevs.c8
-rw-r--r--usr/src/lib/libnvpair/Makefile.com6
-rw-r--r--usr/src/lib/libnvpair/libnvpair.c353
-rw-r--r--usr/src/lib/libnvpair/libnvpair.h10
-rw-r--r--usr/src/lib/libnvpair/mapfile-vers6
-rw-r--r--usr/src/pkgdefs/SUNWfmd/prototype_i3862
-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
-rw-r--r--usr/src/uts/intel/io/dktp/controller/ata/ata_common.h2
-rw-r--r--usr/src/uts/intel/io/dktp/controller/ata/ata_disk.c24
-rw-r--r--usr/src/uts/sun/io/scsi/adapters/esp.c105
-rw-r--r--usr/src/uts/sun/io/scsi/adapters/fas.c47
-rw-r--r--usr/src/uts/sun/io/scsi/adapters/sf.c40
-rw-r--r--usr/src/uts/sun/sys/scsi/adapters/espcmd.h15
-rw-r--r--usr/src/uts/sun/sys/scsi/adapters/fascmd.h14
83 files changed, 4431 insertions, 1831 deletions
diff --git a/usr/src/cmd/biosdev/biosdev.c b/usr/src/cmd/biosdev/biosdev.c
index 0be13a799b..e12e444a53 100644
--- a/usr/src/cmd/biosdev/biosdev.c
+++ b/usr/src/cmd/biosdev/biosdev.c
@@ -327,15 +327,17 @@ search_children_match_busaddr(di_node_t node, char *matchbusaddr)
di_node_t cnode;
char *busaddr;
di_path_t pi = DI_PATH_NIL;
- char pbuf[MAXPATHLEN];
if (matchbusaddr == NULL)
return (DI_NODE_NIL);
- while ((pi = di_path_next_client(node, pi)) != DI_PATH_NIL)
- if (strncmp(di_path_addr(pi, pbuf), matchbusaddr, MAXPATHLEN)
- == 0)
+ while ((pi = di_path_phci_next_path(node, pi)) != DI_PATH_NIL) {
+ busaddr = di_path_bus_addr(pi);
+ if (busaddr == NULL)
+ continue;
+ if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0)
return (di_path_client_node(pi));
+ }
for (cnode = di_child_node(node); cnode != DI_NODE_NIL;
cnode = di_sibling_node(cnode)) {
@@ -343,9 +345,10 @@ search_children_match_busaddr(di_node_t node, char *matchbusaddr)
if (busaddr == NULL)
continue;
if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0)
- break;
+ return (cnode);
}
- return (cnode);
+
+ return (DI_NODE_NIL);
}
/*
diff --git a/usr/src/cmd/fm/eversholt/common/check.c b/usr/src/cmd/fm/eversholt/common/check.c
index b592fefccf..fea3048659 100644
--- a/usr/src/cmd/fm/eversholt/common/check.c
+++ b/usr/src/cmd/fm/eversholt/common/check.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.
*
* check.c -- routines for checking the prop tree
@@ -80,6 +80,7 @@ static struct {
{ T_DEFECT, "ASRU", 0, check_fru_asru, O_ERR },
{ T_EREPORT, "poller", 0, check_id, O_ERR },
{ T_EREPORT, "delivery", 0, check_timeval, O_ERR },
+ { T_EREPORT, "discard_if_config_unknown", 0, check_num, O_ERR },
{ T_SERD, "N", 1, check_num, O_ERR },
{ T_SERD, "T", 1, check_timeval, O_ERR },
{ T_SERD, "method", 1, check_serd_method, O_ERR },
@@ -991,18 +992,18 @@ check_func(struct node *np)
"first parameter of within must be"
" either a time value or zero.");
- /*
- * if two parameters, the right or max must
- * be either T_NUM, T_NAME or T_TIMEVAL
- */
- if (arglist->u.expr.right->t != T_NUM &&
- arglist->u.expr.right->t != T_TIMEVAL &&
- arglist->u.expr.right->t != T_NAME)
- outfl(O_ERR,
- arglist->file, arglist->line,
- "second parameter of within must "
- "be 0, \"infinity\" "
- "or time value.");
+ /*
+ * if two parameters, the right or max must
+ * be either T_NUM, T_NAME or T_TIMEVAL
+ */
+ if (arglist->u.expr.right->t != T_NUM &&
+ arglist->u.expr.right->t != T_TIMEVAL &&
+ arglist->u.expr.right->t != T_NAME)
+ outfl(O_ERR,
+ arglist->file, arglist->line,
+ "second parameter of within must "
+ "be 0, \"infinity\" "
+ "or time value.");
/*
* if right or left is a T_NUM it must
@@ -1034,21 +1035,12 @@ check_func(struct node *np)
"valid name for within "
"parameter.");
- /*
- * the first parameter [min] must not be greater
- * than the second parameter [max].
- */
- if (arglist->u.expr.left->u.ull >
- arglist->u.expr.right->u.ull)
- outfl(O_ERR,
- arglist->file, arglist->line,
- "the first value (min) of"
- " within must be less than"
- " the second (max) value");
- break;
- case T_TIMEVAL:
- break; /* no restrictions on T_TIMEVAL */
- default:
+ /*
+ * the first parameter [min] must not be greater
+ * than the second parameter [max].
+ */
+ if (arglist->u.expr.left->u.ull >
+ arglist->u.expr.right->u.ull)
outfl(O_ERR, arglist->file, arglist->line,
"parameter of within must be 0"
", \"infinity\" or a time value.");
diff --git a/usr/src/cmd/fm/eversholt/common/literals.h b/usr/src/cmd/fm/eversholt/common/literals.h
index 6c7cb67128..509c827f28 100644
--- a/usr/src/cmd/fm/eversholt/common/literals.h
+++ b/usr/src/cmd/fm/eversholt/common/literals.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.
*
* literals.h -- public definitions for literals in string table
@@ -132,6 +132,7 @@ L_DECL(method);
L_DECL(poller);
L_DECL(timeout);
L_DECL(trip);
+L_DECL(discard_if_config_unknown);
/* property values */
L_DECL(A);
diff --git a/usr/src/cmd/fm/eversholt/common/tree.c b/usr/src/cmd/fm/eversholt/common/tree.c
index 7c43636eff..1e89dcdb16 100644
--- a/usr/src/cmd/fm/eversholt/common/tree.c
+++ b/usr/src/cmd/fm/eversholt/common/tree.c
@@ -126,6 +126,8 @@ tree_fini(void)
Ereports = NULL;
lut_free(Ereportenames, NULL, NULL);
Ereportenames = NULL;
+ lut_free(Ereportenames_discard, NULL, NULL);
+ Ereportenames_discard = NULL;
lut_free(SERDs, NULL, NULL);
SERDs = NULL;
lut_free(STATs, NULL, NULL);
@@ -1119,13 +1121,28 @@ tree_decl(enum nodetype t, struct node *np, struct node *nvpairs,
ret = dodecl(T_EREPORT, file, line, np, nvpairs,
&Ereports, Ereportcount, 0);
/*
- * keep a lut of just the enames, so that the DE
+ * Keep a lut of just the enames, so that the DE
* can subscribe to a uniqified list of event
* classes.
*/
Ereportenames =
tree_name2np_lut_add(Ereportenames,
np->u.event.ename, np);
+
+ /*
+ * Keep a lut of the enames (event classes) to
+ * silently discard if we can't find a matching
+ * configuration node when an ereport of of a given
+ * class is received. Such events are declaired
+ * with 'discard_if_config_unknown=1'.
+ */
+ if (tree_s2np_lut_lookup(ret->u.stmt.lutp,
+ L_discard_if_config_unknown)) {
+ Ereportenames_discard = lut_add(
+ Ereportenames_discard,
+ (void *)np->u.event.ename->u.name.s,
+ (void *)np->u.event.ename->u.name.s, NULL);
+ }
break;
default:
diff --git a/usr/src/cmd/fm/eversholt/common/tree.h b/usr/src/cmd/fm/eversholt/common/tree.h
index 3dd430ce8a..e95ebff605 100644
--- a/usr/src/cmd/fm/eversholt/common/tree.h
+++ b/usr/src/cmd/fm/eversholt/common/tree.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.
*
* tree.h -- public definitions for tree module
@@ -321,6 +321,7 @@ struct lut *Defects;
struct lut *Errors;
struct lut *Ereports;
struct lut *Ereportenames;
+struct lut *Ereportenames_discard;
struct lut *SERDs;
struct lut *STATs;
struct lut *ASRUs;
diff --git a/usr/src/cmd/fm/fmdump/common/fmdump.c b/usr/src/cmd/fm/fmdump/common/fmdump.c
index a07828df05..8839858e52 100644
--- a/usr/src/cmd/fm/fmdump/common/fmdump.c
+++ b/usr/src/cmd/fm/fmdump/common/fmdump.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.
*/
@@ -35,6 +35,7 @@
#include <errno.h>
#include <time.h>
#include <ctype.h>
+#include <regex.h>
#include <fmdump.h>
@@ -136,7 +137,8 @@ static int
usage(FILE *fp)
{
(void) fprintf(fp, "Usage: %s [-efvV] [-c class] [-R root] [-t time] "
- "[-T time] [-u uuid] [file]\n", g_pname);
+ "[-T time] [-u uuid]\n\t\t[-n name[.name]*[=value]] [file]\n",
+ g_pname);
(void) fprintf(fp,
"\t-c select events that match the specified class\n"
@@ -146,6 +148,8 @@ usage(FILE *fp)
"\t-t select events that occurred after the specified time\n"
"\t-T select events that occurred before the specified time\n"
"\t-u select events that match the specified uuid\n"
+ "\t-n select events containing named nvpair "
+ "(with matching value)\n"
"\t-v set verbose mode: display additional event detail\n"
"\t-V set very verbose mode: display complete event contents\n");
@@ -176,7 +180,7 @@ gettimeopt(const char *arg)
const char *name;
hrtime_t mul;
} suffix[] = {
- { "ns", NANOSEC / NANOSEC },
+ { "ns", NANOSEC / NANOSEC },
{ "nsec", NANOSEC / NANOSEC },
{ "us", NANOSEC / MICROSEC },
{ "usec", NANOSEC / MICROSEC },
@@ -375,6 +379,59 @@ xoff_iter(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
}
/*
+ * Initialize fmd_log_filter_nvarg_t from -n name=value argument string.
+ */
+static fmd_log_filter_nvarg_t *
+setupnamevalue(char *namevalue)
+{
+ fmd_log_filter_nvarg_t *argt;
+ char *value;
+ regex_t *value_regex = NULL;
+ char errstr[128];
+ int rv;
+
+ if ((value = strchr(namevalue, '=')) == NULL) {
+ value_regex = NULL;
+ } else {
+ *value++ = '\0'; /* separate name and value string */
+
+ /*
+ * Skip white space before value to facilitate direct
+ * cut/paste from previous fmdump output.
+ */
+ while (isspace(*value))
+ value++;
+
+ if ((value_regex = malloc(sizeof (regex_t))) == NULL) {
+ (void) fprintf(stderr, "%s: failed to allocate memory: "
+ "%s\n", g_pname, strerror(errno));
+ exit(FMDUMP_EXIT_FATAL);
+ }
+
+ /* compile regular expression for possible string match */
+ if ((rv = regcomp(value_regex, value,
+ REG_NOSUB|REG_NEWLINE)) != 0) {
+ (void) regerror(rv, value_regex, errstr,
+ sizeof (errstr));
+ (void) fprintf(stderr, "unexpected regular expression "
+ "in %s: %s\n", value, errstr);
+ free(value_regex);
+ exit(FMDUMP_EXIT_USAGE);
+ }
+ }
+
+ if ((argt = malloc(sizeof (fmd_log_filter_nvarg_t))) == NULL) {
+ (void) fprintf(stderr, "%s: failed to allocate memory: %s\n",
+ g_pname, strerror(errno));
+ exit(FMDUMP_EXIT_FATAL);
+ }
+ argt->nvarg_name = namevalue; /* now just name */
+ argt->nvarg_value = value;
+ argt->nvarg_value_regex = value_regex;
+ return (argt);
+}
+
+/*
* If the -a option is not present, filter out fault records that correspond
* to events that the producer requested not be messaged for administrators.
*/
@@ -420,7 +477,8 @@ main(int argc, char *argv[])
allfv = alloca(sizeof (fmd_log_filter_t) * argc);
while (optind < argc) {
- while ((c = getopt(argc, argv, "ac:efHO:R:t:T:u:vV")) != EOF) {
+ while ((c =
+ getopt(argc, argv, "ac:efHn:O:R:t:T:u:vV")) != EOF) {
switch (c) {
case 'a':
opt_a++;
@@ -463,6 +521,12 @@ main(int argc, char *argv[])
opt_u++;
opt_a++; /* -u implies -a */
break;
+ case 'n': {
+ fltfv[fltfc].filt_func = fmd_log_filter_nv;
+ fltfv[fltfc].filt_arg = setupnamevalue(optarg);
+ allfv[allfc++] = fltfv[fltfc++];
+ break;
+ }
case 'v':
opt_v++;
break;
diff --git a/usr/src/cmd/fm/fmtopo/common/fmtopo.c b/usr/src/cmd/fm/fmtopo/common/fmtopo.c
index 1566ec6656..17ec4bfa87 100644
--- a/usr/src/cmd/fm/fmtopo/common/fmtopo.c
+++ b/usr/src/cmd/fm/fmtopo/common/fmtopo.c
@@ -361,6 +361,16 @@ print_prop_nameval(topo_hdl_t *thp, nvlist_t *nvl)
(void) printf("]");
break;
}
+ case DATA_TYPE_STRING_ARRAY: {
+ char **val;
+
+ (void) nvpair_value_string_array(pv_nvp, &val, &nelem);
+ (void) printf(" [ ");
+ for (i = 0; i < nelem; i++)
+ (void) printf("%s ", val[i]);
+ (void) printf("]");
+ break;
+ }
default:
(void) fprintf(stderr, " unknown data type (%d)",
nvpair_type(pv_nvp));
diff --git a/usr/src/cmd/fm/modules/common/disk-monitor/topo_gather.c b/usr/src/cmd/fm/modules/common/disk-monitor/topo_gather.c
index c8c0e08bbc..580c168833 100644
--- a/usr/src/cmd/fm/modules/common/disk-monitor/topo_gather.c
+++ b/usr/src/cmd/fm/modules/common/disk-monitor/topo_gather.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.
*/
@@ -295,7 +295,7 @@ topo_add_disk(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
/*
* Add the logical disk node, if it exists
*/
- if (topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
+ if (topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
TOPO_STORAGE_LOGICAL_DISK_NAME, &devpath, &err) == 0) {
(void) nvlist_add_string(diskp->props, DISK_PROP_LOGNAME,
devpath);
@@ -306,19 +306,19 @@ topo_add_disk(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
* Add the FRU information (if present in the node) to the diskmon's
* fru data structure:
*/
- (void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
+ (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
TOPO_STORAGE_MODEL, &model, &err);
- (void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
+ (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
TOPO_STORAGE_MANUFACTURER, &manuf, &err);
- (void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
+ (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
TOPO_STORAGE_SERIAL_NUM, &serial, &err);
- (void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
+ (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
TOPO_STORAGE_FIRMWARE_REV, &firmrev, &err);
- (void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
+ (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
TOPO_STORAGE_CAPACITY, &capacity, &err);
frup = new_dmfru(manuf, model, firmrev, serial,
diff --git a/usr/src/cmd/fm/modules/common/eversholt/config.c b/usr/src/cmd/fm/modules/common/eversholt/config.c
index 8278295af4..6e659c54ec 100644
--- a/usr/src/cmd/fm/modules/common/eversholt/config.c
+++ b/usr/src/cmd/fm/modules/common/eversholt/config.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.
*/
@@ -355,13 +355,19 @@ config_cook(struct cfgdata *cdata)
}
/*
- * If this property is a device path, cache it for quick lookup
+ * If this property is a device path or devid, cache it
+ * for quick lookup.
*/
if (pn == stable(TOPO_IO_DEV)) {
sv = stable(equals + 1);
- out(O_ALTFP|O_VERB3, "caching %s\n", sv);
+ out(O_ALTFP|O_VERB3, "caching dev %s\n", sv);
cdata->devcache = lut_add(cdata->devcache,
(void *)sv, (void *)newnode, NULL);
+ } else if (pn == stable(TOPO_IO_DEVID)) {
+ sv = stable(equals + 1);
+ out(O_ALTFP|O_VERB3, "caching devid %s\n", sv);
+ cdata->devidcache = lut_add(cdata->devidcache,
+ (void *)sv, (void *)newnode, NULL);
}
*equals = '=';
@@ -424,6 +430,9 @@ config_free(struct cfgdata *cp)
if (cp->devcache != NULL)
lut_free(cp->devcache, NULL, NULL);
cp->devcache = NULL;
+ if (cp->devidcache != NULL)
+ lut_free(cp->devidcache, NULL, NULL);
+ cp->devidcache = NULL;
if (cp->cpucache != NULL)
lut_free(cp->cpucache, NULL, NULL);
cp->cpucache = NULL;
@@ -534,13 +543,20 @@ prtdevcache(void *lhs, void *rhs, void *arg)
/*ARGSUSED*/
static void
+prtdevidcache(void *lhs, void *rhs, void *arg)
+{
+ out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
+}
+
+/*ARGSUSED*/
+static void
prtcpucache(void *lhs, void *rhs, void *arg)
{
out(O_ALTFP|O_VERB, "%u -> %p", (uint32_t)lhs, rhs);
}
/*
- * config_bydev_lookup -- look up the path in our DEVcache lut. If we find
+ * config_bydev_lookup -- look up the path in our devcache lut. If we find
* it return the config path, but as a struct node.
*/
struct node *
@@ -566,6 +582,32 @@ config_bydev_lookup(struct cfgdata *fromcfg, const char *path)
}
/*
+ * config_bydevid_lookup -- look up the path in our DEVIDcache lut.
+ * If we find it return the config path, but as a struct node.
+ */
+struct node *
+config_bydevid_lookup(struct cfgdata *fromcfg, const char *devid)
+{
+ struct config *find;
+ struct node *np;
+
+ out(O_ALTFP|O_VERB3, "Device id cache:");
+ lut_walk(fromcfg->devcache, (lut_cb)prtdevidcache, NULL);
+
+ if ((find = lut_lookup(fromcfg->devidcache,
+ (void *) stable(devid), NULL)) == NULL)
+ return (NULL);
+
+ np = config_nodeize(find);
+ if (np != NULL) {
+ out(O_ALTFP|O_VERB, "Matching config entry:");
+ ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np);
+ out(O_ALTFP|O_VERB, NULL);
+ }
+ return (np);
+}
+
+/*
* config_bycpuid_lookup -- look up the cpu id in our CPUcache lut.
* If we find it return the config path, but as a struct node.
*/
diff --git a/usr/src/cmd/fm/modules/common/eversholt/config.h b/usr/src/cmd/fm/modules/common/eversholt/config.h
index fb33bf28f3..a7f578738a 100644
--- a/usr/src/cmd/fm/modules/common/eversholt/config.h
+++ b/usr/src/cmd/fm/modules/common/eversholt/config.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.
*
* config.h -- public definitions for config module
@@ -55,6 +55,7 @@ struct cfgdata {
char *nextfree;
struct config *cooked;
struct lut *devcache;
+ struct lut *devidcache;
struct lut *cpucache;
};
@@ -85,6 +86,7 @@ void config_print(int flags, struct config *croot);
struct node *config_bydev_lookup(struct cfgdata *, const char *);
struct node *config_bycpuid_lookup(struct cfgdata *, uint32_t);
+struct node *config_bydevid_lookup(struct cfgdata *, const char *);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/fm/modules/common/eversholt/eft.c b/usr/src/cmd/fm/modules/common/eversholt/eft.c
index 47c83272bc..3fe0bad895 100644
--- a/usr/src/cmd/fm/modules/common/eversholt/eft.c
+++ b/usr/src/cmd/fm/modules/common/eversholt/eft.c
@@ -212,6 +212,15 @@ dosubscribe(struct node *lhs, struct node *rhs, void *arg)
FREE(ename);
}
+/*ARGSUSED*/
+static void
+dodiscardprint(struct node *lhs, struct node *rhs, void *arg)
+{
+ char *ename = (char *)lhs;
+
+ out(O_DEBUG, "allow silent discard_if_config_unknown: \"%s\"", ename);
+}
+
extern struct stats *Filecount;
/*
@@ -260,11 +269,30 @@ _fmd_init(fmd_hdl_t *hdl)
/* keep handle for routines like out() which need it */
Hdl = hdl;
- Estats = fmd_prop_get_int32(hdl, "estats");
-
+ /* set up out(O_ALTFP) first things so it is available for debug */
alloc_init();
out_init("eft");
+ if ((fname = fmd_prop_get_string(hdl, "status")) != NULL) {
+ FILE *fp;
+
+ if ((fp = fopen(fname, "a")) == NULL) {
+ fmd_prop_free_string(hdl, fname);
+ out(O_DIE|O_SYS, "status property file: %s", fname);
+ }
+
+ (void) setlinebuf(fp);
+ out_altfp(fp);
+
+ out(O_DEBUG, "appending status changes to \"%s\"", fname);
+ fmd_prop_free_string(hdl, fname);
+
+ out(O_ALTFP|O_STAMP, "\neft.so startup");
+ }
+
+
+ Estats = fmd_prop_get_int32(hdl, "estats");
stats_init(Estats);
+
stable_init(0);
literals_init();
platform_init();
@@ -297,6 +325,7 @@ _fmd_init(fmd_hdl_t *hdl)
/* subscribe to events we expect to consume */
lut_walk(Ereportenames, (lut_cb)dosubscribe, NULL);
+ lut_walk(Ereportenames_discard, (lut_cb)dodiscardprint, NULL);
/* subscribe to repair events so we can clear state on repair */
fmd_hdl_subscribe(hdl, "list.repaired");
@@ -311,23 +340,6 @@ _fmd_init(fmd_hdl_t *hdl)
Serd_Override = fmd_prop_get_string(hdl, "serd_override");
Max_fme = fmd_prop_get_int32(hdl, "maxfme");
- if ((fname = fmd_prop_get_string(hdl, "status")) != NULL) {
- FILE *fp;
-
- if ((fp = fopen(fname, "a")) == NULL) {
- fmd_prop_free_string(hdl, fname);
- out(O_DIE|O_SYS, "status property file: %s", fname);
- }
-
- (void) setlinebuf(fp);
- out_altfp(fp);
-
- out(O_DEBUG, "appending status changes to \"%s\"", fname);
- fmd_prop_free_string(hdl, fname);
-
- out(O_ALTFP|O_STAMP, "\neft.so startup");
- }
-
out(O_DEBUG, "initialized, verbose %d warn %d autoclose %s "
"maxfme %d", Verbose, Warn, Autoclose == NULL ? "(NULL)" :
Autoclose, Max_fme);
diff --git a/usr/src/cmd/fm/modules/common/eversholt/fme.c b/usr/src/cmd/fm/modules/common/eversholt/fme.c
index 63565493e3..c20b002b8a 100644
--- a/usr/src/cmd/fm/modules/common/eversholt/fme.c
+++ b/usr/src/cmd/fm/modules/common/eversholt/fme.c
@@ -742,6 +742,7 @@ fme_restart(fmd_hdl_t *hdl, fmd_case_t *inprogress)
cfgdata = MALLOC(sizeof (struct cfgdata));
cfgdata->cooked = NULL;
cfgdata->devcache = NULL;
+ cfgdata->devidcache = NULL;
cfgdata->cpucache = NULL;
cfgdata->raw_refcnt = 1;
@@ -1377,28 +1378,42 @@ retry_lone_ereport:
*/
void
fme_receive_external_report(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl,
- const char *eventstring)
+ const char *class)
{
- struct node *epnamenp = platform_getpath(nvl);
- const struct ipath *ipp;
+ struct node *epnamenp;
+ fmd_case_t *fmcase;
+ const struct ipath *ipp;
- /*
- * XFILE: If we ended up without a path, it's an X-file.
- * For now, use our undiagnosable interface.
- */
- if (epnamenp == NULL) {
- fmd_case_t *fmcase;
+ class = stable(class);
- out(O_ALTFP, "XFILE: Unable to get path from ereport");
- Undiag_reason = UD_NOPATH;
- fmcase = fmd_case_open(hdl, NULL);
- publish_undiagnosable(hdl, ffep, fmcase);
+ /* Get the component path from the ereport */
+ epnamenp = platform_getpath(nvl);
+
+ /* See if we ended up without a path. */
+ if (epnamenp == NULL) {
+ /* See if class permits silent discard on unknown component. */
+ if (lut_lookup(Ereportenames_discard, (void *)class, NULL)) {
+ out(O_ALTFP|O_VERB2, "Unable to map \"%s\" ereport "
+ "to component path, but silent discard allowed.",
+ class);
+ } else {
+ /*
+ * XFILE: Failure to find a component is bad unless
+ * 'discard_if_config_unknown=1' was specified in the
+ * ereport definition. Indicate undiagnosable.
+ */
+ out(O_ALTFP, "XFILE: Unable to map \"%s\" ereport "
+ "to component path.", class);
+ Undiag_reason = UD_NOPATH;
+ fmcase = fmd_case_open(hdl, NULL);
+ publish_undiagnosable(hdl, ffep, fmcase);
+ }
return;
}
ipp = ipath(epnamenp);
tree_free(epnamenp);
- fme_receive_report(hdl, ffep, stable(eventstring), ipp, nvl);
+ fme_receive_report(hdl, ffep, class, ipp, nvl);
}
/*ARGSUSED*/
diff --git a/usr/src/cmd/fm/modules/common/eversholt/platform.c b/usr/src/cmd/fm/modules/common/eversholt/platform.c
index 7119cf059c..8b814e40c9 100644
--- a/usr/src/cmd/fm/modules/common/eversholt/platform.c
+++ b/usr/src/cmd/fm/modules/common/eversholt/platform.c
@@ -229,86 +229,98 @@ hc_fmri_nodeize(nvlist_t *hcfmri)
struct node *
platform_getpath(nvlist_t *nvl)
{
- struct node *ret;
- nvlist_t *dfmri = NULL;
- char *scheme = NULL;
- char *path = NULL;
-
- /*
- * For now we assume the "path" part of the error report is
- * the detector FMRI
- */
+ struct node *ret;
+ nvlist_t *dfmri;
+ char *scheme;
+ char *path;
+ char *devid;
+ uint32_t cpuid;
+ enum {DT_HC, DT_DEVID, DT_DEV, DT_CPU, DT_UNKNOWN} type = DT_UNKNOWN;
+
+ /* Find the detector */
if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &dfmri) != 0) {
out(O_ALTFP, "XFILE: ereport has no detector FMRI");
return (NULL);
}
+ /* get the scheme from the detector */
if (nvlist_lookup_string(dfmri, FM_FMRI_SCHEME, &scheme) != 0) {
out(O_ALTFP, "XFILE: detector FMRI missing scheme");
return (NULL);
}
- if (strcmp(scheme, FM_FMRI_SCHEME_HC) != 0) {
- /*
- * later, if FM_FMRI_SCHEME_DEV or FM_FMRI_SCHEME_CPU
- * we can look and perform a reverse translation into
- * an hc node
- */
- uint32_t id;
- int isdev = 0;
-
- out(O_ALTFP|O_VERB, "Received ereport in scheme %s", scheme);
- if (strcmp(scheme, FM_FMRI_SCHEME_DEV) == 0) {
- isdev = 1;
- } else if (strcmp(scheme, FM_FMRI_SCHEME_CPU) != 0) {
- out(O_ALTFP, "XFILE: detector FMRI not recognized "
- "(scheme is %s, expect %s or %s or %s)",
- scheme, FM_FMRI_SCHEME_HC, FM_FMRI_SCHEME_DEV,
- FM_FMRI_SCHEME_CPU);
+ /* based on scheme, determine type */
+ if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
+ /* already in hc scheme */
+ return (hc_fmri_nodeize(dfmri));
+ } else if (strcmp(scheme, FM_FMRI_SCHEME_DEV) == 0) {
+ /* devid takes precedence over path */
+ if (nvlist_lookup_string(dfmri,
+ FM_FMRI_DEV_ID, &devid) == 0)
+ type = DT_DEVID;
+ else if (nvlist_lookup_string(dfmri,
+ FM_FMRI_DEV_PATH, &path) == 0)
+ type = DT_DEV;
+ else {
+ out(O_ALTFP, "XFILE: detector FMRI missing %s or %s",
+ FM_FMRI_DEV_ID, FM_FMRI_DEV_PATH);
return (NULL);
}
-
- if (isdev == 1 &&
- nvlist_lookup_string(dfmri, FM_FMRI_DEV_PATH, &path) != 0) {
- out(O_ALTFP, "XFILE: detector FMRI missing %s",
- FM_FMRI_DEV_PATH);
- return (NULL);
- } else if (isdev == 0 &&
- nvlist_lookup_uint32(dfmri, FM_FMRI_CPU_ID, &id) != 0) {
+ } else if (strcmp(scheme, FM_FMRI_SCHEME_CPU) != 0) {
+ if (nvlist_lookup_uint32(dfmri, FM_FMRI_CPU_ID, &cpuid) == 0)
+ type = DT_CPU;
+ else {
out(O_ALTFP, "XFILE: detector FMRI missing %s",
FM_FMRI_CPU_ID);
return (NULL);
}
+ } else {
+ out(O_ALTFP, "XFILE: detector FMRI not recognized "
+ "(scheme is %s, expect %s or %s or %s)",
+ scheme, FM_FMRI_SCHEME_HC, FM_FMRI_SCHEME_DEV,
+ FM_FMRI_SCHEME_CPU);
+ return (NULL);
+ }
- lut_free(Usednames, NULL, NULL);
- Usednames = NULL;
- in_getpath = 1;
- if (config_snapshot() == NULL) {
- out(O_ALTFP,
- "XFILE: cannot snapshot configuration");
- in_getpath = 0;
- return (NULL);
- }
+ out(O_ALTFP|O_VERB, "Received ereport in scheme %s", scheme);
- /*
- * Look up the path or cpu id in the last config snapshot.
- */
- if (isdev == 1 &&
- (ret = config_bydev_lookup(Lastcfg, path)) == NULL)
- out(O_ALTFP, "XFILE: no configuration node has "
- "device path matching %s.", path);
- else if (isdev == 0 &&
- (ret = config_bycpuid_lookup(Lastcfg, id)) == NULL)
- out(O_ALTFP, "XFILE: no configuration node has "
- "cpu-id matching %u.", id);
-
- structconfig_free(Lastcfg->cooked);
- config_free(Lastcfg);
+ /* take a config snapshot */
+ lut_free(Usednames, NULL, NULL);
+ Usednames = NULL;
+ in_getpath = 1;
+ if (config_snapshot() == NULL) {
+ out(O_ALTFP, "XFILE: cannot snapshot configuration");
in_getpath = 0;
- return (ret);
+ return (NULL);
}
- return (hc_fmri_nodeize(dfmri));
+ /* Look up the path, cpuid, or devid in the last config snapshot. */
+ switch (type) {
+ case DT_DEV:
+ if ((ret = config_bydev_lookup(Lastcfg, path)) == NULL)
+ out(O_ALTFP, "platform_getpath: no configuration node "
+ "has device path matching \"%s\".", path);
+
+ break;
+
+ case DT_DEVID:
+ if ((ret = config_bydevid_lookup(Lastcfg, devid)) == NULL)
+ out(O_ALTFP, "platform_getpath: no configuration node "
+ "has devid matching \"%s\".", devid);
+ break;
+
+ case DT_CPU:
+ if ((ret = config_bycpuid_lookup(Lastcfg, cpuid)) == NULL)
+ out(O_ALTFP, "platform_getpath: no configuration node "
+ "has cpu-id matching %u.", cpuid);
+ break;
+ }
+
+ /* free the snapshot */
+ structconfig_free(Lastcfg->cooked);
+ config_free(Lastcfg);
+ in_getpath = 0;
+ return (ret);
}
/* Allocate space for raw config strings in chunks of this size */
@@ -672,6 +684,7 @@ platform_config_snapshot(void)
Lastcfg->begin = Lastcfg->nextfree = Lastcfg->end = NULL;
Lastcfg->cooked = NULL;
Lastcfg->devcache = NULL;
+ Lastcfg->devidcache = NULL;
Lastcfg->cpucache = NULL;
diff --git a/usr/src/cmd/mdb/common/modules/genunix/devinfo.c b/usr/src/cmd/mdb/common/modules/genunix/devinfo.c
index 892d17fe57..a564225c8c 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/devinfo.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/devinfo.c
@@ -1290,6 +1290,9 @@ devnames(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{ "DN_NO_AUTODETACH", DN_NO_AUTODETACH, DN_NO_AUTODETACH },
{ "DN_GLDV3_DRIVER", DN_GLDV3_DRIVER, DN_GLDV3_DRIVER},
{ "DN_PHCI_DRIVER", DN_PHCI_DRIVER, DN_PHCI_DRIVER},
+ { "DN_OPEN_RETURNS_EINTR", \
+ DN_OPEN_RETURNS_EINTR, DN_OPEN_RETURNS_EINTR},
+ { "DN_SCSI_SIZE_CLEAN", DN_SCSI_SIZE_CLEAN, DN_SCSI_SIZE_CLEAN},
{ NULL, 0, 0 }
};
diff --git a/usr/src/cmd/prtconf/pdevinfo.c b/usr/src/cmd/prtconf/pdevinfo.c
index bd202d215d..29b26fd5ef 100644
--- a/usr/src/cmd/prtconf/pdevinfo.c
+++ b/usr/src/cmd/prtconf/pdevinfo.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.
*/
@@ -939,15 +939,16 @@ path_state_name(di_path_state_t st)
static void
dump_pathing_data(int ilev, di_node_t node)
{
- di_path_t pi = DI_PATH_NIL;
- int firsttime = 1;
+ di_path_t pi = DI_PATH_NIL;
+ di_node_t phci_node;
+ char *phci_path;
+ int path_instance;
+ int firsttime = 1;
if (node == DI_PATH_NIL)
return;
- while ((pi = di_path_next_phci(node, pi)) != DI_PATH_NIL) {
- di_node_t phci_node = di_path_phci_node(pi);
-
+ while ((pi = di_path_client_next_path(node, pi)) != DI_PATH_NIL) {
if (firsttime) {
indent_to_level(ilev);
firsttime = 0;
@@ -955,9 +956,30 @@ dump_pathing_data(int ilev, di_node_t node)
(void) printf("Paths from multipath bus adapters:\n");
}
+ /*
+ * Print the path instance and full "pathinfo" path, which is
+ * the same as the /devices devifo path had the device been
+ * enumerated under pHCI.
+ */
+ phci_node = di_path_phci_node(pi);
+ phci_path = di_devfs_path(phci_node);
+ path_instance = di_path_instance(pi);
+ if (phci_path) {
+ if (path_instance > 0) {
+ indent_to_level(ilev);
+ (void) printf("Path %d: %s/%s@%s\n",
+ path_instance, phci_path,
+ di_node_name(node),
+ di_path_bus_addr(pi));
+ }
+ di_devfs_path_free(phci_path);
+ }
+
+ /* print phci driver, instance, and path state information */
indent_to_level(ilev);
(void) printf("%s#%d (%s)\n", di_driver_name(phci_node),
di_instance(phci_node), path_state_name(di_path_state(pi)));
+
dump_prop_list_common(&pathprop_dumpops, ilev + 1, pi);
}
}
diff --git a/usr/src/cmd/rcm_daemon/common/mpxio_rcm.c b/usr/src/cmd/rcm_daemon/common/mpxio_rcm.c
index 5d1a23dad2..bb17e5977b 100644
--- a/usr/src/cmd/rcm_daemon/common/mpxio_rcm.c
+++ b/usr/src/cmd/rcm_daemon/common/mpxio_rcm.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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -640,7 +639,7 @@ get_nclients(di_node_t dinode, void *arg)
static int
is_client(di_node_t dinode)
{
- return (di_path_next_phci(dinode, DI_PATH_NIL) != DI_PATH_NIL);
+ return (di_path_client_next_path(dinode, DI_PATH_NIL) != DI_PATH_NIL);
}
/*
@@ -775,7 +774,8 @@ build_groups(di_node_t dinode, void *arg)
/*
* Build a sorted array of PHCIs pertaining to the client.
*/
- while ((dipath = di_path_next_phci(dinode, dipath)) != DI_PATH_NIL)
+ while ((dipath =
+ di_path_client_next_path(dinode, dipath)) != DI_PATH_NIL)
nphcis++;
/* Skip non-clients. */
@@ -788,7 +788,8 @@ build_groups(di_node_t dinode, void *arg)
strerror(errno));
return (DI_WALK_TERMINATE);
}
- while ((dipath = di_path_next_phci(dinode, dipath)) != DI_PATH_NIL) {
+ while ((dipath =
+ di_path_client_next_path(dinode, dipath)) != DI_PATH_NIL) {
phcinode = di_path_phci_node(dipath);
if (phcinode == DI_NODE_NIL) {
free_phcis(i, phcis); /* free preceeding PHCIs */
diff --git a/usr/src/common/nvpair/nvpair.c b/usr/src/common/nvpair/nvpair.c
index 3d1f3972af..602da73a53 100644
--- a/usr/src/common/nvpair/nvpair.c
+++ b/usr/src/common/nvpair/nvpair.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.
*/
@@ -37,15 +37,19 @@
#if defined(_KERNEL) && !defined(_BOOT)
#include <sys/varargs.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
#else
#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
#include <strings.h>
#endif
#ifndef offsetof
-#define offsetof(s, m) ((size_t)(&(((s *)0)->m)))
+#define offsetof(s, m) ((size_t)(&(((s *)0)->m)))
#endif
-
+#define skip_whitespace(p) while ((*(p) == ' ') || (*(p) == '\t')) p++
/*
* nvpair.c - Provides kernel & userland interfaces for manipulating
@@ -1154,6 +1158,27 @@ nvpair_type(nvpair_t *nvp)
return (NVP_TYPE(nvp));
}
+int
+nvpair_type_is_array(nvpair_t *nvp)
+{
+ data_type_t type = NVP_TYPE(nvp);
+
+ if ((type == DATA_TYPE_BYTE_ARRAY) ||
+ (type == DATA_TYPE_UINT8_ARRAY) ||
+ (type == DATA_TYPE_INT16_ARRAY) ||
+ (type == DATA_TYPE_UINT16_ARRAY) ||
+ (type == DATA_TYPE_INT32_ARRAY) ||
+ (type == DATA_TYPE_UINT32_ARRAY) ||
+ (type == DATA_TYPE_INT64_ARRAY) ||
+ (type == DATA_TYPE_UINT64_ARRAY) ||
+ (type == DATA_TYPE_BOOLEAN_ARRAY) ||
+ (type == DATA_TYPE_STRING_ARRAY) ||
+ (type == DATA_TYPE_NVLIST_ARRAY))
+ return (1);
+ return (0);
+
+}
+
static int
nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data)
{
@@ -1484,30 +1509,201 @@ nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...)
return (ret);
}
-int
-nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)
-{
- nvpriv_t *priv;
- nvpair_t *nvp;
- i_nvp_t *curr;
-
- if (name == NULL || nvl == NULL ||
- (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+/*
+ * Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function
+ * returns zero and a pointer to the matching nvpair is returned in '*ret'
+ * (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate
+ * multiple levels of embedded nvlists, with 'sep' as the separator. As an
+ * example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or
+ * "a.d[3].e[1]". This matches the C syntax for array embed (for convience,
+ * code also supports "a.d[3]e[1]" syntax).
+ *
+ * If 'ip' is non-NULL and the last name component is an array, return the
+ * value of the "...[index]" array index in *ip. For an array reference that
+ * is not indexed, *ip will be returned as -1. If there is a syntax error in
+ * 'name', and 'ep' is non-NULL then *ep will be set to point to the location
+ * inside the 'name' string where the syntax error was detected.
+ */
+static int
+nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep,
+ nvpair_t **ret, int *ip, char **ep)
+{
+ nvpair_t *nvp;
+ const char *np;
+ char *sepp;
+ char *idxp, *idxep;
+ nvlist_t **nva;
+ long idx;
+ int n;
+
+ if (ip)
+ *ip = -1; /* not indexed */
+ if (ep)
+ *ep = NULL;
+
+ if ((nvl == NULL) || (name == NULL))
return (EINVAL);
- if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))
- return (ENOTSUP);
+ /* step through components of name */
+ for (np = name; np && *np; np = sepp) {
+ /* ensure unique names */
+ if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))
+ return (ENOTSUP);
- for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
- nvp = &curr->nvi_nvp;
+ /* skip white space */
+ skip_whitespace(np);
+ if (*np == 0)
+ break;
- if (strcmp(name, NVP_NAME(nvp)) == 0) {
- *ret = nvp;
- return (0);
+ /* set 'sepp' to end of current component 'np' */
+ if (sep)
+ sepp = strchr(np, sep);
+ else
+ sepp = NULL;
+
+ /* find start of next "[ index ]..." */
+ idxp = strchr(np, '[');
+
+ /* if sepp comes first, set idxp to NULL */
+ if (sepp && idxp && (sepp < idxp))
+ idxp = NULL;
+
+ /*
+ * At this point 'idxp' is set if there is an index
+ * expected for the current component.
+ */
+ if (idxp) {
+ /* set 'n' to length of current 'np' name component */
+ n = idxp++ - np;
+
+ /* keep sepp up to date for *ep use as we advance */
+ skip_whitespace(idxp);
+ sepp = idxp;
+
+ /* determine the index value */
+#if defined(_KERNEL) && !defined(_BOOT)
+ if (ddi_strtol(idxp, &idxep, 0, &idx))
+ goto fail;
+#else
+ idx = strtol(idxp, &idxep, 0);
+#endif
+ if (idxep == idxp)
+ goto fail;
+
+ /* keep sepp up to date for *ep use as we advance */
+ sepp = idxep;
+
+ /* skip white space index value and check for ']' */
+ skip_whitespace(sepp);
+ if (*sepp++ != ']')
+ goto fail;
+
+ /* for embedded arrays, support C syntax: "a[1].b" */
+ skip_whitespace(sepp);
+ if (sep && (*sepp == sep))
+ sepp++;
+ } else if (sepp) {
+ n = sepp++ - np;
+ } else {
+ n = strlen(np);
+ }
+
+ /* trim trailing whitespace by reducing length of 'np' */
+ if (n == 0)
+ goto fail;
+ for (n--; (np[n] == ' ') || (np[n] == '\t'); n--)
+ ;
+ n++;
+
+ /* skip whitespace, and set sepp to NULL if complete */
+ if (sepp) {
+ skip_whitespace(sepp);
+ if (*sepp == 0)
+ sepp = NULL;
+ }
+
+ /*
+ * At this point:
+ * o 'n' is the length of current 'np' component.
+ * o 'idxp' is set if there was an index, and value 'idx'.
+ * o 'sepp' is set to the beginning of the next component,
+ * and set to NULL if we have no more components.
+ *
+ * Search for nvpair with matching component name.
+ */
+ for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(nvl, nvp)) {
+
+ /* continue if no match on name */
+ if (strncmp(np, nvpair_name(nvp), n) ||
+ (strlen(nvpair_name(nvp)) != n))
+ continue;
+
+ /* if indexed, verify type is array oriented */
+ if (idxp && !nvpair_type_is_array(nvp))
+ goto fail;
+
+ /*
+ * Full match found, return nvp and idx if this
+ * was the last component.
+ */
+ if (sepp == NULL) {
+ if (ret)
+ *ret = nvp;
+ if (ip && idxp)
+ *ip = (int)idx; /* return index */
+ return (0); /* found */
+ }
+
+ /*
+ * More components: current match must be
+ * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY
+ * to support going deeper.
+ */
+ if (nvpair_type(nvp) == DATA_TYPE_NVLIST) {
+ nvl = EMBEDDED_NVL(nvp);
+ break;
+ } else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) {
+ (void) nvpair_value_nvlist_array(nvp,
+ &nva, (uint_t *)&n);
+ if ((n < 0) || (idx >= n))
+ goto fail;
+ nvl = nva[idx];
+ break;
+ }
+
+ /* type does not support more levels */
+ goto fail;
}
+ if (nvp == NULL)
+ goto fail; /* 'name' not found */
+
+ /* search for match of next component in embedded 'nvl' list */
}
- return (ENOENT);
+fail: if (ep && sepp)
+ *ep = sepp;
+ return (EINVAL);
+}
+
+/*
+ * Return pointer to nvpair with specified 'name'.
+ */
+int
+nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)
+{
+ return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL));
+}
+
+/*
+ * Determine if named nvpair exists in nvlist (use embedded separator of '.'
+ * and return array index). See nvlist_lookup_nvpair_ei_sep for more detailed
+ * description.
+ */
+int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl,
+ const char *name, nvpair_t **ret, int *ip, char **ep)
+{
+ return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep));
}
boolean_t
diff --git a/usr/src/lib/fm/libfmd_log/common/fmd_filter.c b/usr/src/lib/fm/libfmd_log/common/fmd_filter.c
index dfc85c9758..b260816275 100644
--- a/usr/src/lib/fm/libfmd_log/common/fmd_filter.c
+++ b/usr/src/lib/fm/libfmd_log/common/fmd_filter.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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,6 +29,8 @@
#include <strings.h>
#include <libgen.h>
+#include <regex.h>
+#include <libnvpair.h>
#include <fmd_log_impl.h>
#include <fmd_log.h>
@@ -73,3 +74,27 @@ fmd_log_filter_after(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
uint64_t nsec = ((struct timeval *)arg)->tv_usec * (NANOSEC / MICROSEC);
return (rp->rec_sec == sec ? rp->rec_nsec >= nsec : rp->rec_sec >= sec);
}
+
+/*ARGSUSED*/
+int
+fmd_log_filter_nv(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
+{
+ fmd_log_filter_nvarg_t *argt = (fmd_log_filter_nvarg_t *)arg;
+ char *name = argt->nvarg_name;
+ char *value = argt->nvarg_value;
+ regex_t *value_regex = argt->nvarg_value_regex;
+ nvpair_t *nvp;
+ int ai;
+
+ /* see if nvlist has named member */
+ if (nvlist_lookup_nvpair_embedded_index(rp->rec_nvl, name,
+ &nvp, &ai, NULL) != 0)
+ return (0); /* name filter failure */
+
+ /* check value match for matching nvpair */
+ if ((value == NULL) ||
+ (nvpair_value_match_regex(nvp, ai, value, value_regex, NULL) == 1))
+ return (1); /* name/value filter pass */
+
+ return (0); /* value filter failure */
+}
diff --git a/usr/src/lib/fm/libfmd_log/common/fmd_log.h b/usr/src/lib/fm/libfmd_log/common/fmd_log.h
index 9c98d8236a..be705571b9 100644
--- a/usr/src/lib/fm/libfmd_log/common/fmd_log.h
+++ b/usr/src/lib/fm/libfmd_log/common/fmd_log.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.
*/
@@ -31,6 +30,7 @@
#include <libnvpair.h>
#include <exacct.h>
+#include <regex.h>
#ifdef __cplusplus
extern "C" {
@@ -101,10 +101,17 @@ extern fmd_log_rec_f fmd_log_filter_class; /* char *name of event class */
extern fmd_log_rec_f fmd_log_filter_uuid; /* char *uuid of list.suspect */
extern fmd_log_rec_f fmd_log_filter_before; /* struct timeval * latest */
extern fmd_log_rec_f fmd_log_filter_after; /* struct timeval * earliest */
+extern fmd_log_rec_f fmd_log_filter_nv; /* char *namevalue in event */
extern int fmd_log_filter(fmd_log_t *,
uint_t, fmd_log_filter_t *, const fmd_log_record_t *);
+typedef struct fmd_log_filter_nvarg {
+ char *nvarg_name;
+ char *nvarg_value;
+ regex_t *nvarg_value_regex;
+} fmd_log_filter_nvarg_t;
+
/*
* fmd_log_xiter() can be used to perform sophisticated iteration over an fmd
* log file such as that required by fmdump(1M). The arguments are as follows:
diff --git a/usr/src/lib/fm/libfmd_log/common/mapfile-vers b/usr/src/lib/fm/libfmd_log/common/mapfile-vers
index d7ba3e2c45..cecb3d2840 100644
--- a/usr/src/lib/fm/libfmd_log/common/mapfile-vers
+++ b/usr/src/lib/fm/libfmd_log/common/mapfile-vers
@@ -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.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -34,6 +34,7 @@ SUNWprivate {
fmd_log_filter_after;
fmd_log_filter_before;
fmd_log_filter_class;
+ fmd_log_filter_nv;
fmd_log_filter_uuid;
fmd_log_header;
fmd_log_iter;
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
index ba49a8bbb0..11d1090748 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
@@ -82,8 +82,10 @@ extern "C" {
#define TOPO_IO_DRIVER "driver"
#define TOPO_IO_MODULE "module"
#define TOPO_IO_DEV "dev"
+#define TOPO_IO_DEVID "devid"
#define TOPO_IO_DEV_PATH "devfs-path"
#define TOPO_IO_AP_PATH "ap-path"
+#define TOPO_IO_PHYS_PATH "phys-path"
#define TOPO_PGROUP_PCI "pci"
#define TOPO_PCI_VENDID "vendor-id"
diff --git a/usr/src/lib/fm/topo/maps/Makefile b/usr/src/lib/fm/topo/maps/Makefile
index 1984b1bbf5..5af237b7b8 100644
--- a/usr/src/lib/fm/topo/maps/Makefile
+++ b/usr/src/lib/fm/topo/maps/Makefile
@@ -45,6 +45,8 @@ sparc_SUBDIRS = sun4u \
i386_SUBDIRS = i86pc \
i386 \
+ SUNW,Sun-Fire-X4200-Server \
+ SUNW,Sun-Fire-X4200-M2 \
SUNW,Sun-Fire-X4500 \
SUNW,Sun-Fire-X4540
diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Makefile b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Makefile
new file mode 100644
index 0000000000..fa4d771486
--- /dev/null
+++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Makefile
@@ -0,0 +1,41 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+# NOTE: The name of the xml file we are building is 'platform'
+# specific, but its build is structured as 'arch' specific since
+# 'uname -i' on all x86 platforms returns i86pc.
+
+ARCH = i86pc
+CLASS = arch
+DTDFILE =
+TOPOFILE = Sun-Fire-X4200-M2-hc-topology.xml
+SRCDIR = ../SUNW,Sun-Fire-X4200-M2
+
+PLATFORM = Sun-Fire-X4200-M2
+TOPOBASE = ../i86pc/i86pc-hc-topology.xml
+
+include ../Makefile.map
diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Sun-Fire-X4200-M2-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Sun-Fire-X4200-M2-hc-topology.xmlgen
new file mode 100644
index 0000000000..e8f94d0f65
--- /dev/null
+++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Sun-Fire-X4200-M2-hc-topology.xmlgen
@@ -0,0 +1,150 @@
+#!/usr/local/bin/perl
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+use Getopt::Std;
+
+# X4200-M2: platform specific begin
+my $sys_supported = { "name" => "Sun-Fire-X4200-M2",
+ "num_bays" => "4",
+ "bay_label" => "HD"};
+# X4200-M2: platform specific end
+
+$IFILE = "filehandle";
+$OFILE = "filehandle";
+
+sub Usage()
+{
+ print STDERR "Usage: xml-gen -p <platform> " .
+ "-i <input_xml_file> -o <output_xml_file>\n";
+}
+
+sub calc_nodes
+{
+# X4200-M2: platform specific begin
+ $controller = 0;
+# X4200-M2: platform specific end
+
+ for ($bay = 0; $bay < $sys_supported->{"num_bays"}; $bay++) {
+
+# X4200-M2: platform specific begin
+ $target = $bay;
+
+ # set hba path, target path, bay path, and attachment point
+ $hpath = "/pci\@7b,0/pci1022,7458\@11/pci1000,3060\@2";
+ $tpath = sprintf("/sd\@%x,0", $target);
+ $apoint = sprintf(":scsi::dsk/c%dt%dd0",
+ $controller + 1, $target);
+# X4200-M2: platform specific end
+
+ printf OFILE "\n <node instance='%d'>\n\n", $bay;
+
+ printf OFILE
+ " <propgroup name='protocol' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='label' type='string' " .
+ "value='%s%d' />\n",
+ $sys_supported->{"bay_label"}, $bay;
+ printf OFILE
+ " </propgroup>\n";
+
+ printf OFILE
+ " <propgroup name='io' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='ap-path' type='string' " .
+ "value='/devices%s%s' />\n", $hpath, $apoint;
+ printf OFILE
+ " </propgroup>\n";
+
+# no LED support
+
+ printf OFILE
+ " <propgroup name='binding' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='occupant-path' type='string' " .
+ "value='%s%s' />\n", $hpath, $tpath;
+ printf OFILE
+ " </propgroup>\n";
+
+ printf OFILE "\n </node>\n\n";
+ }
+}
+
+$ok = getopts("p:i:o:h", \%options);
+if ($options{'h'}) {
+ Usage();
+ exit (1);
+}
+
+$platform = $options{'p'};
+$input_file = $options{'i'};
+$output_file = $options{'o'};
+
+if (!$platform || !$input_file || !$output_file) {
+ Usage();
+ exit (1);
+}
+
+open(IFILE, "< $input_file") || die("$input_file cannot be opened.");
+open(OFILE, "> $output_file") || die("$output_file cannot be opened.");
+my $in_chassis_range = 0;
+
+while ($line = <IFILE>) {
+ chomp($line);
+
+ if ($line =~ /range\s+name\s?=\s?\Wchassis\W/) {
+ $in_chassis_range = 1;
+ }
+ if ($in_chassis_range && ($line =~ /<\/dependents>/)) {
+ last;
+ } else {
+ print OFILE "$line\n";
+ }
+}
+
+print OFILE " <!--xml-gen internal storage-->\n";
+printf OFILE " <range name='bay' min='0' max='%d'>\n",
+ $sys_supported->{"num_bays"}-1;
+
+calc_nodes(0);
+
+printf OFILE " <dependents grouping='children'>\n";
+printf OFILE " <range name='disk' min='0' max='0'>\n";
+printf OFILE " <enum-method name='disk' version='1' />\n";
+printf OFILE " </range>\n";
+printf OFILE " </dependents>\n\n";
+printf OFILE " </range>\n";
+
+print OFILE "$line\n";
+while ($line = <IFILE>) {
+ print OFILE $line;
+}
+
+close OFILE;
+close IFILE;
diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Makefile b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Makefile
new file mode 100644
index 0000000000..40cc3f7c5b
--- /dev/null
+++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Makefile
@@ -0,0 +1,41 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+# NOTE: The name of the xml file we are building is 'platform'
+# specific, but its build is structured as 'arch' specific since
+# 'uname -i' on all x86 platforms returns i86pc.
+
+ARCH = i86pc
+CLASS = arch
+DTDFILE =
+TOPOFILE = Sun-Fire-X4200-Server-hc-topology.xml
+SRCDIR = ../SUNW,Sun-Fire-X4200-Server
+
+PLATFORM = Sun-Fire-X4200
+TOPOBASE = ../i86pc/i86pc-hc-topology.xml
+
+include ../Makefile.map
diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Sun-Fire-X4200-Server-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Sun-Fire-X4200-Server-hc-topology.xmlgen
new file mode 100644
index 0000000000..d6bd251c68
--- /dev/null
+++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Sun-Fire-X4200-Server-hc-topology.xmlgen
@@ -0,0 +1,150 @@
+#!/usr/local/bin/perl
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+use Getopt::Std;
+
+# X4200-Server: platform specific begin
+my $sys_supported = { "name" => "Sun-Fire-X4200-Server",
+ "num_bays" => "4",
+ "bay_label" => "HD"};
+# X4200-Server: platform specific end
+
+$IFILE = "filehandle";
+$OFILE = "filehandle";
+
+sub Usage()
+{
+ print STDERR "Usage: xml-gen -p <platform> " .
+ "-i <input_xml_file> -o <output_xml_file>\n";
+}
+
+sub calc_nodes
+{
+# X4200-Server: platform specific begin
+ $controller = 0;
+# X4200-Server: platform specific end
+
+ for ($bay = 0; $bay < $sys_supported->{"num_bays"}; $bay++) {
+
+# X4200-Server: platform specific begin
+ $target = $bay;
+
+ # set hba path, target path, bay path, and attachment point
+ $hpath = "/pci\@0,0/pci1022,7450\@2/pci1000,3060\@3";
+ $tpath = sprintf("/sd\@%x,0", $target);
+ $apoint = sprintf(":scsi::dsk/c%dt%dd0",
+ $controller + 1, $target);
+# X4200-Server: platform specific end
+
+ printf OFILE "\n <node instance='%d'>\n\n", $bay;
+
+ printf OFILE
+ " <propgroup name='protocol' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='label' type='string' " .
+ "value='%s%d' />\n",
+ $sys_supported->{"bay_label"}, $bay;
+ printf OFILE
+ " </propgroup>\n";
+
+ printf OFILE
+ " <propgroup name='io' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='ap-path' type='string' " .
+ "value='/devices%s%s' />\n", $hpath, $apoint;
+ printf OFILE
+ " </propgroup>\n";
+
+# no LED support
+
+ printf OFILE
+ " <propgroup name='binding' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='occupant-path' type='string' " .
+ "value='%s%s' />\n", $hpath, $tpath;
+ printf OFILE
+ " </propgroup>\n";
+
+ printf OFILE "\n </node>\n\n";
+ }
+}
+
+$ok = getopts("p:i:o:h", \%options);
+if ($options{'h'}) {
+ Usage();
+ exit (1);
+}
+
+$platform = $options{'p'};
+$input_file = $options{'i'};
+$output_file = $options{'o'};
+
+if (!$platform || !$input_file || !$output_file) {
+ Usage();
+ exit (1);
+}
+
+open(IFILE, "< $input_file") || die("$input_file cannot be opened.");
+open(OFILE, "> $output_file") || die("$output_file cannot be opened.");
+my $in_chassis_range = 0;
+
+while ($line = <IFILE>) {
+ chomp($line);
+
+ if ($line =~ /range\s+name\s?=\s?\Wchassis\W/) {
+ $in_chassis_range = 1;
+ }
+ if ($in_chassis_range && ($line =~ /<\/dependents>/)) {
+ last;
+ } else {
+ print OFILE "$line\n";
+ }
+}
+
+print OFILE " <!--xml-gen internal storage-->\n";
+printf OFILE " <range name='bay' min='0' max='%d'>\n",
+ $sys_supported->{"num_bays"}-1;
+
+calc_nodes(0);
+
+printf OFILE " <dependents grouping='children'>\n";
+printf OFILE " <range name='disk' min='0' max='0'>\n";
+printf OFILE " <enum-method name='disk' version='1' />\n";
+printf OFILE " </range>\n";
+printf OFILE " </dependents>\n\n";
+printf OFILE " </range>\n";
+
+print OFILE "$line\n";
+while ($line = <IFILE>) {
+ print OFILE $line;
+}
+
+close OFILE;
+close IFILE;
diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen
index afb5b1c879..0d58d0b2d0 100644
--- a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen
+++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen
@@ -23,146 +23,144 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
+#pragma ident "%Z%%M% %I% %E% SMI"
#
use Getopt::Std;
-
-my $sys_supported = {"name" => "Sun-Fire-X4500",
- "prop_name" => "sfx4500",
- "num_bays" => "48"};
-
+# X4500: platform specific begin
+my $sys_supported = { "name" => "Sun-Fire-X4500",
+ "prop_name" => "sfx4500",
+ "num_bays" => "48",
+ "bay_label" => "HD_ID_"};
+# X4500: platform specific end
$IFILE = "filehandle";
$OFILE = "filehandle";
sub Usage()
{
- print STDERR "Usage: xml-gen -p <platform> -i <input_xml_file> -o <output_xml_file>\n";
+ print STDERR "Usage: xml-gen -p <platform> " .
+ "-i <input_xml_file> -o <output_xml_file>\n";
}
+# Define properties associated with LED manipulation.
+# We have three LEDs per disk: Present (PRSNT), OK-to-remove (OK2RM), and fault.
+# We track the following states (absent present configured unconfigured) via
+# the PRSNT/OK2RM LEDs (FAULT LED is maintained separately).
sub calc_sfx_prop
{
my $name = shift;
- my $hdd = shift;
+ my $bay = shift;
my $sid = shift;
- printf OFILE "\n";
- printf OFILE " <propgroup name='%s-properties'", $name;
- printf OFILE " version='1' name-stability='Private'";
- printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='fru-update-action'";
- printf OFILE " type='string' value='ipmi:fru gid=3 hdd=%d' />\n", $hdd;
- printf OFILE " <propval name='indicator-name-0'";
- printf OFILE " type='string' value='+PRSNT' />\n";
- printf OFILE " <propval name='indicator-action-0'";
- printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0001' />\n",
- $sid;
- printf OFILE " <propval name='indicator-name-1'";
- printf OFILE " type='string' value='-PRSNT' />\n";
- printf OFILE " <propval name='indicator-action-1'";
- printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0001' />\n",
- $sid;
- printf OFILE " <propval name='indicator-name-2'";
- printf OFILE " type='string' value='+OK2RM' />\n";
- printf OFILE " <propval name='indicator-action-2'";
- printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0008' />\n",
- $sid;
- printf OFILE " <propval name='indicator-name-3'";
- printf OFILE " type='string' value='-OK2RM' />\n";
- printf OFILE " <propval name='indicator-action-3'";
- printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0008' />\n",
- $sid;
- printf OFILE " <propval name='indicator-name-4'";
- printf OFILE " type='string' value='+FAULT' />\n";
- printf OFILE " <propval name='indicator-action-4'";
- printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0002' />\n",
- $sid;
- printf OFILE " <propval name='indicator-name-5'";
- printf OFILE " type='string' value='-FAULT' />\n";
- printf OFILE " <propval name='indicator-action-5'";
- printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0002' />\n",
- $sid;
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-0' type='string' value='absent>present' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-0' type='string' value='+PRSNT&amp;+OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-1' type='string' value='present>configured' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-1' type='string' value='+PRSNT&amp;-OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-2' type='string' value='configured>unconfigured' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-2' type='string' value='+OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-3' type='string' value='unconfigured>configured' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-3' type='string' value='-OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-4' type='string' value='unconfigured>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-4' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-5' type='string' value='configured>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-5' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-6' type='string' value='present>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-6' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " </propgroup>\n";
- printf OFILE "\n";
+ my @names = (
+ "+PRSNT", "-PRSNT",
+ "+OK2RM", "-OK2RM",
+ "+FAULT", "-FAULT");
+ my @masks = (
+ "amask=0x0001", "dmask=0x0001",
+ "amask=0x0008", "dmask=0x0008",
+ "amask=0x0002", "dmask=0x0002");
+ my @states = (
+ "absent>present", "present>configured",
+ "configured>unconfigured", "unconfigured>configured",
+ "unconfigured>absent", "configured>absent",
+ "present>absent", "absent>configured");
+ my @actions = (
+ "+PRSNT&amp;+OK2RM", "+PRSNT&amp;-OK2RM",
+ "+OK2RM", "-OK2RM",
+ "-OK2RM&amp;-PRSNT", "-OK2RM&amp;-PRSNT",
+ "-OK2RM&amp;-PRSNT", "-OK2RM&amp;+PRSNT");
+
+ printf OFILE "\n";
+ printf OFILE
+ " <propgroup name='%s-properties' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n", $name;
+ printf OFILE
+ " <propval name='fru-update-action' type='string' " .
+ "value='ipmi:fru gid=3 hdd=%d' />\n", $bay;
+
+ for ($i = 0; $i < 6; $i++) {
+ printf OFILE
+ " <propval name='indicator-name-%d' type='string' " .
+ "value='%s' />\n", $i, $names[$i];
+ printf OFILE
+ " <propval name='indicator-action-%d' " .
+ "type='string' value='ipmi:state sid=%d %s' />\n",
+ $i, $sid, $masks[$i];
+ }
+
+ for ($i = 0; $i < 8; $i++) {
+ printf OFILE
+ " <propval name='indicator-rule-states-%d' " .
+ "type='string' value='%s' />\n", $i, $states[$i];
+ printf OFILE
+ " <propval name='indicator-rule-actions-%d' " .
+ "type='string' value='%s' />\n", $i, $actions[$i];
+ }
+ printf OFILE
+ " </propgroup>\n\n";
}
-sub calc_nodes
+sub calc_nodes
{
+
+# X4500: platform specific begin
my @pci0=(1, 2, 0);
my @pci1=(4, 3, 8, 7, 2, 1);
+# X4500: platform specific end
+
+ for ($bay = 0; $bay < $sys_supported->{"num_bays"}; $bay++) {
- for ($cnt = 0; $cnt < $sys_supported->{"num_bays"}; $cnt++) {
- $hdd = $cnt;
- $sid = 90 + $cnt;
- $d = (($cnt/12) + (($cnt & 1) << 2));
- $index = (($cnt >> 2) % 3);
+# X4500: platform specific begin
+ $sid = 90 + $bay;
+ $target = (($bay/12) + (($bay & 1) << 2));
+ $index = (($bay >> 2) % 3);
$p0 = $pci0[$index];
- $index = (($cnt >> 1) % 6);
+ $index = (($bay >> 1) % 6);
$p1 = $pci1[$index];
- printf OFILE "\n";
- printf OFILE " <node instance='%d'>\n", $cnt;
- printf OFILE "\n";
- printf OFILE " <propgroup name='protocol'";
- printf OFILE " version='1' name-stability='Private'";
- printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='ASRU' ";
- printf OFILE "type='fmri' value=";
- printf OFILE "'dev:////pci@%d,0/pci1022,7458@%d", $p0, $p1;
- printf OFILE "/pci11ab,11ab\@1' />\n";
- printf OFILE " <propval name='label'";
- printf OFILE " type='string' value='bay%d' />\n", $cnt;
- printf OFILE " </propgroup>\n";
-
- printf OFILE " <propgroup name='io'";
- printf OFILE " version='1' name-stability='Private'";
- printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='ap-path'";
- printf OFILE " type='string'";
- printf OFILE " value='/devices/pci@%d,0/pci1022,7458@%d", $p0, $p1;
- printf OFILE "/pci11ab,11ab\@1:%d' />\n", $d;
- printf OFILE " </propgroup>\n";
-
- calc_sfx_prop($sys_supported->{"prop_name"}, $hdd, $sid);
- printf OFILE " <propgroup name='binding'";
- printf OFILE " version='1' name-stability='Private'";
- printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='occupant-path'";
- printf OFILE " type='string'";
- printf OFILE " value='/pci@%d,0/pci1022,7458@%d", $p0, $p1;
- printf OFILE "/pci11ab,11ab\@1/disk@%d,0' />\n", $d;
- printf OFILE " </propgroup>\n";
- printf OFILE "\n";
- printf OFILE " </node>\n";
- printf OFILE "\n";
+
+ # set hba path, target path, bay path, and attachment point
+ $hpath = sprintf("/pci\@%x,0/pci1022,7458\@%x/pci11ab,11ab\@1",
+ $p0, $p1);
+ $tpath = sprintf("/disk\@%x,0", $target);
+ $apoint = sprintf(":%d", $target);
+# X4500: platform specific end
+
+ printf OFILE "\n <node instance='%d'>\n\n", $bay;
+
+ printf OFILE
+ " <propgroup name='protocol' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='label' type='string' " .
+ "value='%s%d' />\n",
+ $sys_supported->{"bay_label"}, $bay;
+ printf OFILE
+ " </propgroup>\n";
+
+ printf OFILE
+ " <propgroup name='io' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='ap-path' type='string' " .
+ "value='/devices%s%s' />\n", $hpath, $apoint;
+ printf OFILE
+ " </propgroup>\n";
+
+# platform specific LED support
+ calc_sfx_prop($sys_supported->{"prop_name"}, $bay, $sid);
+
+ printf OFILE
+ " <propgroup name='binding' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='occupant-path' type='string' " .
+ "value='%s%s' />\n", $hpath, $tpath;
+ printf OFILE
+ " </propgroup>\n";
+
+ printf OFILE "\n </node>\n\n";
}
}
@@ -170,7 +168,7 @@ $ok = getopts("p:i:o:h", \%options);
if ($options{'h'}) {
Usage();
exit (1);
-}
+}
$platform = $options{'p'};
$input_file = $options{'i'};
@@ -184,8 +182,10 @@ if (!$platform || !$input_file || !$output_file) {
open(IFILE, "< $input_file") || die("$input_file cannot be opened.");
open(OFILE, "> $output_file") || die("$output_file cannot be opened.");
my $in_chassis_range = 0;
+
while ($line = <IFILE>) {
chomp($line);
+
if ($line =~ /range\s+name\s?=\s?\Wchassis\W/) {
$in_chassis_range = 1;
}
@@ -195,19 +195,20 @@ while ($line = <IFILE>) {
print OFILE "$line\n";
}
}
-print OFILE " <!--xml-gen internal storage-->\n";
-printf OFILE " <range name='bay' min='0' max='%d'>\n", $sys_supported->{"num_bays"};
+
+print OFILE " <!--xml-gen internal storage-->\n";
+printf OFILE " <range name='bay' min='0' max='%d'>\n",
+ $sys_supported->{"num_bays"}-1;
+
calc_nodes(0);
-printf OFILE " <dependents grouping='children'>\n";
-printf OFILE " <range name='disk' min='0'";
-printf OFILE " max='1'>\n";
-printf OFILE " <enum-method name='disk'";
-printf OFILE " version='1' />\n";
-printf OFILE " </range>\n";
-printf OFILE " </dependents>\n";
-printf OFILE "\n";
-printf OFILE " </range>\n";
+printf OFILE " <dependents grouping='children'>\n";
+printf OFILE " <range name='disk' min='0' max='0'>\n";
+printf OFILE " <enum-method name='disk' version='1' />\n";
+printf OFILE " </range>\n";
+printf OFILE " </dependents>\n\n";
+printf OFILE " </range>\n";
+
print OFILE "$line\n";
while ($line = <IFILE>) {
print OFILE $line;
diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen
index 0d49a3c83a..1d1c8a8250 100644
--- a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen
+++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen
@@ -23,154 +23,143 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
+#pragma ident "%Z%%M% %I% %E% SMI"
#
use Getopt::Std;
-
-my $sys_supported = {"name" => "Sun-Fire-X4540",
- "prop_name" => "sfx4500",
- "num_bays" => "48"};
-
+# X4540: platform specific begin
+my $sys_supported = { "name" => "Sun-Fire-X4540",
+ "prop_name" => "sfx4500",
+ "num_bays" => "48",
+ "bay_label" => "HD_ID_"};
+# X4540: platform specific end
$IFILE = "filehandle";
$OFILE = "filehandle";
sub Usage()
{
- print STDERR "Usage: xml-gen -p <platform> -i <input_xml_file> -o <output_xml_file>\n";
+ print STDERR "Usage: xml-gen -p <platform> " .
+ "-i <input_xml_file> -o <output_xml_file>\n";
}
+# Define properties associated with LED manipulation.
+# We have three LEDs per disk: Present (PRSNT), OK-to-remove (OK2RM), and fault.
+# We track the following states (absent present configured unconfigured) via
+# the PRSNT/OK2RM LEDs (FAULT LED is maintained separately).
sub calc_sfx_prop
{
my $name = shift;
- my $hdd = shift;
+ my $bay = shift;
my $sid = shift;
- printf OFILE "\n";
- printf OFILE " <propgroup name='%s-properties'", $name;
- printf OFILE " version='1' name-stability='Private'";
- printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='fru-update-action'";
- printf OFILE " type='string' value='ipmi:fru gid=3 hdd=%d' />\n", $hdd;
- printf OFILE " <propval name='indicator-name-0'";
- printf OFILE " type='string' value='+PRSNT' />\n";
- printf OFILE " <propval name='indicator-action-0'";
- printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0001' />\n",
- $sid;
- printf OFILE " <propval name='indicator-name-1'";
- printf OFILE " type='string' value='-PRSNT' />\n";
- printf OFILE " <propval name='indicator-action-1'";
- printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0001' />\n",
- $sid;
- printf OFILE " <propval name='indicator-name-2'";
- printf OFILE " type='string' value='+OK2RM' />\n";
- printf OFILE " <propval name='indicator-action-2'";
- printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0008' />\n",
- $sid;
- printf OFILE " <propval name='indicator-name-3'";
- printf OFILE " type='string' value='-OK2RM' />\n";
- printf OFILE " <propval name='indicator-action-3'";
- printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0008' />\n",
- $sid;
- printf OFILE " <propval name='indicator-name-4'";
- printf OFILE " type='string' value='+FAULT' />\n";
- printf OFILE " <propval name='indicator-action-4'";
- printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0002' />\n",
- $sid;
- printf OFILE " <propval name='indicator-name-5'";
- printf OFILE " type='string' value='-FAULT' />\n";
- printf OFILE " <propval name='indicator-action-5'";
- printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0002' />\n",
- $sid;
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-0' type='string' value='absent>present' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-0' type='string' value='+PRSNT&amp;+OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-1' type='string' value='present>configured' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-1' type='string' value='+PRSNT&amp;-OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-2' type='string' value='configured>unconfigured' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-2' type='string' value='+OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-3' type='string' value='unconfigured>configured' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-3' type='string' value='-OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-4' type='string' value='unconfigured>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-4' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-5' type='string' value='configured>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-5' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-6' type='string' value='present>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-6' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "states-7' type='string' value='absent>configured' />\n";
- printf OFILE " <propval name='indicator-rule-";
- printf OFILE "actions-7' type='string' value='-OK2RM&amp;+PRSNT' />\n";
- printf OFILE " </propgroup>\n";
- printf OFILE "\n";
+ my @names = (
+ "+PRSNT", "-PRSNT",
+ "+OK2RM", "-OK2RM",
+ "+FAULT", "-FAULT");
+ my @masks = (
+ "amask=0x0001", "dmask=0x0001",
+ "amask=0x0008", "dmask=0x0008",
+ "amask=0x0002", "dmask=0x0002");
+ my @states = (
+ "absent>present", "present>configured",
+ "configured>unconfigured", "unconfigured>configured",
+ "unconfigured>absent", "configured>absent",
+ "present>absent", "absent>configured");
+ my @actions = (
+ "+PRSNT&amp;+OK2RM", "+PRSNT&amp;-OK2RM",
+ "+OK2RM", "-OK2RM",
+ "-OK2RM&amp;-PRSNT", "-OK2RM&amp;-PRSNT",
+ "-OK2RM&amp;-PRSNT", "-OK2RM&amp;+PRSNT");
+
+ printf OFILE "\n";
+ printf OFILE
+ " <propgroup name='%s-properties' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n", $name;
+ printf OFILE
+ " <propval name='fru-update-action' type='string' " .
+ "value='ipmi:fru gid=3 hdd=%d' />\n", $bay;
+
+ for ($i = 0; $i < 6; $i++) {
+ printf OFILE
+ " <propval name='indicator-name-%d' type='string' " .
+ "value='%s' />\n", $i, $names[$i];
+ printf OFILE
+ " <propval name='indicator-action-%d' " .
+ "type='string' value='ipmi:state sid=%d %s' />\n",
+ $i, $sid, $masks[$i];
+ }
+
+ for ($i = 0; $i < 8; $i++) {
+ printf OFILE
+ " <propval name='indicator-rule-states-%d' " .
+ "type='string' value='%s' />\n", $i, $states[$i];
+ printf OFILE
+ " <propval name='indicator-rule-actions-%d' " .
+ "type='string' value='%s' />\n", $i, $actions[$i];
+ }
+ printf OFILE
+ " </propgroup>\n\n";
}
-sub calc_nodes
+sub calc_nodes
{
+
+# X4540: platform specific begin
my @pci0=(0, 0, 0, 0x3c, 0x3c, 0x3c);
my @pci1=(0x377, 0x375, 0x376, 0x377, 0x375, 0x376);
my @pci2=(0xa, 0xb, 0xf, 0xa, 0xb, 0xf);
+# X4540: platform specific end
for ($bay = 0; $bay < $sys_supported->{"num_bays"}; $bay++) {
- $controller = $bay / 8;
- $target = $bay % 8 ;
+# X4540: platform specific begin
$sid = 90 + $bay;
+ $target = $bay % 8;
+ $controller = $bay / 8;
- $physdev = "/pci\@" . sprintf("%x", $pci0[$controller]) .
- ",0/pci10de," . sprintf("%x", $pci1[$controller]) .
- "\@" . sprintf("%x", $pci2[$controller]) .
- "/pci1000,1000\@0";
-
- printf OFILE "\n";
- printf OFILE " <node instance='%d'>\n", $bay;
- printf OFILE "\n";
- printf OFILE " <propgroup name='protocol'";
- printf OFILE " version='1' name-stability='Private'";
- printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='ASRU' ";
- printf OFILE "type='fmri' value=";
- printf OFILE "'dev:///" . $physdev . "' />\n";
- printf OFILE " <propval name='label'";
- printf OFILE " type='string' value='bay%d' />\n", $bay;
- printf OFILE " </propgroup>\n";
-
- printf OFILE " <propgroup name='io'";
- printf OFILE " version='1' name-stability='Private'";
- printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='ap-path'";
- printf OFILE " type='string'";
- printf OFILE " value='/devices" . $physdev;
- printf OFILE ":scsi::dsk/c%dt%dd0", $controller + 1, $target;
- printf OFILE "' />\n";
- printf OFILE " </propgroup>\n";
-
+ # set hba path, target path, bay path, and attachment point
+ $hpath = sprintf("/pci\@%x,0/pci10de,%x\@%x/pci1000,1000\@0",
+ $pci0[$controller], $pci1[$controller], $pci2[$controller]);
+ $tpath = sprintf("/sd\@%x,0", $target);
+ $apoint = sprintf(":scsi::dsk/c%dt%dd0",
+ $controller + 1, $target);
+# X4540: platform specific end
+
+ printf OFILE "\n <node instance='%d'>\n\n", $bay;
+
+ printf OFILE
+ " <propgroup name='protocol' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='label' type='string' " .
+ "value='%s%d' />\n",
+ $sys_supported->{"bay_label"}, $bay;
+ printf OFILE
+ " </propgroup>\n";
+
+ printf OFILE
+ " <propgroup name='io' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='ap-path' type='string' " .
+ "value='/devices%s%s' />\n", $hpath, $apoint;
+ printf OFILE
+ " </propgroup>\n";
+
+# platform specific LED support
calc_sfx_prop($sys_supported->{"prop_name"}, $bay, $sid);
- printf OFILE " <propgroup name='binding'";
- printf OFILE " version='1' name-stability='Private'";
- printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='occupant-path'";
- printf OFILE " type='string'";
- printf OFILE " value='" . $physdev . "/sd\@%d,0", $target;
- printf OFILE "' />\n";
- printf OFILE " </propgroup>\n";
- printf OFILE "\n";
- printf OFILE " </node>\n";
- printf OFILE "\n";
+
+ printf OFILE
+ " <propgroup name='binding' version='1' " .
+ "name-stability='Private' data-stability='Private' >\n";
+ printf OFILE
+ " <propval name='occupant-path' type='string' " .
+ "value='%s%s' />\n", $hpath, $tpath;
+ printf OFILE
+ " </propgroup>\n";
+
+ printf OFILE "\n </node>\n\n";
}
}
@@ -178,7 +167,7 @@ $ok = getopts("p:i:o:h", \%options);
if ($options{'h'}) {
Usage();
exit (1);
-}
+}
$platform = $options{'p'};
$input_file = $options{'i'};
@@ -192,30 +181,33 @@ if (!$platform || !$input_file || !$output_file) {
open(IFILE, "< $input_file") || die("$input_file cannot be opened.");
open(OFILE, "> $output_file") || die("$output_file cannot be opened.");
my $in_chassis_range = 0;
+
while ($line = <IFILE>) {
chomp($line);
+
if ($line =~ /range\s+name\s?=\s?\Wchassis\W/) {
$in_chassis_range = 1;
}
- if ($in_chassis_range && ($line =~ /\/dependents/)) {
+ if ($in_chassis_range && ($line =~ /<\/dependents>/)) {
last;
} else {
print OFILE "$line\n";
}
}
-print OFILE " <!--xml-gen internal storage-->\n";
-printf OFILE " <range name='bay' min='0' max='%d'>\n", $sys_supported->{"num_bays"};
+
+print OFILE " <!--xml-gen internal storage-->\n";
+printf OFILE " <range name='bay' min='0' max='%d'>\n",
+ $sys_supported->{"num_bays"}-1;
+
calc_nodes(0);
-printf OFILE " <dependents grouping='children'>\n";
-printf OFILE " <range name='disk' min='0'";
-printf OFILE " max='1'>\n";
-printf OFILE " <enum-method name='disk'";
-printf OFILE " version='1' />\n";
-printf OFILE " </range>\n";
-printf OFILE " </dependents>\n";
-printf OFILE "\n";
-printf OFILE " </range>\n";
+printf OFILE " <dependents grouping='children'>\n";
+printf OFILE " <range name='disk' min='0' max='0'>\n";
+printf OFILE " <enum-method name='disk' version='1' />\n";
+printf OFILE " </range>\n";
+printf OFILE " </dependents>\n\n";
+printf OFILE " </range>\n";
+
print OFILE "$line\n";
while ($line = <IFILE>) {
print OFILE $line;
diff --git a/usr/src/lib/fm/topo/modules/Makefile.plugin b/usr/src/lib/fm/topo/modules/Makefile.plugin
index fd459b0bb5..9ceaf85f45 100644
--- a/usr/src/lib/fm/topo/modules/Makefile.plugin
+++ b/usr/src/lib/fm/topo/modules/Makefile.plugin
@@ -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.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -37,9 +37,11 @@ include ../../../../../Makefile.lib
# Set PROG and OBJS based on the values of MODULE and SRCS. We expect that
# these macros to be defined by the Makefile that is including this file.
#
-SRCS = $(MODULESRCS:%.c=%.c)
+# SHAREDSRCS is used to share sources between multiple libtopo modules.
+#
+SRCS = $(MODULESRCS:%.c=%.c) $(SHAREDSRCS:%.c=../../common/$(SHAREDMODULE)/%.c)
PROG = $(MODULE:%=%.so)
-OBJS = $(SRCS:%.c=%.o)
+OBJS = $(MODULESRCS:%.c=%.o) $(SHAREDSRCS:%.c=%.o)
#
# Set ROOTPROG and ROOTCONF based on the values of MODULE, CLASS, and PLATFORMS
@@ -84,6 +86,10 @@ $(PROG): $(OBJS) $(APIMAP)
$(COMPILE.c) $<
$(CTFCONVERT_O)
+%.o: ../../common/$(SHAREDMODULE)/%.c
+ $(COMPILE.c) $<
+ $(CTFCONVERT_O)
+
%.o: %.c
$(COMPILE.c) $<
$(CTFCONVERT_O)
diff --git a/usr/src/lib/fm/topo/modules/common/disk/Makefile b/usr/src/lib/fm/topo/modules/common/disk/Makefile
index 49002147c7..b4821a6a82 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/Makefile
+++ b/usr/src/lib/fm/topo/modules/common/disk/Makefile
@@ -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"
@@ -27,7 +27,7 @@
MODULE = disk
CLASS = common
-MODULESRCS = disk.c
+MODULESRCS = disk.c disk_common.c
include ../../Makefile.plugin
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk.c b/usr/src/lib/fm/topo/modules/common/disk/disk.c
index 8253eabb9c..c248e90553 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk.c
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk.c
@@ -18,9 +18,8 @@
*
* 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"
@@ -37,667 +36,103 @@
#include <sys/fm/protocol.h>
#include "disk.h"
-static int disk_status(topo_mod_t *, tnode_t *, topo_version_t,
- nvlist_t *, nvlist_t **);
-
-/*
- * Given a /devices path for a whole disk, appending this extension gives the
- * path to a raw device that can be opened.
- */
-#if defined(__i386) || defined(__amd64)
-#define PHYS_EXTN ":q,raw"
-#elif defined(__sparc) || defined(__sparcv9)
-#define PHYS_EXTN ":c,raw"
-#else
-#error Unknown architecture
-#endif
-
static int disk_enum(topo_mod_t *, tnode_t *, const char *,
topo_instance_t, topo_instance_t, void *, void *);
static const topo_modops_t disk_ops =
{ disk_enum, NULL };
-const topo_modinfo_t disk_info =
+static const topo_modinfo_t disk_info =
{DISK, FM_FMRI_SCHEME_HC, DISK_VERSION, &disk_ops};
-static const topo_pgroup_info_t io_pgroup =
- { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
-
-static const topo_pgroup_info_t disk_auth_pgroup = {
- FM_FMRI_AUTHORITY,
- TOPO_STABILITY_PRIVATE,
- TOPO_STABILITY_PRIVATE,
-};
-
-static const topo_pgroup_info_t storage_pgroup = {
- TOPO_STORAGE_PGROUP,
- TOPO_STABILITY_PRIVATE,
- TOPO_STABILITY_PRIVATE,
- 1
-};
-
-/*
- * Methods for disks. This is used by the disk-transport module to
- * generate ereports based off SCSI disk status.
- */
-static const topo_method_t disk_methods[] = {
- { TOPO_METH_DISK_STATUS, TOPO_METH_DISK_STATUS_DESC,
- TOPO_METH_DISK_STATUS_VERSION, TOPO_STABILITY_INTERNAL,
- disk_status },
- { NULL }
-};
-static di_devlink_handle_t devlink_hdl = NULL;
-
-/* disk node information */
-typedef struct disk_di_node {
- topo_list_t ddn_list;
- int ddn_instance;
- char *ddn_devid;
- di_node_t ddn_node;
- char *ddn_lpath; /* logical path */
- char *ddn_dpath; /* device path */
-}disk_di_node_t;
-
-typedef struct disk_di_nodes {
- pthread_mutex_t disk_di_nodes_lock;
- topo_list_t disk_di_nodes_list;
-}disk_di_nodes_t;
-
-/* list of devices */
-static disk_di_nodes_t disk_di_nodes;
-
-/* given a device find it in the global device list */
-static disk_di_node_t *
-disk_di_node_match_device(char *device)
-{
- disk_di_node_t *dnode;
-
- (void) pthread_mutex_lock(&disk_di_nodes.disk_di_nodes_lock);
- for (dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list));
- dnode != NULL; dnode = topo_list_next(dnode)) {
- if (dnode->ddn_devid != NULL &&
- strcmp(device,
- dnode->ddn_dpath) == 0) {
- (void) pthread_mutex_unlock(
- &disk_di_nodes.disk_di_nodes_lock);
- return (dnode);
- }
- }
- (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock);
- return (NULL);
-}
-
-/* get the disk storage group information */
-static void
-disk_storage_info(topo_mod_t *mod, disk_di_node_t *dnode,
- char **model, char **manuf, char **serial, char **firm, char **cap)
-{
- char *entry;
- di_node_t node = dnode->ddn_node;
- int64_t *nblocksp;
- uint64_t nblocks;
- int *dblksizep;
- uint_t dblksize;
- char lentry[MAXPATHLEN];
-
- if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
- INQUIRY_VENDOR_ID, &entry) > 0) {
- *manuf = topo_mod_strdup(mod, entry);
- }
- if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
- INQUIRY_PRODUCT_ID, &entry) > 0) {
- *model = topo_mod_strdup(mod, entry);
- }
- if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
- INQUIRY_REVISION_ID, &entry) > 0) {
- *firm = topo_mod_strdup(mod, entry);
- }
- if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
- INQUIRY_SERIAL_NO, &entry) > 0) {
- *serial = topo_mod_strdup(mod, entry);
- }
- if (di_prop_lookup_int64(DDI_DEV_T_ANY, node,
- "device-nblocks", &nblocksp) > 0) {
- nblocks = (uint64_t)*nblocksp;
- /*
- * To save kernel memory, the driver may not
- * define "device-dblksize" when its value is
- * the default DEV_BSIZE value.
- */
- if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
- "device-dblksize", &dblksizep) > 0)
- dblksize = (uint_t)*dblksizep;
- else
- dblksize = DEV_BSIZE; /* default value */
- (void) snprintf(lentry, sizeof (lentry),
- "%" PRIu64, nblocks * dblksize);
- *cap = topo_mod_strdup(mod, lentry);
- }
-}
-
-/* populate the protocol group properties */
-static void
-disk_set_proto_props(topo_mod_t *mod, tnode_t *dtn, int pinst)
-{
- int err;
- nvlist_t *asru = NULL;
- char label[32];
- char *func = "disk_set_proto_props";
- nvlist_t *fmri;
- disk_di_node_t *dnode;
-
- /* set the asru */
- dnode = topo_node_getspecific(dtn);
- asru = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION,
- dnode->ddn_dpath, dnode->ddn_devid);
- if (topo_node_asru_set(dtn, asru, 0, &err) != 0) {
- topo_mod_dprintf(mod,
- "%s: topo_node_asru_set error %d\n",
- func, err);
- nvlist_free(asru);
- (void) topo_mod_seterrno(mod, err);
- return;
- }
- nvlist_free(asru);
-
- (void) snprintf(label, sizeof (label), "HD_ID_%d", pinst);
- if (topo_node_label_set(dtn, label, &err) != 0) {
- topo_mod_dprintf(mod, "%s: label error %s\n", func,
- topo_strerror(err));
- (void) topo_mod_seterrno(mod, err);
- return;
- }
-
- /* get the resource property */
- if (topo_node_resource(dtn, &fmri, &err) != 0) {
- topo_mod_dprintf(mod,
- "%s: topo_node_resource error: %s\n", func,
- topo_strerror(err));
- (void) topo_mod_seterrno(mod, err);
- return;
- }
-
- /* set the child fru to the same as the resource */
- if (topo_node_fru_set(dtn, fmri, 0, &err) != 0) {
- topo_mod_dprintf(mod,
- "%s: topo_node_fru_set error: %s\n", func,
- topo_strerror(err));
- (void) topo_mod_seterrno(mod, err);
- nvlist_free(fmri);
- return;
- }
- nvlist_free(fmri);
-}
-
-
-/*
- * Set the properties of the disk node which include:
- * group: protocol properties: resource, asru, label, fru
- * group: authority properties: product-id, chasis-id, server-id
- * group: io properties: devfs-path
- * group: storage properties:
- * - logical-disk, disk-model, disk-manufacturer, serial-number
- * - firmware-revision, capacity-in-bytes
- */
-static void
-disk_set_props(tnode_t *dtn, tnode_t *parent, char *model, char *manuf,
- char *serial, char *firm, char *cap, int *err, topo_mod_t *mod)
-{
- char *device;
- char *ptr, *ptr1;
- int inst = topo_node_instance(parent);
- disk_di_node_t *dnode;
-
- dnode = topo_node_getspecific(dtn);
-
- /* set the protocol group properties */
- disk_set_proto_props(mod, dtn, inst);
-
- /* create/set the authority group */
- if (topo_pgroup_create(dtn, &disk_auth_pgroup, err) == 0) {
- (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY,
- FM_FMRI_AUTH_PRODUCT, err);
- (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY,
- FM_FMRI_AUTH_CHASSIS, err);
- (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY,
- FM_FMRI_AUTH_SERVER, err);
- }
-
- /* create/set the devfs-path in the io group */
- (void) topo_pgroup_create(dtn, &io_pgroup, err);
-
- if (topo_prop_get_string(parent, TOPO_BINDING_PGROUP,
- TOPO_BINDING_OCCUPANT, &device, err) == 0) {
- (void) topo_prop_set_string(dtn, TOPO_PGROUP_IO,
- TOPO_IO_DEV_PATH, TOPO_PROP_IMMUTABLE, device, err);
-
- topo_mod_strfree(mod, device);
- }
-
- /* create the storage group */
- (void) topo_pgroup_create(dtn, &storage_pgroup, err);
-
- /* set the storage group properties */
- ptr = strrchr(dnode->ddn_lpath, '/');
- ptr1 = strchr(ptr, 's');
- if (ptr1)
- *ptr1 = '\0';
- (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP,
- TOPO_STORAGE_LOGICAL_DISK_NAME, TOPO_PROP_IMMUTABLE,
- ptr+1, err);
- if (ptr1)
- *ptr1 = 's';
-
-
- /* populate the storage group properties */
- if (model) {
- (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP,
- TOPO_STORAGE_MODEL, TOPO_PROP_IMMUTABLE, model, err);
- }
- if (manuf) {
- (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP,
- TOPO_STORAGE_MANUFACTURER, TOPO_PROP_IMMUTABLE, manuf,
- err);
- }
- if (serial) {
- (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP,
- TOPO_STORAGE_SERIAL_NUM, TOPO_PROP_IMMUTABLE, serial, err);
- }
- if (firm) {
- (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP,
- TOPO_STORAGE_FIRMWARE_REV, TOPO_PROP_IMMUTABLE, firm, err);
- }
- if (cap) {
- (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP,
- TOPO_STORAGE_CAPACITY, TOPO_PROP_IMMUTABLE, cap, err);
- }
-}
-
-/* create the disk topo node */
-/*ARGSUSED*/
-static tnode_t *
-disk_tnode_create(topo_mod_t *mod, tnode_t *parent,
- const char *name, topo_instance_t i, char *model, char *manuf,
- char *serial, char *firm, char *cap, void *priv)
-{
- int err, len = 0;
- nvlist_t *fmri;
- tnode_t *dtn;
- char *mm = NULL;
- char *s;
- nvlist_t *auth = topo_mod_auth(mod, parent);
-
- if ((s = strchr(model, ' ')) != NULL) {
- *s = '-';
- }
- len = strlen(manuf) + strlen(model) + 2;
- if ((mm = topo_mod_alloc(mod, len)) != NULL)
- (void) snprintf(mm, len, "%s-%s", manuf, model);
- else
- mm = model;
-
- fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i,
- NULL, auth, mm, firm, serial);
-
- nvlist_free(auth);
-
- if (mm != model)
- topo_mod_free(mod, mm, len);
- else if (*s != NULL)
- *s = ' ';
-
- if (fmri == NULL) {
- topo_mod_dprintf(mod,
- "Unable to make nvlist for %s bind: %s.\n",
- name, topo_mod_errmsg(mod));
- return (NULL);
- }
-
- if ((dtn = topo_node_bind(mod, parent, name, i, fmri)) == NULL) {
- topo_mod_dprintf(mod,
- "topo_node_bind (%s%d/%s%d) failed: %s\n",
- topo_node_name(parent), topo_node_instance(parent),
- name, i,
- topo_strerror(topo_mod_errno(mod)));
- nvlist_free(fmri);
- return (NULL);
- }
- nvlist_free(fmri);
- topo_node_setspecific(dtn, priv);
-
- /* add the properties of the disk */
- disk_set_props(dtn, parent, model, manuf, serial, firm, cap,
- &err, mod);
-
- return (dtn);
-}
-
-/*ARGSUSED*/
-static tnode_t *
-disk_declare(tnode_t *parent, const char *name, topo_instance_t i,
- void *priv, topo_mod_t *mod)
-{
- tnode_t *dtn;
- int err;
- char *func = "disk_declare";
- char *model = NULL, *manuf = NULL, *serial = NULL;
- char *cap = NULL, *firm = NULL;
- disk_di_node_t *dnode = (disk_di_node_t *)priv;
- nvlist_t *fmri;
-
- disk_storage_info(mod, dnode,
- &model, &manuf, &serial, &firm, &cap);
-
- /* create the node */
- dtn = disk_tnode_create(mod, parent,
- name, i, model, manuf, serial, firm, cap, priv);
-
- topo_mod_strfree(mod, model);
- topo_mod_strfree(mod, manuf);
- topo_mod_strfree(mod, serial);
- topo_mod_strfree(mod, firm);
- topo_mod_strfree(mod, cap);
-
- if (dtn == NULL) {
- return (NULL);
- }
-
- /* set the parent fru */
- if (topo_node_resource(parent, &fmri, &err) != 0) {
- topo_mod_dprintf(mod,
- "%s: topo_node_resource error: %s\n", func,
- topo_strerror(err));
- topo_node_unbind(dtn);
- return (NULL);
- }
- if (topo_node_fru_set(parent, fmri, 0, &err) != 0) {
- topo_mod_dprintf(mod, "%s topo_node_fru error: %s\n",
- func, topo_strerror(err));
- nvlist_free(fmri);
- topo_node_unbind(dtn);
- return (NULL);
- }
-
- if (topo_method_register(mod, dtn, disk_methods) != 0) {
- topo_mod_dprintf(mod,
- "topo_method_register failed: %s\n",
- topo_strerror(topo_mod_errno(mod)));
- nvlist_free(fmri);
- topo_node_unbind(dtn);
- return (NULL);
- }
-
- nvlist_free(fmri);
-
- return (dtn);
-}
-
/*ARGSUSED*/
static int
-disk_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
- topo_instance_t min, topo_instance_t max, void *arg, void *notused)
+disk_enum(topo_mod_t *mod, tnode_t *baynode,
+ const char *name, topo_instance_t min, topo_instance_t max,
+ void *arg, void *notused)
{
- tnode_t *diskn;
char *device;
int err;
- disk_di_node_t *dnode;
+ nvlist_t *fmri;
+ topo_list_t *dlistp = topo_mod_getspecific(mod);
if (strcmp(name, DISK) != 0) {
- topo_mod_dprintf(mod,
- "Currently only know how to enumerate %s components.\n",
- DISK);
+ topo_mod_dprintf(mod, "disk_enum: "
+ "only know how to enumerate %s components.\n", DISK);
return (-1);
}
- if (topo_prop_get_string(rnode, TOPO_BINDING_PGROUP,
- TOPO_BINDING_OCCUPANT, &device, &err) != 0)
- return (-1);
-
- if ((dnode = disk_di_node_match_device(device)) == NULL) {
- topo_mod_dprintf(mod,
- "No occupant found for bay=%d.\n",
- topo_node_instance(rnode));
- topo_mod_strfree(mod, device);
+ /* set the parent fru */
+ if (topo_node_resource(baynode, &fmri, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_enum: "
+ "topo_node_resource error %s\n", topo_strerror(err));
return (-1);
}
-
- diskn = disk_declare(rnode, name, 0, dnode, mod);
- if (diskn == NULL) {
- topo_mod_dprintf(mod, "Enumeration of %s failed: %s\n",
- DISK, topo_strerror(topo_mod_errno(mod)));
- topo_mod_strfree(mod, device);
- return (-1); /* mod_errno already set */
+ if (topo_node_fru_set(baynode, fmri, 0, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_enum: "
+ "topo_node_fru error %s\n", topo_strerror(err));
+ nvlist_free(fmri);
+ return (-1);
}
- topo_mod_strfree(mod, device);
- return (0);
-}
-
-/*
- * Query the current disk status. If successful, the disk status is returned as
- * an nvlist consisting of at least the following members:
- *
- * protocol string Supported protocol (currently "scsi")
- *
- * status nvlist Arbitrary protocol-specific information
- * about the current state of the disk.
- *
- * faults nvlist A list of supported faults. Each
- * element of this list is a boolean value.
- * An element's existence indicates that
- * the drive supports detecting this fault,
- * and the value indicates the current
- * state of the fault.
- *
- * <fault-name> nvlist For each fault named in 'faults', a
- * nvlist describing protocol-specific
- * attributes of the fault.
- *
- * This method relies on the libdiskstatus library to query this information.
- */
-static int
-disk_status(topo_mod_t *mod, tnode_t *nodep, topo_version_t vers,
- nvlist_t *in_nvl, nvlist_t **out_nvl)
-{
- disk_status_t *dsp;
- char *devpath, *fullpath;
- size_t pathlen;
- int err;
- nvlist_t *status;
- *out_nvl = NULL;
-
- if (vers != TOPO_METH_DISK_STATUS_VERSION)
- return (topo_mod_seterrno(mod, EMOD_VER_NEW));
+ nvlist_free(fmri);
/*
- * If the caller specifies the "path" parameter, then this indicates
- * that we should use this instead of deriving it from the topo node
- * itself.
+ * For internal storage, get the path to the occupant from the
+ * binding group of the bay node
*/
- if (nvlist_lookup_string(in_nvl, "path", &fullpath) == 0) {
- devpath = NULL;
- } else {
- /*
- * Get the /devices path and attempt to open the disk status
- * handle.
- */
- if (topo_prop_get_string(nodep, TOPO_PGROUP_IO,
- TOPO_IO_DEV_PATH, &devpath, &err) != 0)
- return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP));
-
- /*
- * Note that sizeof(string) includes the terminating NULL byte
- */
- pathlen = strlen(devpath) + sizeof ("/devices") +
- sizeof (PHYS_EXTN) - 1;
-
- if ((fullpath = topo_mod_alloc(mod, pathlen)) == NULL)
- return (topo_mod_seterrno(mod, EMOD_NOMEM));
-
- (void) snprintf(fullpath, pathlen, "/devices%s%s", devpath,
- PHYS_EXTN);
-
- topo_mod_strfree(mod, devpath);
- }
-
- if ((dsp = disk_status_open(fullpath, &err)) == NULL) {
- if (devpath)
- topo_mod_free(mod, fullpath, pathlen);
- return (topo_mod_seterrno(mod, err == EDS_NOMEM ?
- EMOD_NOMEM : EMOD_METHOD_NOTSUP));
- }
-
- if (devpath)
- topo_mod_free(mod, fullpath, pathlen);
-
- if ((status = disk_status_get(dsp)) == NULL) {
- err = (disk_status_errno(dsp) == EDS_NOMEM ?
- EMOD_NOMEM : EMOD_METHOD_NOTSUP);
- disk_status_close(dsp);
- return (topo_mod_seterrno(mod, err));
- }
-
- *out_nvl = status;
- disk_status_close(dsp);
- return (0);
-}
-
-/* di_devlink callback for disk_drvinst2devpath */
-static int
-disk_drvinst2devpath_devlink_callback(di_devlink_t dl, void *arg)
-{
- char **devpathp = (char **)arg;
- char *devpath = (char *)di_devlink_path(dl);
-
- *devpathp = strdup(devpath);
- return (DI_WALK_TERMINATE);
-}
-
-static disk_di_node_t *
-disk_di_node_add(int *instancep, char *devid, di_node_t node, topo_mod_t *mod)
-{
- int mlen;
- char *devpath, *minorpath;
- char *extn = ":a";
- disk_di_node_t *dnode;
-
- (void) pthread_mutex_lock(&(disk_di_nodes.disk_di_nodes_lock));
- for (dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list));
- dnode != NULL; dnode = topo_list_next(dnode)) {
- if (strcmp(dnode->ddn_devid, devid) == 0) {
- topo_mod_dprintf(mod,
- "disk_node_add - already there %s\n", devid);
- (void) pthread_mutex_unlock(
- &disk_di_nodes.disk_di_nodes_lock);
- return (dnode); /* return existing node */
- }
- }
-
- if ((dnode = topo_mod_alloc(mod, sizeof (disk_di_node_t))) == NULL) {
- topo_mod_dprintf(mod,
- "disk_node_add - topo_mod_alloc failed\n");
- (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock);
- return (NULL); /* return existing node */
+ if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING,
+ TOPO_BINDING_OCCUPANT, &device, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_enum: "
+ "binding error %s\n", topo_strerror(err));
+ return (-1);
}
- dnode->ddn_devid = strdup(devid);
- dnode->ddn_instance = *instancep;
- dnode->ddn_node = node;
- dnode->ddn_dpath = di_devfs_path(node);
-
- mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1;
- minorpath = topo_mod_alloc(mod, mlen);
- (void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath,
- extn);
- /* walk devlink looking for node that maps to /device path */
- devpath = NULL;
- (void) di_devlink_walk(devlink_hdl, "^dsk/",
- minorpath, DI_PRIMARY_LINK,
- (void *)&devpath, disk_drvinst2devpath_devlink_callback);
- topo_mod_free(mod, minorpath, mlen);
- dnode->ddn_lpath = devpath;
-
- topo_list_append(&disk_di_nodes.disk_di_nodes_list, (void *)dnode);
- (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock);
-
- topo_mod_dprintf(mod,
- "disk_node_add - adding %s inst: %d\n",
- dnode->ddn_devid, *instancep);
- *instancep = (*instancep) + 1;
- return (dnode);
-}
-
-/*ARGSUSED*/
-static int
-disk_walk_di_nodes(di_node_t node, void *arg)
-{
- ddi_devid_t devid = NULL;
- char *devidstr;
- static int instance_devid = 0;
- topo_mod_t *mod = (topo_mod_t *)arg;
- /* only interested in nodes that have devids */
- devid = (ddi_devid_t)di_devid(node);
- if (devid == NULL)
- return (DI_WALK_CONTINUE);
+ /* locate and topo enumerate the disk with that path */
+ err = disk_declare_path(mod, baynode, dlistp, device);
- /* ... with a string representation of the devid */
- devidstr = devid_str_encode(devid, NULL);
- if (devidstr == NULL)
- return (DI_WALK_CONTINUE);
-
- /* create/find the devid scsi topology node */
- (void) disk_di_node_add(&instance_devid, devidstr, node, mod);
- devid_str_free(devidstr);
- return (DI_WALK_CONTINUE);
+ topo_mod_strfree(mod, device);
+ return (err);
}
/*ARGSUSED*/
int
_topo_init(topo_mod_t *mod, topo_version_t version)
{
- di_node_t devtree;
+ topo_list_t *dlistp;
/*
* Turn on module debugging output
*/
if (getenv("TOPODISKDEBUG") != NULL)
topo_mod_setdebug(mod);
- topo_mod_dprintf(mod, "initializing %s enumerator\n", DISK);
+ topo_mod_dprintf(mod, "_topo_init: "
+ "initializing %s enumerator\n", DISK);
if (topo_mod_register(mod, &disk_info, TOPO_VERSION) != 0) {
- topo_mod_dprintf(mod, "%s registration failed: %s\n",
- DISK, topo_mod_errmsg(mod));
- return (-1); /* mod errno already set */
+ topo_mod_dprintf(mod, "_topo_init: "
+ "%s registration failed: %s\n", DISK, topo_mod_errmsg(mod));
+ return (-1); /* mod errno already set */
}
- (void) pthread_mutex_init(&disk_di_nodes.disk_di_nodes_lock, NULL);
- disk_di_nodes.disk_di_nodes_list.l_next = NULL;
- disk_di_nodes.disk_di_nodes_list.l_prev = NULL;
-
- devtree = di_init("/", DINFOCACHE);
- /* we don't get all the nodes with topo_mod_devinfo */
- if (devtree == NULL) {
- topo_mod_unregister(mod);
- (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock);
- topo_mod_dprintf(mod, "topo_mod_devinfo init failed.");
+ if ((dlistp = topo_mod_zalloc(mod, sizeof (topo_list_t))) == NULL) {
+ topo_mod_dprintf(mod, "_topo_inti: failed to allocate "
+ "disk list");
return (-1);
}
- /* walk the tree to get the devids */
- devlink_hdl = di_devlink_init(NULL, 0);
- if (devlink_hdl == DI_NODE_NIL) {
+
+ if (disk_list_gather(mod, dlistp) != 0) {
topo_mod_unregister(mod);
- (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock);
- topo_mod_dprintf(mod, "di_devlink init failed.");
+ topo_mod_free(mod, dlistp, sizeof (topo_list_t));
+ topo_mod_dprintf(mod, "_topo_init: "
+ "failed to locate disks");
return (-1);
}
- (void) di_walk_node(devtree, DI_WALK_CLDFIRST, mod,
- disk_walk_di_nodes);
- if (devlink_hdl != NULL)
- (void) di_devlink_fini(&devlink_hdl);
+ topo_mod_dprintf(mod, "_topo_init: "
+ "%s enumerator initialized\n", DISK);
- topo_mod_dprintf(mod, "%s enumerator initialized\n", DISK);
+ topo_mod_setspecific(mod, dlistp);
return (0);
}
@@ -705,19 +140,10 @@ _topo_init(topo_mod_t *mod, topo_version_t version)
void
_topo_fini(topo_mod_t *mod)
{
- disk_di_node_t *dnode;
-
- (void) pthread_mutex_lock(&disk_di_nodes.disk_di_nodes_lock);
- while ((dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list)))
- != NULL) {
- free(dnode->ddn_lpath);
- free(dnode->ddn_dpath);
- free(dnode->ddn_devid);
- topo_list_delete(&(disk_di_nodes.disk_di_nodes_list),
- (void *)dnode);
- topo_mod_free(mod, dnode, sizeof (disk_di_node_t));
- }
- (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock);
- (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock);
+ topo_list_t *dlistp = topo_mod_getspecific(mod);
+ disk_list_free(mod, dlistp);
+ topo_mod_free(mod, dlistp, sizeof (topo_list_t));
topo_mod_unregister(mod);
+ topo_mod_dprintf(mod, "_topo_fini: "
+ "%s enumerator uninitialized\n", DISK);
}
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk.h b/usr/src/lib/fm/topo/modules/common/disk/disk.h
index 2968c3663a..8596945b26 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk.h
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk.h
@@ -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.
*/
@@ -29,6 +29,9 @@
#pragma ident "%Z%%M% %I% %E% SMI"
+#include <fm/topo_mod.h>
+#include <libdevinfo.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -39,12 +42,8 @@ extern "C" {
/* Max. number of devices for thumper */
#define DEVID_MAX 48
-/* Properties for binding group */
-#define TOPO_BINDING_PGROUP "binding"
-#define TOPO_BINDING_OCCUPANT "occupant-path"
-
/* Properties added to the "storage" pgroup: */
-#define TOPO_STORAGE_PGROUP "storage"
+#define TOPO_PGROUP_STORAGE "storage"
#define TOPO_STORAGE_LOGICAL_DISK_NAME "logical-disk"
#define TOPO_STORAGE_MODEL "model"
#define TOPO_STORAGE_MANUFACTURER "manufacturer"
@@ -52,6 +51,23 @@ extern "C" {
#define TOPO_STORAGE_FIRMWARE_REV "firmware-revision"
#define TOPO_STORAGE_CAPACITY "capacity-in-bytes"
+/*
+ * Properties for binding group: The binding group required in platform
+ * specific xml that describes 'bay' nodes containing internal disks.
+ */
+#define TOPO_PGROUP_BINDING "binding"
+#define TOPO_BINDING_OCCUPANT "occupant-path"
+
+struct topo_list;
+
+/* Methods shared with the ses module (disk_common.c) */
+extern int disk_list_gather(topo_mod_t *, struct topo_list *);
+extern void disk_list_free(topo_mod_t *, struct topo_list *);
+extern int disk_declare_path(topo_mod_t *, tnode_t *,
+ struct topo_list *, const char *);
+extern int disk_declare_addr(topo_mod_t *, tnode_t *,
+ struct topo_list *, const char *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
new file mode 100644
index 0000000000..3cc6651d7e
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
@@ -0,0 +1,868 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Functions in this file are shared between the disk and ses enumerators.
+ *
+ * A topo_list_t of all disks is returned by a successful disk_list_gather()
+ * call, and the list is freed by a disk_list_free(). To create a 'disk' topo
+ * node below a specific 'bay' parent node either disk_declare_path() or
+ * disk_declare_addr() are called. The caller determines which 'disk' is
+ * in which 'bay'. A disk's 'label' and 'authority' information come from
+ * its parent 'bay' node.
+ */
+
+#include <strings.h>
+#include <libdevinfo.h>
+#include <devid.h>
+#include <sys/libdevid.h>
+#include <pthread.h>
+#include <inttypes.h>
+#include <sys/dkio.h>
+#include <sys/scsi/scsi_types.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_list.h>
+#include <fm/libdiskstatus.h>
+#include <sys/fm/protocol.h>
+#include "disk.h"
+
+/*
+ * disk node information.
+ */
+typedef struct disk_di_node {
+ topo_list_t ddn_list; /* list of disks */
+
+ /* the following two fields are always defined */
+ char *ddn_devid; /* devid of disk */
+ char *ddn_dpath; /* path to devinfo (may be vhci) */
+ char **ddn_ppath; /* physical path to device (phci) */
+ int ddn_ppath_count;
+
+ char *ddn_lpath; /* logical path (public /dev name) */
+
+ char *ddn_mfg; /* misc information about device */
+ char *ddn_model;
+ char *ddn_serial;
+ char *ddn_firm;
+ char *ddn_cap;
+
+ char **ddn_target_port;
+ int ddn_target_port_count;
+} disk_di_node_t;
+
+/* common callback information for di_walk_node() and di_devlink_walk */
+typedef struct disk_cbdata {
+ topo_mod_t *dcb_mod;
+ topo_list_t *dcb_list;
+
+ di_devlink_handle_t dcb_devhdl;
+ disk_di_node_t *dcb_dnode; /* for di_devlink_walk only */
+} disk_cbdata_t;
+
+/*
+ * Given a /devices path for a whole disk, appending this extension gives the
+ * path to a raw device that can be opened.
+ */
+#if defined(__i386) || defined(__amd64)
+#define PHYS_EXTN ":q,raw"
+#elif defined(__sparc) || defined(__sparcv9)
+#define PHYS_EXTN ":c,raw"
+#else
+#error Unknown architecture
+#endif
+
+/*
+ * Methods for disks. This is used by the disk-transport module to
+ * generate ereports based off SCSI disk status.
+ */
+static int disk_status(topo_mod_t *, tnode_t *, topo_version_t,
+ nvlist_t *, nvlist_t **);
+
+static const topo_method_t disk_methods[] = {
+ { TOPO_METH_DISK_STATUS, TOPO_METH_DISK_STATUS_DESC,
+ TOPO_METH_DISK_STATUS_VERSION, TOPO_STABILITY_INTERNAL,
+ disk_status },
+ { NULL }
+};
+
+static const topo_pgroup_info_t io_pgroup = {
+ TOPO_PGROUP_IO,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+static const topo_pgroup_info_t disk_auth_pgroup = {
+ FM_FMRI_AUTHORITY,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+static const topo_pgroup_info_t storage_pgroup = {
+ TOPO_PGROUP_STORAGE,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+/*
+ * Set the properties of the disk node, from disk_di_node_t data.
+ * Properties include:
+ * group: protocol properties: resource, asru, label, fru
+ * group: authority properties: product-id, chasis-id, server-id
+ * group: io properties: devfs-path, devid
+ * group: storage properties:
+ * - logical-disk, disk-model, disk-manufacturer, serial-number
+ * - firmware-revision, capacity-in-bytes
+ */
+static int
+disk_set_props(topo_mod_t *mod, tnode_t *parent,
+ tnode_t *dtn, disk_di_node_t *dnode)
+{
+ nvlist_t *asru = NULL;
+ char *label = NULL;
+ nvlist_t *fmri = NULL;
+ int err;
+
+ /* form and set the asru */
+ if ((asru = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION,
+ dnode->ddn_dpath, dnode->ddn_devid)) == NULL) {
+ err = ETOPO_FMRI_UNKNOWN;
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "asru error %s\n", topo_strerror(err));
+ goto error;
+ }
+ if (topo_node_asru_set(dtn, asru, 0, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "asru_set error %s\n", topo_strerror(err));
+ goto error;
+ }
+
+ /* pull the label property down from our parent 'bay' node */
+ if (topo_node_label(parent, &label, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "label error %s\n", topo_strerror(err));
+ goto error;
+ }
+ if (topo_node_label_set(dtn, label, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "label_set error %s\n", topo_strerror(err));
+ goto error;
+ }
+
+ /* get the resource fmri, and use it as the fru */
+ if (topo_node_resource(dtn, &fmri, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "resource error: %s\n", topo_strerror(err));
+ goto error;
+ }
+ if (topo_node_fru_set(dtn, fmri, 0, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "fru_set error: %s\n", topo_strerror(err));
+ goto error;
+ }
+
+ /* create/set the authority group */
+ if ((topo_pgroup_create(dtn, &disk_auth_pgroup, &err) != 0) &&
+ (err != ETOPO_PROP_DEFD)) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "create disk_auth error %s\n", topo_strerror(err));
+ goto error;
+ }
+
+ /* create/set the devfs-path and devid in the io group */
+ if (topo_pgroup_create(dtn, &io_pgroup, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "create io error %s\n", topo_strerror(err));
+ goto error;
+ }
+
+ if (topo_prop_set_string(dtn, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
+ TOPO_PROP_IMMUTABLE, dnode->ddn_dpath, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "set dev error %s\n", topo_strerror(err));
+ goto error;
+ }
+
+ if (topo_prop_set_string(dtn, TOPO_PGROUP_IO, TOPO_IO_DEVID,
+ TOPO_PROP_IMMUTABLE, dnode->ddn_devid, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "set devid error %s\n", topo_strerror(err));
+ goto error;
+ }
+
+ if (dnode->ddn_ppath_count != 0 &&
+ topo_prop_set_string_array(dtn, TOPO_PGROUP_IO, TOPO_IO_PHYS_PATH,
+ TOPO_PROP_IMMUTABLE, (const char **)dnode->ddn_ppath,
+ dnode->ddn_ppath_count, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "set phys-path error %s\n", topo_strerror(err));
+ goto error;
+ }
+
+ /* create the storage group */
+ if (topo_pgroup_create(dtn, &storage_pgroup, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "create storage error %s\n", topo_strerror(err));
+ goto error;
+ }
+
+ /* set the storage group public /dev name */
+ if (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_LOGICAL_DISK_NAME, TOPO_PROP_IMMUTABLE,
+ dnode->ddn_lpath, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "set disk_name error %s\n", topo_strerror(err));
+ goto error;
+ }
+
+ /* populate other misc storage group properties */
+ if (dnode->ddn_mfg && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_MANUFACTURER, TOPO_PROP_IMMUTABLE,
+ dnode->ddn_mfg, &err) != 0)) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "set mfg error %s\n", topo_strerror(err));
+ goto error;
+ }
+ if (dnode->ddn_model && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_MODEL, TOPO_PROP_IMMUTABLE,
+ dnode->ddn_model, &err) != 0)) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "set model error %s\n", topo_strerror(err));
+ goto error;
+ }
+ if (dnode->ddn_serial && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_SERIAL_NUM, TOPO_PROP_IMMUTABLE,
+ dnode->ddn_serial, &err) != 0)) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "set serial error %s\n", topo_strerror(err));
+ goto error;
+ }
+ if (dnode->ddn_firm && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_FIRMWARE_REV, TOPO_PROP_IMMUTABLE,
+ dnode->ddn_firm, &err) != 0)) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "set firm error %s\n", topo_strerror(err));
+ goto error;
+ }
+ if (dnode->ddn_cap && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_CAPACITY, TOPO_PROP_IMMUTABLE,
+ dnode->ddn_cap, &err) != 0)) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "set cap error %s\n", topo_strerror(err));
+ goto error;
+ }
+ err = 0;
+
+out: if (fmri)
+ nvlist_free(fmri);
+ if (label)
+ topo_mod_strfree(mod, label);
+ if (asru)
+ nvlist_free(asru);
+ return (err);
+
+error: err = topo_mod_seterrno(mod, err);
+ goto out;
+}
+
+/* create the disk topo node */
+static tnode_t *
+disk_tnode_create(topo_mod_t *mod, tnode_t *parent,
+ disk_di_node_t *dnode, const char *name, topo_instance_t i)
+{
+ int len;
+ nvlist_t *fmri;
+ tnode_t *dtn;
+ char *part = NULL;
+ char *b = NULL;
+ nvlist_t *auth;
+
+ /* form 'part=' of fmri as "<mfg>-<model>" */
+ if (dnode->ddn_mfg && dnode->ddn_model) {
+ /* XXX replace first ' ' in the model with a '-' */
+ if ((b = strchr(dnode->ddn_model, ' ')) != NULL)
+ *b = '-';
+ len = strlen(dnode->ddn_mfg) + 1 + strlen(dnode->ddn_model) + 1;
+ if ((part = topo_mod_alloc(mod, len)) != NULL)
+ (void) snprintf(part, len, "%s-%s",
+ dnode->ddn_mfg, dnode->ddn_model);
+ }
+
+ auth = topo_mod_auth(mod, parent);
+ fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i, NULL,
+ auth, part ? part : dnode->ddn_model, dnode->ddn_firm,
+ dnode->ddn_serial);
+ nvlist_free(auth);
+
+ if (part && (part != dnode->ddn_model))
+ topo_mod_free(mod, part, len);
+ else if (b)
+ *b = ' '; /* restore blank */
+
+ if (fmri == NULL) {
+ topo_mod_dprintf(mod, "disk_tnode_create: "
+ "hcfmri (%s%d/%s%d) error %s\n",
+ topo_node_name(parent), topo_node_instance(parent),
+ name, i, topo_strerror(topo_mod_errno(mod)));
+ return (NULL);
+ }
+
+ if ((dtn = topo_node_bind(mod, parent, name, i, fmri)) == NULL) {
+ topo_mod_dprintf(mod, "disk_tnode_create: "
+ "bind (%s%d/%s%d) error %s\n",
+ topo_node_name(parent), topo_node_instance(parent),
+ name, i, topo_strerror(topo_mod_errno(mod)));
+ nvlist_free(fmri);
+ return (NULL);
+ }
+ nvlist_free(fmri);
+
+ /* add the properties of the disk */
+ if (disk_set_props(mod, parent, dtn, dnode) != 0) {
+ topo_mod_dprintf(mod, "disk_tnode_create: "
+ "disk_set_props (%s%d/%s%d) error %s\n",
+ topo_node_name(parent), topo_node_instance(parent),
+ name, i, topo_strerror(topo_mod_errno(mod)));
+ topo_node_unbind(dtn);
+ return (NULL);
+ }
+ return (dtn);
+}
+
+static int
+disk_declare(topo_mod_t *mod, tnode_t *parent, disk_di_node_t *dnode)
+{
+ tnode_t *dtn;
+
+ /* create the disk topo node: one disk per 'bay' */
+ dtn = disk_tnode_create(mod, parent, dnode, DISK, 0);
+ if (dtn == NULL) {
+ topo_mod_dprintf(mod, "disk_declare: "
+ "disk_tnode_create error %s\n",
+ topo_strerror(topo_mod_errno(mod)));
+ return (-1);
+ }
+
+ /* register disk_methods against the disk topo node */
+ if (topo_method_register(mod, dtn, disk_methods) != 0) {
+ topo_mod_dprintf(mod, "disk_declare: "
+ "topo_method_register error %s\n",
+ topo_strerror(topo_mod_errno(mod)));
+ topo_node_unbind(dtn);
+ return (-1);
+ }
+ return (0);
+}
+
+int
+disk_declare_path(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp,
+ const char *path)
+{
+ disk_di_node_t *dnode;
+ int i;
+
+ /*
+ * Check for match using physical phci (ddn_ppath). Use
+ * di_devfs_path_match so generic.vs.non-generic names match.
+ */
+ for (dnode = topo_list_next(listp); dnode != NULL;
+ dnode = topo_list_next(dnode)) {
+ if (dnode->ddn_ppath == NULL)
+ continue;
+
+ for (i = 0; i < dnode->ddn_ppath_count; i++) {
+ if (di_devfs_path_match(dnode->ddn_ppath[0], path))
+ return (disk_declare(mod, parent, dnode));
+ }
+ }
+
+ topo_mod_dprintf(mod, "disk_declare_path: "
+ "failed to find disk matching path %s", path);
+ return (0);
+}
+
+int
+disk_declare_addr(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp,
+ const char *addr)
+{
+ disk_di_node_t *dnode;
+ int i;
+
+ /* Check for match using addr. */
+ for (dnode = topo_list_next(listp); dnode != NULL;
+ dnode = topo_list_next(dnode)) {
+ if (dnode->ddn_target_port == NULL)
+ continue;
+
+ for (i = 0; i < dnode->ddn_target_port_count; i++) {
+ if (strncmp(dnode->ddn_target_port[i], addr,
+ strcspn(dnode->ddn_target_port[i], ":")) == 0)
+ return (disk_declare(mod, parent, dnode));
+ }
+ }
+
+ topo_mod_dprintf(mod, "disk_declare_addr: "
+ "failed to find disk matching addr %s", addr);
+ return (0);
+}
+
+/* di_devlink callback for disk_di_node_add */
+static int
+disk_devlink_callback(di_devlink_t dl, void *arg)
+{
+ disk_cbdata_t *cbp = (disk_cbdata_t *)arg;
+ topo_mod_t *mod = cbp->dcb_mod;
+ disk_di_node_t *dnode = cbp->dcb_dnode;
+ const char *devpath;
+ char *ctds, *slice;
+
+ devpath = di_devlink_path(dl);
+ if ((dnode == NULL) || (devpath == NULL))
+ return (DI_WALK_TERMINATE);
+
+ /* trim the slice off the public name */
+ if (((ctds = strrchr(devpath, '/')) != NULL) &&
+ ((slice = strchr(ctds, 's')) != NULL))
+ *slice = '\0';
+
+ /* Establish the public /dev name (no slice) */
+ dnode->ddn_lpath = topo_mod_strdup(mod, ctds ? ctds + 1 : devpath);
+
+ if (ctds && slice)
+ *slice = 's';
+ return (DI_WALK_TERMINATE);
+}
+
+static void
+disk_di_node_free(topo_mod_t *mod, disk_di_node_t *dnode)
+{
+ int i;
+
+ /* free the stuff we point to */
+ topo_mod_strfree(mod, dnode->ddn_devid);
+ for (i = 0; i < dnode->ddn_ppath_count; i++)
+ topo_mod_strfree(mod, dnode->ddn_ppath[i]);
+ topo_mod_free(mod, dnode->ddn_ppath,
+ dnode->ddn_ppath_count * sizeof (uintptr_t));
+ topo_mod_strfree(mod, dnode->ddn_dpath);
+ topo_mod_strfree(mod, dnode->ddn_lpath);
+
+ topo_mod_strfree(mod, dnode->ddn_mfg);
+ topo_mod_strfree(mod, dnode->ddn_model);
+ topo_mod_strfree(mod, dnode->ddn_serial);
+ topo_mod_strfree(mod, dnode->ddn_firm);
+ topo_mod_strfree(mod, dnode->ddn_cap);
+
+ for (i = 0; i < dnode->ddn_target_port_count; i++)
+ topo_mod_strfree(mod, dnode->ddn_target_port[i]);
+ topo_mod_free(mod, dnode->ddn_target_port,
+ dnode->ddn_target_port_count * sizeof (uintptr_t));
+
+ /* free self */
+ topo_mod_free(mod, dnode, sizeof (disk_di_node_t));
+}
+
+static int
+disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp)
+{
+ topo_mod_t *mod = cbp->dcb_mod;
+ disk_di_node_t *dnode;
+ di_path_t pnode;
+ char *path;
+ int mlen;
+ char *minorpath;
+ char *extn = ":a";
+ char *s;
+ int64_t *nblocksp;
+ uint64_t nblocks;
+ int *dblksizep;
+ uint_t dblksize;
+ char lentry[MAXPATHLEN];
+ int pathcount, portcount;
+ int ret, i;
+
+ /* check for list duplicate using devid search */
+ for (dnode = topo_list_next(cbp->dcb_list);
+ dnode != NULL; dnode = topo_list_next(dnode)) {
+ if (devid_str_compare(dnode->ddn_devid, devid) == 0) {
+ topo_mod_dprintf(mod, "disk_di_node_add: "
+ "already there %s\n", devid);
+ return (0);
+ }
+ }
+
+ if ((dnode = topo_mod_zalloc(mod, sizeof (disk_di_node_t))) == NULL)
+ return (-1);
+
+ /* Establish the devid. */
+ dnode->ddn_devid = topo_mod_strdup(mod, devid);
+ if (dnode->ddn_devid == NULL)
+ goto error;
+
+ /* Establish the devinfo dpath */
+ if ((path = di_devfs_path(node)) == NULL) {
+ topo_mod_seterrno(mod, errno);
+ goto error;
+ }
+
+ dnode->ddn_dpath = topo_mod_strdup(mod, path);
+ di_devfs_path_free(path);
+ if (dnode->ddn_dpath == NULL)
+ goto error;
+
+ /*
+ * Establish the physical ppath and target ports. If the device is
+ * non-mpxio then dpath and ppath are the same, and the target port is a
+ * property of the device node.
+ *
+ * If dpath is a client node under scsi_vhci, then iterate over all
+ * paths and get their physical paths and target port properrties.
+ * di_path_client_next_path call below will
+ * return non-NULL, and ppath is set to the physical path to the first
+ * pathinfo node.
+ *
+ * NOTE: It is possible to get a generic.vs.non-generic path
+ * for di_devfs_path.vs.di_path_devfs_path like:
+ * xml: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/sd@2,0
+ * pnode: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/disk@2,0
+ * To resolve this issue disk_declare_path() needs to use the
+ * special di_devfs_path_match() interface.
+ */
+ pathcount = portcount = 0;
+ pnode = NULL;
+ while ((pnode = di_path_client_next_path(node, pnode)) != NULL) {
+ if ((ret = di_path_prop_lookup_strings(pnode,
+ "target-port", &s)) > 0)
+ portcount += ret;
+ pathcount++;
+ }
+
+ if (pathcount == 0) {
+ if ((dnode->ddn_ppath =
+ topo_mod_zalloc(mod, sizeof (uintptr_t))) == NULL)
+ goto error;
+
+ dnode->ddn_ppath_count = 1;
+ if ((dnode->ddn_ppath[0] = topo_mod_strdup(mod,
+ dnode->ddn_dpath)) == NULL)
+ goto error;
+
+ if ((ret = di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+ "target-port", &s)) > 0) {
+ if ((dnode->ddn_target_port = topo_mod_zalloc(mod,
+ ret * sizeof (uintptr_t))) == NULL)
+ goto error;
+
+ dnode->ddn_target_port_count = ret;
+
+ for (i = 0; i < ret; i++) {
+ if ((dnode->ddn_target_port[i] =
+ topo_mod_strdup(mod, s)) == NULL)
+ goto error;
+
+ s += strlen(s) + 1;
+ }
+ }
+ } else {
+ if ((dnode->ddn_ppath = topo_mod_zalloc(mod,
+ pathcount * sizeof (uintptr_t))) == NULL)
+ goto error;
+
+ dnode->ddn_ppath_count = pathcount;
+
+ if (portcount != 0 &&
+ ((dnode->ddn_target_port = topo_mod_zalloc(mod,
+ portcount * sizeof (uintptr_t)))) == NULL)
+ goto error;
+
+ dnode->ddn_target_port_count = portcount;
+
+ pnode = NULL;
+ pathcount = portcount = 0;
+ while ((pnode = di_path_client_next_path(node,
+ pnode)) != NULL) {
+ if ((path = di_path_devfs_path(pnode)) == NULL) {
+ topo_mod_seterrno(mod, errno);
+ goto error;
+ }
+
+ dnode->ddn_ppath[pathcount] =
+ topo_mod_strdup(mod, path);
+ di_devfs_path_free(path);
+ if (dnode->ddn_ppath[pathcount] == NULL)
+ goto error;
+
+ if ((ret = di_path_prop_lookup_strings(pnode,
+ "target-port", &s)) > 0) {
+ for (i = 0; i < ret; i++) {
+ if ((dnode->ddn_target_port[portcount] =
+ topo_mod_strdup(mod, s)) == NULL)
+ goto error;
+
+ portcount++;
+ s += strlen(s) + 1;
+ }
+ }
+
+ pathcount++;
+ }
+ }
+
+ /*
+ * Find the public /dev name by adding a minor name and using
+ * di_devlink interface for reverse translation (use devinfo path).
+ */
+ mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1;
+ if ((minorpath = topo_mod_alloc(mod, mlen)) == NULL)
+ goto error;
+ (void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath, extn);
+ cbp->dcb_dnode = dnode;
+ (void) di_devlink_walk(cbp->dcb_devhdl, "^dsk/", minorpath,
+ DI_PRIMARY_LINK, cbp, disk_devlink_callback);
+ topo_mod_free(mod, minorpath, mlen);
+ if (dnode->ddn_lpath == NULL) {
+ topo_mod_dprintf(mod, "disk_di_node_add: "
+ "failed to determine logical path");
+ goto error;
+ }
+
+ /* cache various bits of optional information about the disk */
+ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+ INQUIRY_VENDOR_ID, &s) > 0) {
+ if ((dnode->ddn_mfg = topo_mod_strdup(mod, s)) == NULL)
+ goto error;
+ }
+ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+ INQUIRY_PRODUCT_ID, &s) > 0) {
+ if ((dnode->ddn_model = topo_mod_strdup(mod, s)) == NULL)
+ goto error;
+ }
+ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+ INQUIRY_REVISION_ID, &s) > 0) {
+ if ((dnode->ddn_firm = topo_mod_strdup(mod, s)) == NULL)
+ goto error;
+ }
+ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+ INQUIRY_SERIAL_NO, &s) > 0) {
+ if ((dnode->ddn_serial = topo_mod_strdup(mod, s)) == NULL)
+ goto error;
+ }
+ if (di_prop_lookup_int64(DDI_DEV_T_ANY, node,
+ "device-nblocks", &nblocksp) > 0) {
+ nblocks = (uint64_t)*nblocksp;
+ /*
+ * To save kernel memory, the driver may not define
+ * "device-dblksize" when its value is default DEV_BSIZE.
+ */
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+ "device-dblksize", &dblksizep) > 0)
+ dblksize = (uint_t)*dblksizep;
+ else
+ dblksize = DEV_BSIZE; /* default value */
+ (void) snprintf(lentry, sizeof (lentry),
+ "%" PRIu64, nblocks * dblksize);
+ if ((dnode->ddn_cap = topo_mod_strdup(mod, lentry)) == NULL)
+ goto error;
+ }
+
+ topo_mod_dprintf(mod, "disk_di_node_add: "
+ "adding %s\n", dnode->ddn_devid);
+ topo_mod_dprintf(mod, " "
+ " %s\n", dnode->ddn_dpath);
+ for (i = 0; i < dnode->ddn_ppath_count; i++) {
+ topo_mod_dprintf(mod, " "
+ " %s\n", dnode->ddn_ppath[i]);
+ }
+ topo_list_append(cbp->dcb_list, dnode);
+ return (0);
+
+error:
+ disk_di_node_free(mod, dnode);
+ return (-1);
+}
+
+/* di_walk_node callback for disk_list_gather */
+static int
+disk_walk_di_nodes(di_node_t node, void *arg)
+{
+ ddi_devid_t devid = NULL;
+ char *devidstr;
+
+ /* only interested in nodes that have devids */
+ devid = (ddi_devid_t)di_devid(node);
+ if (devid == NULL)
+ return (DI_WALK_CONTINUE);
+
+ /* ... with a string representation of the devid */
+ devidstr = devid_str_encode(devid, NULL);
+ if (devidstr == NULL)
+ return (DI_WALK_CONTINUE);
+
+ /* create/find the devid scsi topology node */
+ (void) disk_di_node_add(node, devidstr, arg);
+ devid_str_free(devidstr);
+ return (DI_WALK_CONTINUE);
+}
+
+int
+disk_list_gather(topo_mod_t *mod, topo_list_t *listp)
+{
+ di_node_t devtree;
+ di_devlink_handle_t devhdl;
+ disk_cbdata_t dcb;
+
+ if ((devtree = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
+ topo_mod_dprintf(mod, "disk_list_gather: "
+ "di_init failed");
+ return (-1);
+ }
+
+ if ((devhdl = di_devlink_init(NULL, 0)) == DI_NODE_NIL) {
+ topo_mod_dprintf(mod, "disk_list_gather: "
+ "di_devlink_init failed");
+ di_fini(devtree);
+ return (-1);
+ }
+
+ dcb.dcb_mod = mod;
+ dcb.dcb_list = listp;
+ dcb.dcb_devhdl = devhdl;
+
+ /* walk the devinfo snapshot looking for nodes with devids */
+ (void) di_walk_node(devtree, DI_WALK_CLDFIRST, &dcb,
+ disk_walk_di_nodes);
+
+ (void) di_devlink_fini(&devhdl);
+ di_fini(devtree);
+
+ return (0);
+}
+
+void
+disk_list_free(topo_mod_t *mod, topo_list_t *listp)
+{
+ disk_di_node_t *dnode;
+
+ while ((dnode = topo_list_next(listp)) != NULL) {
+ /* order of delete/free is important */
+ topo_list_delete(listp, dnode);
+ disk_di_node_free(mod, dnode);
+ }
+}
+
+/*
+ * Query the current disk status. If successful, the disk status is returned
+ * as an nvlist consisting of at least the following members:
+ *
+ * protocol string Supported protocol (currently "scsi")
+ *
+ * status nvlist Arbitrary protocol-specific information
+ * about the current state of the disk.
+ *
+ * faults nvlist A list of supported faults. Each
+ * element of this list is a boolean value.
+ * An element's existence indicates that
+ * the drive supports detecting this fault,
+ * and the value indicates the current
+ * state of the fault.
+ *
+ * <fault-name> nvlist For each fault named in 'faults', a
+ * nvlist describing protocol-specific
+ * attributes of the fault.
+ *
+ * This method relies on the libdiskstatus library to query this information.
+ */
+static int
+disk_status(topo_mod_t *mod, tnode_t *nodep, topo_version_t vers,
+ nvlist_t *in_nvl, nvlist_t **out_nvl)
+{
+ disk_status_t *dsp;
+ char *devpath, *fullpath;
+ size_t pathlen;
+ nvlist_t *status;
+ int err;
+
+ *out_nvl = NULL;
+
+ if (vers != TOPO_METH_DISK_STATUS_VERSION)
+ return (topo_mod_seterrno(mod, EMOD_VER_NEW));
+
+ /*
+ * If the caller specifies the "path" parameter, then this indicates
+ * that we should use this instead of deriving it from the topo node
+ * itself.
+ */
+ if (nvlist_lookup_string(in_nvl, "path", &fullpath) == 0) {
+ devpath = NULL;
+ } else {
+ /*
+ * Get the /devices path and attempt to open the disk status
+ * handle.
+ */
+ if (topo_prop_get_string(nodep, TOPO_PGROUP_IO,
+ TOPO_IO_DEV_PATH, &devpath, &err) != 0)
+ return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP));
+
+ /*
+ * Note that sizeof(string) includes the terminating NULL byte
+ */
+ pathlen = strlen(devpath) + sizeof ("/devices") +
+ sizeof (PHYS_EXTN) - 1;
+
+ if ((fullpath = topo_mod_alloc(mod, pathlen)) == NULL)
+ return (topo_mod_seterrno(mod, EMOD_NOMEM));
+
+ (void) snprintf(fullpath, pathlen, "/devices%s%s", devpath,
+ PHYS_EXTN);
+
+ topo_mod_strfree(mod, devpath);
+ }
+
+ if ((dsp = disk_status_open(fullpath, &err)) == NULL) {
+ if (devpath)
+ topo_mod_free(mod, fullpath, pathlen);
+ return (topo_mod_seterrno(mod, err == EDS_NOMEM ?
+ EMOD_NOMEM : EMOD_METHOD_NOTSUP));
+ }
+
+ if (devpath)
+ topo_mod_free(mod, fullpath, pathlen);
+
+ if ((status = disk_status_get(dsp)) == NULL) {
+ err = (disk_status_errno(dsp) == EDS_NOMEM ?
+ EMOD_NOMEM : EMOD_METHOD_NOTSUP);
+ disk_status_close(dsp);
+ return (topo_mod_seterrno(mod, err));
+ }
+
+ *out_nvl = status;
+ disk_status_close(dsp);
+ return (0);
+}
diff --git a/usr/src/lib/libdevinfo/devinfo.c b/usr/src/lib/libdevinfo/devinfo.c
index 8c103d2f7a..582aad2156 100644
--- a/usr/src/lib/libdevinfo/devinfo.c
+++ b/usr/src/lib/libdevinfo/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.
*/
@@ -855,12 +855,12 @@ int
di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg,
int (*minor_callback)(di_node_t, di_minor_t, void *))
{
- struct node_list *head; /* node_list for tree walk */
+ struct node_list *head; /* node_list for tree walk */
#ifdef DEBUG
- char *path = di_devfs_path(root);
- DPRINTF((DI_INFO, "walking minor nodes under %s\n", path));
- di_devfs_path_free(path);
+ char *devfspath = di_devfs_path(root);
+ DPRINTF((DI_INFO, "walking minor nodes under %s\n", devfspath));
+ di_devfs_path_free(devfspath);
#endif
if (root == NULL) {
@@ -877,7 +877,7 @@ di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg,
head->node = root;
DPRINTF((DI_INFO, "Start minor walking from node %s\n",
- di_node_name(root)));
+ di_node_name(root)));
while (head != NULL)
walk_one_minor_list(&head, minor_type, flag, arg,
@@ -931,7 +931,7 @@ di_compatible_names(di_node_t node, char **names)
}
*names = (caddr_t)node +
- DI_NODE(node)->compat_names - DI_NODE(node)->self;
+ DI_NODE(node)->compat_names - DI_NODE(node)->self;
c = *names;
len = DI_NODE(node)->compat_length;
@@ -1130,7 +1130,7 @@ char *
di_devfs_minor_path(di_minor_t minor)
{
di_node_t node;
- char *full_path, *name, *path;
+ char *full_path, *name, *devfspath;
int full_path_len;
if (minor == DI_MINOR_NIL) {
@@ -1140,20 +1140,72 @@ di_devfs_minor_path(di_minor_t minor)
name = di_minor_name(minor);
node = di_minor_devinfo(minor);
- path = di_devfs_path(node);
- if (path == NULL)
+ devfspath = di_devfs_path(node);
+ if (devfspath == NULL)
return (NULL);
/* make the full path to the device minor node */
- full_path_len = strlen(path) + strlen(name) + 2;
+ full_path_len = strlen(devfspath) + strlen(name) + 2;
full_path = (char *)calloc(1, full_path_len);
if (full_path != NULL)
- (void) snprintf(full_path, full_path_len, "%s:%s", path, name);
+ (void) snprintf(full_path, full_path_len, "%s:%s",
+ devfspath, name);
+
+ di_devfs_path_free(devfspath);
+ return (full_path);
+}
+
+/*
+ * Produce a string representation of path to di_path_t (pathinfo node). This
+ * string is identical to di_devfs_path had the device been enumerated under
+ * the pHCI: it has a base path to pHCI, then uses node_name of client, and
+ * device unit-address of pathinfo node.
+ */
+char *
+di_path_devfs_path(di_path_t path)
+{
+ di_node_t phci_node;
+ char *phci_path, *path_name, *path_addr;
+ char *full_path;
+ int full_path_len;
+
+ if (path == DI_PATH_NIL) {
+ errno = EINVAL;
+ return (NULL);
+ }
- di_devfs_path_free(path);
+ /* get name@addr for path */
+ path_name = di_path_node_name(path);
+ path_addr = di_path_bus_addr(path);
+ if ((path_name == NULL) || (path_addr == NULL))
+ return (NULL);
+
+ /* base path to pHCI devinfo node */
+ phci_node = di_path_phci_node(path);
+ if (phci_node == NULL)
+ return (NULL);
+ phci_path = di_devfs_path(phci_node);
+ if (phci_path == NULL)
+ return (NULL);
+
+ /* make the full string representation of path */
+ full_path_len = strlen(phci_path) + 1 + strlen(path_name) +
+ 1 + strlen(path_addr) + 1;
+ full_path = (char *)calloc(1, full_path_len);
+
+ if (full_path != NULL)
+ (void) snprintf(full_path, full_path_len, "%s/%s@%s",
+ phci_path, path_name, path_addr);
+ di_devfs_path_free(phci_path);
return (full_path);
}
+char *
+di_path_client_devfs_path(di_path_t path)
+{
+ return (di_devfs_path(di_path_client_node(path)));
+}
+
void
di_devfs_path_free(char *buf)
{
@@ -1165,6 +1217,128 @@ di_devfs_path_free(char *buf)
free(buf);
}
+/*
+ * Return 1 if name is a IEEE-1275 generic name. If new generic
+ * names are defined, they should be added to this table
+ */
+static int
+is_generic(const char *name, int len)
+{
+ const char **gp;
+
+ /* from IEEE-1275 recommended practices section 3 */
+ static const char *generic_names[] = {
+ "atm",
+ "disk",
+ "display",
+ "dma-controller",
+ "ethernet",
+ "fcs",
+ "fdc",
+ "fddi",
+ "fibre-channel",
+ "ide",
+ "interrupt-controller",
+ "isa",
+ "keyboard",
+ "memory",
+ "mouse",
+ "nvram",
+ "pc-card",
+ "pci",
+ "printer",
+ "rtc",
+ "sbus",
+ "scanner",
+ "scsi",
+ "serial",
+ "sound",
+ "ssa",
+ "tape",
+ "timer",
+ "token-ring",
+ "vme",
+ 0
+ };
+
+ for (gp = generic_names; *gp; gp++) {
+ if ((strncmp(*gp, name, len) == 0) &&
+ (strlen(*gp) == len))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Determine if two paths below /devices refer to the same device, ignoring
+ * any generic .vs. non-generic 'name' issues in "[[/]name[@addr[:minor]]]*".
+ * Return 1 if the paths match.
+ */
+int
+di_devfs_path_match(const char *dp1, const char *dp2)
+{
+ const char *p1, *p2;
+ const char *ec1, *ec2;
+ const char *at1, *at2;
+ char nc;
+ int g1, g2;
+
+ /* progress through both strings */
+ for (p1 = dp1, p2 = dp2; (*p1 == *p2) && *p1; p1++, p2++) {
+ /* require match until the start of a component */
+ if (*p1 != '/')
+ continue;
+
+ /* advance p1 and p2 to start of 'name' in component */
+ nc = *(p1 + 1);
+ if ((nc == '\0') || (nc == '/'))
+ continue; /* skip trash */
+ p1++;
+ p2++;
+
+ /*
+ * Both p1 and p2 point to beginning of 'name' in component.
+ * Determine where current component ends: next '/' or '\0'.
+ */
+ ec1 = strchr(p1, '/');
+ if (ec1 == NULL)
+ ec1 = p1 + strlen(p1);
+ ec2 = strchr(p2, '/');
+ if (ec2 == NULL)
+ ec2 = p2 + strlen(p2);
+
+ /* Determine where name ends based on whether '@' exists */
+ at1 = strchr(p1, '@');
+ at2 = strchr(p2, '@');
+ if (at1 && (at1 < ec1))
+ ec1 = at1;
+ if (at2 && (at2 < ec2))
+ ec2 = at2;
+
+ /*
+ * At this point p[12] point to beginning of name and
+ * ec[12] point to character past the end of name. Determine
+ * if the names are generic.
+ */
+ g1 = is_generic(p1, ec1 - p1);
+ g2 = is_generic(p2, ec2 - p2);
+
+ if (g1 != g2) {
+ /*
+ * one generic and one non-generic
+ * skip past the names in the match.
+ */
+ p1 = ec1;
+ p2 = ec2;
+ } else {
+ if (*p1 != *p2)
+ break;
+ }
+ }
+
+ return ((*p1 == *p2) ? 1 : 0);
+}
+
/* minor data access */
di_minor_t
di_minor_next(di_node_t node, di_minor_t minor)
@@ -1245,7 +1419,7 @@ dev_t
di_minor_devt(di_minor_t minor)
{
return (makedev(DI_MINOR(minor)->dev_major,
- DI_MINOR(minor)->dev_minor));
+ DI_MINOR(minor)->dev_minor));
}
int
@@ -1261,7 +1435,7 @@ di_minor_nodetype(di_minor_t minor)
return (NULL);
return ((caddr_t)minor -
- DI_MINOR(minor)->self + DI_MINOR(minor)->node_type);
+ DI_MINOR(minor)->self + DI_MINOR(minor)->node_type);
}
/*
@@ -1712,7 +1886,7 @@ di_prop_rawdata(di_prop_t prop, uchar_t **prop_data)
* Consolidation private interfaces for accessing I/O multipathing data
*/
di_path_t
-di_path_next_client(di_node_t node, di_path_t path)
+di_path_phci_next_path(di_node_t node, di_path_t path)
{
caddr_t pa;
@@ -1733,7 +1907,8 @@ di_path_next_client(di_node_t node, di_path_t path)
* Path is NIL; the caller is asking for the first path info node
*/
if (DI_NODE(node)->multipath_phci != 0) {
- DPRINTF((DI_INFO, "phci: returning %p\n", ((caddr_t)node -
+ DPRINTF((DI_INFO, "phci_next_path: returning %p\n",
+ ((caddr_t)node -
DI_NODE(node)->self + DI_NODE(node)->multipath_phci)));
return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
DI_NODE(node)->multipath_phci));
@@ -1753,7 +1928,7 @@ di_path_next_client(di_node_t node, di_path_t path)
}
di_path_t
-di_path_next_phci(di_node_t node, di_path_t path)
+di_path_client_next_path(di_node_t node, di_path_t path)
{
caddr_t pa;
@@ -1774,7 +1949,8 @@ di_path_next_phci(di_node_t node, di_path_t path)
* Path is NIL; the caller is asking for the first path info node
*/
if (DI_NODE(node)->multipath_client != 0) {
- DPRINTF((DI_INFO, "client: returning %p\n", ((caddr_t)node -
+ DPRINTF((DI_INFO, "client_next_path: returning %p\n",
+ ((caddr_t)node -
DI_NODE(node)->self + DI_NODE(node)->multipath_client)));
return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
DI_NODE(node)->multipath_client));
@@ -1794,8 +1970,21 @@ di_path_next_phci(di_node_t node, di_path_t path)
}
/*
- * XXX Obsolete wrapper to be removed. Won't work under multilevel.
+ * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces
+ * below after NWS consolidation switches to using di_path_bus_addr,
+ * di_path_phci_next_path, and di_path_client_next_path per CR6638521.
*/
+char *
+di_path_addr(di_path_t path, char *buf)
+{
+ caddr_t pa; /* starting address of map */
+
+ pa = (caddr_t)path - DI_PATH(path)->self;
+
+ (void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr),
+ MAXPATHLEN);
+ return (buf);
+}
di_path_t
di_path_next(di_node_t node, di_path_t path)
{
@@ -1805,9 +1994,9 @@ di_path_next(di_node_t node, di_path_t path)
}
if (DI_NODE(node)->multipath_client) {
- return (di_path_next_phci(node, path));
+ return (di_path_client_next_path(node, path));
} else if (DI_NODE(node)->multipath_phci) {
- return (di_path_next_client(node, path));
+ return (di_path_phci_next_path(node, path));
} else {
/*
* The node had multipathing data but didn't appear to be a
@@ -1817,6 +2006,19 @@ di_path_next(di_node_t node, di_path_t path)
return (DI_PATH_NIL);
}
}
+di_path_t
+di_path_next_phci(di_node_t node, di_path_t path)
+{
+ return (di_path_client_next_path(node, path));
+}
+di_path_t
+di_path_next_client(di_node_t node, di_path_t path)
+{
+ return (di_path_phci_next_path(node, path));
+}
+
+
+
di_path_state_t
di_path_state(di_path_t path)
@@ -1825,15 +2027,31 @@ di_path_state(di_path_t path)
}
char *
-di_path_addr(di_path_t path, char *buf)
+di_path_node_name(di_path_t path)
{
- caddr_t pa; /* starting address of map */
+ di_node_t client_node;
- pa = (caddr_t)path - DI_PATH(path)->self;
+ /* pathinfo gets node_name from client */
+ if ((client_node = di_path_client_node(path)) == NULL)
+ return (NULL);
+ return (di_node_name(client_node));
+}
- (void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr),
- MAXPATHLEN);
- return (buf);
+char *
+di_path_bus_addr(di_path_t path)
+{
+ caddr_t pa = (caddr_t)path - DI_PATH(path)->self;
+
+ if (DI_PATH(path)->path_addr == 0)
+ return (NULL);
+
+ return ((char *)(pa + DI_PATH(path)->path_addr));
+}
+
+int
+di_path_instance(di_path_t path)
+{
+ return (DI_PATH(path)->path_instance);
}
di_node_t
@@ -2472,7 +2690,7 @@ di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop)
struct di_prom_handle *p = (struct di_prom_handle *)ph;
DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n",
- node, p));
+ node, p));
/*
* paranoid check
@@ -2656,7 +2874,7 @@ di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node,
}
len = di_prop_decode_common((void *)&prop->data, prop->len,
- DI_PROP_TYPE_INT, 1);
+ DI_PROP_TYPE_INT, 1);
*prom_prop_data = (int *)((void *)prop->data);
return (len);
@@ -2905,6 +3123,18 @@ di_node_private_get(di_node_t node)
}
void
+di_path_private_set(di_path_t path, void *data)
+{
+ DI_PATH(path)->user_private_data = (uintptr_t)data;
+}
+
+void *
+di_path_private_get(di_path_t path)
+{
+ return ((void *)(uintptr_t)DI_PATH(path)->user_private_data);
+}
+
+void
di_lnode_private_set(di_lnode_t lnode, void *data)
{
DI_LNODE(lnode)->user_private_data = (uintptr_t)data;
@@ -3028,24 +3258,24 @@ di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint)
if (DI_LNODE(lnode)->link_out == NULL)
return (DI_LINK_NIL);
return (DI_LINK((caddr_t)di_all +
- DI_LNODE(lnode)->link_out));
+ DI_LNODE(lnode)->link_out));
} else {
if (DI_LINK(link)->src_link_next == NULL)
return (DI_LINK_NIL);
return (DI_LINK((caddr_t)di_all +
- DI_LINK(link)->src_link_next));
+ DI_LINK(link)->src_link_next));
}
} else {
if (link == DI_LINK_NIL) {
if (DI_LNODE(lnode)->link_in == NULL)
return (DI_LINK_NIL);
return (DI_LINK((caddr_t)di_all +
- DI_LNODE(lnode)->link_in));
+ DI_LNODE(lnode)->link_in));
} else {
if (DI_LINK(link)->tgt_link_next == NULL)
return (DI_LINK_NIL);
return (DI_LINK((caddr_t)di_all +
- DI_LINK(link)->tgt_link_next));
+ DI_LINK(link)->tgt_link_next));
}
}
/* NOTREACHED */
@@ -3084,10 +3314,10 @@ di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
struct node_list *head; /* node_list for tree walk */
#ifdef DEBUG
- char *path = di_devfs_path(root);
+ char *devfspath = di_devfs_path(root);
DPRINTF((DI_INFO, "walking %s link data under %s\n",
- (endpoint == DI_LINK_SRC) ? "src" : "tgt", path));
- di_devfs_path_free(path);
+ (endpoint == DI_LINK_SRC) ? "src" : "tgt", devfspath));
+ di_devfs_path_free(devfspath);
#endif
/*
@@ -3108,7 +3338,7 @@ di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
head->node = root;
DPRINTF((DI_INFO, "Start link data walking from node %s\n",
- di_node_name(root)));
+ di_node_name(root)));
while (head != NULL)
walk_one_link(&head, endpoint, arg, link_callback);
@@ -3149,9 +3379,9 @@ di_walk_lnode(di_node_t root, uint_t flag, void *arg,
struct node_list *head; /* node_list for tree walk */
#ifdef DEBUG
- char *path = di_devfs_path(root);
- DPRINTF((DI_INFO, "walking lnode data under %s\n", path));
- di_devfs_path_free(path);
+ char *devfspath = di_devfs_path(root);
+ DPRINTF((DI_INFO, "walking lnode data under %s\n", devfspath));
+ di_devfs_path_free(devfspath);
#endif
/*
@@ -3171,7 +3401,7 @@ di_walk_lnode(di_node_t root, uint_t flag, void *arg,
head->node = root;
DPRINTF((DI_INFO, "Start lnode data walking from node %s\n",
- di_node_name(root)));
+ di_node_name(root)));
while (head != NULL)
walk_one_lnode(&head, arg, lnode_callback);
@@ -3180,18 +3410,17 @@ di_walk_lnode(di_node_t root, uint_t flag, void *arg,
}
di_node_t
-di_lookup_node(di_node_t root, char *path)
+di_lookup_node(di_node_t root, char *devfspath)
{
struct di_all *dap;
di_node_t node;
- char copy[MAXPATHLEN];
- char *slash, *pname, *paddr;
+ char *copy, *slash, *pname, *paddr;
/*
* Path must be absolute and musn't have duplicate slashes
*/
- if (*path != '/' || strstr(path, "//")) {
- DPRINTF((DI_ERR, "Invalid path: %s\n", path));
+ if (*devfspath != '/' || strstr(devfspath, "//")) {
+ DPRINTF((DI_ERR, "Invalid path: %s\n", devfspath));
return (DI_NODE_NIL);
}
@@ -3206,15 +3435,15 @@ di_lookup_node(di_node_t root, char *path)
return (DI_NODE_NIL);
}
- if (strlcpy(copy, path, sizeof (copy)) >= sizeof (copy)) {
- DPRINTF((DI_ERR, "path too long: %s\n", path));
+ if ((copy = strdup(devfspath)) == NULL) {
+ DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
return (DI_NODE_NIL);
}
for (slash = copy, node = root; slash; ) {
/*
- * Handle path = "/" case as well as trailing '/'
+ * Handle devfspath = "/" case as well as trailing '/'
*/
if (*(slash + 1) == '\0')
break;
@@ -3259,14 +3488,72 @@ di_lookup_node(di_node_t root, char *path)
*/
if (node == DI_NODE_NIL) {
DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr));
+ free(copy);
return (DI_NODE_NIL);
}
}
assert(node != DI_NODE_NIL);
+ free(copy);
return (node);
}
+di_path_t
+di_lookup_path(di_node_t root, char *devfspath)
+{
+ di_node_t phci_node;
+ di_path_t path = DI_PATH_NIL;
+ char *copy, *lastslash;
+ char *pname, *paddr;
+ char *path_name, *path_addr;
+
+ if ((copy = strdup(devfspath)) == NULL) {
+ DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
+ return (DI_NODE_NIL);
+ }
+
+ if ((lastslash = strrchr(copy, '/')) == NULL) {
+ DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
+ goto out;
+ }
+
+ /* stop at pHCI and find the node for the phci */
+ *lastslash = '\0';
+ phci_node = di_lookup_node(root, copy);
+ if (phci_node == NULL) {
+ DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
+ goto out;
+ }
+
+ /* set up pname and paddr for last component */
+ pname = lastslash + 1;
+ if ((paddr = strchr(pname, '@')) == NULL) {
+ DPRINTF((DI_ERR, "failed to find unit-addr: %s\n", devfspath));
+ goto out;
+ }
+ *paddr++ = '\0';
+
+ /* walk paths below phci looking for match */
+ for (path = di_path_phci_next_path(phci_node, DI_PATH_NIL);
+ path != DI_PATH_NIL;
+ path = di_path_phci_next_path(phci_node, path)) {
+
+ /* get name@addr of path */
+ path_name = di_path_node_name(path);
+ path_addr = di_path_bus_addr(path);
+ if ((path_name == NULL) || (path_addr == NULL))
+ continue;
+
+ /* break on match */
+ if ((strcmp(pname, path_name) == 0) &&
+ (strcmp(paddr, path_addr) == 0))
+ break;
+ }
+
+out: free(copy);
+ return (path);
+}
+
static char *
msglevel2str(di_debug_t msglevel)
{
diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h
index 2314ee1c9c..ca745b3b31 100644
--- a/usr/src/lib/libdevinfo/libdevinfo.h
+++ b/usr/src/lib/libdevinfo/libdevinfo.h
@@ -100,31 +100,32 @@ extern "C" {
((type) == DI_PROP_TYPE_INT64))
/* opaque handles */
-
-typedef struct di_node *di_node_t; /* opaque handle to node */
-typedef struct di_minor *di_minor_t; /* opaque handle to minor node */
-typedef struct di_prop *di_prop_t; /* opaque handle to property */
-typedef struct di_prom_prop *di_prom_prop_t; /* opaque handle to prom prop */
-typedef struct di_prom_handle *di_prom_handle_t; /* opaque handle */
-typedef struct di_path *di_path_t; /* opaque handle */
-typedef struct di_path_prop *di_path_prop_t; /* opaque handle */
-
+typedef struct di_node *di_node_t; /* node */
+typedef struct di_minor *di_minor_t; /* minor_node */
+typedef struct di_path *di_path_t; /* path_node */
+typedef struct di_link *di_link_t; /* link */
+typedef struct di_lnode *di_lnode_t; /* endpoint */
+typedef struct di_devlink *di_devlink_t; /* devlink */
+
+typedef struct di_prop *di_prop_t; /* node property */
+typedef struct di_path_prop *di_path_prop_t; /* path property */
+typedef struct di_prom_prop *di_prom_prop_t; /* prom property */
+
+typedef struct di_prom_handle *di_prom_handle_t; /* prom snapshot */
typedef struct di_devlink_handle *di_devlink_handle_t; /* devlink snapshot */
-typedef struct di_devlink *di_devlink_t; /* opaque handle to devlink */
-typedef struct di_link *di_link_t; /* opaque handle to link */
-typedef struct di_lnode *di_lnode_t; /* opaque handle to endpoint */
+
/*
* Null handles to make handles really opaque
*/
-#define DI_NODE_NIL NULL
-#define DI_LINK_NIL NULL
-#define DI_LNODE_NIL NULL
-#define DI_MINOR_NIL NULL
-#define DI_PROP_NIL NULL
+#define DI_NODE_NIL NULL
+#define DI_MINOR_NIL NULL
+#define DI_PATH_NIL NULL
+#define DI_LINK_NIL NULL
+#define DI_LNODE_NIL NULL
+#define DI_PROP_NIL NULL
#define DI_PROM_PROP_NIL NULL
#define DI_PROM_HANDLE_NIL NULL
-#define DI_PATH_NIL NULL
/*
* IEEE 1275 properties and other standardized property names
@@ -138,92 +139,76 @@ typedef struct di_lnode *di_lnode_t; /* opaque handle to endpoint */
#define DI_PROP_REG "reg"
#define DI_PROP_AP_NAMES "ap-names"
-
/* Interface Prototypes */
/*
* Snapshot initialization and cleanup
*/
-extern di_node_t di_init(const char *phys_path, uint_t flag);
-extern void di_fini(di_node_t root);
+extern di_node_t di_init(const char *phys_path, uint_t flag);
+extern void di_fini(di_node_t root);
/*
- * tree traversal
+ * node: traversal, data access, and parameters
*/
-extern di_node_t di_parent_node(di_node_t node);
-extern di_node_t di_sibling_node(di_node_t node);
-extern di_node_t di_child_node(di_node_t node);
-extern di_node_t di_drv_first_node(const char *drv_name, di_node_t root);
-extern di_node_t di_drv_next_node(di_node_t node);
-extern di_node_t di_vhci_first_node(di_node_t root);
-extern di_node_t di_vhci_next_node(di_node_t node);
-extern di_node_t di_phci_first_node(di_node_t vhci_node);
-extern di_node_t di_phci_next_node(di_node_t node);
+extern int di_walk_node(di_node_t root, uint_t flag, void *arg,
+ int (*node_callback)(di_node_t node, void *arg));
-/*
- * tree walking assistants
- */
-extern int di_walk_node(di_node_t root, uint_t flag, void *arg,
- int (*node_callback)(di_node_t node, void *arg));
-extern int di_walk_minor(di_node_t root, const char *minortype, uint_t flag,
- void *arg, int (*minor_callback)(di_node_t node, di_minor_t minor,
- void *arg));
-extern int di_walk_link(di_node_t root, uint_t flag, uint_t endpoint,
- void *arg, int (*link_callback)(di_link_t link, void *arg));
-extern int di_walk_lnode(di_node_t root, uint_t flag,
- void *arg, int (*lnode_callback)(di_lnode_t lnode, void *arg));
+extern di_node_t di_drv_first_node(const char *drv_name, di_node_t root);
+extern di_node_t di_drv_next_node(di_node_t node);
-extern void di_node_private_set(di_node_t node, void *data);
-extern void *di_node_private_get(di_node_t node);
-extern void di_minor_private_set(di_minor_t minor, void *data);
-extern void *di_minor_private_get(di_minor_t minor);
-extern void di_lnode_private_set(di_lnode_t lnode, void *data);
-extern void *di_lnode_private_get(di_lnode_t lnode);
-extern void di_link_private_set(di_link_t link, void *data);
-extern void *di_link_private_get(di_link_t link);
+extern di_node_t di_parent_node(di_node_t node);
+extern di_node_t di_sibling_node(di_node_t node);
+extern di_node_t di_child_node(di_node_t node);
-/*
- * generic node parameters
- */
-extern char *di_node_name(di_node_t node);
-extern char *di_bus_addr(di_node_t node);
-extern char *di_binding_name(di_node_t node);
-extern int di_compatible_names(di_node_t, char **names);
-extern int di_instance(di_node_t node);
-extern int di_nodeid(di_node_t node);
-extern int di_driver_major(di_node_t node);
-extern uint_t di_state(di_node_t node);
-extern ddi_node_state_t di_node_state(di_node_t node);
-extern ddi_devid_t di_devid(di_node_t node);
-
-extern char *di_driver_name(di_node_t node);
-extern uint_t di_driver_ops(di_node_t node);
+extern char *di_node_name(di_node_t node);
+extern char *di_bus_addr(di_node_t node);
+extern char *di_binding_name(di_node_t node);
+extern int di_compatible_names(di_node_t, char **names);
+extern int di_instance(di_node_t node);
+extern int di_nodeid(di_node_t node);
+extern int di_driver_major(di_node_t node);
+extern uint_t di_state(di_node_t node);
+extern ddi_node_state_t di_node_state(di_node_t node);
+extern ddi_devid_t di_devid(di_node_t node);
+extern char *di_driver_name(di_node_t node);
+extern uint_t di_driver_ops(di_node_t node);
-extern char *di_devfs_path(di_node_t node);
-extern char *di_devfs_minor_path(di_minor_t minor);
+extern void di_node_private_set(di_node_t node, void *data);
+extern void *di_node_private_get(di_node_t node);
-extern void di_devfs_path_free(char *path_buf);
+extern char *di_devfs_path(di_node_t node);
+extern char *di_devfs_minor_path(di_minor_t minor);
+extern void di_devfs_path_free(char *path_buf);
/*
- * layering data access
+ * path_node: traversal, data access, and parameters
*/
-extern di_link_t di_link_next_by_node(di_node_t node,
- di_link_t link, uint_t endpoint);
-extern di_link_t di_link_next_by_lnode(di_lnode_t lnode,
- di_link_t link, uint_t endpoint);
-extern di_lnode_t di_link_to_lnode(di_link_t link, uint_t endpoint);
+extern di_path_t di_path_phci_next_path(di_node_t node, di_path_t);
+extern di_path_t di_path_client_next_path(di_node_t node, di_path_t);
-extern di_lnode_t di_lnode_next(di_node_t node, di_lnode_t lnode);
-extern char *di_lnode_name(di_lnode_t lnode);
-extern di_node_t di_lnode_devinfo(di_lnode_t lnode);
-extern int di_lnode_devt(di_lnode_t lnode, dev_t *devt);
+extern di_node_t di_path_phci_node(di_path_t path);
+extern di_node_t di_path_client_node(di_path_t path);
-extern int di_link_spectype(di_link_t link);
+extern char *di_path_node_name(di_path_t path);
+extern char *di_path_bus_addr(di_path_t path);
+extern int di_path_instance(di_path_t path);
+extern di_path_state_t di_path_state(di_path_t path);
+
+extern char *di_path_devfs_path(di_path_t path);
+extern char *di_path_client_devfs_path(di_path_t path);
+
+extern void di_path_private_set(di_path_t path, void *data);
+extern void *di_path_private_get(di_path_t path);
/*
- * minor data access
+ * minor_node: traversal, data access, and parameters
*/
+extern int di_walk_minor(di_node_t root, const char *minortype,
+ uint_t flag, void *arg,
+ int (*minor_callback)(di_node_t node,
+ di_minor_t minor, void *arg));
extern di_minor_t di_minor_next(di_node_t node, di_minor_t minor);
+
extern di_node_t di_minor_devinfo(di_minor_t minor);
extern ddi_minor_type di_minor_type(di_minor_t minor);
extern char *di_minor_name(di_minor_t minor);
@@ -231,44 +216,109 @@ extern dev_t di_minor_devt(di_minor_t minor);
extern int di_minor_spectype(di_minor_t minor);
extern char *di_minor_nodetype(di_minor_t node);
+extern void di_minor_private_set(di_minor_t minor, void *data);
+extern void *di_minor_private_get(di_minor_t minor);
+
+/*
+ * node: property access
+ */
+extern di_prop_t di_prop_next(di_node_t node, di_prop_t prop);
+
+extern char *di_prop_name(di_prop_t prop);
+extern int di_prop_type(di_prop_t prop);
+extern dev_t di_prop_devt(di_prop_t prop);
+
+extern int di_prop_ints(di_prop_t prop, int **prop_data);
+extern int di_prop_int64(di_prop_t prop, int64_t **prop_data);
+extern int di_prop_strings(di_prop_t prop, char **prop_data);
+extern int di_prop_bytes(di_prop_t prop, uchar_t **prop_data);
+
+extern int di_prop_lookup_bytes(dev_t dev, di_node_t node,
+ const char *prop_name, uchar_t **prop_data);
+extern int di_prop_lookup_ints(dev_t dev, di_node_t node,
+ const char *prop_name, int **prop_data);
+extern int di_prop_lookup_int64(dev_t dev, di_node_t node,
+ const char *prop_name, int64_t **prop_data);
+extern int di_prop_lookup_strings(dev_t dev, di_node_t node,
+ const char *prop_name, char **prop_data);
+
/*
- * Software property access
+ * prom_node: property access
*/
-extern di_prop_t di_prop_next(di_node_t node, di_prop_t prop);
-extern dev_t di_prop_devt(di_prop_t prop);
-extern char *di_prop_name(di_prop_t prop);
-extern int di_prop_type(di_prop_t prop);
-extern int di_prop_ints(di_prop_t prop, int **prop_data);
-extern int di_prop_int64(di_prop_t prop, int64_t **prop_data);
-extern int di_prop_strings(di_prop_t prop, char **prop_data);
-extern int di_prop_bytes(di_prop_t prop, uchar_t **prop_data);
-extern int di_prop_lookup_ints(dev_t dev, di_node_t node,
- const char *prop_name, int **prop_data);
-extern int di_prop_lookup_int64(dev_t dev, di_node_t node,
- const char *prop_name, int64_t **prop_data);
-extern int di_prop_lookup_strings(dev_t dev, di_node_t node,
- const char *prop_name, char **prop_data);
-extern int di_prop_lookup_bytes(dev_t dev, di_node_t node,
- const char *prop_name, uchar_t **prop_data);
+extern di_prom_handle_t di_prom_init(void);
+extern void di_prom_fini(di_prom_handle_t ph);
+
+extern di_prom_prop_t di_prom_prop_next(di_prom_handle_t ph, di_node_t node,
+ di_prom_prop_t prom_prop);
+
+extern char *di_prom_prop_name(di_prom_prop_t prom_prop);
+extern int di_prom_prop_data(di_prom_prop_t prop,
+ uchar_t **prom_prop_data);
+
+extern int di_prom_prop_lookup_ints(di_prom_handle_t prom,
+ di_node_t node, const char *prom_prop_name,
+ int **prom_prop_data);
+extern int di_prom_prop_lookup_strings(di_prom_handle_t prom,
+ di_node_t node, const char *prom_prop_name,
+ char **prom_prop_data);
+extern int di_prom_prop_lookup_bytes(di_prom_handle_t prom,
+ di_node_t node, const char *prom_prop_name,
+ uchar_t **prom_prop_data);
/*
- * PROM property access
+ * path_node: property access
*/
-extern di_prom_handle_t di_prom_init(void);
-extern void di_prom_fini(di_prom_handle_t ph);
+extern di_path_prop_t di_path_prop_next(di_path_t path, di_path_prop_t prop);
+
+extern char *di_path_prop_name(di_path_prop_t prop);
+extern int di_path_prop_type(di_path_prop_t prop);
+extern int di_path_prop_len(di_path_prop_t prop);
+
+extern int di_path_prop_bytes(di_path_prop_t prop,
+ uchar_t **prop_data);
+extern int di_path_prop_ints(di_path_prop_t prop,
+ int **prop_data);
+extern int di_path_prop_int64s(di_path_prop_t prop,
+ int64_t **prop_data);
+extern int di_path_prop_strings(di_path_prop_t prop,
+ char **prop_data);
+
+extern int di_path_prop_lookup_bytes(di_path_t path,
+ const char *prop_name, uchar_t **prop_data);
+extern int di_path_prop_lookup_ints(di_path_t path,
+ const char *prop_name, int **prop_data);
+extern int di_path_prop_lookup_int64s(di_path_t path,
+ const char *prop_name, int64_t **prop_data);
+extern int di_path_prop_lookup_strings(di_path_t path,
+ const char *prop_name, char **prop_data);
+
+/*
+ * layering link/lnode: traversal, data access, and parameters
+ */
+extern int di_walk_link(di_node_t root, uint_t flag,
+ uint_t endpoint, void *arg,
+ int (*link_callback)(di_link_t link, void *arg));
+extern int di_walk_lnode(di_node_t root, uint_t flag, void *arg,
+ int (*lnode_callback)(di_lnode_t lnode, void *arg));
+
+extern di_link_t di_link_next_by_node(di_node_t node,
+ di_link_t link, uint_t endpoint);
+extern di_link_t di_link_next_by_lnode(di_lnode_t lnode,
+ di_link_t link, uint_t endpoint);
+extern di_lnode_t di_lnode_next(di_node_t node, di_lnode_t lnode);
+extern char *di_lnode_name(di_lnode_t lnode);
-extern di_prom_prop_t di_prom_prop_next(di_prom_handle_t ph, di_node_t node,
- di_prom_prop_t prom_prop);
+extern int di_link_spectype(di_link_t link);
+extern di_lnode_t di_link_to_lnode(di_link_t link, uint_t endpoint);
+
+extern di_node_t di_lnode_devinfo(di_lnode_t lnode);
+extern int di_lnode_devt(di_lnode_t lnode, dev_t *devt);
-extern char *di_prom_prop_name(di_prom_prop_t prom_prop);
-extern int di_prom_prop_data(di_prom_prop_t prop, uchar_t **prom_prop_data);
+extern void di_link_private_set(di_link_t link, void *data);
+extern void *di_link_private_get(di_link_t link);
+extern void di_lnode_private_set(di_lnode_t lnode, void *data);
+extern void *di_lnode_private_get(di_lnode_t lnode);
-extern int di_prom_prop_lookup_ints(di_prom_handle_t prom, di_node_t node,
- const char *prom_prop_name, int **prom_prop_data);
-extern int di_prom_prop_lookup_strings(di_prom_handle_t prom, di_node_t node,
- const char *prom_prop_name, char **prom_prop_data);
-extern int di_prom_prop_lookup_bytes(di_prom_handle_t prom, di_node_t node,
- const char *prom_prop_name, uchar_t **prom_prop_data);
/*
* Private interfaces
@@ -276,12 +326,17 @@ extern int di_prom_prop_lookup_bytes(di_prom_handle_t prom, di_node_t node,
* The interfaces and structures below are private to this implementation
* of Solaris and are subject to change at any time without notice.
*
- * Applications and drivers using these interfaces will fail
+ * Applications and drivers using these interfaces may fail
* to run on future releases.
*/
-
extern di_prop_t di_prop_find(dev_t match_dev, di_node_t node,
const char *name);
+extern int di_devfs_path_match(const char *dp1, const char *dp2);
+
+extern di_node_t di_vhci_first_node(di_node_t root);
+extern di_node_t di_vhci_next_node(di_node_t node);
+extern di_node_t di_phci_first_node(di_node_t vhci_node);
+extern di_node_t di_phci_next_node(di_node_t node);
/*
* Interfaces for handling IEEE 1275 and other standardized properties
@@ -305,35 +360,14 @@ extern int di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node,
di_slot_name_t **prop_data);
/*
- * Interfaces for accessing I/O multipathing data
+ * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces
+ * below after NWS consolidation switches to using di_path_bus_addr,
+ * di_path_phci_next_path, and di_path_client_next_path per CR6638521.
*/
-/* XXX remove di_path_next() after updating NWS consolidation */
+extern char *di_path_addr(di_path_t path, char *buf);
extern di_path_t di_path_next(di_node_t node, di_path_t path);
extern di_path_t di_path_next_phci(di_node_t node, di_path_t path);
extern di_path_t di_path_next_client(di_node_t node, di_path_t path);
-extern di_path_state_t di_path_state(di_path_t path);
-extern char *di_path_addr(di_path_t path, char *buf);
-extern di_node_t di_path_client_node(di_path_t path);
-extern void di_path_client_path(di_path_t path, char *buf);
-extern di_node_t di_path_phci_node(di_path_t path);
-extern void di_path_phci_path(di_path_t path, char *buf);
-extern di_path_prop_t di_path_prop_next(di_path_t path, di_path_prop_t prop);
-extern char *di_path_prop_name(di_path_prop_t prop);
-extern int di_path_prop_type(di_path_prop_t prop);
-extern int di_path_prop_len(di_path_prop_t prop);
-extern int di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data);
-extern int di_path_prop_ints(di_path_prop_t prop, int **prop_data);
-extern int di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data);
-extern int di_path_prop_strings(di_path_prop_t prop, char **prop_data);
-extern int di_path_prop_lookup_bytes(di_path_t path, const char *prop_name,
- uchar_t **prop_data);
-extern int di_path_prop_lookup_ints(di_path_t path, const char *prop_name,
- int **prop_data);
-extern int di_path_prop_lookup_int64s(di_path_t path, const char *prop_name,
- int64_t **prop_data);
-extern int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
- char **prop_data);
-
/*
* Interfaces for private data
@@ -436,11 +470,12 @@ extern int di_devperm_login(const char *, uid_t, gid_t, void (*)(char *));
extern int di_devperm_logout(const char *);
/*
- * Private interface for looking up a node in a snapshot
+ * Private interface for looking up, by path string, a node/path/minor
+ * in a snapshot.
*/
+extern di_path_t di_lookup_path(di_node_t root, char *path);
extern di_node_t di_lookup_node(di_node_t root, char *path);
-
/*
* Private hotplug interfaces to be used between cfgadm pci plugin and
* devfsadm link generator.
diff --git a/usr/src/lib/libdevinfo/mapfile-vers b/usr/src/lib/libdevinfo/mapfile-vers
index aa49121009..581729d3e6 100644
--- a/usr/src/lib/libdevinfo/mapfile-vers
+++ b/usr/src/lib/libdevinfo/mapfile-vers
@@ -25,6 +25,34 @@
# ident "%Z%%M% %I% %E% SMI"
#
+SUNW_1.4 {
+ global:
+ di_path_bus_addr;
+ di_path_client_devfs_path;
+ di_path_client_next_path;
+ di_path_client_node;
+ di_path_devfs_path;
+ di_path_instance;
+ di_path_node_name;
+ di_path_phci_next_path;
+ di_path_phci_node;
+ di_path_private_get;
+ di_path_private_set;
+ di_path_prop_bytes;
+ di_path_prop_int64s;
+ di_path_prop_ints;
+ di_path_prop_len;
+ di_path_prop_lookup_bytes;
+ di_path_prop_lookup_int64s;
+ di_path_prop_lookup_ints;
+ di_path_prop_lookup_strings;
+ di_path_prop_name;
+ di_path_prop_next;
+ di_path_prop_strings;
+ di_path_prop_type;
+ di_path_state;
+} SUNW_1.3;
+
SUNW_1.3 {
global:
di_devfs_minor_path;
@@ -80,8 +108,8 @@ SUNW_1.1 {
di_minor_nodetype;
di_minor_spectype;
di_minor_type;
- di_nodeid;
di_node_name;
+ di_nodeid;
di_parent_node;
di_prom_fini;
di_prom_init;
@@ -123,11 +151,15 @@ SUNWprivate_1.1 {
devfs_get_prom_names;
devfs_install2target;
devfs_load_minor_perm;
+ devfs_parse_binding_file;
devfs_path_to_drv;
devfs_read_minor_perm;
devfs_resolve_aliases;
devfs_rm_minor_perm;
devfs_target2install;
+ devfs_walk_minor_nodes;
+ device_exists;
+ di_devfs_path_match;
di_devlink_add_link;
di_devlink_cache_walk;
di_devlink_close;
@@ -143,42 +175,34 @@ SUNWprivate_1.1 {
di_devlink_type;
di_devlink_update;
di_devlink_walk;
- di_devperm_login;
- di_devperm_logout;
- di_devname_get_mapinfo;
- di_devname_get_mapent;
di_devname_action_on_key;
+ di_devname_get_mapent;
+ di_devname_get_mapinfo;
di_devname_print_mapinfo;
- di_driver_private_data;
+ di_devperm_login;
+ di_devperm_logout;
di_dim_fini;
di_dim_init;
di_dim_path_dev;
di_dim_path_devices;
+ di_dli_close;
+ di_dli_name;
+ di_dli_openr;
+ di_dli_openw;
+ di_driver_private_data;
+ di_flags;
di_init_driver;
di_init_impl;
di_lookup_node;
+ di_lookup_path;
di_minor_devinfo;
di_node_state;
di_parent_private_data;
+# XXX remove: di_path_(addr,next,next_client,next_phci)
di_path_addr;
- di_path_client_node;
di_path_next;
di_path_next_client;
di_path_next_phci;
- di_path_phci_node;
- di_path_prop_bytes;
- di_path_prop_int64s;
- di_path_prop_ints;
- di_path_prop_len;
- di_path_prop_lookup_bytes;
- di_path_prop_lookup_int64s;
- di_path_prop_lookup_ints;
- di_path_prop_lookup_strings;
- di_path_prop_name;
- di_path_prop_next;
- di_path_prop_strings;
- di_path_prop_type;
- di_path_state;
di_phci_first_node;
di_phci_next_node;
di_prof_add_dev;
@@ -186,37 +210,29 @@ SUNWprivate_1.1 {
di_prof_add_map;
di_prof_add_symlink;
di_prof_commit;
- di_prof_init;
di_prof_fini;
+ di_prof_init;
+ di_prom_prop_lookup_slot_names;
+ di_prom_prop_slot_names;
di_prop_drv_next;
+ di_prop_find;
di_prop_global_next;
di_prop_hw_next;
+ di_prop_lookup_slot_names;
di_prop_rawdata;
+ di_prop_slot_names;
di_prop_sys_next;
+ di_retire_device;
+ di_retired;
+ di_slot_names_decode;
+ di_slot_names_free;
+ di_unretire_device;
di_vhci_first_node;
di_vhci_next_node;
- di_dli_name;
- di_dli_openr;
- di_dli_openw;
- di_dli_close;
- di_slot_names_free;
- di_slot_names_decode;
- di_prop_slot_names;
- di_prom_prop_slot_names;
- di_prop_lookup_slot_names;
- di_prom_prop_lookup_slot_names;
- di_prop_find;
- device_exists;
finddev_close;
finddev_emptydir;
finddev_next;
finddev_readdir;
- di_flags;
- di_retire_device;
- di_unretire_device;
- di_retired;
- devfs_parse_binding_file;
- devfs_walk_minor_nodes;
local:
*;
};
diff --git a/usr/src/lib/libdiskmgt/common/findevs.c b/usr/src/lib/libdiskmgt/common/findevs.c
index 076281693d..81230e6323 100644
--- a/usr/src/lib/libdiskmgt/common/findevs.c
+++ b/usr/src/lib/libdiskmgt/common/findevs.c
@@ -688,7 +688,7 @@ add_disk2controller(disk_t *diskp, struct search_args *args)
/* note: mpxio di_path stuff is all consolidation private */
di_path_t pi = DI_PATH_NIL;
- while ((pi = di_path_next_phci(node, pi)) != DI_PATH_NIL) {
+ while ((pi = di_path_client_next_path(node, pi)) != DI_PATH_NIL) {
int cnt;
uchar_t *bytes;
char str[MAXPATHLEN];
@@ -770,7 +770,8 @@ add_int2array(int p, int **parray)
cnt = 0;
if (pa != NULL) {
- for (; pa[cnt] != -1; cnt++);
+ for (; pa[cnt] != -1; cnt++)
+ ;
}
new_array = (int *)calloc(cnt + 2, sizeof (int *));
@@ -804,7 +805,8 @@ add_ptr2array(void *p, void ***parray)
cnt = 0;
if (pa != NULL) {
- for (; pa[cnt]; cnt++);
+ for (; pa[cnt]; cnt++)
+ ;
}
new_array = (void **)calloc(cnt + 2, sizeof (void *));
diff --git a/usr/src/lib/libnvpair/Makefile.com b/usr/src/lib/libnvpair/Makefile.com
index 532a1032cc..4439415f03 100644
--- a/usr/src/lib/libnvpair/Makefile.com
+++ b/usr/src/lib/libnvpair/Makefile.com
@@ -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.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -50,6 +50,10 @@ LIBS = $(DYNLIB) $(LINTLIB)
# turn off ptr-cast warnings
LINTFLAGS64 += -erroff=E_BAD_PTR_CAST_ALIGN
+# turn off warning caused by lint bug: not understanding SCNi8 "hhi"
+LINTFLAGS += -erroff=E_BAD_FORMAT_STR2
+LINTFLAGS64 += -erroff=E_BAD_FORMAT_STR2
+
CFLAGS += $(CCVERBOSE)
CPPFLAGS += -D_REENTRANT
diff --git a/usr/src/lib/libnvpair/libnvpair.c b/usr/src/lib/libnvpair/libnvpair.c
index 58a47f1f06..664a3fff6f 100644
--- a/usr/src/lib/libnvpair/libnvpair.c
+++ b/usr/src/lib/libnvpair/libnvpair.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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -28,6 +27,8 @@
#include <unistd.h>
#include <strings.h>
+#include <sys/types.h>
+#include <sys/inttypes.h>
#include "libnvpair.h"
/*
@@ -264,3 +265,347 @@ nvlist_print(FILE *fp, nvlist_t *nvl)
{
nvlist_print_with_indent(fp, nvl, 0);
}
+
+/*
+ * Determine if string 'value' matches 'nvp' value. The 'value' string is
+ * converted, depending on the type of 'nvp', prior to match. For numeric
+ * types, a radix independent sscanf conversion of 'value' is used. If 'nvp'
+ * is an array type, 'ai' is the index into the array against which we are
+ * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass
+ * in a regex_t compilation of value in 'value_regex' to trigger regular
+ * expression string match instead of simple strcmp().
+ *
+ * Return 1 on match, 0 on no-match, and -1 on error. If the error is
+ * related to value syntax error and 'ep' is non-NULL, *ep will point into
+ * the 'value' string at the location where the error exists.
+ *
+ * NOTE: It may be possible to move the non-regex_t version of this into
+ * common code used by library/kernel/boot.
+ */
+int
+nvpair_value_match_regex(nvpair_t *nvp, int ai,
+ char *value, regex_t *value_regex, char **ep)
+{
+ char *evalue;
+ uint_t a_len;
+ int sr;
+
+ if (ep)
+ *ep = NULL;
+
+ if ((nvp == NULL) || (value == NULL))
+ return (-1); /* error fail match - invalid args */
+
+ /* make sure array and index combination make sense */
+ if ((nvpair_type_is_array(nvp) && (ai < 0)) ||
+ (!nvpair_type_is_array(nvp) && (ai >= 0)))
+ return (-1); /* error fail match - bad index */
+
+ /* non-string values should be single 'chunk' */
+ if ((nvpair_type(nvp) != DATA_TYPE_STRING) &&
+ (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) {
+ value += strspn(value, " \t");
+ evalue = value + strcspn(value, " \t");
+ if (*evalue) {
+ if (ep)
+ *ep = evalue;
+ return (-1); /* error fail match - syntax */
+ }
+ }
+
+ sr = EOF;
+ switch (nvpair_type(nvp)) {
+ case DATA_TYPE_STRING: {
+ char *val;
+
+ /* check string value for match */
+ if (nvpair_value_string(nvp, &val) == 0) {
+ if (value_regex) {
+ if (regexec(value_regex, val,
+ (size_t)0, NULL, 0) == 0)
+ return (1); /* match */
+ } else {
+ if (strcmp(value, val) == 0)
+ return (1); /* match */
+ }
+ }
+ break;
+ }
+ case DATA_TYPE_STRING_ARRAY: {
+ char **val_array;
+
+ /* check indexed string value of array for match */
+ if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len)) {
+ if (value_regex) {
+ if (regexec(value_regex, val_array[ai],
+ (size_t)0, NULL, 0) == 0)
+ return (1);
+ } else {
+ if (strcmp(value, val_array[ai]) == 0)
+ return (1);
+ }
+ }
+ break;
+ }
+ case DATA_TYPE_BYTE: {
+ uchar_t val, val_arg;
+
+ /* scanf uchar_t from value and check for match */
+ sr = sscanf(value, "%c", &val_arg);
+ if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_BYTE_ARRAY: {
+ uchar_t *val_array, val_arg;
+
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%c", &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT8: {
+ int8_t val, val_arg;
+
+ /* scanf int8_t from value and check for match */
+ sr = sscanf(value, "%"SCNi8, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int8(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT8_ARRAY: {
+ int8_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi8, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT8: {
+ uint8_t val, val_arg;
+
+ /* scanf uint8_t from value and check for match */
+ sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint8(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT8_ARRAY: {
+ uint8_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT16: {
+ int16_t val, val_arg;
+
+ /* scanf int16_t from value and check for match */
+ sr = sscanf(value, "%"SCNi16, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int16(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT16_ARRAY: {
+ int16_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi16, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT16: {
+ uint16_t val, val_arg;
+
+ /* scanf uint16_t from value and check for match */
+ sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint16(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT16_ARRAY: {
+ uint16_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT32: {
+ int32_t val, val_arg;
+
+ /* scanf int32_t from value and check for match */
+ sr = sscanf(value, "%"SCNi32, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int32(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT32_ARRAY: {
+ int32_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi32, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT32: {
+ uint32_t val, val_arg;
+
+ /* scanf uint32_t from value and check for match */
+ sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint32(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT32_ARRAY: {
+ uint32_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT64: {
+ int64_t val, val_arg;
+
+ /* scanf int64_t from value and check for match */
+ sr = sscanf(value, "%"SCNi64, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int64(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT64_ARRAY: {
+ int64_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi64, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT64: {
+ uint64_t val_arg, val;
+
+ /* scanf uint64_t from value and check for match */
+ sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint64(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT64_ARRAY: {
+ uint64_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_BOOLEAN_VALUE: {
+ boolean_t val, val_arg;
+
+ /* scanf boolean_t from value and check for match */
+ sr = sscanf(value, "%"SCNi32, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_boolean_value(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_BOOLEAN_ARRAY: {
+ boolean_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi32, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_boolean_array(nvp,
+ &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_HRTIME:
+ case DATA_TYPE_NVLIST:
+ case DATA_TYPE_NVLIST_ARRAY:
+ case DATA_TYPE_BOOLEAN:
+ case DATA_TYPE_UNKNOWN:
+ default:
+ /*
+ * unknown/unsupported data type
+ */
+ return (-1); /* error fail match */
+ }
+
+ /*
+ * check to see if sscanf failed conversion, return approximate
+ * pointer to problem
+ */
+ if (sr != 1) {
+ if (ep)
+ *ep = value;
+ return (-1); /* error fail match - syntax */
+ }
+
+ return (0); /* fail match */
+}
+
+int
+nvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep)
+{
+ return (nvpair_value_match_regex(nvp, ai, value, NULL, ep));
+}
diff --git a/usr/src/lib/libnvpair/libnvpair.h b/usr/src/lib/libnvpair/libnvpair.h
index d1d25ea70e..e655e0d406 100644
--- a/usr/src/lib/libnvpair/libnvpair.h
+++ b/usr/src/lib/libnvpair/libnvpair.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.
*/
@@ -32,12 +31,15 @@
#include <sys/nvpair.h>
#include <stdlib.h>
#include <stdio.h>
+#include <regex.h>
#ifdef __cplusplus
extern "C" {
#endif
void nvlist_print(FILE *, nvlist_t *);
+int nvpair_value_match(nvpair_t *, int, char *, char **);
+int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *, char **);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libnvpair/mapfile-vers b/usr/src/lib/libnvpair/mapfile-vers
index 50252d220f..fb80a984b1 100644
--- a/usr/src/lib/libnvpair/mapfile-vers
+++ b/usr/src/lib/libnvpair/mapfile-vers
@@ -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.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -147,6 +147,10 @@ SUNWprivate_1.1 {
nvlist_lookup_hrtime;
nvlist_print;
nvpair_value_hrtime;
+ nvpair_type_is_array;
+ nvlist_lookup_nvpair_embedded_index;
+ nvpair_value_match;
+ nvpair_value_match_regex;
local:
*;
};
diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_i386 b/usr/src/pkgdefs/SUNWfmd/prototype_i386
index 4866dcd088..3caa790b75 100644
--- a/usr/src/pkgdefs/SUNWfmd/prototype_i386
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_i386
@@ -85,5 +85,7 @@ f none usr/platform/i86pc/lib/fm/topo/maps/chip-hc-topology.xml 444 root bin
f none usr/platform/i86pc/lib/fm/topo/maps/fan-hc-topology.xml 444 root bin
f none usr/platform/i86pc/lib/fm/topo/maps/i86pc-hc-topology.xml 444 root bin
f none usr/platform/i86pc/lib/fm/topo/maps/psu-hc-topology.xml 444 root bin
+f none usr/platform/i86pc/lib/fm/topo/maps/Sun-Fire-X4200-M2-hc-topology.xml 444 root bin
+f none usr/platform/i86pc/lib/fm/topo/maps/Sun-Fire-X4200-Server-hc-topology.xml 444 root bin
f none usr/platform/i86pc/lib/fm/topo/maps/Sun-Fire-X4500-hc-topology.xml 444 root bin
f none usr/platform/i86pc/lib/fm/topo/maps/Sun-Fire-X4540-hc-topology.xml 444 root bin
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
diff --git a/usr/src/uts/intel/io/dktp/controller/ata/ata_common.h b/usr/src/uts/intel/io/dktp/controller/ata/ata_common.h
index 6ed2c16498..d50f00b214 100644
--- a/usr/src/uts/intel/io/dktp/controller/ata/ata_common.h
+++ b/usr/src/uts/intel/io/dktp/controller/ata/ata_common.h
@@ -471,7 +471,7 @@ typedef struct ata_drv {
/* Used by disk side only */
- struct scsi_device ad_device;
+ struct scsi_device *ad_device;
struct scsi_inquiry ad_inquiry;
struct ctl_obj ad_ctl_obj;
uchar_t ad_rd_cmd;
diff --git a/usr/src/uts/intel/io/dktp/controller/ata/ata_disk.c b/usr/src/uts/intel/io/dktp/controller/ata/ata_disk.c
index 974b7d5631..cb95337b69 100644
--- a/usr/src/uts/intel/io/dktp/controller/ata/ata_disk.c
+++ b/usr/src/uts/intel/io/dktp/controller/ata/ata_disk.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.
*/
@@ -373,7 +373,8 @@ ata_disk_init_drive(
/*
* set up the scsi_device and ctl_obj structures
*/
- devp = &ata_drvp->ad_device;
+ devp = kmem_zalloc(scsi_device_size(), KM_SLEEP);
+ ata_drvp->ad_device = devp;
ctlobjp = &ata_drvp->ad_ctl_obj;
devp->sd_inq = &ata_drvp->ad_inquiry;
@@ -418,8 +419,11 @@ ata_disk_init_drive(
if (ata_drvp->ad_block_factor == 0)
ata_drvp->ad_block_factor = 1;
- if (!ata_disk_setup_parms(ata_ctlp, ata_drvp))
+ if (!ata_disk_setup_parms(ata_ctlp, ata_drvp)) {
+ ata_drvp->ad_device = NULL;
+ kmem_free(devp, scsi_device_size());
return (FALSE);
+ }
ata_disk_fake_inquiry(ata_drvp);
@@ -750,12 +754,16 @@ void
ata_disk_uninit_drive(
ata_drv_t *ata_drvp)
{
- struct scsi_device *devp = &ata_drvp->ad_device;
+ struct scsi_device *devp = ata_drvp->ad_device;
ADBG_TRACE(("ata_disk_uninit_drive entered\n"));
- if (ata_drvp->ad_flags & AD_MUTEX_INIT)
- mutex_destroy(&devp->sd_mutex);
+ if (devp) {
+ if (ata_drvp->ad_flags & AD_MUTEX_INIT)
+ mutex_destroy(&devp->sd_mutex);
+ ata_drvp->ad_device = NULL;
+ kmem_free(devp, scsi_device_size());
+ }
}
@@ -811,13 +819,13 @@ ata_disk_bus_ctl(
/* set up pointers to child dip */
- devp = &ata_drvp->ad_device;
+ devp = ata_drvp->ad_device;
/*
* If sd_dev is set, it means that the target has already
* being initialized. The cdip is a duplicate node from
* reexpansion of driver.conf. Fail INITCHILD here.
*/
- if (devp->sd_dev != NULL) {
+ if ((devp == NULL) || (devp->sd_dev != NULL)) {
return (DDI_FAILURE);
}
devp->sd_dev = cdip;
diff --git a/usr/src/uts/sun/io/scsi/adapters/esp.c b/usr/src/uts/sun/io/scsi/adapters/esp.c
index 3e628bd505..956fea0036 100644
--- a/usr/src/uts/sun/io/scsi/adapters/esp.c
+++ b/usr/src/uts/sun/io/scsi/adapters/esp.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.
*/
@@ -723,6 +723,9 @@ esp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
*/
tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
+ /* Indicate that we are 'sizeof (scsi_*(9S))' clean. */
+ scsi_size_clean(dip); /* SCSI_SIZE_CLEAN_VERIFY ok */
+
/*
* the ESC has a rerun bug and the workaround is
* to round up the ESC count; rather than
@@ -1041,7 +1044,7 @@ esp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
*/
(void) sprintf(buf, "esp%d_cache", instance);
esp->e_kmem_cache = kmem_cache_create(buf,
- sizeof (struct esp_cmd), 8,
+ ESP_CMD_SIZE, 8,
esp_kmem_cache_constructor, esp_kmem_cache_destructor,
NULL, (void *)esp, NULL, 0);
if (esp->e_kmem_cache == NULL) {
@@ -1979,7 +1982,7 @@ esp_wakeup_callback_thread(struct callback_info *cb_info)
}
cb_info->c_qlen--;
mutex_exit(&cb_info->c_mutex);
- (*sp->cmd_pkt.pkt_comp)((struct scsi_pkt *)sp);
+ (*sp->cmd_pkt.pkt_comp)(&sp->cmd_pkt);
mutex_enter(&cb_info->c_mutex);
}
/*
@@ -2057,7 +2060,7 @@ esp_callback(struct esp *esp)
ASSERT(sp->cmd_pkt.pkt_comp != 0);
serviced++;
mutex_exit(&cb_info->c_mutex);
- (*sp->cmd_pkt.pkt_comp)((struct scsi_pkt *)sp);
+ (*sp->cmd_pkt.pkt_comp)(&sp->cmd_pkt);
mutex_enter(&cb_info->c_mutex);
n++;
}
@@ -2203,7 +2206,7 @@ esp_callback(struct esp *esp)
static void
esp_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
{
- struct esp_cmd *cmd = (struct esp_cmd *)pkt;
+ struct esp_cmd *cmd = (struct esp_cmd *)pkt->pkt_ha_private;
TRACE_0(TR_FAC_SCSI, TR_ESP_SCSI_IMPL_DMAFREE_START,
"esp_scsi_dmafree_start");
@@ -2225,7 +2228,7 @@ static void
esp_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
{
int i;
- struct esp_cmd *sp = (struct esp_cmd *)pkt;
+ struct esp_cmd *sp = (struct esp_cmd *)pkt->pkt_ha_private;
if (sp->cmd_flags & CFLAG_DMAVALID) {
i = ddi_dma_sync(sp->cmd_dmahandle, 0, 0,
@@ -2273,7 +2276,7 @@ esp_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
ddi_dma_handle_t save_dma_handle;
save_dma_handle = cmd->cmd_dmahandle;
- bzero(cmd, sizeof (*cmd));
+ bzero(cmd, ESP_CMD_SIZE);
cmd->cmd_dmahandle = save_dma_handle;
cmd->cmd_pkt.pkt_scbp = (opaque_t)cmd->cmd_scb;
@@ -2285,6 +2288,7 @@ esp_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
cmd->cmd_pkt.pkt_cdbp = (opaque_t)&cmd->cmd_cdb;
cmd->cmd_pkt.pkt_private = cmd->cmd_pkt_private;
+ cmd->cmd_pkt.pkt_ha_private = (opaque_t)cmd;
} else {
failure++;
}
@@ -2309,7 +2313,7 @@ esp_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
TRACE_0(TR_FAC_SCSI, TR_ESP_SCSI_IMPL_PKTALLOC_END,
"esp_scsi_pktalloc_end");
} else {
- cmd = (struct esp_cmd *)pkt;
+ cmd = (struct esp_cmd *)pkt->pkt_ha_private;
new_cmd = NULL;
}
@@ -2361,8 +2365,7 @@ dma_failure:
}
cmd->cmd_flags = cmd_flags & ~CFLAG_DMAVALID;
if (new_cmd) {
- esp_scsi_destroy_pkt(ap,
- (struct scsi_pkt *)new_cmd);
+ esp_scsi_destroy_pkt(ap, &new_cmd->cmd_pkt);
}
TRACE_0(TR_FAC_SCSI, TR_SCSI_IMPL_DMAGET_END,
"esp_scsi_dmaget_end");
@@ -2377,7 +2380,7 @@ dma_failure:
"esp_scsi_dmaget_end");
}
- return ((struct scsi_pkt *)cmd);
+ return (&cmd->cmd_pkt);
}
/*
@@ -2427,7 +2430,7 @@ esp_pkt_alloc_extern(struct esp *esp, struct esp_cmd *sp,
static void
esp_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
{
- struct esp_cmd *sp = (struct esp_cmd *)pkt;
+ struct esp_cmd *sp = (struct esp_cmd *)pkt->pkt_ha_private;
struct esp *esp = ADDR2ESP(ap);
/*
@@ -2503,7 +2506,7 @@ esp_kmem_cache_constructor(void *buf, void *cdrarg, int kmflags)
int (*callback)(caddr_t) = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP:
DDI_DMA_DONTWAIT;
- bzero(cmd, sizeof (struct esp_cmd));
+ bzero(cmd, ESP_CMD_SIZE);
if (ddi_dma_alloc_handle(esp->e_dev,
esp->e_dma_attr, callback, NULL,
@@ -2731,8 +2734,7 @@ esp_empty_startQ(struct esp *esp)
}
if (sp->cmd_pkt.pkt_comp) {
mutex_exit(ESP_MUTEX);
- (*sp->cmd_pkt.pkt_comp)(
- (struct scsi_pkt *)sp);
+ (*sp->cmd_pkt.pkt_comp)(&sp->cmd_pkt);
mutex_enter(ESP_MUTEX);
}
mutex_enter(&esp->e_startQ_mutex);
@@ -2771,7 +2773,7 @@ esp_empty_startQ(struct esp *esp)
static int
esp_start(struct scsi_address *ap, struct scsi_pkt *pkt)
{
- struct esp_cmd *sp = (struct esp_cmd *)pkt;
+ struct esp_cmd *sp = (struct esp_cmd *)pkt->pkt_ha_private;
struct esp *esp = ADDR2ESP(ap);
int rval;
@@ -4482,7 +4484,7 @@ esp_call_pkt_comp(struct esp *esp, struct esp_cmd *sp)
} else if ((sp->cmd_pkt.pkt_flags & FLAG_IMMEDIATE_CB) &&
sp->cmd_pkt.pkt_comp) {
mutex_exit(ESP_MUTEX);
- (*sp->cmd_pkt.pkt_comp)((struct scsi_pkt *)sp);
+ (*sp->cmd_pkt.pkt_comp)(&sp->cmd_pkt);
mutex_enter(ESP_MUTEX);
} else {
EPRINTF2("No completion routine for 0x%p reason %x\n",
@@ -7952,7 +7954,7 @@ esp_makeproxy_cmd(struct esp_cmd *sp, struct scsi_address *ap, int nmsgs, ...)
int i;
ASSERT(nmsgs <= (CDB_GROUP5 - CDB_GROUP0 - 3));
- bzero(sp, sizeof (*sp));
+ bzero(sp, ESP_CMD_SIZE);
sp->cmd_pkt.pkt_address = *ap;
sp->cmd_pkt.pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
sp->cmd_pkt.pkt_scbp = (opaque_t)&sp->cmd_scb[0];
@@ -8348,7 +8350,8 @@ esp_cmd_timeout(struct esp *esp, struct esp_cmd *sp,
* disable DVMA to avoid a timeout on SS1
*/
if (dmar->dmaga_csr & DMAGA_ENDVMA) {
- while (dmar->dmaga_csr & DMAGA_REQPEND);
+ while (dmar->dmaga_csr & DMAGA_REQPEND)
+ ;
dmar->dmaga_csr &= ~DMAGA_ENDVMA;
dma_enabled++;
}
@@ -8573,7 +8576,9 @@ esp_create_arq_pkt(struct esp *esp, struct scsi_address *ap, int create)
/*
* Allocate a request sense packet using get_pktiopb
*/
- struct esp_cmd *rqpktp;
+ struct esp_cmd *rqcmd;
+ struct scsi_pkt *rqpkt;
+ struct buf *bp;
int slot = ap->a_target * NLUNS_PER_TARGET | ap->a_lun;
int rval = 0;
@@ -8584,10 +8589,10 @@ esp_create_arq_pkt(struct esp *esp, struct scsi_address *ap, int create)
*/
if (esp->e_save_pkt[slot]) {
rval = -1;
- } else if ((rqpktp = esp->e_arq_pkt[slot]) != 0) {
- struct buf *bp = (struct buf *)
- (rqpktp->cmd_pkt.pkt_private);
- scsi_destroy_pkt((struct scsi_pkt *)rqpktp);
+ } else if ((rqcmd = esp->e_arq_pkt[slot]) != 0) {
+ rqpkt = &rqcmd->cmd_pkt;
+ bp = (struct buf *)rqpkt->pkt_private;
+ scsi_destroy_pkt(rqpkt);
scsi_free_consistent_buf(bp);
esp->e_rq_sense_data[slot] = 0;
esp->e_arq_pkt[slot] = 0;
@@ -8599,7 +8604,6 @@ esp_create_arq_pkt(struct esp *esp, struct scsi_address *ap, int create)
* drivers to use SENSE_LENGTH
* Allocate a request sense packet.
*/
- struct buf *bp;
/*
* if one exists, don't create another
@@ -8609,25 +8613,25 @@ esp_create_arq_pkt(struct esp *esp, struct scsi_address *ap, int create)
}
bp = scsi_alloc_consistent_buf(ap, (struct buf *)NULL,
SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL);
- rqpktp = (struct esp_cmd *)scsi_init_pkt(ap,
- (struct scsi_pkt *)NULL, bp, CDB_GROUP0, 1, 0,
- PKT_CONSISTENT, SLEEP_FUNC, NULL);
+ rqpkt = scsi_init_pkt(ap, (struct scsi_pkt *)NULL,
+ bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT, SLEEP_FUNC, NULL);
+ rqcmd = (struct esp_cmd *)rqpkt->pkt_ha_private;
esp->e_rq_sense_data[slot] =
(struct scsi_extended_sense *)bp->b_un.b_addr;
- rqpktp->cmd_pkt.pkt_private = (opaque_t)bp;
+ rqpkt->pkt_private = (opaque_t)bp;
- RQ_MAKECOM_G0(((struct scsi_pkt *)rqpktp),
+ RQ_MAKECOM_G0(rqpkt,
FLAG_NOPARITY | FLAG_SENSING | FLAG_HEAD | FLAG_NODISCON,
(char)SCMD_REQUEST_SENSE, 0, (char)SENSE_LENGTH);
- rqpktp->cmd_flags |= CFLAG_CMDARQ;
- esp->e_arq_pkt[slot] = rqpktp;
+ rqcmd->cmd_flags |= CFLAG_CMDARQ;
+ esp->e_arq_pkt[slot] = rqcmd;
/*
* we need a function ptr here so abort/reset can
* delay callbacks; esp_call_pkt_comp() calls
* esp_complete_arq_pkt() directly without releasing the lock
*/
#ifndef __lock_lint
- rqpktp->cmd_pkt.pkt_comp =
+ rqpkt->pkt_comp =
(void (*)(struct scsi_pkt *))esp_complete_arq_pkt;
#endif
}
@@ -8762,7 +8766,7 @@ static int
_esp_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
{
struct esp *esp = ADDR2ESP(ap);
- struct esp_cmd *sp = (struct esp_cmd *)pkt;
+ struct esp_cmd *sp = (struct esp_cmd *)pkt->pkt_ha_private;
int rval = FALSE;
short slot = (ap->a_target * NLUNS_PER_TARGET) | ap->a_lun;
struct esp_cmd *cur_sp = esp->e_slots[slot];
@@ -9191,7 +9195,8 @@ esp_assert_atn(struct esp *esp)
volatile struct dmaga *dmar = esp->e_dma;
if (dmar->dmaga_csr & DMAGA_ENDVMA) {
- while (dmar->dmaga_csr & DMAGA_REQPEND);
+ while (dmar->dmaga_csr & DMAGA_REQPEND)
+ ;
dmar->dmaga_csr &= ~DMAGA_ENDVMA;
Esp_cmd(esp, CMD_SET_ATN);
dmar->dmaga_csr |= DMAGA_ENDVMA;
@@ -9255,9 +9260,9 @@ static int
esp_abort_disconnected_cmd(struct esp *esp, struct scsi_address *ap,
struct esp_cmd *sp, uchar_t msg, int slot)
{
- auto struct esp_cmd local;
- struct esp_cmd *proxy_cmdp = &local;
- int target = ap->a_target;
+ struct esp_cmd *proxy_cmdp;
+ int target = ap->a_target;
+ int rval;
/*
* if reset delay is active, we cannot start a selection
@@ -9269,6 +9274,7 @@ esp_abort_disconnected_cmd(struct esp *esp, struct scsi_address *ap,
IPRINTF1("aborting disconnected tagged cmd(s) with %s\n",
scsi_mname(msg));
+ proxy_cmdp = kmem_alloc(ESP_CMD_SIZE, KM_SLEEP);
if (TAGGED(target) && (msg == MSG_ABORT)) {
esp_makeproxy_cmd(proxy_cmdp, ap, 1, msg);
} else if (sp) {
@@ -9280,13 +9286,16 @@ esp_abort_disconnected_cmd(struct esp *esp, struct scsi_address *ap,
} else if (NOTAG(target) && (msg == MSG_ABORT)) {
esp_makeproxy_cmd(proxy_cmdp, ap, 1, msg);
} else {
- return (FALSE);
+ rval = FALSE;
+ goto out;
}
} else {
esp_makeproxy_cmd(proxy_cmdp, ap, 1, msg);
}
- return (esp_do_proxy_cmd(esp, proxy_cmdp, ap, slot, scsi_mname(msg)));
+ rval = esp_do_proxy_cmd(esp, proxy_cmdp, ap, slot, scsi_mname(msg));
+out: kmem_free(proxy_cmdp, ESP_CMD_SIZE);
+ return (rval);
}
/*
@@ -9704,8 +9713,8 @@ esp_reset_cleanup(struct esp *esp, int slot)
static int
esp_reset_disconnected_cmd(struct esp *esp, struct scsi_address *ap, int slot)
{
- auto struct esp_cmd local;
- struct esp_cmd *sp = &local;
+ struct esp_cmd *proxy_cmdp;
+ int rval;
/*
* if reset delay active we cannot access the target
@@ -9716,9 +9725,12 @@ esp_reset_disconnected_cmd(struct esp *esp, struct scsi_address *ap, int slot)
esp_check_in_transport(esp, NULL);
- esp_makeproxy_cmd(sp, ap, 1, MSG_DEVICE_RESET);
- return (esp_do_proxy_cmd(esp, sp, ap, slot,
- scsi_mname(MSG_DEVICE_RESET)));
+ proxy_cmdp = kmem_alloc(ESP_CMD_SIZE, KM_SLEEP);
+ esp_makeproxy_cmd(proxy_cmdp, ap, 1, MSG_DEVICE_RESET);
+ rval = esp_do_proxy_cmd(esp, proxy_cmdp, ap, slot,
+ scsi_mname(MSG_DEVICE_RESET));
+ kmem_free(proxy_cmdp, ESP_CMD_SIZE);
+ return (rval);
}
/*
@@ -10432,7 +10444,8 @@ esp_printstate(struct esp *esp, char *msg)
* disable DVMA to avoid a timeout on SS1
*/
if (dmar->dmaga_csr & DMAGA_ENDVMA) {
- while (dmar->dmaga_csr & DMAGA_REQPEND);
+ while (dmar->dmaga_csr & DMAGA_REQPEND)
+ ;
dmar->dmaga_csr &= ~DMAGA_ENDVMA;
fifo_flag = ep->esp_fifo_flag;
dmar->dmaga_csr |= DMAGA_ENDVMA;
diff --git a/usr/src/uts/sun/io/scsi/adapters/fas.c b/usr/src/uts/sun/io/scsi/adapters/fas.c
index 4d77e705d3..75f0ad8a10 100644
--- a/usr/src/uts/sun/io/scsi/adapters/fas.c
+++ b/usr/src/uts/sun/io/scsi/adapters/fas.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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -691,6 +690,9 @@ fas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
*/
tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
+ /* Indicate that we are 'sizeof (scsi_*(9S))' clean. */
+ scsi_size_clean(dip); /* SCSI_SIZE_CLEAN_VERIFY ok */
+
/*
* initialize transport structure
*/
@@ -1636,7 +1638,8 @@ FAS_FLUSH_DMA_HARD(struct fas *fas)
fas->f_dma_csr |= (DMA_INTEN|DMA_TWO_CYCLE|DMA_DSBL_PARITY|
DMA_DSBL_DRAIN);
fas->f_dma_csr &= ~(DMA_ENDVMA | DMA_WRITE);
- while (fas_dma_reg_read(fas, &fas->f_dma->dma_csr) & DMA_REQPEND);
+ while (fas_dma_reg_read(fas, &fas->f_dma->dma_csr) & DMA_REQPEND)
+ ;
fas_dma_reg_write(fas, &fas->f_dma->dma_csr, 0);
fas_dma_reg_write(fas, &fas->f_dma->dma_csr, fas->f_dma_csr);
fas_dma_reg_write(fas, &fas->f_dma->dma_addr, 0);
@@ -8084,7 +8087,7 @@ fas_makeproxy_cmd(struct fas_cmd *sp, struct scsi_address *ap,
ASSERT(nmsgs <= (CDB_GROUP5 - CDB_GROUP0 - 3));
bzero(sp, sizeof (*sp));
- bzero(pkt, sizeof (*pkt));
+ bzero(pkt, scsi_pkt_size());
pkt->pkt_address = *ap;
pkt->pkt_cdbp = (opaque_t)&sp->cmd_cdb[0];
@@ -8198,10 +8201,11 @@ static int
fas_abort_disconnected_cmd(struct fas *fas, struct scsi_address *ap,
struct fas_cmd *sp, uchar_t msg, int slot)
{
- auto struct fas_cmd local;
- struct scsi_pkt pkt;
- struct fas_cmd *proxy_cmdp = &local;
- int target = ap->a_target;
+ auto struct fas_cmd local;
+ struct fas_cmd *proxy_cmdp = &local;
+ struct scsi_pkt *pkt;
+ int rval;
+ int target = ap->a_target;
/*
* if reset delay is active, we cannot start a selection
@@ -8216,16 +8220,19 @@ fas_abort_disconnected_cmd(struct fas *fas, struct scsi_address *ap,
IPRINTF1("aborting disconnected tagged cmd(s) with %s\n",
scsi_mname(msg));
+ pkt = kmem_alloc(scsi_pkt_size(), KM_SLEEP);
if (sp && (TAGGED(target) && (msg == MSG_ABORT_TAG))) {
int tag = sp->cmd_tag[1];
ASSERT(sp == fas->f_active[slot]->f_slot[tag]);
- fas_makeproxy_cmd(proxy_cmdp, ap, &pkt, 3,
+ fas_makeproxy_cmd(proxy_cmdp, ap, pkt, 3,
MSG_SIMPLE_QTAG, tag, msg);
} else {
- fas_makeproxy_cmd(proxy_cmdp, ap, &pkt, 1, msg);
+ fas_makeproxy_cmd(proxy_cmdp, ap, pkt, 1, msg);
}
- return (fas_do_proxy_cmd(fas, proxy_cmdp, ap, scsi_mname(msg)));
+ rval = fas_do_proxy_cmd(fas, proxy_cmdp, ap, scsi_mname(msg));
+ kmem_free(pkt, scsi_pkt_size());
+ return (rval);
}
/*
@@ -8530,12 +8537,16 @@ fas_reset_cleanup(struct fas *fas, int slot)
static int
fas_reset_disconnected_cmd(struct fas *fas, struct scsi_address *ap)
{
- auto struct fas_cmd local;
- struct fas_cmd *sp = &local;
- struct scsi_pkt pkt;
+ auto struct fas_cmd local;
+ struct fas_cmd *sp = &local;
+ struct scsi_pkt *pkt;
+ int rval;
- fas_makeproxy_cmd(sp, ap, &pkt, 1, MSG_DEVICE_RESET);
- return (fas_do_proxy_cmd(fas, sp, ap, scsi_mname(MSG_DEVICE_RESET)));
+ pkt = kmem_alloc(scsi_pkt_size(), KM_SLEEP);
+ fas_makeproxy_cmd(sp, ap, pkt, 1, MSG_DEVICE_RESET);
+ rval = fas_do_proxy_cmd(fas, sp, ap, scsi_mname(MSG_DEVICE_RESET));
+ kmem_free(pkt, scsi_pkt_size());
+ return (rval);
}
/*
diff --git a/usr/src/uts/sun/io/scsi/adapters/sf.c b/usr/src/uts/sun/io/scsi/adapters/sf.c
index e00452879b..ffdbc78c36 100644
--- a/usr/src/uts/sun/io/scsi/adapters/sf.c
+++ b/usr/src/uts/sun/io/scsi/adapters/sf.c
@@ -18,12 +18,10 @@
*
* 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.
*/
-
#pragma ident "%Z%%M% %I% %E% SMI"
/*
@@ -577,7 +575,7 @@ sf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
(void) sprintf(buf, "sf%d_cache", instance);
sf->sf_pkt_cache = kmem_cache_create(buf,
sizeof (fcal_packet_t) + sizeof (struct sf_pkt) +
- sizeof (struct scsi_pkt), 8,
+ scsi_pkt_size(), 8,
sf_kmem_cache_constructor, sf_kmem_cache_destructor,
NULL, NULL, NULL, 0);
if (sf->sf_pkt_cache == NULL) {
@@ -671,6 +669,9 @@ sf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
goto fail;
}
+ /* Indicate that we are 'sizeof (scsi_*(9S))' clean. */
+ scsi_size_clean(dip); /* SCSI_SIZE_CLEAN_VERIFY ok */
+
/* save ptr to new transport structure and fill it in */
sf->sf_tran = tran;
@@ -1559,7 +1560,7 @@ sf_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
new_cmd = cmd; /* for later cleanup if needed */
} else {
/* pkt already exists -- just a request for DMA allocation */
- cmd = (struct sf_pkt *)pkt->pkt_ha_private;
+ cmd = PKT2CMD(pkt);
fpkt = cmd->cmd_fp_pkt;
}
@@ -1687,7 +1688,7 @@ sf_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
static void
sf_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
{
- struct sf_pkt *cmd = (struct sf_pkt *)pkt->pkt_ha_private;
+ struct sf_pkt *cmd = PKT2CMD(pkt);
struct sf *sf = ADDR2SF(ap);
struct sf_target *target = ADDR2TARGET(ap);
struct fcal_packet *fpkt = cmd->cmd_fp_pkt;
@@ -1727,7 +1728,7 @@ sf_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
static void
sf_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
{
- struct sf_pkt *cmd = (struct sf_pkt *)pkt->pkt_ha_private;
+ struct sf_pkt *cmd = PKT2CMD(pkt);
if (cmd->cmd_flags & CFLAG_DMAVALID) {
@@ -1745,7 +1746,7 @@ sf_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
static void
sf_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
{
- struct sf_pkt *cmd = (struct sf_pkt *)pkt->pkt_ha_private;
+ struct sf_pkt *cmd = PKT2CMD(pkt);
if (cmd->cmd_flags & CFLAG_DMAVALID) {
@@ -4599,10 +4600,8 @@ sf_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
deferred_destroy = 0;
if (pkt != NULL) {
- cmd = (struct sf_pkt *)((char *)pkt - sizeof (struct sf_pkt)
- - sizeof (struct fcal_packet));
- fpkt = (struct fcal_packet *)((char *)cmd +
- sizeof (struct sf_pkt));
+ cmd = PKT2CMD(pkt);
+ fpkt = cmd->cmd_fp_pkt;
SF_DEBUG(2, (sf, CE_NOTE, "sf_abort packet %p\n",
(void *)fpkt));
pcmd = NULL;
@@ -6230,7 +6229,7 @@ sf_target_timeout(struct sf *sf, struct sf_pkt *cmd)
SF_DEBUG(1, (sf, CE_NOTE, "Command 0x%p to target %x timed out\n",
(void *)cmd->cmd_fp_pkt, cmd->cmd_pkt->pkt_address.a_target));
- fpkt = (struct fcal_packet *)((char *)cmd + sizeof (struct sf_pkt));
+ fpkt = cmd->cmd_fp_pkt;
if (sf_core && (sf_core & SF_CORE_CMD_TIMEOUT)) {
sf_token = (int *)(uintptr_t)
@@ -6819,7 +6818,7 @@ sf_ioctl(dev_t dev,
struct devctl_iocdata *dcp;
dev_info_t *cdip;
struct scsi_address ap;
- scsi_hba_tran_t tran;
+ scsi_hba_tran_t *tran;
sf = ddi_get_soft_state(sf_state, SF_MINOR2INST(getminor(dev)));
@@ -6967,15 +6966,20 @@ sf_ioctl(dev_t dev,
retval = ENXIO;
goto dun;
}
- tran = *target->sft_tran;
+
+ /* This is ugly */
+ tran = kmem_zalloc(scsi_hba_tran_size(), KM_SLEEP);
+ bcopy(target->sft_tran, tran, scsi_hba_tran_size());
mutex_exit(&target->sft_mutex);
- ap.a_hba_tran = &tran;
+ ap.a_hba_tran = tran;
ap.a_target = sf_alpa_to_switch[target->sft_al_pa];
if (sf_reset(&ap, RESET_TARGET) == FALSE) {
retval = EIO;
- goto dun;
+ } else {
+ retval = 0;
}
- break;
+ kmem_free(tran, scsi_hba_tran_size());
+ goto dun;
case DEVCTL_BUS_QUIESCE:
case DEVCTL_BUS_UNQUIESCE:
diff --git a/usr/src/uts/sun/sys/scsi/adapters/espcmd.h b/usr/src/uts/sun/sys/scsi/adapters/espcmd.h
index cb4a9b680d..d2d94d994e 100644
--- a/usr/src/uts/sun/sys/scsi/adapters/espcmd.h
+++ b/usr/src/uts/sun/sys/scsi/adapters/espcmd.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,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#ifndef _SYS_SCSI_ADAPTERS_ESPCMD_H
@@ -60,7 +59,6 @@ extern "C" {
* needs 16 byte CDBs
*/
struct esp_cmd {
- struct scsi_pkt cmd_pkt; /* the generic packet itself */
struct esp_cmd *cmd_forw; /* ready fifo que link */
uchar_t *cmd_cdbp; /* active command pointer */
uchar_t *cmd_scbp; /* active status pointer */
@@ -91,7 +89,12 @@ struct esp_cmd {
uchar_t cmd_scb[EXTCMDS_STATUS_SIZE]; /* arq size */
ushort_t cmd_age; /* cmd age (tagged queing) */
uchar_t cmd_tag[2]; /* command tag */
+ struct scsi_pkt cmd_pkt; /* must be last */
+ /* the generic packet itself */
+ /* ... scsi_pkt_size() */
};
+#define ESP_CMD_SIZE (sizeof (struct esp_cmd) - \
+ sizeof (struct scsi_pkt) + scsi_pkt_size())
/*
diff --git a/usr/src/uts/sun/sys/scsi/adapters/fascmd.h b/usr/src/uts/sun/sys/scsi/adapters/fascmd.h
index cbd4c7cb36..4be027b359 100644
--- a/usr/src/uts/sun/sys/scsi/adapters/fascmd.h
+++ b/usr/src/uts/sun/sys/scsi/adapters/fascmd.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,10 +19,9 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 1996-2001 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
-
#ifndef _SYS_SCSI_ADAPTERS_FASCMD_H
#define _SYS_SCSI_ADAPTERS_FASCMD_H
@@ -61,8 +59,8 @@ extern "C" {
#define PKT2CMD(pkt) ((struct fas_cmd *)(pkt)->pkt_ha_private)
#define CMD2PKT(sp) ((sp)->cmd_pkt)
-#define EXTCMD_SIZE (sizeof (struct fas_cmd) + sizeof (struct scsi_pkt))
-#define EXTCMDS_STATUS_SIZE (sizeof (struct scsi_arq_status))
+#define EXTCMD_SIZE (sizeof (struct fas_cmd) + scsi_pkt_size())
+#define EXTCMDS_STATUS_SIZE (sizeof (struct scsi_arq_status))
struct fas_cmd {
struct scsi_pkt *cmd_pkt; /* the generic packet itself */