1 /* $NetBSD: cmds.c,v 1.8 2005/06/02 05:59:32 lukem 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 1999 Michael Smith 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * from FreeBSD: command.c,v 1.2 2000/04/11 23:04:17 msmith Exp 65 */ 66 67 #ifndef lint 68 #include <sys/cdefs.h> 69 __RCSID("$NetBSD: cmds.c,v 1.8 2005/06/02 05:59:32 lukem Exp $"); 70 #endif /* not lint */ 71 72 #include <sys/types.h> 73 #include <sys/ioctl.h> 74 #include <sys/queue.h> 75 #include <sys/endian.h> 76 77 #include <dev/ic/mlxreg.h> 78 #include <dev/ic/mlxio.h> 79 80 #include <err.h> 81 #include <fcntl.h> 82 #include <stdio.h> 83 #include <stdlib.h> 84 #include <string.h> 85 #include <ctype.h> 86 #include <unistd.h> 87 #include <getopt.h> 88 89 #include "extern.h" 90 91 static void cmd_status0(struct mlx_disk *); 92 static void cmd_check0(struct mlx_disk *); 93 static void cmd_detach0(struct mlx_disk *); 94 95 static struct mlx_rebuild_status rs; 96 static int rstatus; 97 98 struct { 99 int hwid; 100 const char *name; 101 } static const mlx_ctlr_names[] = { 102 { 0x00, "960E/960M" }, 103 { 0x01, "960P/PD" }, 104 { 0x02, "960PL" }, 105 { 0x10, "960PG" }, 106 { 0x11, "960PJ" }, 107 { 0x12, "960PR" }, 108 { 0x13, "960PT" }, 109 { 0x14, "960PTL0" }, 110 { 0x15, "960PRL" } , 111 { 0x16, "960PTL1" }, 112 { 0x20, "1100PVX" }, 113 { -1, NULL }, 114 }; 115 116 /* 117 * Status output 118 */ 119 static void 120 cmd_status0(struct mlx_disk *md) 121 { 122 int result; 123 124 result = md->hwunit; 125 if (ioctl(mlxfd, MLXD_STATUS, &result) < 0) 126 err(EXIT_FAILURE, "ioctl(MLXD_STATUS)"); 127 128 switch(result) { 129 case MLX_SYSD_ONLINE: 130 printf("%s: online\n", md->name); 131 break; 132 133 case MLX_SYSD_CRITICAL: 134 printf("%s: critical\n", md->name); 135 if (!rstatus) 136 rstatus = 1; 137 break; 138 139 case MLX_SYSD_OFFLINE: 140 printf("%s: offline\n", md->name); 141 rstatus = 2; 142 break; 143 144 default: 145 printf("%s: unknown status 0x%02x\n", md->name, result); 146 break; 147 } 148 149 /* Rebuild/check in progress on this drive? */ 150 if (rs.rs_drive == md->hwunit && 151 rs.rs_code != MLX_REBUILDSTAT_IDLE) { 152 switch(rs.rs_code) { 153 case MLX_REBUILDSTAT_REBUILDCHECK: 154 printf(" [consistency check"); 155 break; 156 157 case MLX_REBUILDSTAT_ADDCAPACITY: 158 printf(" [add capacity"); 159 break; 160 161 case MLX_REBUILDSTAT_ADDCAPACITYINIT: 162 printf(" [add capacity init"); 163 break; 164 165 default: 166 printf(" [unknown operation"); 167 break; 168 } 169 170 printf(": %d/%d, %d%% complete]\n", rs.rs_remaining, rs.rs_size, 171 ((rs.rs_size - rs.rs_remaining) / (rs.rs_size / 100))); 172 } 173 } 174 175 int 176 cmd_status(char **argv) 177 { 178 179 if (ioctl(mlxfd, MLX_REBUILDSTAT, &rs) < 0) 180 err(EXIT_FAILURE, "ioctl(MLX_REBUILDSTAT)"); 181 182 mlx_disk_iterate(cmd_status0); 183 return (rstatus); 184 } 185 186 /* 187 * Display controller status. 188 */ 189 int 190 cmd_cstatus(char **argv) 191 { 192 struct mlx_enquiry2 enq; 193 struct mlx_phys_drv pd; 194 static char buf[80]; 195 const char *model; 196 int i, channel, target; 197 198 model = NULL; /* XXXGCC -Wuninitialized */ 199 200 for (i = 0; i < sizeof(mlx_ctlr_names) / sizeof(mlx_ctlr_names[0]); i++) 201 if (ci.ci_hardware_id == mlx_ctlr_names[i].hwid) { 202 model = mlx_ctlr_names[i].name; 203 break; 204 } 205 206 if (i == sizeof(mlx_ctlr_names) / sizeof(mlx_ctlr_names[0])) { 207 snprintf(buf, sizeof(buf), " model 0x%x", ci.ci_hardware_id); 208 model = buf; 209 } 210 211 printf("DAC%s, %d channel%s, firmware %d.%02d-%c-%02d", 212 model, ci.ci_nchan, 213 ci.ci_nchan > 1 ? "s" : "", 214 ci.ci_firmware_id[0], ci.ci_firmware_id[1], 215 ci.ci_firmware_id[3], ci.ci_firmware_id[2]); 216 if (ci.ci_mem_size != 0) 217 printf(", %dMB RAM", ci.ci_mem_size >> 20); 218 printf("\n"); 219 220 if (verbosity > 0 && ci.ci_iftype > 1) { 221 mlx_enquiry(&enq); 222 223 printf(" Hardware ID\t\t\t0x%08x\n", 224 le32toh(*(u_int32_t *)enq.me_hardware_id)); 225 printf(" Firmware ID\t\t\t0x%08x\n", 226 le32toh(*(u_int32_t *)enq.me_firmware_id)); 227 printf(" Configured/Actual channels\t%d/%d\n", 228 enq.me_configured_channels, enq.me_actual_channels); 229 printf(" Max Targets\t\t\t%d\n", enq.me_max_targets); 230 printf(" Max Tags\t\t\t%d\n", enq.me_max_tags); 231 printf(" Max System Drives\t\t%d\n", enq.me_max_sys_drives); 232 printf(" Max Arms\t\t\t%d\n", enq.me_max_arms); 233 printf(" Max Spans\t\t\t%d\n", enq.me_max_spans); 234 printf(" DRAM/cache/flash/NVRAM size\t%d/%d/%d/%d\n", 235 le32toh(enq.me_mem_size), le32toh(enq.me_cache_size), 236 le32toh(enq.me_flash_size), le32toh(enq.me_nvram_size)); 237 printf(" DRAM type\t\t\t%d\n", le16toh(enq.me_mem_type)); 238 printf(" Clock Speed\t\t\t%dns\n", 239 le16toh(enq.me_clock_speed)); 240 printf(" Hardware Speed\t\t%dns\n", 241 le16toh(enq.me_hardware_speed)); 242 printf(" Max Commands\t\t\t%d\n", 243 le16toh(enq.me_max_commands)); 244 printf(" Max SG Entries\t\t%d\n", le16toh(enq.me_max_sg)); 245 printf(" Max DP\t\t\t%d\n", le16toh(enq.me_max_dp)); 246 printf(" Max IOD\t\t\t%d\n", le16toh(enq.me_max_iod)); 247 printf(" Max Comb\t\t\t%d\n", le16toh(enq.me_max_comb)); 248 printf(" Latency\t\t\t%ds\n", enq.me_latency); 249 printf(" SCSI Timeout\t\t\t%ds\n", enq.me_scsi_timeout); 250 printf(" Min Free Lines\t\t%d\n", 251 le16toh(enq.me_min_freelines)); 252 printf(" Rate Constant\t\t\t%d\n", enq.me_rate_const); 253 printf(" MAXBLK\t\t\t%d\n", le16toh(enq.me_maxblk)); 254 printf(" Blocking Factor\t\t%d sectors\n", 255 le16toh(enq.me_blocking_factor)); 256 printf(" Cache Line Size\t\t%d blocks\n", 257 le16toh(enq.me_cacheline)); 258 printf(" SCSI Capability\t\t%s%dMHz, %d bit\n", 259 enq.me_scsi_cap & (1<<4) ? "differential " : "", 260 (1 << ((enq.me_scsi_cap >> 2) & 3)) * 10, 261 8 << (enq.me_scsi_cap & 0x3)); 262 printf(" Firmware Build Number\t\t%d\n", 263 le16toh(enq.me_firmware_build)); 264 printf(" Fault Management Type\t\t%d\n", 265 enq.me_fault_mgmt_type); 266 #if 0 267 printf(" Features\t\t\t%b\n", enq.me_firmware_features, 268 "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n"); 269 #endif 270 } else if (verbosity > 0 && ci.ci_iftype == 1) 271 warnx("can't be verbose for this firmware level"); 272 273 fflush(stdout); 274 275 if (ci.ci_firmware_id[0] < 3) { 276 warnx("can't display physical drives for this firmware level"); 277 return (0); 278 } 279 280 /* 281 * Fetch and print physical drive data. 282 */ 283 for (channel = 0; channel < enq.me_configured_channels; channel++) { 284 for (target = 0; target < enq.me_max_targets; target++) 285 if (mlx_get_device_state(channel, target, &pd) == 0 && 286 (pd.pd_flags1 & MLX_PHYS_DRV_PRESENT) != 0) 287 mlx_print_phys_drv(&pd, channel, target, " "); 288 } 289 290 return (0); 291 } 292 293 /* 294 * Recscan for new or changed system drives. 295 */ 296 int 297 cmd_rescan(char **argv) 298 { 299 300 if (ioctl(mlxfd, MLX_RESCAN_DRIVES) < 0) 301 err(EXIT_FAILURE, "rescan failed"); 302 return (0); 303 } 304 305 /* 306 * Detach one or more system drives from a controller. 307 */ 308 static void 309 cmd_detach0(struct mlx_disk *md) 310 { 311 312 if (ioctl(mlxfd, MLXD_DETACH, &md->hwunit) < 0) 313 warn("can't detach %s", md->name); 314 } 315 316 int 317 cmd_detach(char **argv) 318 { 319 320 mlx_disk_iterate(cmd_detach0); 321 return (0); 322 } 323 324 /* 325 * Initiate a consistency check on a system drive. 326 */ 327 static void 328 cmd_check0(struct mlx_disk *md) 329 { 330 int result; 331 332 if (ioctl(mlxfd, MLXD_CHECKASYNC, &result) == 0) 333 return; 334 335 switch (result) { 336 case 0x0002: 337 warnx("one or more of the SCSI disks on which %s", md->name); 338 warnx("depends is DEAD."); 339 break; 340 341 case 0x0105: 342 warnx("drive %s is invalid, or not a drive which ", md->name); 343 warnx("can be checked."); 344 break; 345 346 case 0x0106: 347 warnx("drive rebuild or consistency check is already "); 348 warnx("in progress on this controller."); 349 break; 350 351 default: 352 err(EXIT_FAILURE, "ioctl(MLXD_CHECKASYNC)"); 353 /* NOTREACHED */ 354 } 355 } 356 357 int 358 cmd_check(char **argv) 359 { 360 361 if (ci.ci_firmware_id[0] < 3) { 362 warnx("action not supported by this firmware version"); 363 return (1); 364 } 365 366 mlx_disk_iterate(cmd_check0); 367 return (0); 368 } 369 370 /* 371 * Initiate a physical drive rebuild. 372 */ 373 int 374 cmd_rebuild(char **argv) 375 { 376 struct mlx_rebuild_request rb; 377 char *p; 378 379 if (ci.ci_firmware_id[0] < 3) { 380 warnx("action not supported by this firmware version"); 381 return (1); 382 } 383 384 if (argv[0] == NULL || argv[1] != NULL) 385 usage(); 386 387 rb.rr_channel = (int)strtol(*argv, &p, 0); 388 if (p[0] != ':' || p[1] == '\0') 389 usage(); 390 391 rb.rr_target = (int)strtol(*argv, &p, 0); 392 if (p[0] != '\0') 393 usage(); 394 395 if (ioctl(mlxfd, MLX_REBUILDASYNC, &rb) == 0) 396 return (0); 397 398 switch (rb.rr_status) { 399 case 0x0002: 400 warnx("the drive at %d:%d is already ONLINE", rb.rr_channel, 401 rb.rr_target); 402 break; 403 404 case 0x0004: 405 warnx("drive failed during rebuild"); 406 break; 407 408 case 0x0105: 409 warnx("there is no drive at %d:%d", rb.rr_channel, 410 rb.rr_target); 411 break; 412 413 case 0x0106: 414 warnx("drive rebuild or consistency check is already in "); 415 warnx("progress on this controller"); 416 break; 417 418 default: 419 err(EXIT_FAILURE, "ioctl(MLXD_CHECKASYNC)"); 420 /* NOTREACHED */ 421 } 422 423 return(0); 424 } 425