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