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