root / hw / megasas.c @ 9c17d615
History | View | Annotate | Download (68.8 kB)
1 | e8f943c3 | Hannes Reinecke | /*
|
---|---|---|---|
2 | e8f943c3 | Hannes Reinecke | * QEMU MegaRAID SAS 8708EM2 Host Bus Adapter emulation
|
3 | e8f943c3 | Hannes Reinecke | * Based on the linux driver code at drivers/scsi/megaraid
|
4 | e8f943c3 | Hannes Reinecke | *
|
5 | e8f943c3 | Hannes Reinecke | * Copyright (c) 2009-2012 Hannes Reinecke, SUSE Labs
|
6 | e8f943c3 | Hannes Reinecke | *
|
7 | e8f943c3 | Hannes Reinecke | * This library is free software; you can redistribute it and/or
|
8 | e8f943c3 | Hannes Reinecke | * modify it under the terms of the GNU Lesser General Public
|
9 | e8f943c3 | Hannes Reinecke | * License as published by the Free Software Foundation; either
|
10 | e8f943c3 | Hannes Reinecke | * version 2 of the License, or (at your option) any later version.
|
11 | e8f943c3 | Hannes Reinecke | *
|
12 | e8f943c3 | Hannes Reinecke | * This library is distributed in the hope that it will be useful,
|
13 | e8f943c3 | Hannes Reinecke | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | e8f943c3 | Hannes Reinecke | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 | e8f943c3 | Hannes Reinecke | * Lesser General Public License for more details.
|
16 | e8f943c3 | Hannes Reinecke | *
|
17 | e8f943c3 | Hannes Reinecke | * You should have received a copy of the GNU Lesser General Public
|
18 | e8f943c3 | Hannes Reinecke | * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
19 | e8f943c3 | Hannes Reinecke | */
|
20 | e8f943c3 | Hannes Reinecke | |
21 | e8f943c3 | Hannes Reinecke | #include "hw.h" |
22 | a2cb15b0 | Michael S. Tsirkin | #include "pci/pci.h" |
23 | 9c17d615 | Paolo Bonzini | #include "sysemu/dma.h" |
24 | a2cb15b0 | Michael S. Tsirkin | #include "pci/msix.h" |
25 | 1de7afc9 | Paolo Bonzini | #include "qemu/iov.h" |
26 | e8f943c3 | Hannes Reinecke | #include "scsi.h" |
27 | e8f943c3 | Hannes Reinecke | #include "scsi-defs.h" |
28 | e8f943c3 | Hannes Reinecke | #include "trace.h" |
29 | e8f943c3 | Hannes Reinecke | |
30 | e8f943c3 | Hannes Reinecke | #include "mfi.h" |
31 | e8f943c3 | Hannes Reinecke | |
32 | e8f943c3 | Hannes Reinecke | #define MEGASAS_VERSION "1.70" |
33 | e8f943c3 | Hannes Reinecke | #define MEGASAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */ |
34 | e8f943c3 | Hannes Reinecke | #define MEGASAS_DEFAULT_FRAMES 1000 /* Windows requires this */ |
35 | e8f943c3 | Hannes Reinecke | #define MEGASAS_MAX_SGE 128 /* Firmware limit */ |
36 | e8f943c3 | Hannes Reinecke | #define MEGASAS_DEFAULT_SGE 80 |
37 | e8f943c3 | Hannes Reinecke | #define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */ |
38 | e8f943c3 | Hannes Reinecke | #define MEGASAS_MAX_ARRAYS 128 |
39 | e8f943c3 | Hannes Reinecke | |
40 | fb654157 | Hannes Reinecke | #define MEGASAS_HBA_SERIAL "QEMU123456" |
41 | 76b523db | Hannes Reinecke | #define NAA_LOCALLY_ASSIGNED_ID 0x3ULL |
42 | 76b523db | Hannes Reinecke | #define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400 |
43 | 76b523db | Hannes Reinecke | |
44 | e8f943c3 | Hannes Reinecke | #define MEGASAS_FLAG_USE_JBOD 0 |
45 | e8f943c3 | Hannes Reinecke | #define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD) |
46 | e8f943c3 | Hannes Reinecke | #define MEGASAS_FLAG_USE_MSIX 1 |
47 | e8f943c3 | Hannes Reinecke | #define MEGASAS_MASK_USE_MSIX (1 << MEGASAS_FLAG_USE_MSIX) |
48 | e8f943c3 | Hannes Reinecke | #define MEGASAS_FLAG_USE_QUEUE64 2 |
49 | e8f943c3 | Hannes Reinecke | #define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64) |
50 | e8f943c3 | Hannes Reinecke | |
51 | a97ad268 | Hannes Reinecke | static const char *mfi_frame_desc[] = { |
52 | e8f943c3 | Hannes Reinecke | "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI", |
53 | e8f943c3 | Hannes Reinecke | "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop"}; |
54 | e8f943c3 | Hannes Reinecke | |
55 | e8f943c3 | Hannes Reinecke | typedef struct MegasasCmd { |
56 | e8f943c3 | Hannes Reinecke | uint32_t index; |
57 | e8f943c3 | Hannes Reinecke | uint16_t flags; |
58 | e8f943c3 | Hannes Reinecke | uint16_t count; |
59 | e8f943c3 | Hannes Reinecke | uint64_t context; |
60 | e8f943c3 | Hannes Reinecke | |
61 | a8170e5e | Avi Kivity | hwaddr pa; |
62 | a8170e5e | Avi Kivity | hwaddr pa_size; |
63 | e8f943c3 | Hannes Reinecke | union mfi_frame *frame;
|
64 | e8f943c3 | Hannes Reinecke | SCSIRequest *req; |
65 | e8f943c3 | Hannes Reinecke | QEMUSGList qsg; |
66 | e8f943c3 | Hannes Reinecke | void *iov_buf;
|
67 | e8f943c3 | Hannes Reinecke | size_t iov_size; |
68 | e8f943c3 | Hannes Reinecke | size_t iov_offset; |
69 | e8f943c3 | Hannes Reinecke | struct MegasasState *state;
|
70 | e8f943c3 | Hannes Reinecke | } MegasasCmd; |
71 | e8f943c3 | Hannes Reinecke | |
72 | e8f943c3 | Hannes Reinecke | typedef struct MegasasState { |
73 | e8f943c3 | Hannes Reinecke | PCIDevice dev; |
74 | e8f943c3 | Hannes Reinecke | MemoryRegion mmio_io; |
75 | e8f943c3 | Hannes Reinecke | MemoryRegion port_io; |
76 | e8f943c3 | Hannes Reinecke | MemoryRegion queue_io; |
77 | e8f943c3 | Hannes Reinecke | uint32_t frame_hi; |
78 | e8f943c3 | Hannes Reinecke | |
79 | e8f943c3 | Hannes Reinecke | int fw_state;
|
80 | e8f943c3 | Hannes Reinecke | uint32_t fw_sge; |
81 | e8f943c3 | Hannes Reinecke | uint32_t fw_cmds; |
82 | e8f943c3 | Hannes Reinecke | uint32_t flags; |
83 | e8f943c3 | Hannes Reinecke | int fw_luns;
|
84 | e8f943c3 | Hannes Reinecke | int intr_mask;
|
85 | e8f943c3 | Hannes Reinecke | int doorbell;
|
86 | e8f943c3 | Hannes Reinecke | int busy;
|
87 | e8f943c3 | Hannes Reinecke | |
88 | e8f943c3 | Hannes Reinecke | MegasasCmd *event_cmd; |
89 | e8f943c3 | Hannes Reinecke | int event_locale;
|
90 | e8f943c3 | Hannes Reinecke | int event_class;
|
91 | e8f943c3 | Hannes Reinecke | int event_count;
|
92 | e8f943c3 | Hannes Reinecke | int shutdown_event;
|
93 | e8f943c3 | Hannes Reinecke | int boot_event;
|
94 | e8f943c3 | Hannes Reinecke | |
95 | 76b523db | Hannes Reinecke | uint64_t sas_addr; |
96 | fb654157 | Hannes Reinecke | char *hba_serial;
|
97 | 76b523db | Hannes Reinecke | |
98 | e8f943c3 | Hannes Reinecke | uint64_t reply_queue_pa; |
99 | e8f943c3 | Hannes Reinecke | void *reply_queue;
|
100 | e8f943c3 | Hannes Reinecke | int reply_queue_len;
|
101 | e8f943c3 | Hannes Reinecke | int reply_queue_head;
|
102 | e8f943c3 | Hannes Reinecke | int reply_queue_tail;
|
103 | e8f943c3 | Hannes Reinecke | uint64_t consumer_pa; |
104 | e8f943c3 | Hannes Reinecke | uint64_t producer_pa; |
105 | e8f943c3 | Hannes Reinecke | |
106 | e8f943c3 | Hannes Reinecke | MegasasCmd frames[MEGASAS_MAX_FRAMES]; |
107 | e8f943c3 | Hannes Reinecke | |
108 | e8f943c3 | Hannes Reinecke | SCSIBus bus; |
109 | e8f943c3 | Hannes Reinecke | } MegasasState; |
110 | e8f943c3 | Hannes Reinecke | |
111 | e8f943c3 | Hannes Reinecke | #define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF |
112 | e8f943c3 | Hannes Reinecke | |
113 | e8f943c3 | Hannes Reinecke | static bool megasas_intr_enabled(MegasasState *s) |
114 | e8f943c3 | Hannes Reinecke | { |
115 | e8f943c3 | Hannes Reinecke | if ((s->intr_mask & MEGASAS_INTR_DISABLED_MASK) !=
|
116 | e8f943c3 | Hannes Reinecke | MEGASAS_INTR_DISABLED_MASK) { |
117 | e8f943c3 | Hannes Reinecke | return true; |
118 | e8f943c3 | Hannes Reinecke | } |
119 | e8f943c3 | Hannes Reinecke | return false; |
120 | e8f943c3 | Hannes Reinecke | } |
121 | e8f943c3 | Hannes Reinecke | |
122 | e8f943c3 | Hannes Reinecke | static bool megasas_use_queue64(MegasasState *s) |
123 | e8f943c3 | Hannes Reinecke | { |
124 | e8f943c3 | Hannes Reinecke | return s->flags & MEGASAS_MASK_USE_QUEUE64;
|
125 | e8f943c3 | Hannes Reinecke | } |
126 | e8f943c3 | Hannes Reinecke | |
127 | e8f943c3 | Hannes Reinecke | static bool megasas_use_msix(MegasasState *s) |
128 | e8f943c3 | Hannes Reinecke | { |
129 | e8f943c3 | Hannes Reinecke | return s->flags & MEGASAS_MASK_USE_MSIX;
|
130 | e8f943c3 | Hannes Reinecke | } |
131 | e8f943c3 | Hannes Reinecke | |
132 | e8f943c3 | Hannes Reinecke | static bool megasas_is_jbod(MegasasState *s) |
133 | e8f943c3 | Hannes Reinecke | { |
134 | e8f943c3 | Hannes Reinecke | return s->flags & MEGASAS_MASK_USE_JBOD;
|
135 | e8f943c3 | Hannes Reinecke | } |
136 | e8f943c3 | Hannes Reinecke | |
137 | e8f943c3 | Hannes Reinecke | static void megasas_frame_set_cmd_status(unsigned long frame, uint8_t v) |
138 | e8f943c3 | Hannes Reinecke | { |
139 | e8f943c3 | Hannes Reinecke | stb_phys(frame + offsetof(struct mfi_frame_header, cmd_status), v);
|
140 | e8f943c3 | Hannes Reinecke | } |
141 | e8f943c3 | Hannes Reinecke | |
142 | e8f943c3 | Hannes Reinecke | static void megasas_frame_set_scsi_status(unsigned long frame, uint8_t v) |
143 | e8f943c3 | Hannes Reinecke | { |
144 | e8f943c3 | Hannes Reinecke | stb_phys(frame + offsetof(struct mfi_frame_header, scsi_status), v);
|
145 | e8f943c3 | Hannes Reinecke | } |
146 | e8f943c3 | Hannes Reinecke | |
147 | e8f943c3 | Hannes Reinecke | /*
|
148 | e8f943c3 | Hannes Reinecke | * Context is considered opaque, but the HBA firmware is running
|
149 | e8f943c3 | Hannes Reinecke | * in little endian mode. So convert it to little endian, too.
|
150 | e8f943c3 | Hannes Reinecke | */
|
151 | e8f943c3 | Hannes Reinecke | static uint64_t megasas_frame_get_context(unsigned long frame) |
152 | e8f943c3 | Hannes Reinecke | { |
153 | e8f943c3 | Hannes Reinecke | return ldq_le_phys(frame + offsetof(struct mfi_frame_header, context)); |
154 | e8f943c3 | Hannes Reinecke | } |
155 | e8f943c3 | Hannes Reinecke | |
156 | e8f943c3 | Hannes Reinecke | static bool megasas_frame_is_ieee_sgl(MegasasCmd *cmd) |
157 | e8f943c3 | Hannes Reinecke | { |
158 | e8f943c3 | Hannes Reinecke | return cmd->flags & MFI_FRAME_IEEE_SGL;
|
159 | e8f943c3 | Hannes Reinecke | } |
160 | e8f943c3 | Hannes Reinecke | |
161 | e8f943c3 | Hannes Reinecke | static bool megasas_frame_is_sgl64(MegasasCmd *cmd) |
162 | e8f943c3 | Hannes Reinecke | { |
163 | e8f943c3 | Hannes Reinecke | return cmd->flags & MFI_FRAME_SGL64;
|
164 | e8f943c3 | Hannes Reinecke | } |
165 | e8f943c3 | Hannes Reinecke | |
166 | e8f943c3 | Hannes Reinecke | static bool megasas_frame_is_sense64(MegasasCmd *cmd) |
167 | e8f943c3 | Hannes Reinecke | { |
168 | e8f943c3 | Hannes Reinecke | return cmd->flags & MFI_FRAME_SENSE64;
|
169 | e8f943c3 | Hannes Reinecke | } |
170 | e8f943c3 | Hannes Reinecke | |
171 | e8f943c3 | Hannes Reinecke | static uint64_t megasas_sgl_get_addr(MegasasCmd *cmd,
|
172 | e8f943c3 | Hannes Reinecke | union mfi_sgl *sgl)
|
173 | e8f943c3 | Hannes Reinecke | { |
174 | e8f943c3 | Hannes Reinecke | uint64_t addr; |
175 | e8f943c3 | Hannes Reinecke | |
176 | e8f943c3 | Hannes Reinecke | if (megasas_frame_is_ieee_sgl(cmd)) {
|
177 | e8f943c3 | Hannes Reinecke | addr = le64_to_cpu(sgl->sg_skinny->addr); |
178 | e8f943c3 | Hannes Reinecke | } else if (megasas_frame_is_sgl64(cmd)) { |
179 | e8f943c3 | Hannes Reinecke | addr = le64_to_cpu(sgl->sg64->addr); |
180 | e8f943c3 | Hannes Reinecke | } else {
|
181 | e8f943c3 | Hannes Reinecke | addr = le32_to_cpu(sgl->sg32->addr); |
182 | e8f943c3 | Hannes Reinecke | } |
183 | e8f943c3 | Hannes Reinecke | return addr;
|
184 | e8f943c3 | Hannes Reinecke | } |
185 | e8f943c3 | Hannes Reinecke | |
186 | e8f943c3 | Hannes Reinecke | static uint32_t megasas_sgl_get_len(MegasasCmd *cmd,
|
187 | e8f943c3 | Hannes Reinecke | union mfi_sgl *sgl)
|
188 | e8f943c3 | Hannes Reinecke | { |
189 | e8f943c3 | Hannes Reinecke | uint32_t len; |
190 | e8f943c3 | Hannes Reinecke | |
191 | e8f943c3 | Hannes Reinecke | if (megasas_frame_is_ieee_sgl(cmd)) {
|
192 | e8f943c3 | Hannes Reinecke | len = le32_to_cpu(sgl->sg_skinny->len); |
193 | e8f943c3 | Hannes Reinecke | } else if (megasas_frame_is_sgl64(cmd)) { |
194 | e8f943c3 | Hannes Reinecke | len = le32_to_cpu(sgl->sg64->len); |
195 | e8f943c3 | Hannes Reinecke | } else {
|
196 | e8f943c3 | Hannes Reinecke | len = le32_to_cpu(sgl->sg32->len); |
197 | e8f943c3 | Hannes Reinecke | } |
198 | e8f943c3 | Hannes Reinecke | return len;
|
199 | e8f943c3 | Hannes Reinecke | } |
200 | e8f943c3 | Hannes Reinecke | |
201 | e8f943c3 | Hannes Reinecke | static union mfi_sgl *megasas_sgl_next(MegasasCmd *cmd, |
202 | e8f943c3 | Hannes Reinecke | union mfi_sgl *sgl)
|
203 | e8f943c3 | Hannes Reinecke | { |
204 | e8f943c3 | Hannes Reinecke | uint8_t *next = (uint8_t *)sgl; |
205 | e8f943c3 | Hannes Reinecke | |
206 | e8f943c3 | Hannes Reinecke | if (megasas_frame_is_ieee_sgl(cmd)) {
|
207 | e8f943c3 | Hannes Reinecke | next += sizeof(struct mfi_sg_skinny); |
208 | e8f943c3 | Hannes Reinecke | } else if (megasas_frame_is_sgl64(cmd)) { |
209 | e8f943c3 | Hannes Reinecke | next += sizeof(struct mfi_sg64); |
210 | e8f943c3 | Hannes Reinecke | } else {
|
211 | e8f943c3 | Hannes Reinecke | next += sizeof(struct mfi_sg32); |
212 | e8f943c3 | Hannes Reinecke | } |
213 | e8f943c3 | Hannes Reinecke | |
214 | e8f943c3 | Hannes Reinecke | if (next >= (uint8_t *)cmd->frame + cmd->pa_size) {
|
215 | e8f943c3 | Hannes Reinecke | return NULL; |
216 | e8f943c3 | Hannes Reinecke | } |
217 | e8f943c3 | Hannes Reinecke | return (union mfi_sgl *)next; |
218 | e8f943c3 | Hannes Reinecke | } |
219 | e8f943c3 | Hannes Reinecke | |
220 | e8f943c3 | Hannes Reinecke | static void megasas_soft_reset(MegasasState *s); |
221 | e8f943c3 | Hannes Reinecke | |
222 | e8f943c3 | Hannes Reinecke | static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl) |
223 | e8f943c3 | Hannes Reinecke | { |
224 | e8f943c3 | Hannes Reinecke | int i;
|
225 | e8f943c3 | Hannes Reinecke | int iov_count = 0; |
226 | e8f943c3 | Hannes Reinecke | size_t iov_size = 0;
|
227 | e8f943c3 | Hannes Reinecke | |
228 | e8f943c3 | Hannes Reinecke | cmd->flags = le16_to_cpu(cmd->frame->header.flags); |
229 | e8f943c3 | Hannes Reinecke | iov_count = cmd->frame->header.sge_count; |
230 | e8f943c3 | Hannes Reinecke | if (iov_count > MEGASAS_MAX_SGE) {
|
231 | e8f943c3 | Hannes Reinecke | trace_megasas_iovec_sgl_overflow(cmd->index, iov_count, |
232 | e8f943c3 | Hannes Reinecke | MEGASAS_MAX_SGE); |
233 | e8f943c3 | Hannes Reinecke | return iov_count;
|
234 | e8f943c3 | Hannes Reinecke | } |
235 | e8f943c3 | Hannes Reinecke | qemu_sglist_init(&cmd->qsg, iov_count, pci_dma_context(&s->dev)); |
236 | e8f943c3 | Hannes Reinecke | for (i = 0; i < iov_count; i++) { |
237 | e8f943c3 | Hannes Reinecke | dma_addr_t iov_pa, iov_size_p; |
238 | e8f943c3 | Hannes Reinecke | |
239 | e8f943c3 | Hannes Reinecke | if (!sgl) {
|
240 | e8f943c3 | Hannes Reinecke | trace_megasas_iovec_sgl_underflow(cmd->index, i); |
241 | e8f943c3 | Hannes Reinecke | goto unmap;
|
242 | e8f943c3 | Hannes Reinecke | } |
243 | e8f943c3 | Hannes Reinecke | iov_pa = megasas_sgl_get_addr(cmd, sgl); |
244 | e8f943c3 | Hannes Reinecke | iov_size_p = megasas_sgl_get_len(cmd, sgl); |
245 | e8f943c3 | Hannes Reinecke | if (!iov_pa || !iov_size_p) {
|
246 | e8f943c3 | Hannes Reinecke | trace_megasas_iovec_sgl_invalid(cmd->index, i, |
247 | e8f943c3 | Hannes Reinecke | iov_pa, iov_size_p); |
248 | e8f943c3 | Hannes Reinecke | goto unmap;
|
249 | e8f943c3 | Hannes Reinecke | } |
250 | e8f943c3 | Hannes Reinecke | qemu_sglist_add(&cmd->qsg, iov_pa, iov_size_p); |
251 | e8f943c3 | Hannes Reinecke | sgl = megasas_sgl_next(cmd, sgl); |
252 | e8f943c3 | Hannes Reinecke | iov_size += (size_t)iov_size_p; |
253 | e8f943c3 | Hannes Reinecke | } |
254 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size > iov_size) {
|
255 | e8f943c3 | Hannes Reinecke | trace_megasas_iovec_overflow(cmd->index, iov_size, cmd->iov_size); |
256 | e8f943c3 | Hannes Reinecke | } else if (cmd->iov_size < iov_size) { |
257 | e8f943c3 | Hannes Reinecke | trace_megasas_iovec_underflow(cmd->iov_size, iov_size, cmd->iov_size); |
258 | e8f943c3 | Hannes Reinecke | } |
259 | e8f943c3 | Hannes Reinecke | cmd->iov_offset = 0;
|
260 | e8f943c3 | Hannes Reinecke | return 0; |
261 | e8f943c3 | Hannes Reinecke | unmap:
|
262 | e8f943c3 | Hannes Reinecke | qemu_sglist_destroy(&cmd->qsg); |
263 | e8f943c3 | Hannes Reinecke | return iov_count - i;
|
264 | e8f943c3 | Hannes Reinecke | } |
265 | e8f943c3 | Hannes Reinecke | |
266 | e8f943c3 | Hannes Reinecke | static void megasas_unmap_sgl(MegasasCmd *cmd) |
267 | e8f943c3 | Hannes Reinecke | { |
268 | e8f943c3 | Hannes Reinecke | qemu_sglist_destroy(&cmd->qsg); |
269 | e8f943c3 | Hannes Reinecke | cmd->iov_offset = 0;
|
270 | e8f943c3 | Hannes Reinecke | } |
271 | e8f943c3 | Hannes Reinecke | |
272 | e8f943c3 | Hannes Reinecke | /*
|
273 | e8f943c3 | Hannes Reinecke | * passthrough sense and io sense are at the same offset
|
274 | e8f943c3 | Hannes Reinecke | */
|
275 | e8f943c3 | Hannes Reinecke | static int megasas_build_sense(MegasasCmd *cmd, uint8_t *sense_ptr, |
276 | e8f943c3 | Hannes Reinecke | uint8_t sense_len) |
277 | e8f943c3 | Hannes Reinecke | { |
278 | e8f943c3 | Hannes Reinecke | uint32_t pa_hi = 0, pa_lo;
|
279 | a8170e5e | Avi Kivity | hwaddr pa; |
280 | e8f943c3 | Hannes Reinecke | |
281 | e8f943c3 | Hannes Reinecke | if (sense_len > cmd->frame->header.sense_len) {
|
282 | e8f943c3 | Hannes Reinecke | sense_len = cmd->frame->header.sense_len; |
283 | e8f943c3 | Hannes Reinecke | } |
284 | e8f943c3 | Hannes Reinecke | if (sense_len) {
|
285 | e8f943c3 | Hannes Reinecke | pa_lo = le32_to_cpu(cmd->frame->pass.sense_addr_lo); |
286 | e8f943c3 | Hannes Reinecke | if (megasas_frame_is_sense64(cmd)) {
|
287 | e8f943c3 | Hannes Reinecke | pa_hi = le32_to_cpu(cmd->frame->pass.sense_addr_hi); |
288 | e8f943c3 | Hannes Reinecke | } |
289 | e8f943c3 | Hannes Reinecke | pa = ((uint64_t) pa_hi << 32) | pa_lo;
|
290 | e8f943c3 | Hannes Reinecke | cpu_physical_memory_write(pa, sense_ptr, sense_len); |
291 | e8f943c3 | Hannes Reinecke | cmd->frame->header.sense_len = sense_len; |
292 | e8f943c3 | Hannes Reinecke | } |
293 | e8f943c3 | Hannes Reinecke | return sense_len;
|
294 | e8f943c3 | Hannes Reinecke | } |
295 | e8f943c3 | Hannes Reinecke | |
296 | e8f943c3 | Hannes Reinecke | static void megasas_write_sense(MegasasCmd *cmd, SCSISense sense) |
297 | e8f943c3 | Hannes Reinecke | { |
298 | e8f943c3 | Hannes Reinecke | uint8_t sense_buf[SCSI_SENSE_BUF_SIZE]; |
299 | e8f943c3 | Hannes Reinecke | uint8_t sense_len = 18;
|
300 | e8f943c3 | Hannes Reinecke | |
301 | e8f943c3 | Hannes Reinecke | memset(sense_buf, 0, sense_len);
|
302 | e8f943c3 | Hannes Reinecke | sense_buf[0] = 0xf0; |
303 | e8f943c3 | Hannes Reinecke | sense_buf[2] = sense.key;
|
304 | e8f943c3 | Hannes Reinecke | sense_buf[7] = 10; |
305 | e8f943c3 | Hannes Reinecke | sense_buf[12] = sense.asc;
|
306 | e8f943c3 | Hannes Reinecke | sense_buf[13] = sense.ascq;
|
307 | e8f943c3 | Hannes Reinecke | megasas_build_sense(cmd, sense_buf, sense_len); |
308 | e8f943c3 | Hannes Reinecke | } |
309 | e8f943c3 | Hannes Reinecke | |
310 | e8f943c3 | Hannes Reinecke | static void megasas_copy_sense(MegasasCmd *cmd) |
311 | e8f943c3 | Hannes Reinecke | { |
312 | e8f943c3 | Hannes Reinecke | uint8_t sense_buf[SCSI_SENSE_BUF_SIZE]; |
313 | e8f943c3 | Hannes Reinecke | uint8_t sense_len; |
314 | e8f943c3 | Hannes Reinecke | |
315 | e8f943c3 | Hannes Reinecke | sense_len = scsi_req_get_sense(cmd->req, sense_buf, |
316 | e8f943c3 | Hannes Reinecke | SCSI_SENSE_BUF_SIZE); |
317 | e8f943c3 | Hannes Reinecke | megasas_build_sense(cmd, sense_buf, sense_len); |
318 | e8f943c3 | Hannes Reinecke | } |
319 | e8f943c3 | Hannes Reinecke | |
320 | e8f943c3 | Hannes Reinecke | /*
|
321 | e8f943c3 | Hannes Reinecke | * Format an INQUIRY CDB
|
322 | e8f943c3 | Hannes Reinecke | */
|
323 | e8f943c3 | Hannes Reinecke | static int megasas_setup_inquiry(uint8_t *cdb, int pg, int len) |
324 | e8f943c3 | Hannes Reinecke | { |
325 | e8f943c3 | Hannes Reinecke | memset(cdb, 0, 6); |
326 | e8f943c3 | Hannes Reinecke | cdb[0] = INQUIRY;
|
327 | e8f943c3 | Hannes Reinecke | if (pg > 0) { |
328 | e8f943c3 | Hannes Reinecke | cdb[1] = 0x1; |
329 | e8f943c3 | Hannes Reinecke | cdb[2] = pg;
|
330 | e8f943c3 | Hannes Reinecke | } |
331 | e8f943c3 | Hannes Reinecke | cdb[3] = (len >> 8) & 0xff; |
332 | e8f943c3 | Hannes Reinecke | cdb[4] = (len & 0xff); |
333 | e8f943c3 | Hannes Reinecke | return len;
|
334 | e8f943c3 | Hannes Reinecke | } |
335 | e8f943c3 | Hannes Reinecke | |
336 | e8f943c3 | Hannes Reinecke | /*
|
337 | e8f943c3 | Hannes Reinecke | * Encode lba and len into a READ_16/WRITE_16 CDB
|
338 | e8f943c3 | Hannes Reinecke | */
|
339 | e8f943c3 | Hannes Reinecke | static void megasas_encode_lba(uint8_t *cdb, uint64_t lba, |
340 | e8f943c3 | Hannes Reinecke | uint32_t len, bool is_write)
|
341 | e8f943c3 | Hannes Reinecke | { |
342 | e8f943c3 | Hannes Reinecke | memset(cdb, 0x0, 16); |
343 | e8f943c3 | Hannes Reinecke | if (is_write) {
|
344 | e8f943c3 | Hannes Reinecke | cdb[0] = WRITE_16;
|
345 | e8f943c3 | Hannes Reinecke | } else {
|
346 | e8f943c3 | Hannes Reinecke | cdb[0] = READ_16;
|
347 | e8f943c3 | Hannes Reinecke | } |
348 | e8f943c3 | Hannes Reinecke | cdb[2] = (lba >> 56) & 0xff; |
349 | e8f943c3 | Hannes Reinecke | cdb[3] = (lba >> 48) & 0xff; |
350 | e8f943c3 | Hannes Reinecke | cdb[4] = (lba >> 40) & 0xff; |
351 | e8f943c3 | Hannes Reinecke | cdb[5] = (lba >> 32) & 0xff; |
352 | e8f943c3 | Hannes Reinecke | cdb[6] = (lba >> 24) & 0xff; |
353 | e8f943c3 | Hannes Reinecke | cdb[7] = (lba >> 16) & 0xff; |
354 | e8f943c3 | Hannes Reinecke | cdb[8] = (lba >> 8) & 0xff; |
355 | e8f943c3 | Hannes Reinecke | cdb[9] = (lba) & 0xff; |
356 | e8f943c3 | Hannes Reinecke | cdb[10] = (len >> 24) & 0xff; |
357 | e8f943c3 | Hannes Reinecke | cdb[11] = (len >> 16) & 0xff; |
358 | e8f943c3 | Hannes Reinecke | cdb[12] = (len >> 8) & 0xff; |
359 | e8f943c3 | Hannes Reinecke | cdb[13] = (len) & 0xff; |
360 | e8f943c3 | Hannes Reinecke | } |
361 | e8f943c3 | Hannes Reinecke | |
362 | e8f943c3 | Hannes Reinecke | /*
|
363 | e8f943c3 | Hannes Reinecke | * Utility functions
|
364 | e8f943c3 | Hannes Reinecke | */
|
365 | e8f943c3 | Hannes Reinecke | static uint64_t megasas_fw_time(void) |
366 | e8f943c3 | Hannes Reinecke | { |
367 | e8f943c3 | Hannes Reinecke | struct tm curtime;
|
368 | e8f943c3 | Hannes Reinecke | uint64_t bcd_time; |
369 | e8f943c3 | Hannes Reinecke | |
370 | e8f943c3 | Hannes Reinecke | qemu_get_timedate(&curtime, 0);
|
371 | e8f943c3 | Hannes Reinecke | bcd_time = ((uint64_t)curtime.tm_sec & 0xff) << 48 | |
372 | e8f943c3 | Hannes Reinecke | ((uint64_t)curtime.tm_min & 0xff) << 40 | |
373 | e8f943c3 | Hannes Reinecke | ((uint64_t)curtime.tm_hour & 0xff) << 32 | |
374 | e8f943c3 | Hannes Reinecke | ((uint64_t)curtime.tm_mday & 0xff) << 24 | |
375 | e8f943c3 | Hannes Reinecke | ((uint64_t)curtime.tm_mon & 0xff) << 16 | |
376 | e8f943c3 | Hannes Reinecke | ((uint64_t)(curtime.tm_year + 1900) & 0xffff); |
377 | e8f943c3 | Hannes Reinecke | |
378 | e8f943c3 | Hannes Reinecke | return bcd_time;
|
379 | e8f943c3 | Hannes Reinecke | } |
380 | e8f943c3 | Hannes Reinecke | |
381 | 76b523db | Hannes Reinecke | /*
|
382 | 76b523db | Hannes Reinecke | * Default disk sata address
|
383 | 76b523db | Hannes Reinecke | * 0x1221 is the magic number as
|
384 | 76b523db | Hannes Reinecke | * present in real hardware,
|
385 | 76b523db | Hannes Reinecke | * so use it here, too.
|
386 | 76b523db | Hannes Reinecke | */
|
387 | 76b523db | Hannes Reinecke | static uint64_t megasas_get_sata_addr(uint16_t id)
|
388 | e8f943c3 | Hannes Reinecke | { |
389 | 76b523db | Hannes Reinecke | uint64_t addr = (0x1221ULL << 48); |
390 | 76b523db | Hannes Reinecke | return addr & (id << 24); |
391 | e8f943c3 | Hannes Reinecke | } |
392 | e8f943c3 | Hannes Reinecke | |
393 | e8f943c3 | Hannes Reinecke | /*
|
394 | e8f943c3 | Hannes Reinecke | * Frame handling
|
395 | e8f943c3 | Hannes Reinecke | */
|
396 | e8f943c3 | Hannes Reinecke | static int megasas_next_index(MegasasState *s, int index, int limit) |
397 | e8f943c3 | Hannes Reinecke | { |
398 | e8f943c3 | Hannes Reinecke | index++; |
399 | e8f943c3 | Hannes Reinecke | if (index == limit) {
|
400 | e8f943c3 | Hannes Reinecke | index = 0;
|
401 | e8f943c3 | Hannes Reinecke | } |
402 | e8f943c3 | Hannes Reinecke | return index;
|
403 | e8f943c3 | Hannes Reinecke | } |
404 | e8f943c3 | Hannes Reinecke | |
405 | e8f943c3 | Hannes Reinecke | static MegasasCmd *megasas_lookup_frame(MegasasState *s,
|
406 | a8170e5e | Avi Kivity | hwaddr frame) |
407 | e8f943c3 | Hannes Reinecke | { |
408 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd = NULL;
|
409 | e8f943c3 | Hannes Reinecke | int num = 0, index; |
410 | e8f943c3 | Hannes Reinecke | |
411 | e8f943c3 | Hannes Reinecke | index = s->reply_queue_head; |
412 | e8f943c3 | Hannes Reinecke | |
413 | e8f943c3 | Hannes Reinecke | while (num < s->fw_cmds) {
|
414 | e8f943c3 | Hannes Reinecke | if (s->frames[index].pa && s->frames[index].pa == frame) {
|
415 | e8f943c3 | Hannes Reinecke | cmd = &s->frames[index]; |
416 | e8f943c3 | Hannes Reinecke | break;
|
417 | e8f943c3 | Hannes Reinecke | } |
418 | e8f943c3 | Hannes Reinecke | index = megasas_next_index(s, index, s->fw_cmds); |
419 | e8f943c3 | Hannes Reinecke | num++; |
420 | e8f943c3 | Hannes Reinecke | } |
421 | e8f943c3 | Hannes Reinecke | |
422 | e8f943c3 | Hannes Reinecke | return cmd;
|
423 | e8f943c3 | Hannes Reinecke | } |
424 | e8f943c3 | Hannes Reinecke | |
425 | e8f943c3 | Hannes Reinecke | static MegasasCmd *megasas_next_frame(MegasasState *s,
|
426 | a8170e5e | Avi Kivity | hwaddr frame) |
427 | e8f943c3 | Hannes Reinecke | { |
428 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd = NULL;
|
429 | e8f943c3 | Hannes Reinecke | int num = 0, index; |
430 | e8f943c3 | Hannes Reinecke | |
431 | e8f943c3 | Hannes Reinecke | cmd = megasas_lookup_frame(s, frame); |
432 | e8f943c3 | Hannes Reinecke | if (cmd) {
|
433 | e8f943c3 | Hannes Reinecke | trace_megasas_qf_found(cmd->index, cmd->pa); |
434 | e8f943c3 | Hannes Reinecke | return cmd;
|
435 | e8f943c3 | Hannes Reinecke | } |
436 | e8f943c3 | Hannes Reinecke | index = s->reply_queue_head; |
437 | e8f943c3 | Hannes Reinecke | num = 0;
|
438 | e8f943c3 | Hannes Reinecke | while (num < s->fw_cmds) {
|
439 | e8f943c3 | Hannes Reinecke | if (!s->frames[index].pa) {
|
440 | e8f943c3 | Hannes Reinecke | cmd = &s->frames[index]; |
441 | e8f943c3 | Hannes Reinecke | break;
|
442 | e8f943c3 | Hannes Reinecke | } |
443 | e8f943c3 | Hannes Reinecke | index = megasas_next_index(s, index, s->fw_cmds); |
444 | e8f943c3 | Hannes Reinecke | num++; |
445 | e8f943c3 | Hannes Reinecke | } |
446 | e8f943c3 | Hannes Reinecke | if (!cmd) {
|
447 | e8f943c3 | Hannes Reinecke | trace_megasas_qf_failed(frame); |
448 | e8f943c3 | Hannes Reinecke | } |
449 | e8f943c3 | Hannes Reinecke | trace_megasas_qf_new(index, cmd); |
450 | e8f943c3 | Hannes Reinecke | return cmd;
|
451 | e8f943c3 | Hannes Reinecke | } |
452 | e8f943c3 | Hannes Reinecke | |
453 | e8f943c3 | Hannes Reinecke | static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
|
454 | a8170e5e | Avi Kivity | hwaddr frame, uint64_t context, int count)
|
455 | e8f943c3 | Hannes Reinecke | { |
456 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd = NULL;
|
457 | e8f943c3 | Hannes Reinecke | int frame_size = MFI_FRAME_SIZE * 16; |
458 | a8170e5e | Avi Kivity | hwaddr frame_size_p = frame_size; |
459 | e8f943c3 | Hannes Reinecke | |
460 | e8f943c3 | Hannes Reinecke | cmd = megasas_next_frame(s, frame); |
461 | e8f943c3 | Hannes Reinecke | /* All frames busy */
|
462 | e8f943c3 | Hannes Reinecke | if (!cmd) {
|
463 | e8f943c3 | Hannes Reinecke | return NULL; |
464 | e8f943c3 | Hannes Reinecke | } |
465 | e8f943c3 | Hannes Reinecke | if (!cmd->pa) {
|
466 | e8f943c3 | Hannes Reinecke | cmd->pa = frame; |
467 | e8f943c3 | Hannes Reinecke | /* Map all possible frames */
|
468 | e8f943c3 | Hannes Reinecke | cmd->frame = cpu_physical_memory_map(frame, &frame_size_p, 0);
|
469 | e8f943c3 | Hannes Reinecke | if (frame_size_p != frame_size) {
|
470 | e8f943c3 | Hannes Reinecke | trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame); |
471 | e8f943c3 | Hannes Reinecke | if (cmd->frame) {
|
472 | e8f943c3 | Hannes Reinecke | cpu_physical_memory_unmap(cmd->frame, frame_size_p, 0, 0); |
473 | e8f943c3 | Hannes Reinecke | cmd->frame = NULL;
|
474 | e8f943c3 | Hannes Reinecke | cmd->pa = 0;
|
475 | e8f943c3 | Hannes Reinecke | } |
476 | e8f943c3 | Hannes Reinecke | s->event_count++; |
477 | e8f943c3 | Hannes Reinecke | return NULL; |
478 | e8f943c3 | Hannes Reinecke | } |
479 | e8f943c3 | Hannes Reinecke | cmd->pa_size = frame_size_p; |
480 | e8f943c3 | Hannes Reinecke | cmd->context = context; |
481 | e8f943c3 | Hannes Reinecke | if (!megasas_use_queue64(s)) {
|
482 | e8f943c3 | Hannes Reinecke | cmd->context &= (uint64_t)0xFFFFFFFF;
|
483 | e8f943c3 | Hannes Reinecke | } |
484 | e8f943c3 | Hannes Reinecke | } |
485 | e8f943c3 | Hannes Reinecke | cmd->count = count; |
486 | e8f943c3 | Hannes Reinecke | s->busy++; |
487 | e8f943c3 | Hannes Reinecke | |
488 | e8f943c3 | Hannes Reinecke | trace_megasas_qf_enqueue(cmd->index, cmd->count, cmd->context, |
489 | e8f943c3 | Hannes Reinecke | s->reply_queue_head, s->busy); |
490 | e8f943c3 | Hannes Reinecke | |
491 | e8f943c3 | Hannes Reinecke | return cmd;
|
492 | e8f943c3 | Hannes Reinecke | } |
493 | e8f943c3 | Hannes Reinecke | |
494 | e8f943c3 | Hannes Reinecke | static void megasas_complete_frame(MegasasState *s, uint64_t context) |
495 | e8f943c3 | Hannes Reinecke | { |
496 | e8f943c3 | Hannes Reinecke | int tail, queue_offset;
|
497 | e8f943c3 | Hannes Reinecke | |
498 | e8f943c3 | Hannes Reinecke | /* Decrement busy count */
|
499 | e8f943c3 | Hannes Reinecke | s->busy--; |
500 | e8f943c3 | Hannes Reinecke | |
501 | e8f943c3 | Hannes Reinecke | if (s->reply_queue_pa) {
|
502 | e8f943c3 | Hannes Reinecke | /*
|
503 | e8f943c3 | Hannes Reinecke | * Put command on the reply queue.
|
504 | e8f943c3 | Hannes Reinecke | * Context is opaque, but emulation is running in
|
505 | e8f943c3 | Hannes Reinecke | * little endian. So convert it.
|
506 | e8f943c3 | Hannes Reinecke | */
|
507 | e8f943c3 | Hannes Reinecke | tail = s->reply_queue_head; |
508 | e8f943c3 | Hannes Reinecke | if (megasas_use_queue64(s)) {
|
509 | e8f943c3 | Hannes Reinecke | queue_offset = tail * sizeof(uint64_t);
|
510 | e8f943c3 | Hannes Reinecke | stq_le_phys(s->reply_queue_pa + queue_offset, context); |
511 | e8f943c3 | Hannes Reinecke | } else {
|
512 | e8f943c3 | Hannes Reinecke | queue_offset = tail * sizeof(uint32_t);
|
513 | e8f943c3 | Hannes Reinecke | stl_le_phys(s->reply_queue_pa + queue_offset, context); |
514 | e8f943c3 | Hannes Reinecke | } |
515 | e8f943c3 | Hannes Reinecke | s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds); |
516 | e8f943c3 | Hannes Reinecke | trace_megasas_qf_complete(context, tail, queue_offset, |
517 | e8f943c3 | Hannes Reinecke | s->busy, s->doorbell); |
518 | e8f943c3 | Hannes Reinecke | } |
519 | e8f943c3 | Hannes Reinecke | |
520 | e8f943c3 | Hannes Reinecke | if (megasas_intr_enabled(s)) {
|
521 | e8f943c3 | Hannes Reinecke | /* Notify HBA */
|
522 | e8f943c3 | Hannes Reinecke | s->doorbell++; |
523 | e8f943c3 | Hannes Reinecke | if (s->doorbell == 1) { |
524 | e8f943c3 | Hannes Reinecke | if (msix_enabled(&s->dev)) {
|
525 | e8f943c3 | Hannes Reinecke | trace_megasas_msix_raise(0);
|
526 | e8f943c3 | Hannes Reinecke | msix_notify(&s->dev, 0);
|
527 | e8f943c3 | Hannes Reinecke | } else {
|
528 | e8f943c3 | Hannes Reinecke | trace_megasas_irq_raise(); |
529 | e8f943c3 | Hannes Reinecke | qemu_irq_raise(s->dev.irq[0]);
|
530 | e8f943c3 | Hannes Reinecke | } |
531 | e8f943c3 | Hannes Reinecke | } |
532 | e8f943c3 | Hannes Reinecke | } else {
|
533 | e8f943c3 | Hannes Reinecke | trace_megasas_qf_complete_noirq(context); |
534 | e8f943c3 | Hannes Reinecke | } |
535 | e8f943c3 | Hannes Reinecke | } |
536 | e8f943c3 | Hannes Reinecke | |
537 | e8f943c3 | Hannes Reinecke | static void megasas_reset_frames(MegasasState *s) |
538 | e8f943c3 | Hannes Reinecke | { |
539 | e8f943c3 | Hannes Reinecke | int i;
|
540 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd; |
541 | e8f943c3 | Hannes Reinecke | |
542 | e8f943c3 | Hannes Reinecke | for (i = 0; i < s->fw_cmds; i++) { |
543 | e8f943c3 | Hannes Reinecke | cmd = &s->frames[i]; |
544 | e8f943c3 | Hannes Reinecke | if (cmd->pa) {
|
545 | e8f943c3 | Hannes Reinecke | cpu_physical_memory_unmap(cmd->frame, cmd->pa_size, 0, 0); |
546 | e8f943c3 | Hannes Reinecke | cmd->frame = NULL;
|
547 | e8f943c3 | Hannes Reinecke | cmd->pa = 0;
|
548 | e8f943c3 | Hannes Reinecke | } |
549 | e8f943c3 | Hannes Reinecke | } |
550 | e8f943c3 | Hannes Reinecke | } |
551 | e8f943c3 | Hannes Reinecke | |
552 | e8f943c3 | Hannes Reinecke | static void megasas_abort_command(MegasasCmd *cmd) |
553 | e8f943c3 | Hannes Reinecke | { |
554 | e8f943c3 | Hannes Reinecke | if (cmd->req) {
|
555 | e2b06058 | Paolo Bonzini | scsi_req_cancel(cmd->req); |
556 | e8f943c3 | Hannes Reinecke | cmd->req = NULL;
|
557 | e8f943c3 | Hannes Reinecke | } |
558 | e8f943c3 | Hannes Reinecke | } |
559 | e8f943c3 | Hannes Reinecke | |
560 | e8f943c3 | Hannes Reinecke | static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd) |
561 | e8f943c3 | Hannes Reinecke | { |
562 | e8f943c3 | Hannes Reinecke | uint32_t pa_hi, pa_lo; |
563 | a8170e5e | Avi Kivity | hwaddr iq_pa, initq_size; |
564 | e8f943c3 | Hannes Reinecke | struct mfi_init_qinfo *initq;
|
565 | e8f943c3 | Hannes Reinecke | uint32_t flags; |
566 | e8f943c3 | Hannes Reinecke | int ret = MFI_STAT_OK;
|
567 | e8f943c3 | Hannes Reinecke | |
568 | e8f943c3 | Hannes Reinecke | pa_lo = le32_to_cpu(cmd->frame->init.qinfo_new_addr_lo); |
569 | e8f943c3 | Hannes Reinecke | pa_hi = le32_to_cpu(cmd->frame->init.qinfo_new_addr_hi); |
570 | e8f943c3 | Hannes Reinecke | iq_pa = (((uint64_t) pa_hi << 32) | pa_lo);
|
571 | e8f943c3 | Hannes Reinecke | trace_megasas_init_firmware((uint64_t)iq_pa); |
572 | e8f943c3 | Hannes Reinecke | initq_size = sizeof(*initq);
|
573 | e8f943c3 | Hannes Reinecke | initq = cpu_physical_memory_map(iq_pa, &initq_size, 0);
|
574 | e8f943c3 | Hannes Reinecke | if (!initq || initq_size != sizeof(*initq)) { |
575 | e8f943c3 | Hannes Reinecke | trace_megasas_initq_map_failed(cmd->index); |
576 | e8f943c3 | Hannes Reinecke | s->event_count++; |
577 | e8f943c3 | Hannes Reinecke | ret = MFI_STAT_MEMORY_NOT_AVAILABLE; |
578 | e8f943c3 | Hannes Reinecke | goto out;
|
579 | e8f943c3 | Hannes Reinecke | } |
580 | e8f943c3 | Hannes Reinecke | s->reply_queue_len = le32_to_cpu(initq->rq_entries) & 0xFFFF;
|
581 | e8f943c3 | Hannes Reinecke | if (s->reply_queue_len > s->fw_cmds) {
|
582 | e8f943c3 | Hannes Reinecke | trace_megasas_initq_mismatch(s->reply_queue_len, s->fw_cmds); |
583 | e8f943c3 | Hannes Reinecke | s->event_count++; |
584 | e8f943c3 | Hannes Reinecke | ret = MFI_STAT_INVALID_PARAMETER; |
585 | e8f943c3 | Hannes Reinecke | goto out;
|
586 | e8f943c3 | Hannes Reinecke | } |
587 | e8f943c3 | Hannes Reinecke | pa_lo = le32_to_cpu(initq->rq_addr_lo); |
588 | e8f943c3 | Hannes Reinecke | pa_hi = le32_to_cpu(initq->rq_addr_hi); |
589 | e8f943c3 | Hannes Reinecke | s->reply_queue_pa = ((uint64_t) pa_hi << 32) | pa_lo;
|
590 | e8f943c3 | Hannes Reinecke | pa_lo = le32_to_cpu(initq->ci_addr_lo); |
591 | e8f943c3 | Hannes Reinecke | pa_hi = le32_to_cpu(initq->ci_addr_hi); |
592 | e8f943c3 | Hannes Reinecke | s->consumer_pa = ((uint64_t) pa_hi << 32) | pa_lo;
|
593 | e8f943c3 | Hannes Reinecke | pa_lo = le32_to_cpu(initq->pi_addr_lo); |
594 | e8f943c3 | Hannes Reinecke | pa_hi = le32_to_cpu(initq->pi_addr_hi); |
595 | e8f943c3 | Hannes Reinecke | s->producer_pa = ((uint64_t) pa_hi << 32) | pa_lo;
|
596 | e8f943c3 | Hannes Reinecke | s->reply_queue_head = ldl_le_phys(s->producer_pa); |
597 | e8f943c3 | Hannes Reinecke | s->reply_queue_tail = ldl_le_phys(s->consumer_pa); |
598 | e8f943c3 | Hannes Reinecke | flags = le32_to_cpu(initq->flags); |
599 | e8f943c3 | Hannes Reinecke | if (flags & MFI_QUEUE_FLAG_CONTEXT64) {
|
600 | e8f943c3 | Hannes Reinecke | s->flags |= MEGASAS_MASK_USE_QUEUE64; |
601 | e8f943c3 | Hannes Reinecke | } |
602 | e8f943c3 | Hannes Reinecke | trace_megasas_init_queue((unsigned long)s->reply_queue_pa, |
603 | e8f943c3 | Hannes Reinecke | s->reply_queue_len, s->reply_queue_head, |
604 | e8f943c3 | Hannes Reinecke | s->reply_queue_tail, flags); |
605 | e8f943c3 | Hannes Reinecke | megasas_reset_frames(s); |
606 | e8f943c3 | Hannes Reinecke | s->fw_state = MFI_FWSTATE_OPERATIONAL; |
607 | e8f943c3 | Hannes Reinecke | out:
|
608 | e8f943c3 | Hannes Reinecke | if (initq) {
|
609 | e8f943c3 | Hannes Reinecke | cpu_physical_memory_unmap(initq, initq_size, 0, 0); |
610 | e8f943c3 | Hannes Reinecke | } |
611 | e8f943c3 | Hannes Reinecke | return ret;
|
612 | e8f943c3 | Hannes Reinecke | } |
613 | e8f943c3 | Hannes Reinecke | |
614 | e8f943c3 | Hannes Reinecke | static int megasas_map_dcmd(MegasasState *s, MegasasCmd *cmd) |
615 | e8f943c3 | Hannes Reinecke | { |
616 | e8f943c3 | Hannes Reinecke | dma_addr_t iov_pa, iov_size; |
617 | e8f943c3 | Hannes Reinecke | |
618 | e8f943c3 | Hannes Reinecke | cmd->flags = le16_to_cpu(cmd->frame->header.flags); |
619 | e8f943c3 | Hannes Reinecke | if (!cmd->frame->header.sge_count) {
|
620 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_zero_sge(cmd->index); |
621 | e8f943c3 | Hannes Reinecke | cmd->iov_size = 0;
|
622 | e8f943c3 | Hannes Reinecke | return 0; |
623 | e8f943c3 | Hannes Reinecke | } else if (cmd->frame->header.sge_count > 1) { |
624 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_invalid_sge(cmd->index, |
625 | e8f943c3 | Hannes Reinecke | cmd->frame->header.sge_count); |
626 | e8f943c3 | Hannes Reinecke | cmd->iov_size = 0;
|
627 | e8f943c3 | Hannes Reinecke | return -1; |
628 | e8f943c3 | Hannes Reinecke | } |
629 | e8f943c3 | Hannes Reinecke | iov_pa = megasas_sgl_get_addr(cmd, &cmd->frame->dcmd.sgl); |
630 | e8f943c3 | Hannes Reinecke | iov_size = megasas_sgl_get_len(cmd, &cmd->frame->dcmd.sgl); |
631 | e8f943c3 | Hannes Reinecke | qemu_sglist_init(&cmd->qsg, 1, pci_dma_context(&s->dev));
|
632 | e8f943c3 | Hannes Reinecke | qemu_sglist_add(&cmd->qsg, iov_pa, iov_size); |
633 | e8f943c3 | Hannes Reinecke | cmd->iov_size = iov_size; |
634 | e8f943c3 | Hannes Reinecke | return cmd->iov_size;
|
635 | e8f943c3 | Hannes Reinecke | } |
636 | e8f943c3 | Hannes Reinecke | |
637 | e8f943c3 | Hannes Reinecke | static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size) |
638 | e8f943c3 | Hannes Reinecke | { |
639 | e8f943c3 | Hannes Reinecke | trace_megasas_finish_dcmd(cmd->index, iov_size); |
640 | e8f943c3 | Hannes Reinecke | |
641 | e8f943c3 | Hannes Reinecke | if (cmd->frame->header.sge_count) {
|
642 | e8f943c3 | Hannes Reinecke | qemu_sglist_destroy(&cmd->qsg); |
643 | e8f943c3 | Hannes Reinecke | } |
644 | e8f943c3 | Hannes Reinecke | if (iov_size > cmd->iov_size) {
|
645 | e8f943c3 | Hannes Reinecke | if (megasas_frame_is_ieee_sgl(cmd)) {
|
646 | e8f943c3 | Hannes Reinecke | cmd->frame->dcmd.sgl.sg_skinny->len = cpu_to_le32(iov_size); |
647 | e8f943c3 | Hannes Reinecke | } else if (megasas_frame_is_sgl64(cmd)) { |
648 | e8f943c3 | Hannes Reinecke | cmd->frame->dcmd.sgl.sg64->len = cpu_to_le32(iov_size); |
649 | e8f943c3 | Hannes Reinecke | } else {
|
650 | e8f943c3 | Hannes Reinecke | cmd->frame->dcmd.sgl.sg32->len = cpu_to_le32(iov_size); |
651 | e8f943c3 | Hannes Reinecke | } |
652 | e8f943c3 | Hannes Reinecke | } |
653 | e8f943c3 | Hannes Reinecke | cmd->iov_size = 0;
|
654 | e8f943c3 | Hannes Reinecke | } |
655 | e8f943c3 | Hannes Reinecke | |
656 | e8f943c3 | Hannes Reinecke | static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) |
657 | e8f943c3 | Hannes Reinecke | { |
658 | e8f943c3 | Hannes Reinecke | struct mfi_ctrl_info info;
|
659 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(info);
|
660 | e8f943c3 | Hannes Reinecke | BusChild *kid; |
661 | e8f943c3 | Hannes Reinecke | int num_ld_disks = 0; |
662 | 76b523db | Hannes Reinecke | uint16_t sdev_id; |
663 | e8f943c3 | Hannes Reinecke | |
664 | e8f943c3 | Hannes Reinecke | memset(&info, 0x0, cmd->iov_size);
|
665 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size < dcmd_size) {
|
666 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, |
667 | e8f943c3 | Hannes Reinecke | dcmd_size); |
668 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
669 | e8f943c3 | Hannes Reinecke | } |
670 | e8f943c3 | Hannes Reinecke | |
671 | e8f943c3 | Hannes Reinecke | info.pci.vendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC); |
672 | e8f943c3 | Hannes Reinecke | info.pci.device = cpu_to_le16(PCI_DEVICE_ID_LSI_SAS1078); |
673 | e8f943c3 | Hannes Reinecke | info.pci.subvendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC); |
674 | e8f943c3 | Hannes Reinecke | info.pci.subdevice = cpu_to_le16(0x1013);
|
675 | e8f943c3 | Hannes Reinecke | |
676 | 76b523db | Hannes Reinecke | /*
|
677 | 76b523db | Hannes Reinecke | * For some reason the firmware supports
|
678 | 76b523db | Hannes Reinecke | * only up to 8 device ports.
|
679 | 76b523db | Hannes Reinecke | * Despite supporting a far larger number
|
680 | 76b523db | Hannes Reinecke | * of devices for the physical devices.
|
681 | 76b523db | Hannes Reinecke | * So just display the first 8 devices
|
682 | 76b523db | Hannes Reinecke | * in the device port list, independent
|
683 | 76b523db | Hannes Reinecke | * of how many logical devices are actually
|
684 | 76b523db | Hannes Reinecke | * present.
|
685 | 76b523db | Hannes Reinecke | */
|
686 | 76b523db | Hannes Reinecke | info.host.type = MFI_INFO_HOST_PCIE; |
687 | e8f943c3 | Hannes Reinecke | info.device.type = MFI_INFO_DEV_SAS3G; |
688 | 76b523db | Hannes Reinecke | info.device.port_count = 8;
|
689 | 76b523db | Hannes Reinecke | QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { |
690 | 76b523db | Hannes Reinecke | SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); |
691 | 76b523db | Hannes Reinecke | |
692 | 76b523db | Hannes Reinecke | if (num_ld_disks < 8) { |
693 | 76b523db | Hannes Reinecke | sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF); |
694 | 76b523db | Hannes Reinecke | info.device.port_addr[num_ld_disks] = |
695 | 76b523db | Hannes Reinecke | cpu_to_le64(megasas_get_sata_addr(sdev_id)); |
696 | 76b523db | Hannes Reinecke | } |
697 | 76b523db | Hannes Reinecke | num_ld_disks++; |
698 | 76b523db | Hannes Reinecke | } |
699 | e8f943c3 | Hannes Reinecke | |
700 | e8f943c3 | Hannes Reinecke | memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20); |
701 | fb654157 | Hannes Reinecke | snprintf(info.serial_number, 32, "%s", s->hba_serial); |
702 | e8f943c3 | Hannes Reinecke | snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION); |
703 | e8f943c3 | Hannes Reinecke | memcpy(info.image_component[0].name, "APP", 3); |
704 | e8f943c3 | Hannes Reinecke | memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9); |
705 | e8f943c3 | Hannes Reinecke | memcpy(info.image_component[0].build_date, __DATE__, 11); |
706 | e8f943c3 | Hannes Reinecke | memcpy(info.image_component[0].build_time, __TIME__, 8); |
707 | e8f943c3 | Hannes Reinecke | info.image_component_count = 1;
|
708 | e8f943c3 | Hannes Reinecke | if (s->dev.has_rom) {
|
709 | e8f943c3 | Hannes Reinecke | uint8_t biosver[32];
|
710 | e8f943c3 | Hannes Reinecke | uint8_t *ptr; |
711 | e8f943c3 | Hannes Reinecke | |
712 | e8f943c3 | Hannes Reinecke | ptr = memory_region_get_ram_ptr(&s->dev.rom); |
713 | e8f943c3 | Hannes Reinecke | memcpy(biosver, ptr + 0x41, 31); |
714 | e8f943c3 | Hannes Reinecke | qemu_put_ram_ptr(ptr); |
715 | e8f943c3 | Hannes Reinecke | memcpy(info.image_component[1].name, "BIOS", 4); |
716 | e8f943c3 | Hannes Reinecke | memcpy(info.image_component[1].version, biosver,
|
717 | e8f943c3 | Hannes Reinecke | strlen((const char *)biosver)); |
718 | e8f943c3 | Hannes Reinecke | info.image_component_count++; |
719 | e8f943c3 | Hannes Reinecke | } |
720 | e8f943c3 | Hannes Reinecke | info.current_fw_time = cpu_to_le32(megasas_fw_time()); |
721 | e8f943c3 | Hannes Reinecke | info.max_arms = 32;
|
722 | e8f943c3 | Hannes Reinecke | info.max_spans = 8;
|
723 | e8f943c3 | Hannes Reinecke | info.max_arrays = MEGASAS_MAX_ARRAYS; |
724 | e8f943c3 | Hannes Reinecke | info.max_lds = s->fw_luns; |
725 | e8f943c3 | Hannes Reinecke | info.max_cmds = cpu_to_le16(s->fw_cmds); |
726 | e8f943c3 | Hannes Reinecke | info.max_sg_elements = cpu_to_le16(s->fw_sge); |
727 | e8f943c3 | Hannes Reinecke | info.max_request_size = cpu_to_le32(MEGASAS_MAX_SECTORS); |
728 | e8f943c3 | Hannes Reinecke | info.lds_present = cpu_to_le16(num_ld_disks); |
729 | e8f943c3 | Hannes Reinecke | info.pd_present = cpu_to_le16(num_ld_disks); |
730 | e8f943c3 | Hannes Reinecke | info.pd_disks_present = cpu_to_le16(num_ld_disks); |
731 | e8f943c3 | Hannes Reinecke | info.hw_present = cpu_to_le32(MFI_INFO_HW_NVRAM | |
732 | e8f943c3 | Hannes Reinecke | MFI_INFO_HW_MEM | |
733 | e8f943c3 | Hannes Reinecke | MFI_INFO_HW_FLASH); |
734 | e8f943c3 | Hannes Reinecke | info.memory_size = cpu_to_le16(512);
|
735 | e8f943c3 | Hannes Reinecke | info.nvram_size = cpu_to_le16(32);
|
736 | e8f943c3 | Hannes Reinecke | info.flash_size = cpu_to_le16(16);
|
737 | e8f943c3 | Hannes Reinecke | info.raid_levels = cpu_to_le32(MFI_INFO_RAID_0); |
738 | e8f943c3 | Hannes Reinecke | info.adapter_ops = cpu_to_le32(MFI_INFO_AOPS_RBLD_RATE | |
739 | e8f943c3 | Hannes Reinecke | MFI_INFO_AOPS_SELF_DIAGNOSTIC | |
740 | e8f943c3 | Hannes Reinecke | MFI_INFO_AOPS_MIXED_ARRAY); |
741 | e8f943c3 | Hannes Reinecke | info.ld_ops = cpu_to_le32(MFI_INFO_LDOPS_DISK_CACHE_POLICY | |
742 | e8f943c3 | Hannes Reinecke | MFI_INFO_LDOPS_ACCESS_POLICY | |
743 | e8f943c3 | Hannes Reinecke | MFI_INFO_LDOPS_IO_POLICY | |
744 | e8f943c3 | Hannes Reinecke | MFI_INFO_LDOPS_WRITE_POLICY | |
745 | e8f943c3 | Hannes Reinecke | MFI_INFO_LDOPS_READ_POLICY); |
746 | e8f943c3 | Hannes Reinecke | info.max_strips_per_io = cpu_to_le16(s->fw_sge); |
747 | e8f943c3 | Hannes Reinecke | info.stripe_sz_ops.min = 3;
|
748 | e8f943c3 | Hannes Reinecke | info.stripe_sz_ops.max = ffs(MEGASAS_MAX_SECTORS + 1) - 1; |
749 | e8f943c3 | Hannes Reinecke | info.properties.pred_fail_poll_interval = cpu_to_le16(300);
|
750 | e8f943c3 | Hannes Reinecke | info.properties.intr_throttle_cnt = cpu_to_le16(16);
|
751 | e8f943c3 | Hannes Reinecke | info.properties.intr_throttle_timeout = cpu_to_le16(50);
|
752 | e8f943c3 | Hannes Reinecke | info.properties.rebuild_rate = 30;
|
753 | e8f943c3 | Hannes Reinecke | info.properties.patrol_read_rate = 30;
|
754 | e8f943c3 | Hannes Reinecke | info.properties.bgi_rate = 30;
|
755 | e8f943c3 | Hannes Reinecke | info.properties.cc_rate = 30;
|
756 | e8f943c3 | Hannes Reinecke | info.properties.recon_rate = 30;
|
757 | e8f943c3 | Hannes Reinecke | info.properties.cache_flush_interval = 4;
|
758 | e8f943c3 | Hannes Reinecke | info.properties.spinup_drv_cnt = 2;
|
759 | e8f943c3 | Hannes Reinecke | info.properties.spinup_delay = 6;
|
760 | e8f943c3 | Hannes Reinecke | info.properties.ecc_bucket_size = 15;
|
761 | e8f943c3 | Hannes Reinecke | info.properties.ecc_bucket_leak_rate = cpu_to_le16(1440);
|
762 | e8f943c3 | Hannes Reinecke | info.properties.expose_encl_devices = 1;
|
763 | e8f943c3 | Hannes Reinecke | info.properties.OnOffProperties = cpu_to_le32(MFI_CTRL_PROP_EnableJBOD); |
764 | e8f943c3 | Hannes Reinecke | info.pd_ops = cpu_to_le32(MFI_INFO_PDOPS_FORCE_ONLINE | |
765 | e8f943c3 | Hannes Reinecke | MFI_INFO_PDOPS_FORCE_OFFLINE); |
766 | e8f943c3 | Hannes Reinecke | info.pd_mix_support = cpu_to_le32(MFI_INFO_PDMIX_SAS | |
767 | e8f943c3 | Hannes Reinecke | MFI_INFO_PDMIX_SATA | |
768 | e8f943c3 | Hannes Reinecke | MFI_INFO_PDMIX_LD); |
769 | e8f943c3 | Hannes Reinecke | |
770 | e8f943c3 | Hannes Reinecke | cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); |
771 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
772 | e8f943c3 | Hannes Reinecke | } |
773 | e8f943c3 | Hannes Reinecke | |
774 | e8f943c3 | Hannes Reinecke | static int megasas_mfc_get_defaults(MegasasState *s, MegasasCmd *cmd) |
775 | e8f943c3 | Hannes Reinecke | { |
776 | e8f943c3 | Hannes Reinecke | struct mfi_defaults info;
|
777 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(struct mfi_defaults); |
778 | e8f943c3 | Hannes Reinecke | |
779 | e8f943c3 | Hannes Reinecke | memset(&info, 0x0, dcmd_size);
|
780 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size < dcmd_size) {
|
781 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, |
782 | e8f943c3 | Hannes Reinecke | dcmd_size); |
783 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
784 | e8f943c3 | Hannes Reinecke | } |
785 | e8f943c3 | Hannes Reinecke | |
786 | 76b523db | Hannes Reinecke | info.sas_addr = cpu_to_le64(s->sas_addr); |
787 | e8f943c3 | Hannes Reinecke | info.stripe_size = 3;
|
788 | e8f943c3 | Hannes Reinecke | info.flush_time = 4;
|
789 | e8f943c3 | Hannes Reinecke | info.background_rate = 30;
|
790 | e8f943c3 | Hannes Reinecke | info.allow_mix_in_enclosure = 1;
|
791 | e8f943c3 | Hannes Reinecke | info.allow_mix_in_ld = 1;
|
792 | e8f943c3 | Hannes Reinecke | info.direct_pd_mapping = 1;
|
793 | e8f943c3 | Hannes Reinecke | /* Enable for BIOS support */
|
794 | e8f943c3 | Hannes Reinecke | info.bios_enumerate_lds = 1;
|
795 | e8f943c3 | Hannes Reinecke | info.disable_ctrl_r = 1;
|
796 | e8f943c3 | Hannes Reinecke | info.expose_enclosure_devices = 1;
|
797 | e8f943c3 | Hannes Reinecke | info.disable_preboot_cli = 1;
|
798 | e8f943c3 | Hannes Reinecke | info.cluster_disable = 1;
|
799 | e8f943c3 | Hannes Reinecke | |
800 | e8f943c3 | Hannes Reinecke | cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); |
801 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
802 | e8f943c3 | Hannes Reinecke | } |
803 | e8f943c3 | Hannes Reinecke | |
804 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_get_bios_info(MegasasState *s, MegasasCmd *cmd) |
805 | e8f943c3 | Hannes Reinecke | { |
806 | e8f943c3 | Hannes Reinecke | struct mfi_bios_data info;
|
807 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(info);
|
808 | e8f943c3 | Hannes Reinecke | |
809 | e8f943c3 | Hannes Reinecke | memset(&info, 0x0, dcmd_size);
|
810 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size < dcmd_size) {
|
811 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, |
812 | e8f943c3 | Hannes Reinecke | dcmd_size); |
813 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
814 | e8f943c3 | Hannes Reinecke | } |
815 | e8f943c3 | Hannes Reinecke | info.continue_on_error = 1;
|
816 | e8f943c3 | Hannes Reinecke | info.verbose = 1;
|
817 | e8f943c3 | Hannes Reinecke | if (megasas_is_jbod(s)) {
|
818 | e8f943c3 | Hannes Reinecke | info.expose_all_drives = 1;
|
819 | e8f943c3 | Hannes Reinecke | } |
820 | e8f943c3 | Hannes Reinecke | |
821 | e8f943c3 | Hannes Reinecke | cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); |
822 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
823 | e8f943c3 | Hannes Reinecke | } |
824 | e8f943c3 | Hannes Reinecke | |
825 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_get_fw_time(MegasasState *s, MegasasCmd *cmd) |
826 | e8f943c3 | Hannes Reinecke | { |
827 | e8f943c3 | Hannes Reinecke | uint64_t fw_time; |
828 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(fw_time);
|
829 | e8f943c3 | Hannes Reinecke | |
830 | e8f943c3 | Hannes Reinecke | fw_time = cpu_to_le64(megasas_fw_time()); |
831 | e8f943c3 | Hannes Reinecke | |
832 | e8f943c3 | Hannes Reinecke | cmd->iov_size -= dma_buf_read((uint8_t *)&fw_time, dcmd_size, &cmd->qsg); |
833 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
834 | e8f943c3 | Hannes Reinecke | } |
835 | e8f943c3 | Hannes Reinecke | |
836 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_set_fw_time(MegasasState *s, MegasasCmd *cmd) |
837 | e8f943c3 | Hannes Reinecke | { |
838 | e8f943c3 | Hannes Reinecke | uint64_t fw_time; |
839 | e8f943c3 | Hannes Reinecke | |
840 | e8f943c3 | Hannes Reinecke | /* This is a dummy; setting of firmware time is not allowed */
|
841 | e8f943c3 | Hannes Reinecke | memcpy(&fw_time, cmd->frame->dcmd.mbox, sizeof(fw_time));
|
842 | e8f943c3 | Hannes Reinecke | |
843 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_set_fw_time(cmd->index, fw_time); |
844 | e8f943c3 | Hannes Reinecke | fw_time = cpu_to_le64(megasas_fw_time()); |
845 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
846 | e8f943c3 | Hannes Reinecke | } |
847 | e8f943c3 | Hannes Reinecke | |
848 | e8f943c3 | Hannes Reinecke | static int megasas_event_info(MegasasState *s, MegasasCmd *cmd) |
849 | e8f943c3 | Hannes Reinecke | { |
850 | e8f943c3 | Hannes Reinecke | struct mfi_evt_log_state info;
|
851 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(info);
|
852 | e8f943c3 | Hannes Reinecke | |
853 | e8f943c3 | Hannes Reinecke | memset(&info, 0, dcmd_size);
|
854 | e8f943c3 | Hannes Reinecke | |
855 | e8f943c3 | Hannes Reinecke | info.newest_seq_num = cpu_to_le32(s->event_count); |
856 | e8f943c3 | Hannes Reinecke | info.shutdown_seq_num = cpu_to_le32(s->shutdown_event); |
857 | e8f943c3 | Hannes Reinecke | info.boot_seq_num = cpu_to_le32(s->boot_event); |
858 | e8f943c3 | Hannes Reinecke | |
859 | e8f943c3 | Hannes Reinecke | cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); |
860 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
861 | e8f943c3 | Hannes Reinecke | } |
862 | e8f943c3 | Hannes Reinecke | |
863 | e8f943c3 | Hannes Reinecke | static int megasas_event_wait(MegasasState *s, MegasasCmd *cmd) |
864 | e8f943c3 | Hannes Reinecke | { |
865 | e8f943c3 | Hannes Reinecke | union mfi_evt event;
|
866 | e8f943c3 | Hannes Reinecke | |
867 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size < sizeof(struct mfi_evt_detail)) { |
868 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, |
869 | e8f943c3 | Hannes Reinecke | sizeof(struct mfi_evt_detail)); |
870 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
871 | e8f943c3 | Hannes Reinecke | } |
872 | e8f943c3 | Hannes Reinecke | s->event_count = cpu_to_le32(cmd->frame->dcmd.mbox[0]);
|
873 | e8f943c3 | Hannes Reinecke | event.word = cpu_to_le32(cmd->frame->dcmd.mbox[4]);
|
874 | e8f943c3 | Hannes Reinecke | s->event_locale = event.members.locale; |
875 | e8f943c3 | Hannes Reinecke | s->event_class = event.members.class; |
876 | e8f943c3 | Hannes Reinecke | s->event_cmd = cmd; |
877 | e8f943c3 | Hannes Reinecke | /* Decrease busy count; event frame doesn't count here */
|
878 | e8f943c3 | Hannes Reinecke | s->busy--; |
879 | e8f943c3 | Hannes Reinecke | cmd->iov_size = sizeof(struct mfi_evt_detail); |
880 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_STATUS;
|
881 | e8f943c3 | Hannes Reinecke | } |
882 | e8f943c3 | Hannes Reinecke | |
883 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd) |
884 | e8f943c3 | Hannes Reinecke | { |
885 | e8f943c3 | Hannes Reinecke | struct mfi_pd_list info;
|
886 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(info);
|
887 | e8f943c3 | Hannes Reinecke | BusChild *kid; |
888 | e8f943c3 | Hannes Reinecke | uint32_t offset, dcmd_limit, num_pd_disks = 0, max_pd_disks;
|
889 | e8f943c3 | Hannes Reinecke | uint16_t sdev_id; |
890 | e8f943c3 | Hannes Reinecke | |
891 | e8f943c3 | Hannes Reinecke | memset(&info, 0, dcmd_size);
|
892 | e8f943c3 | Hannes Reinecke | offset = 8;
|
893 | e8f943c3 | Hannes Reinecke | dcmd_limit = offset + sizeof(struct mfi_pd_address); |
894 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size < dcmd_limit) {
|
895 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, |
896 | e8f943c3 | Hannes Reinecke | dcmd_limit); |
897 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
898 | e8f943c3 | Hannes Reinecke | } |
899 | e8f943c3 | Hannes Reinecke | |
900 | e8f943c3 | Hannes Reinecke | max_pd_disks = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address); |
901 | e8f943c3 | Hannes Reinecke | if (max_pd_disks > s->fw_luns) {
|
902 | e8f943c3 | Hannes Reinecke | max_pd_disks = s->fw_luns; |
903 | e8f943c3 | Hannes Reinecke | } |
904 | e8f943c3 | Hannes Reinecke | |
905 | e8f943c3 | Hannes Reinecke | QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { |
906 | e8f943c3 | Hannes Reinecke | SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); |
907 | e8f943c3 | Hannes Reinecke | |
908 | e8f943c3 | Hannes Reinecke | sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF); |
909 | e8f943c3 | Hannes Reinecke | info.addr[num_pd_disks].device_id = cpu_to_le16(sdev_id); |
910 | e8f943c3 | Hannes Reinecke | info.addr[num_pd_disks].encl_device_id = 0xFFFF;
|
911 | e8f943c3 | Hannes Reinecke | info.addr[num_pd_disks].encl_index = 0;
|
912 | e8f943c3 | Hannes Reinecke | info.addr[num_pd_disks].slot_number = (sdev->id & 0xFF);
|
913 | e8f943c3 | Hannes Reinecke | info.addr[num_pd_disks].scsi_dev_type = sdev->type; |
914 | e8f943c3 | Hannes Reinecke | info.addr[num_pd_disks].connect_port_bitmap = 0x1;
|
915 | e8f943c3 | Hannes Reinecke | info.addr[num_pd_disks].sas_addr[0] =
|
916 | 76b523db | Hannes Reinecke | cpu_to_le64(megasas_get_sata_addr(sdev_id)); |
917 | e8f943c3 | Hannes Reinecke | num_pd_disks++; |
918 | e8f943c3 | Hannes Reinecke | offset += sizeof(struct mfi_pd_address); |
919 | e8f943c3 | Hannes Reinecke | } |
920 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_pd_get_list(cmd->index, num_pd_disks, |
921 | e8f943c3 | Hannes Reinecke | max_pd_disks, offset); |
922 | e8f943c3 | Hannes Reinecke | |
923 | e8f943c3 | Hannes Reinecke | info.size = cpu_to_le32(offset); |
924 | e8f943c3 | Hannes Reinecke | info.count = cpu_to_le32(num_pd_disks); |
925 | e8f943c3 | Hannes Reinecke | |
926 | e8f943c3 | Hannes Reinecke | cmd->iov_size -= dma_buf_read((uint8_t *)&info, offset, &cmd->qsg); |
927 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
928 | e8f943c3 | Hannes Reinecke | } |
929 | e8f943c3 | Hannes Reinecke | |
930 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_pd_list_query(MegasasState *s, MegasasCmd *cmd) |
931 | e8f943c3 | Hannes Reinecke | { |
932 | e8f943c3 | Hannes Reinecke | uint16_t flags; |
933 | e8f943c3 | Hannes Reinecke | |
934 | e8f943c3 | Hannes Reinecke | /* mbox0 contains flags */
|
935 | e8f943c3 | Hannes Reinecke | flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
|
936 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_pd_list_query(cmd->index, flags); |
937 | e8f943c3 | Hannes Reinecke | if (flags == MR_PD_QUERY_TYPE_ALL ||
|
938 | e8f943c3 | Hannes Reinecke | megasas_is_jbod(s)) { |
939 | e8f943c3 | Hannes Reinecke | return megasas_dcmd_pd_get_list(s, cmd);
|
940 | e8f943c3 | Hannes Reinecke | } |
941 | e8f943c3 | Hannes Reinecke | |
942 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
943 | e8f943c3 | Hannes Reinecke | } |
944 | e8f943c3 | Hannes Reinecke | |
945 | e8f943c3 | Hannes Reinecke | static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun, |
946 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd) |
947 | e8f943c3 | Hannes Reinecke | { |
948 | e8f943c3 | Hannes Reinecke | struct mfi_pd_info *info = cmd->iov_buf;
|
949 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(struct mfi_pd_info); |
950 | e8f943c3 | Hannes Reinecke | BlockConf *conf = &sdev->conf; |
951 | e8f943c3 | Hannes Reinecke | uint64_t pd_size; |
952 | e8f943c3 | Hannes Reinecke | uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF); |
953 | e8f943c3 | Hannes Reinecke | uint8_t cmdbuf[6];
|
954 | e8f943c3 | Hannes Reinecke | SCSIRequest *req; |
955 | e8f943c3 | Hannes Reinecke | size_t len, resid; |
956 | e8f943c3 | Hannes Reinecke | |
957 | e8f943c3 | Hannes Reinecke | if (!cmd->iov_buf) {
|
958 | e8f943c3 | Hannes Reinecke | cmd->iov_buf = g_malloc(dcmd_size); |
959 | e8f943c3 | Hannes Reinecke | memset(cmd->iov_buf, 0, dcmd_size);
|
960 | e8f943c3 | Hannes Reinecke | info = cmd->iov_buf; |
961 | e8f943c3 | Hannes Reinecke | info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */ |
962 | e8f943c3 | Hannes Reinecke | info->vpd_page83[0] = 0x7f; |
963 | e8f943c3 | Hannes Reinecke | megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data)); |
964 | e8f943c3 | Hannes Reinecke | req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd); |
965 | e8f943c3 | Hannes Reinecke | if (!req) {
|
966 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_req_alloc_failed(cmd->index, |
967 | e8f943c3 | Hannes Reinecke | "PD get info std inquiry");
|
968 | e8f943c3 | Hannes Reinecke | g_free(cmd->iov_buf); |
969 | e8f943c3 | Hannes Reinecke | cmd->iov_buf = NULL;
|
970 | e8f943c3 | Hannes Reinecke | return MFI_STAT_FLASH_ALLOC_FAIL;
|
971 | e8f943c3 | Hannes Reinecke | } |
972 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_internal_submit(cmd->index, |
973 | e8f943c3 | Hannes Reinecke | "PD get info std inquiry", lun);
|
974 | e8f943c3 | Hannes Reinecke | len = scsi_req_enqueue(req); |
975 | e8f943c3 | Hannes Reinecke | if (len > 0) { |
976 | e8f943c3 | Hannes Reinecke | cmd->iov_size = len; |
977 | e8f943c3 | Hannes Reinecke | scsi_req_continue(req); |
978 | e8f943c3 | Hannes Reinecke | } |
979 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_STATUS;
|
980 | e8f943c3 | Hannes Reinecke | } else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) { |
981 | e8f943c3 | Hannes Reinecke | megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83)); |
982 | e8f943c3 | Hannes Reinecke | req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd); |
983 | e8f943c3 | Hannes Reinecke | if (!req) {
|
984 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_req_alloc_failed(cmd->index, |
985 | e8f943c3 | Hannes Reinecke | "PD get info vpd inquiry");
|
986 | e8f943c3 | Hannes Reinecke | return MFI_STAT_FLASH_ALLOC_FAIL;
|
987 | e8f943c3 | Hannes Reinecke | } |
988 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_internal_submit(cmd->index, |
989 | e8f943c3 | Hannes Reinecke | "PD get info vpd inquiry", lun);
|
990 | e8f943c3 | Hannes Reinecke | len = scsi_req_enqueue(req); |
991 | e8f943c3 | Hannes Reinecke | if (len > 0) { |
992 | e8f943c3 | Hannes Reinecke | cmd->iov_size = len; |
993 | e8f943c3 | Hannes Reinecke | scsi_req_continue(req); |
994 | e8f943c3 | Hannes Reinecke | } |
995 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_STATUS;
|
996 | e8f943c3 | Hannes Reinecke | } |
997 | e8f943c3 | Hannes Reinecke | /* Finished, set FW state */
|
998 | e8f943c3 | Hannes Reinecke | if ((info->inquiry_data[0] >> 5) == 0) { |
999 | e8f943c3 | Hannes Reinecke | if (megasas_is_jbod(cmd->state)) {
|
1000 | e8f943c3 | Hannes Reinecke | info->fw_state = cpu_to_le16(MFI_PD_STATE_SYSTEM); |
1001 | e8f943c3 | Hannes Reinecke | } else {
|
1002 | e8f943c3 | Hannes Reinecke | info->fw_state = cpu_to_le16(MFI_PD_STATE_ONLINE); |
1003 | e8f943c3 | Hannes Reinecke | } |
1004 | e8f943c3 | Hannes Reinecke | } else {
|
1005 | e8f943c3 | Hannes Reinecke | info->fw_state = cpu_to_le16(MFI_PD_STATE_OFFLINE); |
1006 | e8f943c3 | Hannes Reinecke | } |
1007 | e8f943c3 | Hannes Reinecke | |
1008 | e8f943c3 | Hannes Reinecke | info->ref.v.device_id = cpu_to_le16(sdev_id); |
1009 | e8f943c3 | Hannes Reinecke | info->state.ddf.pd_type = cpu_to_le16(MFI_PD_DDF_TYPE_IN_VD| |
1010 | e8f943c3 | Hannes Reinecke | MFI_PD_DDF_TYPE_INTF_SAS); |
1011 | e8f943c3 | Hannes Reinecke | bdrv_get_geometry(conf->bs, &pd_size); |
1012 | e8f943c3 | Hannes Reinecke | info->raw_size = cpu_to_le64(pd_size); |
1013 | e8f943c3 | Hannes Reinecke | info->non_coerced_size = cpu_to_le64(pd_size); |
1014 | e8f943c3 | Hannes Reinecke | info->coerced_size = cpu_to_le64(pd_size); |
1015 | e8f943c3 | Hannes Reinecke | info->encl_device_id = 0xFFFF;
|
1016 | e8f943c3 | Hannes Reinecke | info->slot_number = (sdev->id & 0xFF);
|
1017 | e8f943c3 | Hannes Reinecke | info->path_info.count = 1;
|
1018 | e8f943c3 | Hannes Reinecke | info->path_info.sas_addr[0] =
|
1019 | 76b523db | Hannes Reinecke | cpu_to_le64(megasas_get_sata_addr(sdev_id)); |
1020 | e8f943c3 | Hannes Reinecke | info->connected_port_bitmap = 0x1;
|
1021 | e8f943c3 | Hannes Reinecke | info->device_speed = 1;
|
1022 | e8f943c3 | Hannes Reinecke | info->link_speed = 1;
|
1023 | e8f943c3 | Hannes Reinecke | resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg); |
1024 | e8f943c3 | Hannes Reinecke | g_free(cmd->iov_buf); |
1025 | e8f943c3 | Hannes Reinecke | cmd->iov_size = dcmd_size - resid; |
1026 | e8f943c3 | Hannes Reinecke | cmd->iov_buf = NULL;
|
1027 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1028 | e8f943c3 | Hannes Reinecke | } |
1029 | e8f943c3 | Hannes Reinecke | |
1030 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd) |
1031 | e8f943c3 | Hannes Reinecke | { |
1032 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(struct mfi_pd_info); |
1033 | e8f943c3 | Hannes Reinecke | uint16_t pd_id; |
1034 | e8f943c3 | Hannes Reinecke | SCSIDevice *sdev = NULL;
|
1035 | e8f943c3 | Hannes Reinecke | int retval = MFI_STAT_DEVICE_NOT_FOUND;
|
1036 | e8f943c3 | Hannes Reinecke | |
1037 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size < dcmd_size) {
|
1038 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
1039 | e8f943c3 | Hannes Reinecke | } |
1040 | e8f943c3 | Hannes Reinecke | |
1041 | e8f943c3 | Hannes Reinecke | /* mbox0 has the ID */
|
1042 | e8f943c3 | Hannes Reinecke | pd_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
|
1043 | e8f943c3 | Hannes Reinecke | sdev = scsi_device_find(&s->bus, 0, pd_id, 0); |
1044 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_pd_get_info(cmd->index, pd_id); |
1045 | e8f943c3 | Hannes Reinecke | |
1046 | e8f943c3 | Hannes Reinecke | if (sdev) {
|
1047 | e8f943c3 | Hannes Reinecke | /* Submit inquiry */
|
1048 | e8f943c3 | Hannes Reinecke | retval = megasas_pd_get_info_submit(sdev, pd_id, cmd); |
1049 | e8f943c3 | Hannes Reinecke | } |
1050 | e8f943c3 | Hannes Reinecke | |
1051 | e8f943c3 | Hannes Reinecke | return retval;
|
1052 | e8f943c3 | Hannes Reinecke | } |
1053 | e8f943c3 | Hannes Reinecke | |
1054 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) |
1055 | e8f943c3 | Hannes Reinecke | { |
1056 | e8f943c3 | Hannes Reinecke | struct mfi_ld_list info;
|
1057 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(info), resid;
|
1058 | e8f943c3 | Hannes Reinecke | uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns;
|
1059 | e8f943c3 | Hannes Reinecke | uint64_t ld_size; |
1060 | e8f943c3 | Hannes Reinecke | BusChild *kid; |
1061 | e8f943c3 | Hannes Reinecke | |
1062 | e8f943c3 | Hannes Reinecke | memset(&info, 0, dcmd_size);
|
1063 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size < dcmd_size) {
|
1064 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, |
1065 | e8f943c3 | Hannes Reinecke | dcmd_size); |
1066 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
1067 | e8f943c3 | Hannes Reinecke | } |
1068 | e8f943c3 | Hannes Reinecke | |
1069 | e8f943c3 | Hannes Reinecke | if (megasas_is_jbod(s)) {
|
1070 | e8f943c3 | Hannes Reinecke | max_ld_disks = 0;
|
1071 | e8f943c3 | Hannes Reinecke | } |
1072 | e8f943c3 | Hannes Reinecke | QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { |
1073 | e8f943c3 | Hannes Reinecke | SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); |
1074 | e8f943c3 | Hannes Reinecke | BlockConf *conf = &sdev->conf; |
1075 | e8f943c3 | Hannes Reinecke | |
1076 | e8f943c3 | Hannes Reinecke | if (num_ld_disks >= max_ld_disks) {
|
1077 | e8f943c3 | Hannes Reinecke | break;
|
1078 | e8f943c3 | Hannes Reinecke | } |
1079 | e8f943c3 | Hannes Reinecke | /* Logical device size is in blocks */
|
1080 | e8f943c3 | Hannes Reinecke | bdrv_get_geometry(conf->bs, &ld_size); |
1081 | e8f943c3 | Hannes Reinecke | info.ld_list[num_ld_disks].ld.v.target_id = sdev->id; |
1082 | 4003e24f | Hannes Reinecke | info.ld_list[num_ld_disks].ld.v.lun_id = sdev->lun; |
1083 | e8f943c3 | Hannes Reinecke | info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL; |
1084 | e8f943c3 | Hannes Reinecke | info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size); |
1085 | e8f943c3 | Hannes Reinecke | num_ld_disks++; |
1086 | e8f943c3 | Hannes Reinecke | } |
1087 | e8f943c3 | Hannes Reinecke | info.ld_count = cpu_to_le32(num_ld_disks); |
1088 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks); |
1089 | e8f943c3 | Hannes Reinecke | |
1090 | e8f943c3 | Hannes Reinecke | resid = dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); |
1091 | e8f943c3 | Hannes Reinecke | cmd->iov_size = dcmd_size - resid; |
1092 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1093 | e8f943c3 | Hannes Reinecke | } |
1094 | e8f943c3 | Hannes Reinecke | |
1095 | e8f943c3 | Hannes Reinecke | static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, |
1096 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd) |
1097 | e8f943c3 | Hannes Reinecke | { |
1098 | e8f943c3 | Hannes Reinecke | struct mfi_ld_info *info = cmd->iov_buf;
|
1099 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(struct mfi_ld_info); |
1100 | e8f943c3 | Hannes Reinecke | uint8_t cdb[6];
|
1101 | e8f943c3 | Hannes Reinecke | SCSIRequest *req; |
1102 | e8f943c3 | Hannes Reinecke | ssize_t len, resid; |
1103 | e8f943c3 | Hannes Reinecke | BlockConf *conf = &sdev->conf; |
1104 | e8f943c3 | Hannes Reinecke | uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF); |
1105 | e8f943c3 | Hannes Reinecke | uint64_t ld_size; |
1106 | e8f943c3 | Hannes Reinecke | |
1107 | e8f943c3 | Hannes Reinecke | if (!cmd->iov_buf) {
|
1108 | e8f943c3 | Hannes Reinecke | cmd->iov_buf = g_malloc(dcmd_size); |
1109 | e8f943c3 | Hannes Reinecke | memset(cmd->iov_buf, 0x0, dcmd_size);
|
1110 | e8f943c3 | Hannes Reinecke | info = cmd->iov_buf; |
1111 | e8f943c3 | Hannes Reinecke | megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83)); |
1112 | e8f943c3 | Hannes Reinecke | req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd); |
1113 | e8f943c3 | Hannes Reinecke | if (!req) {
|
1114 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_req_alloc_failed(cmd->index, |
1115 | e8f943c3 | Hannes Reinecke | "LD get info vpd inquiry");
|
1116 | e8f943c3 | Hannes Reinecke | g_free(cmd->iov_buf); |
1117 | e8f943c3 | Hannes Reinecke | cmd->iov_buf = NULL;
|
1118 | e8f943c3 | Hannes Reinecke | return MFI_STAT_FLASH_ALLOC_FAIL;
|
1119 | e8f943c3 | Hannes Reinecke | } |
1120 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_internal_submit(cmd->index, |
1121 | e8f943c3 | Hannes Reinecke | "LD get info vpd inquiry", lun);
|
1122 | e8f943c3 | Hannes Reinecke | len = scsi_req_enqueue(req); |
1123 | e8f943c3 | Hannes Reinecke | if (len > 0) { |
1124 | e8f943c3 | Hannes Reinecke | cmd->iov_size = len; |
1125 | e8f943c3 | Hannes Reinecke | scsi_req_continue(req); |
1126 | e8f943c3 | Hannes Reinecke | } |
1127 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_STATUS;
|
1128 | e8f943c3 | Hannes Reinecke | } |
1129 | e8f943c3 | Hannes Reinecke | |
1130 | e8f943c3 | Hannes Reinecke | info->ld_config.params.state = MFI_LD_STATE_OPTIMAL; |
1131 | e8f943c3 | Hannes Reinecke | info->ld_config.properties.ld.v.target_id = lun; |
1132 | e8f943c3 | Hannes Reinecke | info->ld_config.params.stripe_size = 3;
|
1133 | e8f943c3 | Hannes Reinecke | info->ld_config.params.num_drives = 1;
|
1134 | e8f943c3 | Hannes Reinecke | info->ld_config.params.is_consistent = 1;
|
1135 | e8f943c3 | Hannes Reinecke | /* Logical device size is in blocks */
|
1136 | e8f943c3 | Hannes Reinecke | bdrv_get_geometry(conf->bs, &ld_size); |
1137 | e8f943c3 | Hannes Reinecke | info->size = cpu_to_le64(ld_size); |
1138 | e8f943c3 | Hannes Reinecke | memset(info->ld_config.span, 0, sizeof(info->ld_config.span)); |
1139 | e8f943c3 | Hannes Reinecke | info->ld_config.span[0].start_block = 0; |
1140 | e8f943c3 | Hannes Reinecke | info->ld_config.span[0].num_blocks = info->size;
|
1141 | e8f943c3 | Hannes Reinecke | info->ld_config.span[0].array_ref = cpu_to_le16(sdev_id);
|
1142 | e8f943c3 | Hannes Reinecke | |
1143 | e8f943c3 | Hannes Reinecke | resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg); |
1144 | e8f943c3 | Hannes Reinecke | g_free(cmd->iov_buf); |
1145 | e8f943c3 | Hannes Reinecke | cmd->iov_size = dcmd_size - resid; |
1146 | e8f943c3 | Hannes Reinecke | cmd->iov_buf = NULL;
|
1147 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1148 | e8f943c3 | Hannes Reinecke | } |
1149 | e8f943c3 | Hannes Reinecke | |
1150 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_ld_get_info(MegasasState *s, MegasasCmd *cmd) |
1151 | e8f943c3 | Hannes Reinecke | { |
1152 | e8f943c3 | Hannes Reinecke | struct mfi_ld_info info;
|
1153 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(info);
|
1154 | e8f943c3 | Hannes Reinecke | uint16_t ld_id; |
1155 | e8f943c3 | Hannes Reinecke | uint32_t max_ld_disks = s->fw_luns; |
1156 | e8f943c3 | Hannes Reinecke | SCSIDevice *sdev = NULL;
|
1157 | e8f943c3 | Hannes Reinecke | int retval = MFI_STAT_DEVICE_NOT_FOUND;
|
1158 | e8f943c3 | Hannes Reinecke | |
1159 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size < dcmd_size) {
|
1160 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
1161 | e8f943c3 | Hannes Reinecke | } |
1162 | e8f943c3 | Hannes Reinecke | |
1163 | e8f943c3 | Hannes Reinecke | /* mbox0 has the ID */
|
1164 | e8f943c3 | Hannes Reinecke | ld_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
|
1165 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_ld_get_info(cmd->index, ld_id); |
1166 | e8f943c3 | Hannes Reinecke | |
1167 | e8f943c3 | Hannes Reinecke | if (megasas_is_jbod(s)) {
|
1168 | e8f943c3 | Hannes Reinecke | return MFI_STAT_DEVICE_NOT_FOUND;
|
1169 | e8f943c3 | Hannes Reinecke | } |
1170 | e8f943c3 | Hannes Reinecke | |
1171 | e8f943c3 | Hannes Reinecke | if (ld_id < max_ld_disks) {
|
1172 | e8f943c3 | Hannes Reinecke | sdev = scsi_device_find(&s->bus, 0, ld_id, 0); |
1173 | e8f943c3 | Hannes Reinecke | } |
1174 | e8f943c3 | Hannes Reinecke | |
1175 | e8f943c3 | Hannes Reinecke | if (sdev) {
|
1176 | e8f943c3 | Hannes Reinecke | retval = megasas_ld_get_info_submit(sdev, ld_id, cmd); |
1177 | e8f943c3 | Hannes Reinecke | } |
1178 | e8f943c3 | Hannes Reinecke | |
1179 | e8f943c3 | Hannes Reinecke | return retval;
|
1180 | e8f943c3 | Hannes Reinecke | } |
1181 | e8f943c3 | Hannes Reinecke | |
1182 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd) |
1183 | e8f943c3 | Hannes Reinecke | { |
1184 | e8f943c3 | Hannes Reinecke | uint8_t data[4096];
|
1185 | e8f943c3 | Hannes Reinecke | struct mfi_config_data *info;
|
1186 | e8f943c3 | Hannes Reinecke | int num_pd_disks = 0, array_offset, ld_offset; |
1187 | e8f943c3 | Hannes Reinecke | BusChild *kid; |
1188 | e8f943c3 | Hannes Reinecke | |
1189 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size > 4096) { |
1190 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
1191 | e8f943c3 | Hannes Reinecke | } |
1192 | e8f943c3 | Hannes Reinecke | |
1193 | e8f943c3 | Hannes Reinecke | QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { |
1194 | e8f943c3 | Hannes Reinecke | num_pd_disks++; |
1195 | e8f943c3 | Hannes Reinecke | } |
1196 | e8f943c3 | Hannes Reinecke | info = (struct mfi_config_data *)&data;
|
1197 | e8f943c3 | Hannes Reinecke | /*
|
1198 | e8f943c3 | Hannes Reinecke | * Array mapping:
|
1199 | e8f943c3 | Hannes Reinecke | * - One array per SCSI device
|
1200 | e8f943c3 | Hannes Reinecke | * - One logical drive per SCSI device
|
1201 | e8f943c3 | Hannes Reinecke | * spanning the entire device
|
1202 | e8f943c3 | Hannes Reinecke | */
|
1203 | e8f943c3 | Hannes Reinecke | info->array_count = num_pd_disks; |
1204 | e8f943c3 | Hannes Reinecke | info->array_size = sizeof(struct mfi_array) * num_pd_disks; |
1205 | e8f943c3 | Hannes Reinecke | info->log_drv_count = num_pd_disks; |
1206 | e8f943c3 | Hannes Reinecke | info->log_drv_size = sizeof(struct mfi_ld_config) * num_pd_disks; |
1207 | e8f943c3 | Hannes Reinecke | info->spares_count = 0;
|
1208 | e8f943c3 | Hannes Reinecke | info->spares_size = sizeof(struct mfi_spare); |
1209 | e8f943c3 | Hannes Reinecke | info->size = sizeof(struct mfi_config_data) + info->array_size + |
1210 | e8f943c3 | Hannes Reinecke | info->log_drv_size; |
1211 | e8f943c3 | Hannes Reinecke | if (info->size > 4096) { |
1212 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
1213 | e8f943c3 | Hannes Reinecke | } |
1214 | e8f943c3 | Hannes Reinecke | |
1215 | e8f943c3 | Hannes Reinecke | array_offset = sizeof(struct mfi_config_data); |
1216 | e8f943c3 | Hannes Reinecke | ld_offset = array_offset + sizeof(struct mfi_array) * num_pd_disks; |
1217 | e8f943c3 | Hannes Reinecke | |
1218 | e8f943c3 | Hannes Reinecke | QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { |
1219 | e8f943c3 | Hannes Reinecke | SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); |
1220 | e8f943c3 | Hannes Reinecke | BlockConf *conf = &sdev->conf; |
1221 | e8f943c3 | Hannes Reinecke | uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF); |
1222 | e8f943c3 | Hannes Reinecke | struct mfi_array *array;
|
1223 | e8f943c3 | Hannes Reinecke | struct mfi_ld_config *ld;
|
1224 | e8f943c3 | Hannes Reinecke | uint64_t pd_size; |
1225 | e8f943c3 | Hannes Reinecke | int i;
|
1226 | e8f943c3 | Hannes Reinecke | |
1227 | e8f943c3 | Hannes Reinecke | array = (struct mfi_array *)(data + array_offset);
|
1228 | e8f943c3 | Hannes Reinecke | bdrv_get_geometry(conf->bs, &pd_size); |
1229 | e8f943c3 | Hannes Reinecke | array->size = cpu_to_le64(pd_size); |
1230 | e8f943c3 | Hannes Reinecke | array->num_drives = 1;
|
1231 | e8f943c3 | Hannes Reinecke | array->array_ref = cpu_to_le16(sdev_id); |
1232 | e8f943c3 | Hannes Reinecke | array->pd[0].ref.v.device_id = cpu_to_le16(sdev_id);
|
1233 | e8f943c3 | Hannes Reinecke | array->pd[0].ref.v.seq_num = 0; |
1234 | e8f943c3 | Hannes Reinecke | array->pd[0].fw_state = MFI_PD_STATE_ONLINE;
|
1235 | e8f943c3 | Hannes Reinecke | array->pd[0].encl.pd = 0xFF; |
1236 | e8f943c3 | Hannes Reinecke | array->pd[0].encl.slot = (sdev->id & 0xFF); |
1237 | e8f943c3 | Hannes Reinecke | for (i = 1; i < MFI_MAX_ROW_SIZE; i++) { |
1238 | e8f943c3 | Hannes Reinecke | array->pd[i].ref.v.device_id = 0xFFFF;
|
1239 | e8f943c3 | Hannes Reinecke | array->pd[i].ref.v.seq_num = 0;
|
1240 | e8f943c3 | Hannes Reinecke | array->pd[i].fw_state = MFI_PD_STATE_UNCONFIGURED_GOOD; |
1241 | e8f943c3 | Hannes Reinecke | array->pd[i].encl.pd = 0xFF;
|
1242 | e8f943c3 | Hannes Reinecke | array->pd[i].encl.slot = 0xFF;
|
1243 | e8f943c3 | Hannes Reinecke | } |
1244 | e8f943c3 | Hannes Reinecke | array_offset += sizeof(struct mfi_array); |
1245 | e8f943c3 | Hannes Reinecke | ld = (struct mfi_ld_config *)(data + ld_offset);
|
1246 | e8f943c3 | Hannes Reinecke | memset(ld, 0, sizeof(struct mfi_ld_config)); |
1247 | e8f943c3 | Hannes Reinecke | ld->properties.ld.v.target_id = (sdev->id & 0xFF);
|
1248 | e8f943c3 | Hannes Reinecke | ld->properties.default_cache_policy = MR_LD_CACHE_READ_AHEAD | |
1249 | e8f943c3 | Hannes Reinecke | MR_LD_CACHE_READ_ADAPTIVE; |
1250 | e8f943c3 | Hannes Reinecke | ld->properties.current_cache_policy = MR_LD_CACHE_READ_AHEAD | |
1251 | e8f943c3 | Hannes Reinecke | MR_LD_CACHE_READ_ADAPTIVE; |
1252 | e8f943c3 | Hannes Reinecke | ld->params.state = MFI_LD_STATE_OPTIMAL; |
1253 | e8f943c3 | Hannes Reinecke | ld->params.stripe_size = 3;
|
1254 | e8f943c3 | Hannes Reinecke | ld->params.num_drives = 1;
|
1255 | e8f943c3 | Hannes Reinecke | ld->params.span_depth = 1;
|
1256 | e8f943c3 | Hannes Reinecke | ld->params.is_consistent = 1;
|
1257 | e8f943c3 | Hannes Reinecke | ld->span[0].start_block = 0; |
1258 | e8f943c3 | Hannes Reinecke | ld->span[0].num_blocks = cpu_to_le64(pd_size);
|
1259 | e8f943c3 | Hannes Reinecke | ld->span[0].array_ref = cpu_to_le16(sdev_id);
|
1260 | e8f943c3 | Hannes Reinecke | ld_offset += sizeof(struct mfi_ld_config); |
1261 | e8f943c3 | Hannes Reinecke | } |
1262 | e8f943c3 | Hannes Reinecke | |
1263 | e8f943c3 | Hannes Reinecke | cmd->iov_size -= dma_buf_read((uint8_t *)data, info->size, &cmd->qsg); |
1264 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1265 | e8f943c3 | Hannes Reinecke | } |
1266 | e8f943c3 | Hannes Reinecke | |
1267 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd) |
1268 | e8f943c3 | Hannes Reinecke | { |
1269 | e8f943c3 | Hannes Reinecke | struct mfi_ctrl_props info;
|
1270 | e8f943c3 | Hannes Reinecke | size_t dcmd_size = sizeof(info);
|
1271 | e8f943c3 | Hannes Reinecke | |
1272 | e8f943c3 | Hannes Reinecke | memset(&info, 0x0, dcmd_size);
|
1273 | e8f943c3 | Hannes Reinecke | if (cmd->iov_size < dcmd_size) {
|
1274 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, |
1275 | e8f943c3 | Hannes Reinecke | dcmd_size); |
1276 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
1277 | e8f943c3 | Hannes Reinecke | } |
1278 | e8f943c3 | Hannes Reinecke | info.pred_fail_poll_interval = cpu_to_le16(300);
|
1279 | e8f943c3 | Hannes Reinecke | info.intr_throttle_cnt = cpu_to_le16(16);
|
1280 | e8f943c3 | Hannes Reinecke | info.intr_throttle_timeout = cpu_to_le16(50);
|
1281 | e8f943c3 | Hannes Reinecke | info.rebuild_rate = 30;
|
1282 | e8f943c3 | Hannes Reinecke | info.patrol_read_rate = 30;
|
1283 | e8f943c3 | Hannes Reinecke | info.bgi_rate = 30;
|
1284 | e8f943c3 | Hannes Reinecke | info.cc_rate = 30;
|
1285 | e8f943c3 | Hannes Reinecke | info.recon_rate = 30;
|
1286 | e8f943c3 | Hannes Reinecke | info.cache_flush_interval = 4;
|
1287 | e8f943c3 | Hannes Reinecke | info.spinup_drv_cnt = 2;
|
1288 | e8f943c3 | Hannes Reinecke | info.spinup_delay = 6;
|
1289 | e8f943c3 | Hannes Reinecke | info.ecc_bucket_size = 15;
|
1290 | e8f943c3 | Hannes Reinecke | info.ecc_bucket_leak_rate = cpu_to_le16(1440);
|
1291 | e8f943c3 | Hannes Reinecke | info.expose_encl_devices = 1;
|
1292 | e8f943c3 | Hannes Reinecke | |
1293 | e8f943c3 | Hannes Reinecke | cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); |
1294 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1295 | e8f943c3 | Hannes Reinecke | } |
1296 | e8f943c3 | Hannes Reinecke | |
1297 | e8f943c3 | Hannes Reinecke | static int megasas_cache_flush(MegasasState *s, MegasasCmd *cmd) |
1298 | e8f943c3 | Hannes Reinecke | { |
1299 | b618f4a1 | Kevin Wolf | bdrv_drain_all(); |
1300 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1301 | e8f943c3 | Hannes Reinecke | } |
1302 | e8f943c3 | Hannes Reinecke | |
1303 | e8f943c3 | Hannes Reinecke | static int megasas_ctrl_shutdown(MegasasState *s, MegasasCmd *cmd) |
1304 | e8f943c3 | Hannes Reinecke | { |
1305 | e8f943c3 | Hannes Reinecke | s->fw_state = MFI_FWSTATE_READY; |
1306 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1307 | e8f943c3 | Hannes Reinecke | } |
1308 | e8f943c3 | Hannes Reinecke | |
1309 | e8f943c3 | Hannes Reinecke | static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd) |
1310 | e8f943c3 | Hannes Reinecke | { |
1311 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_DCMD;
|
1312 | e8f943c3 | Hannes Reinecke | } |
1313 | e8f943c3 | Hannes Reinecke | |
1314 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd) |
1315 | e8f943c3 | Hannes Reinecke | { |
1316 | 10d6530c | Hannes Reinecke | struct mfi_ctrl_props info;
|
1317 | 10d6530c | Hannes Reinecke | size_t dcmd_size = sizeof(info);
|
1318 | 10d6530c | Hannes Reinecke | |
1319 | 10d6530c | Hannes Reinecke | if (cmd->iov_size < dcmd_size) {
|
1320 | 10d6530c | Hannes Reinecke | trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, |
1321 | 10d6530c | Hannes Reinecke | dcmd_size); |
1322 | 10d6530c | Hannes Reinecke | return MFI_STAT_INVALID_PARAMETER;
|
1323 | 10d6530c | Hannes Reinecke | } |
1324 | 10d6530c | Hannes Reinecke | dma_buf_write((uint8_t *)&info, cmd->iov_size, &cmd->qsg); |
1325 | 10d6530c | Hannes Reinecke | trace_megasas_dcmd_unsupported(cmd->index, cmd->iov_size); |
1326 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1327 | e8f943c3 | Hannes Reinecke | } |
1328 | e8f943c3 | Hannes Reinecke | |
1329 | e8f943c3 | Hannes Reinecke | static int megasas_dcmd_dummy(MegasasState *s, MegasasCmd *cmd) |
1330 | e8f943c3 | Hannes Reinecke | { |
1331 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_dummy(cmd->index, cmd->iov_size); |
1332 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1333 | e8f943c3 | Hannes Reinecke | } |
1334 | e8f943c3 | Hannes Reinecke | |
1335 | e8f943c3 | Hannes Reinecke | static const struct dcmd_cmd_tbl_t { |
1336 | e8f943c3 | Hannes Reinecke | int opcode;
|
1337 | e8f943c3 | Hannes Reinecke | const char *desc; |
1338 | e8f943c3 | Hannes Reinecke | int (*func)(MegasasState *s, MegasasCmd *cmd);
|
1339 | e8f943c3 | Hannes Reinecke | } dcmd_cmd_tbl[] = { |
1340 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC, "CTRL_HOST_MEM_ALLOC",
|
1341 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1342 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_GET_INFO, "CTRL_GET_INFO",
|
1343 | e8f943c3 | Hannes Reinecke | megasas_ctrl_get_info }, |
1344 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_GET_PROPERTIES, "CTRL_GET_PROPERTIES",
|
1345 | e8f943c3 | Hannes Reinecke | megasas_dcmd_get_properties }, |
1346 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_SET_PROPERTIES, "CTRL_SET_PROPERTIES",
|
1347 | e8f943c3 | Hannes Reinecke | megasas_dcmd_set_properties }, |
1348 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_ALARM_GET, "CTRL_ALARM_GET",
|
1349 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1350 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_ALARM_ENABLE, "CTRL_ALARM_ENABLE",
|
1351 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1352 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_ALARM_DISABLE, "CTRL_ALARM_DISABLE",
|
1353 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1354 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_ALARM_SILENCE, "CTRL_ALARM_SILENCE",
|
1355 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1356 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_ALARM_TEST, "CTRL_ALARM_TEST",
|
1357 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1358 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_EVENT_GETINFO, "CTRL_EVENT_GETINFO",
|
1359 | e8f943c3 | Hannes Reinecke | megasas_event_info }, |
1360 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_EVENT_GET, "CTRL_EVENT_GET",
|
1361 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1362 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_EVENT_WAIT, "CTRL_EVENT_WAIT",
|
1363 | e8f943c3 | Hannes Reinecke | megasas_event_wait }, |
1364 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_SHUTDOWN, "CTRL_SHUTDOWN",
|
1365 | e8f943c3 | Hannes Reinecke | megasas_ctrl_shutdown }, |
1366 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_HIBERNATE_STANDBY, "CTRL_STANDBY",
|
1367 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1368 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_GET_TIME, "CTRL_GET_TIME",
|
1369 | e8f943c3 | Hannes Reinecke | megasas_dcmd_get_fw_time }, |
1370 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_SET_TIME, "CTRL_SET_TIME",
|
1371 | e8f943c3 | Hannes Reinecke | megasas_dcmd_set_fw_time }, |
1372 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_BIOS_DATA_GET, "CTRL_BIOS_DATA_GET",
|
1373 | e8f943c3 | Hannes Reinecke | megasas_dcmd_get_bios_info }, |
1374 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_FACTORY_DEFAULTS, "CTRL_FACTORY_DEFAULTS",
|
1375 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1376 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_MFC_DEFAULTS_GET, "CTRL_MFC_DEFAULTS_GET",
|
1377 | e8f943c3 | Hannes Reinecke | megasas_mfc_get_defaults }, |
1378 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_MFC_DEFAULTS_SET, "CTRL_MFC_DEFAULTS_SET",
|
1379 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1380 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CTRL_CACHE_FLUSH, "CTRL_CACHE_FLUSH",
|
1381 | e8f943c3 | Hannes Reinecke | megasas_cache_flush }, |
1382 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_PD_GET_LIST, "PD_GET_LIST",
|
1383 | e8f943c3 | Hannes Reinecke | megasas_dcmd_pd_get_list }, |
1384 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_PD_LIST_QUERY, "PD_LIST_QUERY",
|
1385 | e8f943c3 | Hannes Reinecke | megasas_dcmd_pd_list_query }, |
1386 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_PD_GET_INFO, "PD_GET_INFO",
|
1387 | e8f943c3 | Hannes Reinecke | megasas_dcmd_pd_get_info }, |
1388 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_PD_STATE_SET, "PD_STATE_SET",
|
1389 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1390 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_PD_REBUILD, "PD_REBUILD",
|
1391 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1392 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_PD_BLINK, "PD_BLINK",
|
1393 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1394 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_PD_UNBLINK, "PD_UNBLINK",
|
1395 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1396 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_LD_GET_LIST, "LD_GET_LIST",
|
1397 | e8f943c3 | Hannes Reinecke | megasas_dcmd_ld_get_list}, |
1398 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_LD_GET_INFO, "LD_GET_INFO",
|
1399 | e8f943c3 | Hannes Reinecke | megasas_dcmd_ld_get_info }, |
1400 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_LD_GET_PROP, "LD_GET_PROP",
|
1401 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1402 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_LD_SET_PROP, "LD_SET_PROP",
|
1403 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1404 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_LD_DELETE, "LD_DELETE",
|
1405 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1406 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CFG_READ, "CFG_READ",
|
1407 | e8f943c3 | Hannes Reinecke | megasas_dcmd_cfg_read }, |
1408 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CFG_ADD, "CFG_ADD",
|
1409 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1410 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CFG_CLEAR, "CFG_CLEAR",
|
1411 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1412 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CFG_FOREIGN_READ, "CFG_FOREIGN_READ",
|
1413 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1414 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CFG_FOREIGN_IMPORT, "CFG_FOREIGN_IMPORT",
|
1415 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1416 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_BBU_STATUS, "BBU_STATUS",
|
1417 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1418 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_BBU_CAPACITY_INFO, "BBU_CAPACITY_INFO",
|
1419 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1420 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_BBU_DESIGN_INFO, "BBU_DESIGN_INFO",
|
1421 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1422 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_BBU_PROP_GET, "BBU_PROP_GET",
|
1423 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1424 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CLUSTER, "CLUSTER",
|
1425 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1426 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CLUSTER_RESET_ALL, "CLUSTER_RESET_ALL",
|
1427 | e8f943c3 | Hannes Reinecke | megasas_dcmd_dummy }, |
1428 | e8f943c3 | Hannes Reinecke | { MFI_DCMD_CLUSTER_RESET_LD, "CLUSTER_RESET_LD",
|
1429 | e8f943c3 | Hannes Reinecke | megasas_cluster_reset_ld }, |
1430 | e8f943c3 | Hannes Reinecke | { -1, NULL, NULL } |
1431 | e8f943c3 | Hannes Reinecke | }; |
1432 | e8f943c3 | Hannes Reinecke | |
1433 | e8f943c3 | Hannes Reinecke | static int megasas_handle_dcmd(MegasasState *s, MegasasCmd *cmd) |
1434 | e8f943c3 | Hannes Reinecke | { |
1435 | e8f943c3 | Hannes Reinecke | int opcode, len;
|
1436 | e8f943c3 | Hannes Reinecke | int retval = 0; |
1437 | e8f943c3 | Hannes Reinecke | const struct dcmd_cmd_tbl_t *cmdptr = dcmd_cmd_tbl; |
1438 | e8f943c3 | Hannes Reinecke | |
1439 | e8f943c3 | Hannes Reinecke | opcode = le32_to_cpu(cmd->frame->dcmd.opcode); |
1440 | e8f943c3 | Hannes Reinecke | trace_megasas_handle_dcmd(cmd->index, opcode); |
1441 | e8f943c3 | Hannes Reinecke | len = megasas_map_dcmd(s, cmd); |
1442 | e8f943c3 | Hannes Reinecke | if (len < 0) { |
1443 | e8f943c3 | Hannes Reinecke | return MFI_STAT_MEMORY_NOT_AVAILABLE;
|
1444 | e8f943c3 | Hannes Reinecke | } |
1445 | e8f943c3 | Hannes Reinecke | while (cmdptr->opcode != -1 && cmdptr->opcode != opcode) { |
1446 | e8f943c3 | Hannes Reinecke | cmdptr++; |
1447 | e8f943c3 | Hannes Reinecke | } |
1448 | e8f943c3 | Hannes Reinecke | if (cmdptr->opcode == -1) { |
1449 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_unhandled(cmd->index, opcode, len); |
1450 | e8f943c3 | Hannes Reinecke | retval = megasas_dcmd_dummy(s, cmd); |
1451 | e8f943c3 | Hannes Reinecke | } else {
|
1452 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_enter(cmd->index, cmdptr->desc, len); |
1453 | e8f943c3 | Hannes Reinecke | retval = cmdptr->func(s, cmd); |
1454 | e8f943c3 | Hannes Reinecke | } |
1455 | e8f943c3 | Hannes Reinecke | if (retval != MFI_STAT_INVALID_STATUS) {
|
1456 | e8f943c3 | Hannes Reinecke | megasas_finish_dcmd(cmd, len); |
1457 | e8f943c3 | Hannes Reinecke | } |
1458 | e8f943c3 | Hannes Reinecke | return retval;
|
1459 | e8f943c3 | Hannes Reinecke | } |
1460 | e8f943c3 | Hannes Reinecke | |
1461 | e8f943c3 | Hannes Reinecke | static int megasas_finish_internal_dcmd(MegasasCmd *cmd, |
1462 | e8f943c3 | Hannes Reinecke | SCSIRequest *req) |
1463 | e8f943c3 | Hannes Reinecke | { |
1464 | e8f943c3 | Hannes Reinecke | int opcode;
|
1465 | e8f943c3 | Hannes Reinecke | int retval = MFI_STAT_OK;
|
1466 | e8f943c3 | Hannes Reinecke | int lun = req->lun;
|
1467 | e8f943c3 | Hannes Reinecke | |
1468 | e8f943c3 | Hannes Reinecke | opcode = le32_to_cpu(cmd->frame->dcmd.opcode); |
1469 | e8f943c3 | Hannes Reinecke | scsi_req_unref(req); |
1470 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_internal_finish(cmd->index, opcode, lun); |
1471 | e8f943c3 | Hannes Reinecke | switch (opcode) {
|
1472 | e8f943c3 | Hannes Reinecke | case MFI_DCMD_PD_GET_INFO:
|
1473 | e8f943c3 | Hannes Reinecke | retval = megasas_pd_get_info_submit(req->dev, lun, cmd); |
1474 | e8f943c3 | Hannes Reinecke | break;
|
1475 | e8f943c3 | Hannes Reinecke | case MFI_DCMD_LD_GET_INFO:
|
1476 | e8f943c3 | Hannes Reinecke | retval = megasas_ld_get_info_submit(req->dev, lun, cmd); |
1477 | e8f943c3 | Hannes Reinecke | break;
|
1478 | e8f943c3 | Hannes Reinecke | default:
|
1479 | e8f943c3 | Hannes Reinecke | trace_megasas_dcmd_internal_invalid(cmd->index, opcode); |
1480 | e8f943c3 | Hannes Reinecke | retval = MFI_STAT_INVALID_DCMD; |
1481 | e8f943c3 | Hannes Reinecke | break;
|
1482 | e8f943c3 | Hannes Reinecke | } |
1483 | e8f943c3 | Hannes Reinecke | if (retval != MFI_STAT_INVALID_STATUS) {
|
1484 | e8f943c3 | Hannes Reinecke | megasas_finish_dcmd(cmd, cmd->iov_size); |
1485 | e8f943c3 | Hannes Reinecke | } |
1486 | e8f943c3 | Hannes Reinecke | return retval;
|
1487 | e8f943c3 | Hannes Reinecke | } |
1488 | e8f943c3 | Hannes Reinecke | |
1489 | e8f943c3 | Hannes Reinecke | static int megasas_enqueue_req(MegasasCmd *cmd, bool is_write) |
1490 | e8f943c3 | Hannes Reinecke | { |
1491 | e8f943c3 | Hannes Reinecke | int len;
|
1492 | e8f943c3 | Hannes Reinecke | |
1493 | e8f943c3 | Hannes Reinecke | len = scsi_req_enqueue(cmd->req); |
1494 | e8f943c3 | Hannes Reinecke | if (len < 0) { |
1495 | e8f943c3 | Hannes Reinecke | len = -len; |
1496 | e8f943c3 | Hannes Reinecke | } |
1497 | e8f943c3 | Hannes Reinecke | if (len > 0) { |
1498 | e8f943c3 | Hannes Reinecke | if (len > cmd->iov_size) {
|
1499 | e8f943c3 | Hannes Reinecke | if (is_write) {
|
1500 | e8f943c3 | Hannes Reinecke | trace_megasas_iov_write_overflow(cmd->index, len, |
1501 | e8f943c3 | Hannes Reinecke | cmd->iov_size); |
1502 | e8f943c3 | Hannes Reinecke | } else {
|
1503 | e8f943c3 | Hannes Reinecke | trace_megasas_iov_read_overflow(cmd->index, len, |
1504 | e8f943c3 | Hannes Reinecke | cmd->iov_size); |
1505 | e8f943c3 | Hannes Reinecke | } |
1506 | e8f943c3 | Hannes Reinecke | } |
1507 | e8f943c3 | Hannes Reinecke | if (len < cmd->iov_size) {
|
1508 | e8f943c3 | Hannes Reinecke | if (is_write) {
|
1509 | e8f943c3 | Hannes Reinecke | trace_megasas_iov_write_underflow(cmd->index, len, |
1510 | e8f943c3 | Hannes Reinecke | cmd->iov_size); |
1511 | e8f943c3 | Hannes Reinecke | } else {
|
1512 | e8f943c3 | Hannes Reinecke | trace_megasas_iov_read_underflow(cmd->index, len, |
1513 | e8f943c3 | Hannes Reinecke | cmd->iov_size); |
1514 | e8f943c3 | Hannes Reinecke | } |
1515 | e8f943c3 | Hannes Reinecke | cmd->iov_size = len; |
1516 | e8f943c3 | Hannes Reinecke | } |
1517 | e8f943c3 | Hannes Reinecke | scsi_req_continue(cmd->req); |
1518 | e8f943c3 | Hannes Reinecke | } |
1519 | e8f943c3 | Hannes Reinecke | return len;
|
1520 | e8f943c3 | Hannes Reinecke | } |
1521 | e8f943c3 | Hannes Reinecke | |
1522 | e8f943c3 | Hannes Reinecke | static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, |
1523 | e8f943c3 | Hannes Reinecke | bool is_logical)
|
1524 | e8f943c3 | Hannes Reinecke | { |
1525 | e8f943c3 | Hannes Reinecke | uint8_t *cdb; |
1526 | e8f943c3 | Hannes Reinecke | int len;
|
1527 | e8f943c3 | Hannes Reinecke | bool is_write;
|
1528 | e8f943c3 | Hannes Reinecke | struct SCSIDevice *sdev = NULL; |
1529 | e8f943c3 | Hannes Reinecke | |
1530 | e8f943c3 | Hannes Reinecke | cdb = cmd->frame->pass.cdb; |
1531 | e8f943c3 | Hannes Reinecke | |
1532 | e8f943c3 | Hannes Reinecke | if (cmd->frame->header.target_id < s->fw_luns) {
|
1533 | e8f943c3 | Hannes Reinecke | sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
|
1534 | e8f943c3 | Hannes Reinecke | cmd->frame->header.lun_id); |
1535 | e8f943c3 | Hannes Reinecke | } |
1536 | e8f943c3 | Hannes Reinecke | cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len); |
1537 | e8f943c3 | Hannes Reinecke | trace_megasas_handle_scsi(mfi_frame_desc[cmd->frame->header.frame_cmd], |
1538 | e8f943c3 | Hannes Reinecke | is_logical, cmd->frame->header.target_id, |
1539 | e8f943c3 | Hannes Reinecke | cmd->frame->header.lun_id, sdev, cmd->iov_size); |
1540 | e8f943c3 | Hannes Reinecke | |
1541 | e8f943c3 | Hannes Reinecke | if (!sdev || (megasas_is_jbod(s) && is_logical)) {
|
1542 | e8f943c3 | Hannes Reinecke | trace_megasas_scsi_target_not_present( |
1543 | e8f943c3 | Hannes Reinecke | mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical, |
1544 | e8f943c3 | Hannes Reinecke | cmd->frame->header.target_id, cmd->frame->header.lun_id); |
1545 | e8f943c3 | Hannes Reinecke | return MFI_STAT_DEVICE_NOT_FOUND;
|
1546 | e8f943c3 | Hannes Reinecke | } |
1547 | e8f943c3 | Hannes Reinecke | |
1548 | e8f943c3 | Hannes Reinecke | if (cmd->frame->header.cdb_len > 16) { |
1549 | e8f943c3 | Hannes Reinecke | trace_megasas_scsi_invalid_cdb_len( |
1550 | e8f943c3 | Hannes Reinecke | mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical, |
1551 | e8f943c3 | Hannes Reinecke | cmd->frame->header.target_id, cmd->frame->header.lun_id, |
1552 | e8f943c3 | Hannes Reinecke | cmd->frame->header.cdb_len); |
1553 | e8f943c3 | Hannes Reinecke | megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE)); |
1554 | e8f943c3 | Hannes Reinecke | cmd->frame->header.scsi_status = CHECK_CONDITION; |
1555 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1556 | e8f943c3 | Hannes Reinecke | return MFI_STAT_SCSI_DONE_WITH_ERROR;
|
1557 | e8f943c3 | Hannes Reinecke | } |
1558 | e8f943c3 | Hannes Reinecke | |
1559 | e8f943c3 | Hannes Reinecke | if (megasas_map_sgl(s, cmd, &cmd->frame->pass.sgl)) {
|
1560 | e8f943c3 | Hannes Reinecke | megasas_write_sense(cmd, SENSE_CODE(TARGET_FAILURE)); |
1561 | e8f943c3 | Hannes Reinecke | cmd->frame->header.scsi_status = CHECK_CONDITION; |
1562 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1563 | e8f943c3 | Hannes Reinecke | return MFI_STAT_SCSI_DONE_WITH_ERROR;
|
1564 | e8f943c3 | Hannes Reinecke | } |
1565 | e8f943c3 | Hannes Reinecke | |
1566 | e8f943c3 | Hannes Reinecke | cmd->req = scsi_req_new(sdev, cmd->index, |
1567 | e8f943c3 | Hannes Reinecke | cmd->frame->header.lun_id, cdb, cmd); |
1568 | e8f943c3 | Hannes Reinecke | if (!cmd->req) {
|
1569 | e8f943c3 | Hannes Reinecke | trace_megasas_scsi_req_alloc_failed( |
1570 | e8f943c3 | Hannes Reinecke | mfi_frame_desc[cmd->frame->header.frame_cmd], |
1571 | e8f943c3 | Hannes Reinecke | cmd->frame->header.target_id, cmd->frame->header.lun_id); |
1572 | e8f943c3 | Hannes Reinecke | megasas_write_sense(cmd, SENSE_CODE(NO_SENSE)); |
1573 | e8f943c3 | Hannes Reinecke | cmd->frame->header.scsi_status = BUSY; |
1574 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1575 | e8f943c3 | Hannes Reinecke | return MFI_STAT_SCSI_DONE_WITH_ERROR;
|
1576 | e8f943c3 | Hannes Reinecke | } |
1577 | e8f943c3 | Hannes Reinecke | |
1578 | e8f943c3 | Hannes Reinecke | is_write = (cmd->req->cmd.mode == SCSI_XFER_TO_DEV); |
1579 | e8f943c3 | Hannes Reinecke | len = megasas_enqueue_req(cmd, is_write); |
1580 | e8f943c3 | Hannes Reinecke | if (len > 0) { |
1581 | e8f943c3 | Hannes Reinecke | if (is_write) {
|
1582 | e8f943c3 | Hannes Reinecke | trace_megasas_scsi_write_start(cmd->index, len); |
1583 | e8f943c3 | Hannes Reinecke | } else {
|
1584 | e8f943c3 | Hannes Reinecke | trace_megasas_scsi_read_start(cmd->index, len); |
1585 | e8f943c3 | Hannes Reinecke | } |
1586 | e8f943c3 | Hannes Reinecke | } else {
|
1587 | e8f943c3 | Hannes Reinecke | trace_megasas_scsi_nodata(cmd->index); |
1588 | e8f943c3 | Hannes Reinecke | } |
1589 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_STATUS;
|
1590 | e8f943c3 | Hannes Reinecke | } |
1591 | e8f943c3 | Hannes Reinecke | |
1592 | e8f943c3 | Hannes Reinecke | static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd) |
1593 | e8f943c3 | Hannes Reinecke | { |
1594 | e8f943c3 | Hannes Reinecke | uint32_t lba_count, lba_start_hi, lba_start_lo; |
1595 | e8f943c3 | Hannes Reinecke | uint64_t lba_start; |
1596 | e8f943c3 | Hannes Reinecke | bool is_write = (cmd->frame->header.frame_cmd == MFI_CMD_LD_WRITE);
|
1597 | e8f943c3 | Hannes Reinecke | uint8_t cdb[16];
|
1598 | e8f943c3 | Hannes Reinecke | int len;
|
1599 | e8f943c3 | Hannes Reinecke | struct SCSIDevice *sdev = NULL; |
1600 | e8f943c3 | Hannes Reinecke | |
1601 | e8f943c3 | Hannes Reinecke | lba_count = le32_to_cpu(cmd->frame->io.header.data_len); |
1602 | e8f943c3 | Hannes Reinecke | lba_start_lo = le32_to_cpu(cmd->frame->io.lba_lo); |
1603 | e8f943c3 | Hannes Reinecke | lba_start_hi = le32_to_cpu(cmd->frame->io.lba_hi); |
1604 | e8f943c3 | Hannes Reinecke | lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo;
|
1605 | e8f943c3 | Hannes Reinecke | |
1606 | e8f943c3 | Hannes Reinecke | if (cmd->frame->header.target_id < s->fw_luns) {
|
1607 | e8f943c3 | Hannes Reinecke | sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
|
1608 | e8f943c3 | Hannes Reinecke | cmd->frame->header.lun_id); |
1609 | e8f943c3 | Hannes Reinecke | } |
1610 | e8f943c3 | Hannes Reinecke | |
1611 | e8f943c3 | Hannes Reinecke | trace_megasas_handle_io(cmd->index, |
1612 | e8f943c3 | Hannes Reinecke | mfi_frame_desc[cmd->frame->header.frame_cmd], |
1613 | e8f943c3 | Hannes Reinecke | cmd->frame->header.target_id, |
1614 | e8f943c3 | Hannes Reinecke | cmd->frame->header.lun_id, |
1615 | e8f943c3 | Hannes Reinecke | (unsigned long)lba_start, (unsigned long)lba_count); |
1616 | e8f943c3 | Hannes Reinecke | if (!sdev) {
|
1617 | e8f943c3 | Hannes Reinecke | trace_megasas_io_target_not_present(cmd->index, |
1618 | e8f943c3 | Hannes Reinecke | mfi_frame_desc[cmd->frame->header.frame_cmd], |
1619 | e8f943c3 | Hannes Reinecke | cmd->frame->header.target_id, cmd->frame->header.lun_id); |
1620 | e8f943c3 | Hannes Reinecke | return MFI_STAT_DEVICE_NOT_FOUND;
|
1621 | e8f943c3 | Hannes Reinecke | } |
1622 | e8f943c3 | Hannes Reinecke | |
1623 | e8f943c3 | Hannes Reinecke | if (cmd->frame->header.cdb_len > 16) { |
1624 | e8f943c3 | Hannes Reinecke | trace_megasas_scsi_invalid_cdb_len( |
1625 | e8f943c3 | Hannes Reinecke | mfi_frame_desc[cmd->frame->header.frame_cmd], 1,
|
1626 | e8f943c3 | Hannes Reinecke | cmd->frame->header.target_id, cmd->frame->header.lun_id, |
1627 | e8f943c3 | Hannes Reinecke | cmd->frame->header.cdb_len); |
1628 | e8f943c3 | Hannes Reinecke | megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE)); |
1629 | e8f943c3 | Hannes Reinecke | cmd->frame->header.scsi_status = CHECK_CONDITION; |
1630 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1631 | e8f943c3 | Hannes Reinecke | return MFI_STAT_SCSI_DONE_WITH_ERROR;
|
1632 | e8f943c3 | Hannes Reinecke | } |
1633 | e8f943c3 | Hannes Reinecke | |
1634 | e8f943c3 | Hannes Reinecke | cmd->iov_size = lba_count * sdev->blocksize; |
1635 | e8f943c3 | Hannes Reinecke | if (megasas_map_sgl(s, cmd, &cmd->frame->io.sgl)) {
|
1636 | e8f943c3 | Hannes Reinecke | megasas_write_sense(cmd, SENSE_CODE(TARGET_FAILURE)); |
1637 | e8f943c3 | Hannes Reinecke | cmd->frame->header.scsi_status = CHECK_CONDITION; |
1638 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1639 | e8f943c3 | Hannes Reinecke | return MFI_STAT_SCSI_DONE_WITH_ERROR;
|
1640 | e8f943c3 | Hannes Reinecke | } |
1641 | e8f943c3 | Hannes Reinecke | |
1642 | e8f943c3 | Hannes Reinecke | megasas_encode_lba(cdb, lba_start, lba_count, is_write); |
1643 | e8f943c3 | Hannes Reinecke | cmd->req = scsi_req_new(sdev, cmd->index, |
1644 | e8f943c3 | Hannes Reinecke | cmd->frame->header.lun_id, cdb, cmd); |
1645 | e8f943c3 | Hannes Reinecke | if (!cmd->req) {
|
1646 | e8f943c3 | Hannes Reinecke | trace_megasas_scsi_req_alloc_failed( |
1647 | e8f943c3 | Hannes Reinecke | mfi_frame_desc[cmd->frame->header.frame_cmd], |
1648 | e8f943c3 | Hannes Reinecke | cmd->frame->header.target_id, cmd->frame->header.lun_id); |
1649 | e8f943c3 | Hannes Reinecke | megasas_write_sense(cmd, SENSE_CODE(NO_SENSE)); |
1650 | e8f943c3 | Hannes Reinecke | cmd->frame->header.scsi_status = BUSY; |
1651 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1652 | e8f943c3 | Hannes Reinecke | return MFI_STAT_SCSI_DONE_WITH_ERROR;
|
1653 | e8f943c3 | Hannes Reinecke | } |
1654 | e8f943c3 | Hannes Reinecke | len = megasas_enqueue_req(cmd, is_write); |
1655 | e8f943c3 | Hannes Reinecke | if (len > 0) { |
1656 | e8f943c3 | Hannes Reinecke | if (is_write) {
|
1657 | e8f943c3 | Hannes Reinecke | trace_megasas_io_write_start(cmd->index, lba_start, lba_count, len); |
1658 | e8f943c3 | Hannes Reinecke | } else {
|
1659 | e8f943c3 | Hannes Reinecke | trace_megasas_io_read_start(cmd->index, lba_start, lba_count, len); |
1660 | e8f943c3 | Hannes Reinecke | } |
1661 | e8f943c3 | Hannes Reinecke | } |
1662 | e8f943c3 | Hannes Reinecke | return MFI_STAT_INVALID_STATUS;
|
1663 | e8f943c3 | Hannes Reinecke | } |
1664 | e8f943c3 | Hannes Reinecke | |
1665 | e8f943c3 | Hannes Reinecke | static int megasas_finish_internal_command(MegasasCmd *cmd, |
1666 | e8f943c3 | Hannes Reinecke | SCSIRequest *req, size_t resid) |
1667 | e8f943c3 | Hannes Reinecke | { |
1668 | e8f943c3 | Hannes Reinecke | int retval = MFI_STAT_INVALID_CMD;
|
1669 | e8f943c3 | Hannes Reinecke | |
1670 | e8f943c3 | Hannes Reinecke | if (cmd->frame->header.frame_cmd == MFI_CMD_DCMD) {
|
1671 | e8f943c3 | Hannes Reinecke | cmd->iov_size -= resid; |
1672 | e8f943c3 | Hannes Reinecke | retval = megasas_finish_internal_dcmd(cmd, req); |
1673 | e8f943c3 | Hannes Reinecke | } |
1674 | e8f943c3 | Hannes Reinecke | return retval;
|
1675 | e8f943c3 | Hannes Reinecke | } |
1676 | e8f943c3 | Hannes Reinecke | |
1677 | e8f943c3 | Hannes Reinecke | static QEMUSGList *megasas_get_sg_list(SCSIRequest *req)
|
1678 | e8f943c3 | Hannes Reinecke | { |
1679 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd = req->hba_private; |
1680 | e8f943c3 | Hannes Reinecke | |
1681 | e8f943c3 | Hannes Reinecke | if (cmd->frame->header.frame_cmd == MFI_CMD_DCMD) {
|
1682 | e8f943c3 | Hannes Reinecke | return NULL; |
1683 | e8f943c3 | Hannes Reinecke | } else {
|
1684 | e8f943c3 | Hannes Reinecke | return &cmd->qsg;
|
1685 | e8f943c3 | Hannes Reinecke | } |
1686 | e8f943c3 | Hannes Reinecke | } |
1687 | e8f943c3 | Hannes Reinecke | |
1688 | e8f943c3 | Hannes Reinecke | static void megasas_xfer_complete(SCSIRequest *req, uint32_t len) |
1689 | e8f943c3 | Hannes Reinecke | { |
1690 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd = req->hba_private; |
1691 | e8f943c3 | Hannes Reinecke | uint8_t *buf; |
1692 | e8f943c3 | Hannes Reinecke | uint32_t opcode; |
1693 | e8f943c3 | Hannes Reinecke | |
1694 | e8f943c3 | Hannes Reinecke | trace_megasas_io_complete(cmd->index, len); |
1695 | e8f943c3 | Hannes Reinecke | |
1696 | e8f943c3 | Hannes Reinecke | if (cmd->frame->header.frame_cmd != MFI_CMD_DCMD) {
|
1697 | e8f943c3 | Hannes Reinecke | scsi_req_continue(req); |
1698 | e8f943c3 | Hannes Reinecke | return;
|
1699 | e8f943c3 | Hannes Reinecke | } |
1700 | e8f943c3 | Hannes Reinecke | |
1701 | e8f943c3 | Hannes Reinecke | buf = scsi_req_get_buf(req); |
1702 | e8f943c3 | Hannes Reinecke | opcode = le32_to_cpu(cmd->frame->dcmd.opcode); |
1703 | e8f943c3 | Hannes Reinecke | if (opcode == MFI_DCMD_PD_GET_INFO && cmd->iov_buf) {
|
1704 | e8f943c3 | Hannes Reinecke | struct mfi_pd_info *info = cmd->iov_buf;
|
1705 | e8f943c3 | Hannes Reinecke | |
1706 | e8f943c3 | Hannes Reinecke | if (info->inquiry_data[0] == 0x7f) { |
1707 | e8f943c3 | Hannes Reinecke | memset(info->inquiry_data, 0, sizeof(info->inquiry_data)); |
1708 | e8f943c3 | Hannes Reinecke | memcpy(info->inquiry_data, buf, len); |
1709 | e8f943c3 | Hannes Reinecke | } else if (info->vpd_page83[0] == 0x7f) { |
1710 | e8f943c3 | Hannes Reinecke | memset(info->vpd_page83, 0, sizeof(info->vpd_page83)); |
1711 | e8f943c3 | Hannes Reinecke | memcpy(info->vpd_page83, buf, len); |
1712 | e8f943c3 | Hannes Reinecke | } |
1713 | e8f943c3 | Hannes Reinecke | scsi_req_continue(req); |
1714 | e8f943c3 | Hannes Reinecke | } else if (opcode == MFI_DCMD_LD_GET_INFO) { |
1715 | e8f943c3 | Hannes Reinecke | struct mfi_ld_info *info = cmd->iov_buf;
|
1716 | e8f943c3 | Hannes Reinecke | |
1717 | e8f943c3 | Hannes Reinecke | if (cmd->iov_buf) {
|
1718 | e8f943c3 | Hannes Reinecke | memcpy(info->vpd_page83, buf, sizeof(info->vpd_page83));
|
1719 | e8f943c3 | Hannes Reinecke | scsi_req_continue(req); |
1720 | e8f943c3 | Hannes Reinecke | } |
1721 | e8f943c3 | Hannes Reinecke | } |
1722 | e8f943c3 | Hannes Reinecke | } |
1723 | e8f943c3 | Hannes Reinecke | |
1724 | e8f943c3 | Hannes Reinecke | static void megasas_command_complete(SCSIRequest *req, uint32_t status, |
1725 | e8f943c3 | Hannes Reinecke | size_t resid) |
1726 | e8f943c3 | Hannes Reinecke | { |
1727 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd = req->hba_private; |
1728 | e8f943c3 | Hannes Reinecke | uint8_t cmd_status = MFI_STAT_OK; |
1729 | e8f943c3 | Hannes Reinecke | |
1730 | e8f943c3 | Hannes Reinecke | trace_megasas_command_complete(cmd->index, status, resid); |
1731 | e8f943c3 | Hannes Reinecke | |
1732 | e8f943c3 | Hannes Reinecke | if (cmd->req != req) {
|
1733 | e8f943c3 | Hannes Reinecke | /*
|
1734 | e8f943c3 | Hannes Reinecke | * Internal command complete
|
1735 | e8f943c3 | Hannes Reinecke | */
|
1736 | e8f943c3 | Hannes Reinecke | cmd_status = megasas_finish_internal_command(cmd, req, resid); |
1737 | e8f943c3 | Hannes Reinecke | if (cmd_status == MFI_STAT_INVALID_STATUS) {
|
1738 | e8f943c3 | Hannes Reinecke | return;
|
1739 | e8f943c3 | Hannes Reinecke | } |
1740 | e8f943c3 | Hannes Reinecke | } else {
|
1741 | e8f943c3 | Hannes Reinecke | req->status = status; |
1742 | e8f943c3 | Hannes Reinecke | trace_megasas_scsi_complete(cmd->index, req->status, |
1743 | e8f943c3 | Hannes Reinecke | cmd->iov_size, req->cmd.xfer); |
1744 | e8f943c3 | Hannes Reinecke | if (req->status != GOOD) {
|
1745 | e8f943c3 | Hannes Reinecke | cmd_status = MFI_STAT_SCSI_DONE_WITH_ERROR; |
1746 | e8f943c3 | Hannes Reinecke | } |
1747 | e8f943c3 | Hannes Reinecke | if (req->status == CHECK_CONDITION) {
|
1748 | e8f943c3 | Hannes Reinecke | megasas_copy_sense(cmd); |
1749 | e8f943c3 | Hannes Reinecke | } |
1750 | e8f943c3 | Hannes Reinecke | |
1751 | e8f943c3 | Hannes Reinecke | megasas_unmap_sgl(cmd); |
1752 | e8f943c3 | Hannes Reinecke | cmd->frame->header.scsi_status = req->status; |
1753 | e8f943c3 | Hannes Reinecke | scsi_req_unref(cmd->req); |
1754 | e8f943c3 | Hannes Reinecke | cmd->req = NULL;
|
1755 | e8f943c3 | Hannes Reinecke | } |
1756 | e8f943c3 | Hannes Reinecke | cmd->frame->header.cmd_status = cmd_status; |
1757 | e8f943c3 | Hannes Reinecke | megasas_complete_frame(cmd->state, cmd->context); |
1758 | e8f943c3 | Hannes Reinecke | } |
1759 | e8f943c3 | Hannes Reinecke | |
1760 | e8f943c3 | Hannes Reinecke | static void megasas_command_cancel(SCSIRequest *req) |
1761 | e8f943c3 | Hannes Reinecke | { |
1762 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd = req->hba_private; |
1763 | e8f943c3 | Hannes Reinecke | |
1764 | e8f943c3 | Hannes Reinecke | if (cmd) {
|
1765 | e8f943c3 | Hannes Reinecke | megasas_abort_command(cmd); |
1766 | e8f943c3 | Hannes Reinecke | } else {
|
1767 | e8f943c3 | Hannes Reinecke | scsi_req_unref(req); |
1768 | e8f943c3 | Hannes Reinecke | } |
1769 | e8f943c3 | Hannes Reinecke | } |
1770 | e8f943c3 | Hannes Reinecke | |
1771 | e8f943c3 | Hannes Reinecke | static int megasas_handle_abort(MegasasState *s, MegasasCmd *cmd) |
1772 | e8f943c3 | Hannes Reinecke | { |
1773 | e8f943c3 | Hannes Reinecke | uint64_t abort_ctx = le64_to_cpu(cmd->frame->abort.abort_context); |
1774 | a8170e5e | Avi Kivity | hwaddr abort_addr, addr_hi, addr_lo; |
1775 | e8f943c3 | Hannes Reinecke | MegasasCmd *abort_cmd; |
1776 | e8f943c3 | Hannes Reinecke | |
1777 | e8f943c3 | Hannes Reinecke | addr_hi = le32_to_cpu(cmd->frame->abort.abort_mfi_addr_hi); |
1778 | e8f943c3 | Hannes Reinecke | addr_lo = le32_to_cpu(cmd->frame->abort.abort_mfi_addr_lo); |
1779 | e8f943c3 | Hannes Reinecke | abort_addr = ((uint64_t)addr_hi << 32) | addr_lo;
|
1780 | e8f943c3 | Hannes Reinecke | |
1781 | e8f943c3 | Hannes Reinecke | abort_cmd = megasas_lookup_frame(s, abort_addr); |
1782 | e8f943c3 | Hannes Reinecke | if (!abort_cmd) {
|
1783 | e8f943c3 | Hannes Reinecke | trace_megasas_abort_no_cmd(cmd->index, abort_ctx); |
1784 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1785 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1786 | e8f943c3 | Hannes Reinecke | } |
1787 | e8f943c3 | Hannes Reinecke | if (!megasas_use_queue64(s)) {
|
1788 | e8f943c3 | Hannes Reinecke | abort_ctx &= (uint64_t)0xFFFFFFFF;
|
1789 | e8f943c3 | Hannes Reinecke | } |
1790 | e8f943c3 | Hannes Reinecke | if (abort_cmd->context != abort_ctx) {
|
1791 | e8f943c3 | Hannes Reinecke | trace_megasas_abort_invalid_context(cmd->index, abort_cmd->index, |
1792 | e8f943c3 | Hannes Reinecke | abort_cmd->context); |
1793 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1794 | e8f943c3 | Hannes Reinecke | return MFI_STAT_ABORT_NOT_POSSIBLE;
|
1795 | e8f943c3 | Hannes Reinecke | } |
1796 | e8f943c3 | Hannes Reinecke | trace_megasas_abort_frame(cmd->index, abort_cmd->index); |
1797 | e8f943c3 | Hannes Reinecke | megasas_abort_command(abort_cmd); |
1798 | e8f943c3 | Hannes Reinecke | if (!s->event_cmd || abort_cmd != s->event_cmd) {
|
1799 | e8f943c3 | Hannes Reinecke | s->event_cmd = NULL;
|
1800 | e8f943c3 | Hannes Reinecke | } |
1801 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1802 | e8f943c3 | Hannes Reinecke | return MFI_STAT_OK;
|
1803 | e8f943c3 | Hannes Reinecke | } |
1804 | e8f943c3 | Hannes Reinecke | |
1805 | e8f943c3 | Hannes Reinecke | static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr, |
1806 | e8f943c3 | Hannes Reinecke | uint32_t frame_count) |
1807 | e8f943c3 | Hannes Reinecke | { |
1808 | e8f943c3 | Hannes Reinecke | uint8_t frame_status = MFI_STAT_INVALID_CMD; |
1809 | e8f943c3 | Hannes Reinecke | uint64_t frame_context; |
1810 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd; |
1811 | e8f943c3 | Hannes Reinecke | |
1812 | e8f943c3 | Hannes Reinecke | /*
|
1813 | e8f943c3 | Hannes Reinecke | * Always read 64bit context, top bits will be
|
1814 | e8f943c3 | Hannes Reinecke | * masked out if required in megasas_enqueue_frame()
|
1815 | e8f943c3 | Hannes Reinecke | */
|
1816 | e8f943c3 | Hannes Reinecke | frame_context = megasas_frame_get_context(frame_addr); |
1817 | e8f943c3 | Hannes Reinecke | |
1818 | e8f943c3 | Hannes Reinecke | cmd = megasas_enqueue_frame(s, frame_addr, frame_context, frame_count); |
1819 | e8f943c3 | Hannes Reinecke | if (!cmd) {
|
1820 | e8f943c3 | Hannes Reinecke | /* reply queue full */
|
1821 | e8f943c3 | Hannes Reinecke | trace_megasas_frame_busy(frame_addr); |
1822 | e8f943c3 | Hannes Reinecke | megasas_frame_set_scsi_status(frame_addr, BUSY); |
1823 | e8f943c3 | Hannes Reinecke | megasas_frame_set_cmd_status(frame_addr, MFI_STAT_SCSI_DONE_WITH_ERROR); |
1824 | e8f943c3 | Hannes Reinecke | megasas_complete_frame(s, frame_context); |
1825 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1826 | e8f943c3 | Hannes Reinecke | return;
|
1827 | e8f943c3 | Hannes Reinecke | } |
1828 | e8f943c3 | Hannes Reinecke | switch (cmd->frame->header.frame_cmd) {
|
1829 | e8f943c3 | Hannes Reinecke | case MFI_CMD_INIT:
|
1830 | e8f943c3 | Hannes Reinecke | frame_status = megasas_init_firmware(s, cmd); |
1831 | e8f943c3 | Hannes Reinecke | break;
|
1832 | e8f943c3 | Hannes Reinecke | case MFI_CMD_DCMD:
|
1833 | e8f943c3 | Hannes Reinecke | frame_status = megasas_handle_dcmd(s, cmd); |
1834 | e8f943c3 | Hannes Reinecke | break;
|
1835 | e8f943c3 | Hannes Reinecke | case MFI_CMD_ABORT:
|
1836 | e8f943c3 | Hannes Reinecke | frame_status = megasas_handle_abort(s, cmd); |
1837 | e8f943c3 | Hannes Reinecke | break;
|
1838 | e8f943c3 | Hannes Reinecke | case MFI_CMD_PD_SCSI_IO:
|
1839 | e8f943c3 | Hannes Reinecke | frame_status = megasas_handle_scsi(s, cmd, 0);
|
1840 | e8f943c3 | Hannes Reinecke | break;
|
1841 | e8f943c3 | Hannes Reinecke | case MFI_CMD_LD_SCSI_IO:
|
1842 | e8f943c3 | Hannes Reinecke | frame_status = megasas_handle_scsi(s, cmd, 1);
|
1843 | e8f943c3 | Hannes Reinecke | break;
|
1844 | e8f943c3 | Hannes Reinecke | case MFI_CMD_LD_READ:
|
1845 | e8f943c3 | Hannes Reinecke | case MFI_CMD_LD_WRITE:
|
1846 | e8f943c3 | Hannes Reinecke | frame_status = megasas_handle_io(s, cmd); |
1847 | e8f943c3 | Hannes Reinecke | break;
|
1848 | e8f943c3 | Hannes Reinecke | default:
|
1849 | e8f943c3 | Hannes Reinecke | trace_megasas_unhandled_frame_cmd(cmd->index, |
1850 | e8f943c3 | Hannes Reinecke | cmd->frame->header.frame_cmd); |
1851 | e8f943c3 | Hannes Reinecke | s->event_count++; |
1852 | e8f943c3 | Hannes Reinecke | break;
|
1853 | e8f943c3 | Hannes Reinecke | } |
1854 | e8f943c3 | Hannes Reinecke | if (frame_status != MFI_STAT_INVALID_STATUS) {
|
1855 | e8f943c3 | Hannes Reinecke | if (cmd->frame) {
|
1856 | e8f943c3 | Hannes Reinecke | cmd->frame->header.cmd_status = frame_status; |
1857 | e8f943c3 | Hannes Reinecke | } else {
|
1858 | e8f943c3 | Hannes Reinecke | megasas_frame_set_cmd_status(frame_addr, frame_status); |
1859 | e8f943c3 | Hannes Reinecke | } |
1860 | e8f943c3 | Hannes Reinecke | megasas_complete_frame(s, cmd->context); |
1861 | e8f943c3 | Hannes Reinecke | } |
1862 | e8f943c3 | Hannes Reinecke | } |
1863 | e8f943c3 | Hannes Reinecke | |
1864 | a8170e5e | Avi Kivity | static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, |
1865 | e8f943c3 | Hannes Reinecke | unsigned size)
|
1866 | e8f943c3 | Hannes Reinecke | { |
1867 | e8f943c3 | Hannes Reinecke | MegasasState *s = opaque; |
1868 | e8f943c3 | Hannes Reinecke | uint32_t retval = 0;
|
1869 | e8f943c3 | Hannes Reinecke | |
1870 | e8f943c3 | Hannes Reinecke | switch (addr) {
|
1871 | e8f943c3 | Hannes Reinecke | case MFI_IDB:
|
1872 | e8f943c3 | Hannes Reinecke | retval = 0;
|
1873 | e8f943c3 | Hannes Reinecke | break;
|
1874 | e8f943c3 | Hannes Reinecke | case MFI_OMSG0:
|
1875 | e8f943c3 | Hannes Reinecke | case MFI_OSP0:
|
1876 | e8f943c3 | Hannes Reinecke | retval = (megasas_use_msix(s) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) |
|
1877 | e8f943c3 | Hannes Reinecke | (s->fw_state & MFI_FWSTATE_MASK) | |
1878 | e8f943c3 | Hannes Reinecke | ((s->fw_sge & 0xff) << 16) | |
1879 | e8f943c3 | Hannes Reinecke | (s->fw_cmds & 0xFFFF);
|
1880 | e8f943c3 | Hannes Reinecke | break;
|
1881 | e8f943c3 | Hannes Reinecke | case MFI_OSTS:
|
1882 | e8f943c3 | Hannes Reinecke | if (megasas_intr_enabled(s) && s->doorbell) {
|
1883 | e8f943c3 | Hannes Reinecke | retval = MFI_1078_RM | 1;
|
1884 | e8f943c3 | Hannes Reinecke | } |
1885 | e8f943c3 | Hannes Reinecke | break;
|
1886 | e8f943c3 | Hannes Reinecke | case MFI_OMSK:
|
1887 | e8f943c3 | Hannes Reinecke | retval = s->intr_mask; |
1888 | e8f943c3 | Hannes Reinecke | break;
|
1889 | e8f943c3 | Hannes Reinecke | case MFI_ODCR0:
|
1890 | e8f943c3 | Hannes Reinecke | retval = s->doorbell; |
1891 | e8f943c3 | Hannes Reinecke | break;
|
1892 | e8f943c3 | Hannes Reinecke | default:
|
1893 | e8f943c3 | Hannes Reinecke | trace_megasas_mmio_invalid_readl(addr); |
1894 | e8f943c3 | Hannes Reinecke | break;
|
1895 | e8f943c3 | Hannes Reinecke | } |
1896 | e8f943c3 | Hannes Reinecke | trace_megasas_mmio_readl(addr, retval); |
1897 | e8f943c3 | Hannes Reinecke | return retval;
|
1898 | e8f943c3 | Hannes Reinecke | } |
1899 | e8f943c3 | Hannes Reinecke | |
1900 | a8170e5e | Avi Kivity | static void megasas_mmio_write(void *opaque, hwaddr addr, |
1901 | e8f943c3 | Hannes Reinecke | uint64_t val, unsigned size)
|
1902 | e8f943c3 | Hannes Reinecke | { |
1903 | e8f943c3 | Hannes Reinecke | MegasasState *s = opaque; |
1904 | e8f943c3 | Hannes Reinecke | uint64_t frame_addr; |
1905 | e8f943c3 | Hannes Reinecke | uint32_t frame_count; |
1906 | e8f943c3 | Hannes Reinecke | int i;
|
1907 | e8f943c3 | Hannes Reinecke | |
1908 | e8f943c3 | Hannes Reinecke | trace_megasas_mmio_writel(addr, val); |
1909 | e8f943c3 | Hannes Reinecke | switch (addr) {
|
1910 | e8f943c3 | Hannes Reinecke | case MFI_IDB:
|
1911 | e8f943c3 | Hannes Reinecke | if (val & MFI_FWINIT_ABORT) {
|
1912 | e8f943c3 | Hannes Reinecke | /* Abort all pending cmds */
|
1913 | e8f943c3 | Hannes Reinecke | for (i = 0; i < s->fw_cmds; i++) { |
1914 | e8f943c3 | Hannes Reinecke | megasas_abort_command(&s->frames[i]); |
1915 | e8f943c3 | Hannes Reinecke | } |
1916 | e8f943c3 | Hannes Reinecke | } |
1917 | e8f943c3 | Hannes Reinecke | if (val & MFI_FWINIT_READY) {
|
1918 | e8f943c3 | Hannes Reinecke | /* move to FW READY */
|
1919 | e8f943c3 | Hannes Reinecke | megasas_soft_reset(s); |
1920 | e8f943c3 | Hannes Reinecke | } |
1921 | e8f943c3 | Hannes Reinecke | if (val & MFI_FWINIT_MFIMODE) {
|
1922 | e8f943c3 | Hannes Reinecke | /* discard MFIs */
|
1923 | e8f943c3 | Hannes Reinecke | } |
1924 | e8f943c3 | Hannes Reinecke | break;
|
1925 | e8f943c3 | Hannes Reinecke | case MFI_OMSK:
|
1926 | e8f943c3 | Hannes Reinecke | s->intr_mask = val; |
1927 | e8f943c3 | Hannes Reinecke | if (!megasas_intr_enabled(s) && !msix_enabled(&s->dev)) {
|
1928 | e8f943c3 | Hannes Reinecke | trace_megasas_irq_lower(); |
1929 | e8f943c3 | Hannes Reinecke | qemu_irq_lower(s->dev.irq[0]);
|
1930 | e8f943c3 | Hannes Reinecke | } |
1931 | e8f943c3 | Hannes Reinecke | if (megasas_intr_enabled(s)) {
|
1932 | e8f943c3 | Hannes Reinecke | trace_megasas_intr_enabled(); |
1933 | e8f943c3 | Hannes Reinecke | } else {
|
1934 | e8f943c3 | Hannes Reinecke | trace_megasas_intr_disabled(); |
1935 | e8f943c3 | Hannes Reinecke | } |
1936 | e8f943c3 | Hannes Reinecke | break;
|
1937 | e8f943c3 | Hannes Reinecke | case MFI_ODCR0:
|
1938 | e8f943c3 | Hannes Reinecke | s->doorbell = 0;
|
1939 | e8f943c3 | Hannes Reinecke | if (s->producer_pa && megasas_intr_enabled(s)) {
|
1940 | e8f943c3 | Hannes Reinecke | /* Update reply queue pointer */
|
1941 | e8f943c3 | Hannes Reinecke | trace_megasas_qf_update(s->reply_queue_head, s->busy); |
1942 | e8f943c3 | Hannes Reinecke | stl_le_phys(s->producer_pa, s->reply_queue_head); |
1943 | e8f943c3 | Hannes Reinecke | if (!msix_enabled(&s->dev)) {
|
1944 | e8f943c3 | Hannes Reinecke | trace_megasas_irq_lower(); |
1945 | e8f943c3 | Hannes Reinecke | qemu_irq_lower(s->dev.irq[0]);
|
1946 | e8f943c3 | Hannes Reinecke | } |
1947 | e8f943c3 | Hannes Reinecke | } |
1948 | e8f943c3 | Hannes Reinecke | break;
|
1949 | e8f943c3 | Hannes Reinecke | case MFI_IQPH:
|
1950 | e8f943c3 | Hannes Reinecke | /* Received high 32 bits of a 64 bit MFI frame address */
|
1951 | e8f943c3 | Hannes Reinecke | s->frame_hi = val; |
1952 | e8f943c3 | Hannes Reinecke | break;
|
1953 | e8f943c3 | Hannes Reinecke | case MFI_IQPL:
|
1954 | e8f943c3 | Hannes Reinecke | /* Received low 32 bits of a 64 bit MFI frame address */
|
1955 | e8f943c3 | Hannes Reinecke | case MFI_IQP:
|
1956 | e8f943c3 | Hannes Reinecke | /* Received 32 bit MFI frame address */
|
1957 | e8f943c3 | Hannes Reinecke | frame_addr = (val & ~0x1F);
|
1958 | e8f943c3 | Hannes Reinecke | /* Add possible 64 bit offset */
|
1959 | e8f943c3 | Hannes Reinecke | frame_addr |= ((uint64_t)s->frame_hi << 32);
|
1960 | e8f943c3 | Hannes Reinecke | s->frame_hi = 0;
|
1961 | e8f943c3 | Hannes Reinecke | frame_count = (val >> 1) & 0xF; |
1962 | e8f943c3 | Hannes Reinecke | megasas_handle_frame(s, frame_addr, frame_count); |
1963 | e8f943c3 | Hannes Reinecke | break;
|
1964 | e8f943c3 | Hannes Reinecke | default:
|
1965 | e8f943c3 | Hannes Reinecke | trace_megasas_mmio_invalid_writel(addr, val); |
1966 | e8f943c3 | Hannes Reinecke | break;
|
1967 | e8f943c3 | Hannes Reinecke | } |
1968 | e8f943c3 | Hannes Reinecke | } |
1969 | e8f943c3 | Hannes Reinecke | |
1970 | e8f943c3 | Hannes Reinecke | static const MemoryRegionOps megasas_mmio_ops = { |
1971 | e8f943c3 | Hannes Reinecke | .read = megasas_mmio_read, |
1972 | e8f943c3 | Hannes Reinecke | .write = megasas_mmio_write, |
1973 | e8f943c3 | Hannes Reinecke | .endianness = DEVICE_LITTLE_ENDIAN, |
1974 | e8f943c3 | Hannes Reinecke | .impl = { |
1975 | e8f943c3 | Hannes Reinecke | .min_access_size = 8,
|
1976 | e8f943c3 | Hannes Reinecke | .max_access_size = 8,
|
1977 | e8f943c3 | Hannes Reinecke | } |
1978 | e8f943c3 | Hannes Reinecke | }; |
1979 | e8f943c3 | Hannes Reinecke | |
1980 | a8170e5e | Avi Kivity | static uint64_t megasas_port_read(void *opaque, hwaddr addr, |
1981 | e8f943c3 | Hannes Reinecke | unsigned size)
|
1982 | e8f943c3 | Hannes Reinecke | { |
1983 | e8f943c3 | Hannes Reinecke | return megasas_mmio_read(opaque, addr & 0xff, size); |
1984 | e8f943c3 | Hannes Reinecke | } |
1985 | e8f943c3 | Hannes Reinecke | |
1986 | a8170e5e | Avi Kivity | static void megasas_port_write(void *opaque, hwaddr addr, |
1987 | e8f943c3 | Hannes Reinecke | uint64_t val, unsigned size)
|
1988 | e8f943c3 | Hannes Reinecke | { |
1989 | e8f943c3 | Hannes Reinecke | megasas_mmio_write(opaque, addr & 0xff, val, size);
|
1990 | e8f943c3 | Hannes Reinecke | } |
1991 | e8f943c3 | Hannes Reinecke | |
1992 | e8f943c3 | Hannes Reinecke | static const MemoryRegionOps megasas_port_ops = { |
1993 | e8f943c3 | Hannes Reinecke | .read = megasas_port_read, |
1994 | e8f943c3 | Hannes Reinecke | .write = megasas_port_write, |
1995 | e8f943c3 | Hannes Reinecke | .endianness = DEVICE_LITTLE_ENDIAN, |
1996 | e8f943c3 | Hannes Reinecke | .impl = { |
1997 | e8f943c3 | Hannes Reinecke | .min_access_size = 4,
|
1998 | e8f943c3 | Hannes Reinecke | .max_access_size = 4,
|
1999 | e8f943c3 | Hannes Reinecke | } |
2000 | e8f943c3 | Hannes Reinecke | }; |
2001 | e8f943c3 | Hannes Reinecke | |
2002 | a8170e5e | Avi Kivity | static uint64_t megasas_queue_read(void *opaque, hwaddr addr, |
2003 | e8f943c3 | Hannes Reinecke | unsigned size)
|
2004 | e8f943c3 | Hannes Reinecke | { |
2005 | e8f943c3 | Hannes Reinecke | return 0; |
2006 | e8f943c3 | Hannes Reinecke | } |
2007 | e8f943c3 | Hannes Reinecke | |
2008 | e8f943c3 | Hannes Reinecke | static const MemoryRegionOps megasas_queue_ops = { |
2009 | e8f943c3 | Hannes Reinecke | .read = megasas_queue_read, |
2010 | e8f943c3 | Hannes Reinecke | .endianness = DEVICE_LITTLE_ENDIAN, |
2011 | e8f943c3 | Hannes Reinecke | .impl = { |
2012 | e8f943c3 | Hannes Reinecke | .min_access_size = 8,
|
2013 | e8f943c3 | Hannes Reinecke | .max_access_size = 8,
|
2014 | e8f943c3 | Hannes Reinecke | } |
2015 | e8f943c3 | Hannes Reinecke | }; |
2016 | e8f943c3 | Hannes Reinecke | |
2017 | e8f943c3 | Hannes Reinecke | static void megasas_soft_reset(MegasasState *s) |
2018 | e8f943c3 | Hannes Reinecke | { |
2019 | e8f943c3 | Hannes Reinecke | int i;
|
2020 | e8f943c3 | Hannes Reinecke | MegasasCmd *cmd; |
2021 | e8f943c3 | Hannes Reinecke | |
2022 | e8f943c3 | Hannes Reinecke | trace_megasas_reset(); |
2023 | e8f943c3 | Hannes Reinecke | for (i = 0; i < s->fw_cmds; i++) { |
2024 | e8f943c3 | Hannes Reinecke | cmd = &s->frames[i]; |
2025 | e8f943c3 | Hannes Reinecke | megasas_abort_command(cmd); |
2026 | e8f943c3 | Hannes Reinecke | } |
2027 | e8f943c3 | Hannes Reinecke | megasas_reset_frames(s); |
2028 | e8f943c3 | Hannes Reinecke | s->reply_queue_len = s->fw_cmds; |
2029 | e8f943c3 | Hannes Reinecke | s->reply_queue_pa = 0;
|
2030 | e8f943c3 | Hannes Reinecke | s->consumer_pa = 0;
|
2031 | e8f943c3 | Hannes Reinecke | s->producer_pa = 0;
|
2032 | e8f943c3 | Hannes Reinecke | s->fw_state = MFI_FWSTATE_READY; |
2033 | e8f943c3 | Hannes Reinecke | s->doorbell = 0;
|
2034 | e8f943c3 | Hannes Reinecke | s->intr_mask = MEGASAS_INTR_DISABLED_MASK; |
2035 | e8f943c3 | Hannes Reinecke | s->frame_hi = 0;
|
2036 | e8f943c3 | Hannes Reinecke | s->flags &= ~MEGASAS_MASK_USE_QUEUE64; |
2037 | e8f943c3 | Hannes Reinecke | s->event_count++; |
2038 | e8f943c3 | Hannes Reinecke | s->boot_event = s->event_count; |
2039 | e8f943c3 | Hannes Reinecke | } |
2040 | e8f943c3 | Hannes Reinecke | |
2041 | e8f943c3 | Hannes Reinecke | static void megasas_scsi_reset(DeviceState *dev) |
2042 | e8f943c3 | Hannes Reinecke | { |
2043 | e8f943c3 | Hannes Reinecke | MegasasState *s = DO_UPCAST(MegasasState, dev.qdev, dev); |
2044 | e8f943c3 | Hannes Reinecke | |
2045 | e8f943c3 | Hannes Reinecke | megasas_soft_reset(s); |
2046 | e8f943c3 | Hannes Reinecke | } |
2047 | e8f943c3 | Hannes Reinecke | |
2048 | e8f943c3 | Hannes Reinecke | static const VMStateDescription vmstate_megasas = { |
2049 | e8f943c3 | Hannes Reinecke | .name = "megasas",
|
2050 | e8f943c3 | Hannes Reinecke | .version_id = 0,
|
2051 | e8f943c3 | Hannes Reinecke | .minimum_version_id = 0,
|
2052 | e8f943c3 | Hannes Reinecke | .minimum_version_id_old = 0,
|
2053 | e8f943c3 | Hannes Reinecke | .fields = (VMStateField[]) { |
2054 | e8f943c3 | Hannes Reinecke | VMSTATE_PCI_DEVICE(dev, MegasasState), |
2055 | e8f943c3 | Hannes Reinecke | |
2056 | e8f943c3 | Hannes Reinecke | VMSTATE_INT32(fw_state, MegasasState), |
2057 | e8f943c3 | Hannes Reinecke | VMSTATE_INT32(intr_mask, MegasasState), |
2058 | e8f943c3 | Hannes Reinecke | VMSTATE_INT32(doorbell, MegasasState), |
2059 | e8f943c3 | Hannes Reinecke | VMSTATE_UINT64(reply_queue_pa, MegasasState), |
2060 | e8f943c3 | Hannes Reinecke | VMSTATE_UINT64(consumer_pa, MegasasState), |
2061 | e8f943c3 | Hannes Reinecke | VMSTATE_UINT64(producer_pa, MegasasState), |
2062 | e8f943c3 | Hannes Reinecke | VMSTATE_END_OF_LIST() |
2063 | e8f943c3 | Hannes Reinecke | } |
2064 | e8f943c3 | Hannes Reinecke | }; |
2065 | e8f943c3 | Hannes Reinecke | |
2066 | 18fc611b | Stefan Weil | static void megasas_scsi_uninit(PCIDevice *d) |
2067 | e8f943c3 | Hannes Reinecke | { |
2068 | e8f943c3 | Hannes Reinecke | MegasasState *s = DO_UPCAST(MegasasState, dev, d); |
2069 | e8f943c3 | Hannes Reinecke | |
2070 | e8f943c3 | Hannes Reinecke | #ifdef USE_MSIX
|
2071 | e8f943c3 | Hannes Reinecke | msix_uninit(&s->dev, &s->mmio_io); |
2072 | e8f943c3 | Hannes Reinecke | #endif
|
2073 | e8f943c3 | Hannes Reinecke | memory_region_destroy(&s->mmio_io); |
2074 | e8f943c3 | Hannes Reinecke | memory_region_destroy(&s->port_io); |
2075 | e8f943c3 | Hannes Reinecke | memory_region_destroy(&s->queue_io); |
2076 | e8f943c3 | Hannes Reinecke | } |
2077 | e8f943c3 | Hannes Reinecke | |
2078 | e8f943c3 | Hannes Reinecke | static const struct SCSIBusInfo megasas_scsi_info = { |
2079 | e8f943c3 | Hannes Reinecke | .tcq = true,
|
2080 | e8f943c3 | Hannes Reinecke | .max_target = MFI_MAX_LD, |
2081 | e8f943c3 | Hannes Reinecke | .max_lun = 255,
|
2082 | e8f943c3 | Hannes Reinecke | |
2083 | e8f943c3 | Hannes Reinecke | .transfer_data = megasas_xfer_complete, |
2084 | e8f943c3 | Hannes Reinecke | .get_sg_list = megasas_get_sg_list, |
2085 | e8f943c3 | Hannes Reinecke | .complete = megasas_command_complete, |
2086 | e8f943c3 | Hannes Reinecke | .cancel = megasas_command_cancel, |
2087 | e8f943c3 | Hannes Reinecke | }; |
2088 | e8f943c3 | Hannes Reinecke | |
2089 | e8f943c3 | Hannes Reinecke | static int megasas_scsi_init(PCIDevice *dev) |
2090 | e8f943c3 | Hannes Reinecke | { |
2091 | e8f943c3 | Hannes Reinecke | MegasasState *s = DO_UPCAST(MegasasState, dev, dev); |
2092 | e8f943c3 | Hannes Reinecke | uint8_t *pci_conf; |
2093 | e8f943c3 | Hannes Reinecke | int i, bar_type;
|
2094 | e8f943c3 | Hannes Reinecke | |
2095 | e8f943c3 | Hannes Reinecke | pci_conf = s->dev.config; |
2096 | e8f943c3 | Hannes Reinecke | |
2097 | e8f943c3 | Hannes Reinecke | /* PCI latency timer = 0 */
|
2098 | e8f943c3 | Hannes Reinecke | pci_conf[PCI_LATENCY_TIMER] = 0;
|
2099 | e8f943c3 | Hannes Reinecke | /* Interrupt pin 1 */
|
2100 | e8f943c3 | Hannes Reinecke | pci_conf[PCI_INTERRUPT_PIN] = 0x01;
|
2101 | e8f943c3 | Hannes Reinecke | |
2102 | e8f943c3 | Hannes Reinecke | memory_region_init_io(&s->mmio_io, &megasas_mmio_ops, s, |
2103 | e8f943c3 | Hannes Reinecke | "megasas-mmio", 0x4000); |
2104 | e8f943c3 | Hannes Reinecke | memory_region_init_io(&s->port_io, &megasas_port_ops, s, |
2105 | e8f943c3 | Hannes Reinecke | "megasas-io", 256); |
2106 | e8f943c3 | Hannes Reinecke | memory_region_init_io(&s->queue_io, &megasas_queue_ops, s, |
2107 | e8f943c3 | Hannes Reinecke | "megasas-queue", 0x40000); |
2108 | e8f943c3 | Hannes Reinecke | |
2109 | e8f943c3 | Hannes Reinecke | #ifdef USE_MSIX
|
2110 | e8f943c3 | Hannes Reinecke | /* MSI-X support is currently broken */
|
2111 | e8f943c3 | Hannes Reinecke | if (megasas_use_msix(s) &&
|
2112 | e8f943c3 | Hannes Reinecke | msix_init(&s->dev, 15, &s->mmio_io, 0, 0x2000)) { |
2113 | e8f943c3 | Hannes Reinecke | s->flags &= ~MEGASAS_MASK_USE_MSIX; |
2114 | e8f943c3 | Hannes Reinecke | } |
2115 | e8f943c3 | Hannes Reinecke | #else
|
2116 | e8f943c3 | Hannes Reinecke | s->flags &= ~MEGASAS_MASK_USE_MSIX; |
2117 | e8f943c3 | Hannes Reinecke | #endif
|
2118 | e8f943c3 | Hannes Reinecke | |
2119 | e8f943c3 | Hannes Reinecke | bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64; |
2120 | e8f943c3 | Hannes Reinecke | pci_register_bar(&s->dev, 0, bar_type, &s->mmio_io);
|
2121 | e8f943c3 | Hannes Reinecke | pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
|
2122 | e8f943c3 | Hannes Reinecke | pci_register_bar(&s->dev, 3, bar_type, &s->queue_io);
|
2123 | e8f943c3 | Hannes Reinecke | |
2124 | e8f943c3 | Hannes Reinecke | if (megasas_use_msix(s)) {
|
2125 | e8f943c3 | Hannes Reinecke | msix_vector_use(&s->dev, 0);
|
2126 | e8f943c3 | Hannes Reinecke | } |
2127 | e8f943c3 | Hannes Reinecke | |
2128 | 76b523db | Hannes Reinecke | if (!s->sas_addr) {
|
2129 | 76b523db | Hannes Reinecke | s->sas_addr = ((NAA_LOCALLY_ASSIGNED_ID << 24) |
|
2130 | 76b523db | Hannes Reinecke | IEEE_COMPANY_LOCALLY_ASSIGNED) << 36;
|
2131 | 76b523db | Hannes Reinecke | s->sas_addr |= (pci_bus_num(dev->bus) << 16);
|
2132 | 76b523db | Hannes Reinecke | s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
|
2133 | 76b523db | Hannes Reinecke | s->sas_addr |= PCI_FUNC(dev->devfn); |
2134 | 76b523db | Hannes Reinecke | } |
2135 | fb654157 | Hannes Reinecke | if (!s->hba_serial) {
|
2136 | fb654157 | Hannes Reinecke | s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL); |
2137 | fb654157 | Hannes Reinecke | } |
2138 | e8f943c3 | Hannes Reinecke | if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
|
2139 | e8f943c3 | Hannes Reinecke | s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE; |
2140 | e8f943c3 | Hannes Reinecke | } else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) { |
2141 | e8f943c3 | Hannes Reinecke | s->fw_sge = 128 - MFI_PASS_FRAME_SIZE;
|
2142 | e8f943c3 | Hannes Reinecke | } else {
|
2143 | e8f943c3 | Hannes Reinecke | s->fw_sge = 64 - MFI_PASS_FRAME_SIZE;
|
2144 | e8f943c3 | Hannes Reinecke | } |
2145 | e8f943c3 | Hannes Reinecke | if (s->fw_cmds > MEGASAS_MAX_FRAMES) {
|
2146 | e8f943c3 | Hannes Reinecke | s->fw_cmds = MEGASAS_MAX_FRAMES; |
2147 | e8f943c3 | Hannes Reinecke | } |
2148 | e8f943c3 | Hannes Reinecke | trace_megasas_init(s->fw_sge, s->fw_cmds, |
2149 | e8f943c3 | Hannes Reinecke | megasas_use_msix(s) ? "MSI-X" : "INTx", |
2150 | e8f943c3 | Hannes Reinecke | megasas_is_jbod(s) ? "jbod" : "raid"); |
2151 | e8f943c3 | Hannes Reinecke | s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ? |
2152 | e8f943c3 | Hannes Reinecke | MAX_SCSI_DEVS : MFI_MAX_LD; |
2153 | e8f943c3 | Hannes Reinecke | s->producer_pa = 0;
|
2154 | e8f943c3 | Hannes Reinecke | s->consumer_pa = 0;
|
2155 | e8f943c3 | Hannes Reinecke | for (i = 0; i < s->fw_cmds; i++) { |
2156 | e8f943c3 | Hannes Reinecke | s->frames[i].index = i; |
2157 | e8f943c3 | Hannes Reinecke | s->frames[i].context = -1;
|
2158 | e8f943c3 | Hannes Reinecke | s->frames[i].pa = 0;
|
2159 | e8f943c3 | Hannes Reinecke | s->frames[i].state = s; |
2160 | e8f943c3 | Hannes Reinecke | } |
2161 | e8f943c3 | Hannes Reinecke | |
2162 | e8f943c3 | Hannes Reinecke | scsi_bus_new(&s->bus, &dev->qdev, &megasas_scsi_info); |
2163 | e8f943c3 | Hannes Reinecke | scsi_bus_legacy_handle_cmdline(&s->bus); |
2164 | e8f943c3 | Hannes Reinecke | return 0; |
2165 | e8f943c3 | Hannes Reinecke | } |
2166 | e8f943c3 | Hannes Reinecke | |
2167 | e8f943c3 | Hannes Reinecke | static Property megasas_properties[] = {
|
2168 | e8f943c3 | Hannes Reinecke | DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
|
2169 | e8f943c3 | Hannes Reinecke | MEGASAS_DEFAULT_SGE), |
2170 | e8f943c3 | Hannes Reinecke | DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
|
2171 | e8f943c3 | Hannes Reinecke | MEGASAS_DEFAULT_FRAMES), |
2172 | fb654157 | Hannes Reinecke | DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
|
2173 | 76b523db | Hannes Reinecke | DEFINE_PROP_HEX64("sas_address", MegasasState, sas_addr, 0), |
2174 | e8f943c3 | Hannes Reinecke | #ifdef USE_MSIX
|
2175 | e8f943c3 | Hannes Reinecke | DEFINE_PROP_BIT("use_msix", MegasasState, flags,
|
2176 | e8f943c3 | Hannes Reinecke | MEGASAS_FLAG_USE_MSIX, false),
|
2177 | e8f943c3 | Hannes Reinecke | #endif
|
2178 | e8f943c3 | Hannes Reinecke | DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
|
2179 | e8f943c3 | Hannes Reinecke | MEGASAS_FLAG_USE_JBOD, false),
|
2180 | e8f943c3 | Hannes Reinecke | DEFINE_PROP_END_OF_LIST(), |
2181 | e8f943c3 | Hannes Reinecke | }; |
2182 | e8f943c3 | Hannes Reinecke | |
2183 | e8f943c3 | Hannes Reinecke | static void megasas_class_init(ObjectClass *oc, void *data) |
2184 | e8f943c3 | Hannes Reinecke | { |
2185 | e8f943c3 | Hannes Reinecke | DeviceClass *dc = DEVICE_CLASS(oc); |
2186 | e8f943c3 | Hannes Reinecke | PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); |
2187 | e8f943c3 | Hannes Reinecke | |
2188 | e8f943c3 | Hannes Reinecke | pc->init = megasas_scsi_init; |
2189 | e8f943c3 | Hannes Reinecke | pc->exit = megasas_scsi_uninit; |
2190 | e8f943c3 | Hannes Reinecke | pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC; |
2191 | e8f943c3 | Hannes Reinecke | pc->device_id = PCI_DEVICE_ID_LSI_SAS1078; |
2192 | e8f943c3 | Hannes Reinecke | pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC; |
2193 | e8f943c3 | Hannes Reinecke | pc->subsystem_id = 0x1013;
|
2194 | e8f943c3 | Hannes Reinecke | pc->class_id = PCI_CLASS_STORAGE_RAID; |
2195 | e8f943c3 | Hannes Reinecke | dc->props = megasas_properties; |
2196 | e8f943c3 | Hannes Reinecke | dc->reset = megasas_scsi_reset; |
2197 | e8f943c3 | Hannes Reinecke | dc->vmsd = &vmstate_megasas; |
2198 | e8f943c3 | Hannes Reinecke | dc->desc = "LSI MegaRAID SAS 1078";
|
2199 | e8f943c3 | Hannes Reinecke | } |
2200 | e8f943c3 | Hannes Reinecke | |
2201 | e8f943c3 | Hannes Reinecke | static const TypeInfo megasas_info = { |
2202 | e8f943c3 | Hannes Reinecke | .name = "megasas",
|
2203 | e8f943c3 | Hannes Reinecke | .parent = TYPE_PCI_DEVICE, |
2204 | e8f943c3 | Hannes Reinecke | .instance_size = sizeof(MegasasState),
|
2205 | e8f943c3 | Hannes Reinecke | .class_init = megasas_class_init, |
2206 | e8f943c3 | Hannes Reinecke | }; |
2207 | e8f943c3 | Hannes Reinecke | |
2208 | e8f943c3 | Hannes Reinecke | static void megasas_register_types(void) |
2209 | e8f943c3 | Hannes Reinecke | { |
2210 | e8f943c3 | Hannes Reinecke | type_register_static(&megasas_info); |
2211 | e8f943c3 | Hannes Reinecke | } |
2212 | e8f943c3 | Hannes Reinecke | |
2213 | e8f943c3 | Hannes Reinecke | type_init(megasas_register_types) |