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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * ISSUES
30  */
31 
32 #include <sys/scsi/scsi.h>
33 #include <sys/note.h>
34 #include <sys/scsi/adapters/fasreg.h>
35 #include <sys/scsi/adapters/fasvar.h>
36 #include <sys/scsi/adapters/fascmd.h>
37 
38 #include <sys/vtrace.h>
39 
40 #ifdef	FASDEBUG
41 extern int  fasdebug;
42 extern int  fasdebug_instance; /* debug all instances */
43 #endif	/* FASDEBUG */
44 
45 void fas_complete_arq_pkt(struct scsi_pkt *pkt);
46 void fas_call_pkt_comp(register struct fas *fas,
47     register struct fas_cmd *sp);
48 void fas_empty_callbackQ(struct fas *fas);
49 int fas_init_callbacks(struct fas *fas);
50 void fas_destroy_callbacks(struct fas *fas);
51 void fas_printf(struct fas *fas, const char *fmt, ...);
52 
53 int
fas_init_callbacks(struct fas * fas)54 fas_init_callbacks(struct fas *fas)
55 {
56 	mutex_init(&fas->f_c_mutex, NULL, MUTEX_DRIVER, fas->f_iblock);
57 
58 	return (0);
59 }
60 
61 void
fas_destroy_callbacks(struct fas * fas)62 fas_destroy_callbacks(struct fas *fas)
63 {
64 	mutex_destroy(&fas->f_c_mutex);
65 }
66 
67 void
fas_empty_callbackQ(struct fas * fas)68 fas_empty_callbackQ(struct fas *fas)
69 {
70 	register struct fas_cmd *sp;
71 
72 	TRACE_0(TR_FAC_SCSI, TR_FAS_EMPTY_CALLBACKQ_START,
73 	    "fas_empty_callbackQ_start");
74 
75 	mutex_enter(&fas->f_c_mutex);
76 
77 	/*
78 	 * don't recurse into calling back: the target driver
79 	 * may call scsi_transport() again which may call
80 	 * fas_empty_callbackQ again
81 	 */
82 	if (fas->f_c_in_callback) {
83 		goto done;
84 	}
85 	fas->f_c_in_callback = 1;
86 
87 	while (fas->f_c_qf) {
88 		register struct fas_cmd *qf = fas->f_c_qf;
89 
90 		fas->f_c_qf = fas->f_c_qb = NULL;
91 		mutex_exit(&fas->f_c_mutex);
92 
93 		while (qf) {
94 			sp = qf;
95 			qf =   sp->cmd_forw;
96 			(*sp->cmd_pkt->pkt_comp)(sp->cmd_pkt);
97 		}
98 
99 		mutex_enter(&fas->f_c_mutex);
100 	}
101 
102 	fas->f_c_in_callback = 0;
103 done:
104 	mutex_exit(&fas->f_c_mutex);
105 
106 	TRACE_0(TR_FAC_SCSI, TR_FAS_EMPTY_CALLBACKQ_END,
107 	    "fas_empty_callbackQ_end");
108 }
109 
110 
111 /*
112  * fas_call_pkt_comp does sanity checking to ensure that we don't
113  * call completion twice on the same packet or a packet that has been freed.
114  * if there is a completion function specified, the packet is queued
115  * up and it is left to the fas_callback thread to empty the queue at
116  * a lower priority; note that there is one callback queue per fas
117  *
118  * we use a separate thread for calling back into the target driver
119  * this thread unqueues packets from the callback queue
120  */
121 void
fas_call_pkt_comp(register struct fas * fas,register struct fas_cmd * sp)122 fas_call_pkt_comp(register struct fas *fas, register struct fas_cmd *sp)
123 {
124 	TRACE_0(TR_FAC_SCSI, TR_FAS_CALL_PKT_COMP_START,
125 	    "fas_call_pkt_comp_start");
126 
127 	ASSERT(sp != 0);
128 	ASSERT((sp->cmd_flags & CFLAG_COMPLETED) == 0);
129 	ASSERT((sp->cmd_flags & CFLAG_FREE) == 0);
130 	ASSERT(sp->cmd_flags & CFLAG_FINISHED);
131 	ASSERT(fas->f_ncmds >= fas->f_ndisc);
132 	ASSERT((sp->cmd_flags & CFLAG_CMDDISC) == 0);
133 	ASSERT(sp != fas->f_current_sp);
134 	ASSERT(sp != fas->f_active[sp->cmd_slot]->f_slot[sp->cmd_tag[1]]);
135 
136 	sp->cmd_flags &= ~CFLAG_IN_TRANSPORT;
137 	sp->cmd_flags |= CFLAG_COMPLETED;
138 	sp->cmd_qfull_retries = 0;
139 
140 	/*
141 	 * if this was an auto request sense, complete immediately to free
142 	 * the arq pkt
143 	 */
144 	if (sp->cmd_pkt->pkt_comp && !(sp->cmd_flags & CFLAG_CMDARQ)) {
145 
146 		if (sp->cmd_pkt->pkt_reason != CMD_CMPLT) {
147 			IPRINTF6("completion for %d.%d, sp=0x%p, "
148 			    "reason=%s, stats=%x, state=%x\n",
149 				Tgt(sp), Lun(sp), (void *)sp,
150 				scsi_rname(sp->cmd_pkt->pkt_reason),
151 				sp->cmd_pkt->pkt_statistics,
152 				sp->cmd_pkt->pkt_state);
153 		} else {
154 			EPRINTF2("completion queued for %d.%dn",
155 				Tgt(sp), Lun(sp));
156 		}
157 
158 		/*
159 		 * append the packet or start a new queue
160 		 */
161 		mutex_enter(&fas->f_c_mutex);
162 		if (fas->f_c_qf) {
163 			/*
164 			 * add to tail
165 			 */
166 			register struct fas_cmd *dp = fas->f_c_qb;
167 			ASSERT(dp != NULL);
168 			fas->f_c_qb =	sp;
169 			sp->cmd_forw = NULL;
170 			dp->cmd_forw = sp;
171 		} else {
172 			/*
173 			 * start new queue
174 			 */
175 			fas->f_c_qf = fas->f_c_qb = sp;
176 			sp->cmd_forw = NULL;
177 		}
178 		mutex_exit(&fas->f_c_mutex);
179 
180 	} else if ((sp->cmd_flags & CFLAG_CMDARQ) && sp->cmd_pkt->pkt_comp) {
181 		/*
182 		 * pkt_comp may be NULL when we are aborting/resetting but then
183 		 * the callback will be redone later
184 		 */
185 		fas_complete_arq_pkt(sp->cmd_pkt);
186 
187 	} else	{
188 		EPRINTF2("No completion routine for 0x%p reason %x\n",
189 		    (void *)sp, sp->cmd_pkt->pkt_reason);
190 	}
191 	TRACE_0(TR_FAC_SCSI, TR_FAS_CALL_PKT_COMP_END,
192 	    "fas_call_pkt_comp_end");
193 }
194