4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
31 #include <sys/bitmap.h>
32 #include <sys/stream.h>
33 #include <sys/strsubr.h>
34 #define _SUN_TPI_VERSION 2
35 #include <sys/tihdr.h>
36 #include <sys/suntpi.h>
39 * Hash table parameters for tpi_provinfo_table.
41 #define TPI_HASH_BITS 4
42 #define TPI_NHASH (1 << TPI_HASH_BITS)
45 * Use the first element in the key for the hash.
47 #define TPI_HASH(p) ((((uintptr_t *)p)[0] >> tpi_hashshift) % TPI_NHASH)
49 * SAMESTR is a very confusing name. LAST_QUEUE is introduced for readability.
51 #define LAST_QUEUE(q) (!SAMESTR(q))
53 static tpi_provinfo_t
*tpi_provinfo_table
[TPI_NHASH
];
54 static kmutex_t tpi_provinfo_lock
;
55 static int tpi_hashshift
;
58 * In most cases there is some transport provider (like tcp or udp) below
59 * transport user (like timod or sockets). However, it is possible to construct
60 * stream without transport provider (e.g. by pushing timod into FIFO). It is
61 * hardly of any use, but this condition was observed with sparcv9 abi tests.
62 * To count for such special case, a special tpi_nullprov static data is
63 * provided to cache information about such degenerated null-transport case.
65 static tpi_provinfo_t tpi_nullprov
; /* Placeholder for null transport */
68 * Initialise the TPI support routines. Called from strinit().
73 mutex_init(&tpi_provinfo_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
76 * Calculate the right shift for hashing a tpi_provinfo_t.
78 tpi_hashshift
= highbit(sizeof (tpi_provinfo_t
));
82 * Generate a downstream signature given the write-side queue. It
83 * passes back the size of the generated key in *keylenp. This routine
84 * cannot multithread as it returns a pointer to a static data item.
86 * There is no way (in the current module loading infrastructure) to
87 * _absolutely_ guarantee that the key below uniquely identifies an
88 * arrangement of modules and drivers. A module _might_ be unloaded and
89 * another module _might_ be loaded such that the qi_minfo is at _exactly_
90 * same kernel address, and then it _might_ be placed in a transport
91 * provider stream in exactly the same configuration (modules above and
92 * below all identical) - but it would take quite a few coincidences
93 * and modules loading and unloading does not usually happen n times a
97 tpi_makekey(queue_t
*q
, size_t *keylenp
)
99 static uintptr_t *key
= NULL
;
103 ASSERT(MUTEX_HELD(&tpi_provinfo_lock
));
105 /* assert this queue is write queue and qprocson() is called before */
106 ASSERT((q
->q_flag
& QREADR
) == 0);
107 ASSERT(q
->q_next
!= NULL
);
110 * This can be global because tpi_makekey is called with
114 key
= kmem_alloc((nstrpush
+ 1) * sizeof (uintptr_t), KM_SLEEP
);
119 * Go down q_next to the driver, but no further. We use the qi_minfo
120 * because we can find in from the queue and it is a stable part of
121 * any driver/module infrastructure.
123 for (i
= 0; !LAST_QUEUE(q
) && (q
= q
->q_next
) != NULL
; ++i
) {
124 ASSERT(i
< nstrpush
+ 1);
125 key
[i
] = (uintptr_t)q
->q_qinfo
->qi_minfo
;
129 * Allocate the actual key with the proper length, and pass it
132 *keylenp
= i
* sizeof (uintptr_t);
133 return ((void *)key
);
137 * Find an existing provider entry given a queue pointer, or allocate a
138 * new empty entry if not found. Because this routine calls kmem_alloc
139 * with KM_SLEEP, and because it traverses the q_next pointers of a stream
140 * it must be called with a proper user context and within a perimeter
141 * which protects the STREAM e.g. an open routine. This routine always
142 * returns a valid pointer.
145 tpi_findprov(queue_t
*q
)
149 tpi_provinfo_t
**tpp
;
151 mutex_enter(&tpi_provinfo_lock
);
154 * Must hold tpi_provinfo_lock since tpi_makekey() returns a pointer
157 key
= tpi_makekey(WR(q
), &keylen
);
160 /* there is nothing below us, return special nullprov entry */
161 mutex_exit(&tpi_provinfo_lock
);
162 return (&tpi_nullprov
);
166 * Look for an existing entry, or the place to put a new one.
168 for (tpp
= &tpi_provinfo_table
[TPI_HASH(key
)]; *tpp
!= NULL
;
169 tpp
= &(*tpp
)->tpi_next
) {
170 if ((*tpp
)->tpi_keylen
== keylen
&&
171 bcmp((*tpp
)->tpi_key
, key
, keylen
) == 0) {
172 mutex_exit(&tpi_provinfo_lock
);
178 * Allocate and fill in the new tpi_provinfo_t.
180 *tpp
= kmem_zalloc(sizeof (tpi_provinfo_t
), KM_SLEEP
);
181 (*tpp
)->tpi_key
= kmem_alloc(keylen
, KM_SLEEP
);
182 bcopy(key
, (*tpp
)->tpi_key
, keylen
);
183 (*tpp
)->tpi_keylen
= keylen
;
184 mutex_init(&(*tpp
)->tpi_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
186 mutex_exit(&tpi_provinfo_lock
);
191 * Allocate a TPI ACK reusing the old message if possible.
194 tpi_ack_alloc(mblk_t
*mp
, size_t size
, uchar_t db_type
, t_scalar_t prim
)
198 if ((mp
= reallocb(mp
, size
, 0)) == NULL
) {
202 if (mp
->b_cont
!= NULL
) {
206 mp
->b_datap
->db_type
= db_type
;
207 mp
->b_wptr
= mp
->b_rptr
+ size
;
208 ((union T_primitives
*)mp
->b_rptr
)->type
= prim
;