diff options
Diffstat (limited to 'usr/src')
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&+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&-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&-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&-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&-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&+OK2RM", "+PRSNT&-OK2RM", + "+OK2RM", "-OK2RM", + "-OK2RM&-PRSNT", "-OK2RM&-PRSNT", + "-OK2RM&-PRSNT", "-OK2RM&+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&+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&-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&-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&-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&-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&+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&+OK2RM", "+PRSNT&-OK2RM", + "+OK2RM", "-OK2RM", + "-OK2RM&-PRSNT", "-OK2RM&-PRSNT", + "-OK2RM&-PRSNT", "-OK2RM&+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 */ |