xref: /freebsd/usr.sbin/mpsutil/mps_cmd.c (revision 48f31f4f)
129b76e53SScott Long /*-
229b76e53SScott Long  * Copyright (c) 2008 Yahoo!, Inc.
329b76e53SScott Long  * All rights reserved.
429b76e53SScott Long  * Written by: John Baldwin <jhb@FreeBSD.org>
529b76e53SScott Long  *
629b76e53SScott Long  * Redistribution and use in source and binary forms, with or without
729b76e53SScott Long  * modification, are permitted provided that the following conditions
829b76e53SScott Long  * are met:
929b76e53SScott Long  * 1. Redistributions of source code must retain the above copyright
1029b76e53SScott Long  *    notice, this list of conditions and the following disclaimer.
1129b76e53SScott Long  * 2. Redistributions in binary form must reproduce the above copyright
1229b76e53SScott Long  *    notice, this list of conditions and the following disclaimer in the
1329b76e53SScott Long  *    documentation and/or other materials provided with the distribution.
1429b76e53SScott Long  * 3. Neither the name of the author nor the names of any co-contributors
1529b76e53SScott Long  *    may be used to endorse or promote products derived from this software
1629b76e53SScott Long  *    without specific prior written permission.
1729b76e53SScott Long  *
1829b76e53SScott Long  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1929b76e53SScott Long  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2029b76e53SScott Long  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2129b76e53SScott Long  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2229b76e53SScott Long  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2329b76e53SScott Long  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2429b76e53SScott Long  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2529b76e53SScott Long  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2629b76e53SScott Long  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2729b76e53SScott Long  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2829b76e53SScott Long  * SUCH DAMAGE.
2929b76e53SScott Long  */
3029b76e53SScott Long 
3129b76e53SScott Long #include <sys/cdefs.h>
3229b76e53SScott Long __RCSID("$FreeBSD$");
3329b76e53SScott Long 
3429b76e53SScott Long #include <sys/param.h>
3529b76e53SScott Long #include <sys/errno.h>
3629b76e53SScott Long #include <sys/ioctl.h>
3729b76e53SScott Long #if 0
3829b76e53SScott Long #include <sys/mps_ioctl.h>
3929b76e53SScott Long #else
4029b76e53SScott Long #include "mps_ioctl.h"
4129b76e53SScott Long #endif
4229b76e53SScott Long #include <sys/sysctl.h>
4329b76e53SScott Long #include <sys/uio.h>
4429b76e53SScott Long 
4529b76e53SScott Long #include <err.h>
4629b76e53SScott Long #include <fcntl.h>
4729b76e53SScott Long #include <stdio.h>
4829b76e53SScott Long #include <stdlib.h>
4929b76e53SScott Long #include <string.h>
5029b76e53SScott Long #include <unistd.h>
5129b76e53SScott Long 
5229b76e53SScott Long #include "mpsutil.h"
5329b76e53SScott Long 
5429b76e53SScott Long #ifndef USE_MPT_IOCTLS
5529b76e53SScott Long #define USE_MPT_IOCTLS
5629b76e53SScott Long #endif
5729b76e53SScott Long 
5829b76e53SScott Long static const char *mps_ioc_status_codes[] = {
5929b76e53SScott Long 	"Success",				/* 0x0000 */
6029b76e53SScott Long 	"Invalid function",
6129b76e53SScott Long 	"Busy",
6229b76e53SScott Long 	"Invalid scatter-gather list",
6329b76e53SScott Long 	"Internal error",
6429b76e53SScott Long 	"Reserved",
6529b76e53SScott Long 	"Insufficient resources",
6629b76e53SScott Long 	"Invalid field",
6729b76e53SScott Long 	"Invalid state",			/* 0x0008 */
6829b76e53SScott Long 	"Operation state not supported",
6929b76e53SScott Long 	NULL,
7029b76e53SScott Long 	NULL,
7129b76e53SScott Long 	NULL,
7229b76e53SScott Long 	NULL,
7329b76e53SScott Long 	NULL,
7429b76e53SScott Long 	NULL,
7529b76e53SScott Long 	NULL,					/* 0x0010 */
7629b76e53SScott Long 	NULL,
7729b76e53SScott Long 	NULL,
7829b76e53SScott Long 	NULL,
7929b76e53SScott Long 	NULL,
8029b76e53SScott Long 	NULL,
8129b76e53SScott Long 	NULL,
8229b76e53SScott Long 	NULL,
8329b76e53SScott Long 	NULL,					/* 0x0018 */
8429b76e53SScott Long 	NULL,
8529b76e53SScott Long 	NULL,
8629b76e53SScott Long 	NULL,
8729b76e53SScott Long 	NULL,
8829b76e53SScott Long 	NULL,
8929b76e53SScott Long 	NULL,
9029b76e53SScott Long 	NULL,
9129b76e53SScott Long 	"Invalid configuration action",		/* 0x0020 */
9229b76e53SScott Long 	"Invalid configuration type",
9329b76e53SScott Long 	"Invalid configuration page",
9429b76e53SScott Long 	"Invalid configuration data",
9529b76e53SScott Long 	"No configuration defaults",
9629b76e53SScott Long 	"Unable to commit configuration change",
9729b76e53SScott Long 	NULL,
9829b76e53SScott Long 	NULL,
9929b76e53SScott Long 	NULL,					/* 0x0028 */
10029b76e53SScott Long 	NULL,
10129b76e53SScott Long 	NULL,
10229b76e53SScott Long 	NULL,
10329b76e53SScott Long 	NULL,
10429b76e53SScott Long 	NULL,
10529b76e53SScott Long 	NULL,
10629b76e53SScott Long 	NULL,
10729b76e53SScott Long 	NULL,					/* 0x0030 */
10829b76e53SScott Long 	NULL,
10929b76e53SScott Long 	NULL,
11029b76e53SScott Long 	NULL,
11129b76e53SScott Long 	NULL,
11229b76e53SScott Long 	NULL,
11329b76e53SScott Long 	NULL,
11429b76e53SScott Long 	NULL,
11529b76e53SScott Long 	NULL,					/* 0x0038 */
11629b76e53SScott Long 	NULL,
11729b76e53SScott Long 	NULL,
11829b76e53SScott Long 	NULL,
11929b76e53SScott Long 	NULL,
12029b76e53SScott Long 	NULL,
12129b76e53SScott Long 	NULL,
12229b76e53SScott Long 	NULL,
12329b76e53SScott Long 	"Recovered SCSI error",			/* 0x0040 */
12429b76e53SScott Long 	"Invalid SCSI bus",
12529b76e53SScott Long 	"Invalid SCSI target ID",
12629b76e53SScott Long 	"SCSI device not there",
12729b76e53SScott Long 	"SCSI data overrun",
12829b76e53SScott Long 	"SCSI data underrun",
12929b76e53SScott Long 	"SCSI I/O error",
13029b76e53SScott Long 	"SCSI protocol error",
13129b76e53SScott Long 	"SCSI task terminated",			/* 0x0048 */
13229b76e53SScott Long 	"SCSI residual mismatch",
13329b76e53SScott Long 	"SCSI task management failed",
13429b76e53SScott Long 	"SCSI I/O controller terminated",
13529b76e53SScott Long 	"SCSI external controller terminated",
13629b76e53SScott Long 	"EEDP guard error",
13729b76e53SScott Long 	"EEDP reference tag error",
13829b76e53SScott Long 	"EEDP application tag error",
13929b76e53SScott Long 	NULL,					/* 0x0050 */
14029b76e53SScott Long 	NULL,
14129b76e53SScott Long 	NULL,
14229b76e53SScott Long 	NULL,
14329b76e53SScott Long 	NULL,
14429b76e53SScott Long 	NULL,
14529b76e53SScott Long 	NULL,
14629b76e53SScott Long 	NULL,
14729b76e53SScott Long 	NULL,					/* 0x0058 */
14829b76e53SScott Long 	NULL,
14929b76e53SScott Long 	NULL,
15029b76e53SScott Long 	NULL,
15129b76e53SScott Long 	NULL,
15229b76e53SScott Long 	NULL,
15329b76e53SScott Long 	NULL,
15429b76e53SScott Long 	NULL,
15529b76e53SScott Long 	"SCSI target priority I/O",		/* 0x0060 */
15629b76e53SScott Long 	"Invalid SCSI target port",
15729b76e53SScott Long 	"Invalid SCSI target I/O index",
15829b76e53SScott Long 	"SCSI target aborted",
15929b76e53SScott Long 	"No connection retryable",
16029b76e53SScott Long 	"No connection",
16129b76e53SScott Long 	"FC aborted",
16229b76e53SScott Long 	"Invalid FC receive ID",
16329b76e53SScott Long 	"FC did invalid",			/* 0x0068 */
16429b76e53SScott Long 	"FC node logged out",
16529b76e53SScott Long 	"Transfer count mismatch",
16629b76e53SScott Long 	"STS data not set",
16729b76e53SScott Long 	"FC exchange canceled",
16829b76e53SScott Long 	"Data offset error",
16929b76e53SScott Long 	"Too much write data",
17029b76e53SScott Long 	"IU too short",
17129b76e53SScott Long 	"ACK NAK timeout",			/* 0x0070 */
17229b76e53SScott Long 	"NAK received",
17329b76e53SScott Long 	NULL,
17429b76e53SScott Long 	NULL,
17529b76e53SScott Long 	NULL,
17629b76e53SScott Long 	NULL,
17729b76e53SScott Long 	NULL,
17829b76e53SScott Long 	NULL,
17929b76e53SScott Long 	NULL,					/* 0x0078 */
18029b76e53SScott Long 	NULL,
18129b76e53SScott Long 	NULL,
18229b76e53SScott Long 	NULL,
18329b76e53SScott Long 	NULL,
18429b76e53SScott Long 	NULL,
18529b76e53SScott Long 	NULL,
18629b76e53SScott Long 	NULL,
18729b76e53SScott Long 	"LAN device not found",			/* 0x0080 */
18829b76e53SScott Long 	"LAN device failure",
18929b76e53SScott Long 	"LAN transmit error",
19029b76e53SScott Long 	"LAN transmit aborted",
19129b76e53SScott Long 	"LAN receive error",
19229b76e53SScott Long 	"LAN receive aborted",
19329b76e53SScott Long 	"LAN partial packet",
19429b76e53SScott Long 	"LAN canceled",
19529b76e53SScott Long 	NULL,					/* 0x0088 */
19629b76e53SScott Long 	NULL,
19729b76e53SScott Long 	NULL,
19829b76e53SScott Long 	NULL,
19929b76e53SScott Long 	NULL,
20029b76e53SScott Long 	NULL,
20129b76e53SScott Long 	NULL,
20229b76e53SScott Long 	NULL,
20329b76e53SScott Long 	"SAS SMP request failed",		/* 0x0090 */
20429b76e53SScott Long 	"SAS SMP data overrun",
20529b76e53SScott Long 	NULL,
20629b76e53SScott Long 	NULL,
20729b76e53SScott Long 	NULL,
20829b76e53SScott Long 	NULL,
20929b76e53SScott Long 	NULL,
21029b76e53SScott Long 	NULL,
21129b76e53SScott Long 	"Inband aborted",			/* 0x0098 */
21229b76e53SScott Long 	"No inband connection",
21329b76e53SScott Long 	NULL,
21429b76e53SScott Long 	NULL,
21529b76e53SScott Long 	NULL,
21629b76e53SScott Long 	NULL,
21729b76e53SScott Long 	NULL,
21829b76e53SScott Long 	NULL,
21929b76e53SScott Long 	"Diagnostic released",			/* 0x00A0 */
22029b76e53SScott Long };
22129b76e53SScott Long 
22229b76e53SScott Long const char *
22329b76e53SScott Long mps_ioc_status(U16 IOCStatus)
22429b76e53SScott Long {
22529b76e53SScott Long 	static char buffer[16];
22629b76e53SScott Long 
22729b76e53SScott Long 	IOCStatus &= MPI2_IOCSTATUS_MASK;
22829b76e53SScott Long 	if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
22929b76e53SScott Long 	    mps_ioc_status_codes[IOCStatus] != NULL)
23029b76e53SScott Long 		return (mps_ioc_status_codes[IOCStatus]);
23129b76e53SScott Long 	snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
23229b76e53SScott Long 	return (buffer);
23329b76e53SScott Long }
23429b76e53SScott Long 
23529b76e53SScott Long #ifdef USE_MPT_IOCTLS
23629b76e53SScott Long int
23729b76e53SScott Long mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
23829b76e53SScott Long {
23929b76e53SScott Long 	int error;
24029b76e53SScott Long 	struct mps_btdh_mapping map;
24129b76e53SScott Long 
24229b76e53SScott Long 	bzero(&map, sizeof(map));
24329b76e53SScott Long 	map.Bus = *bus;
24429b76e53SScott Long 	map.TargetID = *target;
24529b76e53SScott Long 	map.DevHandle = *devhandle;
24629b76e53SScott Long 
24729b76e53SScott Long 	if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
24829b76e53SScott Long 		error = errno;
24929b76e53SScott Long 		warn("Failed to map bus/target/device");
25029b76e53SScott Long 		return (error);
25129b76e53SScott Long 	}
25229b76e53SScott Long 
25329b76e53SScott Long 	*bus = map.Bus;
25429b76e53SScott Long 	*target = map.TargetID;
25529b76e53SScott Long 	*devhandle = map.DevHandle;
25629b76e53SScott Long 
25729b76e53SScott Long 	return (0);
25829b76e53SScott Long }
25929b76e53SScott Long 
26029b76e53SScott Long int
26129b76e53SScott Long mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
26229b76e53SScott Long     MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
26329b76e53SScott Long {
26429b76e53SScott Long 	MPI2_CONFIG_REQUEST req;
26529b76e53SScott Long 	MPI2_CONFIG_REPLY reply;
26629b76e53SScott Long 
26729b76e53SScott Long 	bzero(&req, sizeof(req));
26829b76e53SScott Long 	req.Function = MPI2_FUNCTION_CONFIG;
26929b76e53SScott Long 	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
27029b76e53SScott Long 	req.Header.PageType = PageType;
27129b76e53SScott Long 	req.Header.PageNumber = PageNumber;
27229b76e53SScott Long 	req.PageAddress = PageAddress;
27329b76e53SScott Long 
27429b76e53SScott Long 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
27529b76e53SScott Long 	    NULL, 0, NULL, 0, 30))
27629b76e53SScott Long 		return (errno);
27729b76e53SScott Long 
27829b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
27929b76e53SScott Long 		if (IOCStatus != NULL)
28029b76e53SScott Long 			*IOCStatus = reply.IOCStatus;
28129b76e53SScott Long 		return (EIO);
28229b76e53SScott Long 	}
28329b76e53SScott Long 	if (header == NULL)
28429b76e53SScott Long 		return (EINVAL);
28529b76e53SScott Long 	*header = reply.Header;
28629b76e53SScott Long 	return (0);
28729b76e53SScott Long }
28829b76e53SScott Long 
28929b76e53SScott Long int
29029b76e53SScott Long mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
29129b76e53SScott Long {
29229b76e53SScott Long 	MPI2_CONFIG_REQUEST req;
29329b76e53SScott Long 	MPI2_CONFIG_REPLY reply;
29429b76e53SScott Long 
29529b76e53SScott Long 	bzero(&req, sizeof(req));
29629b76e53SScott Long 	req.Function = MPI2_FUNCTION_CONFIG;
29729b76e53SScott Long 	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
29829b76e53SScott Long 	req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
29929b76e53SScott Long 	req.ExtPageType = ExtPageType;
30029b76e53SScott Long 	req.Header.PageNumber = PageNumber;
30129b76e53SScott Long 	req.PageAddress = PageAddress;
30229b76e53SScott Long 
30329b76e53SScott Long 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
30429b76e53SScott Long 	    NULL, 0, NULL, 0, 30))
30529b76e53SScott Long 		return (errno);
30629b76e53SScott Long 
30729b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
30829b76e53SScott Long 		if (IOCStatus != NULL)
30929b76e53SScott Long 			*IOCStatus = reply.IOCStatus;
31029b76e53SScott Long 		return (EIO);
31129b76e53SScott Long 	}
31229b76e53SScott Long 	if ((header == NULL) || (ExtPageLength == NULL))
31329b76e53SScott Long 		return (EINVAL);
31429b76e53SScott Long 	*header = reply.Header;
31529b76e53SScott Long 	*ExtPageLength = reply.ExtPageLength;
31629b76e53SScott Long 	return (0);
31729b76e53SScott Long }
31829b76e53SScott Long 
31929b76e53SScott Long void *
32029b76e53SScott Long mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
32129b76e53SScott Long     U16 *IOCStatus)
32229b76e53SScott Long {
32329b76e53SScott Long 	MPI2_CONFIG_REQUEST req;
32429b76e53SScott Long 	MPI2_CONFIG_PAGE_HEADER header;
32529b76e53SScott Long 	MPI2_CONFIG_REPLY reply;
32629b76e53SScott Long 	void *buf;
32729b76e53SScott Long 	int error, len;
32829b76e53SScott Long 
32929b76e53SScott Long 	bzero(&header, sizeof(header));
33029b76e53SScott Long 	error = mps_read_config_page_header(fd, PageType, PageNumber,
33129b76e53SScott Long 	    PageAddress, &header, IOCStatus);
33229b76e53SScott Long 	if (error) {
33329b76e53SScott Long 		errno = error;
33429b76e53SScott Long 		return (NULL);
33529b76e53SScott Long 	}
33629b76e53SScott Long 
33729b76e53SScott Long 	bzero(&req, sizeof(req));
33829b76e53SScott Long 	req.Function = MPI2_FUNCTION_CONFIG;
33929b76e53SScott Long 	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
34029b76e53SScott Long 	req.PageAddress = PageAddress;
34129b76e53SScott Long 	req.Header = header;
34229b76e53SScott Long 	req.Header.PageLength = reply.Header.PageLength;
34329b76e53SScott Long 	if (reply.Header.PageLength == 0)
34429b76e53SScott Long 		req.Header.PageLength = 4;
34529b76e53SScott Long 
34629b76e53SScott Long 	len = req.Header.PageLength * 4;
34729b76e53SScott Long 	buf = malloc(len);
34829b76e53SScott Long 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
34929b76e53SScott Long 	    buf, len, NULL, 0, 30)) {
35029b76e53SScott Long 		error = errno;
35129b76e53SScott Long 		free(buf);
35229b76e53SScott Long 		errno = error;
35329b76e53SScott Long 		return (NULL);
35429b76e53SScott Long 	}
35529b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
35629b76e53SScott Long 		if (IOCStatus != NULL)
35729b76e53SScott Long 			*IOCStatus = reply.IOCStatus;
35829b76e53SScott Long 		else
35929b76e53SScott Long 			warnx("Reading config page failed: 0x%x %s",
36029b76e53SScott Long 			    reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
36129b76e53SScott Long 		free(buf);
36229b76e53SScott Long 		errno = EIO;
36329b76e53SScott Long 		return (NULL);
36429b76e53SScott Long 	}
36529b76e53SScott Long 	return (buf);
36629b76e53SScott Long }
36729b76e53SScott Long 
36829b76e53SScott Long void *
36929b76e53SScott Long mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
37029b76e53SScott Long     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
37129b76e53SScott Long {
37229b76e53SScott Long 	MPI2_CONFIG_REQUEST req;
37329b76e53SScott Long 	MPI2_CONFIG_PAGE_HEADER header;
37429b76e53SScott Long 	MPI2_CONFIG_REPLY reply;
37529b76e53SScott Long 	U16 pagelen;
37629b76e53SScott Long 	void *buf;
37729b76e53SScott Long 	int error, len;
37829b76e53SScott Long 
37929b76e53SScott Long 	if (IOCStatus != NULL)
38029b76e53SScott Long 		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
38129b76e53SScott Long 	bzero(&header, sizeof(header));
38229b76e53SScott Long 	error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
38329b76e53SScott Long 	    PageAddress, &header, &pagelen, IOCStatus);
38429b76e53SScott Long 	if (error) {
38529b76e53SScott Long 		errno = error;
38629b76e53SScott Long 		return (NULL);
38729b76e53SScott Long 	}
38829b76e53SScott Long 
38929b76e53SScott Long 	bzero(&req, sizeof(req));
39029b76e53SScott Long 	req.Function = MPI2_FUNCTION_CONFIG;
39129b76e53SScott Long 	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
39229b76e53SScott Long 	req.PageAddress = PageAddress;
39329b76e53SScott Long 	req.Header = header;
39429b76e53SScott Long 	if (pagelen == 0)
39529b76e53SScott Long 		pagelen = 4;
39629b76e53SScott Long 	req.ExtPageLength = pagelen;
39729b76e53SScott Long 	req.ExtPageType = ExtPageType;
39829b76e53SScott Long 
39929b76e53SScott Long 	len = pagelen * 4;
40029b76e53SScott Long 	buf = malloc(len);
40129b76e53SScott Long 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
40229b76e53SScott Long 	    buf, len, NULL, 0, 30)) {
40329b76e53SScott Long 		error = errno;
40429b76e53SScott Long 		free(buf);
40529b76e53SScott Long 		errno = error;
40629b76e53SScott Long 		return (NULL);
40729b76e53SScott Long 	}
40829b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
40929b76e53SScott Long 		if (IOCStatus != NULL)
41029b76e53SScott Long 			*IOCStatus = reply.IOCStatus;
41129b76e53SScott Long 		else
41229b76e53SScott Long 			warnx("Reading extended config page failed: %s",
41329b76e53SScott Long 			    mps_ioc_status(reply.IOCStatus));
41429b76e53SScott Long 		free(buf);
41529b76e53SScott Long 		errno = EIO;
41629b76e53SScott Long 		return (NULL);
41729b76e53SScott Long 	}
41829b76e53SScott Long 	return (buf);
41929b76e53SScott Long }
42029b76e53SScott Long 
42129b76e53SScott Long #else
42229b76e53SScott Long 
42329b76e53SScott Long int
42429b76e53SScott Long mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
42529b76e53SScott Long     MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
42629b76e53SScott Long {
42729b76e53SScott Long 	struct mps_cfg_page_req req;
42829b76e53SScott Long 
42929b76e53SScott Long 	if (IOCStatus != NULL)
43029b76e53SScott Long 		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
43129b76e53SScott Long 	if (header == NULL)
43229b76e53SScott Long 		return (EINVAL);
43329b76e53SScott Long 	bzero(&req, sizeof(req));
43429b76e53SScott Long 	req.header.PageType = PageType;
43529b76e53SScott Long 	req.header.PageNumber = PageNumber;
43629b76e53SScott Long 	req.page_address = PageAddress;
43729b76e53SScott Long 	if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
43829b76e53SScott Long 		return (errno);
43929b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
44029b76e53SScott Long 		if (IOCStatus != NULL)
44129b76e53SScott Long 			*IOCStatus = req.ioc_status;
44229b76e53SScott Long 		return (EIO);
44329b76e53SScott Long 	}
44429b76e53SScott Long 	bcopy(&req.header, header, sizeof(*header));
44529b76e53SScott Long 	return (0);
44629b76e53SScott Long }
44729b76e53SScott Long 
44829b76e53SScott Long void *
44929b76e53SScott Long mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
45029b76e53SScott Long     U16 *IOCStatus)
45129b76e53SScott Long {
45229b76e53SScott Long 	struct mps_cfg_page_req req;
45329b76e53SScott Long 	void *buf;
45429b76e53SScott Long 	int error;
45529b76e53SScott Long 
45629b76e53SScott Long 	error = mps_read_config_page_header(fd, PageType, PageNumber,
45729b76e53SScott Long 	    PageAddress, &req.header, IOCStatus);
45829b76e53SScott Long 	if (error) {
45929b76e53SScott Long 		errno = error;
46029b76e53SScott Long 		return (NULL);
46129b76e53SScott Long 	}
46229b76e53SScott Long 
46329b76e53SScott Long 	if (req.header.PageLength == 0)
46429b76e53SScott Long 		req.header.PageLength = 4;
46529b76e53SScott Long 	req.len = req.header.PageLength * 4;
46629b76e53SScott Long 	buf = malloc(req.len);
46729b76e53SScott Long 	req.buf = buf;
46829b76e53SScott Long 	bcopy(&req.header, buf, sizeof(req.header));
46929b76e53SScott Long 	if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
47029b76e53SScott Long 		error = errno;
47129b76e53SScott Long 		free(buf);
47229b76e53SScott Long 		errno = error;
47329b76e53SScott Long 		return (NULL);
47429b76e53SScott Long 	}
47529b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
47629b76e53SScott Long 		if (IOCStatus != NULL)
47729b76e53SScott Long 			*IOCStatus = req.ioc_status;
47829b76e53SScott Long 		else
47929b76e53SScott Long 			warnx("Reading config page failed: 0x%x %s",
48029b76e53SScott Long 			    req.ioc_status, mps_ioc_status(req.ioc_status));
48129b76e53SScott Long 		free(buf);
48229b76e53SScott Long 		errno = EIO;
48329b76e53SScott Long 		return (NULL);
48429b76e53SScott Long 	}
48529b76e53SScott Long 	return (buf);
48629b76e53SScott Long }
48729b76e53SScott Long 
48829b76e53SScott Long void *
48929b76e53SScott Long mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
49029b76e53SScott Long     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
49129b76e53SScott Long {
49229b76e53SScott Long 	struct mps_ext_cfg_page_req req;
49329b76e53SScott Long 	void *buf;
49429b76e53SScott Long 	int error;
49529b76e53SScott Long 
49629b76e53SScott Long 	if (IOCStatus != NULL)
49729b76e53SScott Long 		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
49829b76e53SScott Long 	bzero(&req, sizeof(req));
49929b76e53SScott Long 	req.header.PageVersion = PageVersion;
50029b76e53SScott Long 	req.header.PageNumber = PageNumber;
50129b76e53SScott Long 	req.header.ExtPageType = ExtPageType;
50229b76e53SScott Long 	req.page_address = PageAddress;
50329b76e53SScott Long 	if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
50429b76e53SScott Long 		return (NULL);
50529b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
50629b76e53SScott Long 		if (IOCStatus != NULL)
50729b76e53SScott Long 			*IOCStatus = req.ioc_status;
50829b76e53SScott Long 		else
50929b76e53SScott Long 			warnx("Reading extended config page header failed: %s",
51029b76e53SScott Long 			    mps_ioc_status(req.ioc_status));
51129b76e53SScott Long 		errno = EIO;
51229b76e53SScott Long 		return (NULL);
51329b76e53SScott Long 	}
51429b76e53SScott Long 	req.len = req.header.ExtPageLength * 4;
51529b76e53SScott Long 	buf = malloc(req.len);
51629b76e53SScott Long 	req.buf = buf;
51729b76e53SScott Long 	bcopy(&req.header, buf, sizeof(req.header));
51829b76e53SScott Long 	if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
51929b76e53SScott Long 		error = errno;
52029b76e53SScott Long 		free(buf);
52129b76e53SScott Long 		errno = error;
52229b76e53SScott Long 		return (NULL);
52329b76e53SScott Long 	}
52429b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
52529b76e53SScott Long 		if (IOCStatus != NULL)
52629b76e53SScott Long 			*IOCStatus = req.ioc_status;
52729b76e53SScott Long 		else
52829b76e53SScott Long 			warnx("Reading extended config page failed: %s",
52929b76e53SScott Long 			    mps_ioc_status(req.ioc_status));
53029b76e53SScott Long 		free(buf);
53129b76e53SScott Long 		errno = EIO;
53229b76e53SScott Long 		return (NULL);
53329b76e53SScott Long 	}
53429b76e53SScott Long 	return (buf);
53529b76e53SScott Long }
53629b76e53SScott Long #endif
53729b76e53SScott Long 
53829b76e53SScott Long #if 0
53929b76e53SScott Long int
54029b76e53SScott Long mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
54129b76e53SScott Long {
54229b76e53SScott Long 	CONFIG_PAGE_HEADER *hdr;
54329b76e53SScott Long 	struct mpt_cfg_page_req req;
54429b76e53SScott Long 
54529b76e53SScott Long 	if (IOCStatus != NULL)
54629b76e53SScott Long 		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
54729b76e53SScott Long 	bzero(&req, sizeof(req));
54829b76e53SScott Long 	req.buf = buf;
54929b76e53SScott Long 	hdr = buf;
55029b76e53SScott Long 	req.len = hdr->PageLength * 4;
55129b76e53SScott Long 	if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
55229b76e53SScott Long 		return (errno);
55329b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
55429b76e53SScott Long 		if (IOCStatus != NULL) {
55529b76e53SScott Long 			*IOCStatus = req.ioc_status;
55629b76e53SScott Long 			return (0);
55729b76e53SScott Long 		}
55829b76e53SScott Long 		warnx("Writing config page failed: %s",
55929b76e53SScott Long 		    mpt_ioc_status(req.ioc_status));
56029b76e53SScott Long 		return (EIO);
56129b76e53SScott Long 	}
56229b76e53SScott Long 	return (0);
56329b76e53SScott Long }
56429b76e53SScott Long 
56529b76e53SScott Long int
56629b76e53SScott Long mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
56729b76e53SScott Long     U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
56829b76e53SScott Long     U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
56929b76e53SScott Long {
57029b76e53SScott Long 	struct mpt_raid_action raid_act;
57129b76e53SScott Long 
57229b76e53SScott Long 	if (IOCStatus != NULL)
57329b76e53SScott Long 		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
57429b76e53SScott Long 	if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
57529b76e53SScott Long 		return (EINVAL);
57629b76e53SScott Long 	bzero(&raid_act, sizeof(raid_act));
57729b76e53SScott Long 	raid_act.action = Action;
57829b76e53SScott Long 	raid_act.volume_bus = VolumeBus;
57929b76e53SScott Long 	raid_act.volume_id = VolumeID;
58029b76e53SScott Long 	raid_act.phys_disk_num = PhysDiskNum;
58129b76e53SScott Long 	raid_act.action_data_word = ActionDataWord;
58229b76e53SScott Long 	if (buf != NULL && len != 0) {
58329b76e53SScott Long 		raid_act.buf = buf;
58429b76e53SScott Long 		raid_act.len = len;
58529b76e53SScott Long 		raid_act.write = write;
58629b76e53SScott Long 	}
58729b76e53SScott Long 
58829b76e53SScott Long 	if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
58929b76e53SScott Long 		return (errno);
59029b76e53SScott Long 
59129b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
59229b76e53SScott Long 		if (IOCStatus != NULL) {
59329b76e53SScott Long 			*IOCStatus = raid_act.ioc_status;
59429b76e53SScott Long 			return (0);
59529b76e53SScott Long 		}
59629b76e53SScott Long 		warnx("RAID action failed: %s",
59729b76e53SScott Long 		    mpt_ioc_status(raid_act.ioc_status));
59829b76e53SScott Long 		return (EIO);
59929b76e53SScott Long 	}
60029b76e53SScott Long 
60129b76e53SScott Long 	if (ActionStatus != NULL)
60229b76e53SScott Long 		*ActionStatus = raid_act.action_status;
60329b76e53SScott Long 	if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
60429b76e53SScott Long 		if (ActionStatus != NULL)
60529b76e53SScott Long 			return (0);
60629b76e53SScott Long 		warnx("RAID action failed: %s",
60729b76e53SScott Long 		    mpt_raid_status(raid_act.action_status));
60829b76e53SScott Long 		return (EIO);
60929b76e53SScott Long 	}
61029b76e53SScott Long 
61129b76e53SScott Long 	if (VolumeStatus != NULL)
61229b76e53SScott Long 		*((U32 *)VolumeStatus) = raid_act.volume_status;
61329b76e53SScott Long 	if (ActionData != NULL)
61429b76e53SScott Long 		bcopy(raid_act.action_data, ActionData, datalen);
61529b76e53SScott Long 	return (0);
61629b76e53SScott Long }
61729b76e53SScott Long #endif
61829b76e53SScott Long 
61929b76e53SScott Long int
62029b76e53SScott Long mps_open(int unit)
62129b76e53SScott Long {
62229b76e53SScott Long 	char path[MAXPATHLEN];
62329b76e53SScott Long 
62448f31f4fSBaptiste Daroussin 	snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
62529b76e53SScott Long 	return (open(path, O_RDWR));
62629b76e53SScott Long }
62729b76e53SScott Long 
62829b76e53SScott Long int
62929b76e53SScott Long mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
63029b76e53SScott Long         uint32_t reply_len, void *buffer, int len, uint32_t flags)
63129b76e53SScott Long {
63229b76e53SScott Long 	struct mps_usr_command cmd;
63329b76e53SScott Long 
63429b76e53SScott Long 	bzero(&cmd, sizeof(struct mps_usr_command));
63529b76e53SScott Long 	cmd.req = req;
63629b76e53SScott Long 	cmd.req_len = req_len;
63729b76e53SScott Long 	cmd.rpl = reply;
63829b76e53SScott Long 	cmd.rpl_len = reply_len;
63929b76e53SScott Long 	cmd.buf = buffer;
64029b76e53SScott Long 	cmd.len = len;
64129b76e53SScott Long 	cmd.flags = flags;
64229b76e53SScott Long 
64329b76e53SScott Long 	if (ioctl(fd, MPSIO_MPS_COMMAND, &cmd) < 0)
64429b76e53SScott Long 		return (errno);
64529b76e53SScott Long 	return (0);
64629b76e53SScott Long }
64729b76e53SScott Long 
64829b76e53SScott Long int
64929b76e53SScott Long mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
65029b76e53SScott Long 	uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
65129b76e53SScott Long 	uint32_t dataout_len, uint32_t timeout)
65229b76e53SScott Long {
65329b76e53SScott Long 	struct mps_pass_thru pass;
65429b76e53SScott Long 
65529b76e53SScott Long 	pass.PtrRequest = (uint64_t)(uintptr_t)req;
65629b76e53SScott Long 	pass.PtrReply = (uint64_t)(uintptr_t)reply;
65729b76e53SScott Long 	pass.PtrData = (uint64_t)(uintptr_t)data_in;
65829b76e53SScott Long 	pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
65929b76e53SScott Long 	pass.RequestSize = req_len;
66029b76e53SScott Long 	pass.ReplySize = reply_len;
66129b76e53SScott Long 	pass.DataSize = datain_len;
66229b76e53SScott Long 	pass.DataOutSize = dataout_len;
66329b76e53SScott Long 	if (datain_len && dataout_len)
66429b76e53SScott Long 		pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
66529b76e53SScott Long 	else if (datain_len)
66629b76e53SScott Long 		pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
66729b76e53SScott Long 	else if (dataout_len)
66829b76e53SScott Long 		pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
66929b76e53SScott Long 	else
67029b76e53SScott Long 		pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
67129b76e53SScott Long 	pass.Timeout = timeout;
67229b76e53SScott Long 
67329b76e53SScott Long 	if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
67429b76e53SScott Long 		return (errno);
67529b76e53SScott Long 	return (0);
67629b76e53SScott Long }
67729b76e53SScott Long 
67829b76e53SScott Long MPI2_IOC_FACTS_REPLY *
67929b76e53SScott Long mps_get_iocfacts(int fd)
68029b76e53SScott Long {
68129b76e53SScott Long 	MPI2_IOC_FACTS_REPLY *facts;
68229b76e53SScott Long 	MPI2_IOC_FACTS_REQUEST req;
68329b76e53SScott Long 	int error;
68429b76e53SScott Long 
68529b76e53SScott Long 	facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
68629b76e53SScott Long 	if (facts == NULL) {
68729b76e53SScott Long 		errno = ENOMEM;
68829b76e53SScott Long 		return (NULL);
68929b76e53SScott Long 	}
69029b76e53SScott Long 
69129b76e53SScott Long 	bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
69229b76e53SScott Long 	req.Function = MPI2_FUNCTION_IOC_FACTS;
69329b76e53SScott Long 
69429b76e53SScott Long #if 1
69529b76e53SScott Long 	error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
69629b76e53SScott Long 	    facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
69729b76e53SScott Long #else
69829b76e53SScott Long 	error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
69929b76e53SScott Long 	    facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
70029b76e53SScott Long #endif
70129b76e53SScott Long 	if (error) {
70229b76e53SScott Long 		free(facts);
70329b76e53SScott Long 		return (NULL);
70429b76e53SScott Long 	}
70529b76e53SScott Long 
70629b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
70729b76e53SScott Long 		free(facts);
70829b76e53SScott Long 		errno = EINVAL;
70929b76e53SScott Long 		return (NULL);
71029b76e53SScott Long 	}
71129b76e53SScott Long 	return (facts);
71229b76e53SScott Long }
71329b76e53SScott Long 
714