findevs.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <fcntl.h>
#include <libdevinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <libgen.h>
#include <unistd.h>
#include <devid.h>
#include "libdiskmgt.h"
#include "disks_private.h"
#define CLUSTER_DEV "did"
/* specify which disk links to use in the /dev directory */
#define DEVLINK_REGEX "rdsk/.*"
#define DEVLINK_FLOPPY_REGEX "rdiskette[0-9]"
#define DEVLINK_DID_REGEX "did/rdsk/.*"
#define FLOPPY_NAME "rdiskette"
#define MAXPROPLEN 1024
#define DEVICE_ID_PROP "devid"
#define PROD_ID_PROP "inquiry-product-id"
#define PROD_ID_USB_PROP "usb-product-name"
#define REMOVABLE_PROP "removable-media"
#define SCSI_OPTIONS_PROP "scsi-options"
#define VENDOR_ID_PROP "inquiry-vendor-id"
#define VENDOR_ID_USB_PROP "usb-vendor-name"
#define WWN_PROP "node-wwn"
/* The list of names of possible disk types used by libdevinfo. */
static char *disktypes[] = {
};
/*
* Most of the removable media will be lumped under here; CD, DVD, MO, etc.
*/
static char *cdromtypes[] = {
};
static char *ctrltypes[] = {
};
static char *bustypes[] = {
"sbus",
"pci",
"usb",
};
void *arg);
struct search_args *args);
static int add_int2array(int p, int **parray);
static int add_ptr2array(void *p, void ***parray);
struct search_args *args);
int size);
struct search_args *args);
static void remove_invalid_controller(char *name,
/*
* The functions in this file do a dev tree walk to build up a model of the
* disks, controllers and paths on the system. This model is returned in the
* args->disk_listp and args->controller_listp members of the args param.
* There is no global data for this file so it is thread safe. It is up to
* the caller to merge the resulting model with any existing model that is
* cached. The caller must also free the memory for this model when it is
* no longer needed.
*/
void
{
args->dev_walk_status = 0;
/*
* Have to make several passes at this with the new devfs caching.
* devices. Finally, we get cluster devices.
*/
flags = DINFOCACHE;
/* do another pass to clean up cluster devpaths */
flags = DINFOCACHE;
}
}
/*
* Definitions of private functions
*/
static bus_t *
{
char *btype;
char *devpath;
char kstat_name[MAXPATHLEN];
if (node == DI_NODE_NIL) {
return (NULL);
}
}
di_devfs_path_free((void *) devpath);
return (NULL);
}
}
return (bp);
}
/* Special handling for root node. */
di_devfs_path_free((void *) devpath);
return (NULL);
}
if (dm_debug) {
}
return (NULL);
}
di_devfs_path_free((void *) devpath);
return (NULL);
}
return (NULL);
}
return (NULL);
}
/* if parent node is a bus, get its name */
di_devfs_path_free((void *) devpath);
return (NULL);
}
} else {
}
return (NULL);
}
return (NULL);
}
}
return (bp);
}
static int
{
struct search_args *args;
char *devpath;
char slice_path[MAXPATHLEN];
int result = DI_WALK_CONTINUE;
return (DI_WALK_CONTINUE);
}
if (dm_debug > 1) {
/* This is all just debugging code */
char *devpath;
char dev_name[MAXPATHLEN];
di_devfs_path_free((void *) devpath);
}
args->dev_walk_status = 0;
/*
* Fix the devpaths for the cluster drive.
*
* We will come through here once for each raw slice device name.
*/
di_devfs_path_free((void *) devpath);
/* Walk the /dev tree to get the cluster devlinks. */
if (args->dev_walk_status != 0) {
}
return (result);
}
static controller_t *
{
char *devpath;
char kstat_name[MAXPATHLEN];
char *c_type = DM_CTYPE_UNKNOWN;
di_devfs_path_free((void *) devpath);
return (cp);
}
/* Special handling for fp attachment node. */
if (pnode != DI_NODE_NIL) {
di_devfs_path_free((void *) devpath);
di_devfs_path_free((void *) devpath);
return (cp);
}
/* not in the list, create it */
}
}
if (dm_debug) {
}
return (NULL);
}
di_devfs_path_free((void *) devpath);
return (NULL);
}
}
return (NULL);
}
}
} else {
}
return (NULL);
}
return (cp);
}
static int
{
struct search_args *args;
char *devidstr;
char kernel_name[MAXPATHLEN];
/*
* Get the diskp value from calling have_disk. Can either be found
* by kernel name or devid.
*/
/*
* On Intel we would also get each fdisk partition as well
*/
char *devlink_path;
/*
* Add other controllers for multipath disks. This will have
* no effect if the controller relationship is already set up.
*/
}
}
if (dm_debug > 1) {
}
}
} else {
/*
* It is possible that we have already added this devpath.
* Do not add it again. new_devpath will return a 0 if
* found, and not add the path.
*/
}
}
}
return (DI_WALK_CONTINUE);
}
static int
{
struct search_args *args;
int result = DI_WALK_CONTINUE;
if (dm_debug > 1) {
/* This is all just debugging code */
char *devpath;
char dev_name[MAXPATHLEN];
di_devfs_path_free((void *) devpath);
"INFO: dev: %s, node: %s%d, minor: 0x%x, type: %s\n",
}
}
}
char *devidstr;
char kernel_name[MAXPATHLEN];
/* Check if we already got this disk and this is another slice */
args->dev_walk_status = 0;
/* This is a newly found disk, create the disk structure. */
}
/* add the controller relationship */
if (args->dev_walk_status == 0) {
}
}
}
}
/* Add the devpaths for the drive. */
if (args->dev_walk_status == 0) {
char *devpath;
char slice_path[MAXPATHLEN];
char *pattern;
/*
* We will come through here once for each of the raw slice
* device names.
*/
di_devfs_path_free((void *) devpath);
} else {
}
/* Walk the /dev tree to get the devlinks. */
}
if (args->dev_walk_status != 0) {
}
}
return (result);
}
static int
{
int i;
if (pnode == DI_NODE_NIL) {
return (0);
}
return (0);
}
return (ENOMEM);
}
/* check if the disk <-> ctrl assoc is already there */
for (i = 0; diskp->controllers[i]; i++) {
return (0);
}
}
/* this is a new controller for this disk */
/* add the disk to the controlller */
return (ENOMEM);
}
/* add the controlller to the disk */
return (ENOMEM);
}
/*
* Set up paths for mpxio controlled drives.
*/
/* note: mpxio di_path stuff is all consolidation private */
int cnt;
char str[MAXPATHLEN];
char *wwn;
/* get the node wwn */
if (cnt > 0) {
int i;
str[0] = 0;
for (i = 0; i < cnt; i++) {
}
}
== NULL) {
return (ENOMEM);
}
}
}
return (0);
}
static int
{
/* add the disk to the path */
return (0);
}
/* add the path to the disk */
return (0);
}
/* add the path state for this disk */
return (0);
}
/* add the path state for this disk */
char *wp;
return (0);
}
}
}
return (1);
}
static int
add_int2array(int p, int **parray)
{
int i;
int cnt;
int *pa;
int *new_array;
cnt = 0;
}
return (ENOMEM);
}
/* copy the existing array */
for (i = 0; i < cnt; i++) {
}
new_array[i] = p;
return (0);
}
static int
add_ptr2array(void *p, void ***parray)
{
int i;
int cnt;
void **pa;
void **new_array;
cnt = 0;
}
return (ENOMEM);
}
/* copy the existing array */
for (i = 0; i < cnt; i++) {
}
new_array[i] = p;
return (0);
}
/*
* This double checks that we aren't going to get into a bad situation.
* This function should never fail, but I just want to double check things.
*/
static int
{
if (dm_debug) {
}
"ERROR: remove controller with disk ptrs\n");
}
"ERROR: remove controller with path ptrs\n");
}
}
return (1);
}
/*
* If we have a controller in the list that is really a path then we need to
* take that controller out of the list since nodes that are paths are not
* considered to be controllers.
*/
static void
{
int i;
for (i = 0; pp[i]; i++) {
}
}
}
}
static disk_t *
{
char *type;
char *prod_id;
char *vendor_id;
if (dm_debug) {
}
return (NULL);
}
return (NULL);
}
return (NULL);
}
}
if (kernel_name != NULL) {
return (NULL);
}
}
return (NULL);
}
} else {
return (NULL);
}
}
}
return (NULL);
}
} else {
return (NULL);
}
}
}
/*
* DVD, CD-ROM, CD-RW, MO, etc. are all reported as CD-ROMS.
* We try to use uscsi later to determine the real type.
* The cd_rom flag tells us that the kernel categorized the drive
* as a CD-ROM. We leave the drv_type as UKNOWN for now.
* The combination of the cd_rom flag being set with the drv_type of
* unknown is what triggers the uscsi probe in drive.c.
*/
if (disk_is_cdrom(type)) {
} else {
/* not a "CD-ROM" or Floppy */
#ifdef i386
/*
* x86 does not have removable property. Check for common
* removable drives, zip & jaz, and mark those correctly.
*/
}
}
}
#endif
}
/*
* For removable jaz or zip drives there is no way
* to get the drive type unless media is inserted, so we
* look at the product-id for a hint.
*/
}
}
} else {
}
}
diskp->volm_path_set = 0;
return (diskp);
}
static char *
{
char *type;
char *name;
/* IDE disks use SCSI nexus as the type, so handle this special case */
return (DM_CTYPE_ATA);
}
return (DM_CTYPE_USB);
}
return (DM_CTYPE_SCSI);
}
return (DM_CTYPE_FIBRE);
}
return (DM_CTYPE_FIBRE);
}
return (DM_CTYPE_ATA);
}
return (DM_CTYPE_UNKNOWN);
}
static boolean_t
disk_is_cdrom(char *type)
{
int type_index;
return (B_TRUE);
}
}
return (B_FALSE);
}
static alias_t *
{
return (ap);
}
}
return (NULL);
}
static bus_t *
{
return (listp);
}
}
return (NULL);
}
static controller_t *
{
return (listp);
}
}
return (NULL);
}
static int
{
int fd;
struct search_args *args;
char *devlink_path;
/*
*/
/* Find the disk by the deviceid we read from the cluster disk. */
if (devlink_path == NULL) {
return (DI_WALK_CONTINUE);
}
if (dm_debug > 1) {
}
char *minor;
char *devidstr;
/*
* This really shouldn't happen, since we should have
* found all of the disks during our first pass through
* the dev tree, but just in case...
*/
if (dm_debug > 1) {
"INFO: cluster create disk\n");
}
}
/* add the controller relationship */
if (args->dev_walk_status == 0) {
}
}
!= 0) {
}
}
}
}
}
if (dm_debug > 1) {
}
}
/* NOTE: if ap->next != NULL have cluster disks w/ multiple paths */
char *basep;
char *namep;
int cnt = 0;
int size;
char alias[MAXPATHLEN];
/*
* alias info with the new alias name.
*/
/* get the new cluster alias name */
} else {
basep++;
}
cnt++;
}
*namep = 0;
}
}
}
}
return (DI_WALK_CONTINUE);
}
/*
* Check if we have the drive in our list, based upon the device id.
* We got the device id from the dev tree walk. This is encoded
* using devid_str_encode(3DEVID). In order to check the device ids we need
* to use the devid_compare(3DEVID) function, so we need to decode the
* string representation of the device id.
*/
static disk_t *
{
return (NULL);
}
break;
}
}
return (listp);
}
/*
* Get the base disk name with no path prefix and no slice (if there is one).
* The name parameter should be big enough to hold the name.
* This handles diskette names ok (/dev/rdiskette0) since there is no slice,
* and converts the raw diskette name.
* But, we don't know how to strip off the slice from third party drive
* names. That just means that their drive name will include a slice on
* it.
*/
static void
{
char *basep;
int cnt = 0;
} else {
basep++;
}
cnt++;
}
*name = 0;
} else {
/*
* a floppy, convert rdiskette name to diskette name,
* by skipping over the 'r' for raw diskette
*/
basep++;
}
/* not a ctds name, just copy it */
}
}
static char *
{
int cnt;
int i;
char str[MAXPATHLEN];
if (cnt < 1) {
return (NULL);
}
str[0] = 0;
for (i = 0; i < cnt; i++) {
}
}
static di_node_t
{
if (pnode == DI_NODE_NIL) {
return (NULL);
}
return (pnode);
}
}
static int
{
int *n;
return (*n);
}
return (0);
}
static char *
{
char *str;
return (str);
}
return (NULL);
}
/*
* Get one of the positive int or boolean properties.
*/
static int
{
int num;
int *ip;
>= 0) {
if (num == 0) {
/* boolean */
return (1);
} else if (num == 1) {
/* single int */
return (*ip);
}
}
return (-1);
}
static char *
{
char *str;
return (str);
}
return (NULL);
}
/*
* Check if we have the drive in our list, based upon the device id, if the
* drive has a device id, or the kernel name, if it doesn't have a device id.
*/
static int
{
return (1);
}
} else {
/* no devid, try matching the kernel names on the drives */
return (1);
}
}
}
return (0);
}
static char *
{
char *type;
int i;
}
for (i = 0; bustypes[i]; i++) {
return (type);
}
}
DDI_NT_USB_ATTACHMENT_POINT) == 0) {
return ("usb");
}
return (NULL);
}
static int
{
return (1);
}
return (0);
}
/*
* If the input name is in c[t]ds format then return 1, otherwise return 0.
*/
static int
{
char *p;
p = name;
if (*p++ != 'c') {
return (0);
}
/* skip controller digits */
while (isdigit(*p)) {
p++;
}
/* handle optional target */
if (*p == 't') {
p++;
/* skip over target */
p++;
}
}
if (*p++ != 'd') {
return (0);
}
while (isdigit(*p)) {
p++;
}
if (*p++ != 's') {
return (0);
}
/* check the slice number */
while (isdigit(*p)) {
p++;
}
if (*p != 0) {
return (0);
}
return (1);
}
static int
{
char *type;
int type_index;
type_index = 0;
return (1);
}
type_index++;
}
return (0);
}
static int
{
char *type;
char *name;
int type_index;
type_index = 0;
return (1);
}
type_index++;
}
return (1);
}
return (0);
}
static int
struct search_args *args)
{
char alias[MAXPATHLEN];
return (ENOMEM);
}
return (ENOMEM);
}
if (kernel_name != NULL) {
return (ENOMEM);
}
} else {
}
if (pnode != DI_NODE_NIL) {
char prop_name[MAXPROPLEN];
}
return (ENOMEM);
}
return (0);
}
/*
* Append the new devpath to the end of the devpath list. This is important
* since we may want to use the order of the devpaths to match up the vtoc
* entries.
*/
static int
{
/*
* First, search the alias list to be sure that this devpath is
* not already there.
*/
return (0);
}
}
/*
* Otherwise, not found so add this new devpath to the list.
*/
return (ENOMEM);
}
return (ENOMEM);
}
} else {
/* append the devpath to the end of the list */
}
}
return (0);
}
static path_t *
char *wwn)
{
char *devpath;
/* Special handling for fp attachment node. */
if (pnode != DI_NODE_NIL) {
}
}
/* check if the path is already there */
int i;
break;
}
}
}
/* the path exists, add this disk to it */
di_devfs_path_free((void *) devpath);
return (NULL);
}
return (pp);
}
/* create a new path */
di_devfs_path_free((void *) devpath);
return (NULL);
}
di_devfs_path_free((void *) devpath);
return (NULL);
}
/* add the disk to the path */
return (NULL);
}
/* add the path to the controller */
return (NULL);
}
/* add the controller to the path */
} else {
}
return (pp);
}
/*
* We pass in the current controller pointer (currp) so we can double check
* that we aren't corrupting the list by removing the element we are on. This
* should never happen, but it doesn't hurt to double check.
*/
static void
struct search_args *args)
{
int i;
for (i = 0; bp->controllers[i]; i++) {
int j;
/* remove pointer to invalid controller (it is a path) */
for (j = i; bp->controllers[j]; j++) {
}
}
}
}
return;
}
}
return;
}
}
return;
}
}
}
/*
* This is the standard strstr code modified for case independence.
*/
static char *
{
/* If the length of the second string is 0, return the first arg. */
if (s2len == 0) {
return (s1);
}
return (s1);
}
s1++;
}
return (NULL);
}