xref: /illumos-gate/usr/src/uts/sun/sys/dada/adapters/ghd/ghd.h (revision 34a0f871d192b33b865455a8812a3d34c1866315)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #ifndef _GHD_H
28 #define	_GHD_H
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #ifdef	__cplusplus
33 extern "C" {
34 #endif
35 
36 #include <sys/types.h>
37 #include <sys/conf.h>
38 #include <sys/kmem.h>
39 #include <sys/ddi.h>
40 #include <sys/sunddi.h>
41 #include <sys/debug.h>
42 #include <sys/scsi/scsi.h>
43 
44 #include "ghd_queue.h"		/* linked list structures */
45 #include "ghd_scsi.h"
46 #include "ghd_waitq.h"
47 #include "ghd_debug.h"
48 
49 #ifndef	TRUE
50 #define	TRUE	1
51 #endif
52 
53 #ifndef	FALSE
54 #define	FALSE	0
55 #endif
56 
57 /*
58  * values for cmd_state:
59  */
60 
61 typedef enum {
62 	GCMD_STATE_IDLE = 0,
63 	GCMD_STATE_WAITQ,
64 	GCMD_STATE_ACTIVE,
65 	GCMD_STATE_DONEQ,
66 	GCMD_STATE_ABORTING_CMD,
67 	GCMD_STATE_ABORTING_DEV,
68 	GCMD_STATE_RESETTING_DEV,
69 	GCMD_STATE_RESETTING_BUS,
70 	GCMD_STATE_HUNG,
71 	GCMD_NSTATES
72 } cmdstate_t;
73 
74 /*
75  * action codes for the HBA timeout function
76  */
77 
78 typedef enum {
79 	GACTION_EARLY_TIMEOUT = 0,	/* timed-out before started */
80 	GACTION_EARLY_ABORT,		/* scsi_abort() before started */
81 	GACTION_ABORT_CMD,		/* abort a specific request */
82 	GACTION_ABORT_DEV,		/* abort everything on specifici dev */
83 	GACTION_RESET_TARGET,		/* reset a specific dev */
84 	GACTION_RESET_BUS,		/* reset the whole bus */
85 	GACTION_INCOMPLETE		/* giving up on incomplete request */
86 } gact_t;
87 
88 
89 /*
90  * the common portion of the Command Control Block
91  */
92 
93 typedef struct ghd_cmd {
94 	L2el_t		 cmd_q;		/* link for for done/active CCB Qs */
95 	cmdstate_t	 cmd_state;	/* request's current state */
96 	uint32_t	 cmd_waitq_level; /* which wait Q this request is on */
97 
98 	L2el_t		 cmd_timer_link; /* ccb timer doubly linked list */
99 	clock_t		 cmd_start_time; /* lbolt at start of request */
100 	clock_t		 cmd_timeout;	/* how long to wait */
101 
102 	opaque_t	 cmd_private;	/* used by the HBA driver */
103 	void		*cmd_pktp;	/* request packet */
104 	gtgt_t		*cmd_gtgtp;	/* dev instance for this request */
105 
106 	ddi_dma_handle_t cmd_dma_handle;
107 	ddi_dma_win_t	 cmd_dmawin;
108 	ddi_dma_seg_t	 cmd_dmaseg;
109 	int		 cmd_dma_flags;
110 	long		 cmd_totxfer;
111 	long		 cmd_resid;
112 } gcmd_t;
113 
114 
115 
116 
117 /*
118  * Initialize the gcmd_t structure
119  */
120 
121 #define	GHD_GCMD_INIT(gcmdp, cmdp, gtgtp)	\
122 	(L2_INIT(&(gcmdp)->cmd_q),		\
123 	L2_INIT(&(gcmdp)->cmd_timer_link),	\
124 	(gcmdp)->cmd_private = (cmdp),		\
125 	(gcmdp)->cmd_gtgtp = (gtgtp)		\
126 )
127 
128 
129 /*
130  * CMD/CCB timer config structure - one per HBA driver module
131  */
132 typedef struct tmr_conf {
133 	kmutex_t	t_mutex;	/* mutex to protect t_ccc_listp */
134 	timeout_id_t	t_timeout_id;	/* handle for timeout() function */
135 	clock_t		t_ticks;	/* periodic timeout in clock ticks */
136 	int		t_refs;		/* reference count */
137 	struct cmd_ctl	*t_ccc_listp;	/* control struct list, one per HBA */
138 } tmr_t;
139 _NOTE(MUTEX_PROTECTS_DATA(tmr_t::t_mutex, tmr_t::t_ccc_listp))
140 _NOTE(MUTEX_PROTECTS_DATA(tmr_t::t_mutex, tmr_t::t_timeout_id))
141 _NOTE(MUTEX_PROTECTS_DATA(tmr_t::t_mutex, tmr_t::t_refs))
142 
143 
144 
145 /*
146  * CMD/CCB timer control structure - one per HBA instance (per board)
147  */
148 typedef struct cmd_ctl {
149 	struct cmd_ctl	*ccc_nextp;	/* list of control structs */
150 	struct tmr_conf	*ccc_tmrp;	/* back ptr to config struct */
151 	char		*ccc_label;	/* name of this HBA driver */
152 	int		ccc_chno;	/* Channle number */
153 
154 	kmutex_t ccc_activel_mutex;	/* mutex to protect list ... */
155 	L2el_t	 ccc_activel;		/* ... list of active CMD/CCBs */
156 
157 	dev_info_t *ccc_hba_dip;
158 	ddi_iblock_cookie_t ccc_iblock;
159 	ddi_softintr_t  ccc_soft_id;	/* ID for timeout softintr */
160 
161 	kmutex_t ccc_hba_mutex;		/* mutex for HBA soft-state */
162 	int	 ccc_hba_pollmode;	/* FLAG_NOINTR mode active? */
163 
164 	L1_t	 ccc_devs;		/* unsorted list of attached devs */
165 	kmutex_t ccc_waitq_mutex;	/* mutex to protect device wait Qs */
166 	Q_t	 ccc_waitq;		/* the HBA's wait queue */
167 
168 	ddi_softintr_t  ccc_doneq_softid; /* ID for doneq softintr */
169 	kmutex_t ccc_doneq_mutex;	/* mutex to protect the doneq */
170 	L2el_t	 ccc_doneq; 		/* completed cmd_t's */
171 
172 	void	*ccc_hba_handle;
173 	int	(*ccc_ccballoc)();	/* alloc/init gcmd and ccb */
174 	void	(*ccc_ccbfree)();
175 	void	(*ccc_sg_func)();
176 	int	(*ccc_hba_start)(void *handle, gcmd_t *);
177 	void    (*ccc_hba_complete)(void *handle, gcmd_t *, int);
178 	void	(*ccc_process_intr)(void *handle, void *intr_status, int chno);
179 	int	(*ccc_get_status)(void *handle, void *intr_status, int chno);
180 	int	(*ccc_timeout_func)(void *handle, gcmd_t *cmdp, gtgt_t *gtgtp,
181 				    gact_t action, int calltype);
182 } ccc_t;
183 _NOTE(MUTEX_PROTECTS_DATA(cmd_ctl::ccc_activel_mutex, cmd_ctl::ccc_activel))
184 _NOTE(MUTEX_PROTECTS_DATA(cmd_ctl::ccc_hba_mutex, cmd_ctl::ccc_hba_dip))
185 _NOTE(DATA_READABLE_WITHOUT_LOCK(cmd_ctl::ccc_hba_dip))
186 _NOTE(MUTEX_PROTECTS_DATA(cmd_ctl::ccc_waitq_mutex, cmd_ctl::ccc_waitq))
187 _NOTE(MUTEX_PROTECTS_DATA(cmd_ctl::ccc_doneq_mutex, cmd_ctl::ccc_doneq))
188 
189 
190 #define	GHBA_QHEAD(cccp)	((cccp)->ccc_waitq.Q_qhead)
191 #define	GHBA_MAXACTIVE(cccp)	((cccp)->ccc_waitq.Q_maxactive)
192 #define	GHBA_NACTIVE(cccp)	((cccp)->ccc_waitq.Q_nactive)
193 
194 /* Initialize the HBA's list headers */
195 #define	CCCP_INIT(cccp)	{				\
196 		L1HEADER_INIT(&(cccp)->ccc_devs);	\
197 		L2_INIT(&(cccp)->ccc_doneq);		\
198 }
199 
200 
201 #define	CCCP2GDEVP(cccp)					\
202 	(L1_EMPTY(&(cccp)->ccc_devs)				\
203 	? (gdev_t *)NULL					\
204 	: (gdev_t *)((cccp)->ccc_devs.l1_headp->le_datap))
205 
206 /* ******************************************************************* */
207 
208 #include "ghd_scsa.h"
209 
210 /*
211  * GHD Entry Points
212  */
213 void	 ghd_complete(ccc_t *cccp, gcmd_t *cmdp);
214 void	 ghd_async_complete(ccc_t *cccp, gcmd_t *cmdp);
215 void	 ghd_doneq_put(ccc_t *cccp, gcmd_t *cmdp);
216 
217 int	 ghd_intr(ccc_t *cccp, void *status, int chno);
218 int	 ghd_register(char *, ccc_t *, dev_info_t *, int, void *hba_handle,
219 			int (*ccc_ccballoc)(gtgt_t *, gcmd_t *, int, int,
220 					    int, int),
221 			void (*ccc_ccbfree)(gcmd_t *),
222 			void (*ccc_sg_func)(gcmd_t *, ddi_dma_cookie_t *,
223 					    int, int),
224 			int  (*hba_start)(void *, gcmd_t *),
225 			void (*hba_complete)(void *, gcmd_t *, int),
226 			uint_t (*int_handler)(caddr_t),
227 			int  (*get_status)(void *, void *, int),
228 			void (*process_intr)(void *, void *, int),
229 			int  (*timeout_func)(void *, gcmd_t *, gtgt_t *,
230 						gact_t, int calltype),
231 			tmr_t *tmrp,
232 			ddi_iblock_cookie_t iblock,
233 			int chno);
234 void	 ghd_unregister(ccc_t *cccp);
235 
236 int	 ghd_transport(ccc_t *cccp, gcmd_t *cmdp, gtgt_t *gtgtp,
237 		uint32_t timeout, int polled, void *intr_status);
238 
239 int	 ghd_tran_abort(ccc_t *cccp, gcmd_t *cmdp, gtgt_t *gtgtp,
240 				void *intr_status);
241 int	 ghd_tran_abort_lun(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status);
242 int	 ghd_tran_reset_target(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status);
243 int	 ghd_tran_reset_bus(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status);
244 
245 
246 /*
247  * Allocate a gcmd_t wrapper and HBA private area
248  */
249 gcmd_t	*ghd_gcmd_alloc(gtgt_t *gtgtp, int ccblen, int sleep);
250 
251 /*
252  * Free the gcmd_t wrapper and HBA private area
253  */
254 void	ghd_gcmd_free(gcmd_t *gcmdp);
255 
256 
257 /*
258  * GHD CMD/CCB timer Entry points
259  */
260 
261 int	ghd_timer_attach(ccc_t *cccp, tmr_t *tmrp,
262 		int (*timeout_func)(void *handle, gcmd_t *, gtgt_t *,
263 		    gact_t, int));
264 void	ghd_timer_detach(ccc_t *cccp);
265 void	ghd_timer_fini(tmr_t *tmrp);
266 void	ghd_timer_init(tmr_t *tmrp, clock_t ticks);
267 void	ghd_timer_newstate(ccc_t *cccp, gcmd_t *cmdp, gtgt_t *gtgtp,
268 				gact_t action, int calltype);
269 void	ghd_timer_poll(ccc_t *cccp);
270 void	ghd_timer_start(ccc_t *cccp, gcmd_t *cmdp, uint32_t cmd_timeout);
271 void	ghd_timer_stop(ccc_t *cccp, gcmd_t *cmdp);
272 
273 
274 /*
275  * Wait queue utility routines
276  */
277 
278 gtgt_t	*ghd_target_init(dev_info_t *, dev_info_t *, ccc_t *, size_t,
279 				void *, uint32_t, uint32_t);
280 void	 ghd_target_free(dev_info_t *, dev_info_t *, ccc_t *, gtgt_t *);
281 void	 ghd_waitq_shuffle_up(ccc_t *, gdev_t *);
282 void	 ghd_waitq_delete(ccc_t *, gcmd_t *);
283 int	 ghd_waitq_process_and_mutex_hold(ccc_t *);
284 void	 ghd_waitq_process_and_mutex_exit(ccc_t *);
285 
286 
287 /*
288  * The values for the calltype arg for the ghd_timer_newstate() function
289  */
290 
291 #define	GHD_NEWSTATE_TGTREQ	0
292 #define	GHD_NEWSTATE_TIMEOUT	1
293 
294 /* ******************************************************************* */
295 
296 /*
297  * specify GHD_INLINE to get optimized versions
298  */
299 #define	GHD_INLINE	1
300 #if defined(GHD_DEBUG) || defined(DEBUG) || defined(__lint)
301 #undef GHD_INLINE
302 #endif
303 
304 #if defined(GHD_INLINE)
305 #define	GHD_COMPLETE(cccp, gcmpd)	GHD_COMPLETE_INLINE(cccp, gcmdp)
306 #define	GHD_TIMER_STOP(cccp, gcmdp)	GHD_TIMER_STOP_INLINE(cccp, gcmdp)
307 #define	GHD_DONEQ_PUT(cccp, gcmdp)	GHD_DONEQ_PUT_INLINE(cccp, gcmdp)
308 #else
309 #define	GHD_COMPLETE(cccp, gcmpd)	ghd_complete(cccp, gcmdp)
310 #define	GHD_TIMER_STOP(cccp, gcmdp)	ghd_timer_stop(cccp, gcmdp)
311 #define	GHD_DONEQ_PUT(cccp, gcmdp)	ghd_doneq_put(cccp, gcmdp)
312 #endif
313 
314 /*
315  * request is complete, stop the request timer and add to doneq
316  */
317 #define	GHD_COMPLETE_INLINE(cccp, gcmdp)		\
318 {						\
319 	ghd_waitq_delete(cccp, gcmdp);		\
320 	(gcmdp)->cmd_state = GCMD_STATE_DONEQ;	\
321 	GHD_TIMER_STOP((cccp), (gcmdp));	\
322 	GHD_DONEQ_PUT((cccp), (gcmdp));		\
323 }
324 
325 #define	GHD_TIMER_STOP_INLINE(cccp, gcmdp)		\
326 {							\
327 	mutex_enter(&(cccp)->ccc_activel_mutex);	\
328 	L2_delete(&(gcmdp)->cmd_timer_link);		\
329 	mutex_exit(&(cccp)->ccc_activel_mutex);		\
330 }
331 
332 /*
333  * mark the request done and append it to the doneq
334  */
335 #define	GHD_DONEQ_PUT_INLINE(cccp, gcmdp)			\
336 {								\
337 								\
338 	mutex_enter(&(cccp)->ccc_doneq_mutex);			\
339 	(gcmdp)->cmd_state = GCMD_STATE_DONEQ;			\
340 	L2_add(&(cccp)->ccc_doneq, &(gcmdp)->cmd_q, (gcmdp));	\
341 	if (!(cccp)->ccc_hba_pollmode)				\
342 		ddi_trigger_softintr((cccp)->ccc_doneq_softid);	\
343 	mutex_exit(&(cccp)->ccc_doneq_mutex);			\
344 }
345 
346 
347 /* ******************************************************************* */
348 
349 /*
350  * These are shortcut macros for linkages setup by GHD
351  */
352 
353 /*
354  * (gcmd_t *) to (struct scsi_pkt *)
355  */
356 #define	GCMDP2PKTP(gcmdp)	((gcmdp)->cmd_pktp)
357 
358 /*
359  * (gcmd_t *) to (gtgt_t *)
360  */
361 #define	GCMDP2GTGTP(gcmdp)	((gcmdp)->cmd_gtgtp)
362 
363 /*
364  * (struct scsi_pkt *) to (gcmd_t *)
365  */
366 #define	PKTP2GCMDP(pktp)	((gcmd_t *)(pktp)->pkt_ha_private)
367 
368 
369 /* These are shortcut macros for linkages setup by SCSA */
370 
371 /*
372  * (struct scsi_address *) to (scsi_hba_tran *)
373  */
374 #define	ADDR2TRAN(ap)		((ap)->a_hba_tran)
375 
376 /*
377  * (struct scsi_device *) to (scsi_address *)
378  */
379 #define	SDEV2ADDR(sdp)		(&(sdp)->sd_address)
380 
381 /*
382  * (struct scsi_device *) to (scsi_hba_tran *)
383  */
384 #define	SDEV2TRAN(sdp)		ADDR2TRAN(SDEV2ADDR(sdp))
385 
386 /*
387  * (struct scsi_pkt *) to (scsi_hba_tran *)
388  */
389 #define	PKTP2TRAN(pktp)		ADDR2TRAN(&(pktp)->pkt_address)
390 
391 /*
392  * (scsi_hba_tran_t *) to (per-target-soft-state *)
393  */
394 #define	TRAN2GTGTP(tranp)	((gtgt_t *)((tranp)->tran_tgt_private))
395 
396 /*
397  * (struct scsi_device *) to (per-target-soft-state *)
398  */
399 #define	SDEV2GTGTP(sd)  	TRAN2GTGTP(SDEV2TRAN(sd))
400 
401 /*
402  * (struct scsi_pkt *) to (per-target-soft-state *)
403  */
404 #define	PKTP2GTGTP(pktp)	TRAN2GTGTP(PKTP2TRAN(pktp))
405 
406 
407 /*
408  * (scsi_hba_tran_t *) to (per-HBA-soft-state *)
409  */
410 #define	TRAN2HBA(tranp)		((tranp)->tran_hba_private)
411 
412 
413 /*
414  * (struct scsi_device *) to (per-HBA-soft-state *)
415  */
416 #define	SDEV2HBA(sd)		TRAN2HBA(SDEV2TRAN(sd))
417 
418 /*
419  * (struct scsi_address *) to (per-target-soft-state *)
420  */
421 #define	ADDR2GTGTP(ap)  	TRAN2GTGTP(ADDR2TRAN(ap))
422 
423 /* ******************************************************************* */
424 
425 
426 #ifdef	__cplusplus
427 }
428 #endif
429 
430 #endif /* _GHD_H */
431