xref: /freebsd/usr.sbin/mlxcontrol/command.c (revision b6a7bef2be790d6b032b94ad8f87a73642f24018)
1b6a7bef2SMike Smith /*-
2b6a7bef2SMike Smith  * Copyright (c) 1999 Michael Smith
3b6a7bef2SMike Smith  * All rights reserved.
4b6a7bef2SMike Smith  *
5b6a7bef2SMike Smith  * Redistribution and use in source and binary forms, with or without
6b6a7bef2SMike Smith  * modification, are permitted provided that the following conditions
7b6a7bef2SMike Smith  * are met:
8b6a7bef2SMike Smith  * 1. Redistributions of source code must retain the above copyright
9b6a7bef2SMike Smith  *    notice, this list of conditions and the following disclaimer.
10b6a7bef2SMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
11b6a7bef2SMike Smith  *    notice, this list of conditions and the following disclaimer in the
12b6a7bef2SMike Smith  *    documentation and/or other materials provided with the distribution.
13b6a7bef2SMike Smith  *
14b6a7bef2SMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15b6a7bef2SMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16b6a7bef2SMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17b6a7bef2SMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18b6a7bef2SMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19b6a7bef2SMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20b6a7bef2SMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21b6a7bef2SMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22b6a7bef2SMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23b6a7bef2SMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24b6a7bef2SMike Smith  * SUCH DAMAGE.
25b6a7bef2SMike Smith  *
26b6a7bef2SMike Smith  *	$FreeBSD$
27b6a7bef2SMike Smith  */
28b6a7bef2SMike Smith 
29b6a7bef2SMike Smith #include <fcntl.h>
30b6a7bef2SMike Smith #include <paths.h>
31b6a7bef2SMike Smith #include <stdio.h>
32b6a7bef2SMike Smith #include <stdlib.h>
33b6a7bef2SMike Smith #include <string.h>
34b6a7bef2SMike Smith #include <unistd.h>
35b6a7bef2SMike Smith #include <err.h>
36b6a7bef2SMike Smith 
37b6a7bef2SMike Smith #if 0
38b6a7bef2SMike Smith #include <sys/mlxio.h>
39b6a7bef2SMike Smith #include <sys/mlxreg.h>
40b6a7bef2SMike Smith #else
41b6a7bef2SMike Smith #include "../sys/dev/mlx/mlxio.h"
42b6a7bef2SMike Smith #include "../sys/dev/mlx/mlxreg.h"
43b6a7bef2SMike Smith #endif
44b6a7bef2SMike Smith 
45b6a7bef2SMike Smith #include "mlxcontrol.h"
46b6a7bef2SMike Smith 
47b6a7bef2SMike Smith static int	cmd_status(int argc, char *argv[]);
48b6a7bef2SMike Smith static int	cmd_rescan(int argc, char *argv[]);
49b6a7bef2SMike Smith static int	cmd_detach(int argc, char *argv[]);
50b6a7bef2SMike Smith static int	cmd_check(int argc, char *argv[]);
51b6a7bef2SMike Smith static int	cmd_rebuild(int argc, char *argv[]);
52b6a7bef2SMike Smith #ifdef SUPPORT_PAUSE
53b6a7bef2SMike Smith static int	cmd_pause(int argc, char *argv[]);
54b6a7bef2SMike Smith #endif
55b6a7bef2SMike Smith static int	cmd_help(int argc, char *argv[]);
56b6a7bef2SMike Smith 
57b6a7bef2SMike Smith extern int	cmd_config(int argc, char *argv[]);
58b6a7bef2SMike Smith 
59b6a7bef2SMike Smith 
60b6a7bef2SMike Smith struct
61b6a7bef2SMike Smith {
62b6a7bef2SMike Smith     char	*cmd;
63b6a7bef2SMike Smith     int		(*func)(int argc, char *argv[]);
64b6a7bef2SMike Smith     char	*desc;
65b6a7bef2SMike Smith     char	*text;
66b6a7bef2SMike Smith } commands[] = {
67b6a7bef2SMike Smith     {"status",	cmd_status,
68b6a7bef2SMike Smith      "displays device status",
69b6a7bef2SMike Smith      "  status [-qv] [<drive>...]\n"
70b6a7bef2SMike Smith      "      Display status for <drive> or all drives if none is listed\n"
71b6a7bef2SMike Smith      "  -q    Suppress output.\n"
72b6a7bef2SMike Smith      "  -v    Display verbose information.\n"
73b6a7bef2SMike Smith      "  Returns 0 if all drives tested are online, 1 if one or more are\n"
74b6a7bef2SMike Smith      "  critical, and 2 if one or more are offline."},
75b6a7bef2SMike Smith     {"rescan",	cmd_rescan,
76b6a7bef2SMike Smith      "scan for new system drives",
77b6a7bef2SMike Smith      "  rescan <controller> [<controller>...]\n"
78b6a7bef2SMike Smith      "      Rescan <controller> for system drives.\n"
79b6a7bef2SMike Smith      "  rescan -a\n"
80b6a7bef2SMike Smith      "      Rescan all controllers for system drives."},
81b6a7bef2SMike Smith     {"detach",	cmd_detach,
82b6a7bef2SMike Smith      "detach system drives",
83b6a7bef2SMike Smith      "  detach <drive> [<drive>...]\n"
84b6a7bef2SMike Smith      "      Detaches <drive> from the controller.\n"
85b6a7bef2SMike Smith      "  detach -a <controller>\n"
86b6a7bef2SMike Smith      "      Detaches all drives on <controller>."},
87b6a7bef2SMike Smith     {"check",	cmd_check,
88b6a7bef2SMike Smith      "consistency-check a system drive",
89b6a7bef2SMike Smith      "  check <drive>\n"
90b6a7bef2SMike Smith      "      Requests a check and rebuild of the parity information on <drive>.\n"
91b6a7bef2SMike Smith      "      Note that each controller can only check one system drive at a time."},
92b6a7bef2SMike Smith     {"rebuild",	cmd_rebuild,
93b6a7bef2SMike Smith      "initiate a rebuild of a dead physical drive",
94b6a7bef2SMike Smith      "  rebuild <controller> <physdrive>\n"
95b6a7bef2SMike Smith      "      All system drives using space on the physical drive <physdrive>\n"
96b6a7bef2SMike Smith      "      are rebuilt, reconstructing all data on the drive.\n"
97b6a7bef2SMike Smith      "      Note that each controller can only perform one rebuild at a time."},
98b6a7bef2SMike Smith #ifdef SUPPORT_PAUSE
99b6a7bef2SMike Smith     {"pause",	cmd_pause,
100b6a7bef2SMike Smith      "pauses controller channels",
101b6a7bef2SMike Smith      "  pause [-t <howlong>] [-d <delay>] <controller> [<channel>...]\n"
102b6a7bef2SMike Smith      "      Pauses SCSI I/O on <channel> and <controller>.  If no channel is specified,\n"
103b6a7bef2SMike Smith      "      all channels are paused.\n"
104b6a7bef2SMike Smith      "  <howlong>   How long (seconds) to pause for (default 30).\n"
105b6a7bef2SMike Smith      "  <delay>     How long (seconds) to wait before pausing (default 30).\n"
106b6a7bef2SMike Smith      "  pause <controller> -c\n"
107b6a7bef2SMike Smith      "      Cancels any pending pause operation on <controller>."},
108b6a7bef2SMike Smith #endif
109b6a7bef2SMike Smith     {"config",	cmd_config,
110b6a7bef2SMike Smith      "examine and update controller configuration",
111b6a7bef2SMike Smith      "  config <controller>\n"
112b6a7bef2SMike Smith      "      Print configuration for <controller>."},
113b6a7bef2SMike Smith     {"help",	cmd_help,
114b6a7bef2SMike Smith      "give help on usage",
115b6a7bef2SMike Smith      ""},
116b6a7bef2SMike Smith     {NULL, NULL, NULL, NULL}
117b6a7bef2SMike Smith };
118b6a7bef2SMike Smith 
119b6a7bef2SMike Smith /********************************************************************************
120b6a7bef2SMike Smith  * Command dispatch and global options parsing.
121b6a7bef2SMike Smith  */
122b6a7bef2SMike Smith 
123b6a7bef2SMike Smith int
124b6a7bef2SMike Smith main(int argc, char *argv[])
125b6a7bef2SMike Smith {
126b6a7bef2SMike Smith     int		ch, i, oargc;
127b6a7bef2SMike Smith     char	**oargv;
128b6a7bef2SMike Smith 
129b6a7bef2SMike Smith     oargc = argc;
130b6a7bef2SMike Smith     oargv = argv;
131b6a7bef2SMike Smith     while ((ch = getopt(argc, argv, "")) != -1)
132b6a7bef2SMike Smith 	switch(ch) {
133b6a7bef2SMike Smith 	default:
134b6a7bef2SMike Smith 	    return(cmd_help(0, NULL));
135b6a7bef2SMike Smith 	}
136b6a7bef2SMike Smith 
137b6a7bef2SMike Smith     argc -= optind;
138b6a7bef2SMike Smith     argv += optind;
139b6a7bef2SMike Smith 
140b6a7bef2SMike Smith     if (argc > 0)
141b6a7bef2SMike Smith 	for (i = 0; commands[i].cmd != NULL; i++)
142b6a7bef2SMike Smith 	    if (!strcmp(argv[0], commands[i].cmd))
143b6a7bef2SMike Smith 		return(commands[i].func(argc, argv));
144b6a7bef2SMike Smith 
145b6a7bef2SMike Smith     return(cmd_help(oargc, oargv));
146b6a7bef2SMike Smith }
147b6a7bef2SMike Smith 
148b6a7bef2SMike Smith /********************************************************************************
149b6a7bef2SMike Smith  * Helptext output
150b6a7bef2SMike Smith  */
151b6a7bef2SMike Smith static int
152b6a7bef2SMike Smith cmd_help(int argc, char *argv[])
153b6a7bef2SMike Smith {
154b6a7bef2SMike Smith     int		i;
155b6a7bef2SMike Smith 
156b6a7bef2SMike Smith     if (argc > 1)
157b6a7bef2SMike Smith 	for (i = 0; commands[i].cmd != NULL; i++)
158b6a7bef2SMike Smith 	    if (!strcmp(argv[1], commands[i].cmd)) {
159b6a7bef2SMike Smith 		fprintf(stderr, "%s\n", commands[i].text);
160b6a7bef2SMike Smith 		fflush(stderr);
161b6a7bef2SMike Smith 		return(0);
162b6a7bef2SMike Smith 	    }
163b6a7bef2SMike Smith 
164b6a7bef2SMike Smith     if (argv != NULL)
165b6a7bef2SMike Smith 	fprintf(stderr, "Unknown command '%s'.\n", argv[1]);
166b6a7bef2SMike Smith     fprintf(stderr, "Valid commands are:\n");
167b6a7bef2SMike Smith     for (i = 0; commands[i].cmd != NULL; i++)
168b6a7bef2SMike Smith 	fprintf(stderr, "  %-20s %s\n", commands[i].cmd, commands[i].desc);
169b6a7bef2SMike Smith     fflush(stderr);
170b6a7bef2SMike Smith     return(0);
171b6a7bef2SMike Smith }
172b6a7bef2SMike Smith 
173b6a7bef2SMike Smith /********************************************************************************
174b6a7bef2SMike Smith  * Status output
175b6a7bef2SMike Smith  *
176b6a7bef2SMike Smith  * status [-qv] [<device> ...]
177b6a7bef2SMike Smith  *		Prints status for <device>, or all if none listed.
178b6a7bef2SMike Smith  *
179b6a7bef2SMike Smith  * -q	Suppresses output, command returns 0 if devices are OK, 1 if one or
180b6a7bef2SMike Smith  *	more devices are critical, 2 if one or more devices are offline.
181b6a7bef2SMike Smith  */
182b6a7bef2SMike Smith static struct mlx_rebuild_status	rs;
183b6a7bef2SMike Smith static int				rs_ctrlr = -1;
184b6a7bef2SMike Smith static int				status_result = 0;
185b6a7bef2SMike Smith 
186b6a7bef2SMike Smith /* XXX more verbosity! */
187b6a7bef2SMike Smith static void
188b6a7bef2SMike Smith status_print(int unit, void *arg)
189b6a7bef2SMike Smith {
190b6a7bef2SMike Smith     int				verbosity = *(int *)arg;
191b6a7bef2SMike Smith     int				fd, result, ctrlr, sysdrive, statvalid;
192b6a7bef2SMike Smith 
193b6a7bef2SMike Smith     /* Find which controller and what system drive we are */
194b6a7bef2SMike Smith     statvalid = 0;
195b6a7bef2SMike Smith     if (mlxd_find_ctrlr(unit, &ctrlr, &sysdrive)) {
196b6a7bef2SMike Smith 	warnx("couldn't get controller/drive for %s", drivepath(unit));
197b6a7bef2SMike Smith     } else {
198b6a7bef2SMike Smith 	/* If we don't have rebuild stats for this controller, get them */
199b6a7bef2SMike Smith 	if (rs_ctrlr == ctrlr) {
200b6a7bef2SMike Smith 	    statvalid = 1;
201b6a7bef2SMike Smith 	} else {
202b6a7bef2SMike Smith 	    if ((fd = open(ctrlrpath(ctrlr), 0)) < 0) {
203b6a7bef2SMike Smith 		warn("can't open %s", ctrlrpath(ctrlr));
204b6a7bef2SMike Smith 	    } else {
205b6a7bef2SMike Smith 		if (ioctl(fd, MLX_REBUILDSTAT, &rs) < 0) {
206b6a7bef2SMike Smith 		    warn("ioctl MLX_REBUILDSTAT");
207b6a7bef2SMike Smith 		} else {
208b6a7bef2SMike Smith 		    rs_ctrlr = ctrlr;
209b6a7bef2SMike Smith 		    statvalid = 1;
210b6a7bef2SMike Smith 		}
211b6a7bef2SMike Smith 		close(fd);
212b6a7bef2SMike Smith 	    }
213b6a7bef2SMike Smith 	}
214b6a7bef2SMike Smith     }
215b6a7bef2SMike Smith 
216b6a7bef2SMike Smith     /* Get the device */
217b6a7bef2SMike Smith     if ((fd = open(drivepath(unit), 0)) < 0) {
218b6a7bef2SMike Smith 	warn("can't open %s", drivepath(unit));
219b6a7bef2SMike Smith 	return;
220b6a7bef2SMike Smith     }
221b6a7bef2SMike Smith 
222b6a7bef2SMike Smith     /* Get its status */
223b6a7bef2SMike Smith     if (ioctl(fd, MLXD_STATUS, &result) < 0) {
224b6a7bef2SMike Smith 	warn("ioctl MLXD_STATUS");
225b6a7bef2SMike Smith     } else {
226b6a7bef2SMike Smith 	switch(result) {
227b6a7bef2SMike Smith 	case MLX_SYSD_ONLINE:
228b6a7bef2SMike Smith 	    if (verbosity > 0)
229b6a7bef2SMike Smith 		printf("%s: online", drivename(unit));
230b6a7bef2SMike Smith 	    break;
231b6a7bef2SMike Smith 	case MLX_SYSD_CRITICAL:
232b6a7bef2SMike Smith 	    if (verbosity > 0)
233b6a7bef2SMike Smith 		printf("%s: critical", drivename(unit));
234b6a7bef2SMike Smith 	    if (status_result < 1)
235b6a7bef2SMike Smith 		status_result = 1;
236b6a7bef2SMike Smith 	    break;
237b6a7bef2SMike Smith 	case MLX_SYSD_OFFLINE:
238b6a7bef2SMike Smith 	    if (verbosity > 0)
239b6a7bef2SMike Smith 		printf("%s: offline", drivename(unit));
240b6a7bef2SMike Smith 	    if (status_result < 2)
241b6a7bef2SMike Smith 		status_result = 2;
242b6a7bef2SMike Smith 	    break;
243b6a7bef2SMike Smith 	default:
244b6a7bef2SMike Smith 	    if (verbosity > 0) {
245b6a7bef2SMike Smith 		printf("%s: unknown status 0x%x", drivename(unit), result);
246b6a7bef2SMike Smith 	    }
247b6a7bef2SMike Smith 	}
248b6a7bef2SMike Smith 	if (verbosity > 0) {
249b6a7bef2SMike Smith 	    /* rebuild/check in progress on this drive? */
250b6a7bef2SMike Smith 	    if (statvalid && (rs_ctrlr == ctrlr) &&
251b6a7bef2SMike Smith 		(rs.rs_drive == sysdrive) && (rs.rs_code != MLX_REBUILDSTAT_IDLE)) {
252b6a7bef2SMike Smith 		switch(rs.rs_code) {
253b6a7bef2SMike Smith 		case MLX_REBUILDSTAT_REBUILDCHECK:
254b6a7bef2SMike Smith 		    printf(" [consistency check");
255b6a7bef2SMike Smith 		    break;
256b6a7bef2SMike Smith 		case MLX_REBUILDSTAT_ADDCAPACITY:
257b6a7bef2SMike Smith 		    printf(" [add capacity");
258b6a7bef2SMike Smith 		    break;
259b6a7bef2SMike Smith 		case MLX_REBUILDSTAT_ADDCAPACITYINIT:
260b6a7bef2SMike Smith 		    printf(" [add capacity init");
261b6a7bef2SMike Smith 		    break;
262b6a7bef2SMike Smith 		default:
263b6a7bef2SMike Smith 		    printf(" [unknown operation");
264b6a7bef2SMike Smith 		}
265b6a7bef2SMike Smith 		printf(": %d/%d, %d%% complete]",
266b6a7bef2SMike Smith 		       rs.rs_remaining, rs.rs_size,
267b6a7bef2SMike Smith 		       ((rs.rs_size - rs.rs_remaining) / (rs.rs_size / 100)));
268b6a7bef2SMike Smith 	    }
269b6a7bef2SMike Smith 	    printf("\n");
270b6a7bef2SMike Smith 	}
271b6a7bef2SMike Smith     }
272b6a7bef2SMike Smith     close(fd);
273b6a7bef2SMike Smith }
274b6a7bef2SMike Smith 
275b6a7bef2SMike Smith static struct
276b6a7bef2SMike Smith {
277b6a7bef2SMike Smith     int		hwid;
278b6a7bef2SMike Smith     char	*name;
279b6a7bef2SMike Smith } mlx_controller_names[] = {
280b6a7bef2SMike Smith     {0x01,	"960P/PD"},
281b6a7bef2SMike Smith     {0x02,	"960PL"},
282b6a7bef2SMike Smith     {0x10,	"960PG"},
283b6a7bef2SMike Smith     {0x11,	"960PJ"},
284b6a7bef2SMike Smith     {0x12,	"960PR"},
285b6a7bef2SMike Smith     {0x13,	"960PT"},
286b6a7bef2SMike Smith     {0x14,	"960PTL0"},
287b6a7bef2SMike Smith     {0x15,	"960PRL"},
288b6a7bef2SMike Smith     {0x16,	"960PTL1"},
289b6a7bef2SMike Smith     {0x20,	"1100PVX"},
290b6a7bef2SMike Smith     {-1, NULL}
291b6a7bef2SMike Smith };
292b6a7bef2SMike Smith 
293b6a7bef2SMike Smith static void
294b6a7bef2SMike Smith controller_print(int unit, void *arg)
295b6a7bef2SMike Smith {
296b6a7bef2SMike Smith     struct mlx_enquiry2	enq;
297b6a7bef2SMike Smith     struct mlx_phys_drv	pd;
298b6a7bef2SMike Smith     int			verbosity = *(int *)arg;
299b6a7bef2SMike Smith     static char		buf[80];
300b6a7bef2SMike Smith     char		*model;
301b6a7bef2SMike Smith     int			i, channel, target;
302b6a7bef2SMike Smith 
303b6a7bef2SMike Smith     if (verbosity == 0)
304b6a7bef2SMike Smith 	return;
305b6a7bef2SMike Smith 
306b6a7bef2SMike Smith     /* fetch and print controller data */
307b6a7bef2SMike Smith     if (mlx_enquiry(unit, &enq)) {
308b6a7bef2SMike Smith 	printf("mlx%d: error submitting ENQUIRY2\n", unit);
309b6a7bef2SMike Smith     } else {
310b6a7bef2SMike Smith 
311b6a7bef2SMike Smith 	for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) {
312b6a7bef2SMike Smith 	    if ((enq.me_hardware_id & 0xff) == mlx_controller_names[i].hwid) {
313b6a7bef2SMike Smith 		model = mlx_controller_names[i].name;
314b6a7bef2SMike Smith 		break;
315b6a7bef2SMike Smith 	    }
316b6a7bef2SMike Smith 	}
317b6a7bef2SMike Smith 	if (model == NULL) {
318b6a7bef2SMike Smith 	    sprintf(buf, " model 0x%x", enq.me_hardware_id & 0xff);
319b6a7bef2SMike Smith 	    model = buf;
320b6a7bef2SMike Smith 	}
321b6a7bef2SMike Smith 
322b6a7bef2SMike Smith 	printf("mlx%d: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n",
323b6a7bef2SMike Smith 	       unit, model,
324b6a7bef2SMike Smith 	       enq.me_actual_channels,
325b6a7bef2SMike Smith 	       enq.me_actual_channels > 1 ? "s" : "",
326b6a7bef2SMike Smith 	       enq.me_firmware_id & 0xff,
327b6a7bef2SMike Smith 	       (enq.me_firmware_id >> 8) & 0xff,
328b6a7bef2SMike Smith 	       (enq.me_firmware_id >> 16),
329b6a7bef2SMike Smith 	       (enq.me_firmware_id >> 24) & 0xff,
330b6a7bef2SMike Smith 	       enq.me_mem_size / (1024 * 1024));
331b6a7bef2SMike Smith 
332b6a7bef2SMike Smith 	if (verbosity > 1) {
333b6a7bef2SMike Smith 	    printf("  Hardware ID                 0x%08x\n", enq.me_hardware_id);
334b6a7bef2SMike Smith 	    printf("  Firmware ID                 0x%08x\n", enq.me_firmware_id);
335b6a7bef2SMike Smith 	    printf("  Configured/Actual channels  %d/%d\n", enq.me_configured_channels,
336b6a7bef2SMike Smith 		      enq.me_actual_channels);
337b6a7bef2SMike Smith 	    printf("  Max Targets                 %d\n", enq.me_max_targets);
338b6a7bef2SMike Smith 	    printf("  Max Tags                    %d\n", enq.me_max_tags);
339b6a7bef2SMike Smith 	    printf("  Max System Drives           %d\n", enq.me_max_sys_drives);
340b6a7bef2SMike Smith 	    printf("  Max Arms                    %d\n", enq.me_max_arms);
341b6a7bef2SMike Smith 	    printf("  Max Spans                   %d\n", enq.me_max_spans);
342b6a7bef2SMike Smith 	    printf("  DRAM/cache/flash/NVRAM size %d/%d/%d/%d\n", enq.me_mem_size,
343b6a7bef2SMike Smith 		      enq.me_cache_size, enq.me_flash_size, enq.me_nvram_size);
344b6a7bef2SMike Smith 	    printf("  DRAM type                   %d\n", enq.me_mem_type);
345b6a7bef2SMike Smith 	    printf("  Clock Speed                 %dns\n", enq.me_clock_speed);
346b6a7bef2SMike Smith 	    printf("  Hardware Speed              %dns\n", enq.me_hardware_speed);
347b6a7bef2SMike Smith 	    printf("  Max Commands                %d\n", enq.me_max_commands);
348b6a7bef2SMike Smith 	    printf("  Max SG Entries              %d\n", enq.me_max_sg);
349b6a7bef2SMike Smith 	    printf("  Max DP                      %d\n", enq.me_max_dp);
350b6a7bef2SMike Smith 	    printf("  Max IOD                     %d\n", enq.me_max_iod);
351b6a7bef2SMike Smith 	    printf("  Max Comb                    %d\n", enq.me_max_comb);
352b6a7bef2SMike Smith 	    printf("  Latency                     %ds\n", enq.me_latency);
353b6a7bef2SMike Smith 	    printf("  SCSI Timeout                %ds\n", enq.me_scsi_timeout);
354b6a7bef2SMike Smith 	    printf("  Min Free Lines              %d\n", enq.me_min_freelines);
355b6a7bef2SMike Smith 	    printf("  Rate Constant               %d\n", enq.me_rate_const);
356b6a7bef2SMike Smith 	    printf("  MAXBLK                      %d\n", enq.me_maxblk);
357b6a7bef2SMike Smith 	    printf("  Blocking Factor             %d sectors\n", enq.me_blocking_factor);
358b6a7bef2SMike Smith 	    printf("  Cache Line Size             %d blocks\n", enq.me_cacheline);
359b6a7bef2SMike Smith 	    printf("  SCSI Capability             %s%dMHz, %d bit\n",
360b6a7bef2SMike Smith 		      enq.me_scsi_cap & (1<<4) ? "differential " : "",
361b6a7bef2SMike Smith 		      (1 << ((enq.me_scsi_cap >> 2) & 3)) * 10,
362b6a7bef2SMike Smith 		      8 << (enq.me_scsi_cap & 0x3));
363b6a7bef2SMike Smith 	    printf("  Firmware Build Number       %d\n", enq.me_firmware_build);
364b6a7bef2SMike Smith 	    printf("  Fault Management Type       %d\n", enq.me_fault_mgmt_type);
365b6a7bef2SMike Smith #if 0
366b6a7bef2SMike Smith 	    printf("  Features                    %b\n", enq.me_firmware_features,
367b6a7bef2SMike Smith 		      "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n");
368b6a7bef2SMike Smith #endif
369b6a7bef2SMike Smith 	}
370b6a7bef2SMike Smith 
371b6a7bef2SMike Smith 	/* fetch and print physical drive data */
372b6a7bef2SMike Smith 	for (channel = 0; channel < enq.me_configured_channels; channel++) {
373b6a7bef2SMike Smith 	    for (target = 0; target < enq.me_max_targets; target++) {
374b6a7bef2SMike Smith 		if ((mlx_get_device_state(unit, channel, target, &pd) == 0) &&
375b6a7bef2SMike Smith 		    (pd.pd_flags1 & MLX_PHYS_DRV_PRESENT)) {
376b6a7bef2SMike Smith 		    mlx_print_phys_drv(&pd, channel, target, "  ", verbosity - 1);
377b6a7bef2SMike Smith 		    if (verbosity > 1) {
378b6a7bef2SMike Smith 			/* XXX print device statistics? */
379b6a7bef2SMike Smith 		    }
380b6a7bef2SMike Smith 		}
381b6a7bef2SMike Smith 	    }
382b6a7bef2SMike Smith 	}
383b6a7bef2SMike Smith     }
384b6a7bef2SMike Smith }
385b6a7bef2SMike Smith 
386b6a7bef2SMike Smith static int
387b6a7bef2SMike Smith cmd_status(int argc, char *argv[])
388b6a7bef2SMike Smith {
389b6a7bef2SMike Smith     int		ch, verbosity = 1, i, unit;
390b6a7bef2SMike Smith 
391b6a7bef2SMike Smith     optreset = 1;
392b6a7bef2SMike Smith     optind = 1;
393b6a7bef2SMike Smith     while ((ch = getopt(argc, argv, "qv")) != -1)
394b6a7bef2SMike Smith 	switch(ch) {
395b6a7bef2SMike Smith 	case 'q':
396b6a7bef2SMike Smith 	    verbosity = 0;
397b6a7bef2SMike Smith 	    break;
398b6a7bef2SMike Smith 	case 'v':
399b6a7bef2SMike Smith 	    verbosity = 2;
400b6a7bef2SMike Smith 	    break;
401b6a7bef2SMike Smith 	default:
402b6a7bef2SMike Smith 	    return(cmd_help(argc, argv));
403b6a7bef2SMike Smith 	}
404b6a7bef2SMike Smith     argc -= optind;
405b6a7bef2SMike Smith     argv += optind;
406b6a7bef2SMike Smith 
407b6a7bef2SMike Smith     if (argc < 1) {
408b6a7bef2SMike Smith 	mlx_foreach(controller_print, &verbosity);
409b6a7bef2SMike Smith 	mlxd_foreach(status_print, &verbosity);
410b6a7bef2SMike Smith     } else {
411b6a7bef2SMike Smith 	for (i = 0; i < argc; i++) {
412b6a7bef2SMike Smith 	    if ((unit = driveunit(argv[i])) == -1) {
413b6a7bef2SMike Smith 		warnx("'%s' is not a valid drive", argv[i]);
414b6a7bef2SMike Smith 	    } else {
415b6a7bef2SMike Smith 		status_print(unit, &verbosity);
416b6a7bef2SMike Smith 	    }
417b6a7bef2SMike Smith 	}
418b6a7bef2SMike Smith     }
419b6a7bef2SMike Smith     return(status_result);
420b6a7bef2SMike Smith }
421b6a7bef2SMike Smith 
422b6a7bef2SMike Smith /********************************************************************************
423b6a7bef2SMike Smith  * Recscan for system drives on one or more controllers.
424b6a7bef2SMike Smith  *
425b6a7bef2SMike Smith  * rescan <controller> [<controller>...]
426b6a7bef2SMike Smith  * rescan -a
427b6a7bef2SMike Smith  */
428b6a7bef2SMike Smith static void
429b6a7bef2SMike Smith rescan_ctrlr(int unit, void *junk)
430b6a7bef2SMike Smith {
431b6a7bef2SMike Smith     int		fd;
432b6a7bef2SMike Smith 
433b6a7bef2SMike Smith     /* Get the device */
434b6a7bef2SMike Smith     if ((fd = open(ctrlrpath(unit), 0)) < 0) {
435b6a7bef2SMike Smith 	warn("can't open %s", ctrlrpath(unit));
436b6a7bef2SMike Smith 	return;
437b6a7bef2SMike Smith     }
438b6a7bef2SMike Smith 
439b6a7bef2SMike Smith     if (ioctl(fd, MLX_RESCAN_DRIVES) < 0)
440b6a7bef2SMike Smith 	warn("can't rescan %s", ctrlrname(unit));
441b6a7bef2SMike Smith     close(fd);
442b6a7bef2SMike Smith }
443b6a7bef2SMike Smith 
444b6a7bef2SMike Smith static int
445b6a7bef2SMike Smith cmd_rescan(int argc, char *argv[])
446b6a7bef2SMike Smith {
447b6a7bef2SMike Smith     int		all = 0, i, ch, unit;
448b6a7bef2SMike Smith 
449b6a7bef2SMike Smith     optreset = 1;
450b6a7bef2SMike Smith     optind = 1;
451b6a7bef2SMike Smith     while ((ch = getopt(argc, argv, "a")) != -1)
452b6a7bef2SMike Smith 	switch(ch) {
453b6a7bef2SMike Smith 	case 'a':
454b6a7bef2SMike Smith 	    all = 1;
455b6a7bef2SMike Smith 	    break;
456b6a7bef2SMike Smith 	default:
457b6a7bef2SMike Smith 	    return(cmd_help(argc, argv));
458b6a7bef2SMike Smith 	}
459b6a7bef2SMike Smith     argc -= optind;
460b6a7bef2SMike Smith     argv += optind;
461b6a7bef2SMike Smith 
462b6a7bef2SMike Smith     if (all) {
463b6a7bef2SMike Smith 	mlx_foreach(rescan_ctrlr, NULL);
464b6a7bef2SMike Smith     } else {
465b6a7bef2SMike Smith 	for (i = 0; i < argc; i++) {
466b6a7bef2SMike Smith 	    if ((unit = ctrlrunit(argv[i])) == -1) {
467b6a7bef2SMike Smith 		warnx("'%s' is not a valid controller", argv[i]);
468b6a7bef2SMike Smith 	    } else {
469b6a7bef2SMike Smith 		rescan_ctrlr(unit, NULL);
470b6a7bef2SMike Smith 	    }
471b6a7bef2SMike Smith 	}
472b6a7bef2SMike Smith     }
473b6a7bef2SMike Smith     return(0);
474b6a7bef2SMike Smith }
475b6a7bef2SMike Smith 
476b6a7bef2SMike Smith /********************************************************************************
477b6a7bef2SMike Smith  * Detach one or more system drives from a controller.
478b6a7bef2SMike Smith  *
479b6a7bef2SMike Smith  * detach <drive> [<drive>...]
480b6a7bef2SMike Smith  *		Detach <drive>.
481b6a7bef2SMike Smith  *
482b6a7bef2SMike Smith  * detach -a <controller> [<controller>...]
483b6a7bef2SMike Smith  *		Detach all drives on <controller>.
484b6a7bef2SMike Smith  *
485b6a7bef2SMike Smith  */
486b6a7bef2SMike Smith static void
487b6a7bef2SMike Smith detach_drive(int unit, void *arg)
488b6a7bef2SMike Smith {
489b6a7bef2SMike Smith     int		fd;
490b6a7bef2SMike Smith 
491b6a7bef2SMike Smith     /* Get the device */
492b6a7bef2SMike Smith     if ((fd = open(ctrlrpath(unit), 0)) < 0) {
493b6a7bef2SMike Smith 	warn("can't open %s", ctrlrpath(unit));
494b6a7bef2SMike Smith 	return;
495b6a7bef2SMike Smith     }
496b6a7bef2SMike Smith 
497b6a7bef2SMike Smith     if (ioctl(fd, MLX_DETACH_DRIVE, &unit) < 0)
498b6a7bef2SMike Smith 	warn("can't detach %s", drivename(unit));
499b6a7bef2SMike Smith     close(fd);
500b6a7bef2SMike Smith }
501b6a7bef2SMike Smith 
502b6a7bef2SMike Smith static int
503b6a7bef2SMike Smith cmd_detach(int argc, char *argv[])
504b6a7bef2SMike Smith {
505b6a7bef2SMike Smith     struct mlxd_foreach_action	ma;
506b6a7bef2SMike Smith     int				all = 0, i, ch, unit;
507b6a7bef2SMike Smith 
508b6a7bef2SMike Smith     optreset = 1;
509b6a7bef2SMike Smith     optind = 1;
510b6a7bef2SMike Smith     while ((ch = getopt(argc, argv, "a")) != -1)
511b6a7bef2SMike Smith 	switch(ch) {
512b6a7bef2SMike Smith 	case 'a':
513b6a7bef2SMike Smith 	    all = 1;
514b6a7bef2SMike Smith 	    break;
515b6a7bef2SMike Smith 	default:
516b6a7bef2SMike Smith 	    return(cmd_help(argc, argv));
517b6a7bef2SMike Smith 	}
518b6a7bef2SMike Smith     argc -= optind;
519b6a7bef2SMike Smith     argv += optind;
520b6a7bef2SMike Smith 
521b6a7bef2SMike Smith     if (all) {
522b6a7bef2SMike Smith 	ma.func = detach_drive;
523b6a7bef2SMike Smith 	ma.arg = &unit;
524b6a7bef2SMike Smith 	for (i = 0; i < argc; i++) {
525b6a7bef2SMike Smith 	    if ((unit = ctrlrunit(argv[i])) == -1) {
526b6a7bef2SMike Smith 		warnx("'%s' is not a valid controller", argv[i]);
527b6a7bef2SMike Smith 	    } else {
528b6a7bef2SMike Smith 		mlxd_foreach_ctrlr(unit, &ma);
529b6a7bef2SMike Smith 	    }
530b6a7bef2SMike Smith 	}
531b6a7bef2SMike Smith     } else {
532b6a7bef2SMike Smith 	for (i = 0; i < argc; i++) {
533b6a7bef2SMike Smith 	    if ((unit = driveunit(argv[i])) == -1) {
534b6a7bef2SMike Smith 		warnx("'%s' is not a valid drive", argv[i]);
535b6a7bef2SMike Smith 	    } else {
536b6a7bef2SMike Smith 		/* run across all controllers to find this drive */
537b6a7bef2SMike Smith 		mlx_foreach(detach_drive, &unit);
538b6a7bef2SMike Smith 	    }
539b6a7bef2SMike Smith 	}
540b6a7bef2SMike Smith     }
541b6a7bef2SMike Smith     return(0);
542b6a7bef2SMike Smith }
543b6a7bef2SMike Smith 
544b6a7bef2SMike Smith /********************************************************************************
545b6a7bef2SMike Smith  * Initiate a consistency check on a system drive.
546b6a7bef2SMike Smith  *
547b6a7bef2SMike Smith  * check [<drive>]
548b6a7bef2SMike Smith  *	Start a check of <drive>
549b6a7bef2SMike Smith  *
550b6a7bef2SMike Smith  */
551b6a7bef2SMike Smith static int
552b6a7bef2SMike Smith cmd_check(int argc, char *argv[])
553b6a7bef2SMike Smith {
554b6a7bef2SMike Smith     int		unit, fd, result;
555b6a7bef2SMike Smith 
556b6a7bef2SMike Smith     if (argc != 2)
557b6a7bef2SMike Smith 	return(cmd_help(argc, argv));
558b6a7bef2SMike Smith 
559b6a7bef2SMike Smith     if ((unit = driveunit(argv[1])) == -1) {
560b6a7bef2SMike Smith 	warnx("'%s' is not a valid drive", argv[1]);
561b6a7bef2SMike Smith     } else {
562b6a7bef2SMike Smith 
563b6a7bef2SMike Smith 	/* Get the device */
564b6a7bef2SMike Smith 	if ((fd = open(drivepath(unit), 0)) < 0) {
565b6a7bef2SMike Smith 	    warn("can't open %s", drivepath(unit));
566b6a7bef2SMike Smith 	} else {
567b6a7bef2SMike Smith 	    /* Try to start the check */
568b6a7bef2SMike Smith 	    if ((ioctl(fd, MLXD_CHECKASYNC, &result)) < 0) {
569b6a7bef2SMike Smith 		switch(result) {
570b6a7bef2SMike Smith 		case 0x0002:
571b6a7bef2SMike Smith 		    warnx("one or more of the SCSI disks on which the drive '%s' depends is DEAD", argv[1]);
572b6a7bef2SMike Smith 		    break;
573b6a7bef2SMike Smith 		case 0x0105:
574b6a7bef2SMike Smith 		    warnx("drive %s is invalid, or not a drive which can be checked", argv[1]);
575b6a7bef2SMike Smith 		    break;
576b6a7bef2SMike Smith 		case 0x0106:
577b6a7bef2SMike Smith 		    warnx("drive rebuild or consistency check is already in progress on this controller");
578b6a7bef2SMike Smith 		    break;
579b6a7bef2SMike Smith 		default:
580b6a7bef2SMike Smith 		    warn("ioctl MLXD_CHECKASYNC");
581b6a7bef2SMike Smith 		}
582b6a7bef2SMike Smith 	    }
583b6a7bef2SMike Smith 	}
584b6a7bef2SMike Smith     }
585b6a7bef2SMike Smith     return(0);
586b6a7bef2SMike Smith }
587b6a7bef2SMike Smith 
588b6a7bef2SMike Smith /********************************************************************************
589b6a7bef2SMike Smith  * Initiate a physical drive rebuild
590b6a7bef2SMike Smith  *
591b6a7bef2SMike Smith  * rebuild <controller> <channel>:<target>
592b6a7bef2SMike Smith  *	Start a rebuild of <controller>:<channel>:<target>
593b6a7bef2SMike Smith  *
594b6a7bef2SMike Smith  */
595b6a7bef2SMike Smith static int
596b6a7bef2SMike Smith cmd_rebuild(int argc, char *argv[])
597b6a7bef2SMike Smith {
598b6a7bef2SMike Smith     struct mlx_rebuild_request	rb;
599b6a7bef2SMike Smith     int				unit, fd;
600b6a7bef2SMike Smith 
601b6a7bef2SMike Smith     if (argc != 3)
602b6a7bef2SMike Smith 	return(cmd_help(argc, argv));
603b6a7bef2SMike Smith 
604b6a7bef2SMike Smith     /* parse arguments */
605b6a7bef2SMike Smith     if ((unit = ctrlrunit(argv[1])) == -1) {
606b6a7bef2SMike Smith 	warnx("'%s' is not a valid controller", argv[1]);
607b6a7bef2SMike Smith 	return(1);
608b6a7bef2SMike Smith     }
609b6a7bef2SMike Smith     /* try diskXXXX and unknownXXXX as we report the latter for a dead drive ... */
610b6a7bef2SMike Smith     if ((sscanf(argv[2], "disk%2d%2d", &rb.rr_channel, &rb.rr_target) != 2) &&
611b6a7bef2SMike Smith 	(sscanf(argv[2], "unknown%2d%2d", &rb.rr_channel, &rb.rr_target) != 2)) {
612b6a7bef2SMike Smith 	warnx("'%s' is not a valid physical drive", argv[2]);
613b6a7bef2SMike Smith 	return(1);
614b6a7bef2SMike Smith     }
615b6a7bef2SMike Smith     /* get the device */
616b6a7bef2SMike Smith     if ((fd = open(ctrlrpath(unit), 0)) < 0) {
617b6a7bef2SMike Smith 	warn("can't open %s", ctrlrpath(unit));
618b6a7bef2SMike Smith 	return(1);
619b6a7bef2SMike Smith     }
620b6a7bef2SMike Smith     /* try to start the rebuild */
621b6a7bef2SMike Smith     if ((ioctl(fd, MLX_REBUILDASYNC, &rb)) < 0) {
622b6a7bef2SMike Smith 	switch(rb.rr_status) {
623b6a7bef2SMike Smith 	case 0x0002:
624b6a7bef2SMike Smith 	    warnx("the drive at %d:%d is already ONLINE", rb.rr_channel, rb.rr_target);
625b6a7bef2SMike Smith 	    break;
626b6a7bef2SMike Smith 	case 0x0004:
627b6a7bef2SMike Smith 	    warnx("drive failed during rebuild");
628b6a7bef2SMike Smith 	    break;
629b6a7bef2SMike Smith 	case 0x0105:
630b6a7bef2SMike Smith 	    warnx("there is no drive at channel %d, target %d", rb.rr_channel, rb.rr_target);
631b6a7bef2SMike Smith 	    break;
632b6a7bef2SMike Smith 	case 0x0106:
633b6a7bef2SMike Smith 	    warnx("drive rebuild or consistency check is already in progress on this controller");
634b6a7bef2SMike Smith 	    break;
635b6a7bef2SMike Smith 	default:
636b6a7bef2SMike Smith 	    warn("ioctl MLXD_CHECKASYNC");
637b6a7bef2SMike Smith 	}
638b6a7bef2SMike Smith     }
639b6a7bef2SMike Smith     return(0);
640b6a7bef2SMike Smith }
641b6a7bef2SMike Smith 
642b6a7bef2SMike Smith #ifdef SUPPORT_PAUSE
643b6a7bef2SMike Smith /********************************************************************************
644b6a7bef2SMike Smith  * Pause one or more channels on a controller
645b6a7bef2SMike Smith  *
646b6a7bef2SMike Smith  * pause [-d <delay>] [-t <time>] <controller> [<channel>...]
647b6a7bef2SMike Smith  *		Pauses <channel> (or all channels) for <time> seconds after a
648b6a7bef2SMike Smith  *		delay of <delay> seconds.
649b6a7bef2SMike Smith  * pause <controller> -c
650b6a7bef2SMike Smith  *		Cancels pending pause
651b6a7bef2SMike Smith  */
652b6a7bef2SMike Smith static int
653b6a7bef2SMike Smith cmd_pause(int argc, char *argv[])
654b6a7bef2SMike Smith {
655b6a7bef2SMike Smith     struct mlx_pause	mp;
656b6a7bef2SMike Smith     int			unit, i, ch, fd, cancel = 0;
657b6a7bef2SMike Smith     char		*cp;
658b6a7bef2SMike Smith     int			oargc = argc;
659b6a7bef2SMike Smith     char		**oargv = argv;
660b6a7bef2SMike Smith 
661b6a7bef2SMike Smith     mp.mp_which = 0;
662b6a7bef2SMike Smith     mp.mp_when = 30;
663b6a7bef2SMike Smith     mp.mp_howlong = 30;
664b6a7bef2SMike Smith     optreset = 1;
665b6a7bef2SMike Smith     optind = 1;
666b6a7bef2SMike Smith     while ((ch = getopt(argc, argv, "cd:t:")) != -1)
667b6a7bef2SMike Smith 	switch(ch) {
668b6a7bef2SMike Smith 	case 'c':
669b6a7bef2SMike Smith 	    cancel = 1;
670b6a7bef2SMike Smith 	    break;
671b6a7bef2SMike Smith 	case 'd':
672b6a7bef2SMike Smith 	    mp.mp_when = strtol(optarg, &cp, 0);
673b6a7bef2SMike Smith 	    if (*cp != 0)
674b6a7bef2SMike Smith 		return(cmd_help(argc, argv));
675b6a7bef2SMike Smith 	    break;
676b6a7bef2SMike Smith 	case 't':
677b6a7bef2SMike Smith 	    mp.mp_howlong = strtol(optarg, &cp, 0);
678b6a7bef2SMike Smith 	    if (*cp != 0)
679b6a7bef2SMike Smith 		return(cmd_help(argc, argv));
680b6a7bef2SMike Smith 	    break;
681b6a7bef2SMike Smith 	default:
682b6a7bef2SMike Smith 	    return(cmd_help(argc, argv));
683b6a7bef2SMike Smith 	}
684b6a7bef2SMike Smith     argc -= optind;
685b6a7bef2SMike Smith     argv += optind;
686b6a7bef2SMike Smith 
687b6a7bef2SMike Smith     /* get controller unit number that we're working on */
688b6a7bef2SMike Smith     if ((argc < 1) || ((unit = ctrlrunit(argv[0])) == -1))
689b6a7bef2SMike Smith 	return(cmd_help(oargc, oargv));
690b6a7bef2SMike Smith 
691b6a7bef2SMike Smith     /* Get the device */
692b6a7bef2SMike Smith     if ((fd = open(ctrlrpath(unit), 0)) < 0) {
693b6a7bef2SMike Smith 	warn("can't open %s", ctrlrpath(unit));
694b6a7bef2SMike Smith 	return(1);
695b6a7bef2SMike Smith     }
696b6a7bef2SMike Smith 
697b6a7bef2SMike Smith     if (argc == 1) {
698b6a7bef2SMike Smith 	/* controller-wide pause/cancel */
699b6a7bef2SMike Smith 	mp.mp_which = cancel ? MLX_PAUSE_CANCEL : MLX_PAUSE_ALL;
700b6a7bef2SMike Smith     } else {
701b6a7bef2SMike Smith 	for (i = 1; i < argc; i++) {
702b6a7bef2SMike Smith 	    ch = strtol(argv[i], &cp, 0);
703b6a7bef2SMike Smith 	    if (*cp != 0) {
704b6a7bef2SMike Smith 		warnx("bad channel number '%s'", argv[i]);
705b6a7bef2SMike Smith 		continue;
706b6a7bef2SMike Smith 	    } else {
707b6a7bef2SMike Smith 		mp.mp_which |= (1 << ch);
708b6a7bef2SMike Smith 	    }
709b6a7bef2SMike Smith 	}
710b6a7bef2SMike Smith     }
711b6a7bef2SMike Smith     if ((ioctl(fd, MLX_PAUSE_CHANNEL, &mp)) < 0)
712b6a7bef2SMike Smith 	warn("couldn't %s %s", cancel ? "cancel pause on" : "pause", ctrlrname(unit));
713b6a7bef2SMike Smith     close(fd);
714b6a7bef2SMike Smith     return(0);
715b6a7bef2SMike Smith }
716b6a7bef2SMike Smith #endif	/* SUPPORT_PAUSE */
717b6a7bef2SMike Smith 
718