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