biosdev.c revision 801d74ddb3d063919e6cf7c6eb3ddc2591c3921d
/*
* 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
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <libdevinfo.h>
#include <fcntl.h>
#include <sys/biosdisk.h>
/*
* structure used for searching device tree for a node matching
*/
typedef struct pcibdf {
int busnum;
int devnum;
int funcnum;
} pcibdf_t;
/*
* structure used for searching device tree for a node matching
* USB serial number.
*/
typedef struct {
} usbser_t;
/*
* structure for holding the mapping info
*/
typedef struct {
int disklist_index; /* index to disk_list of the mapped path */
int matchcount; /* number of matches per this device number */
} mapinfo_t;
#define DEVFS_PREFIX "/devices"
#define BIOSPROPNAME_TMPL "biosdev-0x%x"
#define BIOSPROPNAME_TMPL_LEN 13
#define BIOSDEV_NUM 8
#define STARTING_DRVNUM 0x80
/*
* array to hold mappings. Element at index X corresponds to BIOS device
* number 0x80 + X
*/
/*
* Cache copy of kernel device tree snapshot root handle, includes devices
* that are detached
*/
/*
* kernel device tree snapshot with currently attached devices. Detached
* devices are not included.
*/
/*
* handle to retrieve prom properties
*/
static int disk_list_len = 0; /* length of disk_list */
static int disk_list_valid = 0; /* number of valid entries in disk_list */
static int debug = 0; /* used for enabling debug output */
/* Local function prototypes */
static void build_disk_list();
static int search_disklist_match_path(char *path);
static void free_disks();
static void cleanup_and_exit(int);
int fn);
char *matchbusaddr);
static void
{
char **newlist;
int newlen;
char *devfspath;
if (disk_list_valid >= disk_list_len) {
/* valid should never really be larger than len */
/* if they are equal we need to init or realloc */
(void) printf("realloc failed to resize disk table\n");
cleanup_and_exit(1);
}
}
if (debug)
}
/* ARGSUSED */
static int
{
char *minortype;
/* exclude CD's */
/* only take p0 raw device */
}
return (DI_WALK_CONTINUE);
}
static void
{
int ret;
if (ret != 0) {
errno);
cleanup_and_exit(1);
}
}
static void
{
int i;
if (disk_list) {
for (i = 0; i < disk_list_valid; i++)
}
}
static int
{
int len;
char *devtype;
"device_type", (char **)&devtype);
if ((len <= 0) ||
return (DI_WALK_CONTINUE);
(int **)®buf);
if (len <= 0) {
/* Try PROM property */
(int **)®buf);
}
if (len > 0) {
/* found it */
return (DI_WALK_TERMINATE);
}
}
return (DI_WALK_CONTINUE);
}
static di_node_t
{
}
static int
{
int len;
char *serialp;
sizeof (uint64_t)) == 0)) {
return (DI_WALK_TERMINATE);
}
return (DI_WALK_CONTINUE);
}
static di_node_t
{
}
/*
* returns the index to the disklist to the disk with matching path
*/
static int
search_disklist_match_path(char *path)
{
int i;
for (i = 0; i < disk_list_valid; i++)
return (i);
}
return (-1);
}
/*
* Find first child of 'node' whose unit address is 'matchbusaddr'
*/
static di_node_t
{
char *busaddr;
if (matchbusaddr == NULL)
return (DI_NODE_NIL);
continue;
break;
}
return (cnode);
}
/*
* Construct a physical device pathname from EDD and verify the
* path exists. Return the index of in disk_list for the mapped
* path on success, -1 on failure.
*/
static int
{
int index;
char busaddrbuf[MAXNAMELEN];
if (debug)
(void) printf("edd not valid\n");
return (-1);
}
/* EDD extensions for devicepath not present */
if (debug)
(void) printf("magic not valid %x pathinfolen %d\n",
return (-1);
}
/* we handle only PCI scsi, ata or sata for now */
if (debug)
return (-1);
}
if (debug)
(void) printf("match_edd bdf %d %d %d\n",
/* look into devinfo tree and find a node with matching pci b/d/f */
if (node == DI_NODE_NIL) {
if (debug)
(void) printf(" could not find a node in tree "
"matching bdf\n");
return (-1);
}
if (debug) {
int i;
(void) printf("interface type ");
for (i = 0; i < 8; i++)
(void) printf(" pci channel %x target %x\n",
}
/*
* Legacy using pci-ide
* the child should be ide@<x>, where x is
* the channel number
*/
busaddrbuf)) != DI_NODE_NIL) {
if (cnode == DI_NODE_NIL)
if (debug)
(void) printf("Interface %s "
"using pci-ide no "
"grandchild at %s\n",
} else {
if (debug)
(void) printf("Interface %s using "
"pci-ide, with no child at %s\n",
}
} else {
/*
* The current EDD (EDD-2) spec does not
* address port number. This is work in
* progress.
* Interprete the first field of device path
* as port number. Needs to be revisited
* with port multiplier support.
*/
} else {
if (debug)
(void) printf("Interface %s, not using"
}
}
} else {
if (debug)
(void) printf("sorry not supported interface %s\n",
bd->interface_type);
}
if (cnode != DI_NODE_NIL) {
if (index >= 0)
return (index);
}
return (-1);
}
/*
* For each disk in list of disks, compare the first block with the
* one from bdd. On the first match, return the index of path in
* disk_list. If none matched return -1.
*/
static int
{
char diskpath[MAXPATHLEN];
int fd;
char buf[512];
int i;
if (!bd->first_block_valid)
return (-1);
for (i = 0; i < disk_list_valid; i++) {
DEVFS_PREFIX, disk_list[i]);
if (fd < 0) {
continue;
}
if (num_read != 512) {
diskpath);
continue;
}
/* found it */
return (i);
}
}
return (-1);
}
static void
cleanup_and_exit(int exitcode)
{
free_disks();
if (root_node != DI_NODE_NIL)
if (root_allnode != DI_NODE_NIL)
if (prom_hdl != DI_PROM_HANDLE_NIL)
}
int
{
int i, c, j;
int matchedindex = -1;
int totalmatches = 0;
switch (c) {
case 'd':
debug = 1;
break;
default:
(void) printf("unknown option %c\n", c);
exit(1);
}
}
cleanup_and_exit(1);
}
cleanup_and_exit(1);
}
cleanup_and_exit(1);
}
/* get a list of all disks in the system */
/* Get property values that were created at boot up time */
for (i = 0; i < BIOSDEV_NUM; i++) {
BIOSPROPNAME_TMPL, i + STARTING_DRVNUM);
biosdataarray[i] = NULL;
}
for (i = 0; i < BIOSDEV_NUM; i++) {
continue;
if (debug)
(void) printf("matching edd 0x%x\n",
i + STARTING_DRVNUM);
if (matchedindex != -1) {
if (debug) {
(void) printf("matched by edd\n");
}
mapinfo[i].matchcount++;
for (j = 0; j < i; j++) {
if (mapinfo[j].matchcount > 0 &&
mapinfo[j].matchcount++;
mapinfo[i].matchcount++;
}
}
} else
if (debug)
(void) printf("No matches by edd\n");
}
/*
* Go through the list and ignore any found matches that are dups.
* This is to workaround issues with BIOSes that do not implement
*/
for (i = 0; i < BIOSDEV_NUM; i++) {
if (debug)
(void) printf("Ignoring dup match_edd\n(count "
i + STARTING_DRVNUM,
mapinfo[i].matchcount = 0;
mapinfo[i].disklist_index = 0;
}
}
/*
* For each bios dev number that we do not have exactly one match
* already, try to match based on first block
*/
for (i = 0; i < BIOSDEV_NUM; i++) {
continue;
continue;
if (debug)
(void) printf("matching first block 0x%x\n",
i + STARTING_DRVNUM);
if (matchedindex != -1) {
if (debug) {
(void) printf("matched by first block\n");
}
mapinfo[i].matchcount++;
for (j = 0; j < i; j++) {
if (mapinfo[j].matchcount > 0 &&
mapinfo[j].matchcount++;
mapinfo[i].matchcount++;
}
}
} else
if (debug) {
(void) printf(" No matches by first block\n");
i + STARTING_DRVNUM);
}
}
for (i = 0; i < BIOSDEV_NUM; i++) {
totalmatches++;
(void) printf("0x%x %s matchcount %d\n",
i + STARTING_DRVNUM,
mapinfo[i].matchcount);
}
}
if (totalmatches == 0) {
cleanup_and_exit(1);
}
cleanup_and_exit(0);
/* NOTREACHED */
return (0);
}