2 * QEMU LSI SAS1068 Host Bus Adapter emulation - configuration pages
4 * Copyright (c) 2016 Red Hat, Inc.
6 * Author: Paolo Bonzini
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 #include "qemu/osdep.h"
19 #include "hw/pci/pci.h"
20 #include "hw/scsi/scsi.h"
26 /* Generic functions for marshaling and unmarshaling. */
30 #define repl3(x) x x x
31 #define repl4(x) x x x x
32 #define repl5(x) x x x x x
33 #define repl6(x) x x x x x x
34 #define repl7(x) x x x x x x x
35 #define repl8(x) x x x x x x x x
37 #define repl(n, x) glue(repl, n)(x)
39 typedef union PackValue
{
44 static size_t vfill(uint8_t *data
, size_t size
, const char *fmt
, va_list ap
)
53 memset(&val
, 0, sizeof(val
));
61 val
.ll
= va_arg(ap
, int);
64 val
.ll
= va_arg(ap
, int64_t);
67 val
.str
= va_arg(ap
, void *);
73 stb_p(data
+ ofs
, val
.ll
);
79 stw_le_p(data
+ ofs
, val
.ll
);
85 stl_le_p(data
+ ofs
, val
.ll
);
91 stq_le_p(data
+ ofs
, val
.ll
);
100 strncpy((void *)data
+ ofs
, val
.str
, cnt
);
102 memset((void *)data
+ ofs
, 0, cnt
);
114 static size_t vpack(uint8_t **p_data
, const char *fmt
, va_list ap1
)
117 uint8_t *data
= NULL
;
123 size
= vfill(NULL
, 0, fmt
, ap2
);
124 *p_data
= data
= g_malloc(size
);
127 return vfill(data
, size
, fmt
, ap1
);
130 static size_t fill(uint8_t *data
, size_t size
, const char *fmt
, ...)
136 ret
= vfill(data
, size
, fmt
, ap
);
142 /* Functions to build the page header and fill in the length, always used
143 * through the macros.
146 #define MPTSAS_CONFIG_PACK(number, type, version, fmt, ...) \
147 mptsas_config_pack(data, "b*bbb" fmt, version, number, type, \
150 static size_t mptsas_config_pack(uint8_t **data
, const char *fmt
, ...)
156 ret
= vpack(data
, fmt
, ap
);
160 assert(ret
/ 4 < 256 && (ret
% 4) == 0);
161 stb_p(*data
+ 1, ret
/ 4);
166 #define MPTSAS_CONFIG_PACK_EXT(number, type, version, fmt, ...) \
167 mptsas_config_pack_ext(data, "b*bbb*wb*b" fmt, version, number, \
168 MPI_CONFIG_PAGETYPE_EXTENDED, type, ## __VA_ARGS__)
170 static size_t mptsas_config_pack_ext(uint8_t **data
, const char *fmt
, ...)
176 ret
= vpack(data
, fmt
, ap
);
180 assert(ret
< 65536 && (ret
% 4) == 0);
181 stw_le_p(*data
+ 4, ret
/ 4);
186 /* Manufacturing pages */
189 size_t mptsas_config_manufacturing_0(MPTSASState
*s
, uint8_t **data
, int address
)
191 return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
201 size_t mptsas_config_manufacturing_1(MPTSASState
*s
, uint8_t **data
, int address
)
203 /* VPD - all zeros */
204 return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
209 size_t mptsas_config_manufacturing_2(MPTSASState
*s
, uint8_t **data
, int address
)
211 PCIDeviceClass
*pcic
= PCI_DEVICE_GET_CLASS(s
);
212 return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
214 pcic
->device_id
, pcic
->revision
);
218 size_t mptsas_config_manufacturing_3(MPTSASState
*s
, uint8_t **data
, int address
)
220 PCIDeviceClass
*pcic
= PCI_DEVICE_GET_CLASS(s
);
221 return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
223 pcic
->device_id
, pcic
->revision
);
227 size_t mptsas_config_manufacturing_4(MPTSASState
*s
, uint8_t **data
, int address
)
230 return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x05,
231 "*l*b*b*b*b*b*b*w*s56*l*l*l*l*l*l"
236 size_t mptsas_config_manufacturing_5(MPTSASState
*s
, uint8_t **data
, int address
)
238 return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x02,
239 "q*b*b*w*l*l", s
->sas_addr
);
243 size_t mptsas_config_manufacturing_6(MPTSASState
*s
, uint8_t **data
, int address
)
245 return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
250 size_t mptsas_config_manufacturing_7(MPTSASState
*s
, uint8_t **data
, int address
)
252 return MPTSAS_CONFIG_PACK(7, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
253 "*l*l*l*s16*b*b*w", MPTSAS_NUM_PORTS
);
257 size_t mptsas_config_manufacturing_8(MPTSASState
*s
, uint8_t **data
, int address
)
259 return MPTSAS_CONFIG_PACK(8, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
264 size_t mptsas_config_manufacturing_9(MPTSASState
*s
, uint8_t **data
, int address
)
266 return MPTSAS_CONFIG_PACK(9, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
271 size_t mptsas_config_manufacturing_10(MPTSASState
*s
, uint8_t **data
, int address
)
273 return MPTSAS_CONFIG_PACK(10, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
280 size_t mptsas_config_io_unit_0(MPTSASState
*s
, uint8_t **data
, int address
)
282 PCIDevice
*pci
= PCI_DEVICE(s
);
283 uint64_t unique_value
= 0x53504D554D4551LL
; /* "QEMUMPTx" */
285 unique_value
|= (uint64_t)pci
->devfn
<< 56;
286 return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IO_UNIT
, 0x00,
291 size_t mptsas_config_io_unit_1(MPTSASState
*s
, uint8_t **data
, int address
)
293 return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IO_UNIT
, 0x02, "l",
294 0x41 /* single function, RAID disabled */ );
298 size_t mptsas_config_io_unit_2(MPTSASState
*s
, uint8_t **data
, int address
)
300 PCIDevice
*pci
= PCI_DEVICE(s
);
301 uint8_t devfn
= pci
->devfn
;
302 return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IO_UNIT
, 0x02,
303 "llbbw*b*b*w*b*b*w*b*b*w*l",
304 0, 0x100, 0 /* pci bus? */, devfn
, 0);
308 size_t mptsas_config_io_unit_3(MPTSASState
*s
, uint8_t **data
, int address
)
310 return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IO_UNIT
, 0x01,
315 size_t mptsas_config_io_unit_4(MPTSASState
*s
, uint8_t **data
, int address
)
317 return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IO_UNIT
, 0x00, "*l*l*q");
320 /* I/O controller pages */
323 size_t mptsas_config_ioc_0(MPTSASState
*s
, uint8_t **data
, int address
)
325 PCIDeviceClass
*pcic
= PCI_DEVICE_GET_CLASS(s
);
327 return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IOC
, 0x01,
329 pcic
->vendor_id
, pcic
->device_id
, pcic
->revision
,
330 pcic
->class_id
, pcic
->subsystem_vendor_id
,
335 size_t mptsas_config_ioc_1(MPTSASState
*s
, uint8_t **data
, int address
)
337 return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IOC
, 0x03,
342 size_t mptsas_config_ioc_2(MPTSASState
*s
, uint8_t **data
, int address
)
344 return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IOC
, 0x04,
349 size_t mptsas_config_ioc_3(MPTSASState
*s
, uint8_t **data
, int address
)
351 return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IOC
, 0x00,
356 size_t mptsas_config_ioc_4(MPTSASState
*s
, uint8_t **data
, int address
)
358 return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IOC
, 0x00,
363 size_t mptsas_config_ioc_5(MPTSASState
*s
, uint8_t **data
, int address
)
365 return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_IOC
, 0x00,
370 size_t mptsas_config_ioc_6(MPTSASState
*s
, uint8_t **data
, int address
)
372 return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_IOC
, 0x01,
373 "*l*b*b*b*b*b*b*b*b*b*b*w*l*l*l*l*b*b*w"
377 /* SAS I/O unit pages (extended) */
379 #define MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE 16
381 #define MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION 0x02
382 #define MPI_SAS_IOUNIT0_RATE_1_5 0x08
383 #define MPI_SAS_IOUNIT0_RATE_3_0 0x09
385 #define MPI_SAS_DEVICE_INFO_NO_DEVICE 0x00000000
386 #define MPI_SAS_DEVICE_INFO_END_DEVICE 0x00000001
387 #define MPI_SAS_DEVICE_INFO_SSP_TARGET 0x00000400
389 #define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS 0x00
391 #define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT 0x0001
392 #define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED 0x0002
393 #define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT 0x0004
397 static SCSIDevice
*mptsas_phy_get_device(MPTSASState
*s
, int i
,
398 int *phy_handle
, int *dev_handle
)
400 SCSIDevice
*d
= scsi_device_find(&s
->bus
, 0, i
, 0);
406 *dev_handle
= d
? i
+ 1 + MPTSAS_NUM_PORTS
: 0;
412 size_t mptsas_config_sas_io_unit_0(MPTSASState
*s
, uint8_t **data
, int address
)
414 size_t size
= MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 0x04,
416 repl(MPTSAS_NUM_PORTS
, "*s16"),
420 size_t ofs
= size
- MPTSAS_NUM_PORTS
* MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE
;
423 for (i
= 0; i
< MPTSAS_NUM_PORTS
; i
++) {
424 int phy_handle
, dev_handle
;
425 SCSIDevice
*dev
= mptsas_phy_get_device(s
, i
, &phy_handle
, &dev_handle
);
427 fill(*data
+ ofs
, MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE
,
430 ? MPI_SAS_IOUNIT0_RATE_3_0
431 : MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION
),
433 ? MPI_SAS_DEVICE_INFO_END_DEVICE
| MPI_SAS_DEVICE_INFO_SSP_TARGET
434 : MPI_SAS_DEVICE_INFO_NO_DEVICE
),
438 ofs
+= MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE
;
445 #define MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE 12
448 size_t mptsas_config_sas_io_unit_1(MPTSASState
*s
, uint8_t **data
, int address
)
450 size_t size
= MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 0x07,
452 repl(MPTSAS_NUM_PORTS
, "*s12"),
456 size_t ofs
= size
- MPTSAS_NUM_PORTS
* MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE
;
459 for (i
= 0; i
< MPTSAS_NUM_PORTS
; i
++) {
460 SCSIDevice
*dev
= mptsas_phy_get_device(s
, i
, NULL
, NULL
);
461 fill(*data
+ ofs
, MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE
,
463 (MPI_SAS_IOUNIT0_RATE_3_0
<< 4) | MPI_SAS_IOUNIT0_RATE_1_5
,
465 ? MPI_SAS_DEVICE_INFO_END_DEVICE
| MPI_SAS_DEVICE_INFO_SSP_TARGET
466 : MPI_SAS_DEVICE_INFO_NO_DEVICE
),
468 ofs
+= MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE
;
476 size_t mptsas_config_sas_io_unit_2(MPTSASState
*s
, uint8_t **data
, int address
)
478 return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 0x06,
483 size_t mptsas_config_sas_io_unit_3(MPTSASState
*s
, uint8_t **data
, int address
)
485 return MPTSAS_CONFIG_PACK_EXT(3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 0x06,
486 "*l*l*l*l*l*l*l*l*l");
489 /* SAS PHY pages (extended) */
491 static int mptsas_phy_addr_get(MPTSASState
*s
, int address
)
494 if ((address
>> MPI_SAS_PHY_PGAD_FORM_SHIFT
) == 0) {
496 } else if ((address
>> MPI_SAS_PHY_PGAD_FORM_SHIFT
) == 1) {
502 if (i
>= MPTSAS_NUM_PORTS
) {
510 size_t mptsas_config_phy_0(MPTSASState
*s
, uint8_t **data
, int address
)
514 int i
= mptsas_phy_addr_get(s
, address
);
518 trace_mptsas_config_sas_phy(s
, address
, i
, phy_handle
, dev_handle
, 0);
522 dev
= mptsas_phy_get_device(s
, i
, &phy_handle
, &dev_handle
);
523 trace_mptsas_config_sas_phy(s
, address
, i
, phy_handle
, dev_handle
, 0);
525 return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY
, 0x01,
527 dev_handle
, s
->sas_addr
, dev_handle
, i
,
529 ? MPI_SAS_DEVICE_INFO_END_DEVICE
/* | MPI_SAS_DEVICE_INFO_SSP_TARGET?? */
530 : MPI_SAS_DEVICE_INFO_NO_DEVICE
),
531 (MPI_SAS_IOUNIT0_RATE_3_0
<< 4) | MPI_SAS_IOUNIT0_RATE_1_5
,
532 (MPI_SAS_IOUNIT0_RATE_3_0
<< 4) | MPI_SAS_IOUNIT0_RATE_1_5
);
536 size_t mptsas_config_phy_1(MPTSASState
*s
, uint8_t **data
, int address
)
540 int i
= mptsas_phy_addr_get(s
, address
);
543 trace_mptsas_config_sas_phy(s
, address
, i
, phy_handle
, dev_handle
, 1);
547 (void) mptsas_phy_get_device(s
, i
, &phy_handle
, &dev_handle
);
548 trace_mptsas_config_sas_phy(s
, address
, i
, phy_handle
, dev_handle
, 1);
550 return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY
, 0x01,
554 /* SAS device pages (extended) */
556 static int mptsas_device_addr_get(MPTSASState
*s
, int address
)
559 uint32_t form
= address
>> MPI_SAS_PHY_PGAD_FORM_SHIFT
;
560 if (form
== MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE
) {
561 handle
= address
& MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK
;
563 if (handle
== 65535) {
564 handle
= MPTSAS_NUM_PORTS
+ 1;
568 i
= handle
- 1 - MPTSAS_NUM_PORTS
;
569 } while (i
< MPTSAS_NUM_PORTS
&& !scsi_device_find(&s
->bus
, 0, i
, 0));
571 } else if (form
== MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
) {
572 if (address
& MPI_SAS_DEVICE_PGAD_BT_BUS_MASK
) {
575 i
= address
& MPI_SAS_DEVICE_PGAD_BT_TID_MASK
;
577 } else if (form
== MPI_SAS_DEVICE_PGAD_FORM_HANDLE
) {
578 handle
= address
& MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK
;
579 i
= handle
- 1 - MPTSAS_NUM_PORTS
;
585 if (i
>= MPTSAS_NUM_PORTS
) {
593 size_t mptsas_config_sas_device_0(MPTSASState
*s
, uint8_t **data
, int address
)
597 int i
= mptsas_device_addr_get(s
, address
);
598 SCSIDevice
*dev
= mptsas_phy_get_device(s
, i
, &phy_handle
, &dev_handle
);
600 trace_mptsas_config_sas_device(s
, address
, i
, phy_handle
, dev_handle
, 0);
605 return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
, 0x05,
607 dev
->wwn
, phy_handle
, i
,
608 MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS
,
610 MPI_SAS_DEVICE_INFO_END_DEVICE
| MPI_SAS_DEVICE_INFO_SSP_TARGET
,
611 (MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT
|
612 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED
|
613 MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT
), i
);
617 size_t mptsas_config_sas_device_1(MPTSASState
*s
, uint8_t **data
, int address
)
621 int i
= mptsas_device_addr_get(s
, address
);
622 SCSIDevice
*dev
= mptsas_phy_get_device(s
, i
, &phy_handle
, &dev_handle
);
624 trace_mptsas_config_sas_device(s
, address
, i
, phy_handle
, dev_handle
, 1);
629 return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
, 0x00,
631 dev
->wwn
, dev_handle
, i
, 0);
635 size_t mptsas_config_sas_device_2(MPTSASState
*s
, uint8_t **data
, int address
)
639 int i
= mptsas_device_addr_get(s
, address
);
640 SCSIDevice
*dev
= mptsas_phy_get_device(s
, i
, &phy_handle
, &dev_handle
);
642 trace_mptsas_config_sas_device(s
, address
, i
, phy_handle
, dev_handle
, 2);
647 return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
, 0x01,
651 typedef struct MPTSASConfigPage
{
654 size_t (*mpt_config_build
)(MPTSASState
*s
, uint8_t **data
, int address
);
657 static const MPTSASConfigPage mptsas_config_pages
[] = {
659 0, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
660 mptsas_config_manufacturing_0
,
662 1, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
663 mptsas_config_manufacturing_1
,
665 2, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
666 mptsas_config_manufacturing_2
,
668 3, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
669 mptsas_config_manufacturing_3
,
671 4, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
672 mptsas_config_manufacturing_4
,
674 5, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
675 mptsas_config_manufacturing_5
,
677 6, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
678 mptsas_config_manufacturing_6
,
680 7, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
681 mptsas_config_manufacturing_7
,
683 8, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
684 mptsas_config_manufacturing_8
,
686 9, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
687 mptsas_config_manufacturing_9
,
689 10, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
690 mptsas_config_manufacturing_10
,
692 0, MPI_CONFIG_PAGETYPE_IO_UNIT
,
693 mptsas_config_io_unit_0
,
695 1, MPI_CONFIG_PAGETYPE_IO_UNIT
,
696 mptsas_config_io_unit_1
,
698 2, MPI_CONFIG_PAGETYPE_IO_UNIT
,
699 mptsas_config_io_unit_2
,
701 3, MPI_CONFIG_PAGETYPE_IO_UNIT
,
702 mptsas_config_io_unit_3
,
704 4, MPI_CONFIG_PAGETYPE_IO_UNIT
,
705 mptsas_config_io_unit_4
,
707 0, MPI_CONFIG_PAGETYPE_IOC
,
710 1, MPI_CONFIG_PAGETYPE_IOC
,
713 2, MPI_CONFIG_PAGETYPE_IOC
,
716 3, MPI_CONFIG_PAGETYPE_IOC
,
719 4, MPI_CONFIG_PAGETYPE_IOC
,
722 5, MPI_CONFIG_PAGETYPE_IOC
,
725 6, MPI_CONFIG_PAGETYPE_IOC
,
728 0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
729 mptsas_config_sas_io_unit_0
,
731 1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
732 mptsas_config_sas_io_unit_1
,
734 2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
735 mptsas_config_sas_io_unit_2
,
737 3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
738 mptsas_config_sas_io_unit_3
,
740 0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY
,
743 1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY
,
746 0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
,
747 mptsas_config_sas_device_0
,
749 1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
,
750 mptsas_config_sas_device_1
,
752 2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
,
753 mptsas_config_sas_device_2
,
757 static const MPTSASConfigPage
*mptsas_find_config_page(int type
, int number
)
759 const MPTSASConfigPage
*page
;
762 for (i
= 0; i
< ARRAY_SIZE(mptsas_config_pages
); i
++) {
763 page
= &mptsas_config_pages
[i
];
764 if (page
->type
== type
&& page
->number
== number
) {
772 void mptsas_process_config(MPTSASState
*s
, MPIMsgConfig
*req
)
774 PCIDevice
*pci
= PCI_DEVICE(s
);
776 MPIMsgConfigReply reply
;
777 const MPTSASConfigPage
*page
;
780 uint8_t *data
= NULL
;
781 uint32_t flags_and_length
;
785 mptsas_fix_config_endianness(req
);
787 QEMU_BUILD_BUG_ON(sizeof(s
->doorbell_msg
) < sizeof(*req
));
788 QEMU_BUILD_BUG_ON(sizeof(s
->doorbell_reply
) < sizeof(reply
));
790 /* Copy common bits from the request into the reply. */
791 memset(&reply
, 0, sizeof(reply
));
792 reply
.Action
= req
->Action
;
793 reply
.Function
= req
->Function
;
794 reply
.MsgContext
= req
->MsgContext
;
795 reply
.MsgLength
= sizeof(reply
) / 4;
796 reply
.PageType
= req
->PageType
;
797 reply
.PageNumber
= req
->PageNumber
;
798 reply
.PageLength
= req
->PageLength
;
799 reply
.PageVersion
= req
->PageVersion
;
801 type
= req
->PageType
& MPI_CONFIG_PAGETYPE_MASK
;
802 if (type
== MPI_CONFIG_PAGETYPE_EXTENDED
) {
803 type
= req
->ExtPageType
;
804 if (type
<= MPI_CONFIG_PAGETYPE_MASK
) {
805 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_TYPE
;
809 reply
.ExtPageType
= req
->ExtPageType
;
812 page
= mptsas_find_config_page(type
, req
->PageNumber
);
814 switch(req
->Action
) {
815 case MPI_CONFIG_ACTION_PAGE_DEFAULT
:
816 case MPI_CONFIG_ACTION_PAGE_HEADER
:
817 case MPI_CONFIG_ACTION_PAGE_READ_NVRAM
:
818 case MPI_CONFIG_ACTION_PAGE_READ_CURRENT
:
819 case MPI_CONFIG_ACTION_PAGE_READ_DEFAULT
:
820 case MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT
:
821 case MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM
:
825 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_ACTION
;
830 page
= mptsas_find_config_page(type
, 1);
832 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_PAGE
;
834 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_TYPE
;
839 if (req
->Action
== MPI_CONFIG_ACTION_PAGE_DEFAULT
||
840 req
->Action
== MPI_CONFIG_ACTION_PAGE_HEADER
) {
841 length
= page
->mpt_config_build(s
, NULL
, req
->PageAddress
);
842 if ((ssize_t
)length
< 0) {
843 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_PAGE
;
850 if (req
->Action
== MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT
||
851 req
->Action
== MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM
) {
852 length
= page
->mpt_config_build(s
, NULL
, req
->PageAddress
);
853 if ((ssize_t
)length
< 0) {
854 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_PAGE
;
856 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_CANT_COMMIT
;
861 flags_and_length
= req
->PageBufferSGE
.FlagsLength
;
862 dmalen
= flags_and_length
& MPI_SGE_LENGTH_MASK
;
864 length
= page
->mpt_config_build(s
, NULL
, req
->PageAddress
);
865 if ((ssize_t
)length
< 0) {
866 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_PAGE
;
873 if (flags_and_length
& MPI_SGE_FLAGS_64_BIT_ADDRESSING
) {
874 pa
= req
->PageBufferSGE
.u
.Address64
;
876 pa
= req
->PageBufferSGE
.u
.Address32
;
879 /* Only read actions left. */
880 length
= page
->mpt_config_build(s
, &data
, req
->PageAddress
);
881 if ((ssize_t
)length
< 0) {
882 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_PAGE
;
885 assert(data
[2] == page
->number
);
886 pci_dma_write(pci
, pa
, data
, MIN(length
, dmalen
));
893 if (type
> MPI_CONFIG_PAGETYPE_MASK
) {
894 reply
.ExtPageLength
= length
/ 4;
895 reply
.ExtPageType
= req
->ExtPageType
;
897 reply
.PageLength
= length
/ 4;
901 mptsas_fix_config_reply_endianness(&reply
);
902 mptsas_reply(s
, (MPIDefaultReply
*)&reply
);