1286180Sscottl/*-
2291002Sbapt * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
3291002Sbapt *
4290061Sscottl * Copyright (c) 2015 Netflix, Inc.
5290061Sscottl * All rights reserved.
6290061Sscottl * Written by: Scott Long <scottl@freebsd.org>
7290061Sscottl *
8286180Sscottl * Copyright (c) 2008 Yahoo!, Inc.
9286180Sscottl * All rights reserved.
10286180Sscottl * Written by: John Baldwin <jhb@FreeBSD.org>
11286180Sscottl *
12286180Sscottl * Redistribution and use in source and binary forms, with or without
13286180Sscottl * modification, are permitted provided that the following conditions
14286180Sscottl * are met:
15286180Sscottl * 1. Redistributions of source code must retain the above copyright
16286180Sscottl *    notice, this list of conditions and the following disclaimer.
17286180Sscottl * 2. Redistributions in binary form must reproduce the above copyright
18286180Sscottl *    notice, this list of conditions and the following disclaimer in the
19286180Sscottl *    documentation and/or other materials provided with the distribution.
20286180Sscottl * 3. Neither the name of the author nor the names of any co-contributors
21286180Sscottl *    may be used to endorse or promote products derived from this software
22286180Sscottl *    without specific prior written permission.
23286180Sscottl *
24286180Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25286180Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26286180Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27286180Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28286180Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29286180Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30286180Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31286180Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32286180Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33286180Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34286180Sscottl * SUCH DAMAGE.
35286180Sscottl */
36286180Sscottl
37286180Sscottl#include <sys/cdefs.h>
38286180Sscottl__RCSID("$FreeBSD: stable/11/usr.sbin/mpsutil/mps_cmd.c 315599 2017-03-20 00:54:45Z pfg $");
39286180Sscottl
40286180Sscottl#include <sys/param.h>
41286180Sscottl#include <sys/errno.h>
42286180Sscottl#include <sys/ioctl.h>
43286180Sscottl#if 0
44286180Sscottl#include <sys/mps_ioctl.h>
45286180Sscottl#else
46286180Sscottl#include "mps_ioctl.h"
47289366Sbapt#include "mpr_ioctl.h"
48286180Sscottl#endif
49286180Sscottl#include <sys/sysctl.h>
50286180Sscottl#include <sys/uio.h>
51286180Sscottl
52286180Sscottl#include <err.h>
53286180Sscottl#include <fcntl.h>
54286180Sscottl#include <stdio.h>
55286180Sscottl#include <stdlib.h>
56286180Sscottl#include <string.h>
57286180Sscottl#include <unistd.h>
58286180Sscottl
59286180Sscottl#include "mpsutil.h"
60286180Sscottl
61286180Sscottl#ifndef USE_MPT_IOCTLS
62286180Sscottl#define USE_MPT_IOCTLS
63286180Sscottl#endif
64286180Sscottl
65286180Sscottlstatic const char *mps_ioc_status_codes[] = {
66286180Sscottl	"Success",				/* 0x0000 */
67286180Sscottl	"Invalid function",
68286180Sscottl	"Busy",
69286180Sscottl	"Invalid scatter-gather list",
70286180Sscottl	"Internal error",
71286180Sscottl	"Reserved",
72286180Sscottl	"Insufficient resources",
73286180Sscottl	"Invalid field",
74286180Sscottl	"Invalid state",			/* 0x0008 */
75286180Sscottl	"Operation state not supported",
76286180Sscottl	NULL,
77286180Sscottl	NULL,
78286180Sscottl	NULL,
79286180Sscottl	NULL,
80286180Sscottl	NULL,
81286180Sscottl	NULL,
82286180Sscottl	NULL,					/* 0x0010 */
83286180Sscottl	NULL,
84286180Sscottl	NULL,
85286180Sscottl	NULL,
86286180Sscottl	NULL,
87286180Sscottl	NULL,
88286180Sscottl	NULL,
89286180Sscottl	NULL,
90286180Sscottl	NULL,					/* 0x0018 */
91286180Sscottl	NULL,
92286180Sscottl	NULL,
93286180Sscottl	NULL,
94286180Sscottl	NULL,
95286180Sscottl	NULL,
96286180Sscottl	NULL,
97286180Sscottl	NULL,
98286180Sscottl	"Invalid configuration action",		/* 0x0020 */
99286180Sscottl	"Invalid configuration type",
100286180Sscottl	"Invalid configuration page",
101286180Sscottl	"Invalid configuration data",
102286180Sscottl	"No configuration defaults",
103286180Sscottl	"Unable to commit configuration change",
104286180Sscottl	NULL,
105286180Sscottl	NULL,
106286180Sscottl	NULL,					/* 0x0028 */
107286180Sscottl	NULL,
108286180Sscottl	NULL,
109286180Sscottl	NULL,
110286180Sscottl	NULL,
111286180Sscottl	NULL,
112286180Sscottl	NULL,
113286180Sscottl	NULL,
114286180Sscottl	NULL,					/* 0x0030 */
115286180Sscottl	NULL,
116286180Sscottl	NULL,
117286180Sscottl	NULL,
118286180Sscottl	NULL,
119286180Sscottl	NULL,
120286180Sscottl	NULL,
121286180Sscottl	NULL,
122286180Sscottl	NULL,					/* 0x0038 */
123286180Sscottl	NULL,
124286180Sscottl	NULL,
125286180Sscottl	NULL,
126286180Sscottl	NULL,
127286180Sscottl	NULL,
128286180Sscottl	NULL,
129286180Sscottl	NULL,
130286180Sscottl	"Recovered SCSI error",			/* 0x0040 */
131286180Sscottl	"Invalid SCSI bus",
132286180Sscottl	"Invalid SCSI target ID",
133286180Sscottl	"SCSI device not there",
134286180Sscottl	"SCSI data overrun",
135286180Sscottl	"SCSI data underrun",
136286180Sscottl	"SCSI I/O error",
137286180Sscottl	"SCSI protocol error",
138286180Sscottl	"SCSI task terminated",			/* 0x0048 */
139286180Sscottl	"SCSI residual mismatch",
140286180Sscottl	"SCSI task management failed",
141286180Sscottl	"SCSI I/O controller terminated",
142286180Sscottl	"SCSI external controller terminated",
143286180Sscottl	"EEDP guard error",
144286180Sscottl	"EEDP reference tag error",
145286180Sscottl	"EEDP application tag error",
146286180Sscottl	NULL,					/* 0x0050 */
147286180Sscottl	NULL,
148286180Sscottl	NULL,
149286180Sscottl	NULL,
150286180Sscottl	NULL,
151286180Sscottl	NULL,
152286180Sscottl	NULL,
153286180Sscottl	NULL,
154286180Sscottl	NULL,					/* 0x0058 */
155286180Sscottl	NULL,
156286180Sscottl	NULL,
157286180Sscottl	NULL,
158286180Sscottl	NULL,
159286180Sscottl	NULL,
160286180Sscottl	NULL,
161286180Sscottl	NULL,
162286180Sscottl	"SCSI target priority I/O",		/* 0x0060 */
163286180Sscottl	"Invalid SCSI target port",
164286180Sscottl	"Invalid SCSI target I/O index",
165286180Sscottl	"SCSI target aborted",
166286180Sscottl	"No connection retryable",
167286180Sscottl	"No connection",
168286180Sscottl	"FC aborted",
169286180Sscottl	"Invalid FC receive ID",
170286180Sscottl	"FC did invalid",			/* 0x0068 */
171286180Sscottl	"FC node logged out",
172286180Sscottl	"Transfer count mismatch",
173286180Sscottl	"STS data not set",
174286180Sscottl	"FC exchange canceled",
175286180Sscottl	"Data offset error",
176286180Sscottl	"Too much write data",
177286180Sscottl	"IU too short",
178286180Sscottl	"ACK NAK timeout",			/* 0x0070 */
179286180Sscottl	"NAK received",
180286180Sscottl	NULL,
181286180Sscottl	NULL,
182286180Sscottl	NULL,
183286180Sscottl	NULL,
184286180Sscottl	NULL,
185286180Sscottl	NULL,
186286180Sscottl	NULL,					/* 0x0078 */
187286180Sscottl	NULL,
188286180Sscottl	NULL,
189286180Sscottl	NULL,
190286180Sscottl	NULL,
191286180Sscottl	NULL,
192286180Sscottl	NULL,
193286180Sscottl	NULL,
194286180Sscottl	"LAN device not found",			/* 0x0080 */
195286180Sscottl	"LAN device failure",
196286180Sscottl	"LAN transmit error",
197286180Sscottl	"LAN transmit aborted",
198286180Sscottl	"LAN receive error",
199286180Sscottl	"LAN receive aborted",
200286180Sscottl	"LAN partial packet",
201286180Sscottl	"LAN canceled",
202286180Sscottl	NULL,					/* 0x0088 */
203286180Sscottl	NULL,
204286180Sscottl	NULL,
205286180Sscottl	NULL,
206286180Sscottl	NULL,
207286180Sscottl	NULL,
208286180Sscottl	NULL,
209286180Sscottl	NULL,
210286180Sscottl	"SAS SMP request failed",		/* 0x0090 */
211286180Sscottl	"SAS SMP data overrun",
212286180Sscottl	NULL,
213286180Sscottl	NULL,
214286180Sscottl	NULL,
215286180Sscottl	NULL,
216286180Sscottl	NULL,
217286180Sscottl	NULL,
218286180Sscottl	"Inband aborted",			/* 0x0098 */
219286180Sscottl	"No inband connection",
220286180Sscottl	NULL,
221286180Sscottl	NULL,
222286180Sscottl	NULL,
223286180Sscottl	NULL,
224286180Sscottl	NULL,
225286180Sscottl	NULL,
226286180Sscottl	"Diagnostic released",			/* 0x00A0 */
227286180Sscottl};
228286180Sscottl
229289366Sbaptstruct mprs_pass_thru {
230289366Sbapt        uint64_t        PtrRequest;
231289366Sbapt        uint64_t        PtrReply;
232289366Sbapt        uint64_t        PtrData;
233289366Sbapt        uint32_t        RequestSize;
234289366Sbapt        uint32_t        ReplySize;
235289366Sbapt        uint32_t        DataSize;
236289366Sbapt        uint32_t        DataDirection;
237289366Sbapt        uint64_t        PtrDataOut;
238289366Sbapt        uint32_t        DataOutSize;
239289366Sbapt        uint32_t        Timeout;
240289366Sbapt};
241289366Sbapt
242289366Sbaptstruct mprs_btdh_mapping {
243289366Sbapt        uint16_t        TargetID;
244289366Sbapt        uint16_t        Bus;
245289366Sbapt        uint16_t        DevHandle;
246289366Sbapt        uint16_t        Reserved;
247289366Sbapt};
248289366Sbapt
249286180Sscottlconst char *
250286180Sscottlmps_ioc_status(U16 IOCStatus)
251286180Sscottl{
252286180Sscottl	static char buffer[16];
253286180Sscottl
254286180Sscottl	IOCStatus &= MPI2_IOCSTATUS_MASK;
255286180Sscottl	if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
256286180Sscottl	    mps_ioc_status_codes[IOCStatus] != NULL)
257286180Sscottl		return (mps_ioc_status_codes[IOCStatus]);
258286180Sscottl	snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
259286180Sscottl	return (buffer);
260286180Sscottl}
261286180Sscottl
262286180Sscottl#ifdef USE_MPT_IOCTLS
263286180Sscottlint
264286180Sscottlmps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
265286180Sscottl{
266286180Sscottl	int error;
267289366Sbapt	struct mprs_btdh_mapping map;
268286180Sscottl
269286180Sscottl	map.Bus = *bus;
270286180Sscottl	map.TargetID = *target;
271286180Sscottl	map.DevHandle = *devhandle;
272286180Sscottl
273286180Sscottl	if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
274286180Sscottl		error = errno;
275286180Sscottl		warn("Failed to map bus/target/device");
276286180Sscottl		return (error);
277286180Sscottl	}
278286180Sscottl
279286180Sscottl	*bus = map.Bus;
280286180Sscottl	*target = map.TargetID;
281286180Sscottl	*devhandle = map.DevHandle;
282286180Sscottl
283286180Sscottl	return (0);
284286180Sscottl}
285286180Sscottl
286286180Sscottlint
287286180Sscottlmps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
288286180Sscottl    MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
289286180Sscottl{
290286180Sscottl	MPI2_CONFIG_REQUEST req;
291286180Sscottl	MPI2_CONFIG_REPLY reply;
292286180Sscottl
293286180Sscottl	bzero(&req, sizeof(req));
294286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
295286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
296286180Sscottl	req.Header.PageType = PageType;
297286180Sscottl	req.Header.PageNumber = PageNumber;
298286180Sscottl	req.PageAddress = PageAddress;
299286180Sscottl
300286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
301286180Sscottl	    NULL, 0, NULL, 0, 30))
302286180Sscottl		return (errno);
303286180Sscottl
304286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
305286180Sscottl		if (IOCStatus != NULL)
306286180Sscottl			*IOCStatus = reply.IOCStatus;
307286180Sscottl		return (EIO);
308286180Sscottl	}
309286180Sscottl	if (header == NULL)
310286180Sscottl		return (EINVAL);
311286180Sscottl	*header = reply.Header;
312286180Sscottl	return (0);
313286180Sscottl}
314286180Sscottl
315286180Sscottlint
316286180Sscottlmps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
317286180Sscottl{
318286180Sscottl	MPI2_CONFIG_REQUEST req;
319286180Sscottl	MPI2_CONFIG_REPLY reply;
320286180Sscottl
321286180Sscottl	bzero(&req, sizeof(req));
322286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
323286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
324286180Sscottl	req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
325286180Sscottl	req.ExtPageType = ExtPageType;
326286180Sscottl	req.Header.PageNumber = PageNumber;
327286180Sscottl	req.PageAddress = PageAddress;
328286180Sscottl
329286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
330286180Sscottl	    NULL, 0, NULL, 0, 30))
331286180Sscottl		return (errno);
332286180Sscottl
333286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
334286180Sscottl		if (IOCStatus != NULL)
335286180Sscottl			*IOCStatus = reply.IOCStatus;
336286180Sscottl		return (EIO);
337286180Sscottl	}
338286180Sscottl	if ((header == NULL) || (ExtPageLength == NULL))
339286180Sscottl		return (EINVAL);
340286180Sscottl	*header = reply.Header;
341286180Sscottl	*ExtPageLength = reply.ExtPageLength;
342286180Sscottl	return (0);
343286180Sscottl}
344286180Sscottl
345286180Sscottlvoid *
346286180Sscottlmps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
347286180Sscottl    U16 *IOCStatus)
348286180Sscottl{
349286180Sscottl	MPI2_CONFIG_REQUEST req;
350286180Sscottl	MPI2_CONFIG_PAGE_HEADER header;
351286180Sscottl	MPI2_CONFIG_REPLY reply;
352286180Sscottl	void *buf;
353286180Sscottl	int error, len;
354286180Sscottl
355286180Sscottl	bzero(&header, sizeof(header));
356286180Sscottl	error = mps_read_config_page_header(fd, PageType, PageNumber,
357286180Sscottl	    PageAddress, &header, IOCStatus);
358286180Sscottl	if (error) {
359286180Sscottl		errno = error;
360286180Sscottl		return (NULL);
361286180Sscottl	}
362286180Sscottl
363286180Sscottl	bzero(&req, sizeof(req));
364286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
365286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
366286180Sscottl	req.PageAddress = PageAddress;
367286180Sscottl	req.Header = header;
368286180Sscottl	req.Header.PageLength = reply.Header.PageLength;
369286180Sscottl	if (reply.Header.PageLength == 0)
370286180Sscottl		req.Header.PageLength = 4;
371286180Sscottl
372286180Sscottl	len = req.Header.PageLength * 4;
373286180Sscottl	buf = malloc(len);
374286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
375286180Sscottl	    buf, len, NULL, 0, 30)) {
376286180Sscottl		error = errno;
377286180Sscottl		free(buf);
378286180Sscottl		errno = error;
379286180Sscottl		return (NULL);
380286180Sscottl	}
381286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
382286180Sscottl		if (IOCStatus != NULL)
383286180Sscottl			*IOCStatus = reply.IOCStatus;
384286180Sscottl		else
385286180Sscottl			warnx("Reading config page failed: 0x%x %s",
386286180Sscottl			    reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
387286180Sscottl		free(buf);
388286180Sscottl		errno = EIO;
389286180Sscottl		return (NULL);
390286180Sscottl	}
391286180Sscottl	return (buf);
392286180Sscottl}
393286180Sscottl
394286180Sscottlvoid *
395286180Sscottlmps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
396286180Sscottl    U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
397286180Sscottl{
398286180Sscottl	MPI2_CONFIG_REQUEST req;
399286180Sscottl	MPI2_CONFIG_PAGE_HEADER header;
400286180Sscottl	MPI2_CONFIG_REPLY reply;
401286180Sscottl	U16 pagelen;
402286180Sscottl	void *buf;
403286180Sscottl	int error, len;
404286180Sscottl
405286180Sscottl	if (IOCStatus != NULL)
406286180Sscottl		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
407286180Sscottl	bzero(&header, sizeof(header));
408286180Sscottl	error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
409286180Sscottl	    PageAddress, &header, &pagelen, IOCStatus);
410286180Sscottl	if (error) {
411286180Sscottl		errno = error;
412286180Sscottl		return (NULL);
413286180Sscottl	}
414286180Sscottl
415286180Sscottl	bzero(&req, sizeof(req));
416286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
417286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
418286180Sscottl	req.PageAddress = PageAddress;
419286180Sscottl	req.Header = header;
420286180Sscottl	if (pagelen == 0)
421286180Sscottl		pagelen = 4;
422286180Sscottl	req.ExtPageLength = pagelen;
423286180Sscottl	req.ExtPageType = ExtPageType;
424286180Sscottl
425286180Sscottl	len = pagelen * 4;
426286180Sscottl	buf = malloc(len);
427286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
428286180Sscottl	    buf, len, NULL, 0, 30)) {
429286180Sscottl		error = errno;
430286180Sscottl		free(buf);
431286180Sscottl		errno = error;
432286180Sscottl		return (NULL);
433286180Sscottl	}
434286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
435286180Sscottl		if (IOCStatus != NULL)
436286180Sscottl			*IOCStatus = reply.IOCStatus;
437286180Sscottl		else
438286180Sscottl			warnx("Reading extended config page failed: %s",
439286180Sscottl			    mps_ioc_status(reply.IOCStatus));
440286180Sscottl		free(buf);
441286180Sscottl		errno = EIO;
442286180Sscottl		return (NULL);
443286180Sscottl	}
444286180Sscottl	return (buf);
445286180Sscottl}
446286180Sscottl
447291002Sbaptint
448291002Sbaptmps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios)
449291002Sbapt{
450291002Sbapt	MPI2_FW_DOWNLOAD_REQUEST req;
451291002Sbapt	MPI2_FW_DOWNLOAD_REPLY reply;
452291002Sbapt
453291002Sbapt	bzero(&req, sizeof(req));
454291002Sbapt	bzero(&reply, sizeof(reply));
455291002Sbapt	req.Function = MPI2_FUNCTION_FW_DOWNLOAD;
456291002Sbapt	req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
457291002Sbapt	req.TotalImageSize = len;
458291002Sbapt	req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
459291002Sbapt
460291002Sbapt	if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
461291002Sbapt	    fw, len, 0)) {
462291002Sbapt		return (-1);
463291002Sbapt	}
464291002Sbapt	return (0);
465291002Sbapt}
466291002Sbapt
467291002Sbaptint
468291002Sbaptmps_firmware_get(int fd, unsigned char **firmware, bool bios)
469291002Sbapt{
470291002Sbapt	MPI2_FW_UPLOAD_REQUEST req;
471291002Sbapt	MPI2_FW_UPLOAD_REPLY reply;
472291002Sbapt	int size;
473291002Sbapt
474291002Sbapt	*firmware = NULL;
475291002Sbapt	bzero(&req, sizeof(req));
476291002Sbapt	bzero(&reply, sizeof(reply));
477291002Sbapt	req.Function = MPI2_FUNCTION_FW_UPLOAD;
478291002Sbapt	req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
479291002Sbapt
480291002Sbapt	if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
481291002Sbapt	    NULL, 0, 0)) {
482291002Sbapt		return (-1);
483291002Sbapt	}
484291002Sbapt	if (reply.ActualImageSize == 0) {
485291002Sbapt		return (-1);
486291002Sbapt	}
487291002Sbapt
488291002Sbapt	size = reply.ActualImageSize;
489315599Spfg	*firmware = calloc(size, sizeof(unsigned char));
490291002Sbapt	if (*firmware == NULL) {
491291002Sbapt		warn("calloc");
492291002Sbapt		return (-1);
493291002Sbapt	}
494291002Sbapt	if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
495291002Sbapt	    *firmware, size, 0)) {
496291002Sbapt		free(*firmware);
497291002Sbapt		return (-1);
498291002Sbapt	}
499291002Sbapt
500291002Sbapt	return (size);
501291002Sbapt}
502291002Sbapt
503286180Sscottl#else
504286180Sscottl
505286180Sscottlint
506286180Sscottlmps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
507286180Sscottl    MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
508286180Sscottl{
509286180Sscottl	struct mps_cfg_page_req req;
510286180Sscottl
511286180Sscottl	if (IOCStatus != NULL)
512286180Sscottl		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
513286180Sscottl	if (header == NULL)
514286180Sscottl		return (EINVAL);
515286180Sscottl	bzero(&req, sizeof(req));
516286180Sscottl	req.header.PageType = PageType;
517286180Sscottl	req.header.PageNumber = PageNumber;
518286180Sscottl	req.page_address = PageAddress;
519286180Sscottl	if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
520286180Sscottl		return (errno);
521286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
522286180Sscottl		if (IOCStatus != NULL)
523286180Sscottl			*IOCStatus = req.ioc_status;
524286180Sscottl		return (EIO);
525286180Sscottl	}
526286180Sscottl	bcopy(&req.header, header, sizeof(*header));
527286180Sscottl	return (0);
528286180Sscottl}
529286180Sscottl
530286180Sscottlvoid *
531286180Sscottlmps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
532286180Sscottl    U16 *IOCStatus)
533286180Sscottl{
534286180Sscottl	struct mps_cfg_page_req req;
535286180Sscottl	void *buf;
536286180Sscottl	int error;
537286180Sscottl
538286180Sscottl	error = mps_read_config_page_header(fd, PageType, PageNumber,
539286180Sscottl	    PageAddress, &req.header, IOCStatus);
540286180Sscottl	if (error) {
541286180Sscottl		errno = error;
542286180Sscottl		return (NULL);
543286180Sscottl	}
544286180Sscottl
545286180Sscottl	if (req.header.PageLength == 0)
546286180Sscottl		req.header.PageLength = 4;
547286180Sscottl	req.len = req.header.PageLength * 4;
548286180Sscottl	buf = malloc(req.len);
549286180Sscottl	req.buf = buf;
550286180Sscottl	bcopy(&req.header, buf, sizeof(req.header));
551286180Sscottl	if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
552286180Sscottl		error = errno;
553286180Sscottl		free(buf);
554286180Sscottl		errno = error;
555286180Sscottl		return (NULL);
556286180Sscottl	}
557286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
558286180Sscottl		if (IOCStatus != NULL)
559286180Sscottl			*IOCStatus = req.ioc_status;
560286180Sscottl		else
561286180Sscottl			warnx("Reading config page failed: 0x%x %s",
562286180Sscottl			    req.ioc_status, mps_ioc_status(req.ioc_status));
563286180Sscottl		free(buf);
564286180Sscottl		errno = EIO;
565286180Sscottl		return (NULL);
566286180Sscottl	}
567286180Sscottl	return (buf);
568286180Sscottl}
569286180Sscottl
570286180Sscottlvoid *
571286180Sscottlmps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
572286180Sscottl    U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
573286180Sscottl{
574286180Sscottl	struct mps_ext_cfg_page_req req;
575286180Sscottl	void *buf;
576286180Sscottl	int error;
577286180Sscottl
578286180Sscottl	if (IOCStatus != NULL)
579286180Sscottl		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
580286180Sscottl	bzero(&req, sizeof(req));
581286180Sscottl	req.header.PageVersion = PageVersion;
582286180Sscottl	req.header.PageNumber = PageNumber;
583286180Sscottl	req.header.ExtPageType = ExtPageType;
584286180Sscottl	req.page_address = PageAddress;
585286180Sscottl	if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
586286180Sscottl		return (NULL);
587286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
588286180Sscottl		if (IOCStatus != NULL)
589286180Sscottl			*IOCStatus = req.ioc_status;
590286180Sscottl		else
591286180Sscottl			warnx("Reading extended config page header failed: %s",
592286180Sscottl			    mps_ioc_status(req.ioc_status));
593286180Sscottl		errno = EIO;
594286180Sscottl		return (NULL);
595286180Sscottl	}
596286180Sscottl	req.len = req.header.ExtPageLength * 4;
597286180Sscottl	buf = malloc(req.len);
598286180Sscottl	req.buf = buf;
599286180Sscottl	bcopy(&req.header, buf, sizeof(req.header));
600286180Sscottl	if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
601286180Sscottl		error = errno;
602286180Sscottl		free(buf);
603286180Sscottl		errno = error;
604286180Sscottl		return (NULL);
605286180Sscottl	}
606286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
607286180Sscottl		if (IOCStatus != NULL)
608286180Sscottl			*IOCStatus = req.ioc_status;
609286180Sscottl		else
610286180Sscottl			warnx("Reading extended config page failed: %s",
611286180Sscottl			    mps_ioc_status(req.ioc_status));
612286180Sscottl		free(buf);
613286180Sscottl		errno = EIO;
614286180Sscottl		return (NULL);
615286180Sscottl	}
616286180Sscottl	return (buf);
617286180Sscottl}
618286180Sscottl#endif
619286180Sscottl
620286180Sscottlint
621286180Sscottlmps_open(int unit)
622286180Sscottl{
623286180Sscottl	char path[MAXPATHLEN];
624286180Sscottl
625289364Sbapt	snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
626286180Sscottl	return (open(path, O_RDWR));
627286180Sscottl}
628286180Sscottl
629286180Sscottlint
630286180Sscottlmps_user_command(int fd, void *req, uint32_t req_len, void *reply,
631286180Sscottl        uint32_t reply_len, void *buffer, int len, uint32_t flags)
632286180Sscottl{
633286180Sscottl	struct mps_usr_command cmd;
634286180Sscottl
635286180Sscottl	bzero(&cmd, sizeof(struct mps_usr_command));
636286180Sscottl	cmd.req = req;
637286180Sscottl	cmd.req_len = req_len;
638286180Sscottl	cmd.rpl = reply;
639286180Sscottl	cmd.rpl_len = reply_len;
640286180Sscottl	cmd.buf = buffer;
641286180Sscottl	cmd.len = len;
642286180Sscottl	cmd.flags = flags;
643286180Sscottl
644289366Sbapt	if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
645286180Sscottl		return (errno);
646286180Sscottl	return (0);
647286180Sscottl}
648286180Sscottl
649286180Sscottlint
650286180Sscottlmps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
651286180Sscottl	uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
652286180Sscottl	uint32_t dataout_len, uint32_t timeout)
653286180Sscottl{
654289366Sbapt	struct mprs_pass_thru pass;
655286180Sscottl
656286180Sscottl	pass.PtrRequest = (uint64_t)(uintptr_t)req;
657286180Sscottl	pass.PtrReply = (uint64_t)(uintptr_t)reply;
658286180Sscottl	pass.PtrData = (uint64_t)(uintptr_t)data_in;
659286180Sscottl	pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
660286180Sscottl	pass.RequestSize = req_len;
661286180Sscottl	pass.ReplySize = reply_len;
662286180Sscottl	pass.DataSize = datain_len;
663286180Sscottl	pass.DataOutSize = dataout_len;
664289366Sbapt	if (datain_len && dataout_len) {
665289366Sbapt		if (is_mps) {
666289366Sbapt			pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
667289366Sbapt		} else {
668289366Sbapt			pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
669289366Sbapt		}
670289366Sbapt	} else if (datain_len) {
671289366Sbapt		if (is_mps) {
672289366Sbapt			pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
673289366Sbapt		} else {
674289366Sbapt			pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
675289366Sbapt		}
676289366Sbapt	} else if (dataout_len) {
677289366Sbapt		if (is_mps) {
678289366Sbapt			pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
679289366Sbapt		} else {
680289366Sbapt			pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
681289366Sbapt		}
682289366Sbapt	} else {
683289366Sbapt		if (is_mps) {
684289366Sbapt			pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
685289366Sbapt		} else {
686289366Sbapt			pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
687289366Sbapt		}
688289366Sbapt	}
689286180Sscottl	pass.Timeout = timeout;
690286180Sscottl
691286180Sscottl	if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
692286180Sscottl		return (errno);
693286180Sscottl	return (0);
694286180Sscottl}
695286180Sscottl
696286180SscottlMPI2_IOC_FACTS_REPLY *
697286180Sscottlmps_get_iocfacts(int fd)
698286180Sscottl{
699286180Sscottl	MPI2_IOC_FACTS_REPLY *facts;
700286180Sscottl	MPI2_IOC_FACTS_REQUEST req;
701286180Sscottl	int error;
702286180Sscottl
703286180Sscottl	facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
704286180Sscottl	if (facts == NULL) {
705286180Sscottl		errno = ENOMEM;
706286180Sscottl		return (NULL);
707286180Sscottl	}
708286180Sscottl
709286180Sscottl	bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
710286180Sscottl	req.Function = MPI2_FUNCTION_IOC_FACTS;
711286180Sscottl
712286180Sscottl#if 1
713286180Sscottl	error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
714286180Sscottl	    facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
715286180Sscottl#else
716286180Sscottl	error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
717286180Sscottl	    facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
718286180Sscottl#endif
719286180Sscottl	if (error) {
720286180Sscottl		free(facts);
721286180Sscottl		return (NULL);
722286180Sscottl	}
723286180Sscottl
724286180Sscottl	if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
725286180Sscottl		free(facts);
726286180Sscottl		errno = EINVAL;
727286180Sscottl		return (NULL);
728286180Sscottl	}
729286180Sscottl	return (facts);
730286180Sscottl}
731286180Sscottl
732