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