112198SEiji.Ota@Sun.COM /*
212198SEiji.Ota@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
312198SEiji.Ota@Sun.COM */
412198SEiji.Ota@Sun.COM
512198SEiji.Ota@Sun.COM /*
612763SGiri.Adari@Sun.COM * This file contains code imported from the OFED rds source file info.c
712763SGiri.Adari@Sun.COM * Oracle elects to have and use the contents of info.c under and governed
812763SGiri.Adari@Sun.COM * by the OpenIB.org BSD license (see below for full license text). However,
912763SGiri.Adari@Sun.COM * the following notice accompanied the original version of this file:
1012763SGiri.Adari@Sun.COM */
1112763SGiri.Adari@Sun.COM
1212763SGiri.Adari@Sun.COM /*
1312198SEiji.Ota@Sun.COM * Copyright (c) 2006 Oracle. All rights reserved.
1412198SEiji.Ota@Sun.COM *
1512198SEiji.Ota@Sun.COM * This software is available to you under a choice of one of two
1612198SEiji.Ota@Sun.COM * licenses. You may choose to be licensed under the terms of the GNU
1712198SEiji.Ota@Sun.COM * General Public License (GPL) Version 2, available from the file
1812198SEiji.Ota@Sun.COM * COPYING in the main directory of this source tree, or the
1912198SEiji.Ota@Sun.COM * OpenIB.org BSD license below:
2012198SEiji.Ota@Sun.COM *
2112198SEiji.Ota@Sun.COM * Redistribution and use in source and binary forms, with or
2212198SEiji.Ota@Sun.COM * without modification, are permitted provided that the following
2312198SEiji.Ota@Sun.COM * conditions are met:
2412198SEiji.Ota@Sun.COM *
2512198SEiji.Ota@Sun.COM * - Redistributions of source code must retain the above
2612198SEiji.Ota@Sun.COM * copyright notice, this list of conditions and the following
2712198SEiji.Ota@Sun.COM * disclaimer.
2812198SEiji.Ota@Sun.COM *
2912198SEiji.Ota@Sun.COM * - Redistributions in binary form must reproduce the above
3012198SEiji.Ota@Sun.COM * copyright notice, this list of conditions and the following
3112198SEiji.Ota@Sun.COM * disclaimer in the documentation and/or other materials
3212198SEiji.Ota@Sun.COM * provided with the distribution.
3312198SEiji.Ota@Sun.COM *
3412198SEiji.Ota@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3512198SEiji.Ota@Sun.COM * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
3612198SEiji.Ota@Sun.COM * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
3712198SEiji.Ota@Sun.COM * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
3812198SEiji.Ota@Sun.COM * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3912198SEiji.Ota@Sun.COM * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
4012198SEiji.Ota@Sun.COM * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4112198SEiji.Ota@Sun.COM * SOFTWARE.
4212198SEiji.Ota@Sun.COM *
4312198SEiji.Ota@Sun.COM */
4412198SEiji.Ota@Sun.COM #include <sys/rds.h>
4512198SEiji.Ota@Sun.COM
4612198SEiji.Ota@Sun.COM #include <sys/ib/clients/rdsv3/rdsv3.h>
4712580SGiri.Adari@Sun.COM #include <sys/ib/clients/rdsv3/rdsv3_debug.h>
4812198SEiji.Ota@Sun.COM
4912198SEiji.Ota@Sun.COM /*
5012198SEiji.Ota@Sun.COM * This file implements a getsockopt() call which copies a set of fixed
5112198SEiji.Ota@Sun.COM * sized structs into a user-specified buffer as a means of providing
5212198SEiji.Ota@Sun.COM * read-only information about RDS.
5312198SEiji.Ota@Sun.COM *
5412198SEiji.Ota@Sun.COM * For a given information source there are a given number of fixed sized
5512198SEiji.Ota@Sun.COM * structs at a given time. The structs are only copied if the user-specified
5612198SEiji.Ota@Sun.COM * buffer is big enough. The destination pages that make up the buffer
5712198SEiji.Ota@Sun.COM * are pinned for the duration of the copy.
5812198SEiji.Ota@Sun.COM *
5912198SEiji.Ota@Sun.COM * This gives us the following benefits:
6012198SEiji.Ota@Sun.COM *
6112198SEiji.Ota@Sun.COM * - simple implementation, no copy "position" across multiple calls
6212198SEiji.Ota@Sun.COM * - consistent snapshot of an info source
6312198SEiji.Ota@Sun.COM * - atomic copy works well with whatever locking info source has
6412198SEiji.Ota@Sun.COM * - one portable tool to get rds info across implementations
6512198SEiji.Ota@Sun.COM * - long-lived tool can get info without allocating
6612198SEiji.Ota@Sun.COM *
6712198SEiji.Ota@Sun.COM * at the following costs:
6812198SEiji.Ota@Sun.COM *
6912198SEiji.Ota@Sun.COM * - info source copy must be pinned, may be "large"
7012198SEiji.Ota@Sun.COM */
7112198SEiji.Ota@Sun.COM
7212198SEiji.Ota@Sun.COM static kmutex_t rdsv3_info_lock;
73*12863SEiji.Ota@Sun.COM static rdsv3_info_func rdsv3_info_funcs[RDS_INFO_LAST - RDS_INFO_FIRST + 1];
7412198SEiji.Ota@Sun.COM
7512198SEiji.Ota@Sun.COM void
rdsv3_info_register_func(int optname,rdsv3_info_func func)7612198SEiji.Ota@Sun.COM rdsv3_info_register_func(int optname, rdsv3_info_func func)
7712198SEiji.Ota@Sun.COM {
78*12863SEiji.Ota@Sun.COM int offset = optname - RDS_INFO_FIRST;
7912198SEiji.Ota@Sun.COM
80*12863SEiji.Ota@Sun.COM ASSERT(optname >= RDS_INFO_FIRST && optname <= RDS_INFO_LAST);
8112198SEiji.Ota@Sun.COM
8212198SEiji.Ota@Sun.COM mutex_enter(&rdsv3_info_lock);
8312676SEiji.Ota@Sun.COM ASSERT(!rdsv3_info_funcs[offset]);
8412198SEiji.Ota@Sun.COM rdsv3_info_funcs[offset] = func;
8512198SEiji.Ota@Sun.COM mutex_exit(&rdsv3_info_lock);
8612198SEiji.Ota@Sun.COM }
8712198SEiji.Ota@Sun.COM
8812198SEiji.Ota@Sun.COM /* ARGSUSED */
8912198SEiji.Ota@Sun.COM void
rdsv3_info_deregister_func(int optname,rdsv3_info_func func)9012198SEiji.Ota@Sun.COM rdsv3_info_deregister_func(int optname, rdsv3_info_func func)
9112198SEiji.Ota@Sun.COM {
92*12863SEiji.Ota@Sun.COM int offset = optname - RDS_INFO_FIRST;
9312198SEiji.Ota@Sun.COM
94*12863SEiji.Ota@Sun.COM ASSERT(optname >= RDS_INFO_FIRST && optname <= RDS_INFO_LAST);
9512198SEiji.Ota@Sun.COM
9612198SEiji.Ota@Sun.COM mutex_enter(&rdsv3_info_lock);
9712198SEiji.Ota@Sun.COM rdsv3_info_funcs[offset] = NULL;
9812198SEiji.Ota@Sun.COM mutex_exit(&rdsv3_info_lock);
9912198SEiji.Ota@Sun.COM }
10012198SEiji.Ota@Sun.COM
10112198SEiji.Ota@Sun.COM /*
10212198SEiji.Ota@Sun.COM * @optval points to the userspace buffer that the information snapshot
10312198SEiji.Ota@Sun.COM * will be copied into.
10412198SEiji.Ota@Sun.COM *
10512198SEiji.Ota@Sun.COM * This function returns -errno if there is a failure, particularly -ENOSPC
10612198SEiji.Ota@Sun.COM * if the given userspace buffer was not large enough to fit the snapshot.
10712198SEiji.Ota@Sun.COM * On success it returns the positive number of bytes of each array element
10812198SEiji.Ota@Sun.COM * in the snapshot.
10912198SEiji.Ota@Sun.COM */
11012198SEiji.Ota@Sun.COM int
rdsv3_info_ioctl(struct rsock * sock,int optname,char * optval,int32_t * rvalp)11112580SGiri.Adari@Sun.COM rdsv3_info_ioctl(struct rsock *sock, int optname, char *optval,
11212580SGiri.Adari@Sun.COM int32_t *rvalp)
11312198SEiji.Ota@Sun.COM {
11412198SEiji.Ota@Sun.COM struct rdsv3_info_iterator iter;
11512198SEiji.Ota@Sun.COM struct rdsv3_info_lengths lens;
11612198SEiji.Ota@Sun.COM rdsv3_info_func func;
11712580SGiri.Adari@Sun.COM struct rds_info_arg arg;
11812580SGiri.Adari@Sun.COM uint32_t ulen = 0, klen;
11912198SEiji.Ota@Sun.COM
120*12863SEiji.Ota@Sun.COM func = rdsv3_info_funcs[optname - RDS_INFO_FIRST];
12112198SEiji.Ota@Sun.COM if (func == NULL) {
12212580SGiri.Adari@Sun.COM RDSV3_DPRINTF2("rdsv3_info_ioctl",
12312580SGiri.Adari@Sun.COM "No Info Function, optname: %d", optname);
12412580SGiri.Adari@Sun.COM return (ENOPROTOOPT);
12512580SGiri.Adari@Sun.COM }
12612580SGiri.Adari@Sun.COM
12712580SGiri.Adari@Sun.COM if (optval == NULL) {
12812580SGiri.Adari@Sun.COM RDSV3_DPRINTF2("rdsv3_info_ioctl", "optval is NULL");
12912580SGiri.Adari@Sun.COM return (EINVAL);
13012580SGiri.Adari@Sun.COM }
13112580SGiri.Adari@Sun.COM if (ddi_copyin(optval, &arg, sizeof (struct rds_info_arg), 0) != 0) {
13212580SGiri.Adari@Sun.COM RDSV3_DPRINTF2("rdsv3_info_ioctl",
13312580SGiri.Adari@Sun.COM "ddi_copyin for address: 0x%p failed", optval);
13412580SGiri.Adari@Sun.COM return (EFAULT);
13512198SEiji.Ota@Sun.COM }
13612198SEiji.Ota@Sun.COM
13712580SGiri.Adari@Sun.COM RDSV3_DPRINTF4("rdsv3_info_ioctl",
13812580SGiri.Adari@Sun.COM "optname: %d lenp: %llx datap: %llx", optname, arg.lenp, arg.datap);
13912580SGiri.Adari@Sun.COM
14012580SGiri.Adari@Sun.COM if (arg.lenp == NULL) {
14112580SGiri.Adari@Sun.COM RDSV3_DPRINTF2("rdsv3_info_ioctl", "arg.lenp is NULL");
14212580SGiri.Adari@Sun.COM return (EFAULT);
14312580SGiri.Adari@Sun.COM }
14412580SGiri.Adari@Sun.COM
14512580SGiri.Adari@Sun.COM if (ddi_copyin((void *)(uintptr_t)arg.lenp, &ulen,
14612580SGiri.Adari@Sun.COM sizeof (uint32_t), 0) != 0) {
14712580SGiri.Adari@Sun.COM RDSV3_DPRINTF2("rdsv3_info_ioctl",
14812580SGiri.Adari@Sun.COM "ddi_copyin for address, lenp: 0x%p failed", arg.lenp);
14912580SGiri.Adari@Sun.COM return (EFAULT);
15012198SEiji.Ota@Sun.COM }
15112198SEiji.Ota@Sun.COM
15212580SGiri.Adari@Sun.COM RDSV3_DPRINTF3("rdsv3_info_ioctl", "optname: %d len: %d datap: %p",
15312580SGiri.Adari@Sun.COM optname, ulen, arg.datap);
15412580SGiri.Adari@Sun.COM
15512580SGiri.Adari@Sun.COM bzero(&iter, sizeof (struct rdsv3_info_iterator));
15612580SGiri.Adari@Sun.COM /* a 0 len call is just trying to probe its length */
15712580SGiri.Adari@Sun.COM if (ulen == 0) {
15812580SGiri.Adari@Sun.COM iter.addr = NULL;
15912580SGiri.Adari@Sun.COM } else if (arg.datap == NULL) {
16012580SGiri.Adari@Sun.COM RDSV3_DPRINTF2("rdsv3_info_ioctl",
16112580SGiri.Adari@Sun.COM "arg.datap is NULL, ulen set to: %d", ulen);
16212580SGiri.Adari@Sun.COM return (EINVAL);
16312580SGiri.Adari@Sun.COM } else {
16412580SGiri.Adari@Sun.COM iter.addr = (char *)(uintptr_t)arg.datap;
16512580SGiri.Adari@Sun.COM }
16612198SEiji.Ota@Sun.COM iter.offset = 0;
16712198SEiji.Ota@Sun.COM
16812580SGiri.Adari@Sun.COM bzero(&lens, sizeof (struct rdsv3_info_lengths));
16912580SGiri.Adari@Sun.COM func(sock, ulen, &iter, &lens);
17012580SGiri.Adari@Sun.COM
17112580SGiri.Adari@Sun.COM klen = lens.nr * lens.each;
17212198SEiji.Ota@Sun.COM
17312580SGiri.Adari@Sun.COM if (ddi_copyout(&klen, (void *)(uintptr_t)arg.lenp,
17412580SGiri.Adari@Sun.COM sizeof (uint32_t), 0) != 0) {
17512580SGiri.Adari@Sun.COM RDSV3_DPRINTF2("rdsv3_info_ioctl",
17612580SGiri.Adari@Sun.COM "ddi_copyout(%p %p) failed", &klen, arg.lenp);
17712580SGiri.Adari@Sun.COM return (EFAULT);
17812198SEiji.Ota@Sun.COM }
17912198SEiji.Ota@Sun.COM
18012580SGiri.Adari@Sun.COM RDSV3_DPRINTF3("rdsv3_info_ioctl",
18112580SGiri.Adari@Sun.COM "optname: %d ulen: %d klen: %d each: %d", optname, ulen, klen,
18212580SGiri.Adari@Sun.COM lens.each);
18312580SGiri.Adari@Sun.COM
18412580SGiri.Adari@Sun.COM if (ulen < klen) {
18512580SGiri.Adari@Sun.COM return (ENOSPC);
18612580SGiri.Adari@Sun.COM }
18712580SGiri.Adari@Sun.COM
18812580SGiri.Adari@Sun.COM RDSV3_DPRINTF4("rdsv3_info_ioctl", "Return optname: %d", optname);
18912580SGiri.Adari@Sun.COM
19012580SGiri.Adari@Sun.COM *rvalp = lens.each;
19112198SEiji.Ota@Sun.COM return (0);
19212198SEiji.Ota@Sun.COM }
193