1/*	$NetBSD: cmds.c,v 1.12 2009/04/17 04:03:39 lukem Exp $	*/
2
3/*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*-
33 * Copyright (c) 1999 Michael Smith
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 * from FreeBSD: command.c,v 1.2 2000/04/11 23:04:17 msmith Exp
58 */
59
60#ifndef lint
61#include <sys/cdefs.h>
62__RCSID("$NetBSD: cmds.c,v 1.12 2009/04/17 04:03:39 lukem Exp $");
63#endif /* not lint */
64
65#include <sys/types.h>
66#include <sys/ioctl.h>
67#include <sys/queue.h>
68#include <sys/endian.h>
69
70#include <dev/ic/mlxreg.h>
71#include <dev/ic/mlxio.h>
72
73#include <err.h>
74#include <fcntl.h>
75#include <stdio.h>
76#include <stdlib.h>
77#include <string.h>
78#include <unistd.h>
79
80#include "extern.h"
81
82static void	cmd_status0(struct mlx_disk *);
83static void	cmd_check0(struct mlx_disk *);
84static void	cmd_detach0(struct mlx_disk *);
85
86static struct	mlx_rebuild_status rs;
87static int	rstatus;
88
89static struct {
90	int	hwid;
91	const char	*name;
92} const mlx_ctlr_names[] = {
93	{ 0x00, "960E/960M" },
94	{ 0x01,	"960P/PD" },
95	{ 0x02,	"960PL" },
96	{ 0x10,	"960PG" },
97	{ 0x11,	"960PJ" },
98	{ 0x12,	"960PR" },
99	{ 0x13,	"960PT" },
100	{ 0x14,	"960PTL0" },
101	{ 0x15,	"960PRL" } ,
102	{ 0x16,	"960PTL1" },
103	{ 0x20,	"1100PVX" },
104	{ -1,	NULL },
105};
106
107/*
108 * Status output
109 */
110static void
111cmd_status0(struct mlx_disk *md)
112{
113	int result;
114
115	result = md->hwunit;
116	if (ioctl(mlxfd, MLXD_STATUS, &result) < 0)
117		err(EXIT_FAILURE, "ioctl(MLXD_STATUS)");
118
119	switch(result) {
120	case MLX_SYSD_ONLINE:
121		printf("%s: online\n", md->name);
122		break;
123
124	case MLX_SYSD_CRITICAL:
125		printf("%s: critical\n", md->name);
126		if (!rstatus)
127			rstatus = 1;
128		break;
129
130	case MLX_SYSD_OFFLINE:
131		printf("%s: offline\n", md->name);
132		rstatus = 2;
133		break;
134
135	default:
136		printf("%s: unknown status 0x%02x\n", md->name, result);
137		break;
138	}
139
140	/* Rebuild/check in progress on this drive? */
141	if (rs.rs_drive == md->hwunit &&
142	    rs.rs_code != MLX_REBUILDSTAT_IDLE) {
143		switch(rs.rs_code) {
144		case MLX_REBUILDSTAT_REBUILDCHECK:
145			printf(" [consistency check");
146			break;
147
148		case MLX_REBUILDSTAT_ADDCAPACITY:
149			printf(" [add capacity");
150			break;
151
152		case MLX_REBUILDSTAT_ADDCAPACITYINIT:
153			printf(" [add capacity init");
154			break;
155
156		default:
157			printf(" [unknown operation");
158			break;
159		}
160
161		printf(": %d/%d, %d%% complete]\n", rs.rs_remaining, rs.rs_size,
162		   ((rs.rs_size - rs.rs_remaining) / (rs.rs_size / 100)));
163	}
164}
165
166int
167cmd_status(char **argv)
168{
169
170	if (ioctl(mlxfd, MLX_REBUILDSTAT, &rs) < 0)
171		err(EXIT_FAILURE, "ioctl(MLX_REBUILDSTAT)");
172
173	mlx_disk_iterate(cmd_status0);
174	return (rstatus);
175}
176
177/*
178 * Display controller status.
179 */
180int
181cmd_cstatus(char **argv)
182{
183	struct mlx_enquiry2 enq;
184	struct mlx_phys_drv pd;
185	static char buf[80];
186	const char *model;
187	int channel, target;
188	size_t i;
189
190	model = NULL;	/* XXXGCC -Wuninitialized */
191
192	for (i = 0; i < sizeof(mlx_ctlr_names) / sizeof(mlx_ctlr_names[0]); i++)
193		if (ci.ci_hardware_id == mlx_ctlr_names[i].hwid) {
194			model = mlx_ctlr_names[i].name;
195			break;
196		}
197
198	if (i == sizeof(mlx_ctlr_names) / sizeof(mlx_ctlr_names[0])) {
199		snprintf(buf, sizeof(buf), " model 0x%x", ci.ci_hardware_id);
200		model = buf;
201	}
202
203	printf("DAC%s, %d channel%s, firmware %d.%02d-%c-%02d",
204	    model, ci.ci_nchan,
205	    ci.ci_nchan > 1 ? "s" : "",
206	    ci.ci_firmware_id[0], ci.ci_firmware_id[1],
207	    ci.ci_firmware_id[3], ci.ci_firmware_id[2]);
208	if (ci.ci_mem_size != 0)
209		printf(", %dMB RAM", ci.ci_mem_size >> 20);
210	printf("\n");
211
212	if (verbosity > 0 && ci.ci_iftype > 1) {
213		uint32_t hid, sid;
214
215		mlx_enquiry(&enq);
216		memcpy(&hid, enq.me_hardware_id, sizeof(hid));
217		memcpy(&sid, enq.me_firmware_id, sizeof(sid));
218
219		printf("  Hardware ID\t\t\t0x%08x\n", le32toh(hid));
220		printf("  Firmware ID\t\t\t0x%08x\n", le32toh(sid));
221		printf("  Configured/Actual channels\t%d/%d\n",
222		    enq.me_configured_channels, enq.me_actual_channels);
223		printf("  Max Targets\t\t\t%d\n", enq.me_max_targets);
224		printf("  Max Tags\t\t\t%d\n", enq.me_max_tags);
225		printf("  Max System Drives\t\t%d\n", enq.me_max_sys_drives);
226		printf("  Max Arms\t\t\t%d\n", enq.me_max_arms);
227		printf("  Max Spans\t\t\t%d\n", enq.me_max_spans);
228		printf("  DRAM/cache/flash/NVRAM size\t%d/%d/%d/%d\n",
229		    le32toh(enq.me_mem_size), le32toh(enq.me_cache_size),
230		    le32toh(enq.me_flash_size), le32toh(enq.me_nvram_size));
231		printf("  DRAM type\t\t\t%d\n", le16toh(enq.me_mem_type));
232		printf("  Clock Speed\t\t\t%dns\n",
233		    le16toh(enq.me_clock_speed));
234		printf("  Hardware Speed\t\t%dns\n",
235		    le16toh(enq.me_hardware_speed));
236		printf("  Max Commands\t\t\t%d\n",
237		    le16toh(enq.me_max_commands));
238		printf("  Max SG Entries\t\t%d\n", le16toh(enq.me_max_sg));
239		printf("  Max DP\t\t\t%d\n", le16toh(enq.me_max_dp));
240		printf("  Max IOD\t\t\t%d\n", le16toh(enq.me_max_iod));
241		printf("  Max Comb\t\t\t%d\n", le16toh(enq.me_max_comb));
242		printf("  Latency\t\t\t%ds\n", enq.me_latency);
243		printf("  SCSI Timeout\t\t\t%ds\n", enq.me_scsi_timeout);
244		printf("  Min Free Lines\t\t%d\n",
245		    le16toh(enq.me_min_freelines));
246		printf("  Rate Constant\t\t\t%d\n", enq.me_rate_const);
247		printf("  MAXBLK\t\t\t%d\n", le16toh(enq.me_maxblk));
248		printf("  Blocking Factor\t\t%d sectors\n",
249		    le16toh(enq.me_blocking_factor));
250		printf("  Cache Line Size\t\t%d blocks\n",
251		    le16toh(enq.me_cacheline));
252		printf("  SCSI Capability\t\t%s%dMHz, %d bit\n",
253		      enq.me_scsi_cap & (1<<4) ? "differential " : "",
254		      (1 << ((enq.me_scsi_cap >> 2) & 3)) * 10,
255		      8 << (enq.me_scsi_cap & 0x3));
256		printf("  Firmware Build Number\t\t%d\n",
257		    le16toh(enq.me_firmware_build));
258		printf("  Fault Management Type\t\t%d\n",
259		    enq.me_fault_mgmt_type);
260#if 0
261		printf("  Features\t\t\t%b\n", enq.me_firmware_features,
262		      "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n");
263#endif
264	} else if (verbosity > 0 && ci.ci_iftype == 1)
265		warnx("can't be verbose for this firmware level");
266
267	fflush(stdout);
268
269	if (ci.ci_firmware_id[0] < 3) {
270		warnx("can't display physical drives for this firmware level");
271		return (0);
272	}
273
274	/*
275	 * Fetch and print physical drive data.
276	 */
277	for (channel = 0; channel < enq.me_configured_channels; channel++) {
278		for (target = 0; target < enq.me_max_targets; target++)
279			if (mlx_get_device_state(channel, target, &pd) == 0 &&
280			    (pd.pd_flags1 & MLX_PHYS_DRV_PRESENT) != 0)
281				mlx_print_phys_drv(&pd, channel, target, "  ");
282	}
283
284	return (0);
285}
286
287/*
288 * Recscan for new or changed system drives.
289 */
290int
291cmd_rescan(char **argv)
292{
293
294	if (ioctl(mlxfd, MLX_RESCAN_DRIVES) < 0)
295		err(EXIT_FAILURE, "rescan failed");
296	return (0);
297}
298
299/*
300 * Detach one or more system drives from a controller.
301 */
302static void
303cmd_detach0(struct mlx_disk *md)
304{
305
306	if (ioctl(mlxfd, MLXD_DETACH, &md->hwunit) < 0)
307		warn("can't detach %s", md->name);
308}
309
310int
311cmd_detach(char **argv)
312{
313
314	mlx_disk_iterate(cmd_detach0);
315	return (0);
316}
317
318/*
319 * Initiate a consistency check on a system drive.
320 */
321static void
322cmd_check0(struct mlx_disk *md)
323{
324	int result;
325
326	if (ioctl(mlxfd, MLXD_CHECKASYNC, &result) == 0)
327		return;
328
329	switch (result) {
330	case 0x0002:
331		warnx("one or more of the SCSI disks on which %s", md->name);
332		warnx("depends is DEAD.");
333		break;
334
335	case 0x0105:
336		warnx("drive %s is invalid, or not a drive which ", md->name);
337		warnx("can be checked.");
338		break;
339
340	case 0x0106:
341		warnx("drive rebuild or consistency check is already ");
342		warnx("in progress on this controller.");
343		break;
344
345	default:
346		err(EXIT_FAILURE, "ioctl(MLXD_CHECKASYNC)");
347		/* NOTREACHED */
348	}
349}
350
351int
352cmd_check(char **argv)
353{
354
355	if (ci.ci_firmware_id[0] < 3) {
356		warnx("action not supported by this firmware version");
357		return (1);
358	}
359
360	mlx_disk_iterate(cmd_check0);
361	return (0);
362}
363
364/*
365 * Initiate a physical drive rebuild.
366 */
367int
368cmd_rebuild(char **argv)
369{
370	struct mlx_rebuild_request rb;
371	char *p;
372
373	if (ci.ci_firmware_id[0] < 3) {
374		warnx("action not supported by this firmware version");
375		return (1);
376	}
377
378	if (argv[0] == NULL || argv[1] != NULL)
379		usage();
380
381	rb.rr_channel = (int)strtol(*argv, &p, 0);
382	if (p[0] != ':' || p[1] == '\0')
383		usage();
384
385	rb.rr_target = (int)strtol(*argv, &p, 0);
386	if (p[0] != '\0')
387		usage();
388
389	if (ioctl(mlxfd, MLX_REBUILDASYNC, &rb) == 0)
390		return (0);
391
392	switch (rb.rr_status) {
393	case 0x0002:
394		warnx("the drive at %d:%d is already ONLINE", rb.rr_channel,
395		    rb.rr_target);
396		break;
397
398	case 0x0004:
399		warnx("drive failed during rebuild");
400		break;
401
402	case 0x0105:
403		warnx("there is no drive at %d:%d", rb.rr_channel,
404		    rb.rr_target);
405		break;
406
407	case 0x0106:
408		warnx("drive rebuild or consistency check is already in ");
409		warnx("progress on this controller");
410		break;
411
412	default:
413		err(EXIT_FAILURE, "ioctl(MLXD_CHECKASYNC)");
414		/* NOTREACHED */
415	}
416
417	return(0);
418}
419