1/* $NetBSD: dklist.c,v 1.8 2008/04/28 20:24:17 martin Exp $ */ 2 3/*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * Copyright (c) 1996 John M. Vinopal 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed for the NetBSD Project 47 * by John M. Vinopal. 48 * 4. The name of the author may not be used to endorse or promote products 49 * derived from this software without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 52 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 53 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 54 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 55 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 56 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 57 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 58 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 59 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64#ifndef lint 65#include <sys/cdefs.h> 66__RCSID("$NetBSD: dklist.c,v 1.8 2008/04/28 20:24:17 martin Exp $"); 67#endif /* not lint */ 68 69#include <sys/types.h> 70#include <sys/disk.h> 71#include <sys/ioctl.h> 72 73#include <dev/ic/mlxreg.h> 74#include <dev/ic/mlxio.h> 75 76#include <err.h> 77#include <fcntl.h> 78#include <kvm.h> 79#include <limits.h> 80#include <nlist.h> 81#include <stdio.h> 82#include <stdlib.h> 83#include <string.h> 84#include <ctype.h> 85#include <unistd.h> 86 87#include "extern.h" 88 89static SIMPLEQ_HEAD(, mlx_disk) mlx_disks; 90 91static struct nlist namelist[] = { 92#define X_DISK_COUNT 0 93 { "_iostat_count", 0, 0, 0, 0 }, /* number of disks */ 94#define X_DISKLIST 1 95 { "_iostatlist", 0, 0, 0, 0 }, /* TAILQ of disks */ 96 { NULL, 0, 0, 0, 0 }, 97}; 98 99#define KVM_ERROR(_string) { \ 100 warnx("%s", (_string)); \ 101 errx(1, "%s", kvm_geterr(kd)); \ 102} 103 104/* 105 * Dereference the namelist pointer `v' and fill in the local copy 106 * 'p' which is of size 's'. 107 */ 108#define deref_nl(kd, v, p, s) \ 109 deref_kptr(kd, (void *)namelist[(v)].n_value, (p), (s)); 110 111static void deref_kptr(kvm_t *, void *, void *, size_t); 112 113void 114mlx_disk_init(void) 115{ 116 117 SIMPLEQ_INIT(&mlx_disks); 118} 119 120int 121mlx_disk_empty(void) 122{ 123 124 return (SIMPLEQ_EMPTY(&mlx_disks)); 125} 126 127void 128mlx_disk_iterate(void (*func)(struct mlx_disk *)) 129{ 130 struct mlx_disk *md; 131 132 SIMPLEQ_FOREACH(md, &mlx_disks, chain) 133 (*func)(md); 134} 135 136static int 137mlx_disk_add0(const char *name) 138{ 139 struct mlx_disk *md; 140 int unit; 141 142 if (name[0] != 'l' || name[1] != 'd' || !isdigit((unsigned char)name[2])) 143 return (-1); 144 145 SIMPLEQ_FOREACH(md, &mlx_disks, chain) 146 if (strcmp(md->name, name) == 0) 147 return (0); 148 149 unit = atoi(name + 2); 150 if (ioctl(mlxfd, MLX_GET_SYSDRIVE, &unit) < 0) 151 return (-1); 152 153 if ((md = malloc(sizeof(*md))) == NULL) 154 err(EXIT_FAILURE, "mlx_disk_add()"); 155 156 strlcpy(md->name, name, sizeof(md->name)); 157 md->hwunit = unit; 158 SIMPLEQ_INSERT_TAIL(&mlx_disks, md, chain); 159 return (0); 160} 161 162void 163mlx_disk_add(const char *name) 164{ 165 166 if (mlx_disk_add0(name) != 0) 167 errx(EXIT_FAILURE, "%s is not attached to %s", name, mlxname); 168} 169 170void 171mlx_disk_add_all(void) 172{ 173 struct iostatlist_head iostat_head; 174 struct io_stats cur_drive, *drv; 175 char errbuf[_POSIX2_LINE_MAX]; 176 char buf[12]; 177 int i, ndrives; 178 kvm_t *kd; 179 180 /* Open the kernel. */ 181 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL) 182 errx(1, "kvm_openfiles: %s", errbuf); 183 184 /* Obtain the namelist symbols from the kernel. */ 185 if (kvm_nlist(kd, namelist)) 186 KVM_ERROR("kvm_nlist failed to read symbols."); 187 188 /* Get the number of attached drives. */ 189 deref_nl(kd, X_DISK_COUNT, &ndrives, sizeof(ndrives)); 190 191 if (ndrives < 0) 192 errx(EXIT_FAILURE, "invalid _disk_count %d.", ndrives); 193 if (ndrives == 0) 194 errx(EXIT_FAILURE, "no drives attached."); 195 196 /* Get a pointer to the first disk. */ 197 deref_nl(kd, X_DISKLIST, &iostat_head, sizeof(iostat_head)); 198 drv = TAILQ_FIRST(&iostat_head); 199 200 /* Try to add each disk to the list. */ 201 for (i = 0; i < ndrives; i++) { 202 deref_kptr(kd, drv, &cur_drive, sizeof(cur_drive)); 203 deref_kptr(kd, cur_drive.io_name, buf, sizeof(buf)); 204 if (cur_drive.io_type == IOSTAT_DISK) 205 mlx_disk_add0(buf); 206 drv = TAILQ_NEXT(&cur_drive, io_link); 207 } 208 209 kvm_close(kd); 210} 211 212/* 213 * Dereference the kernel pointer `kptr' and fill in the local copy pointed 214 * to by `ptr'. The storage space must be pre-allocated, and the size of 215 * the copy passed in `len'. 216 */ 217static void 218deref_kptr(kvm_t *kd, void *kptr, void *ptr, size_t len) 219{ 220 char buf[128]; 221 222 if ((size_t)kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) { 223 memset(buf, 0, sizeof(buf)); 224 snprintf(buf, sizeof buf, "can't dereference kptr 0x%lx", 225 (u_long)kptr); 226 KVM_ERROR(buf); 227 } 228} 229