xref: /illumos-gate/usr/src/uts/intel/io/dktp/hba/ghd/ghd.h (revision 012e6ce759c490003aed29439cc47d3d73a99ad3)
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 2004 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 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
34 #include <sys/types.h>
35 #include <sys/conf.h>
36 #include <sys/kmem.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/debug.h>
40 #include <sys/scsi/scsi.h>
41 
42 #include "ghd_queue.h"		/* linked list structures */
43 #include "ghd_scsi.h"
44 #include "ghd_waitq.h"
45 #include "ghd_debug.h"
46 
47 #ifndef	TRUE
48 #define	TRUE	1
49 #endif
50 
51 #ifndef	FALSE
52 #define	FALSE	0
53 #endif
54 
55 /*
56  * values for cmd_state:
57  */
58 
59 typedef enum {
60 	GCMD_STATE_IDLE = 0,
61 	GCMD_STATE_WAITQ,
62 	GCMD_STATE_ACTIVE,
63 	GCMD_STATE_DONEQ,
64 	GCMD_STATE_ABORTING_CMD,
65 	GCMD_STATE_ABORTING_DEV,
66 	GCMD_STATE_RESETTING_DEV,
67 	GCMD_STATE_RESETTING_BUS,
68 	GCMD_STATE_HUNG,
69 	GCMD_NSTATES
70 } cmdstate_t;
71 
72 /*
73  * action codes for the HBA timeout function
74  */
75 
76 typedef enum {
77 	GACTION_EARLY_TIMEOUT = 0,	/* timed-out before started */
78 	GACTION_EARLY_ABORT,		/* scsi_abort() before started */
79 	GACTION_ABORT_CMD,		/* abort a specific request */
80 	GACTION_ABORT_DEV,		/* abort everything on specifici dev */
81 	GACTION_RESET_TARGET,		/* reset a specific dev */
82 	GACTION_RESET_BUS,		/* reset the whole bus */
83 	GACTION_INCOMPLETE		/* giving up on incomplete request */
84 } gact_t;
85 
86 /*
87  * types of ghd_timer_poll() invocations
88  */
89 
90 typedef enum {
91 	GHD_TIMER_POLL_ALL = 0,		/* time out all expired commands */
92 	GHD_TIMER_POLL_ONE		/* time out one, let caller loop */
93 } gtimer_poll_t;
94 
95 /*
96  * the common portion of the Command Control Block
97  */
98 
99 typedef struct ghd_cmd {
100 	L2el_t		 cmd_q;		/* link for for done/active CCB Qs */
101 	cmdstate_t	 cmd_state;	/* request's current state */
102 	ulong_t		 cmd_waitq_level; /* which wait Q this request is on */
103 	int		 cmd_flags;	/* generic magic info */
104 
105 	L2el_t		 cmd_timer_link; /* ccb timer doubly linked list */
106 	ulong_t		 cmd_start_time; /* lbolt at start of request */
107 	ulong_t		 cmd_timeout;	/* how long to wait */
108 
109 	opaque_t	 cmd_private;	/* used by the HBA driver */
110 	void		*cmd_pktp;	/* request packet */
111 	gtgt_t		*cmd_gtgtp;	/* dev instance for this request */
112 
113 	int		 cmd_dma_flags;
114 	ddi_dma_handle_t cmd_dma_handle;
115 	ddi_dma_win_t	 cmd_dmawin;
116 	ddi_dma_seg_t	 cmd_dmaseg;
117 
118 	uint_t		 cmd_wcount;	/* ddi_dma_attr: window count */
119 	uint_t		 cmd_windex;	/* ddi_dma_attr: current window */
120 	uint_t		 cmd_ccount;	/* ddi_dma_attr: cookie count */
121 	uint_t		 cmd_cindex;	/* ddi_dma_attr: current cookie */
122 
123 	long		 cmd_totxfer;	/* # bytes transferred so far */
124 	ddi_dma_cookie_t cmd_first_cookie;
125 	int		 use_first;
126 } gcmd_t;
127 
128 
129 /* definitions for cmd_flags */
130 #define	GCMDFLG_RESET_NOTIFY	1	/* command is a reset notification */
131 
132 /*
133  * Initialize the gcmd_t structure
134  */
135 
136 #define	GHD_GCMD_INIT(gcmdp, cmdp, gtgtp)	\
137 	(L2_INIT(&(gcmdp)->cmd_q),		\
138 	L2_INIT(&(gcmdp)->cmd_timer_link),	\
139 	(gcmdp)->cmd_private = (cmdp),		\
140 	(gcmdp)->cmd_gtgtp = (gtgtp)		\
141 )
142 
143 
144 /*
145  * CMD/CCB timer config structure - one per HBA driver module
146  */
147 typedef struct tmr_conf {
148 	kmutex_t	t_mutex;	/* mutex to protect t_ccc_listp */
149 	timeout_id_t	t_timeout_id;	/* handle for timeout() function */
150 	long		t_ticks;	/* periodic timeout in clock ticks */
151 	int		t_refs;		/* reference count */
152 	struct cmd_ctl	*t_ccc_listp;	/* control struct list, one per HBA */
153 } tmr_t;
154 
155 
156 
157 /*
158  * CMD/CCB timer control structure - one per HBA instance (per board)
159  */
160 typedef struct cmd_ctl {
161 	struct cmd_ctl	*ccc_nextp;	/* list of control structs */
162 	struct tmr_conf	*ccc_tmrp;	/* back ptr to config struct */
163 	char		*ccc_label;	/* name of this HBA driver */
164 
165 	kmutex_t ccc_activel_mutex;	/* mutex to protect list ... */
166 	L2el_t	 ccc_activel;		/* ... list of active CMD/CCBs */
167 
168 	dev_info_t *ccc_hba_dip;
169 	ddi_iblock_cookie_t ccc_iblock;
170 	ddi_softintr_t  ccc_soft_id;	/* ID for timeout softintr */
171 
172 	kmutex_t ccc_hba_mutex;		/* mutex for HBA soft-state */
173 	int	 ccc_hba_pollmode;	/* FLAG_NOINTR mode active? */
174 
175 	L1_t	 ccc_devs;		/* unsorted list of attached devs */
176 	kmutex_t ccc_waitq_mutex;	/* mutex to protect device wait Qs */
177 	Q_t	 ccc_waitq;		/* the HBA's wait queue */
178 	clock_t	 ccc_waitq_freezetime;	/* time the waitq was frozen, ticks */
179 	uint_t	 ccc_waitq_freezedelay;	/* delta time until waitq thaws, ms */
180 
181 	ddi_softintr_t  ccc_doneq_softid; /* ID for doneq softintr */
182 	kmutex_t ccc_doneq_mutex;	/* mutex to protect the doneq */
183 	L2el_t	 ccc_doneq; 		/* completed cmd_t's */
184 
185 	void	*ccc_hba_handle;
186 	int	(*ccc_ccballoc)();	/* alloc/init gcmd and ccb */
187 	void	(*ccc_ccbfree)();
188 	void	(*ccc_sg_func)();
189 	int	(*ccc_hba_start)(void *handle, gcmd_t *);
190 	void    (*ccc_hba_complete)(void *handle, gcmd_t *, int);
191 	void	(*ccc_process_intr)(void *handle, void *intr_status);
192 	int	(*ccc_get_status)(void *handle, void *intr_status);
193 	int	(*ccc_timeout_func)(void *handle, gcmd_t *cmdp, gtgt_t *gtgtp,
194 			gact_t action, int calltype);
195 	void 	(*ccc_hba_reset_notify_callback)(gtgt_t *gtgtp,
196 			void (*callback)(caddr_t),
197 			caddr_t arg);
198 	L2el_t	 ccc_reset_notify_list;	/* list of reset notifications */
199 	kmutex_t ccc_reset_notify_mutex; /* and a mutex to protect it */
200 	char	 ccc_timeout_pending;	/* timeout Q's softintr is triggered */
201 	char	 ccc_waitq_frozen;	/* ccc_waitq_freezetime non-null */
202 	char	 ccc_waitq_held;	/* frozen, but no freezetime */
203 } ccc_t;
204 
205 #define	GHBA_QHEAD(cccp)	((cccp)->ccc_waitq.Q_qhead)
206 #define	GHBA_MAXACTIVE(cccp)	((cccp)->ccc_waitq.Q_maxactive)
207 #define	GHBA_NACTIVE(cccp)	((cccp)->ccc_waitq.Q_nactive)
208 
209 /* Initialize the HBA's list headers */
210 #define	CCCP_INIT(cccp)	{				\
211 		L1HEADER_INIT(&(cccp)->ccc_devs);	\
212 		L2_INIT(&(cccp)->ccc_doneq);		\
213 		L2_INIT(&(cccp)->ccc_reset_notify_list);	\
214 }
215 
216 
217 #define	CCCP2GDEVP(cccp)					\
218 	(L1_EMPTY(&(cccp)->ccc_devs)				\
219 	? (gdev_t *)NULL					\
220 	: (gdev_t *)((cccp)->ccc_devs.l1_headp->le_datap))
221 
222 
223 /*
224  * reset_notify handling: these elements are on the ccc_t's
225  * reset_notify_list, one for each notification requested.  The
226  * gtgtp isn't needed except for debug.
227  */
228 
229 typedef struct ghd_reset_notify_list {
230 	gtgt_t *gtgtp;
231 	void (*callback)(caddr_t);
232 	caddr_t	arg;
233 	L2el_t l2_link;
234 } ghd_reset_notify_list_t;
235 
236 /* ******************************************************************* */
237 
238 #include "ghd_scsa.h"
239 #include "ghd_dma.h"
240 
241 /*
242  * GHD Entry Points
243  */
244 void	 ghd_complete(ccc_t *cccp, gcmd_t *cmdp);
245 void	 ghd_doneq_put_head(ccc_t *cccp, gcmd_t *cmdp);
246 void	 ghd_doneq_put_tail(ccc_t *cccp, gcmd_t *cmdp);
247 
248 int	 ghd_intr(ccc_t *cccp, void *status);
249 int	 ghd_register(char *, ccc_t *, dev_info_t *, int, void *hba_handle,
250 			int (*ccc_ccballoc)(gtgt_t *, gcmd_t *, int, int,
251 					    int, int),
252 			void (*ccc_ccbfree)(gcmd_t *),
253 			void (*ccc_sg_func)(gcmd_t *, ddi_dma_cookie_t *,
254 					    int, int),
255 			int  (*hba_start)(void *, gcmd_t *),
256 			void (*hba_complete)(void *, gcmd_t *, int),
257 			uint_t (*int_handler)(caddr_t),
258 			int  (*get_status)(void *, void *),
259 			void (*process_intr)(void *, void *),
260 			int  (*timeout_func)(void *, gcmd_t *, gtgt_t *,
261 				gact_t, int),
262 			tmr_t *tmrp,
263 			void (*hba_reset_notify_callback)(gtgt_t *,
264 				void (*)(caddr_t), caddr_t));
265 void	ghd_unregister(ccc_t *cccp);
266 
267 int	ghd_transport(ccc_t *cccp, gcmd_t *cmdp, gtgt_t *gtgtp,
268 	    ulong_t timeout, int polled, void *intr_status);
269 
270 int	ghd_tran_abort(ccc_t *cccp, gcmd_t *cmdp, gtgt_t *gtgtp,
271 	    void *intr_status);
272 int	ghd_tran_abort_lun(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status);
273 int	ghd_tran_reset_target(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status);
274 int	ghd_tran_reset_bus(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status);
275 int	ghd_reset_notify(ccc_t *cccp, gtgt_t *gtgtp, int flag,
276 	    void (*callback)(caddr_t), caddr_t arg);
277 void	ghd_freeze_waitq(ccc_t *cccp, int delay);
278 void	ghd_trigger_reset_notify(ccc_t *cccp);
279 
280 void	 ghd_queue_hold(ccc_t *cccp);
281 void	 ghd_queue_unhold(ccc_t *cccp);
282 
283 /*
284  * Allocate a gcmd_t wrapper and HBA private area
285  */
286 gcmd_t	*ghd_gcmd_alloc(gtgt_t *gtgtp, int ccblen, int sleep);
287 
288 /*
289  * Free the gcmd_t wrapper and HBA private area
290  */
291 void	ghd_gcmd_free(gcmd_t *gcmdp);
292 
293 
294 /*
295  * GHD CMD/CCB timer Entry points
296  */
297 
298 int	ghd_timer_attach(ccc_t *cccp, tmr_t *tmrp,
299 	    int (*timeout_func)(void *handle, gcmd_t *, gtgt_t *,
300 	    gact_t, int));
301 void	ghd_timer_detach(ccc_t *cccp);
302 void	ghd_timer_fini(tmr_t *tmrp);
303 void	ghd_timer_init(tmr_t *tmrp, long ticks);
304 void	ghd_timer_newstate(ccc_t *cccp, gcmd_t *cmdp, gtgt_t *gtgtp,
305 	    gact_t action, int calltype);
306 void	ghd_timer_poll(ccc_t *cccp, gtimer_poll_t calltype);
307 void	ghd_timer_start(ccc_t *cccp, gcmd_t *cmdp, long cmd_timeout);
308 void	ghd_timer_stop(ccc_t *cccp, gcmd_t *cmdp);
309 
310 
311 /*
312  * Wait queue utility routines
313  */
314 
315 gtgt_t	*ghd_target_init(dev_info_t *, dev_info_t *, ccc_t *, size_t,
316 	    void *, ushort_t, uchar_t);
317 void	 ghd_target_free(dev_info_t *, dev_info_t *, ccc_t *, gtgt_t *);
318 void	 ghd_waitq_shuffle_up(ccc_t *, gdev_t *);
319 void	 ghd_waitq_delete(ccc_t *, gcmd_t *);
320 int	 ghd_waitq_process_and_mutex_hold(ccc_t *);
321 void	 ghd_waitq_process_and_mutex_exit(ccc_t *);
322 
323 
324 /*
325  * The values for the calltype arg for the ghd_timer_newstate() function,
326  * and the HBA timeout-action function (ccc_timeout_func)
327  */
328 
329 #define	GHD_TGTREQ		0
330 #define	GHD_TIMEOUT		1
331 
332 /* ******************************************************************* */
333 
334 /*
335  * specify GHD_INLINE to get optimized versions
336  */
337 #define	GHD_INLINE	1
338 #if defined(GHD_DEBUG) || defined(DEBUG) || defined(__lint)
339 #undef	GHD_INLINE
340 #endif
341 
342 #if defined(GHD_INLINE)
343 #define	GHD_COMPLETE(cccp, gcmpd)	GHD_COMPLETE_INLINE(cccp, gcmdp)
344 #define	GHD_TIMER_STOP(cccp, gcmdp)	GHD_TIMER_STOP_INLINE(cccp, gcmdp)
345 #define	GHD_DONEQ_PUT_HEAD(cccp, gcmdp)	GHD_DONEQ_PUT_HEAD_INLINE(cccp, gcmdp)
346 #define	GHD_DONEQ_PUT_TAIL(cccp, gcmdp)	GHD_DONEQ_PUT_TAIL_INLINE(cccp, gcmdp)
347 #else
348 #define	GHD_COMPLETE(cccp, gcmpd)	ghd_complete(cccp, gcmdp)
349 #define	GHD_TIMER_STOP(cccp, gcmdp)	ghd_timer_stop(cccp, gcmdp)
350 #define	GHD_DONEQ_PUT_HEAD(cccp, gcmdp)	ghd_doneq_put_head(cccp, gcmdp)
351 #define	GHD_DONEQ_PUT_TAIL(cccp, gcmdp)	ghd_doneq_put_tail(cccp, gcmdp)
352 #endif
353 
354 /*
355  * request is complete, stop the request timer and add to doneq
356  */
357 #define	GHD_COMPLETE_INLINE(cccp, gcmdp)	\
358 {						\
359 	ghd_waitq_delete(cccp, gcmdp);		\
360 	(gcmdp)->cmd_state = GCMD_STATE_DONEQ;	\
361 	GHD_TIMER_STOP((cccp), (gcmdp));	\
362 	GHD_DONEQ_PUT_TAIL((cccp), (gcmdp));	\
363 }
364 
365 #define	GHD_TIMER_STOP_INLINE(cccp, gcmdp)	\
366 {						\
367 	mutex_enter(&(cccp)->ccc_activel_mutex);\
368 	L2_delete(&(gcmdp)->cmd_timer_link);	\
369 	mutex_exit(&(cccp)->ccc_activel_mutex);	\
370 }
371 
372 /*
373  * mark the request done and append it to the head of the doneq
374  */
375 #define	GHD_DONEQ_PUT_HEAD_INLINE(cccp, gcmdp)			\
376 {								\
377 	kmutex_t *doneq_mutexp = &(cccp)->ccc_doneq_mutex;	\
378 								\
379 	mutex_enter(doneq_mutexp);				\
380 	(gcmdp)->cmd_state = GCMD_STATE_DONEQ;			\
381 	L2_add_head(&(cccp)->ccc_doneq, &(gcmdp)->cmd_q, (gcmdp));	\
382 	if (!(cccp)->ccc_hba_pollmode)				\
383 		ddi_trigger_softintr((cccp)->ccc_doneq_softid);	\
384 	mutex_exit(doneq_mutexp);				\
385 }
386 
387 /*
388  * mark the request done and append it to the tail of the doneq
389  */
390 #define	GHD_DONEQ_PUT_TAIL_INLINE(cccp, gcmdp)			\
391 {								\
392 	kmutex_t *doneq_mutexp = &(cccp)->ccc_doneq_mutex;	\
393 								\
394 	mutex_enter(doneq_mutexp);				\
395 	(gcmdp)->cmd_state = GCMD_STATE_DONEQ;			\
396 	L2_add(&(cccp)->ccc_doneq, &(gcmdp)->cmd_q, (gcmdp));	\
397 	if (!(cccp)->ccc_hba_pollmode)				\
398 		ddi_trigger_softintr((cccp)->ccc_doneq_softid);	\
399 	mutex_exit(doneq_mutexp);				\
400 }
401 
402 /* ******************************************************************* */
403 
404 /*
405  * These are shortcut macros for linkages setup by GHD
406  */
407 
408 /*
409  * (gcmd_t *) to (struct scsi_pkt *)
410  */
411 #define	GCMDP2PKTP(gcmdp)	((gcmdp)->cmd_pktp)
412 
413 /*
414  * (gcmd_t *) to (gtgt_t *)
415  */
416 #define	GCMDP2GTGTP(gcmdp)	((gcmdp)->cmd_gtgtp)
417 
418 /*
419  * (gcmd_t *) to (gdev_t *)
420  */
421 #define	GCMDP2GDEVP(gcmdp)	((gcmdp)->cmd_gtgtp->gt_gdevp)
422 
423 /*
424  * (gcmd_t *) to (ccc_t *)
425  */
426 #define	GCMDP2CCCP(gcmdp)	(GCMDP2GTGTP(gcmdp)->gt_ccc)
427 
428 /*
429  * (struct scsi_pkt *) to (gcmd_t *)
430  */
431 #define	PKTP2GCMDP(pktp)	((gcmd_t *)(pktp)->pkt_ha_private)
432 
433 
434 /* These are shortcut macros for linkages setup by SCSA */
435 
436 /*
437  * (struct scsi_address *) to (scsi_hba_tran *)
438  */
439 #define	ADDR2TRAN(ap)		((ap)->a_hba_tran)
440 
441 /*
442  * (struct scsi_device *) to (scsi_address *)
443  */
444 #define	SDEV2ADDR(sdp)		(&(sdp)->sd_address)
445 
446 /*
447  * (struct scsi_device *) to (scsi_hba_tran *)
448  */
449 #define	SDEV2TRAN(sdp)		ADDR2TRAN(SDEV2ADDR(sdp))
450 
451 /*
452  * (struct scsi_pkt *) to (scsi_hba_tran *)
453  */
454 #define	PKTP2TRAN(pktp)		ADDR2TRAN(&(pktp)->pkt_address)
455 
456 /*
457  * (scsi_hba_tran_t *) to (per-target-soft-state *)
458  */
459 #define	TRAN2GTGTP(tranp)	((gtgt_t *)((tranp)->tran_tgt_private))
460 
461 /*
462  * (struct scsi_device *) to (per-target-soft-state *)
463  */
464 #define	SDEV2GTGTP(sd)  	TRAN2GTGTP(SDEV2TRAN(sd))
465 
466 /*
467  * (struct scsi_pkt *) to (per-target-soft-state *)
468  */
469 #define	PKTP2GTGTP(pktp)	TRAN2GTGTP(PKTP2TRAN(pktp))
470 
471 
472 /*
473  * (scsi_hba_tran_t *) to (per-HBA-soft-state *)
474  */
475 #define	TRAN2HBA(tranp)		((tranp)->tran_hba_private)
476 
477 
478 /*
479  * (struct scsi_device *) to (per-HBA-soft-state *)
480  */
481 #define	SDEV2HBA(sd)		TRAN2HBA(SDEV2TRAN(sd))
482 
483 /*
484  * (struct scsi_address *) to (per-target-soft-state *)
485  */
486 #define	ADDR2GTGTP(ap)  	TRAN2GTGTP(ADDR2TRAN(ap))
487 
488 /* ******************************************************************* */
489 
490 
491 #ifdef __cplusplus
492 }
493 #endif
494 
495 #endif /* _GHD_H */
496