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