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