1 /*-
2 * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
3 *
4 * Copyright (c) 2015 Netflix, Inc.
5 * Written by: Scott Long <scottl@freebsd.org>
6 *
7 * Copyright (c) 2008 Yahoo!, Inc.
8 * All rights reserved.
9 * Written by: John Baldwin <jhb@FreeBSD.org>
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the author nor the names of any co-contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/param.h>
37 #include <sys/errno.h>
38 #include <sys/ioctl.h>
39 #include <sys/sysctl.h>
40 #include <sys/uio.h>
41 #include <sys/endian.h>
42
43 #include <err.h>
44 #include <fcntl.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 #include "mpsutil.h"
51 #include <dev/mps/mps_ioctl.h>
52 #include <dev/mpr/mpr_ioctl.h>
53
54 #ifndef USE_MPT_IOCTLS
55 #define USE_MPT_IOCTLS
56 #endif
57
58 static const char *mps_ioc_status_codes[] = {
59 "Success", /* 0x0000 */
60 "Invalid function",
61 "Busy",
62 "Invalid scatter-gather list",
63 "Internal error",
64 "Reserved",
65 "Insufficient resources",
66 "Invalid field",
67 "Invalid state", /* 0x0008 */
68 "Operation state not supported",
69 NULL,
70 NULL,
71 NULL,
72 NULL,
73 NULL,
74 NULL,
75 NULL, /* 0x0010 */
76 NULL,
77 NULL,
78 NULL,
79 NULL,
80 NULL,
81 NULL,
82 NULL,
83 NULL, /* 0x0018 */
84 NULL,
85 NULL,
86 NULL,
87 NULL,
88 NULL,
89 NULL,
90 NULL,
91 "Invalid configuration action", /* 0x0020 */
92 "Invalid configuration type",
93 "Invalid configuration page",
94 "Invalid configuration data",
95 "No configuration defaults",
96 "Unable to commit configuration change",
97 NULL,
98 NULL,
99 NULL, /* 0x0028 */
100 NULL,
101 NULL,
102 NULL,
103 NULL,
104 NULL,
105 NULL,
106 NULL,
107 NULL, /* 0x0030 */
108 NULL,
109 NULL,
110 NULL,
111 NULL,
112 NULL,
113 NULL,
114 NULL,
115 NULL, /* 0x0038 */
116 NULL,
117 NULL,
118 NULL,
119 NULL,
120 NULL,
121 NULL,
122 NULL,
123 "Recovered SCSI error", /* 0x0040 */
124 "Invalid SCSI bus",
125 "Invalid SCSI target ID",
126 "SCSI device not there",
127 "SCSI data overrun",
128 "SCSI data underrun",
129 "SCSI I/O error",
130 "SCSI protocol error",
131 "SCSI task terminated", /* 0x0048 */
132 "SCSI residual mismatch",
133 "SCSI task management failed",
134 "SCSI I/O controller terminated",
135 "SCSI external controller terminated",
136 "EEDP guard error",
137 "EEDP reference tag error",
138 "EEDP application tag error",
139 NULL, /* 0x0050 */
140 NULL,
141 NULL,
142 NULL,
143 NULL,
144 NULL,
145 NULL,
146 NULL,
147 NULL, /* 0x0058 */
148 NULL,
149 NULL,
150 NULL,
151 NULL,
152 NULL,
153 NULL,
154 NULL,
155 "SCSI target priority I/O", /* 0x0060 */
156 "Invalid SCSI target port",
157 "Invalid SCSI target I/O index",
158 "SCSI target aborted",
159 "No connection retryable",
160 "No connection",
161 "FC aborted",
162 "Invalid FC receive ID",
163 "FC did invalid", /* 0x0068 */
164 "FC node logged out",
165 "Transfer count mismatch",
166 "STS data not set",
167 "FC exchange canceled",
168 "Data offset error",
169 "Too much write data",
170 "IU too short",
171 "ACK NAK timeout", /* 0x0070 */
172 "NAK received",
173 NULL,
174 NULL,
175 NULL,
176 NULL,
177 NULL,
178 NULL,
179 NULL, /* 0x0078 */
180 NULL,
181 NULL,
182 NULL,
183 NULL,
184 NULL,
185 NULL,
186 NULL,
187 "LAN device not found", /* 0x0080 */
188 "LAN device failure",
189 "LAN transmit error",
190 "LAN transmit aborted",
191 "LAN receive error",
192 "LAN receive aborted",
193 "LAN partial packet",
194 "LAN canceled",
195 NULL, /* 0x0088 */
196 NULL,
197 NULL,
198 NULL,
199 NULL,
200 NULL,
201 NULL,
202 NULL,
203 "SAS SMP request failed", /* 0x0090 */
204 "SAS SMP data overrun",
205 NULL,
206 NULL,
207 NULL,
208 NULL,
209 NULL,
210 NULL,
211 "Inband aborted", /* 0x0098 */
212 "No inband connection",
213 NULL,
214 NULL,
215 NULL,
216 NULL,
217 NULL,
218 NULL,
219 "Diagnostic released", /* 0x00A0 */
220 };
221
222 struct mprs_pass_thru {
223 uint64_t PtrRequest;
224 uint64_t PtrReply;
225 uint64_t PtrData;
226 uint32_t RequestSize;
227 uint32_t ReplySize;
228 uint32_t DataSize;
229 uint32_t DataDirection;
230 uint64_t PtrDataOut;
231 uint32_t DataOutSize;
232 uint32_t Timeout;
233 };
234
235 struct mprs_btdh_mapping {
236 uint16_t TargetID;
237 uint16_t Bus;
238 uint16_t DevHandle;
239 uint16_t Reserved;
240 };
241
242 static void adjust_iocfacts_endianness(MPI2_IOC_FACTS_REPLY *facts);
243
244 const char *
mps_ioc_status(U16 IOCStatus)245 mps_ioc_status(U16 IOCStatus)
246 {
247 static char buffer[16];
248
249 IOCStatus &= MPI2_IOCSTATUS_MASK;
250 if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
251 mps_ioc_status_codes[IOCStatus] != NULL)
252 return (mps_ioc_status_codes[IOCStatus]);
253 snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
254 return (buffer);
255 }
256
257 #ifdef USE_MPT_IOCTLS
258 int
mps_map_btdh(int fd,uint16_t * devhandle,uint16_t * bus,uint16_t * target)259 mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
260 {
261 int error;
262 struct mprs_btdh_mapping map;
263
264 map.Bus = *bus;
265 map.TargetID = *target;
266 map.DevHandle = *devhandle;
267
268 if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
269 error = errno;
270 warn("Failed to map bus/target/device");
271 return (error);
272 }
273
274 *bus = map.Bus;
275 *target = map.TargetID;
276 *devhandle = map.DevHandle;
277
278 return (0);
279 }
280
281 int
mps_set_slot_status(int fd,U16 handle,U16 slot,U32 status)282 mps_set_slot_status(int fd, U16 handle, U16 slot, U32 status)
283 {
284 MPI2_SEP_REQUEST req;
285 MPI2_SEP_REPLY reply;
286
287 bzero(&req, sizeof(req));
288 req.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
289 req.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
290 req.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS;
291 req.EnclosureHandle = handle;
292 req.Slot = slot;
293 req.SlotStatus = status;
294
295 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
296 NULL, 0, NULL, 0, 30) != 0)
297 return (errno);
298
299 if (!IOC_STATUS_SUCCESS(le16toh(reply.IOCStatus)))
300 return (EIO);
301 return (0);
302 }
303
304 int
mps_read_config_page_header(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,MPI2_CONFIG_PAGE_HEADER * header,U16 * IOCStatus)305 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
306 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
307 {
308 MPI2_CONFIG_REQUEST req;
309 MPI2_CONFIG_REPLY reply;
310
311 bzero(&req, sizeof(req));
312 req.Function = MPI2_FUNCTION_CONFIG;
313 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
314 req.Header.PageType = PageType;
315 req.Header.PageNumber = PageNumber;
316 req.PageAddress = PageAddress;
317
318 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
319 NULL, 0, NULL, 0, 30))
320 return (errno);
321
322 if (!IOC_STATUS_SUCCESS(le16toh(reply.IOCStatus))) {
323 if (IOCStatus != NULL)
324 *IOCStatus = reply.IOCStatus;
325 return (EIO);
326 }
327 if (header == NULL)
328 return (EINVAL);
329 *header = reply.Header;
330 return (0);
331 }
332
333 int
mps_read_ext_config_page_header(int fd,U8 ExtPageType,U8 PageNumber,U32 PageAddress,MPI2_CONFIG_PAGE_HEADER * header,U16 * ExtPageLength,U16 * IOCStatus)334 mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
335 {
336 MPI2_CONFIG_REQUEST req;
337 MPI2_CONFIG_REPLY reply;
338
339 bzero(&req, sizeof(req));
340 req.Function = MPI2_FUNCTION_CONFIG;
341 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
342 req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
343 req.ExtPageType = ExtPageType;
344 req.Header.PageNumber = PageNumber;
345 req.PageAddress = htole32(PageAddress);
346
347 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
348 NULL, 0, NULL, 0, 30))
349 return (errno);
350
351 if (!IOC_STATUS_SUCCESS(le16toh(reply.IOCStatus))) {
352 if (IOCStatus != NULL)
353 *IOCStatus = le16toh(reply.IOCStatus);
354 return (EIO);
355 }
356 if ((header == NULL) || (ExtPageLength == NULL))
357 return (EINVAL);
358 *header = reply.Header;
359 *ExtPageLength = reply.ExtPageLength;
360 return (0);
361 }
362
363 void *
mps_read_config_page(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)364 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
365 U16 *IOCStatus)
366 {
367 MPI2_CONFIG_REQUEST req;
368 MPI2_CONFIG_PAGE_HEADER header;
369 MPI2_CONFIG_REPLY reply;
370 void *buf;
371 int error, len;
372
373 bzero(&header, sizeof(header));
374 error = mps_read_config_page_header(fd, PageType, PageNumber,
375 PageAddress, &header, IOCStatus);
376 if (error) {
377 errno = error;
378 return (NULL);
379 }
380
381 bzero(&req, sizeof(req));
382 req.Function = MPI2_FUNCTION_CONFIG;
383 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
384 req.PageAddress = htole32(PageAddress);
385 req.Header = header;
386 if (req.Header.PageLength == 0)
387 req.Header.PageLength = 4;
388
389 len = req.Header.PageLength * 4;
390 buf = malloc(len);
391 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
392 buf, len, NULL, 0, 30)) {
393 error = errno;
394 free(buf);
395 errno = error;
396 return (NULL);
397 }
398 reply.IOCStatus = le16toh(reply.IOCStatus);
399 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
400 if (IOCStatus != NULL)
401 *IOCStatus = reply.IOCStatus;
402 else
403 warnx("Reading config page failed: 0x%x %s",
404 reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
405 free(buf);
406 errno = EIO;
407 return (NULL);
408 }
409 return (buf);
410 }
411
412 void *
mps_read_extended_config_page(int fd,U8 ExtPageType,U8 PageVersion,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)413 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
414 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
415 {
416 MPI2_CONFIG_REQUEST req;
417 MPI2_CONFIG_PAGE_HEADER header;
418 MPI2_CONFIG_REPLY reply;
419 U16 pagelen;
420 void *buf;
421 int error, len;
422
423 if (IOCStatus != NULL)
424 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
425 bzero(&header, sizeof(header));
426 error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
427 PageAddress, &header, &pagelen, IOCStatus);
428 if (error) {
429 errno = error;
430 return (NULL);
431 }
432
433 bzero(&req, sizeof(req));
434 req.Function = MPI2_FUNCTION_CONFIG;
435 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
436 req.PageAddress = htole32(PageAddress);
437 req.Header = header;
438 if (pagelen == 0)
439 pagelen = htole16(4);
440 req.ExtPageLength = pagelen;
441 req.ExtPageType = ExtPageType;
442
443 len = le16toh(pagelen) * 4;
444 buf = malloc(len);
445 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
446 buf, len, NULL, 0, 30)) {
447 error = errno;
448 free(buf);
449 errno = error;
450 return (NULL);
451 }
452 reply.IOCStatus = le16toh(reply.IOCStatus);
453 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
454 if (IOCStatus != NULL)
455 *IOCStatus = reply.IOCStatus;
456 else
457 warnx("Reading extended config page failed: %s",
458 mps_ioc_status(reply.IOCStatus));
459 free(buf);
460 errno = EIO;
461 return (NULL);
462 }
463 return (buf);
464 }
465
466 int
mps_firmware_send(int fd,unsigned char * fw,uint32_t len,bool bios)467 mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios)
468 {
469 MPI2_FW_DOWNLOAD_REQUEST req;
470 MPI2_FW_DOWNLOAD_REPLY reply;
471
472 bzero(&req, sizeof(req));
473 bzero(&reply, sizeof(reply));
474 req.Function = MPI2_FUNCTION_FW_DOWNLOAD;
475 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
476 req.TotalImageSize = htole32(len);
477 req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
478
479 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
480 fw, len, 0)) {
481 return (-1);
482 }
483 return (0);
484 }
485
486 int
mps_firmware_get(int fd,unsigned char ** firmware,bool bios)487 mps_firmware_get(int fd, unsigned char **firmware, bool bios)
488 {
489 MPI2_FW_UPLOAD_REQUEST req;
490 MPI2_FW_UPLOAD_REPLY reply;
491 int size;
492
493 *firmware = NULL;
494 bzero(&req, sizeof(req));
495 bzero(&reply, sizeof(reply));
496 req.Function = MPI2_FUNCTION_FW_UPLOAD;
497 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
498
499 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
500 NULL, 0, 0)) {
501 return (-1);
502 }
503 if (reply.ActualImageSize == 0) {
504 return (-1);
505 }
506
507 size = le32toh(reply.ActualImageSize);
508 *firmware = calloc(size, sizeof(unsigned char));
509 if (*firmware == NULL) {
510 warn("calloc");
511 return (-1);
512 }
513 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
514 *firmware, size, 0)) {
515 free(*firmware);
516 return (-1);
517 }
518
519 return (size);
520 }
521
522 #else
523
524 int
mps_read_config_page_header(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,MPI2_CONFIG_PAGE_HEADER * header,U16 * IOCStatus)525 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
526 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
527 {
528 struct mps_cfg_page_req req;
529
530 if (IOCStatus != NULL)
531 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
532 if (header == NULL)
533 return (EINVAL);
534 bzero(&req, sizeof(req));
535 req.header.PageType = PageType;
536 req.header.PageNumber = PageNumber;
537 req.page_address = PageAddress;
538 if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
539 return (errno);
540 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
541 if (IOCStatus != NULL)
542 *IOCStatus = req.ioc_status;
543 return (EIO);
544 }
545 bcopy(&req.header, header, sizeof(*header));
546 return (0);
547 }
548
549 void *
mps_read_config_page(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)550 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
551 U16 *IOCStatus)
552 {
553 struct mps_cfg_page_req req;
554 void *buf;
555 int error;
556
557 error = mps_read_config_page_header(fd, PageType, PageNumber,
558 PageAddress, &req.header, IOCStatus);
559 if (error) {
560 errno = error;
561 return (NULL);
562 }
563
564 if (req.header.PageLength == 0)
565 req.header.PageLength = 4;
566 req.len = req.header.PageLength * 4;
567 buf = malloc(req.len);
568 req.buf = buf;
569 bcopy(&req.header, buf, sizeof(req.header));
570 if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
571 error = errno;
572 free(buf);
573 errno = error;
574 return (NULL);
575 }
576 req.ioc_status = le16toh(req.ioc_status);
577 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
578 if (IOCStatus != NULL)
579 *IOCStatus = req.ioc_status;
580 else
581 warnx("Reading config page failed: 0x%x %s",
582 req.ioc_status, mps_ioc_status(req.ioc_status));
583 free(buf);
584 errno = EIO;
585 return (NULL);
586 }
587 return (buf);
588 }
589
590 void *
mps_read_extended_config_page(int fd,U8 ExtPageType,U8 PageVersion,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)591 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
592 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
593 {
594 struct mps_ext_cfg_page_req req;
595 void *buf;
596 int error;
597
598 if (IOCStatus != NULL)
599 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
600 bzero(&req, sizeof(req));
601 req.header.PageVersion = PageVersion;
602 req.header.PageNumber = PageNumber;
603 req.header.ExtPageType = ExtPageType;
604 req.page_address = htole32(PageAddress);
605 if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
606 return (NULL);
607 req.ioc_status = le16toh(req.ioc_status);
608 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
609 if (IOCStatus != NULL)
610 *IOCStatus = req.ioc_status;
611 else
612 warnx("Reading extended config page header failed: %s",
613 mps_ioc_status(req.ioc_status));
614 errno = EIO;
615 return (NULL);
616 }
617 req.len = req.header.ExtPageLength * 4;
618 buf = malloc(req.len);
619 req.buf = buf;
620 bcopy(&req.header, buf, sizeof(req.header));
621 if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
622 error = errno;
623 free(buf);
624 errno = error;
625 return (NULL);
626 }
627 req.ioc_status = le16toh(req.ioc_status);
628 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
629 if (IOCStatus != NULL)
630 *IOCStatus = req.ioc_status;
631 else
632 warnx("Reading extended config page failed: %s",
633 mps_ioc_status(req.ioc_status));
634 free(buf);
635 errno = EIO;
636 return (NULL);
637 }
638 return (buf);
639 }
640 #endif
641
642 int
mps_open(int unit)643 mps_open(int unit)
644 {
645 char path[MAXPATHLEN];
646
647 snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
648 return (open(path, O_RDWR));
649 }
650
651 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)652 mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
653 uint32_t reply_len, void *buffer, int len, uint32_t flags)
654 {
655 struct mps_usr_command cmd;
656
657 bzero(&cmd, sizeof(struct mps_usr_command));
658 cmd.req = req;
659 cmd.req_len = req_len;
660 cmd.rpl = reply;
661 cmd.rpl_len = reply_len;
662 cmd.buf = buffer;
663 cmd.len = len;
664 cmd.flags = flags;
665
666 if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
667 return (errno);
668 return (0);
669 }
670
671 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)672 mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
673 uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
674 uint32_t dataout_len, uint32_t timeout)
675 {
676 struct mprs_pass_thru pass;
677
678 bzero(&pass, sizeof(pass));
679 pass.PtrRequest = (uint64_t)(uintptr_t)req;
680 pass.PtrReply = (uint64_t)(uintptr_t)reply;
681 pass.RequestSize = req_len;
682 pass.ReplySize = reply_len;
683 if (datain_len && dataout_len) {
684 pass.PtrData = (uint64_t)(uintptr_t)data_in;
685 pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
686 pass.DataSize = datain_len;
687 pass.DataOutSize = dataout_len;
688 if (is_mps) {
689 pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
690 } else {
691 pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
692 }
693 } else if (datain_len) {
694 pass.PtrData = (uint64_t)(uintptr_t)data_in;
695 pass.DataSize = datain_len;
696 if (is_mps) {
697 pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
698 } else {
699 pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
700 }
701 } else if (dataout_len) {
702 pass.PtrData = (uint64_t)(uintptr_t)data_out;
703 pass.DataSize = dataout_len;
704 if (is_mps) {
705 pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
706 } else {
707 pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
708 }
709 } else {
710 if (is_mps) {
711 pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
712 } else {
713 pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
714 }
715 }
716 pass.Timeout = timeout;
717
718 if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
719 return (errno);
720 return (0);
721 }
722
723 /* Return the length in bytes of the device's MPI2_IOC_FACTS reply */
724 static size_t
mps_get_ioc_factslen(int fd)725 mps_get_ioc_factslen(int fd)
726 {
727 MPI2_IOC_FACTS_REQUEST req;
728 const size_t factslen = 4;
729 char factsbuf[4] = {0};
730 MPI2_IOC_FACTS_REPLY *facts = (MPI2_IOC_FACTS_REPLY*)factsbuf;
731 int error;
732
733 bzero(&req, sizeof(req));
734 req.Function = MPI2_FUNCTION_IOC_FACTS;
735 error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
736 factsbuf, factslen, NULL, 0, NULL, 0, 10);
737
738 if (error)
739 return (0);
740
741 /* The card's response is measured in dwords */
742 return (facts->MsgLength * 4);
743 }
744
745 MPI2_IOC_FACTS_REPLY *
mps_get_iocfacts(int fd)746 mps_get_iocfacts(int fd)
747 {
748 MPI2_IOC_FACTS_REPLY *facts;
749 MPI2_IOC_FACTS_REQUEST req;
750 size_t factslen;
751 int error;
752
753 factslen = mps_get_ioc_factslen(fd);
754 if (factslen == 0)
755 return (NULL);
756
757 facts = malloc(factslen);
758 if (facts == NULL) {
759 errno = ENOMEM;
760 return (NULL);
761 }
762
763 bzero(&req, sizeof(req));
764 req.Function = MPI2_FUNCTION_IOC_FACTS;
765
766 #if 1
767 error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
768 facts, factslen, NULL, 0, NULL, 0, 10);
769 #else
770 error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
771 facts, factslen, NULL, 0, 0);
772 #endif
773 if (error) {
774 free(facts);
775 return (NULL);
776 }
777
778 if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
779 free(facts);
780 errno = EINVAL;
781 return (NULL);
782 }
783 adjust_iocfacts_endianness(facts);
784 return (facts);
785 }
786
787 static void
adjust_iocfacts_endianness(MPI2_IOC_FACTS_REPLY * facts)788 adjust_iocfacts_endianness(MPI2_IOC_FACTS_REPLY *facts)
789 {
790 facts->MsgVersion = le16toh(facts->MsgVersion);
791 facts->HeaderVersion = le16toh(facts->HeaderVersion);
792 facts->Reserved1 = le16toh(facts->Reserved1);
793 facts->IOCExceptions = le16toh(facts->IOCExceptions);
794 facts->IOCStatus = le16toh(facts->IOCStatus);
795 facts->IOCLogInfo = le32toh(facts->IOCLogInfo);
796 facts->RequestCredit = le16toh(facts->RequestCredit);
797 facts->ProductID = le16toh(facts->ProductID);
798 facts->IOCCapabilities = le32toh(facts->IOCCapabilities);
799 facts->IOCRequestFrameSize =
800 le16toh(facts->IOCRequestFrameSize);
801 facts->FWVersion.Word = le32toh(facts->FWVersion.Word);
802 facts->MaxInitiators = le16toh(facts->MaxInitiators);
803 facts->MaxTargets = le16toh(facts->MaxTargets);
804 facts->MaxSasExpanders = le16toh(facts->MaxSasExpanders);
805 facts->MaxEnclosures = le16toh(facts->MaxEnclosures);
806 facts->ProtocolFlags = le16toh(facts->ProtocolFlags);
807 facts->HighPriorityCredit = le16toh(facts->HighPriorityCredit);
808 facts->MaxReplyDescriptorPostQueueDepth =
809 le16toh(facts->MaxReplyDescriptorPostQueueDepth);
810 facts->MaxDevHandle = le16toh(facts->MaxDevHandle);
811 facts->MaxPersistentEntries =
812 le16toh(facts->MaxPersistentEntries);
813 facts->MinDevHandle = le16toh(facts->MinDevHandle);
814 }
815