138465Smsmith/*-
238465Smsmith * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
338465Smsmith * All rights reserved.
438465Smsmith *
538465Smsmith * Redistribution and use in source and binary forms, with or without
638465Smsmith * modification, are permitted provided that the following conditions
738465Smsmith * are met:
838465Smsmith * 1. Redistributions of source code must retain the above copyright
938465Smsmith *    notice, this list of conditions and the following disclaimer.
1038465Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1138465Smsmith *    notice, this list of conditions and the following disclaimer in the
1238465Smsmith *    documentation and/or other materials provided with the distribution.
1338465Smsmith *
1438465Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538465Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638465Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738465Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838465Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938465Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038465Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138465Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238465Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338465Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438465Smsmith * SUCH DAMAGE.
2538465Smsmith */
2638465Smsmith
27124140Sobrien#include <sys/cdefs.h>
28124140Sobrien__FBSDID("$FreeBSD$");
29124140Sobrien
3038465Smsmith#include <stand.h>
31236076Smarius
32236076Smarius#include "bootstrap.h"
3367227Sobrien#include "libofw.h"
34237766Savg#include "../zfs/libzfs.h"
3538465Smsmith
36106738Sjakestatic int ofw_parsedev(struct ofw_devdesc **, const char *, const char **);
3738465Smsmith
3838465Smsmith/*
3938465Smsmith * Point (dev) at an allocated device specifier for the device matching the
4038465Smsmith * path in (devspec). If it contains an explicit device specification,
4138465Smsmith * use that.  If not, use the default device.
4238465Smsmith */
4338465Smsmithint
4467227Sobrienofw_getdev(void **vdev, const char *devspec, const char **path)
4538465Smsmith{
4667227Sobrien    struct ofw_devdesc **dev = (struct ofw_devdesc **)vdev;
4738465Smsmith    int				rv;
48106738Sjake
4938465Smsmith    /*
5038465Smsmith     * If it looks like this is just a path and no
5138465Smsmith     * device, go with the current device.
5238465Smsmith     */
5338465Smsmith    if ((devspec == NULL) ||
54123703Sgrehan	((strchr(devspec, '@') == NULL) &&
55123703Sgrehan	(strchr(devspec, ':') == NULL))) {
5638465Smsmith
5767227Sobrien	if (((rv = ofw_parsedev(dev, getenv("currdev"), NULL)) == 0) &&
5838465Smsmith	    (path != NULL))
5938465Smsmith		*path = devspec;
6038465Smsmith	return(rv);
6138465Smsmith    }
6238465Smsmith
6338465Smsmith    /*
6438465Smsmith     * Try to parse the device name off the beginning of the devspec
6538465Smsmith     */
6667227Sobrien    return(ofw_parsedev(dev, devspec, path));
6738465Smsmith}
6838465Smsmith
6938465Smsmith/*
7038465Smsmith * Point (dev) at an allocated device specifier matching the string version
7138465Smsmith * at the beginning of (devspec).  Return a pointer to the remaining
7238465Smsmith * text in (path).
7338465Smsmith */
7438465Smsmithstatic int
7567227Sobrienofw_parsedev(struct ofw_devdesc **dev, const char *devspec, const char **path)
7638465Smsmith{
77106738Sjake    struct ofw_devdesc	*idev;
7838465Smsmith    struct devsw	*dv;
79106738Sjake    phandle_t		handle;
80106738Sjake    const char		*p;
81106738Sjake    const char		*s;
82236076Smarius    char		*ep;
83106738Sjake    char		name[256];
84106738Sjake    char		type[64];
85237766Savg    int			err;
86106738Sjake    int			len;
87106738Sjake    int			i;
8838465Smsmith
89106738Sjake    for (p = s = devspec; *s != '\0'; p = s) {
90106738Sjake	if ((s = strchr(p + 1, '/')) == NULL)
91106738Sjake	    s = strchr(p, '\0');
92106738Sjake	len = s - devspec;
93106738Sjake	bcopy(devspec, name, len);
94106738Sjake	name[len] = '\0';
95236076Smarius	if ((handle = OF_finddevice(name)) == -1) {
96236076Smarius	    bcopy(name, type, len);
97236076Smarius	    type[len] = '\0';
98236076Smarius	} else if (OF_getprop(handle, "device_type", type, sizeof(type)) == -1)
99106738Sjake	    continue;
100106738Sjake	for (i = 0; (dv = devsw[i]) != NULL; i++) {
101107483Sjake	    if (strncmp(dv->dv_name, type, strlen(dv->dv_name)) == 0)
102106738Sjake		goto found;
10338465Smsmith	}
10438465Smsmith    }
105106738Sjake    return(ENOENT);
10638465Smsmith
107106738Sjakefound:
108151649Smarius    if (path != NULL && *s != '\0')
109106738Sjake	*path = s;
11067227Sobrien    idev = malloc(sizeof(struct ofw_devdesc));
111151649Smarius    if (idev == NULL) {
112151649Smarius	printf("ofw_parsedev: malloc failed\n");
113151649Smarius	return ENOMEM;
114151649Smarius    }
115106738Sjake    strcpy(idev->d_path, name);
11638465Smsmith    idev->d_dev = dv;
11738465Smsmith    idev->d_type = dv->dv_type;
118236076Smarius    if (idev->d_type == DEVT_ZFS) {
119237766Savg	p = devspec + strlen(dv->dv_name);
120237766Savg	err = zfs_parsedev((struct zfs_devdesc *)idev, p, path);
121237766Savg	if (err != 0) {
122237766Savg	    free(idev);
123237766Savg	    return (err);
124236076Smarius	}
125236076Smarius    }
126236076Smarius
12738475Sdfr    if (dev == NULL) {
12838475Sdfr	free(idev);
12938475Sdfr    } else {
13038465Smsmith	*dev = idev;
13138475Sdfr    }
13238465Smsmith    return(0);
13338465Smsmith}
13468548Sbenno
13584968Srobertint
136123703Sgrehanofw_setcurrdev(struct env_var *ev, int flags, const void *value)
13768548Sbenno{
138106738Sjake    struct ofw_devdesc	*ncurr;
139106738Sjake    int			rv;
14068548Sbenno
141106738Sjake    if ((rv = ofw_parsedev(&ncurr, value, NULL)) != 0)
142106738Sjake	return rv;
14368548Sbenno
144106738Sjake    free(ncurr);
145106738Sjake    env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
146106738Sjake    return 0;
14768548Sbenno}
148