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
|
/*
* Copyright (c) 2004-05 Applied Micro Circuits Corporation.
* Copyright (c) 2004-05 Vinod Kashyap.
* 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$
*/
/*
* AMCC'S 3ware driver for 9000 series storage controllers.
*
* Author: Vinod Kashyap
*/
#ifndef TW_OSL_H
#define TW_OSL_H
/*
* OS Layer internal macros, structures and functions.
*/
#define TW_OSLI_DEVICE_NAME "3ware 9000 series Storage Controller"
#define TW_OSLI_MALLOC_CLASS M_TWA
#define TW_OSLI_MAX_NUM_IOS TW_CL_MAX_SIMULTANEOUS_REQUESTS
#define TW_OSLI_MAX_NUM_AENS 0x100
/* Possible values of req->state. */
#define TW_OSLI_REQ_STATE_INIT 0x0 /* being initialized */
#define TW_OSLI_REQ_STATE_BUSY 0x1 /* submitted to CL */
#define TW_OSLI_REQ_STATE_PENDING 0x2 /* in pending queue */
#define TW_OSLI_REQ_STATE_COMPLETE 0x3 /* completed by CL */
/* Possible values of req->flags. */
#define TW_OSLI_REQ_FLAGS_DATA_IN (1<<0) /* read request */
#define TW_OSLI_REQ_FLAGS_DATA_OUT (1<<1) /* write request */
#define TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED (1<<2)/* data in ccb is misaligned,
have to copy to/from private buffer */
#define TW_OSLI_REQ_FLAGS_MAPPED (1<<3) /* request has been mapped */
#define TW_OSLI_REQ_FLAGS_IN_PROGRESS (1<<4) /* bus_dmamap_load returned
EINPROGRESS */
#define TW_OSLI_REQ_FLAGS_PASSTHRU (1<<5) /* pass through request */
#define TW_OSLI_REQ_FLAGS_SLEEPING (1<<6) /* owner sleeping on this cmd */
/* Possible values of sc->state. */
#define TW_OSLI_CTLR_STATE_OPEN (1<<0) /* control device is open */
#define TW_OSLI_CTLR_STATE_SIMQ_FROZEN (1<<1) /* simq frozen */
#ifdef TW_OSL_DEBUG
struct tw_osli_q_stats {
TW_UINT32 cur_len; /* current # of items in q */
TW_UINT32 max_len; /* max value reached by q_length */
};
#endif /* TW_OSL_DEBUG */
/* Queues of OSL internal request context packets. */
#define TW_OSLI_FREE_Q 0 /* free q */
#define TW_OSLI_BUSY_Q 1 /* q of reqs submitted to CL */
#define TW_OSLI_Q_COUNT 2 /* total number of queues */
/* Driver's request packet. */
struct tw_osli_req_context {
struct tw_cl_req_handle req_handle;/* tag to track req b/w OSL & CL */
struct twa_softc *ctlr; /* ptr to OSL's controller context */
TW_VOID *data; /* ptr to data being passed to CL */
TW_UINT32 length; /* length of buf being passed to CL */
/*
* ptr to, and length of data passed to us from above, in case a buffer
* copy was done due to non-compliance to alignment requirements
*/
TW_VOID *real_data;
TW_UINT32 real_length;
TW_UINT32 state; /* request state */
TW_UINT32 flags; /* request flags */
/* error encountered before request submission to CL */
TW_UINT32 error_code;
/* ptr to orig req for use during callback */
TW_VOID *orig_req;
struct tw_cl_link link; /* to link this request in a list */
bus_dmamap_t dma_map;/* DMA map for data */
struct tw_cl_req_packet req_pkt;/* req pkt understood by CL */
};
/* Per-controller structure. */
struct twa_softc {
struct tw_cl_ctlr_handle ctlr_handle;
struct tw_osli_req_context *req_ctxt_buf;
/* Controller state. */
TW_UINT32 state;
TW_UINT32 flags;
TW_UINT32 alignment;
TW_UINT32 sg_size_factor;
TW_VOID *non_dma_mem;
TW_VOID *dma_mem;
TW_UINT64 dma_mem_phys;
#ifdef TW_OSL_FLASH_FIRMWARE
TW_VOID *flash_dma_mem;
TW_UINT64 flash_dma_mem_phys;
#endif /* TW_OSL_FLASH_FIRMWARE */
/* Request queues and arrays. */
struct tw_cl_link req_q_head[TW_OSLI_Q_COUNT];
struct task deferred_intr_callback;/* taskqueue function */
struct mtx io_lock_handle;/* general purpose lock */
struct mtx *io_lock;/* ptr to general purpose lock */
struct mtx q_lock_handle; /* queue manipulation lock */
struct mtx *q_lock;/* ptr to queue manipulation lock */
#ifdef TW_OSL_DEBUG
struct tw_osli_q_stats q_stats[TW_OSLI_Q_COUNT];/* queue statistics */
#endif /* TW_OSL_DEBUG */
device_t bus_dev; /* bus device */
struct cdev *ctrl_dev; /* control device */
struct resource *reg_res; /* register interface window */
TW_INT32 reg_res_id; /* register resource id */
bus_space_handle_t bus_handle; /* bus space handle */
bus_space_tag_t bus_tag; /* bus space tag */
bus_dma_tag_t parent_tag; /* parent DMA tag */
bus_dma_tag_t cmd_tag; /* DMA tag for CL's DMA'able mem */
bus_dma_tag_t dma_tag; /* data buffer DMA tag */
bus_dma_tag_t ioctl_tag; /* ioctl data buffer DMA tag */
bus_dmamap_t cmd_map; /* DMA map for CL's DMA'able mem */
bus_dmamap_t ioctl_map; /* DMA map for ioctl data buffers */
#ifdef TW_OSL_FLASH_FIRMWARE
bus_dma_tag_t flash_tag;/* DMA tag for CL's fw flash mem */
bus_dmamap_t flash_map;/* DMA map for CL's fw flash mem */
#endif /* TW_OSL_FLASH_FIRMWARE */
struct resource *irq_res; /* interrupt resource */
TW_INT32 irq_res_id; /* register resource id */
TW_VOID *intr_handle; /* interrupt handle */
struct sysctl_ctx_list sysctl_ctxt; /* sysctl context */
struct sysctl_oid *sysctl_tree; /* sysctl oid */
struct cam_sim *sim; /* sim for this controller */
struct cam_path *path; /* peripheral, path, tgt, lun
associated with this controller */
};
/*
* Queue primitives.
*/
#ifdef TW_OSL_DEBUG
#define TW_OSLI_Q_INIT(sc, q_type) do { \
(sc)->q_stats[q_type].cur_len = 0; \
(sc)->q_stats[q_type].max_len = 0; \
} while(0)
#define TW_OSLI_Q_INSERT(sc, q_type) do { \
struct tw_osli_q_stats *q_stats = &((sc)->q_stats[q_type]); \
\
if (++(q_stats->cur_len) > q_stats->max_len) \
q_stats->max_len = q_stats->cur_len; \
} while(0)
#define TW_OSLI_Q_REMOVE(sc, q_type) \
(sc)->q_stats[q_type].cur_len--
#else /* TW_OSL_DEBUG */
#define TW_OSLI_Q_INIT(sc, q_index)
#define TW_OSLI_Q_INSERT(sc, q_index)
#define TW_OSLI_Q_REMOVE(sc, q_index)
#endif /* TW_OSL_DEBUG */
/* Initialize a queue of requests. */
static __inline TW_VOID
tw_osli_req_q_init(struct twa_softc *sc, TW_UINT8 q_type)
{
TW_CL_Q_INIT(&(sc->req_q_head[q_type]));
TW_OSLI_Q_INIT(sc, q_type);
}
/* Insert the given request at the head of the given queue (q_type). */
static __inline TW_VOID
tw_osli_req_q_insert_head(struct tw_osli_req_context *req, TW_UINT8 q_type)
{
mtx_lock_spin(req->ctlr->q_lock);
TW_CL_Q_INSERT_HEAD(&(req->ctlr->req_q_head[q_type]), &(req->link));
TW_OSLI_Q_INSERT(req->ctlr, q_type);
mtx_unlock_spin(req->ctlr->q_lock);
}
/* Insert the given request at the tail of the given queue (q_type). */
static __inline TW_VOID
tw_osli_req_q_insert_tail(struct tw_osli_req_context *req, TW_UINT8 q_type)
{
mtx_lock_spin(req->ctlr->q_lock);
TW_CL_Q_INSERT_TAIL(&(req->ctlr->req_q_head[q_type]), &(req->link));
TW_OSLI_Q_INSERT(req->ctlr, q_type);
mtx_unlock_spin(req->ctlr->q_lock);
}
/* Remove and return the request at the head of the given queue (q_type). */
static __inline struct tw_osli_req_context *
tw_osli_req_q_remove_head(struct twa_softc *sc, TW_UINT8 q_type)
{
struct tw_osli_req_context *req = NULL;
struct tw_cl_link *link;
mtx_lock_spin(sc->q_lock);
if ((link = TW_CL_Q_FIRST_ITEM(&(sc->req_q_head[q_type]))) !=
TW_CL_NULL) {
req = TW_CL_STRUCT_HEAD(link,
struct tw_osli_req_context, link);
TW_CL_Q_REMOVE_ITEM(&(sc->req_q_head[q_type]), &(req->link));
TW_OSLI_Q_REMOVE(sc, q_type);
}
mtx_unlock_spin(sc->q_lock);
return(req);
}
/* Remove the given request from the given queue (q_type). */
static __inline TW_VOID
tw_osli_req_q_remove_item(struct tw_osli_req_context *req, TW_UINT8 q_type)
{
mtx_lock_spin(req->ctlr->q_lock);
TW_CL_Q_REMOVE_ITEM(&(req->ctlr->req_q_head[q_type]), &(req->link));
TW_OSLI_Q_REMOVE(req->ctlr, q_type);
mtx_unlock_spin(req->ctlr->q_lock);
}
#ifdef TW_OSL_DEBUG
extern TW_INT32 TW_DEBUG_LEVEL_FOR_OSL;
#define tw_osli_dbg_dprintf(dbg_level, sc, fmt, args...) \
if (dbg_level <= TW_DEBUG_LEVEL_FOR_OSL) \
device_printf(sc->bus_dev, "%s: " fmt "\n", \
__func__, ##args)
#define tw_osli_dbg_printf(dbg_level, fmt, args...) \
if (dbg_level <= TW_DEBUG_LEVEL_FOR_OSL) \
printf("%s: " fmt "\n", __func__, ##args)
#else /* TW_OSL_DEBUG */
#define tw_osli_dbg_dprintf(dbg_level, sc, fmt, args...)
#define tw_osli_dbg_printf(dbg_level, fmt, args...)
#endif /* TW_OSL_DEBUG */
/* For regular printing. */
#define twa_printf(sc, fmt, args...) \
device_printf(((struct twa_softc *)(sc))->bus_dev, fmt, ##args)
/* For printing in the "consistent error reporting" format. */
#define tw_osli_printf(sc, err_specific_desc, args...) \
device_printf((sc)->bus_dev, \
"%s: (0x%02X: 0x%04X): %s: " err_specific_desc "\n", ##args)
#endif /* TW_OSL_H */
|