xref: /freebsd/usr.sbin/mptutil/mpt_cmd.c (revision fc58801ccc318e391722e23c01826884edd25bf9)
1fc58801cSScott Long /*-
2fc58801cSScott Long  * Copyright (c) 2008 Yahoo!, Inc.
3fc58801cSScott Long  * All rights reserved.
4fc58801cSScott Long  * Written by: John Baldwin <jhb@FreeBSD.org>
5fc58801cSScott Long  *
6fc58801cSScott Long  * Redistribution and use in source and binary forms, with or without
7fc58801cSScott Long  * modification, are permitted provided that the following conditions
8fc58801cSScott Long  * are met:
9fc58801cSScott Long  * 1. Redistributions of source code must retain the above copyright
10fc58801cSScott Long  *    notice, this list of conditions and the following disclaimer.
11fc58801cSScott Long  * 2. Redistributions in binary form must reproduce the above copyright
12fc58801cSScott Long  *    notice, this list of conditions and the following disclaimer in the
13fc58801cSScott Long  *    documentation and/or other materials provided with the distribution.
14fc58801cSScott Long  * 3. Neither the name of the author nor the names of any co-contributors
15fc58801cSScott Long  *    may be used to endorse or promote products derived from this software
16fc58801cSScott Long  *    without specific prior written permission.
17fc58801cSScott Long  *
18fc58801cSScott Long  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19fc58801cSScott Long  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20fc58801cSScott Long  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21fc58801cSScott Long  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22fc58801cSScott Long  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23fc58801cSScott Long  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24fc58801cSScott Long  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25fc58801cSScott Long  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26fc58801cSScott Long  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27fc58801cSScott Long  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28fc58801cSScott Long  * SUCH DAMAGE.
29fc58801cSScott Long  */
30fc58801cSScott Long 
31fc58801cSScott Long #include <sys/cdefs.h>
32fc58801cSScott Long __RCSID("$FreeBSD$");
33fc58801cSScott Long 
34fc58801cSScott Long #include <sys/param.h>
35fc58801cSScott Long #include <sys/errno.h>
36fc58801cSScott Long #include <sys/ioctl.h>
37fc58801cSScott Long #include <sys/mpt_ioctl.h>
38fc58801cSScott Long #include <sys/sysctl.h>
39fc58801cSScott Long #include <sys/uio.h>
40fc58801cSScott Long 
41fc58801cSScott Long #include <err.h>
42fc58801cSScott Long #include <fcntl.h>
43fc58801cSScott Long #include <stdio.h>
44fc58801cSScott Long #include <stdlib.h>
45fc58801cSScott Long #include <string.h>
46fc58801cSScott Long #include <unistd.h>
47fc58801cSScott Long 
48fc58801cSScott Long #include "mptutil.h"
49fc58801cSScott Long 
50fc58801cSScott Long static const char *mpt_ioc_status_codes[] = {
51fc58801cSScott Long 	"Success",				/* 0x0000 */
52fc58801cSScott Long 	"Invalid function",
53fc58801cSScott Long 	"Busy",
54fc58801cSScott Long 	"Invalid scatter-gather list",
55fc58801cSScott Long 	"Internal error",
56fc58801cSScott Long 	"Reserved",
57fc58801cSScott Long 	"Insufficient resources",
58fc58801cSScott Long 	"Invalid field",
59fc58801cSScott Long 	"Invalid state",			/* 0x0008 */
60fc58801cSScott Long 	"Operation state not supported",
61fc58801cSScott Long 	NULL,
62fc58801cSScott Long 	NULL,
63fc58801cSScott Long 	NULL,
64fc58801cSScott Long 	NULL,
65fc58801cSScott Long 	NULL,
66fc58801cSScott Long 	NULL,
67fc58801cSScott Long 	NULL,					/* 0x0010 */
68fc58801cSScott Long 	NULL,
69fc58801cSScott Long 	NULL,
70fc58801cSScott Long 	NULL,
71fc58801cSScott Long 	NULL,
72fc58801cSScott Long 	NULL,
73fc58801cSScott Long 	NULL,
74fc58801cSScott Long 	NULL,
75fc58801cSScott Long 	NULL,					/* 0x0018 */
76fc58801cSScott Long 	NULL,
77fc58801cSScott Long 	NULL,
78fc58801cSScott Long 	NULL,
79fc58801cSScott Long 	NULL,
80fc58801cSScott Long 	NULL,
81fc58801cSScott Long 	NULL,
82fc58801cSScott Long 	NULL,
83fc58801cSScott Long 	"Invalid configuration action",		/* 0x0020 */
84fc58801cSScott Long 	"Invalid configuration type",
85fc58801cSScott Long 	"Invalid configuration page",
86fc58801cSScott Long 	"Invalid configuration data",
87fc58801cSScott Long 	"No configuration defaults",
88fc58801cSScott Long 	"Unable to commit configuration change",
89fc58801cSScott Long 	NULL,
90fc58801cSScott Long 	NULL,
91fc58801cSScott Long 	NULL,					/* 0x0028 */
92fc58801cSScott Long 	NULL,
93fc58801cSScott Long 	NULL,
94fc58801cSScott Long 	NULL,
95fc58801cSScott Long 	NULL,
96fc58801cSScott Long 	NULL,
97fc58801cSScott Long 	NULL,
98fc58801cSScott Long 	NULL,
99fc58801cSScott Long 	NULL,					/* 0x0030 */
100fc58801cSScott Long 	NULL,
101fc58801cSScott Long 	NULL,
102fc58801cSScott Long 	NULL,
103fc58801cSScott Long 	NULL,
104fc58801cSScott Long 	NULL,
105fc58801cSScott Long 	NULL,
106fc58801cSScott Long 	NULL,
107fc58801cSScott Long 	NULL,					/* 0x0038 */
108fc58801cSScott Long 	NULL,
109fc58801cSScott Long 	NULL,
110fc58801cSScott Long 	NULL,
111fc58801cSScott Long 	NULL,
112fc58801cSScott Long 	NULL,
113fc58801cSScott Long 	NULL,
114fc58801cSScott Long 	NULL,
115fc58801cSScott Long 	"Recovered SCSI error",			/* 0x0040 */
116fc58801cSScott Long 	"Invalid SCSI bus",
117fc58801cSScott Long 	"Invalid SCSI target ID",
118fc58801cSScott Long 	"SCSI device not there",
119fc58801cSScott Long 	"SCSI data overrun",
120fc58801cSScott Long 	"SCSI data underrun",
121fc58801cSScott Long 	"SCSI I/O error",
122fc58801cSScott Long 	"SCSI protocol error",
123fc58801cSScott Long 	"SCSI task terminated",			/* 0x0048 */
124fc58801cSScott Long 	"SCSI residual mismatch",
125fc58801cSScott Long 	"SCSI task management failed",
126fc58801cSScott Long 	"SCSI I/O controller terminated",
127fc58801cSScott Long 	"SCSI external controller terminated",
128fc58801cSScott Long 	"EEDP guard error",
129fc58801cSScott Long 	"EEDP reference tag error",
130fc58801cSScott Long 	"EEDP application tag error",
131fc58801cSScott Long 	NULL,					/* 0x0050 */
132fc58801cSScott Long 	NULL,
133fc58801cSScott Long 	NULL,
134fc58801cSScott Long 	NULL,
135fc58801cSScott Long 	NULL,
136fc58801cSScott Long 	NULL,
137fc58801cSScott Long 	NULL,
138fc58801cSScott Long 	NULL,
139fc58801cSScott Long 	NULL,					/* 0x0058 */
140fc58801cSScott Long 	NULL,
141fc58801cSScott Long 	NULL,
142fc58801cSScott Long 	NULL,
143fc58801cSScott Long 	NULL,
144fc58801cSScott Long 	NULL,
145fc58801cSScott Long 	NULL,
146fc58801cSScott Long 	NULL,
147fc58801cSScott Long 	"SCSI target priority I/O",		/* 0x0060 */
148fc58801cSScott Long 	"Invalid SCSI target port",
149fc58801cSScott Long 	"Invalid SCSI target I/O index",
150fc58801cSScott Long 	"SCSI target aborted",
151fc58801cSScott Long 	"No connection retryable",
152fc58801cSScott Long 	"No connection",
153fc58801cSScott Long 	"FC aborted",
154fc58801cSScott Long 	"Invalid FC receive ID",
155fc58801cSScott Long 	"FC did invalid",			/* 0x0068 */
156fc58801cSScott Long 	"FC node logged out",
157fc58801cSScott Long 	"Transfer count mismatch",
158fc58801cSScott Long 	"STS data not set",
159fc58801cSScott Long 	"FC exchange canceled",
160fc58801cSScott Long 	"Data offset error",
161fc58801cSScott Long 	"Too much write data",
162fc58801cSScott Long 	"IU too short",
163fc58801cSScott Long 	"ACK NAK timeout",			/* 0x0070 */
164fc58801cSScott Long 	"NAK received",
165fc58801cSScott Long 	NULL,
166fc58801cSScott Long 	NULL,
167fc58801cSScott Long 	NULL,
168fc58801cSScott Long 	NULL,
169fc58801cSScott Long 	NULL,
170fc58801cSScott Long 	NULL,
171fc58801cSScott Long 	NULL,					/* 0x0078 */
172fc58801cSScott Long 	NULL,
173fc58801cSScott Long 	NULL,
174fc58801cSScott Long 	NULL,
175fc58801cSScott Long 	NULL,
176fc58801cSScott Long 	NULL,
177fc58801cSScott Long 	NULL,
178fc58801cSScott Long 	NULL,
179fc58801cSScott Long 	"LAN device not found",			/* 0x0080 */
180fc58801cSScott Long 	"LAN device failure",
181fc58801cSScott Long 	"LAN transmit error",
182fc58801cSScott Long 	"LAN transmit aborted",
183fc58801cSScott Long 	"LAN receive error",
184fc58801cSScott Long 	"LAN receive aborted",
185fc58801cSScott Long 	"LAN partial packet",
186fc58801cSScott Long 	"LAN canceled",
187fc58801cSScott Long 	NULL,					/* 0x0088 */
188fc58801cSScott Long 	NULL,
189fc58801cSScott Long 	NULL,
190fc58801cSScott Long 	NULL,
191fc58801cSScott Long 	NULL,
192fc58801cSScott Long 	NULL,
193fc58801cSScott Long 	NULL,
194fc58801cSScott Long 	NULL,
195fc58801cSScott Long 	"SAS SMP request failed",		/* 0x0090 */
196fc58801cSScott Long 	"SAS SMP data overrun",
197fc58801cSScott Long 	NULL,
198fc58801cSScott Long 	NULL,
199fc58801cSScott Long 	NULL,
200fc58801cSScott Long 	NULL,
201fc58801cSScott Long 	NULL,
202fc58801cSScott Long 	NULL,
203fc58801cSScott Long 	"Inband aborted",			/* 0x0098 */
204fc58801cSScott Long 	"No inband connection",
205fc58801cSScott Long 	NULL,
206fc58801cSScott Long 	NULL,
207fc58801cSScott Long 	NULL,
208fc58801cSScott Long 	NULL,
209fc58801cSScott Long 	NULL,
210fc58801cSScott Long 	NULL,
211fc58801cSScott Long 	"Diagnostic released",			/* 0x00A0 */
212fc58801cSScott Long };
213fc58801cSScott Long 
214fc58801cSScott Long static const char *mpt_raid_action_status_codes[] = {
215fc58801cSScott Long 	"Success",
216fc58801cSScott Long 	"Invalid action",
217fc58801cSScott Long 	"Failure",
218fc58801cSScott Long 	"Operation in progress",
219fc58801cSScott Long };
220fc58801cSScott Long 
221fc58801cSScott Long const char *
222fc58801cSScott Long mpt_ioc_status(U16 IOCStatus)
223fc58801cSScott Long {
224fc58801cSScott Long 	static char buffer[16];
225fc58801cSScott Long 
226fc58801cSScott Long 	IOCStatus &= MPI_IOCSTATUS_MASK;
227fc58801cSScott Long 	if (IOCStatus < sizeof(mpt_ioc_status_codes) / sizeof(char *) &&
228fc58801cSScott Long 	    mpt_ioc_status_codes[IOCStatus] != NULL)
229fc58801cSScott Long 		return (mpt_ioc_status_codes[IOCStatus]);
230fc58801cSScott Long 	snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
231fc58801cSScott Long 	return (buffer);
232fc58801cSScott Long }
233fc58801cSScott Long 
234fc58801cSScott Long const char *
235fc58801cSScott Long mpt_raid_status(U16 ActionStatus)
236fc58801cSScott Long {
237fc58801cSScott Long 	static char buffer[16];
238fc58801cSScott Long 
239fc58801cSScott Long 	if (ActionStatus < sizeof(mpt_raid_action_status_codes) /
240fc58801cSScott Long 	    sizeof(char *))
241fc58801cSScott Long 		return (mpt_raid_action_status_codes[ActionStatus]);
242fc58801cSScott Long 	snprintf(buffer, sizeof(buffer), "Status: 0x%04x", ActionStatus);
243fc58801cSScott Long 	return (buffer);
244fc58801cSScott Long }
245fc58801cSScott Long 
246fc58801cSScott Long const char *
247fc58801cSScott Long mpt_raid_level(U8 VolumeType)
248fc58801cSScott Long {
249fc58801cSScott Long 	static char buf[16];
250fc58801cSScott Long 
251fc58801cSScott Long 	switch (VolumeType) {
252fc58801cSScott Long 	case MPI_RAID_VOL_TYPE_IS:
253fc58801cSScott Long 		return ("RAID-0");
254fc58801cSScott Long 	case MPI_RAID_VOL_TYPE_IM:
255fc58801cSScott Long 		return ("RAID-1");
256fc58801cSScott Long 	case MPI_RAID_VOL_TYPE_IME:
257fc58801cSScott Long 		return ("RAID-1E");
258fc58801cSScott Long 	case MPI_RAID_VOL_TYPE_RAID_5:
259fc58801cSScott Long 		return ("RAID-5");
260fc58801cSScott Long 	case MPI_RAID_VOL_TYPE_RAID_6:
261fc58801cSScott Long 		return ("RAID-6");
262fc58801cSScott Long 	case MPI_RAID_VOL_TYPE_RAID_10:
263fc58801cSScott Long 		return ("RAID-10");
264fc58801cSScott Long 	case MPI_RAID_VOL_TYPE_RAID_50:
265fc58801cSScott Long 		return ("RAID-50");
266fc58801cSScott Long 	default:
267fc58801cSScott Long 		sprintf(buf, "LVL 0x%02x", VolumeType);
268fc58801cSScott Long 		return (buf);
269fc58801cSScott Long 	}
270fc58801cSScott Long }
271fc58801cSScott Long 
272fc58801cSScott Long const char *
273fc58801cSScott Long mpt_volume_name(U8 VolumeBus, U8 VolumeID)
274fc58801cSScott Long {
275fc58801cSScott Long 	static struct mpt_query_disk info;
276fc58801cSScott Long 	static char buf[16];
277fc58801cSScott Long 
278fc58801cSScott Long 	if (mpt_query_disk(VolumeBus, VolumeID, &info) != 0) {
279fc58801cSScott Long 		/*
280fc58801cSScott Long 		 * We only print out the bus number if it is non-zero
281fc58801cSScott Long 		 * since mpt(4) only supports devices on bus zero
282fc58801cSScott Long 		 * anyway.
283fc58801cSScott Long 		 */
284fc58801cSScott Long 		if (VolumeBus == 0)
285fc58801cSScott Long 			snprintf(buf, sizeof(buf), "%d", VolumeID);
286fc58801cSScott Long 		else
287fc58801cSScott Long 			snprintf(buf, sizeof(buf), "%d:%d", VolumeBus,
288fc58801cSScott Long 			    VolumeID);
289fc58801cSScott Long 		return (buf);
290fc58801cSScott Long 	}
291fc58801cSScott Long 	return (info.devname);
292fc58801cSScott Long }
293fc58801cSScott Long 
294fc58801cSScott Long int
295fc58801cSScott Long mpt_lookup_volume(int fd, const char *name, U8 *VolumeBus, U8 *VolumeID)
296fc58801cSScott Long {
297fc58801cSScott Long 	CONFIG_PAGE_IOC_2 *ioc2;
298fc58801cSScott Long 	CONFIG_PAGE_IOC_2_RAID_VOL *vol;
299fc58801cSScott Long 	struct mpt_query_disk info;
300fc58801cSScott Long 	char *cp;
301fc58801cSScott Long 	long bus, id;
302fc58801cSScott Long 	int i;
303fc58801cSScott Long 
304fc58801cSScott Long 	/*
305fc58801cSScott Long 	 * Check for a raw [<bus>:]<id> string.  If the bus is not
306fc58801cSScott Long 	 * specified, assume bus 0.
307fc58801cSScott Long 	 */
308fc58801cSScott Long 	bus = strtol(name, &cp, 0);
309fc58801cSScott Long 	if (*cp == ':') {
310fc58801cSScott Long 		id = strtol(cp + 1, &cp, 0);
311fc58801cSScott Long 		if (*cp == '\0') {
312fc58801cSScott Long 			if (bus < 0 || bus > 0xff || id < 0 || id > 0xff) {
313fc58801cSScott Long 				errno = EINVAL;
314fc58801cSScott Long 				return (-1);
315fc58801cSScott Long 			}
316fc58801cSScott Long 			*VolumeBus = bus;
317fc58801cSScott Long 			*VolumeID = id;
318fc58801cSScott Long 			return (0);
319fc58801cSScott Long 		}
320fc58801cSScott Long 	} else if (*cp == '\0') {
321fc58801cSScott Long 		if (bus < 0 || bus > 0xff) {
322fc58801cSScott Long 			errno = EINVAL;
323fc58801cSScott Long 			return (-1);
324fc58801cSScott Long 		}
325fc58801cSScott Long 		*VolumeBus = 0;
326fc58801cSScott Long 		*VolumeID = bus;
327fc58801cSScott Long 		return (0);
328fc58801cSScott Long 	}
329fc58801cSScott Long 
330fc58801cSScott Long 	ioc2 = mpt_read_ioc_page(fd, 2, NULL);
331fc58801cSScott Long 	if (ioc2 == NULL)
332fc58801cSScott Long 		return (-1);
333fc58801cSScott Long 
334fc58801cSScott Long 	vol = ioc2->RaidVolume;
335fc58801cSScott Long 	for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) {
336fc58801cSScott Long 		if (mpt_query_disk(vol->VolumeBus, vol->VolumeID, &info) != 0)
337fc58801cSScott Long 			continue;
338fc58801cSScott Long 		if (strcmp(name, info.devname) == 0) {
339fc58801cSScott Long 			*VolumeBus = vol->VolumeBus;
340fc58801cSScott Long 			*VolumeID = vol->VolumeID;
341fc58801cSScott Long 			free(ioc2);
342fc58801cSScott Long 			return (0);
343fc58801cSScott Long 		}
344fc58801cSScott Long 	}
345fc58801cSScott Long 	free(ioc2);
346fc58801cSScott Long 	errno = EINVAL;
347fc58801cSScott Long 	return (-1);
348fc58801cSScott Long }
349fc58801cSScott Long 
350fc58801cSScott Long int
351fc58801cSScott Long mpt_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
352fc58801cSScott Long     CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
353fc58801cSScott Long {
354fc58801cSScott Long 	struct mpt_cfg_page_req req;
355fc58801cSScott Long 
356fc58801cSScott Long 	if (IOCStatus != NULL)
357fc58801cSScott Long 		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
358fc58801cSScott Long 	bzero(&req, sizeof(req));
359fc58801cSScott Long 	req.header.PageType = PageType;
360fc58801cSScott Long 	req.header.PageNumber = PageNumber;
361fc58801cSScott Long 	req.page_address = PageAddress;
362fc58801cSScott Long 	if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
363fc58801cSScott Long 		return (-1);
364fc58801cSScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
365fc58801cSScott Long 		if (IOCStatus != NULL)
366fc58801cSScott Long 			*IOCStatus = req.ioc_status;
367fc58801cSScott Long 		else
368fc58801cSScott Long 			warnx("Reading config page header failed: %s",
369fc58801cSScott Long 			    mpt_ioc_status(req.ioc_status));
370fc58801cSScott Long 		errno = EIO;
371fc58801cSScott Long 		return (-1);
372fc58801cSScott Long 	}
373fc58801cSScott Long 	*header = req.header;
374fc58801cSScott Long 	return (0);
375fc58801cSScott Long }
376fc58801cSScott Long 
377fc58801cSScott Long void *
378fc58801cSScott Long mpt_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
379fc58801cSScott Long     U16 *IOCStatus)
380fc58801cSScott Long {
381fc58801cSScott Long 	struct mpt_cfg_page_req req;
382fc58801cSScott Long 	void *buf;
383fc58801cSScott Long 	int save_errno;
384fc58801cSScott Long 
385fc58801cSScott Long 	if (IOCStatus != NULL)
386fc58801cSScott Long 		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
387fc58801cSScott Long 	bzero(&req, sizeof(req));
388fc58801cSScott Long 	req.header.PageType = PageType;
389fc58801cSScott Long 	req.header.PageNumber = PageNumber;
390fc58801cSScott Long 	req.page_address = PageAddress;
391fc58801cSScott Long 	if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
392fc58801cSScott Long 		return (NULL);
393fc58801cSScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
394fc58801cSScott Long 		if (IOCStatus != NULL)
395fc58801cSScott Long 			*IOCStatus = req.ioc_status;
396fc58801cSScott Long 		else
397fc58801cSScott Long 			warnx("Reading config page header failed: %s",
398fc58801cSScott Long 			    mpt_ioc_status(req.ioc_status));
399fc58801cSScott Long 		errno = EIO;
400fc58801cSScott Long 		return (NULL);
401fc58801cSScott Long 	}
402fc58801cSScott Long 	req.len = req.header.PageLength * 4;
403fc58801cSScott Long 	buf = malloc(req.len);
404fc58801cSScott Long 	req.buf = buf;
405fc58801cSScott Long 	bcopy(&req.header, buf, sizeof(req.header));
406fc58801cSScott Long 	if (ioctl(fd, MPTIO_READ_CFG_PAGE, &req) < 0) {
407fc58801cSScott Long 		save_errno = errno;
408fc58801cSScott Long 		free(buf);
409fc58801cSScott Long 		errno = save_errno;
410fc58801cSScott Long 		return (NULL);
411fc58801cSScott Long 	}
412fc58801cSScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
413fc58801cSScott Long 		if (IOCStatus != NULL)
414fc58801cSScott Long 			*IOCStatus = req.ioc_status;
415fc58801cSScott Long 		else
416fc58801cSScott Long 			warnx("Reading config page failed: %s",
417fc58801cSScott Long 			    mpt_ioc_status(req.ioc_status));
418fc58801cSScott Long 		free(buf);
419fc58801cSScott Long 		errno = EIO;
420fc58801cSScott Long 		return (NULL);
421fc58801cSScott Long 	}
422fc58801cSScott Long 	return (buf);
423fc58801cSScott Long }
424fc58801cSScott Long 
425fc58801cSScott Long void *
426fc58801cSScott Long mpt_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
427fc58801cSScott Long     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
428fc58801cSScott Long {
429fc58801cSScott Long 	struct mpt_ext_cfg_page_req req;
430fc58801cSScott Long 	void *buf;
431fc58801cSScott Long 	int save_errno;
432fc58801cSScott Long 
433fc58801cSScott Long 	if (IOCStatus != NULL)
434fc58801cSScott Long 		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
435fc58801cSScott Long 	bzero(&req, sizeof(req));
436fc58801cSScott Long 	req.header.PageVersion = PageVersion;
437fc58801cSScott Long 	req.header.PageNumber = PageNumber;
438fc58801cSScott Long 	req.header.ExtPageType = ExtPageType;
439fc58801cSScott Long 	req.page_address = PageAddress;
440fc58801cSScott Long 	if (ioctl(fd, MPTIO_READ_EXT_CFG_HEADER, &req) < 0)
441fc58801cSScott Long 		return (NULL);
442fc58801cSScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
443fc58801cSScott Long 		if (IOCStatus != NULL)
444fc58801cSScott Long 			*IOCStatus = req.ioc_status;
445fc58801cSScott Long 		else
446fc58801cSScott Long 			warnx("Reading extended config page header failed: %s",
447fc58801cSScott Long 			    mpt_ioc_status(req.ioc_status));
448fc58801cSScott Long 		errno = EIO;
449fc58801cSScott Long 		return (NULL);
450fc58801cSScott Long 	}
451fc58801cSScott Long 	req.len = req.header.ExtPageLength * 4;
452fc58801cSScott Long 	buf = malloc(req.len);
453fc58801cSScott Long 	req.buf = buf;
454fc58801cSScott Long 	bcopy(&req.header, buf, sizeof(req.header));
455fc58801cSScott Long 	if (ioctl(fd, MPTIO_READ_EXT_CFG_PAGE, &req) < 0) {
456fc58801cSScott Long 		save_errno = errno;
457fc58801cSScott Long 		free(buf);
458fc58801cSScott Long 		errno = save_errno;
459fc58801cSScott Long 		return (NULL);
460fc58801cSScott Long 	}
461fc58801cSScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
462fc58801cSScott Long 		if (IOCStatus != NULL)
463fc58801cSScott Long 			*IOCStatus = req.ioc_status;
464fc58801cSScott Long 		else
465fc58801cSScott Long 			warnx("Reading extended config page failed: %s",
466fc58801cSScott Long 			    mpt_ioc_status(req.ioc_status));
467fc58801cSScott Long 		free(buf);
468fc58801cSScott Long 		errno = EIO;
469fc58801cSScott Long 		return (NULL);
470fc58801cSScott Long 	}
471fc58801cSScott Long 	return (buf);
472fc58801cSScott Long }
473fc58801cSScott Long 
474fc58801cSScott Long int
475fc58801cSScott Long mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
476fc58801cSScott Long {
477fc58801cSScott Long 	CONFIG_PAGE_HEADER *hdr;
478fc58801cSScott Long 	struct mpt_cfg_page_req req;
479fc58801cSScott Long 
480fc58801cSScott Long 	if (IOCStatus != NULL)
481fc58801cSScott Long 		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
482fc58801cSScott Long 	bzero(&req, sizeof(req));
483fc58801cSScott Long 	req.buf = buf;
484fc58801cSScott Long 	hdr = buf;
485fc58801cSScott Long 	req.len = hdr->PageLength * 4;
486fc58801cSScott Long 	if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
487fc58801cSScott Long 		return (-1);
488fc58801cSScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
489fc58801cSScott Long 		if (IOCStatus != NULL) {
490fc58801cSScott Long 			*IOCStatus = req.ioc_status;
491fc58801cSScott Long 			return (0);
492fc58801cSScott Long 		}
493fc58801cSScott Long 		warnx("Writing config page failed: %s",
494fc58801cSScott Long 		    mpt_ioc_status(req.ioc_status));
495fc58801cSScott Long 		errno = EIO;
496fc58801cSScott Long 		return (-1);
497fc58801cSScott Long 	}
498fc58801cSScott Long 	return (0);
499fc58801cSScott Long }
500fc58801cSScott Long 
501fc58801cSScott Long int
502fc58801cSScott Long mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
503fc58801cSScott Long     U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
504fc58801cSScott Long     U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
505fc58801cSScott Long {
506fc58801cSScott Long 	struct mpt_raid_action raid_act;
507fc58801cSScott Long 
508fc58801cSScott Long 	if (IOCStatus != NULL)
509fc58801cSScott Long 		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
510fc58801cSScott Long 	if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data)) {
511fc58801cSScott Long 		errno = EINVAL;
512fc58801cSScott Long 		return (-1);
513fc58801cSScott Long 	}
514fc58801cSScott Long 	bzero(&raid_act, sizeof(raid_act));
515fc58801cSScott Long 	raid_act.action = Action;
516fc58801cSScott Long 	raid_act.volume_bus = VolumeBus;
517fc58801cSScott Long 	raid_act.volume_id = VolumeID;
518fc58801cSScott Long 	raid_act.phys_disk_num = PhysDiskNum;
519fc58801cSScott Long 	raid_act.action_data_word = ActionDataWord;
520fc58801cSScott Long 	if (buf != NULL && len != 0) {
521fc58801cSScott Long 		raid_act.buf = buf;
522fc58801cSScott Long 		raid_act.len = len;
523fc58801cSScott Long 		raid_act.write = write;
524fc58801cSScott Long 	}
525fc58801cSScott Long 
526fc58801cSScott Long 	if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
527fc58801cSScott Long 		return (-1);
528fc58801cSScott Long 
529fc58801cSScott Long 	if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
530fc58801cSScott Long 		if (IOCStatus != NULL) {
531fc58801cSScott Long 			*IOCStatus = raid_act.ioc_status;
532fc58801cSScott Long 			return (0);
533fc58801cSScott Long 		}
534fc58801cSScott Long 		warnx("RAID action failed: %s",
535fc58801cSScott Long 		    mpt_ioc_status(raid_act.ioc_status));
536fc58801cSScott Long 		errno = EIO;
537fc58801cSScott Long 		return (-1);
538fc58801cSScott Long 	}
539fc58801cSScott Long 
540fc58801cSScott Long 	if (ActionStatus != NULL)
541fc58801cSScott Long 		*ActionStatus = raid_act.action_status;
542fc58801cSScott Long 	if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
543fc58801cSScott Long 		if (ActionStatus != NULL)
544fc58801cSScott Long 			return (0);
545fc58801cSScott Long 		warnx("RAID action failed: %s",
546fc58801cSScott Long 		    mpt_raid_status(raid_act.action_status));
547fc58801cSScott Long 		errno = EIO;
548fc58801cSScott Long 		return (-1);
549fc58801cSScott Long 	}
550fc58801cSScott Long 
551fc58801cSScott Long 	if (VolumeStatus != NULL)
552fc58801cSScott Long 		*((U32 *)VolumeStatus) = raid_act.volume_status;
553fc58801cSScott Long 	if (ActionData != NULL)
554fc58801cSScott Long 		bcopy(raid_act.action_data, ActionData, datalen);
555fc58801cSScott Long 	return (0);
556fc58801cSScott Long }
557fc58801cSScott Long 
558fc58801cSScott Long int
559fc58801cSScott Long mpt_open(int unit)
560fc58801cSScott Long {
561fc58801cSScott Long 	char path[MAXPATHLEN];
562fc58801cSScott Long 
563fc58801cSScott Long 	snprintf(path, sizeof(path), "/dev/mpt%d", unit);
564fc58801cSScott Long 	return (open(path, O_RDWR));
565fc58801cSScott Long }
566fc58801cSScott Long 
567fc58801cSScott Long int
568fc58801cSScott Long mpt_table_handler(struct mptutil_command **start, struct mptutil_command **end,
569fc58801cSScott Long     int ac, char **av)
570fc58801cSScott Long {
571fc58801cSScott Long 	struct mptutil_command **cmd;
572fc58801cSScott Long 
573fc58801cSScott Long 	if (ac < 2) {
574fc58801cSScott Long 		warnx("The %s command requires a sub-command.", av[0]);
575fc58801cSScott Long 		return (EINVAL);
576fc58801cSScott Long 	}
577fc58801cSScott Long 	for (cmd = start; cmd < end; cmd++) {
578fc58801cSScott Long 		if (strcmp((*cmd)->name, av[1]) == 0)
579fc58801cSScott Long 			return ((*cmd)->handler(ac - 1, av + 1));
580fc58801cSScott Long 	}
581fc58801cSScott Long 
582fc58801cSScott Long 	warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
583fc58801cSScott Long 	return (ENOENT);
584fc58801cSScott Long }
585fc58801cSScott Long 
586fc58801cSScott Long #ifdef DEBUG
587fc58801cSScott Long void
588fc58801cSScott Long hexdump(const void *ptr, int length, const char *hdr, int flags)
589fc58801cSScott Long {
590fc58801cSScott Long 	int i, j, k;
591fc58801cSScott Long 	int cols;
592fc58801cSScott Long 	const unsigned char *cp;
593fc58801cSScott Long 	char delim;
594fc58801cSScott Long 
595fc58801cSScott Long 	if ((flags & HD_DELIM_MASK) != 0)
596fc58801cSScott Long 		delim = (flags & HD_DELIM_MASK) >> 8;
597fc58801cSScott Long 	else
598fc58801cSScott Long 		delim = ' ';
599fc58801cSScott Long 
600fc58801cSScott Long 	if ((flags & HD_COLUMN_MASK) != 0)
601fc58801cSScott Long 		cols = flags & HD_COLUMN_MASK;
602fc58801cSScott Long 	else
603fc58801cSScott Long 		cols = 16;
604fc58801cSScott Long 
605fc58801cSScott Long 	cp = ptr;
606fc58801cSScott Long 	for (i = 0; i < length; i+= cols) {
607fc58801cSScott Long 		if (hdr != NULL)
608fc58801cSScott Long 			printf("%s", hdr);
609fc58801cSScott Long 
610fc58801cSScott Long 		if ((flags & HD_OMIT_COUNT) == 0)
611fc58801cSScott Long 			printf("%04x  ", i);
612fc58801cSScott Long 
613fc58801cSScott Long 		if ((flags & HD_OMIT_HEX) == 0) {
614fc58801cSScott Long 			for (j = 0; j < cols; j++) {
615fc58801cSScott Long 				k = i + j;
616fc58801cSScott Long 				if (k < length)
617fc58801cSScott Long 					printf("%c%02x", delim, cp[k]);
618fc58801cSScott Long 				else
619fc58801cSScott Long 					printf("   ");
620fc58801cSScott Long 			}
621fc58801cSScott Long 		}
622fc58801cSScott Long 
623fc58801cSScott Long 		if ((flags & HD_OMIT_CHARS) == 0) {
624fc58801cSScott Long 			printf("  |");
625fc58801cSScott Long 			for (j = 0; j < cols; j++) {
626fc58801cSScott Long 				k = i + j;
627fc58801cSScott Long 				if (k >= length)
628fc58801cSScott Long 					printf(" ");
629fc58801cSScott Long 				else if (cp[k] >= ' ' && cp[k] <= '~')
630fc58801cSScott Long 					printf("%c", cp[k]);
631fc58801cSScott Long 				else
632fc58801cSScott Long 					printf(".");
633fc58801cSScott Long 			}
634fc58801cSScott Long 			printf("|");
635fc58801cSScott Long 		}
636fc58801cSScott Long 		printf("\n");
637fc58801cSScott Long 	}
638fc58801cSScott Long }
639fc58801cSScott Long #endif
640