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 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 62 fas_destroy_callbacks(struct fas *fas) 63 { 64 mutex_destroy(&fas->f_c_mutex); 65 } 66 67 void 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 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