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