1 /* $NetBSD: dmover_backend.c,v 1.8 2008/01/05 02:47:03 matt Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * dmover_backend.c: Backend management functions for dmover-api. 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: dmover_backend.c,v 1.8 2008/01/05 02:47:03 matt Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/mutex.h> 47 #include <sys/simplelock.h> 48 #include <sys/systm.h> 49 50 #include <dev/dmover/dmovervar.h> 51 52 TAILQ_HEAD(, dmover_backend) dmover_backend_list; 53 kmutex_t dmover_backend_list_lock; 54 static int initialized; 55 static struct simplelock initialized_slock = SIMPLELOCK_INITIALIZER; 56 57 static void 58 initialize(void) 59 { 60 61 simple_lock(&initialized_slock); 62 if (__predict_true(initialized == 0)) { 63 TAILQ_INIT(&dmover_backend_list); 64 mutex_init(&dmover_backend_list_lock, MUTEX_DEFAULT, IPL_VM); 65 66 /* Initialize the other bits of dmover. */ 67 dmover_session_initialize(); 68 dmover_request_initialize(); 69 dmover_process_initialize(); 70 71 initialized = 1; 72 } 73 simple_unlock(&initialized_slock); 74 } 75 76 /* 77 * dmover_backend_register: [back-end interface function] 78 * 79 * Register a back-end with dmover-api. 80 */ 81 void 82 dmover_backend_register(struct dmover_backend *dmb) 83 { 84 85 if (__predict_false(initialized == 0)) 86 initialize(); 87 88 LIST_INIT(&dmb->dmb_sessions); 89 dmb->dmb_nsessions = 0; 90 91 TAILQ_INIT(&dmb->dmb_pendreqs); 92 dmb->dmb_npendreqs = 0; 93 94 mutex_enter(&dmover_backend_list_lock); 95 TAILQ_INSERT_TAIL(&dmover_backend_list, dmb, dmb_list); 96 mutex_exit(&dmover_backend_list_lock); 97 } 98 99 /* 100 * dmover_backend_unregister: [back-end interface function] 101 * 102 * Un-register a back-end from dmover-api. 103 */ 104 void 105 dmover_backend_unregister(struct dmover_backend *dmb) 106 { 107 108 #ifdef DIAGNOSTIC 109 if (__predict_false(initialized == 0)) { 110 int croak; 111 112 simple_lock(&initialized_slock); 113 croak = (initialized == 0); 114 simple_unlock(&initialized_slock); 115 116 if (croak) 117 panic("dmover_backend_unregister: not initialized"); 118 } 119 #endif 120 121 /* XXX */ 122 if (dmb->dmb_nsessions) 123 panic("dmover_backend_unregister"); 124 125 mutex_enter(&dmover_backend_list_lock); 126 TAILQ_REMOVE(&dmover_backend_list, dmb, dmb_list); 127 mutex_exit(&dmover_backend_list_lock); 128 } 129 130 /* 131 * dmover_backend_alloc: 132 * 133 * Allocate and return a back-end on behalf of a session. 134 */ 135 int 136 dmover_backend_alloc(struct dmover_session *dses, const char *type) 137 { 138 struct dmover_backend *dmb, *best_dmb = NULL; 139 const struct dmover_algdesc *algdesc, *best_algdesc = NULL; 140 141 if (__predict_false(initialized == 0)) { 142 int fail; 143 144 simple_lock(&initialized_slock); 145 fail = (initialized == 0); 146 simple_unlock(&initialized_slock); 147 148 if (fail) 149 return (ESRCH); 150 } 151 152 mutex_enter(&dmover_backend_list_lock); 153 154 /* First, find a back-end that can handle the session parts. */ 155 for (dmb = TAILQ_FIRST(&dmover_backend_list); dmb != NULL; 156 dmb = TAILQ_NEXT(dmb, dmb_list)) { 157 /* 158 * First, check to see if the back-end supports the 159 * function we wish to perform. 160 */ 161 algdesc = dmover_algdesc_lookup(dmb->dmb_algdescs, 162 dmb->dmb_nalgdescs, type); 163 if (algdesc == NULL) 164 continue; 165 166 if (best_dmb == NULL) { 167 best_dmb = dmb; 168 best_algdesc = algdesc; 169 continue; 170 } 171 172 /* 173 * XXX All the stuff from here on should be shot in 174 * XXX the head. Instead, we should build a list 175 * XXX of candidates, and select the best back-end 176 * XXX when a request is scheduled for processing. 177 */ 178 179 if (dmb->dmb_speed >= best_dmb->dmb_speed) { 180 /* 181 * If the current best match is slower than 182 * this back-end, then this one is the new 183 * best match. 184 */ 185 if (dmb->dmb_speed > best_dmb->dmb_speed) { 186 best_dmb = dmb; 187 best_algdesc = algdesc; 188 continue; 189 } 190 191 /* 192 * If this back-end has fewer sessions allocated 193 * to it than the current best match, then this 194 * one is now the best match. 195 */ 196 if (best_dmb->dmb_nsessions > dmb->dmb_nsessions) { 197 best_dmb = dmb; 198 best_algdesc = algdesc; 199 continue; 200 } 201 } 202 } 203 if (best_dmb == NULL) { 204 mutex_exit(&dmover_backend_list_lock); 205 return (ESRCH); 206 } 207 208 KASSERT(best_algdesc != NULL); 209 210 /* Plug the back-end into the static (XXX) assignment. */ 211 dses->__dses_assignment.das_backend = best_dmb; 212 dses->__dses_assignment.das_algdesc = best_algdesc; 213 214 dses->dses_ninputs = best_algdesc->dad_ninputs; 215 216 LIST_INSERT_HEAD(&best_dmb->dmb_sessions, dses, __dses_list); 217 best_dmb->dmb_nsessions++; 218 219 mutex_exit(&dmover_backend_list_lock); 220 221 return (0); 222 } 223 224 /* 225 * dmover_backend_release: 226 * 227 * Release the back-end from the specified session. 228 */ 229 void 230 dmover_backend_release(struct dmover_session *dses) 231 { 232 struct dmover_backend *dmb; 233 234 mutex_enter(&dmover_backend_list_lock); 235 236 /* XXX Clear out the static assignment. */ 237 dmb = dses->__dses_assignment.das_backend; 238 dses->__dses_assignment.das_backend = NULL; 239 dses->__dses_assignment.das_algdesc = NULL; 240 241 LIST_REMOVE(dses, __dses_list); 242 dmb->dmb_nsessions--; 243 244 mutex_exit(&dmover_backend_list_lock); 245 } 246