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