1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
|
/*-
* Copyright (c) 2009 Yahoo! Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _MPSVAR_H
#define _MPSVAR_H
#define MPS_DB_MAX_WAIT 2500
#define MPS_REQ_FRAMES 1024
#define MPS_EVT_REPLY_FRAMES 32
#define MPS_REPLY_FRAMES MPS_REQ_FRAMES
#define MPS_CHAIN_FRAMES 2048
#define MPS_SENSE_LEN SSD_FULL_SIZE
#define MPS_MSI_COUNT 1
#define MPS_SGE64_SIZE 12
#define MPS_SGE32_SIZE 8
#define MPS_SGC_SIZE 8
#define MPS_PERIODIC_DELAY 1 /* 1 second heartbeat/watchdog check */
struct mps_softc;
struct mps_command;
struct mpssas_softc;
struct mpssas_target;
MALLOC_DECLARE(M_MPT2);
typedef void mps_evt_callback_t(struct mps_softc *, uintptr_t,
MPI2_EVENT_NOTIFICATION_REPLY *reply);
typedef void mps_command_callback_t(struct mps_softc *, struct mps_command *cm);
struct mps_chain {
TAILQ_ENTRY(mps_chain) chain_link;
MPI2_SGE_IO_UNION *chain;
uint32_t chain_busaddr;
};
/*
* This needs to be at least 2 to support SMP passthrough.
*/
#define MPS_IOVEC_COUNT 2
struct mps_command {
TAILQ_ENTRY(mps_command) cm_link;
struct mps_softc *cm_sc;
void *cm_data;
u_int cm_length;
struct uio cm_uio;
struct iovec cm_iovec[MPS_IOVEC_COUNT];
u_int cm_max_segs;
u_int cm_sglsize;
MPI2_SGE_IO_UNION *cm_sge;
uint8_t *cm_req;
uint8_t *cm_reply;
uint32_t cm_reply_data;
mps_command_callback_t *cm_complete;
void *cm_complete_data;
struct mpssas_target *cm_targ;
MPI2_REQUEST_DESCRIPTOR_UNION cm_desc;
u_int cm_flags;
#define MPS_CM_FLAGS_POLLED (1 << 0)
#define MPS_CM_FLAGS_COMPLETE (1 << 1)
#define MPS_CM_FLAGS_SGE_SIMPLE (1 << 2)
#define MPS_CM_FLAGS_DATAOUT (1 << 3)
#define MPS_CM_FLAGS_DATAIN (1 << 4)
#define MPS_CM_FLAGS_WAKEUP (1 << 5)
#define MPS_CM_FLAGS_ACTIVE (1 << 6)
#define MPS_CM_FLAGS_USE_UIO (1 << 7)
#define MPS_CM_FLAGS_SMP_PASS (1 << 8)
#define MPS_CM_FLAGS_CHAIN_FAILED (1 << 9)
#define MPS_CM_FLAGS_ERROR_MASK MPS_CM_FLAGS_CHAIN_FAILED
u_int cm_state;
#define MPS_CM_STATE_FREE 0
#define MPS_CM_STATE_BUSY 1
#define MPS_CM_STATE_TIMEDOUT 2
bus_dmamap_t cm_dmamap;
struct scsi_sense_data *cm_sense;
TAILQ_HEAD(, mps_chain) cm_chain_list;
uint32_t cm_req_busaddr;
uint32_t cm_sense_busaddr;
struct callout cm_callout;
};
struct mps_event_handle {
TAILQ_ENTRY(mps_event_handle) eh_list;
mps_evt_callback_t *callback;
void *data;
uint8_t mask[16];
};
struct mps_softc {
device_t mps_dev;
struct cdev *mps_cdev;
u_int mps_flags;
#define MPS_FLAGS_INTX (1 << 0)
#define MPS_FLAGS_MSI (1 << 1)
#define MPS_FLAGS_BUSY (1 << 2)
#define MPS_FLAGS_SHUTDOWN (1 << 3)
#define MPS_FLAGS_ATTACH_DONE (1 << 4)
u_int mps_debug;
u_int allow_multiple_tm_cmds;
int tm_cmds_active;
int io_cmds_active;
int io_cmds_highwater;
int chain_free;
int chain_free_lowwater;
uint64_t chain_alloc_fail;
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
struct mps_command *commands;
struct mps_chain *chains;
struct callout periodic;
struct mpssas_softc *sassc;
TAILQ_HEAD(, mps_command) req_list;
TAILQ_HEAD(, mps_chain) chain_list;
TAILQ_HEAD(, mps_command) tm_list;
TAILQ_HEAD(, mps_command) io_list;
int replypostindex;
int replyfreeindex;
struct resource *mps_regs_resource;
bus_space_handle_t mps_bhandle;
bus_space_tag_t mps_btag;
int mps_regs_rid;
bus_dma_tag_t mps_parent_dmat;
bus_dma_tag_t buffer_dmat;
MPI2_IOC_FACTS_REPLY *facts;
MPI2_PORT_FACTS_REPLY *pfacts;
int num_reqs;
int num_replies;
int fqdepth; /* Free queue */
int pqdepth; /* Post queue */
uint8_t event_mask[16];
TAILQ_HEAD(, mps_event_handle) event_list;
struct mps_event_handle *mps_log_eh;
struct mtx mps_mtx;
struct intr_config_hook mps_ich;
struct resource *mps_irq[MPS_MSI_COUNT];
void *mps_intrhand[MPS_MSI_COUNT];
int mps_irq_rid[MPS_MSI_COUNT];
uint8_t *req_frames;
bus_addr_t req_busaddr;
bus_dma_tag_t req_dmat;
bus_dmamap_t req_map;
uint8_t *reply_frames;
bus_addr_t reply_busaddr;
bus_dma_tag_t reply_dmat;
bus_dmamap_t reply_map;
struct scsi_sense_data *sense_frames;
bus_addr_t sense_busaddr;
bus_dma_tag_t sense_dmat;
bus_dmamap_t sense_map;
uint8_t *chain_frames;
bus_addr_t chain_busaddr;
bus_dma_tag_t chain_dmat;
bus_dmamap_t chain_map;
MPI2_REPLY_DESCRIPTORS_UNION *post_queue;
bus_addr_t post_busaddr;
uint32_t *free_queue;
bus_addr_t free_busaddr;
bus_dma_tag_t queues_dmat;
bus_dmamap_t queues_map;
};
struct mps_config_params {
MPI2_CONFIG_EXT_PAGE_HEADER_UNION hdr;
u_int action;
u_int page_address; /* Attributes, not a phys address */
u_int status;
void *buffer;
u_int length;
int timeout;
void (*callback)(struct mps_softc *, struct mps_config_params *);
void *cbdata;
};
static __inline uint32_t
mps_regread(struct mps_softc *sc, uint32_t offset)
{
return (bus_space_read_4(sc->mps_btag, sc->mps_bhandle, offset));
}
static __inline void
mps_regwrite(struct mps_softc *sc, uint32_t offset, uint32_t val)
{
bus_space_write_4(sc->mps_btag, sc->mps_bhandle, offset, val);
}
static __inline void
mps_free_reply(struct mps_softc *sc, uint32_t busaddr)
{
if (++sc->replyfreeindex >= sc->fqdepth)
sc->replyfreeindex = 0;
sc->free_queue[sc->replyfreeindex] = busaddr;
mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
}
static __inline struct mps_chain *
mps_alloc_chain(struct mps_softc *sc)
{
struct mps_chain *chain;
if ((chain = TAILQ_FIRST(&sc->chain_list)) != NULL) {
TAILQ_REMOVE(&sc->chain_list, chain, chain_link);
sc->chain_free--;
if (sc->chain_free < sc->chain_free_lowwater)
sc->chain_free_lowwater = sc->chain_free;
} else
sc->chain_alloc_fail++;
return (chain);
}
static __inline void
mps_free_chain(struct mps_softc *sc, struct mps_chain *chain)
{
#if 0
bzero(chain->chain, 128);
#endif
sc->chain_free++;
TAILQ_INSERT_TAIL(&sc->chain_list, chain, chain_link);
}
static __inline void
mps_free_command(struct mps_softc *sc, struct mps_command *cm)
{
struct mps_chain *chain, *chain_temp;
if (cm->cm_reply != NULL) {
mps_free_reply(sc, cm->cm_reply_data);
cm->cm_reply = NULL;
}
cm->cm_flags = 0;
cm->cm_complete = NULL;
cm->cm_complete_data = NULL;
cm->cm_targ = 0;
cm->cm_max_segs = 0;
cm->cm_state = MPS_CM_STATE_FREE;
TAILQ_FOREACH_SAFE(chain, &cm->cm_chain_list, chain_link, chain_temp) {
TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link);
mps_free_chain(sc, chain);
}
TAILQ_INSERT_TAIL(&sc->req_list, cm, cm_link);
}
static __inline struct mps_command *
mps_alloc_command(struct mps_softc *sc)
{
struct mps_command *cm;
cm = TAILQ_FIRST(&sc->req_list);
if (cm == NULL)
return (NULL);
TAILQ_REMOVE(&sc->req_list, cm, cm_link);
KASSERT(cm->cm_state == MPS_CM_STATE_FREE, ("mps: Allocating busy command\n"));
cm->cm_state = MPS_CM_STATE_BUSY;
return (cm);
}
static __inline void
mps_lock(struct mps_softc *sc)
{
mtx_lock(&sc->mps_mtx);
}
static __inline void
mps_unlock(struct mps_softc *sc)
{
mtx_unlock(&sc->mps_mtx);
}
#define MPS_INFO (1 << 0)
#define MPS_TRACE (1 << 1)
#define MPS_FAULT (1 << 2)
#define MPS_EVENT (1 << 3)
#define MPS_LOG (1 << 4)
#define mps_printf(sc, args...) \
device_printf((sc)->mps_dev, ##args)
#define mps_dprint(sc, level, msg, args...) \
do { \
if (sc->mps_debug & level) \
device_printf(sc->mps_dev, msg, ##args); \
} while (0)
#define mps_dprint_field(sc, level, msg, args...) \
do { \
if (sc->mps_debug & level) \
printf("\t" msg, ##args); \
} while (0)
#define MPS_PRINTFIELD_START(sc, tag...) \
mps_dprint((sc), MPS_INFO, ##tag); \
mps_dprint_field((sc), MPS_INFO, ":\n")
#define MPS_PRINTFIELD_END(sc, tag) \
mps_dprint((sc), MPS_INFO, tag "\n")
#define MPS_PRINTFIELD(sc, facts, attr, fmt) \
mps_dprint_field((sc), MPS_INFO, #attr ": " #fmt "\n", (facts)->attr)
#define MPS_EVENTFIELD_START(sc, tag...) \
mps_dprint((sc), MPS_EVENT, ##tag); \
mps_dprint_field((sc), MPS_EVENT, ":\n")
#define MPS_EVENTFIELD(sc, facts, attr, fmt) \
mps_dprint_field((sc), MPS_EVENT, #attr ": " #fmt "\n", (facts)->attr)
static __inline void
mps_from_u64(uint64_t data, U64 *mps)
{
(mps)->High = (uint32_t)((data) >> 32);
(mps)->Low = (uint32_t)((data) & 0xffffffff);
}
static __inline uint64_t
mps_to_u64(U64 *data)
{
return (((uint64_t)data->High << 32) | data->Low);
}
static __inline void
mps_mask_intr(struct mps_softc *sc)
{
uint32_t mask;
mask = mps_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
mask |= MPI2_HIM_REPLY_INT_MASK;
mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
}
static __inline void
mps_unmask_intr(struct mps_softc *sc)
{
uint32_t mask;
mask = mps_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
mask &= ~MPI2_HIM_REPLY_INT_MASK;
mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
}
int mps_pci_setup_interrupts(struct mps_softc *);
int mps_attach(struct mps_softc *sc);
int mps_free(struct mps_softc *sc);
void mps_intr(void *);
void mps_intr_msi(void *);
void mps_intr_locked(void *);
int mps_register_events(struct mps_softc *, uint8_t *, mps_evt_callback_t *,
void *, struct mps_event_handle **);
int mps_update_events(struct mps_softc *, struct mps_event_handle *, uint8_t *);
int mps_deregister_events(struct mps_softc *, struct mps_event_handle *);
int mps_request_polled(struct mps_softc *sc, struct mps_command *cm);
void mps_enqueue_request(struct mps_softc *, struct mps_command *);
int mps_push_sge(struct mps_command *, void *, size_t, int);
int mps_add_dmaseg(struct mps_command *, vm_paddr_t, size_t, u_int, int);
int mps_attach_sas(struct mps_softc *sc);
int mps_detach_sas(struct mps_softc *sc);
int mps_map_command(struct mps_softc *sc, struct mps_command *cm);
int mps_read_config_page(struct mps_softc *, struct mps_config_params *);
int mps_write_config_page(struct mps_softc *, struct mps_config_params *);
void mps_memaddr_cb(void *, bus_dma_segment_t *, int , int );
void mpi_init_sge(struct mps_command *cm, void *req, void *sge);
int mps_attach_user(struct mps_softc *);
void mps_detach_user(struct mps_softc *);
SYSCTL_DECL(_hw_mps);
#endif
|