cmds.c revision 1.7 1 /* $NetBSD: cmds.c,v 1.7 2003/07/13 12:30:17 itojun 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.7 2003/07/13 12:30:17 itojun 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 for (i = 0; i < sizeof(mlx_ctlr_names) / sizeof(mlx_ctlr_names[0]); i++)
199 if (ci.ci_hardware_id == mlx_ctlr_names[i].hwid) {
200 model = mlx_ctlr_names[i].name;
201 break;
202 }
203
204 if (i == sizeof(mlx_ctlr_names) / sizeof(mlx_ctlr_names[0])) {
205 snprintf(buf, sizeof(buf), " model 0x%x", ci.ci_hardware_id);
206 model = buf;
207 }
208
209 printf("DAC%s, %d channel%s, firmware %d.%02d-%c-%02d",
210 model, ci.ci_nchan,
211 ci.ci_nchan > 1 ? "s" : "",
212 ci.ci_firmware_id[0], ci.ci_firmware_id[1],
213 ci.ci_firmware_id[3], ci.ci_firmware_id[2]);
214 if (ci.ci_mem_size != 0)
215 printf(", %dMB RAM", ci.ci_mem_size >> 20);
216 printf("\n");
217
218 if (verbosity > 0 && ci.ci_iftype > 1) {
219 mlx_enquiry(&enq);
220
221 printf(" Hardware ID\t\t\t0x%08x\n",
222 le32toh(*(u_int32_t *)enq.me_hardware_id));
223 printf(" Firmware ID\t\t\t0x%08x\n",
224 le32toh(*(u_int32_t *)enq.me_firmware_id));
225 printf(" Configured/Actual channels\t%d/%d\n",
226 enq.me_configured_channels, enq.me_actual_channels);
227 printf(" Max Targets\t\t\t%d\n", enq.me_max_targets);
228 printf(" Max Tags\t\t\t%d\n", enq.me_max_tags);
229 printf(" Max System Drives\t\t%d\n", enq.me_max_sys_drives);
230 printf(" Max Arms\t\t\t%d\n", enq.me_max_arms);
231 printf(" Max Spans\t\t\t%d\n", enq.me_max_spans);
232 printf(" DRAM/cache/flash/NVRAM size\t%d/%d/%d/%d\n",
233 le32toh(enq.me_mem_size), le32toh(enq.me_cache_size),
234 le32toh(enq.me_flash_size), le32toh(enq.me_nvram_size));
235 printf(" DRAM type\t\t\t%d\n", le16toh(enq.me_mem_type));
236 printf(" Clock Speed\t\t\t%dns\n",
237 le16toh(enq.me_clock_speed));
238 printf(" Hardware Speed\t\t%dns\n",
239 le16toh(enq.me_hardware_speed));
240 printf(" Max Commands\t\t\t%d\n",
241 le16toh(enq.me_max_commands));
242 printf(" Max SG Entries\t\t%d\n", le16toh(enq.me_max_sg));
243 printf(" Max DP\t\t\t%d\n", le16toh(enq.me_max_dp));
244 printf(" Max IOD\t\t\t%d\n", le16toh(enq.me_max_iod));
245 printf(" Max Comb\t\t\t%d\n", le16toh(enq.me_max_comb));
246 printf(" Latency\t\t\t%ds\n", enq.me_latency);
247 printf(" SCSI Timeout\t\t\t%ds\n", enq.me_scsi_timeout);
248 printf(" Min Free Lines\t\t%d\n",
249 le16toh(enq.me_min_freelines));
250 printf(" Rate Constant\t\t\t%d\n", enq.me_rate_const);
251 printf(" MAXBLK\t\t\t%d\n", le16toh(enq.me_maxblk));
252 printf(" Blocking Factor\t\t%d sectors\n",
253 le16toh(enq.me_blocking_factor));
254 printf(" Cache Line Size\t\t%d blocks\n",
255 le16toh(enq.me_cacheline));
256 printf(" SCSI Capability\t\t%s%dMHz, %d bit\n",
257 enq.me_scsi_cap & (1<<4) ? "differential " : "",
258 (1 << ((enq.me_scsi_cap >> 2) & 3)) * 10,
259 8 << (enq.me_scsi_cap & 0x3));
260 printf(" Firmware Build Number\t\t%d\n",
261 le16toh(enq.me_firmware_build));
262 printf(" Fault Management Type\t\t%d\n",
263 enq.me_fault_mgmt_type);
264 #if 0
265 printf(" Features\t\t\t%b\n", enq.me_firmware_features,
266 "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n");
267 #endif
268 } else if (verbosity > 0 && ci.ci_iftype == 1)
269 warnx("can't be verbose for this firmware level");
270
271 fflush(stdout);
272
273 if (ci.ci_firmware_id[0] < 3) {
274 warnx("can't display physical drives for this firmware level");
275 return (0);
276 }
277
278 /*
279 * Fetch and print physical drive data.
280 */
281 for (channel = 0; channel < enq.me_configured_channels; channel++) {
282 for (target = 0; target < enq.me_max_targets; target++)
283 if (mlx_get_device_state(channel, target, &pd) == 0 &&
284 (pd.pd_flags1 & MLX_PHYS_DRV_PRESENT) != 0)
285 mlx_print_phys_drv(&pd, channel, target, " ");
286 }
287
288 return (0);
289 }
290
291 /*
292 * Recscan for new or changed system drives.
293 */
294 int
295 cmd_rescan(char **argv)
296 {
297
298 if (ioctl(mlxfd, MLX_RESCAN_DRIVES) < 0)
299 err(EXIT_FAILURE, "rescan failed");
300 return (0);
301 }
302
303 /*
304 * Detach one or more system drives from a controller.
305 */
306 static void
307 cmd_detach0(struct mlx_disk *md)
308 {
309
310 if (ioctl(mlxfd, MLXD_DETACH, &md->hwunit) < 0)
311 warn("can't detach %s", md->name);
312 }
313
314 int
315 cmd_detach(char **argv)
316 {
317
318 mlx_disk_iterate(cmd_detach0);
319 return (0);
320 }
321
322 /*
323 * Initiate a consistency check on a system drive.
324 */
325 static void
326 cmd_check0(struct mlx_disk *md)
327 {
328 int result;
329
330 if (ioctl(mlxfd, MLXD_CHECKASYNC, &result) == 0)
331 return;
332
333 switch (result) {
334 case 0x0002:
335 warnx("one or more of the SCSI disks on which %s", md->name);
336 warnx("depends is DEAD.");
337 break;
338
339 case 0x0105:
340 warnx("drive %s is invalid, or not a drive which ", md->name);
341 warnx("can be checked.");
342 break;
343
344 case 0x0106:
345 warnx("drive rebuild or consistency check is already ");
346 warnx("in progress on this controller.");
347 break;
348
349 default:
350 err(EXIT_FAILURE, "ioctl(MLXD_CHECKASYNC)");
351 /* NOTREACHED */
352 }
353 }
354
355 int
356 cmd_check(char **argv)
357 {
358
359 if (ci.ci_firmware_id[0] < 3) {
360 warnx("action not supported by this firmware version");
361 return (1);
362 }
363
364 mlx_disk_iterate(cmd_check0);
365 return (0);
366 }
367
368 /*
369 * Initiate a physical drive rebuild.
370 */
371 int
372 cmd_rebuild(char **argv)
373 {
374 struct mlx_rebuild_request rb;
375 char *p;
376
377 if (ci.ci_firmware_id[0] < 3) {
378 warnx("action not supported by this firmware version");
379 return (1);
380 }
381
382 if (argv[0] == NULL || argv[1] != NULL)
383 usage();
384
385 rb.rr_channel = (int)strtol(*argv, &p, 0);
386 if (p[0] != ':' || p[1] == '\0')
387 usage();
388
389 rb.rr_target = (int)strtol(*argv, &p, 0);
390 if (p[0] != '\0')
391 usage();
392
393 if (ioctl(mlxfd, MLX_REBUILDASYNC, &rb) == 0)
394 return (0);
395
396 switch (rb.rr_status) {
397 case 0x0002:
398 warnx("the drive at %d:%d is already ONLINE", rb.rr_channel,
399 rb.rr_target);
400 break;
401
402 case 0x0004:
403 warnx("drive failed during rebuild");
404 break;
405
406 case 0x0105:
407 warnx("there is no drive at %d:%d", rb.rr_channel,
408 rb.rr_target);
409 break;
410
411 case 0x0106:
412 warnx("drive rebuild or consistency check is already in ");
413 warnx("progress on this controller");
414 break;
415
416 default:
417 err(EXIT_FAILURE, "ioctl(MLXD_CHECKASYNC)");
418 /* NOTREACHED */
419 }
420
421 return(0);
422 }
423