disk_common.c revision 888e055994b8b0dc77b98c53dd97026237caec5d
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * CDDL HEADER START
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * The contents of this file are subject to the terms of the
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Common Development and Distribution License (the "License").
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * You may not use this file except in compliance with the License.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * See the License for the specific language governing permissions
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * and limitations under the License.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * When distributing Covered Code, include this CDDL HEADER in each
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * If applicable, add the following below this CDDL HEADER, with the
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * fields enclosed by brackets "[]" replaced with your own identifying
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * information: Portions Copyright [yyyy] [name of copyright owner]
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * CDDL HEADER END
738c43b514a3570e657652233a5a19291a328a28Eric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Use is subject to license terms.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Functions in this file are shared between the disk and ses enumerators.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * A topo_list_t of all disks is returned by a successful disk_list_gather()
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * call, and the list is freed by a disk_list_free(). To create a 'disk' topo
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * node below a specific 'bay' parent node either disk_declare_path() or
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * disk_declare_addr() are called. The caller determines which 'disk' is
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * in which 'bay'. A disk's 'label' and 'authority' information come from
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * its parent 'bay' node.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * disk node information.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcthtypedef struct disk_di_node {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* the following two fields are always defined */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth/* common callback information for di_walk_node() and di_devlink_walk */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcthtypedef struct disk_cbdata {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth disk_di_node_t *dcb_dnode; /* for di_devlink_walk only */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Given a /devices path for a whole disk, appending this extension gives the
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * path to a raw device that can be opened.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Methods for disks. This is used by the disk-transport module to
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * generate ereports based off SCSI disk status.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcthstatic int disk_status(topo_mod_t *, tnode_t *, topo_version_t,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Set the properties of the disk node, from disk_di_node_t data.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Properties include:
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * group: protocol properties: resource, asru, label, fru
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * group: authority properties: product-id, chasis-id, server-id
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * group: io properties: devfs-path, devid
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * group: storage properties:
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * - logical-disk, disk-model, disk-manufacturer, serial-number
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * - firmware-revision, capacity-in-bytes
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* form and set the asru */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if ((asru = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* pull the label property down from our parent 'bay' node */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* get the resource fmri, and use it as the fru */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* create/set the authority group */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if ((topo_pgroup_create(dtn, &disk_auth_pgroup, &err) != 0) &&
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* create/set the devfs-path and devid in the io group */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (topo_prop_set_string(dtn, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (topo_prop_set_string(dtn, TOPO_PGROUP_IO, TOPO_IO_DEVID,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth topo_prop_set_string_array(dtn, TOPO_PGROUP_IO, TOPO_IO_PHYS_PATH,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* create the storage group */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (topo_pgroup_create(dtn, &storage_pgroup, &err) != 0) {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* set the storage group public /dev name */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* populate other misc storage group properties */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (dnode->ddn_mfg && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (dnode->ddn_model && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (dnode->ddn_serial && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (dnode->ddn_firm && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (dnode->ddn_cap && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
738c43b514a3570e657652233a5a19291a328a28Eric Schrock * Trim leading and trailing whitespace from the string.
738c43b514a3570e657652233a5a19291a328a28Eric Schrockstatic char *
738c43b514a3570e657652233a5a19291a328a28Eric Schrockdisk_trim_whitespace(topo_mod_t *mod, const char *begin)
940d71d237794874e18a0eb72f6564821a823517eschrock const char *end;
940d71d237794874e18a0eb72f6564821a823517eschrock if ((buf = topo_mod_alloc(mod, count + 1)) == NULL)
738c43b514a3570e657652233a5a19291a328a28Eric Schrock * Manufacturing strings can contain characters that are invalid for use in hc
738c43b514a3570e657652233a5a19291a328a28Eric Schrock * authority names. This trims leading and trailing whitespace, and
738c43b514a3570e657652233a5a19291a328a28Eric Schrock * substitutes any characters known to be bad.
738c43b514a3570e657652233a5a19291a328a28Eric Schrockdisk_auth_clean(topo_mod_t *mod, const char *str)
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth/* create the disk topo node */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth disk_di_node_t *dnode, const char *name, topo_instance_t i)
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* form 'part=' of fmri as "<mfg>-<model>" */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i, NULL,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth "hcfmri (%s%d/%s%d) error %s\n",
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if ((dtn = topo_node_bind(mod, parent, name, i, fmri)) == NULL) {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth "bind (%s%d/%s%d) error %s\n",
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* add the properties of the disk */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth "disk_set_props (%s%d/%s%d) error %s\n",
602ca9ea8f9ce0933f0944601cc5d230e91a950dcthdisk_declare(topo_mod_t *mod, tnode_t *parent, disk_di_node_t *dnode)
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* create the disk topo node: one disk per 'bay' */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth "disk_tnode_create error %s\n",
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (-1);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* register disk_methods against the disk topo node */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (topo_method_register(mod, dtn, disk_methods) != 0) {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth "topo_method_register error %s\n",
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (-1);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (0);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcthdisk_declare_path(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth const char *path)
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Check for match using physical phci (ddn_ppath). Use
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * di_devfs_path_match so generic.vs.non-generic names match.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (0);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcthdisk_declare_addr(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth const char *addr)
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* Check for match using addr. */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (0);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth/* di_devlink callback for disk_di_node_add */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth const char *devpath;
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* trim the slice off the public name */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* Establish the public /dev name (no slice) */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth dnode->ddn_lpath = topo_mod_strdup(mod, ctds ? ctds + 1 : devpath);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcthstatic void
602ca9ea8f9ce0933f0944601cc5d230e91a950dcthdisk_di_node_free(topo_mod_t *mod, disk_di_node_t *dnode)
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* free the stuff we point to */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* free self */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcthdisk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp)
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* check for list duplicate using devid search */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (0);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if ((dnode = topo_mod_zalloc(mod, sizeof (disk_di_node_t))) == NULL)
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (-1);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* Establish the devid. */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* Establish the devinfo dpath */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Establish the physical ppath and target ports. If the device is
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * non-mpxio then dpath and ppath are the same, and the target port is a
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * property of the device node.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * If dpath is a client node under scsi_vhci, then iterate over all
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * paths and get their physical paths and target port properrties.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * di_path_client_next_path call below will
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * return non-NULL, and ppath is set to the physical path to the first
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * pathinfo node.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * NOTE: It is possible to get a generic.vs.non-generic path
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * for di_devfs_path.vs.di_path_devfs_path like:
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * xml: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/sd@2,0
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * pnode: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/disk@2,0
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * To resolve this issue disk_declare_path() needs to use the
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * special di_devfs_path_match() interface.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth while ((pnode = di_path_client_next_path(node, pnode)) != NULL) {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (pathcount == 0) {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth for (i = 0; i < ret; i++) {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (portcount != 0 &&
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth for (i = 0; i < ret; i++) {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Find the public /dev name by adding a minor name and using
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * di_devlink interface for reverse translation (use devinfo path).
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth (void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath, extn);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth (void) di_devlink_walk(cbp->dcb_devhdl, "^dsk/", minorpath,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth "failed to determine logical path");
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* cache various bits of optional information about the disk */
738c43b514a3570e657652233a5a19291a328a28Eric Schrock if ((dnode->ddn_mfg = disk_trim_whitespace(mod, s)) == NULL)
738c43b514a3570e657652233a5a19291a328a28Eric Schrock if ((dnode->ddn_model = disk_trim_whitespace(mod, s)) == NULL)
738c43b514a3570e657652233a5a19291a328a28Eric Schrock if ((dnode->ddn_firm = disk_trim_whitespace(mod, s)) == NULL)
738c43b514a3570e657652233a5a19291a328a28Eric Schrock if ((dnode->ddn_serial = disk_trim_whitespace(mod, s)) == NULL)
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * To save kernel memory, the driver may not define
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * "device-dblksize" when its value is default DEV_BSIZE.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if ((dnode->ddn_cap = topo_mod_strdup(mod, lentry)) == NULL)
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (0);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (-1);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth/* di_walk_node callback for disk_list_gather */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* only interested in nodes that have devids */
738c43b514a3570e657652233a5a19291a328a28Eric Schrock if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* create/find the devid scsi topology node */
738c43b514a3570e657652233a5a19291a328a28Eric Schrock if ((devtree = topo_mod_devinfo(mod)) == DI_NODE_NIL) {
525b85dbd2fc64df4bd0092c1a2b0827dd8e1e89Eric Schrock "topo_mod_devinfo() failed");
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (-1);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if ((devhdl = di_devlink_init(NULL, 0)) == DI_NODE_NIL) {
525b85dbd2fc64df4bd0092c1a2b0827dd8e1e89Eric Schrock "di_devlink_init() failed");
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (-1);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* walk the devinfo snapshot looking for nodes with devids */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (0);
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* order of delete/free is important */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Query the current disk status. If successful, the disk status is returned
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * as an nvlist consisting of at least the following members:
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * protocol string Supported protocol (currently "scsi")
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * status nvlist Arbitrary protocol-specific information
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * about the current state of the disk.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * faults nvlist A list of supported faults. Each
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * element of this list is a boolean value.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * An element's existence indicates that
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * the drive supports detecting this fault,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * and the value indicates the current
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * state of the fault.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * <fault-name> nvlist For each fault named in 'faults', a
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * nvlist describing protocol-specific
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * attributes of the fault.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * This method relies on the libdiskstatus library to query this information.
602ca9ea8f9ce0933f0944601cc5d230e91a950dcthdisk_status(topo_mod_t *mod, tnode_t *nodep, topo_version_t vers,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * If the caller specifies the "path" parameter, then this indicates
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * that we should use this instead of deriving it from the topo node
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth if (nvlist_lookup_string(in_nvl, "path", &fullpath) == 0) {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Get the /devices path and attempt to open the disk status
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth * Note that sizeof(string) includes the terminating NULL byte
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth (void) snprintf(fullpath, pathlen, "/devices%s%s", devpath,
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth return (0);