xref: /freebsd-13.1/sys/dev/twa/tw_cl.h (revision bed02296)
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 #ifndef TW_CL_H
40 
41 #define TW_CL_H
42 
43 /*
44  * Common Layer internal macros, structures and functions.
45  */
46 
47 #define TW_CLI_SECTOR_SIZE		0x200
48 #define TW_CLI_REQUEST_TIMEOUT_PERIOD	60 /* seconds */
49 #define TW_CLI_RESET_TIMEOUT_PERIOD	60 /* seconds */
50 #define TW_CLI_MAX_RESET_ATTEMPTS	2
51 
52 /* Possible values of ctlr->ioctl_lock.lock. */
53 #define TW_CLI_LOCK_FREE		0x0	/* lock is free */
54 #define TW_CLI_LOCK_HELD		0x1	/* lock is held */
55 
56 /* Possible values of req->state. */
57 #define TW_CLI_REQ_STATE_INIT		0x0	/* being initialized */
58 #define TW_CLI_REQ_STATE_BUSY		0x1	/* submitted to controller */
59 #define TW_CLI_REQ_STATE_PENDING	0x2	/* in pending queue */
60 #define TW_CLI_REQ_STATE_COMPLETE	0x3	/* completed by controller */
61 
62 /* Possible values of req->flags. */
63 #define TW_CLI_REQ_FLAGS_7K		(1<<0)	/* 7000 cmd pkt */
64 #define TW_CLI_REQ_FLAGS_9K		(1<<1)	/* 9000 cmd pkt */
65 #define TW_CLI_REQ_FLAGS_INTERNAL	(1<<2)	/* internal request */
66 #define TW_CLI_REQ_FLAGS_PASSTHRU	(1<<3)	/* passthru request */
67 #define TW_CLI_REQ_FLAGS_EXTERNAL	(1<<4)	/* external request */
68 
69 #ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE
70 /* Register offsets in PCI config space. */
71 #define TW_CLI_PCI_CONFIG_COMMAND_OFFSET	0x4 /* cmd register offset */
72 #define TW_CLI_PCI_CONFIG_STATUS_OFFSET		0x6 /* status register offset */
73 #endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */
74 
75 #ifdef TW_OSL_DEBUG
76 struct tw_cli_q_stats {
77 	TW_UINT32	cur_len;/* current # of entries in q */
78 	TW_UINT32	max_len;	 /* max # of entries in q, ever reached */
79 };
80 #endif /* TW_OSL_DEBUG */
81 
82 /* Queues of CL internal request context packets. */
83 #define TW_CLI_FREE_Q		0	/* free q */
84 #define TW_CLI_BUSY_Q		1	/* q of reqs submitted to fw */
85 #define TW_CLI_PENDING_Q	2	/* q of reqs deferred due to 'q full' */
86 #define TW_CLI_COMPLETE_Q	3	/* q of reqs completed by fw */
87 #define TW_CLI_RESET_Q		4	/* q of reqs reset by timeout */
88 #define TW_CLI_Q_COUNT		5	/* total number of queues */
89 
90 /* CL's internal request context. */
91 struct tw_cli_req_context {
92 	struct tw_cl_req_handle	*req_handle;/* handle to track requests between
93 						OSL & CL */
94 	struct tw_cli_ctlr_context  *ctlr; /* ptr to CL's controller context */
95 	struct tw_cl_command_packet *cmd_pkt;/* ptr to ctlr cmd pkt */
96 	TW_UINT64	cmd_pkt_phys;	/* cmd pkt physical address */
97 	TW_VOID		*data;		/* ptr to data being passed to fw */
98 	TW_UINT32	length;		/* length of data being passed to fw */
99 	TW_UINT64	data_phys;	/* physical address of data */
100 
101 	TW_UINT32	state;		/* request state */
102 	TW_UINT32	flags;		/* request flags */
103 
104 	TW_UINT32	error_code;	/* error encountered before submission
105 					of request to fw, if any */
106 
107 	TW_VOID		*orig_req;	/* ptr to original request for use
108 					during callback */
109 	TW_VOID		(*tw_cli_callback)(struct tw_cli_req_context *req);
110 					/* CL internal callback */
111 	TW_UINT32	request_id;	/* request id for tracking with fw */
112 	struct tw_cl_link link;		/* to link this request in a list */
113 };
114 
115 /* CL's internal controller context. */
116 struct tw_cli_ctlr_context {
117 	struct tw_cl_ctlr_handle *ctlr_handle;	/* handle to track ctlr between
118 							OSL & CL. */
119 	struct tw_cli_req_context *req_ctxt_buf;/* pointer to the array of CL's
120 						internal request context pkts */
121 	struct tw_cl_command_packet *cmd_pkt_buf;/* ptr to array of cmd pkts */
122 
123 	TW_UINT64		cmd_pkt_phys;	/* phys addr of cmd_pkt_buf */
124 
125 	TW_UINT32		device_id;	/* controller device id */
126 	TW_UINT32		arch_id;	/* controller architecture id */
127 	TW_UINT8 		active;			  /* Initialization done, and controller is active. */
128 	TW_UINT8 		interrupts_enabled;	  /* Interrupts on controller enabled. */
129 	TW_UINT8 		internal_req_busy;	  /* Data buffer for internal requests in use. */
130 	TW_UINT8 		get_more_aens;		  /* More AEN's need to be retrieved. */
131 	TW_UINT8 		reset_needed;		  /* Controller needs a soft reset. */
132 	TW_UINT8 		reset_in_progress;	  /* Controller is being reset. */
133 	TW_UINT8 		reset_phase1_in_progress; /* In 'phase 1' of reset. */
134 	TW_UINT32		flags;		/* controller settings */
135 	TW_UINT32		sg_size_factor;	/* SG element size should be a
136 							multiple of this */
137 
138 	/* Request queues and arrays. */
139 	struct tw_cl_link	req_q_head[TW_CLI_Q_COUNT];
140 
141 	TW_UINT8		*internal_req_data;/* internal req data buf */
142 	TW_UINT64		internal_req_data_phys;/* phys addr of internal
143 							req data buf */
144 	TW_UINT32		max_simult_reqs; /* max simultaneous requests
145 							supported */
146 	TW_UINT32		max_aens_supported;/* max AEN's supported */
147 	/* AEN handler fields. */
148 	struct tw_cl_event_packet *aen_queue;	/* circular queue of AENs from
149 							firmware/CL/OSL */
150 	TW_UINT32		aen_head;	/* AEN queue head */
151 	TW_UINT32		aen_tail;	/* AEN queue tail */
152 	TW_UINT32		aen_cur_seq_id;	/* index of the last event+1 */
153 	TW_UINT32		aen_q_overflow;	/* indicates if unretrieved
154 						events were overwritten */
155 	TW_UINT32		aen_q_wrapped;	/* indicates if AEN queue ever
156 							wrapped */
157 
158 	TW_UINT16		working_srl;	/* driver & firmware negotiated
159 							srl */
160 	TW_UINT16		working_branch;	/* branch # of the firmware
161 					that the driver is compatible with */
162 	TW_UINT16		working_build;	/* build # of the firmware
163 					that the driver is compatible with */
164 	TW_UINT16		fw_on_ctlr_srl;	/* srl of running firmware */
165 	TW_UINT16		fw_on_ctlr_branch;/* branch # of running
166 							firmware */
167 	TW_UINT16		fw_on_ctlr_build;/* build # of running
168 							firmware */
169 	TW_UINT32		operating_mode; /* base mode/current mode */
170 
171 	TW_INT32		host_intr_pending;/* host intr processing
172 							needed */
173 	TW_INT32		attn_intr_pending;/* attn intr processing
174 							needed */
175 	TW_INT32		cmd_intr_pending;/* cmd intr processing
176 							needed */
177 	TW_INT32		resp_intr_pending;/* resp intr processing
178 							needed */
179 
180 	TW_LOCK_HANDLE		gen_lock_handle;/* general purpose lock */
181 	TW_LOCK_HANDLE		*gen_lock;/* ptr to general purpose lock */
182 	TW_LOCK_HANDLE		io_lock_handle;	/* lock held during cmd
183 						submission */
184 	TW_LOCK_HANDLE		*io_lock;/* ptr to lock held during cmd
185 						submission */
186 
187 #ifdef TW_OSL_CAN_SLEEP
188 	TW_SLEEP_HANDLE		sleep_handle;	/* handle to co-ordinate sleeps
189 						& wakeups */
190 #endif /* TW_OSL_CAN_SLEEP */
191 
192 	struct {
193 		TW_UINT32	lock;		/* lock state */
194 		TW_TIME		timeout;	/* time at which the lock will
195 						become available, even if not
196 						explicitly released */
197 	} ioctl_lock;		/* lock for use by user applications, for
198 				synchronization between ioctl calls */
199 #ifdef TW_OSL_DEBUG
200 	struct tw_cli_q_stats	q_stats[TW_CLI_Q_COUNT];/* queue statistics */
201 #endif /* TW_OSL_DEBUG */
202 };
203 
204 /*
205  * Queue primitives
206  */
207 
208 #ifdef TW_OSL_DEBUG
209 
210 #define TW_CLI_Q_INIT(ctlr, q_type)	do {				\
211 	(ctlr)->q_stats[q_type].cur_len = 0;				\
212 	(ctlr)->q_stats[q_type].max_len = 0;				\
213 } while (0)
214 
215 #define TW_CLI_Q_INSERT(ctlr, q_type)	do {				\
216 	struct tw_cli_q_stats *q_stats = &((ctlr)->q_stats[q_type]);	\
217 									\
218 	if (++(q_stats->cur_len) > q_stats->max_len)			\
219 		q_stats->max_len = q_stats->cur_len;			\
220 } while (0)
221 
222 #define TW_CLI_Q_REMOVE(ctlr, q_type)					\
223 	(ctlr)->q_stats[q_type].cur_len--
224 
225 #else /* TW_OSL_DEBUG */
226 
227 #define TW_CLI_Q_INIT(ctlr, q_index)
228 #define TW_CLI_Q_INSERT(ctlr, q_index)
229 #define TW_CLI_Q_REMOVE(ctlr, q_index)
230 
231 #endif /* TW_OSL_DEBUG */
232 
233 /* Initialize a queue of requests. */
234 static __inline TW_VOID
tw_cli_req_q_init(struct tw_cli_ctlr_context * ctlr,TW_UINT8 q_type)235 tw_cli_req_q_init(struct tw_cli_ctlr_context *ctlr, TW_UINT8 q_type)
236 {
237 	TW_CL_Q_INIT(&(ctlr->req_q_head[q_type]));
238 	TW_CLI_Q_INIT(ctlr, q_type);
239 }
240 
241 /* Insert the given request at the head of the given queue (q_type). */
242 static __inline TW_VOID
tw_cli_req_q_insert_head(struct tw_cli_req_context * req,TW_UINT8 q_type)243 tw_cli_req_q_insert_head(struct tw_cli_req_context *req, TW_UINT8 q_type)
244 {
245 	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
246 
247 	tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
248 	TW_CL_Q_INSERT_HEAD(&(ctlr->req_q_head[q_type]), &(req->link));
249 	TW_CLI_Q_INSERT(ctlr, q_type);
250 	tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
251 }
252 
253 /* Insert the given request at the tail of the given queue (q_type). */
254 static __inline TW_VOID
tw_cli_req_q_insert_tail(struct tw_cli_req_context * req,TW_UINT8 q_type)255 tw_cli_req_q_insert_tail(struct tw_cli_req_context *req, TW_UINT8 q_type)
256 {
257 	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
258 
259 	tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
260 	TW_CL_Q_INSERT_TAIL(&(ctlr->req_q_head[q_type]), &(req->link));
261 	TW_CLI_Q_INSERT(ctlr, q_type);
262 	tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
263 }
264 
265 /* Remove and return the request at the head of the given queue (q_type). */
266 static __inline struct tw_cli_req_context *
tw_cli_req_q_remove_head(struct tw_cli_ctlr_context * ctlr,TW_UINT8 q_type)267 tw_cli_req_q_remove_head(struct tw_cli_ctlr_context *ctlr, TW_UINT8 q_type)
268 {
269 	struct tw_cli_req_context	*req = TW_CL_NULL;
270 	struct tw_cl_link		*link;
271 
272 	tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
273 	if ((link = TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[q_type]))) !=
274 		TW_CL_NULL) {
275 		req = TW_CL_STRUCT_HEAD(link,
276 			struct tw_cli_req_context, link);
277 		TW_CL_Q_REMOVE_ITEM(&(ctlr->req_q_head[q_type]), &(req->link));
278 		TW_CLI_Q_REMOVE(ctlr, q_type);
279 	}
280 	tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
281 	return(req);
282 }
283 
284 /* Remove the given request from the given queue (q_type). */
285 static __inline TW_VOID
tw_cli_req_q_remove_item(struct tw_cli_req_context * req,TW_UINT8 q_type)286 tw_cli_req_q_remove_item(struct tw_cli_req_context *req, TW_UINT8 q_type)
287 {
288 	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
289 
290 	tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
291 	TW_CL_Q_REMOVE_ITEM(&(ctlr->req_q_head[q_type]), &(req->link));
292 	TW_CLI_Q_REMOVE(ctlr, q_type);
293 	tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
294 }
295 
296 /* Create an event packet for an event/error posted by the controller. */
297 #define tw_cli_create_ctlr_event(ctlr, event_src, cmd_hdr)	do {	\
298 	TW_UINT8 severity =						\
299 		GET_SEVERITY((cmd_hdr)->status_block.res__severity);	\
300 									\
301 	tw_cl_create_event(ctlr->ctlr_handle, TW_CL_TRUE, event_src,	\
302 		(cmd_hdr)->status_block.error,				\
303 		severity,						\
304 		tw_cli_severity_string_table[severity],			\
305 		(cmd_hdr)->err_specific_desc +				\
306 		tw_osl_strlen((cmd_hdr)->err_specific_desc) + 1,	\
307 		(cmd_hdr)->err_specific_desc);				\
308 	/* Print 18 bytes of sense information. */			\
309 	tw_cli_dbg_printf(2, ctlr->ctlr_handle,				\
310 		tw_osl_cur_func(),					\
311 		"sense info: %x %x %x %x %x %x %x %x %x "		\
312 		"%x %x %x %x %x %x %x %x %x",				\
313 		(cmd_hdr)->sense_data[0], (cmd_hdr)->sense_data[1],	\
314 		(cmd_hdr)->sense_data[2], (cmd_hdr)->sense_data[3],	\
315 		(cmd_hdr)->sense_data[4], (cmd_hdr)->sense_data[5],	\
316 		(cmd_hdr)->sense_data[6], (cmd_hdr)->sense_data[7],	\
317 		(cmd_hdr)->sense_data[8], (cmd_hdr)->sense_data[9],	\
318 		(cmd_hdr)->sense_data[10], (cmd_hdr)->sense_data[11],	\
319 		(cmd_hdr)->sense_data[12], (cmd_hdr)->sense_data[13],	\
320 		(cmd_hdr)->sense_data[14], (cmd_hdr)->sense_data[15],	\
321 		(cmd_hdr)->sense_data[16], (cmd_hdr)->sense_data[17]);	\
322 } while (0)
323 
324 #endif /* TW_CL_H */
325