1219089Spjd/*-
2219089Spjd * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3219089Spjd * All rights reserved.
4219089Spjd *
5219089Spjd * Redistribution and use in source and binary forms, with or without
6219089Spjd * modification, are permitted provided that the following conditions
7219089Spjd * are met:
8219089Spjd * 1. Redistributions of source code must retain the above copyright
9219089Spjd *    notice, this list of conditions and the following disclaimer.
10219089Spjd * 2. Redistributions in binary form must reproduce the above copyright
11219089Spjd *    notice, this list of conditions and the following disclaimer in the
12219089Spjd *    documentation and/or other materials provided with the distribution.
13219089Spjd *
14219089Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15219089Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16219089Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17219089Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18219089Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19219089Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20219089Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21219089Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22219089Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23219089Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24219089Spjd * SUCH DAMAGE.
25219089Spjd */
26219089Spjd
27219089Spjd#include <sys/cdefs.h>
28219089Spjd__FBSDID("$FreeBSD$");
29219089Spjd
30219089Spjd#include <sys/param.h>
31219089Spjd#include <sys/jail.h>
32219089Spjd#include <sys/kernel.h>
33219089Spjd#include <sys/libkern.h>
34219089Spjd#include <sys/limits.h>
35219089Spjd#include <sys/misc.h>
36219089Spjd#include <sys/sunddi.h>
37219089Spjd#include <sys/sysctl.h>
38219089Spjd
39219089Spjdint
40219089Spjdddi_strtol(const char *str, char **nptr, int base, long *result)
41219089Spjd{
42219089Spjd
43219089Spjd	*result = strtol(str, nptr, base);
44219089Spjd	if (*result == 0)
45219089Spjd		return (EINVAL);
46219089Spjd	else if (*result == LONG_MIN || *result == LONG_MAX)
47219089Spjd		return (ERANGE);
48219089Spjd	return (0);
49219089Spjd}
50219089Spjd
51219089Spjdint
52219089Spjdddi_strtoul(const char *str, char **nptr, int base, unsigned long *result)
53219089Spjd{
54219089Spjd
55219089Spjd	if (str == hw_serial) {
56219089Spjd		*result = prison0.pr_hostid;
57219089Spjd		return (0);
58219089Spjd	}
59219089Spjd
60219089Spjd	*result = strtoul(str, nptr, base);
61219089Spjd	if (*result == 0)
62219089Spjd		return (EINVAL);
63219089Spjd	else if (*result == ULONG_MAX)
64219089Spjd		return (ERANGE);
65219089Spjd	return (0);
66219089Spjd}
67219089Spjd
68219089Spjdint
69219089Spjdddi_strtoull(const char *str, char **nptr, int base, unsigned long long *result)
70219089Spjd{
71219089Spjd
72219089Spjd	*result = (unsigned long long)strtouq(str, nptr, base);
73219089Spjd	if (*result == 0)
74219089Spjd		return (EINVAL);
75219089Spjd	else if (*result == ULLONG_MAX)
76219089Spjd		return (ERANGE);
77219089Spjd	return (0);
78219089Spjd}
79219089Spjd
80219089Spjdstruct ddi_soft_state_item {
81219089Spjd	int	 ssi_item;
82219089Spjd	void	*ssi_data;
83219089Spjd	LIST_ENTRY(ddi_soft_state_item) ssi_next;
84219089Spjd};
85219089Spjd
86219089Spjdstruct ddi_soft_state {
87219089Spjd	size_t		ss_size;
88219089Spjd	kmutex_t	ss_lock;
89219089Spjd	LIST_HEAD(, ddi_soft_state_item) ss_list;
90219089Spjd};
91219089Spjd
92219089Spjdstatic void *
93219089Spjdddi_get_soft_state_locked(struct ddi_soft_state *ss, int item)
94219089Spjd{
95219089Spjd	struct ddi_soft_state_item *itemp;
96219089Spjd
97219092Spjd	ASSERT(MUTEX_HELD(&ss->ss_lock));
98219089Spjd
99219089Spjd	LIST_FOREACH(itemp, &ss->ss_list, ssi_next) {
100219089Spjd		if (itemp->ssi_item == item)
101219089Spjd			return (itemp->ssi_data);
102219089Spjd	}
103219089Spjd	return (NULL);
104219089Spjd}
105219089Spjd
106219089Spjdvoid *
107219089Spjdddi_get_soft_state(void *state, int item)
108219089Spjd{
109219089Spjd	struct ddi_soft_state *ss = state;
110219089Spjd	void *data;
111219089Spjd
112219089Spjd	mutex_enter(&ss->ss_lock);
113219089Spjd	data = ddi_get_soft_state_locked(ss, item);
114219089Spjd	mutex_exit(&ss->ss_lock);
115219089Spjd	return (data);
116219089Spjd}
117219089Spjd
118219089Spjdint
119219089Spjdddi_soft_state_zalloc(void *state, int item)
120219089Spjd{
121219089Spjd	struct ddi_soft_state *ss = state;
122219089Spjd	struct ddi_soft_state_item *itemp;
123219089Spjd
124219089Spjd	itemp = kmem_alloc(sizeof(*itemp), KM_SLEEP);
125219089Spjd	itemp->ssi_item = item;
126219089Spjd	itemp->ssi_data = kmem_zalloc(ss->ss_size, KM_SLEEP);
127219089Spjd
128219089Spjd	mutex_enter(&ss->ss_lock);
129219089Spjd	if (ddi_get_soft_state_locked(ss, item) != NULL) {
130219089Spjd		mutex_exit(&ss->ss_lock);
131219089Spjd		kmem_free(itemp->ssi_data, ss->ss_size);
132219089Spjd		kmem_free(itemp, sizeof(*itemp));
133219089Spjd		return (DDI_FAILURE);
134219089Spjd	}
135219089Spjd	LIST_INSERT_HEAD(&ss->ss_list, itemp, ssi_next);
136219089Spjd	mutex_exit(&ss->ss_lock);
137219089Spjd	return (DDI_SUCCESS);
138219089Spjd}
139219089Spjd
140219089Spjdstatic void
141219089Spjdddi_soft_state_free_locked(struct ddi_soft_state *ss, int item)
142219089Spjd{
143219089Spjd	struct ddi_soft_state_item *itemp;
144219089Spjd
145219092Spjd	ASSERT(MUTEX_HELD(&ss->ss_lock));
146219089Spjd
147219089Spjd	LIST_FOREACH(itemp, &ss->ss_list, ssi_next) {
148219089Spjd		if (itemp->ssi_item == item)
149219089Spjd			break;
150219089Spjd	}
151219089Spjd	if (itemp != NULL) {
152219089Spjd		LIST_REMOVE(itemp, ssi_next);
153219089Spjd		kmem_free(itemp->ssi_data, ss->ss_size);
154219089Spjd		kmem_free(itemp, sizeof(*itemp));
155219089Spjd	}
156219089Spjd}
157219089Spjd
158219089Spjdvoid
159219089Spjdddi_soft_state_free(void *state, int item)
160219089Spjd{
161219089Spjd	struct ddi_soft_state *ss = state;
162219089Spjd
163219089Spjd	mutex_enter(&ss->ss_lock);
164219089Spjd	ddi_soft_state_free_locked(ss, item);
165219089Spjd	mutex_exit(&ss->ss_lock);
166219089Spjd}
167219089Spjd
168219089Spjdint
169219089Spjdddi_soft_state_init(void **statep, size_t size, size_t nitems __unused)
170219089Spjd{
171219089Spjd	struct ddi_soft_state *ss;
172219089Spjd
173219089Spjd	ss = kmem_alloc(sizeof(*ss), KM_SLEEP);
174219089Spjd	mutex_init(&ss->ss_lock, NULL, MUTEX_DEFAULT, NULL);
175219089Spjd	ss->ss_size = size;
176219089Spjd	LIST_INIT(&ss->ss_list);
177219089Spjd	*statep = ss;
178219089Spjd	return (0);
179219089Spjd}
180219089Spjd
181219089Spjdvoid
182219089Spjdddi_soft_state_fini(void **statep)
183219089Spjd{
184219089Spjd	struct ddi_soft_state *ss = *statep;
185219089Spjd	struct ddi_soft_state_item *itemp;
186219089Spjd	int item;
187219089Spjd
188219089Spjd	mutex_enter(&ss->ss_lock);
189219089Spjd	while ((itemp = LIST_FIRST(&ss->ss_list)) != NULL) {
190219089Spjd		item = itemp->ssi_item;
191219089Spjd		ddi_soft_state_free_locked(ss, item);
192219089Spjd	}
193219089Spjd	mutex_exit(&ss->ss_lock);
194219089Spjd	mutex_destroy(&ss->ss_lock);
195219089Spjd	kmem_free(ss, sizeof(*ss));
196219089Spjd
197219089Spjd	*statep = NULL;
198219089Spjd}
199