xref: /dragonfly/sys/dev/raid/twa/tw_cl.h (revision 1e0dd9dd32a69a1d3bbe6a9e41c3a63aae59fb4d)
1 /*
2  * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
3  * Copyright (c) 2004-05 Vinod Kashyap
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *        $FreeBSD: head/sys/dev/twa/tw_cl.h 212008 2010-08-30 19:15:04Z delphij $
28  */
29 
30 /*
31  * AMCC'S 3ware driver for 9000 series storage controllers.
32  *
33  * Author: Vinod Kashyap
34  * Modifications by: Adam Radford
35  */
36 
37 
38 
39 #ifndef TW_CL_H
40 
41 #define TW_CL_H
42 
43 
44 /*
45  * Common Layer internal macros, structures and functions.
46  */
47 
48 
49 #define TW_CLI_SECTOR_SIZE              0x200
50 #define TW_CLI_REQUEST_TIMEOUT_PERIOD   60 /* seconds */
51 #define TW_CLI_RESET_TIMEOUT_PERIOD     60 /* seconds */
52 #define TW_CLI_MAX_RESET_ATTEMPTS       2
53 
54 /* Possible values of ctlr->ioctl_lock.lock. */
55 #define TW_CLI_LOCK_FREE                0x0       /* lock is free */
56 #define TW_CLI_LOCK_HELD                0x1       /* lock is held */
57 
58 /* Possible values of req->state. */
59 #define TW_CLI_REQ_STATE_INIT           0x0       /* being initialized */
60 #define TW_CLI_REQ_STATE_BUSY           0x1       /* submitted to controller */
61 #define TW_CLI_REQ_STATE_PENDING        0x2       /* in pending queue */
62 #define TW_CLI_REQ_STATE_COMPLETE       0x3       /* completed by controller */
63 
64 /* Possible values of req->flags. */
65 #define TW_CLI_REQ_FLAGS_7K             (1<<0)    /* 7000 cmd pkt */
66 #define TW_CLI_REQ_FLAGS_9K             (1<<1)    /* 9000 cmd pkt */
67 #define TW_CLI_REQ_FLAGS_INTERNAL       (1<<2)    /* internal request */
68 #define TW_CLI_REQ_FLAGS_PASSTHRU       (1<<3)    /* passthru request */
69 #define TW_CLI_REQ_FLAGS_EXTERNAL       (1<<4)    /* external request */
70 
71 #ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE
72 /* Register offsets in PCI config space. */
73 #define TW_CLI_PCI_CONFIG_COMMAND_OFFSET          0x4 /* cmd register offset */
74 #define TW_CLI_PCI_CONFIG_STATUS_OFFSET           0x6 /* status register offset */
75 #endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */
76 
77 
78 #ifdef TW_OSL_DEBUG
79 struct tw_cli_q_stats {
80           TW_UINT32 cur_len;/* current # of entries in q */
81           TW_UINT32 max_len;   /* max # of entries in q, ever reached */
82 };
83 #endif /* TW_OSL_DEBUG */
84 
85 
86 /* Queues of CL internal request context packets. */
87 #define TW_CLI_FREE_Q                   0         /* free q */
88 #define TW_CLI_BUSY_Q                   1         /* q of reqs submitted to fw */
89 #define TW_CLI_PENDING_Q      2         /* q of reqs deferred due to 'q full' */
90 #define TW_CLI_COMPLETE_Q     3         /* q of reqs completed by fw */
91 #define TW_CLI_RESET_Q                  4         /* q of reqs reset by timeout */
92 #define TW_CLI_Q_COUNT                  5         /* total number of queues */
93 
94 
95 /* CL's internal request context. */
96 struct tw_cli_req_context {
97           struct tw_cl_req_handle       *req_handle;/* handle to track requests between
98                                                             OSL & CL */
99           struct tw_cli_ctlr_context  *ctlr; /* ptr to CL's controller context */
100           struct tw_cl_command_packet *cmd_pkt;/* ptr to ctlr cmd pkt */
101           TW_UINT64 cmd_pkt_phys;       /* cmd pkt physical address */
102           TW_VOID             *data;              /* ptr to data being passed to fw */
103           TW_UINT32 length;             /* length of data being passed to fw */
104           TW_UINT64 data_phys;          /* physical address of data */
105 
106           TW_UINT32 state;              /* request state */
107           TW_UINT32 flags;              /* request flags */
108 
109           TW_UINT32 error_code;         /* error encountered before submission
110                                                   of request to fw, if any */
111 
112           TW_VOID             *orig_req;          /* ptr to original request for use
113                                                   during callback */
114           TW_VOID             (*tw_cli_callback)(struct tw_cli_req_context *req);
115                                                   /* CL internal callback */
116           TW_UINT32 request_id;         /* request id for tracking with fw */
117           struct tw_cl_link link;                 /* to link this request in a list */
118 };
119 
120 
121 /* CL's internal controller context. */
122 struct tw_cli_ctlr_context {
123           struct tw_cl_ctlr_handle *ctlr_handle;  /* handle to track ctlr between
124                                                                       OSL & CL. */
125           struct tw_cli_req_context *req_ctxt_buf;/* pointer to the array of CL's
126                                                             internal request context pkts */
127           struct tw_cl_command_packet *cmd_pkt_buf;/* ptr to array of cmd pkts */
128 
129           TW_UINT64           cmd_pkt_phys;       /* phys addr of cmd_pkt_buf */
130 
131           TW_UINT32           device_id;          /* controller device id */
132           TW_UINT32           arch_id;  /* controller architecture id */
133           TW_UINT8            active;                         /* Initialization done, and controller is active. */
134           TW_UINT8            interrupts_enabled;   /* Interrupts on controller enabled. */
135           TW_UINT8            internal_req_busy;    /* Data buffer for internal requests in use. */
136           TW_UINT8            get_more_aens;                  /* More AEN's need to be retrieved. */
137           TW_UINT8            reset_needed;                   /* Controller needs a soft reset. */
138           TW_UINT8            reset_in_progress;    /* Controller is being reset. */
139           TW_UINT8            reset_phase1_in_progress; /* In 'phase 1' of reset. */
140           TW_UINT32           flags;              /* controller settings */
141           TW_UINT32           sg_size_factor;     /* SG element size should be a
142                                                                       multiple of this */
143 
144           /* Request queues and arrays. */
145           struct tw_cl_link   req_q_head[TW_CLI_Q_COUNT];
146 
147           TW_UINT8            *internal_req_data;/* internal req data buf */
148           TW_UINT64           internal_req_data_phys;/* phys addr of internal
149                                                                       req data buf */
150           TW_UINT32           max_simult_reqs; /* max simultaneous requests
151                                                                       supported */
152           TW_UINT32           max_aens_supported;/* max AEN's supported */
153           /* AEN handler fields. */
154           struct tw_cl_event_packet *aen_queue;   /* circular queue of AENs from
155                                                                       firmware/CL/OSL */
156           TW_UINT32           aen_head; /* AEN queue head */
157           TW_UINT32           aen_tail; /* AEN queue tail */
158           TW_UINT32           aen_cur_seq_id;     /* index of the last event+1 */
159           TW_UINT32           aen_q_overflow;     /* indicates if unretrieved
160                                                             events were overwritten */
161           TW_UINT32           aen_q_wrapped;      /* indicates if AEN queue ever
162                                                                       wrapped */
163 
164           TW_UINT16           working_srl;        /* driver & firmware negotiated
165                                                                       srl */
166           TW_UINT16           working_branch;     /* branch # of the firmware
167                                                   that the driver is compatible with */
168           TW_UINT16           working_build;      /* build # of the firmware
169                                                   that the driver is compatible with */
170           TW_UINT16           fw_on_ctlr_srl;     /* srl of running firmware */
171           TW_UINT16           fw_on_ctlr_branch;/* branch # of running
172                                                                       firmware */
173           TW_UINT16           fw_on_ctlr_build;/* build # of running
174                                                                       firmware */
175           TW_UINT32           operating_mode; /* base mode/current mode */
176 
177           TW_INT32            host_intr_pending;/* host intr processing
178                                                                       needed */
179           TW_INT32            attn_intr_pending;/* attn intr processing
180                                                                       needed */
181           TW_INT32            cmd_intr_pending;/* cmd intr processing
182                                                                       needed */
183           TW_INT32            resp_intr_pending;/* resp intr processing
184                                                                       needed */
185 
186           TW_LOCK_HANDLE                gen_lock_handle;/* general purpose lock */
187           TW_LOCK_HANDLE                *gen_lock;/* ptr to general purpose lock */
188           TW_LOCK_HANDLE                io_lock_handle;     /* lock held during cmd
189                                                             submission */
190           TW_LOCK_HANDLE                *io_lock;/* ptr to lock held during cmd
191                                                             submission */
192 
193 #ifdef TW_OSL_CAN_SLEEP
194           TW_SLEEP_HANDLE               sleep_handle;       /* handle to co-ordinate sleeps
195                                                             & wakeups */
196 #endif /* TW_OSL_CAN_SLEEP */
197 
198           struct {
199                     TW_UINT32 lock;               /* lock state */
200                     TW_TIME             timeout;  /* time at which the lock will
201                                                             become available, even if not
202                                                             explicitly released */
203           } ioctl_lock;                 /* lock for use by user applications, for
204                                         synchronization between ioctl calls */
205 #ifdef TW_OSL_DEBUG
206           struct tw_cli_q_stats         q_stats[TW_CLI_Q_COUNT];/* queue statistics */
207 #endif /* TW_OSL_DEBUG */
208 };
209 
210 
211 
212 /*
213  * Queue primitives
214  */
215 
216 #ifdef TW_OSL_DEBUG
217 
218 #define TW_CLI_Q_INIT(ctlr, q_type)     do {                                    \
219           (ctlr)->q_stats[q_type].cur_len = 0;                                  \
220           (ctlr)->q_stats[q_type].max_len = 0;                                  \
221 } while (0)
222 
223 
224 #define TW_CLI_Q_INSERT(ctlr, q_type)   do {                                    \
225           struct tw_cli_q_stats *q_stats = &((ctlr)->q_stats[q_type]);          \
226                                                                                           \
227           if (++(q_stats->cur_len) > q_stats->max_len)                          \
228                     q_stats->max_len = q_stats->cur_len;                        \
229 } while (0)
230 
231 
232 #define TW_CLI_Q_REMOVE(ctlr, q_type)                                           \
233           (ctlr)->q_stats[q_type].cur_len--
234 
235 #else /* TW_OSL_DEBUG */
236 
237 #define TW_CLI_Q_INIT(ctlr, q_index)
238 #define TW_CLI_Q_INSERT(ctlr, q_index)
239 #define TW_CLI_Q_REMOVE(ctlr, q_index)
240 
241 #endif /* TW_OSL_DEBUG */
242 
243 
244 /* Initialize a queue of requests. */
245 static __inline TW_VOID
tw_cli_req_q_init(struct tw_cli_ctlr_context * ctlr,TW_UINT8 q_type)246 tw_cli_req_q_init(struct tw_cli_ctlr_context *ctlr, TW_UINT8 q_type)
247 {
248           TW_CL_Q_INIT(&(ctlr->req_q_head[q_type]));
249           TW_CLI_Q_INIT(ctlr, q_type);
250 }
251 
252 
253 
254 /* Insert the given request at the head of the given queue (q_type). */
255 static __inline TW_VOID
tw_cli_req_q_insert_head(struct tw_cli_req_context * req,TW_UINT8 q_type)256 tw_cli_req_q_insert_head(struct tw_cli_req_context *req, TW_UINT8 q_type)
257 {
258           struct tw_cli_ctlr_context    *ctlr = req->ctlr;
259 
260           tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
261           TW_CL_Q_INSERT_HEAD(&(ctlr->req_q_head[q_type]), &(req->link));
262           TW_CLI_Q_INSERT(ctlr, q_type);
263           tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
264 }
265 
266 
267 
268 /* Insert the given request at the tail of the given queue (q_type). */
269 static __inline TW_VOID
tw_cli_req_q_insert_tail(struct tw_cli_req_context * req,TW_UINT8 q_type)270 tw_cli_req_q_insert_tail(struct tw_cli_req_context *req, TW_UINT8 q_type)
271 {
272           struct tw_cli_ctlr_context    *ctlr = req->ctlr;
273 
274           tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
275           TW_CL_Q_INSERT_TAIL(&(ctlr->req_q_head[q_type]), &(req->link));
276           TW_CLI_Q_INSERT(ctlr, q_type);
277           tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
278 }
279 
280 
281 
282 /* Remove and return the request at the head of the given queue (q_type). */
283 static __inline struct tw_cli_req_context *
tw_cli_req_q_remove_head(struct tw_cli_ctlr_context * ctlr,TW_UINT8 q_type)284 tw_cli_req_q_remove_head(struct tw_cli_ctlr_context *ctlr, TW_UINT8 q_type)
285 {
286           struct tw_cli_req_context     *req = TW_CL_NULL;
287           struct tw_cl_link             *link;
288 
289           tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
290           if ((link = TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[q_type]))) !=
291                     TW_CL_NULL) {
292                     req = TW_CL_STRUCT_HEAD(link,
293                               struct tw_cli_req_context, link);
294                     TW_CL_Q_REMOVE_ITEM(&(ctlr->req_q_head[q_type]), &(req->link));
295                     TW_CLI_Q_REMOVE(ctlr, q_type);
296           }
297           tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
298           return(req);
299 }
300 
301 
302 
303 /* Remove the given request from the given queue (q_type). */
304 static __inline TW_VOID
tw_cli_req_q_remove_item(struct tw_cli_req_context * req,TW_UINT8 q_type)305 tw_cli_req_q_remove_item(struct tw_cli_req_context *req, TW_UINT8 q_type)
306 {
307           struct tw_cli_ctlr_context    *ctlr = req->ctlr;
308 
309           tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
310           TW_CL_Q_REMOVE_ITEM(&(ctlr->req_q_head[q_type]), &(req->link));
311           TW_CLI_Q_REMOVE(ctlr, q_type);
312           tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
313 }
314 
315 
316 
317 /* Create an event packet for an event/error posted by the controller. */
318 #define tw_cli_create_ctlr_event(ctlr, event_src, cmd_hdr)  do {      \
319           TW_UINT8 severity =                                                   \
320                     GET_SEVERITY((cmd_hdr)->status_block.res__severity);        \
321                                                                                           \
322           tw_cl_create_event(ctlr->ctlr_handle, TW_CL_TRUE, event_src,          \
323                     (cmd_hdr)->status_block.error,                                        \
324                     severity,                                                   \
325                     tw_cli_severity_string_table[severity],                     \
326                     (cmd_hdr)->err_specific_desc +                                        \
327                     tw_osl_strlen((cmd_hdr)->err_specific_desc) + 1,  \
328                     (cmd_hdr)->err_specific_desc);                                        \
329           /* Print 18 bytes of sense information. */                            \
330           tw_cli_dbg_printf(2, ctlr->ctlr_handle,                               \
331                     tw_osl_cur_func(),                                          \
332                     "sense info: %x %x %x %x %x %x %x %x %x "                   \
333                     "%x %x %x %x %x %x %x %x %x",                               \
334                     (cmd_hdr)->sense_data[0], (cmd_hdr)->sense_data[1],         \
335                     (cmd_hdr)->sense_data[2], (cmd_hdr)->sense_data[3],         \
336                     (cmd_hdr)->sense_data[4], (cmd_hdr)->sense_data[5],         \
337                     (cmd_hdr)->sense_data[6], (cmd_hdr)->sense_data[7],         \
338                     (cmd_hdr)->sense_data[8], (cmd_hdr)->sense_data[9],         \
339                     (cmd_hdr)->sense_data[10], (cmd_hdr)->sense_data[11],       \
340                     (cmd_hdr)->sense_data[12], (cmd_hdr)->sense_data[13],       \
341                     (cmd_hdr)->sense_data[14], (cmd_hdr)->sense_data[15],       \
342                     (cmd_hdr)->sense_data[16], (cmd_hdr)->sense_data[17]);      \
343 } while (0)
344 
345 
346 
347 #endif /* TW_CL_H */
348