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 (c) 1996,1999-2000 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Main Transport Routine for DADA. 31 * 32 */ 33 34 #include <sys/dada/dada.h> 35 #include <sys/thread.h> 36 37 38 #define A_TO_TRAN(ap) ((ap)->a_hba_tran) 39 #define P_TO_TRAN(pkt) ((pkt)->pkt_address.a_hba_tran) 40 #define P_TO_ADDR(pkt) (&((pkt)->pkt_address)) 41 42 43 extern kmutex_t dcd_flag_nointr_mutex; 44 extern kcondvar_t dcd_flag_nointr_cv; 45 46 static void 47 dcd_flag_nointr_comp(struct dcd_pkt *pkt) 48 { 49 50 mutex_enter(&dcd_flag_nointr_mutex); 51 52 pkt->pkt_comp = NULL; 53 54 /* 55 * We need cv_broadcast, because there can be more than 56 * one thread sleeping on the cv. We will wake all of them. 57 * The correct one will continue and the reset will again go to 58 * sleep. 59 */ 60 cv_broadcast(&dcd_flag_nointr_cv); 61 mutex_exit(&dcd_flag_nointr_mutex); 62 } 63 64 65 int 66 dcd_transport(struct dcd_pkt *pkt) 67 { 68 69 struct dcd_address *ap = P_TO_ADDR(pkt); 70 extern int do_polled_io; 71 int rval; 72 73 /* 74 * Check if we are required to do polled I/O. We can 75 * get dcd_pkts that don't have the FLAG_NOINTR bit 76 * set in the pkt_flags. When do_polled_io is set 77 * we will probably be at a high IPL and not get any 78 * command completion interrupts. We force polled I/Os 79 * for such packets and do a callback of the completion 80 * routine ourselves. 81 */ 82 if (!do_polled_io && ((pkt->pkt_flags & FLAG_NOINTR) == 0)) { 83 return ((*A_TO_TRAN(ap)->tran_start)(ap, pkt)); 84 } else if ((curthread->t_flag & T_INTR_THREAD) || (do_polled_io) || 85 (pkt->pkt_flags & FLAG_FORCENOINTR)) { 86 87 if (pkt->pkt_flags & FLAG_FORCENOINTR) { 88 /* 89 * FLAG_FORCENOINTR means we do not want to rely on 90 * device interrupts. Set the FLAG_NOINTR 91 * so the command gets completed in polled mode. 92 */ 93 pkt->pkt_flags &= ~FLAG_FORCENOINTR; 94 pkt->pkt_flags |= FLAG_NOINTR; 95 } 96 97 /* 98 * If its an interrupt thread or we already have the 99 * the FLAG_NOINTR flag set, we go ahead and call the 100 * the hba's start routine directly. We force polling 101 * only if we have do_polled_io set and FLAG_NOINTR 102 * not set. 103 */ 104 if (!do_polled_io || (pkt->pkt_flags & FLAG_NOINTR)) { 105 return ((*A_TO_TRAN(ap)->tran_start)(ap, pkt)); 106 } else { 107 uint_t savef; 108 void (*savec)(); 109 /* 110 * save the completion routine and pkt_flags 111 */ 112 savef = pkt->pkt_flags; 113 savec = pkt->pkt_comp; 114 pkt->pkt_flags |= FLAG_NOINTR; 115 pkt->pkt_comp = 0; 116 117 rval = (*A_TO_TRAN(ap)->tran_start)(ap, pkt); 118 119 /* 120 * Restore the pkt_completion routine 121 * and pkt flags and call the completion 122 * routine. 123 */ 124 pkt->pkt_comp = savec; 125 pkt->pkt_flags = savef; 126 (*pkt->pkt_comp)(pkt); 127 return (rval); 128 } 129 } else { 130 uint_t savef; 131 void (*savec)(); 132 int status; 133 134 savef = pkt->pkt_flags; 135 savec = pkt->pkt_comp; 136 137 pkt->pkt_comp = dcd_flag_nointr_comp; 138 pkt->pkt_flags &= ~FLAG_NOINTR; 139 pkt->pkt_flags |= FLAG_IMMEDIATE_CB; 140 141 if ((status = (*A_TO_TRAN(ap)->tran_start)(ap, pkt)) == 142 TRAN_ACCEPT) { 143 mutex_enter(& dcd_flag_nointr_mutex); 144 while (pkt->pkt_comp != NULL) { 145 cv_wait(&dcd_flag_nointr_cv, 146 &dcd_flag_nointr_mutex); 147 } 148 mutex_exit(&dcd_flag_nointr_mutex); 149 } 150 pkt->pkt_flags = savef; 151 pkt->pkt_comp = savec; 152 return (status); 153 } 154 } 155