xref: /freebsd/usr.sbin/mpsutil/mps_cmd.c (revision 4d65a7c6)
129b76e53SScott Long /*-
23e891891SBaptiste Daroussin  * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
33e891891SBaptiste Daroussin  *
4883bb7e9SScott Long  * Copyright (c) 2015 Netflix, Inc.
5883bb7e9SScott Long  * Written by: Scott Long <scottl@freebsd.org>
6883bb7e9SScott Long  *
729b76e53SScott Long  * Copyright (c) 2008 Yahoo!, Inc.
829b76e53SScott Long  * All rights reserved.
929b76e53SScott Long  * Written by: John Baldwin <jhb@FreeBSD.org>
1029b76e53SScott Long  *
1129b76e53SScott Long  * Redistribution and use in source and binary forms, with or without
1229b76e53SScott Long  * modification, are permitted provided that the following conditions
1329b76e53SScott Long  * are met:
1429b76e53SScott Long  * 1. Redistributions of source code must retain the above copyright
1529b76e53SScott Long  *    notice, this list of conditions and the following disclaimer.
1629b76e53SScott Long  * 2. Redistributions in binary form must reproduce the above copyright
1729b76e53SScott Long  *    notice, this list of conditions and the following disclaimer in the
1829b76e53SScott Long  *    documentation and/or other materials provided with the distribution.
1929b76e53SScott Long  * 3. Neither the name of the author nor the names of any co-contributors
2029b76e53SScott Long  *    may be used to endorse or promote products derived from this software
2129b76e53SScott Long  *    without specific prior written permission.
2229b76e53SScott Long  *
2329b76e53SScott Long  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2429b76e53SScott Long  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2529b76e53SScott Long  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2629b76e53SScott Long  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2729b76e53SScott Long  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2829b76e53SScott Long  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2929b76e53SScott Long  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3029b76e53SScott Long  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3129b76e53SScott Long  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3229b76e53SScott Long  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3329b76e53SScott Long  * SUCH DAMAGE.
3429b76e53SScott Long  */
3529b76e53SScott Long 
3629b76e53SScott Long #include <sys/param.h>
3729b76e53SScott Long #include <sys/errno.h>
3829b76e53SScott Long #include <sys/ioctl.h>
3929b76e53SScott Long #include <sys/sysctl.h>
4029b76e53SScott Long #include <sys/uio.h>
41fc9780fdSAlfredo Dal'Ava Junior #include <sys/endian.h>
4229b76e53SScott Long 
4329b76e53SScott Long #include <err.h>
4429b76e53SScott Long #include <fcntl.h>
4529b76e53SScott Long #include <stdio.h>
4629b76e53SScott Long #include <stdlib.h>
4729b76e53SScott Long #include <string.h>
4829b76e53SScott Long #include <unistd.h>
4929b76e53SScott Long 
5029b76e53SScott Long #include "mpsutil.h"
5139e2d6bcSScott Long #include <dev/mps/mps_ioctl.h>
5239e2d6bcSScott Long #include <dev/mpr/mpr_ioctl.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 
2225a92b271SBaptiste Daroussin struct mprs_pass_thru {
2235a92b271SBaptiste Daroussin         uint64_t        PtrRequest;
2245a92b271SBaptiste Daroussin         uint64_t        PtrReply;
2255a92b271SBaptiste Daroussin         uint64_t        PtrData;
2265a92b271SBaptiste Daroussin         uint32_t        RequestSize;
2275a92b271SBaptiste Daroussin         uint32_t        ReplySize;
2285a92b271SBaptiste Daroussin         uint32_t        DataSize;
2295a92b271SBaptiste Daroussin         uint32_t        DataDirection;
2305a92b271SBaptiste Daroussin         uint64_t        PtrDataOut;
2315a92b271SBaptiste Daroussin         uint32_t        DataOutSize;
2325a92b271SBaptiste Daroussin         uint32_t        Timeout;
2335a92b271SBaptiste Daroussin };
2345a92b271SBaptiste Daroussin 
2355a92b271SBaptiste Daroussin struct mprs_btdh_mapping {
2365a92b271SBaptiste Daroussin         uint16_t        TargetID;
2375a92b271SBaptiste Daroussin         uint16_t        Bus;
2385a92b271SBaptiste Daroussin         uint16_t        DevHandle;
2395a92b271SBaptiste Daroussin         uint16_t        Reserved;
2405a92b271SBaptiste Daroussin };
2415a92b271SBaptiste Daroussin 
242fc9780fdSAlfredo Dal'Ava Junior static void adjust_iocfacts_endianness(MPI2_IOC_FACTS_REPLY *facts);
243fc9780fdSAlfredo Dal'Ava Junior 
24429b76e53SScott Long const char *
mps_ioc_status(U16 IOCStatus)24529b76e53SScott Long mps_ioc_status(U16 IOCStatus)
24629b76e53SScott Long {
24729b76e53SScott Long 	static char buffer[16];
24829b76e53SScott Long 
24929b76e53SScott Long 	IOCStatus &= MPI2_IOCSTATUS_MASK;
25029b76e53SScott Long 	if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
25129b76e53SScott Long 	    mps_ioc_status_codes[IOCStatus] != NULL)
25229b76e53SScott Long 		return (mps_ioc_status_codes[IOCStatus]);
25329b76e53SScott Long 	snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
25429b76e53SScott Long 	return (buffer);
25529b76e53SScott Long }
25629b76e53SScott Long 
25729b76e53SScott Long #ifdef USE_MPT_IOCTLS
25829b76e53SScott Long int
mps_map_btdh(int fd,uint16_t * devhandle,uint16_t * bus,uint16_t * target)25929b76e53SScott Long mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
26029b76e53SScott Long {
26129b76e53SScott Long 	int error;
2625a92b271SBaptiste Daroussin 	struct mprs_btdh_mapping map;
26329b76e53SScott Long 
26429b76e53SScott Long 	map.Bus = *bus;
26529b76e53SScott Long 	map.TargetID = *target;
26629b76e53SScott Long 	map.DevHandle = *devhandle;
26729b76e53SScott Long 
26829b76e53SScott Long 	if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
26929b76e53SScott Long 		error = errno;
27029b76e53SScott Long 		warn("Failed to map bus/target/device");
27129b76e53SScott Long 		return (error);
27229b76e53SScott Long 	}
27329b76e53SScott Long 
27429b76e53SScott Long 	*bus = map.Bus;
27529b76e53SScott Long 	*target = map.TargetID;
27629b76e53SScott Long 	*devhandle = map.DevHandle;
27729b76e53SScott Long 
27829b76e53SScott Long 	return (0);
27929b76e53SScott Long }
28029b76e53SScott Long 
28129b76e53SScott Long int
mps_set_slot_status(int fd,U16 handle,U16 slot,U32 status)282c2a13d6fSAndriy Gapon mps_set_slot_status(int fd, U16 handle, U16 slot, U32 status)
283c2a13d6fSAndriy Gapon {
284c2a13d6fSAndriy Gapon 	MPI2_SEP_REQUEST req;
285c2a13d6fSAndriy Gapon 	MPI2_SEP_REPLY reply;
286c2a13d6fSAndriy Gapon 
287c2a13d6fSAndriy Gapon 	bzero(&req, sizeof(req));
288c2a13d6fSAndriy Gapon 	req.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
289c2a13d6fSAndriy Gapon 	req.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
290c2a13d6fSAndriy Gapon 	req.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS;
291c2a13d6fSAndriy Gapon 	req.EnclosureHandle = handle;
292c2a13d6fSAndriy Gapon 	req.Slot = slot;
293c2a13d6fSAndriy Gapon 	req.SlotStatus = status;
294c2a13d6fSAndriy Gapon 
295c2a13d6fSAndriy Gapon 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
296c2a13d6fSAndriy Gapon 	    NULL, 0, NULL, 0, 30) != 0)
297c2a13d6fSAndriy Gapon 		return (errno);
298c2a13d6fSAndriy Gapon 
299fc9780fdSAlfredo Dal'Ava Junior 	if (!IOC_STATUS_SUCCESS(le16toh(reply.IOCStatus)))
300c2a13d6fSAndriy Gapon 		return (EIO);
301c2a13d6fSAndriy Gapon 	return (0);
302c2a13d6fSAndriy Gapon }
303c2a13d6fSAndriy Gapon 
304c2a13d6fSAndriy Gapon int
mps_read_config_page_header(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,MPI2_CONFIG_PAGE_HEADER * header,U16 * IOCStatus)30529b76e53SScott Long mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
30629b76e53SScott Long     MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
30729b76e53SScott Long {
30829b76e53SScott Long 	MPI2_CONFIG_REQUEST req;
30929b76e53SScott Long 	MPI2_CONFIG_REPLY reply;
31029b76e53SScott Long 
31129b76e53SScott Long 	bzero(&req, sizeof(req));
31229b76e53SScott Long 	req.Function = MPI2_FUNCTION_CONFIG;
31329b76e53SScott Long 	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
31429b76e53SScott Long 	req.Header.PageType = PageType;
31529b76e53SScott Long 	req.Header.PageNumber = PageNumber;
31629b76e53SScott Long 	req.PageAddress = PageAddress;
31729b76e53SScott Long 
31829b76e53SScott Long 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
31929b76e53SScott Long 	    NULL, 0, NULL, 0, 30))
32029b76e53SScott Long 		return (errno);
32129b76e53SScott Long 
322fc9780fdSAlfredo Dal'Ava Junior 	if (!IOC_STATUS_SUCCESS(le16toh(reply.IOCStatus))) {
32329b76e53SScott Long 		if (IOCStatus != NULL)
32429b76e53SScott Long 			*IOCStatus = reply.IOCStatus;
32529b76e53SScott Long 		return (EIO);
32629b76e53SScott Long 	}
32729b76e53SScott Long 	if (header == NULL)
32829b76e53SScott Long 		return (EINVAL);
32929b76e53SScott Long 	*header = reply.Header;
33029b76e53SScott Long 	return (0);
33129b76e53SScott Long }
33229b76e53SScott Long 
33329b76e53SScott Long int
mps_read_ext_config_page_header(int fd,U8 ExtPageType,U8 PageNumber,U32 PageAddress,MPI2_CONFIG_PAGE_HEADER * header,U16 * ExtPageLength,U16 * IOCStatus)33429b76e53SScott Long mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
33529b76e53SScott Long {
33629b76e53SScott Long 	MPI2_CONFIG_REQUEST req;
33729b76e53SScott Long 	MPI2_CONFIG_REPLY reply;
33829b76e53SScott Long 
33929b76e53SScott Long 	bzero(&req, sizeof(req));
34029b76e53SScott Long 	req.Function = MPI2_FUNCTION_CONFIG;
34129b76e53SScott Long 	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
34229b76e53SScott Long 	req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
34329b76e53SScott Long 	req.ExtPageType = ExtPageType;
34429b76e53SScott Long 	req.Header.PageNumber = PageNumber;
345fc9780fdSAlfredo Dal'Ava Junior 	req.PageAddress = htole32(PageAddress);
34629b76e53SScott Long 
34729b76e53SScott Long 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
34829b76e53SScott Long 	    NULL, 0, NULL, 0, 30))
34929b76e53SScott Long 		return (errno);
35029b76e53SScott Long 
351fc9780fdSAlfredo Dal'Ava Junior 	if (!IOC_STATUS_SUCCESS(le16toh(reply.IOCStatus))) {
35229b76e53SScott Long 		if (IOCStatus != NULL)
353fc9780fdSAlfredo Dal'Ava Junior 			*IOCStatus = le16toh(reply.IOCStatus);
35429b76e53SScott Long 		return (EIO);
35529b76e53SScott Long 	}
35629b76e53SScott Long 	if ((header == NULL) || (ExtPageLength == NULL))
35729b76e53SScott Long 		return (EINVAL);
35829b76e53SScott Long 	*header = reply.Header;
35929b76e53SScott Long 	*ExtPageLength = reply.ExtPageLength;
36029b76e53SScott Long 	return (0);
36129b76e53SScott Long }
36229b76e53SScott Long 
36329b76e53SScott Long void *
mps_read_config_page(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)36429b76e53SScott Long mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
36529b76e53SScott Long     U16 *IOCStatus)
36629b76e53SScott Long {
36729b76e53SScott Long 	MPI2_CONFIG_REQUEST req;
36829b76e53SScott Long 	MPI2_CONFIG_PAGE_HEADER header;
36929b76e53SScott Long 	MPI2_CONFIG_REPLY reply;
37029b76e53SScott Long 	void *buf;
37129b76e53SScott Long 	int error, len;
37229b76e53SScott Long 
37329b76e53SScott Long 	bzero(&header, sizeof(header));
37429b76e53SScott Long 	error = mps_read_config_page_header(fd, PageType, PageNumber,
37529b76e53SScott Long 	    PageAddress, &header, IOCStatus);
37629b76e53SScott Long 	if (error) {
37729b76e53SScott Long 		errno = error;
37829b76e53SScott Long 		return (NULL);
37929b76e53SScott Long 	}
38029b76e53SScott Long 
38129b76e53SScott Long 	bzero(&req, sizeof(req));
38229b76e53SScott Long 	req.Function = MPI2_FUNCTION_CONFIG;
38329b76e53SScott Long 	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
384fc9780fdSAlfredo Dal'Ava Junior 	req.PageAddress = htole32(PageAddress);
38529b76e53SScott Long 	req.Header = header;
38699cc4d51SScott Long 	if (req.Header.PageLength == 0)
38729b76e53SScott Long 		req.Header.PageLength = 4;
38829b76e53SScott Long 
38929b76e53SScott Long 	len = req.Header.PageLength * 4;
39029b76e53SScott Long 	buf = malloc(len);
39129b76e53SScott Long 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
39229b76e53SScott Long 	    buf, len, NULL, 0, 30)) {
39329b76e53SScott Long 		error = errno;
39429b76e53SScott Long 		free(buf);
39529b76e53SScott Long 		errno = error;
39629b76e53SScott Long 		return (NULL);
39729b76e53SScott Long 	}
398fc9780fdSAlfredo Dal'Ava Junior 	reply.IOCStatus = le16toh(reply.IOCStatus);
39929b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
40029b76e53SScott Long 		if (IOCStatus != NULL)
40129b76e53SScott Long 			*IOCStatus = reply.IOCStatus;
40229b76e53SScott Long 		else
40329b76e53SScott Long 			warnx("Reading config page failed: 0x%x %s",
40429b76e53SScott Long 			    reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
40529b76e53SScott Long 		free(buf);
40629b76e53SScott Long 		errno = EIO;
40729b76e53SScott Long 		return (NULL);
40829b76e53SScott Long 	}
40929b76e53SScott Long 	return (buf);
41029b76e53SScott Long }
41129b76e53SScott Long 
41229b76e53SScott Long void *
mps_read_extended_config_page(int fd,U8 ExtPageType,U8 PageVersion,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)41329b76e53SScott Long mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
41429b76e53SScott Long     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
41529b76e53SScott Long {
41629b76e53SScott Long 	MPI2_CONFIG_REQUEST req;
41729b76e53SScott Long 	MPI2_CONFIG_PAGE_HEADER header;
41829b76e53SScott Long 	MPI2_CONFIG_REPLY reply;
41929b76e53SScott Long 	U16 pagelen;
42029b76e53SScott Long 	void *buf;
42129b76e53SScott Long 	int error, len;
42229b76e53SScott Long 
42329b76e53SScott Long 	if (IOCStatus != NULL)
42429b76e53SScott Long 		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
42529b76e53SScott Long 	bzero(&header, sizeof(header));
42629b76e53SScott Long 	error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
42729b76e53SScott Long 	    PageAddress, &header, &pagelen, IOCStatus);
42829b76e53SScott Long 	if (error) {
42929b76e53SScott Long 		errno = error;
43029b76e53SScott Long 		return (NULL);
43129b76e53SScott Long 	}
43229b76e53SScott Long 
43329b76e53SScott Long 	bzero(&req, sizeof(req));
43429b76e53SScott Long 	req.Function = MPI2_FUNCTION_CONFIG;
43529b76e53SScott Long 	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
436fc9780fdSAlfredo Dal'Ava Junior 	req.PageAddress = htole32(PageAddress);
43729b76e53SScott Long 	req.Header = header;
43829b76e53SScott Long 	if (pagelen == 0)
439fc9780fdSAlfredo Dal'Ava Junior 		pagelen = htole16(4);
44029b76e53SScott Long 	req.ExtPageLength = pagelen;
44129b76e53SScott Long 	req.ExtPageType = ExtPageType;
44229b76e53SScott Long 
443fc9780fdSAlfredo Dal'Ava Junior 	len = le16toh(pagelen) * 4;
44429b76e53SScott Long 	buf = malloc(len);
44529b76e53SScott Long 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
44629b76e53SScott Long 	    buf, len, NULL, 0, 30)) {
44729b76e53SScott Long 		error = errno;
44829b76e53SScott Long 		free(buf);
44929b76e53SScott Long 		errno = error;
45029b76e53SScott Long 		return (NULL);
45129b76e53SScott Long 	}
452fc9780fdSAlfredo Dal'Ava Junior 	reply.IOCStatus = le16toh(reply.IOCStatus);
45329b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
45429b76e53SScott Long 		if (IOCStatus != NULL)
45529b76e53SScott Long 			*IOCStatus = reply.IOCStatus;
45629b76e53SScott Long 		else
45729b76e53SScott Long 			warnx("Reading extended config page failed: %s",
45829b76e53SScott Long 			    mps_ioc_status(reply.IOCStatus));
45929b76e53SScott Long 		free(buf);
46029b76e53SScott Long 		errno = EIO;
46129b76e53SScott Long 		return (NULL);
46229b76e53SScott Long 	}
46329b76e53SScott Long 	return (buf);
46429b76e53SScott Long }
46529b76e53SScott Long 
4663e891891SBaptiste Daroussin int
mps_firmware_send(int fd,unsigned char * fw,uint32_t len,bool bios)4673e891891SBaptiste Daroussin mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios)
4683e891891SBaptiste Daroussin {
4693e891891SBaptiste Daroussin 	MPI2_FW_DOWNLOAD_REQUEST req;
4703e891891SBaptiste Daroussin 	MPI2_FW_DOWNLOAD_REPLY reply;
4713e891891SBaptiste Daroussin 
4723e891891SBaptiste Daroussin 	bzero(&req, sizeof(req));
4733e891891SBaptiste Daroussin 	bzero(&reply, sizeof(reply));
4743e891891SBaptiste Daroussin 	req.Function = MPI2_FUNCTION_FW_DOWNLOAD;
4753e891891SBaptiste Daroussin 	req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
476fc9780fdSAlfredo Dal'Ava Junior 	req.TotalImageSize = htole32(len);
4773e891891SBaptiste Daroussin 	req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
4783e891891SBaptiste Daroussin 
4793e891891SBaptiste Daroussin 	if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
4803e891891SBaptiste Daroussin 	    fw, len, 0)) {
4813e891891SBaptiste Daroussin 		return (-1);
4823e891891SBaptiste Daroussin 	}
4833e891891SBaptiste Daroussin 	return (0);
4843e891891SBaptiste Daroussin }
4853e891891SBaptiste Daroussin 
4863e891891SBaptiste Daroussin int
mps_firmware_get(int fd,unsigned char ** firmware,bool bios)4873e891891SBaptiste Daroussin mps_firmware_get(int fd, unsigned char **firmware, bool bios)
4883e891891SBaptiste Daroussin {
4893e891891SBaptiste Daroussin 	MPI2_FW_UPLOAD_REQUEST req;
4903e891891SBaptiste Daroussin 	MPI2_FW_UPLOAD_REPLY reply;
4913e891891SBaptiste Daroussin 	int size;
4923e891891SBaptiste Daroussin 
4933e891891SBaptiste Daroussin 	*firmware = NULL;
4943e891891SBaptiste Daroussin 	bzero(&req, sizeof(req));
4953e891891SBaptiste Daroussin 	bzero(&reply, sizeof(reply));
4963e891891SBaptiste Daroussin 	req.Function = MPI2_FUNCTION_FW_UPLOAD;
4973e891891SBaptiste Daroussin 	req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
4983e891891SBaptiste Daroussin 
4993e891891SBaptiste Daroussin 	if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
5003e891891SBaptiste Daroussin 	    NULL, 0, 0)) {
5013e891891SBaptiste Daroussin 		return (-1);
5023e891891SBaptiste Daroussin 	}
5033e891891SBaptiste Daroussin 	if (reply.ActualImageSize == 0) {
5043e891891SBaptiste Daroussin 		return (-1);
5053e891891SBaptiste Daroussin 	}
5063e891891SBaptiste Daroussin 
507fc9780fdSAlfredo Dal'Ava Junior 	size = le32toh(reply.ActualImageSize);
5084b6fa244SPedro F. Giffuni 	*firmware = calloc(size, sizeof(unsigned char));
5093e891891SBaptiste Daroussin 	if (*firmware == NULL) {
5103e891891SBaptiste Daroussin 		warn("calloc");
5113e891891SBaptiste Daroussin 		return (-1);
5123e891891SBaptiste Daroussin 	}
5133e891891SBaptiste Daroussin 	if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
5143e891891SBaptiste Daroussin 	    *firmware, size, 0)) {
5153e891891SBaptiste Daroussin 		free(*firmware);
5163e891891SBaptiste Daroussin 		return (-1);
5173e891891SBaptiste Daroussin 	}
5183e891891SBaptiste Daroussin 
5193e891891SBaptiste Daroussin 	return (size);
5203e891891SBaptiste Daroussin }
5213e891891SBaptiste Daroussin 
52229b76e53SScott Long #else
52329b76e53SScott Long 
52429b76e53SScott Long int
mps_read_config_page_header(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,MPI2_CONFIG_PAGE_HEADER * header,U16 * IOCStatus)52529b76e53SScott Long mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
52629b76e53SScott Long     MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
52729b76e53SScott Long {
52829b76e53SScott Long 	struct mps_cfg_page_req req;
52929b76e53SScott Long 
53029b76e53SScott Long 	if (IOCStatus != NULL)
53129b76e53SScott Long 		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
53229b76e53SScott Long 	if (header == NULL)
53329b76e53SScott Long 		return (EINVAL);
53429b76e53SScott Long 	bzero(&req, sizeof(req));
53529b76e53SScott Long 	req.header.PageType = PageType;
53629b76e53SScott Long 	req.header.PageNumber = PageNumber;
53729b76e53SScott Long 	req.page_address = PageAddress;
53829b76e53SScott Long 	if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
53929b76e53SScott Long 		return (errno);
54029b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
54129b76e53SScott Long 		if (IOCStatus != NULL)
54229b76e53SScott Long 			*IOCStatus = req.ioc_status;
54329b76e53SScott Long 		return (EIO);
54429b76e53SScott Long 	}
54529b76e53SScott Long 	bcopy(&req.header, header, sizeof(*header));
54629b76e53SScott Long 	return (0);
54729b76e53SScott Long }
54829b76e53SScott Long 
54929b76e53SScott Long void *
mps_read_config_page(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)55029b76e53SScott Long mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
55129b76e53SScott Long     U16 *IOCStatus)
55229b76e53SScott Long {
55329b76e53SScott Long 	struct mps_cfg_page_req req;
55429b76e53SScott Long 	void *buf;
55529b76e53SScott Long 	int error;
55629b76e53SScott Long 
55729b76e53SScott Long 	error = mps_read_config_page_header(fd, PageType, PageNumber,
55829b76e53SScott Long 	    PageAddress, &req.header, IOCStatus);
55929b76e53SScott Long 	if (error) {
56029b76e53SScott Long 		errno = error;
56129b76e53SScott Long 		return (NULL);
56229b76e53SScott Long 	}
56329b76e53SScott Long 
56429b76e53SScott Long 	if (req.header.PageLength == 0)
56529b76e53SScott Long 		req.header.PageLength = 4;
56629b76e53SScott Long 	req.len = req.header.PageLength * 4;
56729b76e53SScott Long 	buf = malloc(req.len);
56829b76e53SScott Long 	req.buf = buf;
56929b76e53SScott Long 	bcopy(&req.header, buf, sizeof(req.header));
57029b76e53SScott Long 	if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
57129b76e53SScott Long 		error = errno;
57229b76e53SScott Long 		free(buf);
57329b76e53SScott Long 		errno = error;
57429b76e53SScott Long 		return (NULL);
57529b76e53SScott Long 	}
576fc9780fdSAlfredo Dal'Ava Junior 	req.ioc_status = le16toh(req.ioc_status);
57729b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
57829b76e53SScott Long 		if (IOCStatus != NULL)
57929b76e53SScott Long 			*IOCStatus = req.ioc_status;
58029b76e53SScott Long 		else
58129b76e53SScott Long 			warnx("Reading config page failed: 0x%x %s",
58229b76e53SScott Long 			    req.ioc_status, mps_ioc_status(req.ioc_status));
58329b76e53SScott Long 		free(buf);
58429b76e53SScott Long 		errno = EIO;
58529b76e53SScott Long 		return (NULL);
58629b76e53SScott Long 	}
58729b76e53SScott Long 	return (buf);
58829b76e53SScott Long }
58929b76e53SScott Long 
59029b76e53SScott Long void *
mps_read_extended_config_page(int fd,U8 ExtPageType,U8 PageVersion,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)59129b76e53SScott Long mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
59229b76e53SScott Long     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
59329b76e53SScott Long {
59429b76e53SScott Long 	struct mps_ext_cfg_page_req req;
59529b76e53SScott Long 	void *buf;
59629b76e53SScott Long 	int error;
59729b76e53SScott Long 
59829b76e53SScott Long 	if (IOCStatus != NULL)
59929b76e53SScott Long 		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
60029b76e53SScott Long 	bzero(&req, sizeof(req));
60129b76e53SScott Long 	req.header.PageVersion = PageVersion;
60229b76e53SScott Long 	req.header.PageNumber = PageNumber;
60329b76e53SScott Long 	req.header.ExtPageType = ExtPageType;
604fc9780fdSAlfredo Dal'Ava Junior 	req.page_address = htole32(PageAddress);
60529b76e53SScott Long 	if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
60629b76e53SScott Long 		return (NULL);
607fc9780fdSAlfredo Dal'Ava Junior 	req.ioc_status = le16toh(req.ioc_status);
60829b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
60929b76e53SScott Long 		if (IOCStatus != NULL)
61029b76e53SScott Long 			*IOCStatus = req.ioc_status;
61129b76e53SScott Long 		else
61229b76e53SScott Long 			warnx("Reading extended config page header failed: %s",
61329b76e53SScott Long 			    mps_ioc_status(req.ioc_status));
61429b76e53SScott Long 		errno = EIO;
61529b76e53SScott Long 		return (NULL);
61629b76e53SScott Long 	}
61729b76e53SScott Long 	req.len = req.header.ExtPageLength * 4;
61829b76e53SScott Long 	buf = malloc(req.len);
61929b76e53SScott Long 	req.buf = buf;
62029b76e53SScott Long 	bcopy(&req.header, buf, sizeof(req.header));
62129b76e53SScott Long 	if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
62229b76e53SScott Long 		error = errno;
62329b76e53SScott Long 		free(buf);
62429b76e53SScott Long 		errno = error;
62529b76e53SScott Long 		return (NULL);
62629b76e53SScott Long 	}
627fc9780fdSAlfredo Dal'Ava Junior 	req.ioc_status = le16toh(req.ioc_status);
62829b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
62929b76e53SScott Long 		if (IOCStatus != NULL)
63029b76e53SScott Long 			*IOCStatus = req.ioc_status;
63129b76e53SScott Long 		else
63229b76e53SScott Long 			warnx("Reading extended config page failed: %s",
63329b76e53SScott Long 			    mps_ioc_status(req.ioc_status));
63429b76e53SScott Long 		free(buf);
63529b76e53SScott Long 		errno = EIO;
63629b76e53SScott Long 		return (NULL);
63729b76e53SScott Long 	}
63829b76e53SScott Long 	return (buf);
63929b76e53SScott Long }
64029b76e53SScott Long #endif
64129b76e53SScott Long 
64229b76e53SScott Long int
mps_open(int unit)64329b76e53SScott Long mps_open(int unit)
64429b76e53SScott Long {
64529b76e53SScott Long 	char path[MAXPATHLEN];
64629b76e53SScott Long 
64748f31f4fSBaptiste Daroussin 	snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
64829b76e53SScott Long 	return (open(path, O_RDWR));
64929b76e53SScott Long }
65029b76e53SScott Long 
65129b76e53SScott Long int
mps_user_command(int fd,void * req,uint32_t req_len,void * reply,uint32_t reply_len,void * buffer,int len,uint32_t flags)65229b76e53SScott Long mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
65329b76e53SScott Long         uint32_t reply_len, void *buffer, int len, uint32_t flags)
65429b76e53SScott Long {
65529b76e53SScott Long 	struct mps_usr_command cmd;
65629b76e53SScott Long 
65729b76e53SScott Long 	bzero(&cmd, sizeof(struct mps_usr_command));
65829b76e53SScott Long 	cmd.req = req;
65929b76e53SScott Long 	cmd.req_len = req_len;
66029b76e53SScott Long 	cmd.rpl = reply;
66129b76e53SScott Long 	cmd.rpl_len = reply_len;
66229b76e53SScott Long 	cmd.buf = buffer;
66329b76e53SScott Long 	cmd.len = len;
66429b76e53SScott Long 	cmd.flags = flags;
66529b76e53SScott Long 
6665a92b271SBaptiste Daroussin 	if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
66729b76e53SScott Long 		return (errno);
66829b76e53SScott Long 	return (0);
66929b76e53SScott Long }
67029b76e53SScott Long 
67129b76e53SScott Long int
mps_pass_command(int fd,void * req,uint32_t req_len,void * reply,uint32_t reply_len,void * data_in,uint32_t datain_len,void * data_out,uint32_t dataout_len,uint32_t timeout)67229b76e53SScott Long mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
67329b76e53SScott Long 	uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
67429b76e53SScott Long 	uint32_t dataout_len, uint32_t timeout)
67529b76e53SScott Long {
6765a92b271SBaptiste Daroussin 	struct mprs_pass_thru pass;
67729b76e53SScott Long 
678b627cd1cSAlexander Motin 	bzero(&pass, sizeof(pass));
67929b76e53SScott Long 	pass.PtrRequest = (uint64_t)(uintptr_t)req;
68029b76e53SScott Long 	pass.PtrReply = (uint64_t)(uintptr_t)reply;
68129b76e53SScott Long 	pass.RequestSize = req_len;
68229b76e53SScott Long 	pass.ReplySize = reply_len;
683b627cd1cSAlexander Motin 	if (datain_len && dataout_len) {
684b627cd1cSAlexander Motin 		pass.PtrData = (uint64_t)(uintptr_t)data_in;
685b627cd1cSAlexander Motin 		pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
68629b76e53SScott Long 		pass.DataSize = datain_len;
68729b76e53SScott Long 		pass.DataOutSize = dataout_len;
6885a92b271SBaptiste Daroussin 		if (is_mps) {
68929b76e53SScott Long 			pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
6905a92b271SBaptiste Daroussin 		} else {
6915a92b271SBaptiste Daroussin 			pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
6925a92b271SBaptiste Daroussin 		}
6935a92b271SBaptiste Daroussin 	} else if (datain_len) {
694b627cd1cSAlexander Motin 		pass.PtrData = (uint64_t)(uintptr_t)data_in;
695b627cd1cSAlexander Motin 		pass.DataSize = datain_len;
6965a92b271SBaptiste Daroussin 		if (is_mps) {
69729b76e53SScott Long 			pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
6985a92b271SBaptiste Daroussin 		} else {
6995a92b271SBaptiste Daroussin 			pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
7005a92b271SBaptiste Daroussin 		}
7015a92b271SBaptiste Daroussin 	} else if (dataout_len) {
702b627cd1cSAlexander Motin 		pass.PtrData = (uint64_t)(uintptr_t)data_out;
703b627cd1cSAlexander Motin 		pass.DataSize = dataout_len;
7045a92b271SBaptiste Daroussin 		if (is_mps) {
70529b76e53SScott Long 			pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
7065a92b271SBaptiste Daroussin 		} else {
7075a92b271SBaptiste Daroussin 			pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
7085a92b271SBaptiste Daroussin 		}
7095a92b271SBaptiste Daroussin 	} else {
7105a92b271SBaptiste Daroussin 		if (is_mps) {
71129b76e53SScott Long 			pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
7125a92b271SBaptiste Daroussin 		} else {
7135a92b271SBaptiste Daroussin 			pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
7145a92b271SBaptiste Daroussin 		}
7155a92b271SBaptiste Daroussin 	}
71629b76e53SScott Long 	pass.Timeout = timeout;
71729b76e53SScott Long 
71829b76e53SScott Long 	if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
71929b76e53SScott Long 		return (errno);
72029b76e53SScott Long 	return (0);
72129b76e53SScott Long }
72229b76e53SScott Long 
7237d154c4dSAlan Somers /* Return the length in bytes of the device's MPI2_IOC_FACTS reply */
7247d154c4dSAlan Somers static size_t
mps_get_ioc_factslen(int fd)7257d154c4dSAlan Somers mps_get_ioc_factslen(int fd)
7267d154c4dSAlan Somers {
7277d154c4dSAlan Somers 	MPI2_IOC_FACTS_REQUEST req;
7287d154c4dSAlan Somers 	const size_t factslen = 4;
7297d154c4dSAlan Somers 	char factsbuf[4] = {0};
7307d154c4dSAlan Somers 	MPI2_IOC_FACTS_REPLY *facts = (MPI2_IOC_FACTS_REPLY*)factsbuf;
7317d154c4dSAlan Somers 	int error;
7327d154c4dSAlan Somers 
7337d154c4dSAlan Somers 	bzero(&req, sizeof(req));
7347d154c4dSAlan Somers 	req.Function = MPI2_FUNCTION_IOC_FACTS;
7357d154c4dSAlan Somers 	error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
7367d154c4dSAlan Somers 	    factsbuf, factslen, NULL, 0, NULL, 0, 10);
7377d154c4dSAlan Somers 
7387d154c4dSAlan Somers 	if (error)
7397d154c4dSAlan Somers 		return (0);
7407d154c4dSAlan Somers 
7417d154c4dSAlan Somers 	/* The card's response is measured in dwords */
7427d154c4dSAlan Somers 	return (facts->MsgLength * 4);
7437d154c4dSAlan Somers }
7447d154c4dSAlan Somers 
74529b76e53SScott Long MPI2_IOC_FACTS_REPLY *
mps_get_iocfacts(int fd)74629b76e53SScott Long mps_get_iocfacts(int fd)
74729b76e53SScott Long {
74829b76e53SScott Long 	MPI2_IOC_FACTS_REPLY *facts;
74929b76e53SScott Long 	MPI2_IOC_FACTS_REQUEST req;
7507d154c4dSAlan Somers 	size_t factslen;
75129b76e53SScott Long 	int error;
75229b76e53SScott Long 
7537d154c4dSAlan Somers 	factslen = mps_get_ioc_factslen(fd);
7547d154c4dSAlan Somers 	if (factslen == 0)
7557d154c4dSAlan Somers 		return (NULL);
75669e85eb8SScott Long 
75769e85eb8SScott Long 	facts = malloc(factslen);
75829b76e53SScott Long 	if (facts == NULL) {
75929b76e53SScott Long 		errno = ENOMEM;
76029b76e53SScott Long 		return (NULL);
76129b76e53SScott Long 	}
76229b76e53SScott Long 
7637d154c4dSAlan Somers 	bzero(&req, sizeof(req));
76429b76e53SScott Long 	req.Function = MPI2_FUNCTION_IOC_FACTS;
76529b76e53SScott Long 
76629b76e53SScott Long #if 1
76729b76e53SScott Long 	error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
76869e85eb8SScott Long 	    facts, factslen, NULL, 0, NULL, 0, 10);
76929b76e53SScott Long #else
77029b76e53SScott Long 	error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
77169e85eb8SScott Long 	    facts, factslen, NULL, 0, 0);
77229b76e53SScott Long #endif
77329b76e53SScott Long 	if (error) {
77429b76e53SScott Long 		free(facts);
77529b76e53SScott Long 		return (NULL);
77629b76e53SScott Long 	}
77729b76e53SScott Long 
77829b76e53SScott Long 	if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
77929b76e53SScott Long 		free(facts);
78029b76e53SScott Long 		errno = EINVAL;
78129b76e53SScott Long 		return (NULL);
78229b76e53SScott Long 	}
783fc9780fdSAlfredo Dal'Ava Junior 	adjust_iocfacts_endianness(facts);
78429b76e53SScott Long 	return (facts);
78529b76e53SScott Long }
78629b76e53SScott Long 
787fc9780fdSAlfredo Dal'Ava Junior static void
adjust_iocfacts_endianness(MPI2_IOC_FACTS_REPLY * facts)788fc9780fdSAlfredo Dal'Ava Junior adjust_iocfacts_endianness(MPI2_IOC_FACTS_REPLY *facts)
789fc9780fdSAlfredo Dal'Ava Junior {
790fc9780fdSAlfredo Dal'Ava Junior 	facts->MsgVersion = le16toh(facts->MsgVersion);
791fc9780fdSAlfredo Dal'Ava Junior 	facts->HeaderVersion = le16toh(facts->HeaderVersion);
792fc9780fdSAlfredo Dal'Ava Junior 	facts->Reserved1 = le16toh(facts->Reserved1);
793fc9780fdSAlfredo Dal'Ava Junior 	facts->IOCExceptions = le16toh(facts->IOCExceptions);
794fc9780fdSAlfredo Dal'Ava Junior 	facts->IOCStatus = le16toh(facts->IOCStatus);
795fc9780fdSAlfredo Dal'Ava Junior 	facts->IOCLogInfo = le32toh(facts->IOCLogInfo);
796fc9780fdSAlfredo Dal'Ava Junior 	facts->RequestCredit = le16toh(facts->RequestCredit);
797fc9780fdSAlfredo Dal'Ava Junior 	facts->ProductID = le16toh(facts->ProductID);
798fc9780fdSAlfredo Dal'Ava Junior 	facts->IOCCapabilities = le32toh(facts->IOCCapabilities);
799fc9780fdSAlfredo Dal'Ava Junior 	facts->IOCRequestFrameSize =
800fc9780fdSAlfredo Dal'Ava Junior 	    le16toh(facts->IOCRequestFrameSize);
801fc9780fdSAlfredo Dal'Ava Junior 	facts->FWVersion.Word = le32toh(facts->FWVersion.Word);
802fc9780fdSAlfredo Dal'Ava Junior 	facts->MaxInitiators = le16toh(facts->MaxInitiators);
803fc9780fdSAlfredo Dal'Ava Junior 	facts->MaxTargets = le16toh(facts->MaxTargets);
804fc9780fdSAlfredo Dal'Ava Junior 	facts->MaxSasExpanders = le16toh(facts->MaxSasExpanders);
805fc9780fdSAlfredo Dal'Ava Junior 	facts->MaxEnclosures = le16toh(facts->MaxEnclosures);
806fc9780fdSAlfredo Dal'Ava Junior 	facts->ProtocolFlags = le16toh(facts->ProtocolFlags);
807fc9780fdSAlfredo Dal'Ava Junior 	facts->HighPriorityCredit = le16toh(facts->HighPriorityCredit);
808fc9780fdSAlfredo Dal'Ava Junior 	facts->MaxReplyDescriptorPostQueueDepth =
809fc9780fdSAlfredo Dal'Ava Junior 	    le16toh(facts->MaxReplyDescriptorPostQueueDepth);
810fc9780fdSAlfredo Dal'Ava Junior 	facts->MaxDevHandle = le16toh(facts->MaxDevHandle);
811fc9780fdSAlfredo Dal'Ava Junior 	facts->MaxPersistentEntries =
812fc9780fdSAlfredo Dal'Ava Junior 	    le16toh(facts->MaxPersistentEntries);
813fc9780fdSAlfredo Dal'Ava Junior 	facts->MinDevHandle = le16toh(facts->MinDevHandle);
814fc9780fdSAlfredo Dal'Ava Junior }
815