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
|
/*
* Copyright (c) 2004-07 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
* Modifications by: Adam Radford
*/
#ifndef TW_CL_H
#define TW_CL_H
/*
* Common Layer internal macros, structures and functions.
*/
#define TW_CLI_SECTOR_SIZE 0x200
#define TW_CLI_REQUEST_TIMEOUT_PERIOD 60 /* seconds */
#define TW_CLI_RESET_TIMEOUT_PERIOD 60 /* seconds */
#define TW_CLI_MAX_RESET_ATTEMPTS 2
/* Possible values of ctlr->ioctl_lock.lock. */
#define TW_CLI_LOCK_FREE 0x0 /* lock is free */
#define TW_CLI_LOCK_HELD 0x1 /* lock is held */
/* Possible values of req->state. */
#define TW_CLI_REQ_STATE_INIT 0x0 /* being initialized */
#define TW_CLI_REQ_STATE_BUSY 0x1 /* submitted to controller */
#define TW_CLI_REQ_STATE_PENDING 0x2 /* in pending queue */
#define TW_CLI_REQ_STATE_COMPLETE 0x3 /* completed by controller */
/* Possible values of req->flags. */
#define TW_CLI_REQ_FLAGS_7K (1<<0) /* 7000 cmd pkt */
#define TW_CLI_REQ_FLAGS_9K (1<<1) /* 9000 cmd pkt */
#define TW_CLI_REQ_FLAGS_INTERNAL (1<<2) /* internal request */
#define TW_CLI_REQ_FLAGS_PASSTHRU (1<<3) /* passthru request */
#define TW_CLI_REQ_FLAGS_EXTERNAL (1<<4) /* external request */
#ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE
/* Register offsets in PCI config space. */
#define TW_CLI_PCI_CONFIG_COMMAND_OFFSET 0x4 /* cmd register offset */
#define TW_CLI_PCI_CONFIG_STATUS_OFFSET 0x6 /* status register offset */
#endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */
#ifdef TW_OSL_DEBUG
struct tw_cli_q_stats {
TW_UINT32 cur_len;/* current # of entries in q */
TW_UINT32 max_len; /* max # of entries in q, ever reached */
};
#endif /* TW_OSL_DEBUG */
/* Queues of CL internal request context packets. */
#define TW_CLI_FREE_Q 0 /* free q */
#define TW_CLI_BUSY_Q 1 /* q of reqs submitted to fw */
#define TW_CLI_PENDING_Q 2 /* q of reqs deferred due to 'q full' */
#define TW_CLI_COMPLETE_Q 3 /* q of reqs completed by fw */
#define TW_CLI_RESET_Q 4 /* q of reqs reset by timeout */
#define TW_CLI_Q_COUNT 5 /* total number of queues */
/* CL's internal request context. */
struct tw_cli_req_context {
struct tw_cl_req_handle *req_handle;/* handle to track requests between
OSL & CL */
struct tw_cli_ctlr_context *ctlr; /* ptr to CL's controller context */
struct tw_cl_command_packet *cmd_pkt;/* ptr to ctlr cmd pkt */
TW_UINT64 cmd_pkt_phys; /* cmd pkt physical address */
TW_VOID *data; /* ptr to data being passed to fw */
TW_UINT32 length; /* length of data being passed to fw */
TW_UINT64 data_phys; /* physical address of data */
TW_UINT32 state; /* request state */
TW_UINT32 flags; /* request flags */
TW_UINT32 error_code; /* error encountered before submission
of request to fw, if any */
TW_VOID *orig_req; /* ptr to original request for use
during callback */
TW_VOID (*tw_cli_callback)(struct tw_cli_req_context *req);
/* CL internal callback */
TW_UINT32 request_id; /* request id for tracking with fw */
struct tw_cl_link link; /* to link this request in a list */
};
/* CL's internal controller context. */
struct tw_cli_ctlr_context {
struct tw_cl_ctlr_handle *ctlr_handle; /* handle to track ctlr between
OSL & CL. */
struct tw_cli_req_context *req_ctxt_buf;/* pointer to the array of CL's
internal request context pkts */
struct tw_cl_command_packet *cmd_pkt_buf;/* ptr to array of cmd pkts */
TW_UINT64 cmd_pkt_phys; /* phys addr of cmd_pkt_buf */
TW_UINT32 device_id; /* controller device id */
TW_UINT32 arch_id; /* controller architecture id */
TW_UINT8 active; /* Initialization done, and controller is active. */
TW_UINT8 interrupts_enabled; /* Interrupts on controller enabled. */
TW_UINT8 internal_req_busy; /* Data buffer for internal requests in use. */
TW_UINT8 get_more_aens; /* More AEN's need to be retrieved. */
TW_UINT8 reset_needed; /* Controller needs a soft reset. */
TW_UINT8 reset_in_progress; /* Controller is being reset. */
TW_UINT8 reset_phase1_in_progress; /* In 'phase 1' of reset. */
TW_UINT32 flags; /* controller settings */
TW_UINT32 sg_size_factor; /* SG element size should be a
multiple of this */
/* Request queues and arrays. */
struct tw_cl_link req_q_head[TW_CLI_Q_COUNT];
TW_UINT8 *internal_req_data;/* internal req data buf */
TW_UINT64 internal_req_data_phys;/* phys addr of internal
req data buf */
TW_UINT32 max_simult_reqs; /* max simultaneous requests
supported */
TW_UINT32 max_aens_supported;/* max AEN's supported */
/* AEN handler fields. */
struct tw_cl_event_packet *aen_queue; /* circular queue of AENs from
firmware/CL/OSL */
TW_UINT32 aen_head; /* AEN queue head */
TW_UINT32 aen_tail; /* AEN queue tail */
TW_UINT32 aen_cur_seq_id; /* index of the last event+1 */
TW_UINT32 aen_q_overflow; /* indicates if unretrieved
events were overwritten */
TW_UINT32 aen_q_wrapped; /* indicates if AEN queue ever
wrapped */
TW_UINT16 working_srl; /* driver & firmware negotiated
srl */
TW_UINT16 working_branch; /* branch # of the firmware
that the driver is compatible with */
TW_UINT16 working_build; /* build # of the firmware
that the driver is compatible with */
TW_UINT16 fw_on_ctlr_srl; /* srl of running firmware */
TW_UINT16 fw_on_ctlr_branch;/* branch # of running
firmware */
TW_UINT16 fw_on_ctlr_build;/* build # of running
firmware */
TW_UINT32 operating_mode; /* base mode/current mode */
TW_INT32 host_intr_pending;/* host intr processing
needed */
TW_INT32 attn_intr_pending;/* attn intr processing
needed */
TW_INT32 cmd_intr_pending;/* cmd intr processing
needed */
TW_INT32 resp_intr_pending;/* resp intr processing
needed */
TW_LOCK_HANDLE gen_lock_handle;/* general purpose lock */
TW_LOCK_HANDLE *gen_lock;/* ptr to general purpose lock */
TW_LOCK_HANDLE io_lock_handle; /* lock held during cmd
submission */
TW_LOCK_HANDLE *io_lock;/* ptr to lock held during cmd
submission */
#ifdef TW_OSL_CAN_SLEEP
TW_SLEEP_HANDLE sleep_handle; /* handle to co-ordinate sleeps
& wakeups */
#endif /* TW_OSL_CAN_SLEEP */
struct {
TW_UINT32 lock; /* lock state */
TW_TIME timeout; /* time at which the lock will
become available, even if not
explicitly released */
} ioctl_lock; /* lock for use by user applications, for
synchronization between ioctl calls */
#ifdef TW_OSL_DEBUG
struct tw_cli_q_stats q_stats[TW_CLI_Q_COUNT];/* queue statistics */
#endif /* TW_OSL_DEBUG */
};
/*
* Queue primitives
*/
#ifdef TW_OSL_DEBUG
#define TW_CLI_Q_INIT(ctlr, q_type) do { \
(ctlr)->q_stats[q_type].cur_len = 0; \
(ctlr)->q_stats[q_type].max_len = 0; \
} while (0)
#define TW_CLI_Q_INSERT(ctlr, q_type) do { \
struct tw_cli_q_stats *q_stats = &((ctlr)->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_CLI_Q_REMOVE(ctlr, q_type) \
(ctlr)->q_stats[q_type].cur_len--
#else /* TW_OSL_DEBUG */
#define TW_CLI_Q_INIT(ctlr, q_index)
#define TW_CLI_Q_INSERT(ctlr, q_index)
#define TW_CLI_Q_REMOVE(ctlr, q_index)
#endif /* TW_OSL_DEBUG */
/* Initialize a queue of requests. */
static __inline TW_VOID
tw_cli_req_q_init(struct tw_cli_ctlr_context *ctlr, TW_UINT8 q_type)
{
TW_CL_Q_INIT(&(ctlr->req_q_head[q_type]));
TW_CLI_Q_INIT(ctlr, q_type);
}
/* Insert the given request at the head of the given queue (q_type). */
static __inline TW_VOID
tw_cli_req_q_insert_head(struct tw_cli_req_context *req, TW_UINT8 q_type)
{
struct tw_cli_ctlr_context *ctlr = req->ctlr;
tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
TW_CL_Q_INSERT_HEAD(&(ctlr->req_q_head[q_type]), &(req->link));
TW_CLI_Q_INSERT(ctlr, q_type);
tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
}
/* Insert the given request at the tail of the given queue (q_type). */
static __inline TW_VOID
tw_cli_req_q_insert_tail(struct tw_cli_req_context *req, TW_UINT8 q_type)
{
struct tw_cli_ctlr_context *ctlr = req->ctlr;
tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
TW_CL_Q_INSERT_TAIL(&(ctlr->req_q_head[q_type]), &(req->link));
TW_CLI_Q_INSERT(ctlr, q_type);
tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
}
/* Remove and return the request at the head of the given queue (q_type). */
static __inline struct tw_cli_req_context *
tw_cli_req_q_remove_head(struct tw_cli_ctlr_context *ctlr, TW_UINT8 q_type)
{
struct tw_cli_req_context *req = TW_CL_NULL;
struct tw_cl_link *link;
tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
if ((link = TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[q_type]))) !=
TW_CL_NULL) {
req = TW_CL_STRUCT_HEAD(link,
struct tw_cli_req_context, link);
TW_CL_Q_REMOVE_ITEM(&(ctlr->req_q_head[q_type]), &(req->link));
TW_CLI_Q_REMOVE(ctlr, q_type);
}
tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
return(req);
}
/* Remove the given request from the given queue (q_type). */
static __inline TW_VOID
tw_cli_req_q_remove_item(struct tw_cli_req_context *req, TW_UINT8 q_type)
{
struct tw_cli_ctlr_context *ctlr = req->ctlr;
tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
TW_CL_Q_REMOVE_ITEM(&(ctlr->req_q_head[q_type]), &(req->link));
TW_CLI_Q_REMOVE(ctlr, q_type);
tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
}
/* Create an event packet for an event/error posted by the controller. */
#define tw_cli_create_ctlr_event(ctlr, event_src, cmd_hdr) do { \
TW_UINT8 severity = \
GET_SEVERITY((cmd_hdr)->status_block.res__severity); \
\
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_TRUE, event_src, \
(cmd_hdr)->status_block.error, \
severity, \
tw_cli_severity_string_table[severity], \
(cmd_hdr)->err_specific_desc + \
tw_osl_strlen((cmd_hdr)->err_specific_desc) + 1, \
(cmd_hdr)->err_specific_desc); \
/* Print 18 bytes of sense information. */ \
tw_cli_dbg_printf(2, ctlr->ctlr_handle, \
tw_osl_cur_func(), \
"sense info: %x %x %x %x %x %x %x %x %x " \
"%x %x %x %x %x %x %x %x %x", \
(cmd_hdr)->sense_data[0], (cmd_hdr)->sense_data[1], \
(cmd_hdr)->sense_data[2], (cmd_hdr)->sense_data[3], \
(cmd_hdr)->sense_data[4], (cmd_hdr)->sense_data[5], \
(cmd_hdr)->sense_data[6], (cmd_hdr)->sense_data[7], \
(cmd_hdr)->sense_data[8], (cmd_hdr)->sense_data[9], \
(cmd_hdr)->sense_data[10], (cmd_hdr)->sense_data[11], \
(cmd_hdr)->sense_data[12], (cmd_hdr)->sense_data[13], \
(cmd_hdr)->sense_data[14], (cmd_hdr)->sense_data[15], \
(cmd_hdr)->sense_data[16], (cmd_hdr)->sense_data[17]); \
} while (0)
#endif /* TW_CL_H */
|