Home | History | Annotate | Line # | Download | only in dmover
dmover_backend.c revision 1.4
      1 /*	$NetBSD: dmover_backend.c,v 1.4 2003/04/01 20:59:15 briggs 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.4 2003/04/01 20:59:15 briggs 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_SHARED, 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_LOCK_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