mps_cmd.c revision 290061
1286180Sscottl/*-
2290061Sscottl * Copyright (c) 2015 Netflix, Inc.
3290061Sscottl * All rights reserved.
4290061Sscottl * Written by: Scott Long <scottl@freebsd.org>
5290061Sscottl *
6286180Sscottl * Copyright (c) 2008 Yahoo!, Inc.
7286180Sscottl * All rights reserved.
8286180Sscottl * Written by: John Baldwin <jhb@FreeBSD.org>
9286180Sscottl *
10286180Sscottl * Redistribution and use in source and binary forms, with or without
11286180Sscottl * modification, are permitted provided that the following conditions
12286180Sscottl * are met:
13286180Sscottl * 1. Redistributions of source code must retain the above copyright
14286180Sscottl *    notice, this list of conditions and the following disclaimer.
15286180Sscottl * 2. Redistributions in binary form must reproduce the above copyright
16286180Sscottl *    notice, this list of conditions and the following disclaimer in the
17286180Sscottl *    documentation and/or other materials provided with the distribution.
18286180Sscottl * 3. Neither the name of the author nor the names of any co-contributors
19286180Sscottl *    may be used to endorse or promote products derived from this software
20286180Sscottl *    without specific prior written permission.
21286180Sscottl *
22286180Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23286180Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24286180Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25286180Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26286180Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27286180Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28286180Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29286180Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30286180Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31286180Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32286180Sscottl * SUCH DAMAGE.
33286180Sscottl */
34286180Sscottl
35286180Sscottl#include <sys/cdefs.h>
36286180Sscottl__RCSID("$FreeBSD: projects/mpsutil/usr.sbin/mpsutil/mps_cmd.c 290061 2015-10-27 20:56:57Z scottl $");
37286180Sscottl
38286180Sscottl#include <sys/param.h>
39286180Sscottl#include <sys/errno.h>
40286180Sscottl#include <sys/ioctl.h>
41286180Sscottl#if 0
42286180Sscottl#include <sys/mps_ioctl.h>
43286180Sscottl#else
44286180Sscottl#include "mps_ioctl.h"
45289366Sbapt#include "mpr_ioctl.h"
46286180Sscottl#endif
47286180Sscottl#include <sys/sysctl.h>
48286180Sscottl#include <sys/uio.h>
49286180Sscottl
50286180Sscottl#include <err.h>
51286180Sscottl#include <fcntl.h>
52286180Sscottl#include <stdio.h>
53286180Sscottl#include <stdlib.h>
54286180Sscottl#include <string.h>
55286180Sscottl#include <unistd.h>
56286180Sscottl
57286180Sscottl#include "mpsutil.h"
58286180Sscottl
59286180Sscottl#ifndef USE_MPT_IOCTLS
60286180Sscottl#define USE_MPT_IOCTLS
61286180Sscottl#endif
62286180Sscottl
63286180Sscottlstatic const char *mps_ioc_status_codes[] = {
64286180Sscottl	"Success",				/* 0x0000 */
65286180Sscottl	"Invalid function",
66286180Sscottl	"Busy",
67286180Sscottl	"Invalid scatter-gather list",
68286180Sscottl	"Internal error",
69286180Sscottl	"Reserved",
70286180Sscottl	"Insufficient resources",
71286180Sscottl	"Invalid field",
72286180Sscottl	"Invalid state",			/* 0x0008 */
73286180Sscottl	"Operation state not supported",
74286180Sscottl	NULL,
75286180Sscottl	NULL,
76286180Sscottl	NULL,
77286180Sscottl	NULL,
78286180Sscottl	NULL,
79286180Sscottl	NULL,
80286180Sscottl	NULL,					/* 0x0010 */
81286180Sscottl	NULL,
82286180Sscottl	NULL,
83286180Sscottl	NULL,
84286180Sscottl	NULL,
85286180Sscottl	NULL,
86286180Sscottl	NULL,
87286180Sscottl	NULL,
88286180Sscottl	NULL,					/* 0x0018 */
89286180Sscottl	NULL,
90286180Sscottl	NULL,
91286180Sscottl	NULL,
92286180Sscottl	NULL,
93286180Sscottl	NULL,
94286180Sscottl	NULL,
95286180Sscottl	NULL,
96286180Sscottl	"Invalid configuration action",		/* 0x0020 */
97286180Sscottl	"Invalid configuration type",
98286180Sscottl	"Invalid configuration page",
99286180Sscottl	"Invalid configuration data",
100286180Sscottl	"No configuration defaults",
101286180Sscottl	"Unable to commit configuration change",
102286180Sscottl	NULL,
103286180Sscottl	NULL,
104286180Sscottl	NULL,					/* 0x0028 */
105286180Sscottl	NULL,
106286180Sscottl	NULL,
107286180Sscottl	NULL,
108286180Sscottl	NULL,
109286180Sscottl	NULL,
110286180Sscottl	NULL,
111286180Sscottl	NULL,
112286180Sscottl	NULL,					/* 0x0030 */
113286180Sscottl	NULL,
114286180Sscottl	NULL,
115286180Sscottl	NULL,
116286180Sscottl	NULL,
117286180Sscottl	NULL,
118286180Sscottl	NULL,
119286180Sscottl	NULL,
120286180Sscottl	NULL,					/* 0x0038 */
121286180Sscottl	NULL,
122286180Sscottl	NULL,
123286180Sscottl	NULL,
124286180Sscottl	NULL,
125286180Sscottl	NULL,
126286180Sscottl	NULL,
127286180Sscottl	NULL,
128286180Sscottl	"Recovered SCSI error",			/* 0x0040 */
129286180Sscottl	"Invalid SCSI bus",
130286180Sscottl	"Invalid SCSI target ID",
131286180Sscottl	"SCSI device not there",
132286180Sscottl	"SCSI data overrun",
133286180Sscottl	"SCSI data underrun",
134286180Sscottl	"SCSI I/O error",
135286180Sscottl	"SCSI protocol error",
136286180Sscottl	"SCSI task terminated",			/* 0x0048 */
137286180Sscottl	"SCSI residual mismatch",
138286180Sscottl	"SCSI task management failed",
139286180Sscottl	"SCSI I/O controller terminated",
140286180Sscottl	"SCSI external controller terminated",
141286180Sscottl	"EEDP guard error",
142286180Sscottl	"EEDP reference tag error",
143286180Sscottl	"EEDP application tag error",
144286180Sscottl	NULL,					/* 0x0050 */
145286180Sscottl	NULL,
146286180Sscottl	NULL,
147286180Sscottl	NULL,
148286180Sscottl	NULL,
149286180Sscottl	NULL,
150286180Sscottl	NULL,
151286180Sscottl	NULL,
152286180Sscottl	NULL,					/* 0x0058 */
153286180Sscottl	NULL,
154286180Sscottl	NULL,
155286180Sscottl	NULL,
156286180Sscottl	NULL,
157286180Sscottl	NULL,
158286180Sscottl	NULL,
159286180Sscottl	NULL,
160286180Sscottl	"SCSI target priority I/O",		/* 0x0060 */
161286180Sscottl	"Invalid SCSI target port",
162286180Sscottl	"Invalid SCSI target I/O index",
163286180Sscottl	"SCSI target aborted",
164286180Sscottl	"No connection retryable",
165286180Sscottl	"No connection",
166286180Sscottl	"FC aborted",
167286180Sscottl	"Invalid FC receive ID",
168286180Sscottl	"FC did invalid",			/* 0x0068 */
169286180Sscottl	"FC node logged out",
170286180Sscottl	"Transfer count mismatch",
171286180Sscottl	"STS data not set",
172286180Sscottl	"FC exchange canceled",
173286180Sscottl	"Data offset error",
174286180Sscottl	"Too much write data",
175286180Sscottl	"IU too short",
176286180Sscottl	"ACK NAK timeout",			/* 0x0070 */
177286180Sscottl	"NAK received",
178286180Sscottl	NULL,
179286180Sscottl	NULL,
180286180Sscottl	NULL,
181286180Sscottl	NULL,
182286180Sscottl	NULL,
183286180Sscottl	NULL,
184286180Sscottl	NULL,					/* 0x0078 */
185286180Sscottl	NULL,
186286180Sscottl	NULL,
187286180Sscottl	NULL,
188286180Sscottl	NULL,
189286180Sscottl	NULL,
190286180Sscottl	NULL,
191286180Sscottl	NULL,
192286180Sscottl	"LAN device not found",			/* 0x0080 */
193286180Sscottl	"LAN device failure",
194286180Sscottl	"LAN transmit error",
195286180Sscottl	"LAN transmit aborted",
196286180Sscottl	"LAN receive error",
197286180Sscottl	"LAN receive aborted",
198286180Sscottl	"LAN partial packet",
199286180Sscottl	"LAN canceled",
200286180Sscottl	NULL,					/* 0x0088 */
201286180Sscottl	NULL,
202286180Sscottl	NULL,
203286180Sscottl	NULL,
204286180Sscottl	NULL,
205286180Sscottl	NULL,
206286180Sscottl	NULL,
207286180Sscottl	NULL,
208286180Sscottl	"SAS SMP request failed",		/* 0x0090 */
209286180Sscottl	"SAS SMP data overrun",
210286180Sscottl	NULL,
211286180Sscottl	NULL,
212286180Sscottl	NULL,
213286180Sscottl	NULL,
214286180Sscottl	NULL,
215286180Sscottl	NULL,
216286180Sscottl	"Inband aborted",			/* 0x0098 */
217286180Sscottl	"No inband connection",
218286180Sscottl	NULL,
219286180Sscottl	NULL,
220286180Sscottl	NULL,
221286180Sscottl	NULL,
222286180Sscottl	NULL,
223286180Sscottl	NULL,
224286180Sscottl	"Diagnostic released",			/* 0x00A0 */
225286180Sscottl};
226286180Sscottl
227289366Sbaptstruct mprs_pass_thru {
228289366Sbapt        uint64_t        PtrRequest;
229289366Sbapt        uint64_t        PtrReply;
230289366Sbapt        uint64_t        PtrData;
231289366Sbapt        uint32_t        RequestSize;
232289366Sbapt        uint32_t        ReplySize;
233289366Sbapt        uint32_t        DataSize;
234289366Sbapt        uint32_t        DataDirection;
235289366Sbapt        uint64_t        PtrDataOut;
236289366Sbapt        uint32_t        DataOutSize;
237289366Sbapt        uint32_t        Timeout;
238289366Sbapt};
239289366Sbapt
240289366Sbaptstruct mprs_btdh_mapping {
241289366Sbapt        uint16_t        TargetID;
242289366Sbapt        uint16_t        Bus;
243289366Sbapt        uint16_t        DevHandle;
244289366Sbapt        uint16_t        Reserved;
245289366Sbapt};
246289366Sbapt
247286180Sscottlconst char *
248286180Sscottlmps_ioc_status(U16 IOCStatus)
249286180Sscottl{
250286180Sscottl	static char buffer[16];
251286180Sscottl
252286180Sscottl	IOCStatus &= MPI2_IOCSTATUS_MASK;
253286180Sscottl	if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
254286180Sscottl	    mps_ioc_status_codes[IOCStatus] != NULL)
255286180Sscottl		return (mps_ioc_status_codes[IOCStatus]);
256286180Sscottl	snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
257286180Sscottl	return (buffer);
258286180Sscottl}
259286180Sscottl
260286180Sscottl#ifdef USE_MPT_IOCTLS
261286180Sscottlint
262286180Sscottlmps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
263286180Sscottl{
264286180Sscottl	int error;
265289366Sbapt	struct mprs_btdh_mapping map;
266286180Sscottl
267286180Sscottl	map.Bus = *bus;
268286180Sscottl	map.TargetID = *target;
269286180Sscottl	map.DevHandle = *devhandle;
270286180Sscottl
271286180Sscottl	if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
272286180Sscottl		error = errno;
273286180Sscottl		warn("Failed to map bus/target/device");
274286180Sscottl		return (error);
275286180Sscottl	}
276286180Sscottl
277286180Sscottl	*bus = map.Bus;
278286180Sscottl	*target = map.TargetID;
279286180Sscottl	*devhandle = map.DevHandle;
280286180Sscottl
281286180Sscottl	return (0);
282286180Sscottl}
283286180Sscottl
284286180Sscottlint
285286180Sscottlmps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
286286180Sscottl    MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
287286180Sscottl{
288286180Sscottl	MPI2_CONFIG_REQUEST req;
289286180Sscottl	MPI2_CONFIG_REPLY reply;
290286180Sscottl
291286180Sscottl	bzero(&req, sizeof(req));
292286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
293286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
294286180Sscottl	req.Header.PageType = PageType;
295286180Sscottl	req.Header.PageNumber = PageNumber;
296286180Sscottl	req.PageAddress = PageAddress;
297286180Sscottl
298286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
299286180Sscottl	    NULL, 0, NULL, 0, 30))
300286180Sscottl		return (errno);
301286180Sscottl
302286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
303286180Sscottl		if (IOCStatus != NULL)
304286180Sscottl			*IOCStatus = reply.IOCStatus;
305286180Sscottl		return (EIO);
306286180Sscottl	}
307286180Sscottl	if (header == NULL)
308286180Sscottl		return (EINVAL);
309286180Sscottl	*header = reply.Header;
310286180Sscottl	return (0);
311286180Sscottl}
312286180Sscottl
313286180Sscottlint
314286180Sscottlmps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
315286180Sscottl{
316286180Sscottl	MPI2_CONFIG_REQUEST req;
317286180Sscottl	MPI2_CONFIG_REPLY reply;
318286180Sscottl
319286180Sscottl	bzero(&req, sizeof(req));
320286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
321286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
322286180Sscottl	req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
323286180Sscottl	req.ExtPageType = ExtPageType;
324286180Sscottl	req.Header.PageNumber = PageNumber;
325286180Sscottl	req.PageAddress = PageAddress;
326286180Sscottl
327286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
328286180Sscottl	    NULL, 0, NULL, 0, 30))
329286180Sscottl		return (errno);
330286180Sscottl
331286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
332286180Sscottl		if (IOCStatus != NULL)
333286180Sscottl			*IOCStatus = reply.IOCStatus;
334286180Sscottl		return (EIO);
335286180Sscottl	}
336286180Sscottl	if ((header == NULL) || (ExtPageLength == NULL))
337286180Sscottl		return (EINVAL);
338286180Sscottl	*header = reply.Header;
339286180Sscottl	*ExtPageLength = reply.ExtPageLength;
340286180Sscottl	return (0);
341286180Sscottl}
342286180Sscottl
343286180Sscottlvoid *
344286180Sscottlmps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
345286180Sscottl    U16 *IOCStatus)
346286180Sscottl{
347286180Sscottl	MPI2_CONFIG_REQUEST req;
348286180Sscottl	MPI2_CONFIG_PAGE_HEADER header;
349286180Sscottl	MPI2_CONFIG_REPLY reply;
350286180Sscottl	void *buf;
351286180Sscottl	int error, len;
352286180Sscottl
353286180Sscottl	bzero(&header, sizeof(header));
354286180Sscottl	error = mps_read_config_page_header(fd, PageType, PageNumber,
355286180Sscottl	    PageAddress, &header, IOCStatus);
356286180Sscottl	if (error) {
357286180Sscottl		errno = error;
358286180Sscottl		return (NULL);
359286180Sscottl	}
360286180Sscottl
361286180Sscottl	bzero(&req, sizeof(req));
362286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
363286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
364286180Sscottl	req.PageAddress = PageAddress;
365286180Sscottl	req.Header = header;
366286180Sscottl	req.Header.PageLength = reply.Header.PageLength;
367286180Sscottl	if (reply.Header.PageLength == 0)
368286180Sscottl		req.Header.PageLength = 4;
369286180Sscottl
370286180Sscottl	len = req.Header.PageLength * 4;
371286180Sscottl	buf = malloc(len);
372286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
373286180Sscottl	    buf, len, NULL, 0, 30)) {
374286180Sscottl		error = errno;
375286180Sscottl		free(buf);
376286180Sscottl		errno = error;
377286180Sscottl		return (NULL);
378286180Sscottl	}
379286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
380286180Sscottl		if (IOCStatus != NULL)
381286180Sscottl			*IOCStatus = reply.IOCStatus;
382286180Sscottl		else
383286180Sscottl			warnx("Reading config page failed: 0x%x %s",
384286180Sscottl			    reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
385286180Sscottl		free(buf);
386286180Sscottl		errno = EIO;
387286180Sscottl		return (NULL);
388286180Sscottl	}
389286180Sscottl	return (buf);
390286180Sscottl}
391286180Sscottl
392286180Sscottlvoid *
393286180Sscottlmps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
394286180Sscottl    U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
395286180Sscottl{
396286180Sscottl	MPI2_CONFIG_REQUEST req;
397286180Sscottl	MPI2_CONFIG_PAGE_HEADER header;
398286180Sscottl	MPI2_CONFIG_REPLY reply;
399286180Sscottl	U16 pagelen;
400286180Sscottl	void *buf;
401286180Sscottl	int error, len;
402286180Sscottl
403286180Sscottl	if (IOCStatus != NULL)
404286180Sscottl		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
405286180Sscottl	bzero(&header, sizeof(header));
406286180Sscottl	error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
407286180Sscottl	    PageAddress, &header, &pagelen, IOCStatus);
408286180Sscottl	if (error) {
409286180Sscottl		errno = error;
410286180Sscottl		return (NULL);
411286180Sscottl	}
412286180Sscottl
413286180Sscottl	bzero(&req, sizeof(req));
414286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
415286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
416286180Sscottl	req.PageAddress = PageAddress;
417286180Sscottl	req.Header = header;
418286180Sscottl	if (pagelen == 0)
419286180Sscottl		pagelen = 4;
420286180Sscottl	req.ExtPageLength = pagelen;
421286180Sscottl	req.ExtPageType = ExtPageType;
422286180Sscottl
423286180Sscottl	len = pagelen * 4;
424286180Sscottl	buf = malloc(len);
425286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
426286180Sscottl	    buf, len, NULL, 0, 30)) {
427286180Sscottl		error = errno;
428286180Sscottl		free(buf);
429286180Sscottl		errno = error;
430286180Sscottl		return (NULL);
431286180Sscottl	}
432286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
433286180Sscottl		if (IOCStatus != NULL)
434286180Sscottl			*IOCStatus = reply.IOCStatus;
435286180Sscottl		else
436286180Sscottl			warnx("Reading extended config page failed: %s",
437286180Sscottl			    mps_ioc_status(reply.IOCStatus));
438286180Sscottl		free(buf);
439286180Sscottl		errno = EIO;
440286180Sscottl		return (NULL);
441286180Sscottl	}
442286180Sscottl	return (buf);
443286180Sscottl}
444286180Sscottl
445286180Sscottl#else
446286180Sscottl
447286180Sscottlint
448286180Sscottlmps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
449286180Sscottl    MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
450286180Sscottl{
451286180Sscottl	struct mps_cfg_page_req req;
452286180Sscottl
453286180Sscottl	if (IOCStatus != NULL)
454286180Sscottl		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
455286180Sscottl	if (header == NULL)
456286180Sscottl		return (EINVAL);
457286180Sscottl	bzero(&req, sizeof(req));
458286180Sscottl	req.header.PageType = PageType;
459286180Sscottl	req.header.PageNumber = PageNumber;
460286180Sscottl	req.page_address = PageAddress;
461286180Sscottl	if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
462286180Sscottl		return (errno);
463286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
464286180Sscottl		if (IOCStatus != NULL)
465286180Sscottl			*IOCStatus = req.ioc_status;
466286180Sscottl		return (EIO);
467286180Sscottl	}
468286180Sscottl	bcopy(&req.header, header, sizeof(*header));
469286180Sscottl	return (0);
470286180Sscottl}
471286180Sscottl
472286180Sscottlvoid *
473286180Sscottlmps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
474286180Sscottl    U16 *IOCStatus)
475286180Sscottl{
476286180Sscottl	struct mps_cfg_page_req req;
477286180Sscottl	void *buf;
478286180Sscottl	int error;
479286180Sscottl
480286180Sscottl	error = mps_read_config_page_header(fd, PageType, PageNumber,
481286180Sscottl	    PageAddress, &req.header, IOCStatus);
482286180Sscottl	if (error) {
483286180Sscottl		errno = error;
484286180Sscottl		return (NULL);
485286180Sscottl	}
486286180Sscottl
487286180Sscottl	if (req.header.PageLength == 0)
488286180Sscottl		req.header.PageLength = 4;
489286180Sscottl	req.len = req.header.PageLength * 4;
490286180Sscottl	buf = malloc(req.len);
491286180Sscottl	req.buf = buf;
492286180Sscottl	bcopy(&req.header, buf, sizeof(req.header));
493286180Sscottl	if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
494286180Sscottl		error = errno;
495286180Sscottl		free(buf);
496286180Sscottl		errno = error;
497286180Sscottl		return (NULL);
498286180Sscottl	}
499286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
500286180Sscottl		if (IOCStatus != NULL)
501286180Sscottl			*IOCStatus = req.ioc_status;
502286180Sscottl		else
503286180Sscottl			warnx("Reading config page failed: 0x%x %s",
504286180Sscottl			    req.ioc_status, mps_ioc_status(req.ioc_status));
505286180Sscottl		free(buf);
506286180Sscottl		errno = EIO;
507286180Sscottl		return (NULL);
508286180Sscottl	}
509286180Sscottl	return (buf);
510286180Sscottl}
511286180Sscottl
512286180Sscottlvoid *
513286180Sscottlmps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
514286180Sscottl    U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
515286180Sscottl{
516286180Sscottl	struct mps_ext_cfg_page_req req;
517286180Sscottl	void *buf;
518286180Sscottl	int error;
519286180Sscottl
520286180Sscottl	if (IOCStatus != NULL)
521286180Sscottl		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
522286180Sscottl	bzero(&req, sizeof(req));
523286180Sscottl	req.header.PageVersion = PageVersion;
524286180Sscottl	req.header.PageNumber = PageNumber;
525286180Sscottl	req.header.ExtPageType = ExtPageType;
526286180Sscottl	req.page_address = PageAddress;
527286180Sscottl	if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
528286180Sscottl		return (NULL);
529286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
530286180Sscottl		if (IOCStatus != NULL)
531286180Sscottl			*IOCStatus = req.ioc_status;
532286180Sscottl		else
533286180Sscottl			warnx("Reading extended config page header failed: %s",
534286180Sscottl			    mps_ioc_status(req.ioc_status));
535286180Sscottl		errno = EIO;
536286180Sscottl		return (NULL);
537286180Sscottl	}
538286180Sscottl	req.len = req.header.ExtPageLength * 4;
539286180Sscottl	buf = malloc(req.len);
540286180Sscottl	req.buf = buf;
541286180Sscottl	bcopy(&req.header, buf, sizeof(req.header));
542286180Sscottl	if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
543286180Sscottl		error = errno;
544286180Sscottl		free(buf);
545286180Sscottl		errno = error;
546286180Sscottl		return (NULL);
547286180Sscottl	}
548286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
549286180Sscottl		if (IOCStatus != NULL)
550286180Sscottl			*IOCStatus = req.ioc_status;
551286180Sscottl		else
552286180Sscottl			warnx("Reading extended config page failed: %s",
553286180Sscottl			    mps_ioc_status(req.ioc_status));
554286180Sscottl		free(buf);
555286180Sscottl		errno = EIO;
556286180Sscottl		return (NULL);
557286180Sscottl	}
558286180Sscottl	return (buf);
559286180Sscottl}
560286180Sscottl#endif
561286180Sscottl
562286180Sscottl#if 0
563286180Sscottlint
564286180Sscottlmpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
565286180Sscottl{
566286180Sscottl	CONFIG_PAGE_HEADER *hdr;
567286180Sscottl	struct mpt_cfg_page_req req;
568286180Sscottl
569286180Sscottl	if (IOCStatus != NULL)
570286180Sscottl		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
571286180Sscottl	bzero(&req, sizeof(req));
572286180Sscottl	req.buf = buf;
573286180Sscottl	hdr = buf;
574286180Sscottl	req.len = hdr->PageLength * 4;
575286180Sscottl	if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
576286180Sscottl		return (errno);
577286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
578286180Sscottl		if (IOCStatus != NULL) {
579286180Sscottl			*IOCStatus = req.ioc_status;
580286180Sscottl			return (0);
581286180Sscottl		}
582286180Sscottl		warnx("Writing config page failed: %s",
583286180Sscottl		    mpt_ioc_status(req.ioc_status));
584286180Sscottl		return (EIO);
585286180Sscottl	}
586286180Sscottl	return (0);
587286180Sscottl}
588286180Sscottl
589286180Sscottlint
590286180Sscottlmpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
591286180Sscottl    U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
592286180Sscottl    U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
593286180Sscottl{
594286180Sscottl	struct mpt_raid_action raid_act;
595286180Sscottl
596286180Sscottl	if (IOCStatus != NULL)
597286180Sscottl		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
598286180Sscottl	if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
599286180Sscottl		return (EINVAL);
600286180Sscottl	bzero(&raid_act, sizeof(raid_act));
601286180Sscottl	raid_act.action = Action;
602286180Sscottl	raid_act.volume_bus = VolumeBus;
603286180Sscottl	raid_act.volume_id = VolumeID;
604286180Sscottl	raid_act.phys_disk_num = PhysDiskNum;
605286180Sscottl	raid_act.action_data_word = ActionDataWord;
606286180Sscottl	if (buf != NULL && len != 0) {
607286180Sscottl		raid_act.buf = buf;
608286180Sscottl		raid_act.len = len;
609286180Sscottl		raid_act.write = write;
610286180Sscottl	}
611286180Sscottl
612286180Sscottl	if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
613286180Sscottl		return (errno);
614286180Sscottl
615286180Sscottl	if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
616286180Sscottl		if (IOCStatus != NULL) {
617286180Sscottl			*IOCStatus = raid_act.ioc_status;
618286180Sscottl			return (0);
619286180Sscottl		}
620286180Sscottl		warnx("RAID action failed: %s",
621286180Sscottl		    mpt_ioc_status(raid_act.ioc_status));
622286180Sscottl		return (EIO);
623286180Sscottl	}
624286180Sscottl
625286180Sscottl	if (ActionStatus != NULL)
626286180Sscottl		*ActionStatus = raid_act.action_status;
627286180Sscottl	if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
628286180Sscottl		if (ActionStatus != NULL)
629286180Sscottl			return (0);
630286180Sscottl		warnx("RAID action failed: %s",
631286180Sscottl		    mpt_raid_status(raid_act.action_status));
632286180Sscottl		return (EIO);
633286180Sscottl	}
634286180Sscottl
635286180Sscottl	if (VolumeStatus != NULL)
636286180Sscottl		*((U32 *)VolumeStatus) = raid_act.volume_status;
637286180Sscottl	if (ActionData != NULL)
638286180Sscottl		bcopy(raid_act.action_data, ActionData, datalen);
639286180Sscottl	return (0);
640286180Sscottl}
641286180Sscottl#endif
642286180Sscottl
643286180Sscottlint
644286180Sscottlmps_open(int unit)
645286180Sscottl{
646286180Sscottl	char path[MAXPATHLEN];
647286180Sscottl
648289364Sbapt	snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
649286180Sscottl	return (open(path, O_RDWR));
650286180Sscottl}
651286180Sscottl
652286180Sscottlint
653286180Sscottlmps_user_command(int fd, void *req, uint32_t req_len, void *reply,
654286180Sscottl        uint32_t reply_len, void *buffer, int len, uint32_t flags)
655286180Sscottl{
656286180Sscottl	struct mps_usr_command cmd;
657286180Sscottl
658286180Sscottl	bzero(&cmd, sizeof(struct mps_usr_command));
659286180Sscottl	cmd.req = req;
660286180Sscottl	cmd.req_len = req_len;
661286180Sscottl	cmd.rpl = reply;
662286180Sscottl	cmd.rpl_len = reply_len;
663286180Sscottl	cmd.buf = buffer;
664286180Sscottl	cmd.len = len;
665286180Sscottl	cmd.flags = flags;
666286180Sscottl
667289366Sbapt	if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
668286180Sscottl		return (errno);
669286180Sscottl	return (0);
670286180Sscottl}
671286180Sscottl
672286180Sscottlint
673286180Sscottlmps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
674286180Sscottl	uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
675286180Sscottl	uint32_t dataout_len, uint32_t timeout)
676286180Sscottl{
677289366Sbapt	struct mprs_pass_thru pass;
678286180Sscottl
679286180Sscottl	pass.PtrRequest = (uint64_t)(uintptr_t)req;
680286180Sscottl	pass.PtrReply = (uint64_t)(uintptr_t)reply;
681286180Sscottl	pass.PtrData = (uint64_t)(uintptr_t)data_in;
682286180Sscottl	pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
683286180Sscottl	pass.RequestSize = req_len;
684286180Sscottl	pass.ReplySize = reply_len;
685286180Sscottl	pass.DataSize = datain_len;
686286180Sscottl	pass.DataOutSize = dataout_len;
687289366Sbapt	if (datain_len && dataout_len) {
688289366Sbapt		if (is_mps) {
689289366Sbapt			pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
690289366Sbapt		} else {
691289366Sbapt			pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
692289366Sbapt		}
693289366Sbapt	} else if (datain_len) {
694289366Sbapt		if (is_mps) {
695289366Sbapt			pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
696289366Sbapt		} else {
697289366Sbapt			pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
698289366Sbapt		}
699289366Sbapt	} else if (dataout_len) {
700289366Sbapt		if (is_mps) {
701289366Sbapt			pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
702289366Sbapt		} else {
703289366Sbapt			pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
704289366Sbapt		}
705289366Sbapt	} else {
706289366Sbapt		if (is_mps) {
707289366Sbapt			pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
708289366Sbapt		} else {
709289366Sbapt			pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
710289366Sbapt		}
711289366Sbapt	}
712286180Sscottl	pass.Timeout = timeout;
713286180Sscottl
714286180Sscottl	if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
715286180Sscottl		return (errno);
716286180Sscottl	return (0);
717286180Sscottl}
718286180Sscottl
719286180SscottlMPI2_IOC_FACTS_REPLY *
720286180Sscottlmps_get_iocfacts(int fd)
721286180Sscottl{
722286180Sscottl	MPI2_IOC_FACTS_REPLY *facts;
723286180Sscottl	MPI2_IOC_FACTS_REQUEST req;
724286180Sscottl	int error;
725286180Sscottl
726286180Sscottl	facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
727286180Sscottl	if (facts == NULL) {
728286180Sscottl		errno = ENOMEM;
729286180Sscottl		return (NULL);
730286180Sscottl	}
731286180Sscottl
732286180Sscottl	bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
733286180Sscottl	req.Function = MPI2_FUNCTION_IOC_FACTS;
734286180Sscottl
735286180Sscottl#if 1
736286180Sscottl	error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
737286180Sscottl	    facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
738286180Sscottl#else
739286180Sscottl	error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
740286180Sscottl	    facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
741286180Sscottl#endif
742286180Sscottl	if (error) {
743286180Sscottl		free(facts);
744286180Sscottl		return (NULL);
745286180Sscottl	}
746286180Sscottl
747286180Sscottl	if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
748286180Sscottl		free(facts);
749286180Sscottl		errno = EINVAL;
750286180Sscottl		return (NULL);
751286180Sscottl	}
752286180Sscottl	return (facts);
753286180Sscottl}
754286180Sscottl
755