/*
* 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
* 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
*/
/*
*/
#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 <strings.h>
#include "libdiskmgt.h"
#include "disks_private.h"
/* specify which disk links to use in the /dev directory */
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_controller_reference(char *name,
controller_t **ctra);
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;
if (node == DI_NODE_NIL) {
return (NULL);
}
}
di_devfs_path_free((void *) devpath);
if (add_ptr2array(cp,
(void ***)&bp->controllers) != 0) {
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
{
char *devpath;
return (DI_WALK_CONTINUE);
}
if (dm_debug > 1) {
/* This is all just debugging code */
char *devpath;
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;
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
{
char *devidstr;
/*
* 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) {
"INFO: devpath %s\n", devlink_path);
}
args) != 0) {
}
} 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
{
if (dm_debug > 1) {
/* This is all just debugging code */
char *devpath;
di_devfs_path_free((void *) devpath);
"INFO: dev: %s, node: %s%d, minor: 0x%x, type: %s\n",
}
}
}
char *devidstr;
/*
* 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) {
if (add_disk2controller(diskp,
args) != 0) {
}
}
}
}
char *str;
return (DI_WALK_CONTINUE);
str);
}
} 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.
*/
}
}
}
/* Add the devpaths for the drive. */
if (args->dev_walk_status == 0) {
char *devpath;
char *pattern;
/*
* We will come through here once for each of
* the raw slice device names.
*/
(void) snprintf(slice_path,
sizeof (slice_path), "%s:%s",
di_devfs_path_free((void *) devpath);
DDI_NT_FD)) {
} 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 */
while (
int cnt;
char *wwn;
/* get the node wwn */
if (cnt > 0) {
int i;
str[0] = 0;
for (i = 0; i < cnt; i++) {
/*
* A byte is only 2 hex chars + 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
{
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
{
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);
}
/*
* 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
{
}
}
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 */
/*
* x86 does not have removable property.
* Check for common removable drives, zip & jaz,
* and mark those correctly.
*/
if (str_case_index(vendor_id,
"iomega") != NULL) {
if (str_case_index(prod_id,
"jaz") != NULL) {
} else if (str_case_index(prod_id,
"zip") != NULL) {
}
}
}
#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 if (str_case_index(prod_id,
"zip") != NULL) {
}
}
} else {
}
}
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_SATA);
}
return (DM_CTYPE_UNKNOWN);
}
static boolean_t
{
}
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;
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;
if ((devidstr =
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) &&
args) != 0))
devlink_path, args) != 0)
}
}
}
}
if (dm_debug > 1)
" disk\n");
}
/*
* NOTE: if ap->next != NULL have cluster
* disks w/ multiple paths.
*/
char *basep;
char *namep;
int cnt = 0;
/*
* update the alias_did 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 {
sizeof (FLOPPY_NAME) - 1) == 0) {
/*
* 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;
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;
/*
* If we find a string, we return it here. If we get more than one
* string, then we're returning a pointer to the whole buffer, even
* though the caller will only 'see' the first string. This is OK
* though, because we only care about the first one.
*/
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 */
listp->kernel_name)) {
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
{
strlen(DDI_NT_BLOCK)) == 0);
}
static int
{
return (1);
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)
{
return (ENOMEM);
return (ENOMEM);
}
return (ENOMEM);
}
if (kernel_name != NULL) {
return (ENOMEM);
}
} else {
}
if (pnode != DI_NODE_NIL) {
}
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);
}
static void
{
int cnt;
return;
int tcnt;
/*
* remove pointer to invalid controller.
* (it is a path)
*/
}
}
}
/*
* 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)
{
/*
* loop through the disks and remove the reference to the
* controller for this disk structure. The disk itself
* is still a valid device, the controller being removed
* is a 'path' so any disk that has a reference to it
* as a controller needs to have this reference removed.
*/
/*
* loop through the controllers and remove the controller itself.
* The controller being removed is a 'path'.
*/
/* CSTYLED */) {
if (dm_debug)
"ERROR: Removing current "
"controller %s from list\n",
continue;
}
else
if (dm_debug)
"INFO: Removed controller %s from list\n",
continue;
}
}
}
/*
* 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);
}