1 /* $NetBSD: dmover_backend.c,v 1.2 2002/08/02 00:31:35 thorpej 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.2 2002/08/02 00:31:35 thorpej Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/lock.h> 47 #include <sys/systm.h> 48 49 #include <dev/dmover/dmovervar.h> 50 51 TAILQ_HEAD(, dmover_backend) dmover_backend_list; 52 struct lock dmover_backend_list_lock; 53 54 #define BACKEND_LIST_LOCK_READ() \ 55 do { \ 56 (void) spinlockmgr(&dmover_backend_list_lock, LK_SHRED, NULL); \ 57 } while (/*CONSTCOND*/0) 58 59 #define BACKEND_LIST_UNLOCK_READ() \ 60 do { \ 61 (void) spinlockmgr(&dmover_backend_list_lock, LK_RELEASE, NULL);\ 62 } while (/*CONSTCOND*/0) 63 64 #define BACKEND_LIST_LOCK_WRITE(s) \ 65 do { \ 66 (s) = splbio(); \ 67 (void) spinlockmgr(&dmover_backend_list_lock, LK_EXCLUSIVE, NULL); \ 68 } while (/*CONSTCOND*/0) 69 70 #define BACKEND_LIST_UNLOCK_WRITE(s) \ 71 do { \ 72 (void) spinlockmgr(&dmover_backend_list_lock, LK_RELEASE, NULL);\ 73 splx((s)); \ 74 } while (/*CONSTCOND*/0) 75 76 static int initialized; 77 static struct simplelock initialized_slock = SIMPLELOCK_INITIALIZER; 78 79 static void 80 initialize(void) 81 { 82 83 simple_lock(&initialized_slock); 84 if (__predict_true(initialized == 0)) { 85 TAILQ_INIT(&dmover_backend_list); 86 spinlockinit(&dmover_backend_list_lock, "dmbelk", 0); 87 88 /* Initialize the other bits of dmover. */ 89 dmover_session_initialize(); 90 dmover_request_initialize(); 91 dmover_process_initialize(); 92 93 initialized = 1; 94 } 95 simple_unlock(&initialized_slock); 96 } 97 98 /* 99 * dmover_backend_register: [back-end interface function] 100 * 101 * Register a back-end with dmover-api. 102 */ 103 void 104 dmover_backend_register(struct dmover_backend *dmb) 105 { 106 int s; 107 108 if (__predict_false(initialized == 0)) 109 initialize(); 110 111 LIST_INIT(&dmb->dmb_sessions); 112 dmb->dmb_nsessions = 0; 113 114 TAILQ_INIT(&dmb->dmb_pendreqs); 115 dmb->dmb_npendreqs = 0; 116 117 BACKEND_LIST_LOCK_WRITE(s); 118 TAILQ_INSERT_TAIL(&dmover_backend_list, dmb, dmb_list); 119 BACKEND_LIST_UNLOCK_WRITE(s); 120 } 121 122 /* 123 * dmover_backend_unregister: [back-end interface function] 124 * 125 * Un-register a back-end from dmover-api. 126 */ 127 void 128 dmover_backend_unregister(struct dmover_backend *dmb) 129 { 130 int s; 131 132 #ifdef DIAGNOSTIC 133 if (__predict_false(initialized == 0)) { 134 int croak; 135 136 simple_lock(&initialized_slock); 137 croak = (initialized == 0); 138 simple_unlock(&initialized_slock); 139 140 if (croak) 141 panic("dmover_backend_unregister: not initialized"); 142 } 143 #endif 144 145 /* XXX */ 146 if (dmb->dmb_nsessions) 147 panic("dmover_backend_unregister"); 148 149 BACKEND_LIST_LOCK_WRITE(s); 150 TAILQ_REMOVE(&dmover_backend_list, dmb, dmb_list); 151 BACKEND_LIST_UNLOCK_WRITE(s); 152 } 153 154 /* 155 * dmover_backend_alloc: 156 * 157 * Allocate and return a back-end on behalf of a session. 158 */ 159 int 160 dmover_backend_alloc(struct dmover_session *dses, const char *type) 161 { 162 struct dmover_backend *dmb, *best_dmb = NULL; 163 const struct dmover_algdesc *algdesc, *best_algdesc = NULL; 164 165 if (__predict_false(initialized == 0)) { 166 int fail; 167 168 simple_lock(&initialized_slock); 169 fail = (initialized == 0); 170 simple_unlock(&initialized_slock); 171 172 if (fail) 173 return (ESRCH); 174 } 175 176 BACKEND_LIST_LOCK_READ(); 177 178 /* First, find a back-end that can handle the session parts. */ 179 for (dmb = TAILQ_FIRST(&dmover_backend_list); dmb != NULL; 180 dmb = TAILQ_NEXT(dmb, dmb_list)) { 181 /* 182 * First, check to see if the back-end supports the 183 * function we wish to perform. 184 */ 185 algdesc = dmover_algdesc_lookup(dmb->dmb_algdescs, 186 dmb->dmb_nalgdescs, type); 187 if (algdesc == NULL) 188 continue; 189 190 if (best_dmb == NULL) { 191 best_dmb = dmb; 192 best_algdesc = algdesc; 193 continue; 194 } 195 196 /* 197 * XXX All the stuff from here on should be shot in 198 * XXX the head. Instead, we should build a list 199 * XXX of candidates, and select the best back-end 200 * XXX when a request is scheduled for processing. 201 */ 202 203 if (dmb->dmb_speed >= best_dmb->dmb_speed) { 204 /* 205 * If the current best match is slower than 206 * this back-end, then this one is the new 207 * best match. 208 */ 209 if (dmb->dmb_speed > best_dmb->dmb_speed) { 210 best_dmb = dmb; 211 best_algdesc = algdesc; 212 continue; 213 } 214 215 /* 216 * If this back-end has fewer sessions allocated 217 * to it than the current best match, then this 218 * one is now the best match. 219 */ 220 if (best_dmb->dmb_nsessions > dmb->dmb_nsessions) { 221 best_dmb = dmb; 222 best_algdesc = algdesc; 223 continue; 224 } 225 } 226 } 227 if (best_dmb == NULL) { 228 BACKEND_LIST_UNLOCK_READ(); 229 return (ESRCH); 230 } 231 232 KASSERT(best_algdesc != NULL); 233 234 /* Plug the back-end into the static (XXX) assignment. */ 235 dses->__dses_assignment.das_backend = best_dmb; 236 dses->__dses_assignment.das_algdesc = best_algdesc; 237 238 dses->dses_ninputs = algdesc->dad_ninputs; 239 240 LIST_INSERT_HEAD(&best_dmb->dmb_sessions, dses, __dses_list); 241 best_dmb->dmb_nsessions++; 242 243 BACKEND_LIST_UNLOCK_READ(); 244 245 return (0); 246 } 247 248 /* 249 * dmover_backend_release: 250 * 251 * Release the back-end from the specified session. 252 */ 253 void 254 dmover_backend_release(struct dmover_session *dses) 255 { 256 struct dmover_backend *dmb; 257 258 BACKEND_LIST_UNLOCK_READ(); 259 260 /* XXX Clear out the static assignment. */ 261 dmb = dses->__dses_assignment.das_backend; 262 dses->__dses_assignment.das_backend = NULL; 263 dses->__dses_assignment.das_algdesc = NULL; 264 265 LIST_REMOVE(dses, __dses_list); 266 dmb->dmb_nsessions--; 267 268 BACKEND_LIST_UNLOCK_READ(); 269 } 270