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