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