17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
58faf39b2Staylor * Common Development and Distribution License (the "License").
68faf39b2Staylor * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21*5bd3d017SNikko He
227c478bd9Sstevel@tonic-gate /*
23*5bd3d017SNikko He * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * Main Transport Routine for SCSA
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
307c478bd9Sstevel@tonic-gate #include <sys/thread.h>
31602ca9eaScth #include <sys/bitmap.h>
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate #define A_TO_TRAN(ap) ((ap)->a_hba_tran)
347c478bd9Sstevel@tonic-gate #define P_TO_TRAN(pkt) ((pkt)->pkt_address.a_hba_tran)
357c478bd9Sstevel@tonic-gate #define P_TO_ADDR(pkt) (&((pkt)->pkt_address))
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate #ifdef DEBUG
387c478bd9Sstevel@tonic-gate #define SCSI_POLL_STAT
397c478bd9Sstevel@tonic-gate #endif
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate #ifdef SCSI_POLL_STAT
427c478bd9Sstevel@tonic-gate int scsi_poll_user;
437c478bd9Sstevel@tonic-gate int scsi_poll_intr;
447c478bd9Sstevel@tonic-gate #endif
457c478bd9Sstevel@tonic-gate
46602ca9eaScth int scsi_pkt_bad_alloc_msg = 1;
47602ca9eaScth extern ulong_t *scsi_pkt_bad_alloc_bitmap;
487c478bd9Sstevel@tonic-gate extern kmutex_t scsi_flag_nointr_mutex;
497c478bd9Sstevel@tonic-gate extern kcondvar_t scsi_flag_nointr_cv;
507c478bd9Sstevel@tonic-gate
51602ca9eaScth extern int do_polled_io;
52602ca9eaScth
53*5bd3d017SNikko He extern int scsi_pkt_allow_naca;
54*5bd3d017SNikko He extern uchar_t scsi_cdb_size[];
55*5bd3d017SNikko He #define NACA_IS_SET(cdb) \
56*5bd3d017SNikko He (((cdb)[scsi_cdb_size[GETGROUP((union scsi_cdb *)(cdb))] - 1] \
57*5bd3d017SNikko He & CDB_FLAG_NACA) ? 1 : 0)
58*5bd3d017SNikko He
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate * we used to set the callback_done value to NULL after the callback
617c478bd9Sstevel@tonic-gate * but this interfered with esp/fas drivers that also set the callback
627c478bd9Sstevel@tonic-gate * to NULL to prevent callbacks during error recovery
631cba8b6cSRandall Ralphs * to prevent confusion, create a truly unique value.
641cba8b6cSRandall Ralphs * The scsi_callback_done() function is used to detect a packet
651cba8b6cSRandall Ralphs * completion being called a second time.
667c478bd9Sstevel@tonic-gate */
671cba8b6cSRandall Ralphs /* ARGSUSED */
681cba8b6cSRandall Ralphs void
scsi_callback_done(struct scsi_pkt * pkt)691cba8b6cSRandall Ralphs scsi_callback_done(struct scsi_pkt *pkt)
701cba8b6cSRandall Ralphs {
711cba8b6cSRandall Ralphs cmn_err(CE_PANIC,
721cba8b6cSRandall Ralphs "%s: duplicate scsi_callback_done() on same scsi_pkt(9s)",
731cba8b6cSRandall Ralphs mod_containing_pc(caller()));
741cba8b6cSRandall Ralphs }
751cba8b6cSRandall Ralphs
761cba8b6cSRandall Ralphs #define CALLBACK_DONE (scsi_callback_done)
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate static void
scsi_flag_nointr_comp(struct scsi_pkt * pkt)797c478bd9Sstevel@tonic-gate scsi_flag_nointr_comp(struct scsi_pkt *pkt)
807c478bd9Sstevel@tonic-gate {
817c478bd9Sstevel@tonic-gate mutex_enter(&scsi_flag_nointr_mutex);
827c478bd9Sstevel@tonic-gate pkt->pkt_comp = CALLBACK_DONE;
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate * We need cv_broadcast, because there can be more
857c478bd9Sstevel@tonic-gate * than one thread sleeping on the cv. We
867c478bd9Sstevel@tonic-gate * will wake all of them. The correct one will
877c478bd9Sstevel@tonic-gate * continue and the rest will again go to sleep.
887c478bd9Sstevel@tonic-gate */
897c478bd9Sstevel@tonic-gate cv_broadcast(&scsi_flag_nointr_cv);
907c478bd9Sstevel@tonic-gate mutex_exit(&scsi_flag_nointr_mutex);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate * A packet can have FLAG_NOINTR set because of target driver or
957c478bd9Sstevel@tonic-gate * scsi_poll(). If FLAG_NOINTR is set and we are in user context,
967c478bd9Sstevel@tonic-gate * we can avoid busy waiting in HBA by replacing the callback
977c478bd9Sstevel@tonic-gate * function with our own function and resetting FLAG_NOINTR. We
987c478bd9Sstevel@tonic-gate * can't do this in interrupt context because cv_wait will
997c478bd9Sstevel@tonic-gate * sleep with CPU priority raised high and in case of some failure,
1007c478bd9Sstevel@tonic-gate * the CPU will be stuck in high priority.
1017c478bd9Sstevel@tonic-gate */
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate int
scsi_transport(struct scsi_pkt * pkt)1047c478bd9Sstevel@tonic-gate scsi_transport(struct scsi_pkt *pkt)
1057c478bd9Sstevel@tonic-gate {
1067c478bd9Sstevel@tonic-gate struct scsi_address *ap = P_TO_ADDR(pkt);
107602ca9eaScth int rval = TRAN_ACCEPT;
108602ca9eaScth major_t major;
109602ca9eaScth
110*5bd3d017SNikko He /*
111*5bd3d017SNikko He * Add an assertion check for debugging as use of the NACA flag
112*5bd3d017SNikko He * can cause problems. If an initiator sets it but does not clear
113*5bd3d017SNikko He * it, other initiators would end up waiting indefinitely for the
114*5bd3d017SNikko He * first to clear ACA.
115*5bd3d017SNikko He */
116*5bd3d017SNikko He if (!scsi_pkt_allow_naca) {
117*5bd3d017SNikko He ASSERT(!NACA_IS_SET(pkt->pkt_cdbp));
118*5bd3d017SNikko He }
119*5bd3d017SNikko He
120602ca9eaScth /*
121602ca9eaScth * The DDI does not allow drivers to allocate their own scsi_pkt(9S),
122602ca9eaScth * a driver can't have *any* compiled in dependencies on the
123602ca9eaScth * "sizeof (struct scsi_pkt)". While this has been the case for years,
124602ca9eaScth * many drivers have still not been fixed (or have regressed - tempted
125602ca9eaScth * by kmem_cache_alloc()). The correct way to allocate a scsi_pkt
126602ca9eaScth * is by calling scsi_hba_pkt_alloc(9F), or by implementing the
127602ca9eaScth * tran_setup_pkt(9E) interfaces.
128602ca9eaScth *
129602ca9eaScth * The code below will identify drivers that violate this rule, and
130602ca9eaScth * print a message. The message will identify broken drivers, and
131602ca9eaScth * encourage getting these drivers fixed - after which this code
132602ca9eaScth * can be removed. Getting HBA drivers fixed is important because
133602ca9eaScth * broken drivers are an impediment to SCSA enhancement.
134602ca9eaScth *
135602ca9eaScth * We use the scsi_pkt_allocated_correctly() to determine if the
136602ca9eaScth * scsi_pkt we are about to start was correctly allocated. The
137602ca9eaScth * scsi_pkt_bad_alloc_bitmap is used to limit messages to one per
138602ca9eaScth * driver per reboot, and with non-debug code we only check the
139602ca9eaScth * first scsi_pkt.
140602ca9eaScth */
141602ca9eaScth if (scsi_pkt_bad_alloc_msg) {
142602ca9eaScth major = ddi_driver_major(P_TO_TRAN(pkt)->tran_hba_dip);
143602ca9eaScth if (!BT_TEST(scsi_pkt_bad_alloc_bitmap, major) &&
144602ca9eaScth !scsi_pkt_allocated_correctly(pkt)) {
145602ca9eaScth BT_SET(scsi_pkt_bad_alloc_bitmap, major);
146602ca9eaScth cmn_err(CE_WARN, "%s: violates DDI scsi_pkt(9S) "
147602ca9eaScth "allocation rules",
148602ca9eaScth ddi_driver_name(P_TO_TRAN(pkt)->tran_hba_dip));
149602ca9eaScth }
150602ca9eaScth #ifndef DEBUG
151602ca9eaScth /* On non-debug kernel, only check the first packet */
152602ca9eaScth BT_SET(scsi_pkt_bad_alloc_bitmap, major);
153602ca9eaScth #endif /* DEBUG */
154602ca9eaScth }
1557c478bd9Sstevel@tonic-gate
1561cba8b6cSRandall Ralphs /* Some retryed packets come with this flag not cleared */
1571cba8b6cSRandall Ralphs pkt->pkt_flags &= ~FLAG_PKT_COMP_CALLED;
1581cba8b6cSRandall Ralphs
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate * Check if we are required to do polled I/O. We can
1617c478bd9Sstevel@tonic-gate * get scsi_pkts that don't have the FLAG_NOINTR bit
1627c478bd9Sstevel@tonic-gate * set in the pkt_flags. When do_polled_io is set
1637c478bd9Sstevel@tonic-gate * we will probably be at a high IPL and not get any
1647c478bd9Sstevel@tonic-gate * command completion interrupts. We force polled I/Os
1657c478bd9Sstevel@tonic-gate * for such packets and do a callback of the completion
1667c478bd9Sstevel@tonic-gate * routine ourselves.
1677c478bd9Sstevel@tonic-gate */
1687c478bd9Sstevel@tonic-gate if (!do_polled_io && ((pkt->pkt_flags & FLAG_NOINTR) == 0)) {
1697c478bd9Sstevel@tonic-gate return (*A_TO_TRAN(ap)->tran_start)(ap, pkt);
1707c478bd9Sstevel@tonic-gate } else if ((curthread->t_flag & T_INTR_THREAD) || do_polled_io) {
1717c478bd9Sstevel@tonic-gate #ifdef SCSI_POLL_STAT
1727c478bd9Sstevel@tonic-gate mutex_enter(&scsi_flag_nointr_mutex);
1737c478bd9Sstevel@tonic-gate scsi_poll_intr++;
1747c478bd9Sstevel@tonic-gate mutex_exit(&scsi_flag_nointr_mutex);
1757c478bd9Sstevel@tonic-gate #endif
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate * If its an interrupt thread or we already have the
1787c478bd9Sstevel@tonic-gate * the FLAG_NOINTR flag set, we go ahead and call the
1797c478bd9Sstevel@tonic-gate * the hba's start routine directly. We force polling
1807c478bd9Sstevel@tonic-gate * only if we have do_polled_io set and FLAG_NOINTR
1817c478bd9Sstevel@tonic-gate * not set.
1827c478bd9Sstevel@tonic-gate */
1837c478bd9Sstevel@tonic-gate if (!do_polled_io || (pkt->pkt_flags & FLAG_NOINTR)) {
1847c478bd9Sstevel@tonic-gate return ((*A_TO_TRAN(ap)->tran_start)(ap, pkt));
1857c478bd9Sstevel@tonic-gate } else {
1867c478bd9Sstevel@tonic-gate uint_t savef;
1877c478bd9Sstevel@tonic-gate void (*savec)();
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate * save the completion routine and pkt_flags
1907c478bd9Sstevel@tonic-gate */
1917c478bd9Sstevel@tonic-gate savef = pkt->pkt_flags;
1927c478bd9Sstevel@tonic-gate savec = pkt->pkt_comp;
1937c478bd9Sstevel@tonic-gate pkt->pkt_flags |= FLAG_NOINTR;
1947c478bd9Sstevel@tonic-gate pkt->pkt_comp = 0;
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate rval = (*A_TO_TRAN(ap)->tran_start)(ap, pkt);
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate /* only continue of transport accepted request */
1997c478bd9Sstevel@tonic-gate if (rval == TRAN_ACCEPT) {
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate * Restore the pkt_completion routine
2027c478bd9Sstevel@tonic-gate * and pkt flags and call the completion
2037c478bd9Sstevel@tonic-gate * routine.
2047c478bd9Sstevel@tonic-gate */
2057c478bd9Sstevel@tonic-gate pkt->pkt_comp = savec;
2067c478bd9Sstevel@tonic-gate pkt->pkt_flags = savef;
207f6715e51Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt);
2087c478bd9Sstevel@tonic-gate return (rval);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate * rval was not TRAN_ACCEPT -- don't want command
2137c478bd9Sstevel@tonic-gate * to be retried
2147c478bd9Sstevel@tonic-gate */
2157c478bd9Sstevel@tonic-gate return (TRAN_FATAL_ERROR);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate } else {
2187c478bd9Sstevel@tonic-gate uint_t savef;
2197c478bd9Sstevel@tonic-gate void (*savec)();
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate #ifdef SCSI_POLL_STAT
2227c478bd9Sstevel@tonic-gate mutex_enter(&scsi_flag_nointr_mutex);
2237c478bd9Sstevel@tonic-gate scsi_poll_user++;
2247c478bd9Sstevel@tonic-gate mutex_exit(&scsi_flag_nointr_mutex);
2257c478bd9Sstevel@tonic-gate #endif
2267c478bd9Sstevel@tonic-gate savef = pkt->pkt_flags;
2277c478bd9Sstevel@tonic-gate savec = pkt->pkt_comp;
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate pkt->pkt_comp = scsi_flag_nointr_comp;
2307c478bd9Sstevel@tonic-gate pkt->pkt_flags &= ~FLAG_NOINTR;
2317c478bd9Sstevel@tonic-gate pkt->pkt_flags |= FLAG_IMMEDIATE_CB;
2327c478bd9Sstevel@tonic-gate
2334c06356bSdh if ((rval = (*A_TO_TRAN(ap)->tran_start)(ap, pkt)) ==
234602ca9eaScth TRAN_ACCEPT) {
2357c478bd9Sstevel@tonic-gate mutex_enter(&scsi_flag_nointr_mutex);
2367c478bd9Sstevel@tonic-gate while (pkt->pkt_comp != CALLBACK_DONE) {
2377c478bd9Sstevel@tonic-gate cv_wait(&scsi_flag_nointr_cv,
238602ca9eaScth &scsi_flag_nointr_mutex);
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate mutex_exit(&scsi_flag_nointr_mutex);
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate pkt->pkt_flags = savef;
2447c478bd9Sstevel@tonic-gate pkt->pkt_comp = savec;
2454c06356bSdh return (rval);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate }
248