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
5b50431b8Stl  * Common Development and Distribution License (the "License").
6b50431b8Stl  * 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  */
217c478bd9Sstevel@tonic-gate /*
22bbe671d2SSriram Popuri  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * generic scsi device watch
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #if DEBUG || lint
317c478bd9Sstevel@tonic-gate #define	SWDEBUG
327c478bd9Sstevel@tonic-gate #endif
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * debug goodies
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate #ifdef SWDEBUG
387c478bd9Sstevel@tonic-gate static int swdebug = 0;
397c478bd9Sstevel@tonic-gate #define	DEBUGGING	((scsi_options & SCSI_DEBUG_TGT) && sddebug > 1)
407c478bd9Sstevel@tonic-gate #define	SW_DEBUG	if (swdebug == 1) scsi_log
417c478bd9Sstevel@tonic-gate #define	SW_DEBUG2	if (swdebug > 1) scsi_log
427c478bd9Sstevel@tonic-gate #else	/* SWDEBUG */
437c478bd9Sstevel@tonic-gate #define	swdebug		(0)
447c478bd9Sstevel@tonic-gate #define	DEBUGGING	(0)
457c478bd9Sstevel@tonic-gate #define	SW_DEBUG	if (0) scsi_log
467c478bd9Sstevel@tonic-gate #define	SW_DEBUG2	if (0) scsi_log
477c478bd9Sstevel@tonic-gate #endif
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * Includes, Declarations and Local Data
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include <sys/note.h>
567c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
577c478bd9Sstevel@tonic-gate #include <sys/var.h>
587c478bd9Sstevel@tonic-gate #include <sys/proc.h>
597c478bd9Sstevel@tonic-gate #include <sys/thread.h>
607c478bd9Sstevel@tonic-gate #include <sys/callb.h>
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * macro for filling in lun value for scsi-1 support
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate #define	FILL_SCSI1_LUN(devp, pkt) \
667c478bd9Sstevel@tonic-gate 	if ((devp->sd_address.a_lun > 0) && \
677c478bd9Sstevel@tonic-gate 	    (devp->sd_inq->inq_ansi == 0x1)) { \
687c478bd9Sstevel@tonic-gate 		((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun = \
697c478bd9Sstevel@tonic-gate 		    devp->sd_address.a_lun; \
707c478bd9Sstevel@tonic-gate 	}
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate char *sw_label = "scsi-watch";
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static int scsi_watch_io_time = SCSI_WATCH_IO_TIME;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * all info resides in the scsi watch structure
787c478bd9Sstevel@tonic-gate  *
797c478bd9Sstevel@tonic-gate  * the monitoring is performed by one separate thread which works
807c478bd9Sstevel@tonic-gate  * from a linked list of scsi_watch_request packets
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate static struct scsi_watch {
837c478bd9Sstevel@tonic-gate 	kthread_t		*sw_thread;	/* the watch thread	*/
847c478bd9Sstevel@tonic-gate 	kmutex_t		sw_mutex;	/* mutex protecting list */
857c478bd9Sstevel@tonic-gate 						/* and this structure */
867c478bd9Sstevel@tonic-gate 	kcondvar_t		sw_cv;		/* cv for waking up thread */
877c478bd9Sstevel@tonic-gate 	struct scsi_watch_request *sw_head;	/* head of linked list	*/
887c478bd9Sstevel@tonic-gate 						/* of request structures */
897c478bd9Sstevel@tonic-gate 	uchar_t			sw_state;	/* for suspend-resume */
907c478bd9Sstevel@tonic-gate 	uchar_t			sw_flags;	/* to start at head of list */
917c478bd9Sstevel@tonic-gate 						/* for watch thread */
92b50431b8Stl 	struct scsi_watch_request *swr_current; /* the command waiting to be */
93b50431b8Stl 						/* processed by the watch */
94b50431b8Stl 						/* thread which is being */
95b50431b8Stl 						/* blocked */
967c478bd9Sstevel@tonic-gate } sw;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #if !defined(lint)
997c478bd9Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(scsi_watch::sw_mutex, scsi_watch))
1007c478bd9Sstevel@tonic-gate #endif
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * Values for sw_state
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate #define	SW_RUNNING		0
1067c478bd9Sstevel@tonic-gate #define	SW_SUSPEND_REQUESTED	1
1077c478bd9Sstevel@tonic-gate #define	SW_SUSPENDED		2
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * values for sw_flags
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate #define	SW_START_HEAD		0x1
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate struct scsi_watch_request {
1157c478bd9Sstevel@tonic-gate 	struct scsi_watch_request *swr_next;	/* linked request list	*/
1167c478bd9Sstevel@tonic-gate 	struct scsi_watch_request *swr_prev;
1177c478bd9Sstevel@tonic-gate 	clock_t			swr_interval;	/* interval between TURs */
1187c478bd9Sstevel@tonic-gate 	clock_t			swr_timeout;	/* count down		*/
1197c478bd9Sstevel@tonic-gate 	uchar_t			swr_busy;	/* TUR in progress	*/
1207c478bd9Sstevel@tonic-gate 	uchar_t			swr_what;	/* watch or stop	*/
1217c478bd9Sstevel@tonic-gate 	uchar_t			swr_sense_length; /* required sense length */
1227c478bd9Sstevel@tonic-gate 	struct scsi_pkt		*swr_pkt;	/* TUR pkt itself	*/
1237c478bd9Sstevel@tonic-gate 	struct scsi_pkt		*swr_rqpkt;	/* request sense pkt	*/
1247c478bd9Sstevel@tonic-gate 	struct buf		*swr_rqbp;	/* bp for request sense data */
12597ddcdceSArtem Kachitchkine 	struct buf		*swr_mmcbp;	/* bp for MMC command data */
1267c478bd9Sstevel@tonic-gate 	int			(*swr_callback)(); /* callback to driver */
1277c478bd9Sstevel@tonic-gate 	caddr_t			swr_callback_arg;
1287c478bd9Sstevel@tonic-gate 	kcondvar_t		swr_terminate_cv; /* cv to wait on to cleanup */
1297c478bd9Sstevel@tonic-gate 						/* request synchronously */
130b50431b8Stl 	int			swr_ref;	/*  refer count to the swr */
131b50431b8Stl 	uchar_t			suspend_destroy; /* flag for free later */
1327c478bd9Sstevel@tonic-gate };
1337c478bd9Sstevel@tonic-gate 
134b50431b8Stl /*
135b50431b8Stl  * values for swr flags
136b50431b8Stl  */
137b50431b8Stl #define	SUSPEND_DESTROY		1
138b50431b8Stl 
1397c478bd9Sstevel@tonic-gate #if !defined(lint)
1407c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unshared data", scsi_watch_request))
1417c478bd9Sstevel@tonic-gate #endif
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate  * values for sw_what
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate #define	SWR_WATCH		0	/* device watch */
1477c478bd9Sstevel@tonic-gate #define	SWR_STOP		1	/* stop monitoring and destroy swr */
1487c478bd9Sstevel@tonic-gate #define	SWR_SUSPEND_REQUESTED	2	/* req. pending suspend */
1497c478bd9Sstevel@tonic-gate #define	SWR_SUSPENDED		3	/* req. is suspended */
1507c478bd9Sstevel@tonic-gate 
15197ddcdceSArtem Kachitchkine static opaque_t scsi_watch_request_submit_impl(struct scsi_device *devp,
15297ddcdceSArtem Kachitchkine     int interval, int sense_length, int (*callback)(), caddr_t cb_arg,
15397ddcdceSArtem Kachitchkine     boolean_t mmc);
1547c478bd9Sstevel@tonic-gate static void scsi_watch_request_destroy(struct scsi_watch_request *swr);
1557c478bd9Sstevel@tonic-gate static void scsi_watch_thread(void);
1567c478bd9Sstevel@tonic-gate static void scsi_watch_request_intr(struct scsi_pkt *pkt);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * setup, called from _init(), the thread is created when we need it
1607c478bd9Sstevel@tonic-gate  * and exits when there is nothing to do anymore and everything has been
1617c478bd9Sstevel@tonic-gate  * cleaned up (ie. resources deallocated)
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate void
scsi_watch_init()1647c478bd9Sstevel@tonic-gate scsi_watch_init()
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate /* NO OTHER THREADS ARE RUNNING */
1677c478bd9Sstevel@tonic-gate 	mutex_init(&sw.sw_mutex, NULL, MUTEX_DRIVER, NULL);
1687c478bd9Sstevel@tonic-gate 	cv_init(&sw.sw_cv, NULL, CV_DRIVER, NULL);
1697c478bd9Sstevel@tonic-gate 	sw.sw_state = SW_RUNNING;
1707c478bd9Sstevel@tonic-gate 	sw.sw_flags = 0;
171b50431b8Stl 	sw.swr_current = NULL;
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate  * cleaning up, called from _fini()
1767c478bd9Sstevel@tonic-gate  */
1777c478bd9Sstevel@tonic-gate void
scsi_watch_fini()1787c478bd9Sstevel@tonic-gate scsi_watch_fini()
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate /* NO OTHER THREADS ARE RUNNING */
1817c478bd9Sstevel@tonic-gate 	/*
1827c478bd9Sstevel@tonic-gate 	 * hope and pray that the thread has exited
1837c478bd9Sstevel@tonic-gate 	 */
1847c478bd9Sstevel@tonic-gate 	ASSERT(sw.sw_thread == 0);
1857c478bd9Sstevel@tonic-gate 	mutex_destroy(&sw.sw_mutex);
1867c478bd9Sstevel@tonic-gate 	cv_destroy(&sw.sw_cv);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate  * allocate an swr (scsi watch request structure) and initialize pkts
1917c478bd9Sstevel@tonic-gate  */
1927c478bd9Sstevel@tonic-gate #define	ROUTE		&devp->sd_address
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate opaque_t
scsi_watch_request_submit(struct scsi_device * devp,int interval,int sense_length,int (* callback)(),caddr_t cb_arg)1957c478bd9Sstevel@tonic-gate scsi_watch_request_submit(
1967c478bd9Sstevel@tonic-gate 	struct scsi_device	*devp,
1977c478bd9Sstevel@tonic-gate 	int			interval,
1987c478bd9Sstevel@tonic-gate 	int			sense_length,
1997c478bd9Sstevel@tonic-gate 	int			(*callback)(),	/* callback function */
2007c478bd9Sstevel@tonic-gate 	caddr_t			cb_arg)		/* device number */
20197ddcdceSArtem Kachitchkine {
20297ddcdceSArtem Kachitchkine 	return (scsi_watch_request_submit_impl(devp, interval, sense_length,
20397ddcdceSArtem Kachitchkine 	    callback, cb_arg, B_FALSE));
20497ddcdceSArtem Kachitchkine }
20597ddcdceSArtem Kachitchkine 
20697ddcdceSArtem Kachitchkine opaque_t
scsi_mmc_watch_request_submit(struct scsi_device * devp,int interval,int sense_length,int (* callback)(),caddr_t cb_arg)20797ddcdceSArtem Kachitchkine scsi_mmc_watch_request_submit(
20897ddcdceSArtem Kachitchkine 	struct scsi_device	*devp,
20997ddcdceSArtem Kachitchkine 	int			interval,
21097ddcdceSArtem Kachitchkine 	int			sense_length,
21197ddcdceSArtem Kachitchkine 	int			(*callback)(),	/* callback function */
21297ddcdceSArtem Kachitchkine 	caddr_t			cb_arg)		/* device number */
21397ddcdceSArtem Kachitchkine {
21497ddcdceSArtem Kachitchkine 	return (scsi_watch_request_submit_impl(devp, interval, sense_length,
21597ddcdceSArtem Kachitchkine 	    callback, cb_arg, B_TRUE));
21697ddcdceSArtem Kachitchkine }
21797ddcdceSArtem Kachitchkine 
21897ddcdceSArtem Kachitchkine static opaque_t
scsi_watch_request_submit_impl(struct scsi_device * devp,int interval,int sense_length,int (* callback)(),caddr_t cb_arg,boolean_t mmc)21997ddcdceSArtem Kachitchkine scsi_watch_request_submit_impl(
22097ddcdceSArtem Kachitchkine 	struct scsi_device	*devp,
22197ddcdceSArtem Kachitchkine 	int			interval,
22297ddcdceSArtem Kachitchkine 	int			sense_length,
22397ddcdceSArtem Kachitchkine 	int			(*callback)(),	/* callback function */
22497ddcdceSArtem Kachitchkine 	caddr_t			cb_arg,		/* device number */
22597ddcdceSArtem Kachitchkine 	boolean_t		mmc)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	register struct scsi_watch_request	*swr = NULL;
2287c478bd9Sstevel@tonic-gate 	register struct scsi_watch_request	*sswr, *p;
2297c478bd9Sstevel@tonic-gate 	struct buf				*bp = NULL;
23097ddcdceSArtem Kachitchkine 	struct buf				*mmcbp = NULL;
2317c478bd9Sstevel@tonic-gate 	struct scsi_pkt				*rqpkt = NULL;
2327c478bd9Sstevel@tonic-gate 	struct scsi_pkt				*pkt = NULL;
2337c478bd9Sstevel@tonic-gate 	uchar_t					dtype;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
236b50431b8Stl 	    "scsi_watch_request_submit: Entering ...\n");
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
2397c478bd9Sstevel@tonic-gate 	if (sw.sw_thread == 0) {
2407c478bd9Sstevel@tonic-gate 		register kthread_t	*t;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 		t = thread_create((caddr_t)NULL, 0, scsi_watch_thread,
243b50431b8Stl 		    NULL, 0, &p0, TS_RUN, v.v_maxsyspri - 2);
2447c478bd9Sstevel@tonic-gate 		sw.sw_thread = t;
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	for (p = sw.sw_head; p != NULL; p = p->swr_next) {
2487c478bd9Sstevel@tonic-gate 		if ((p->swr_callback_arg == cb_arg) &&
249b50431b8Stl 		    (p->swr_callback == callback))
2507c478bd9Sstevel@tonic-gate 			break;
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	/* update time interval for an existing request */
2547c478bd9Sstevel@tonic-gate 	if (p) {
255b50431b8Stl 		if (p->swr_what != SWR_STOP) {
256b50431b8Stl 			p->swr_timeout = p->swr_interval
257b50431b8Stl 			    = drv_usectohz(interval);
258b50431b8Stl 			p->swr_what = SWR_WATCH;
259b50431b8Stl 			p->swr_ref++;
260b50431b8Stl 			cv_signal(&sw.sw_cv);
261b50431b8Stl 			mutex_exit(&sw.sw_mutex);
262b50431b8Stl 			return ((opaque_t)p);
263b50431b8Stl 		}
2647c478bd9Sstevel@tonic-gate 	}
2657c478bd9Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	/*
2687c478bd9Sstevel@tonic-gate 	 * allocate space for scsi_watch_request
2697c478bd9Sstevel@tonic-gate 	 */
2707c478bd9Sstevel@tonic-gate 	swr = kmem_zalloc(sizeof (struct scsi_watch_request), KM_SLEEP);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/*
2737c478bd9Sstevel@tonic-gate 	 * allocate request sense bp and pkt and make cmd
2747c478bd9Sstevel@tonic-gate 	 * we shouldn't really need it if ARQ is enabled but it is useful
2757c478bd9Sstevel@tonic-gate 	 * if the ARQ failed.
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 	bp = scsi_alloc_consistent_buf(ROUTE, NULL,
278b50431b8Stl 	    sense_length, B_READ, SLEEP_FUNC, NULL);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	rqpkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
281b50431b8Stl 	    bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT, SLEEP_FUNC, NULL);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	(void) scsi_setup_cdb((union scsi_cdb *)rqpkt->pkt_cdbp,
2847c478bd9Sstevel@tonic-gate 	    SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0);
2857c478bd9Sstevel@tonic-gate 	FILL_SCSI1_LUN(devp, rqpkt);
2867c478bd9Sstevel@tonic-gate 	rqpkt->pkt_private = (opaque_t)swr;
2877c478bd9Sstevel@tonic-gate 	rqpkt->pkt_time = scsi_watch_io_time;
2887c478bd9Sstevel@tonic-gate 	rqpkt->pkt_comp = scsi_watch_request_intr;
2897c478bd9Sstevel@tonic-gate 	rqpkt->pkt_flags |= FLAG_HEAD;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	/*
29297ddcdceSArtem Kachitchkine 	 * Create TUR pkt or GET STATUS EVENT NOTIFICATION for MMC requests or
29397ddcdceSArtem Kachitchkine 	 * a zero byte WRITE(10) based on the disk-type for reservation state.
2947c478bd9Sstevel@tonic-gate 	 * For inq_dtype of SBC (DIRECT, dtype == 0)
2957c478bd9Sstevel@tonic-gate 	 * OR for RBC devices (dtype is 0xE) AND for
2967c478bd9Sstevel@tonic-gate 	 * ANSI version of SPC/SPC-2/SPC-3 (inq_ansi == 3-5).
2977c478bd9Sstevel@tonic-gate 	 */
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	dtype = devp->sd_inq->inq_dtype & DTYPE_MASK;
30097ddcdceSArtem Kachitchkine 	if (mmc) {
30197ddcdceSArtem Kachitchkine 		mmcbp = scsi_alloc_consistent_buf(ROUTE, NULL,
30297ddcdceSArtem Kachitchkine 		    8, B_READ, SLEEP_FUNC, NULL);
30397ddcdceSArtem Kachitchkine 
30497ddcdceSArtem Kachitchkine 		pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, mmcbp,
30597ddcdceSArtem Kachitchkine 		    CDB_GROUP1, sizeof (struct scsi_arq_status),
30697ddcdceSArtem Kachitchkine 		    0, 0, SLEEP_FUNC, NULL);
30797ddcdceSArtem Kachitchkine 
30897ddcdceSArtem Kachitchkine 		(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
30997ddcdceSArtem Kachitchkine 		    SCMD_GET_EVENT_STATUS_NOTIFICATION, 0, 8, 0);
31097ddcdceSArtem Kachitchkine 		pkt->pkt_cdbp[1] = 1; /* polled */
31197ddcdceSArtem Kachitchkine 		pkt->pkt_cdbp[4] = 1 << SD_GESN_MEDIA_CLASS;
31297ddcdceSArtem Kachitchkine 	} else if (((dtype == 0) || (dtype == 0xE)) &&
313b50431b8Stl 	    (devp->sd_inq->inq_ansi > 2)) {
3147c478bd9Sstevel@tonic-gate 		pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, NULL,
315b50431b8Stl 		    CDB_GROUP1, sizeof (struct scsi_arq_status),
316b50431b8Stl 		    0, 0, SLEEP_FUNC, NULL);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 		(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
319b50431b8Stl 		    SCMD_WRITE_G1, 0, 0, 0);
3207c478bd9Sstevel@tonic-gate 	} else {
3217c478bd9Sstevel@tonic-gate 		pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, NULL,
322b50431b8Stl 		    CDB_GROUP0, sizeof (struct scsi_arq_status),
323b50431b8Stl 		    0, 0, SLEEP_FUNC, NULL);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 		(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
326b50431b8Stl 		    SCMD_TEST_UNIT_READY, 0, 0, 0);
3277c478bd9Sstevel@tonic-gate 		FILL_SCSI1_LUN(devp, pkt);
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	pkt->pkt_private = (opaque_t)swr;
3317c478bd9Sstevel@tonic-gate 	pkt->pkt_time = scsi_watch_io_time;
3327c478bd9Sstevel@tonic-gate 	pkt->pkt_comp = scsi_watch_request_intr;
3337c478bd9Sstevel@tonic-gate 	if (scsi_ifgetcap(&pkt->pkt_address, "tagged-qing", 1) == 1) {
3347c478bd9Sstevel@tonic-gate 		pkt->pkt_flags |= FLAG_STAG;
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	/*
3387c478bd9Sstevel@tonic-gate 	 * set the allocated resources in swr
3397c478bd9Sstevel@tonic-gate 	 */
3407c478bd9Sstevel@tonic-gate 	swr->swr_rqbp = bp;
3417c478bd9Sstevel@tonic-gate 	swr->swr_rqpkt = rqpkt;
34297ddcdceSArtem Kachitchkine 	swr->swr_mmcbp = mmcbp;
3437c478bd9Sstevel@tonic-gate 	swr->swr_pkt = pkt;
3447c478bd9Sstevel@tonic-gate 	swr->swr_timeout = swr->swr_interval = drv_usectohz(interval);
3457c478bd9Sstevel@tonic-gate 	swr->swr_callback = callback;
3467c478bd9Sstevel@tonic-gate 	swr->swr_callback_arg = cb_arg;
3477c478bd9Sstevel@tonic-gate 	swr->swr_what = SWR_WATCH;
3487c478bd9Sstevel@tonic-gate 	swr->swr_sense_length = (uchar_t)sense_length;
349b50431b8Stl 	swr->swr_ref = 1;
3507c478bd9Sstevel@tonic-gate 	cv_init(&swr->swr_terminate_cv, NULL, CV_DRIVER, NULL);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/*
3537c478bd9Sstevel@tonic-gate 	 * add to the list and wake up the thread
3547c478bd9Sstevel@tonic-gate 	 */
3557c478bd9Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
3567c478bd9Sstevel@tonic-gate 	swr->swr_next = sw.sw_head;
3577c478bd9Sstevel@tonic-gate 	swr->swr_prev = NULL;
3587c478bd9Sstevel@tonic-gate 	if (sw.sw_head) {
3597c478bd9Sstevel@tonic-gate 		sw.sw_head->swr_prev = swr;
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 	sw.sw_head = swr;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	/*
3647c478bd9Sstevel@tonic-gate 	 * reset all timeouts, so all requests are in sync again
3657c478bd9Sstevel@tonic-gate 	 * XXX there is a small window where the watch thread releases
3667c478bd9Sstevel@tonic-gate 	 * the mutex so that could upset the resyncing
3677c478bd9Sstevel@tonic-gate 	 */
3687c478bd9Sstevel@tonic-gate 	sswr = swr;
3697c478bd9Sstevel@tonic-gate 	while (sswr) {
3707c478bd9Sstevel@tonic-gate 		sswr->swr_timeout = swr->swr_interval;
3717c478bd9Sstevel@tonic-gate 		sswr = sswr->swr_next;
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 	cv_signal(&sw.sw_cv);
3747c478bd9Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
3757c478bd9Sstevel@tonic-gate 	return ((opaque_t)swr);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate  * called by (eg. pwr management) to resume the scsi_watch_thread
3817c478bd9Sstevel@tonic-gate  */
3827c478bd9Sstevel@tonic-gate void
scsi_watch_resume(opaque_t token)3837c478bd9Sstevel@tonic-gate scsi_watch_resume(opaque_t token)
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 	struct scsi_watch_request *swr = (struct scsi_watch_request *)NULL;
3867c478bd9Sstevel@tonic-gate 	/*
3877c478bd9Sstevel@tonic-gate 	 * Change the state to SW_RUNNING and wake up the scsi_watch_thread
3887c478bd9Sstevel@tonic-gate 	 */
3897c478bd9Sstevel@tonic-gate 	SW_DEBUG(0, sw_label, SCSI_DEBUG, "scsi_watch_resume:\n");
3907c478bd9Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	if (!sw.sw_head)
3937c478bd9Sstevel@tonic-gate 		goto exit;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/* search for token */
3967c478bd9Sstevel@tonic-gate 	for (swr = sw.sw_head; swr; swr = swr->swr_next) {
3977c478bd9Sstevel@tonic-gate 		if (swr == (struct scsi_watch_request *)token)
3987c478bd9Sstevel@tonic-gate 			break;
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/* if we can't find this value, then we just do nothing */
4027c478bd9Sstevel@tonic-gate 	if (swr == (struct scsi_watch_request *)NULL)
4037c478bd9Sstevel@tonic-gate 		goto exit;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	swr->swr_what = SWR_WATCH;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	/* see if all swr's are awake, then start the thread again */
4097c478bd9Sstevel@tonic-gate 	for (swr = sw.sw_head; swr; swr = swr->swr_next) {
4107c478bd9Sstevel@tonic-gate 		if (swr->swr_what != SWR_WATCH)
4117c478bd9Sstevel@tonic-gate 			goto exit;
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	sw.sw_state = SW_RUNNING;
4157c478bd9Sstevel@tonic-gate 	cv_signal(&sw.sw_cv);
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate exit:
4187c478bd9Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate /*
4237c478bd9Sstevel@tonic-gate  * called by clients (eg. pwr management) to suspend the scsi_watch_thread
4247c478bd9Sstevel@tonic-gate  */
4257c478bd9Sstevel@tonic-gate void
scsi_watch_suspend(opaque_t token)4267c478bd9Sstevel@tonic-gate scsi_watch_suspend(opaque_t token)
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate 	struct scsi_watch_request *swr = (struct scsi_watch_request *)NULL;
4297c478bd9Sstevel@tonic-gate 	clock_t halfsec_delay = drv_usectohz(500000);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	SW_DEBUG(0, sw_label, SCSI_DEBUG, "scsi_watch_suspend:\n");
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if (!sw.sw_head)
4367c478bd9Sstevel@tonic-gate 		goto exit;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	/* search for token */
4397c478bd9Sstevel@tonic-gate 	for (swr = sw.sw_head; swr; swr = swr->swr_next) {
4407c478bd9Sstevel@tonic-gate 		if (swr == (struct scsi_watch_request *)token)
4417c478bd9Sstevel@tonic-gate 			break;
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	/* if we can't find this value, then we just do nothing */
4457c478bd9Sstevel@tonic-gate 	if (swr == (struct scsi_watch_request *)NULL)
4467c478bd9Sstevel@tonic-gate 		goto exit;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	for (;;) {
4507c478bd9Sstevel@tonic-gate 		if (swr->swr_busy) {
4517c478bd9Sstevel@tonic-gate 			/*
4527c478bd9Sstevel@tonic-gate 			 * XXX: Assumes that this thread can rerun
4537c478bd9Sstevel@tonic-gate 			 * till all outstanding cmds are complete
4547c478bd9Sstevel@tonic-gate 			 */
4557c478bd9Sstevel@tonic-gate 			swr->swr_what = SWR_SUSPEND_REQUESTED;
456*d3d50737SRafael Vanoni 			(void) cv_reltimedwait(&sw.sw_cv, &sw.sw_mutex,
457*d3d50737SRafael Vanoni 			    halfsec_delay, TR_CLOCK_TICK);
4587c478bd9Sstevel@tonic-gate 		} else {
4597c478bd9Sstevel@tonic-gate 			swr->swr_what = SWR_SUSPENDED;
4607c478bd9Sstevel@tonic-gate 			break;
4617c478bd9Sstevel@tonic-gate 		}
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	/* see if all swr's are suspended, then suspend the thread */
4657c478bd9Sstevel@tonic-gate 	for (swr = sw.sw_head; swr; swr = swr->swr_next) {
4667c478bd9Sstevel@tonic-gate 		if (swr->swr_what != SWR_SUSPENDED)
4677c478bd9Sstevel@tonic-gate 			goto exit;
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	sw.sw_state = SW_SUSPENDED;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate exit:
4737c478bd9Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate  * destroy swr, called for watch thread
4787c478bd9Sstevel@tonic-gate  */
4797c478bd9Sstevel@tonic-gate static void
scsi_watch_request_destroy(struct scsi_watch_request * swr)4807c478bd9Sstevel@tonic-gate scsi_watch_request_destroy(struct scsi_watch_request *swr)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&sw.sw_mutex));
4837c478bd9Sstevel@tonic-gate 	ASSERT(swr->swr_busy == 0);
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
486b50431b8Stl 	    "scsi_watch_request_destroy: Entering ...\n");
487b50431b8Stl 	if (swr->swr_ref != 0)
488b50431b8Stl 		return;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	/*
4917c478bd9Sstevel@tonic-gate 	 * remove swr from linked list and destroy pkts
4927c478bd9Sstevel@tonic-gate 	 */
4937c478bd9Sstevel@tonic-gate 	if (swr->swr_prev) {
4947c478bd9Sstevel@tonic-gate 		swr->swr_prev->swr_next = swr->swr_next;
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 	if (swr->swr_next) {
4977c478bd9Sstevel@tonic-gate 		swr->swr_next->swr_prev = swr->swr_prev;
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 	if (sw.sw_head == swr) {
5007c478bd9Sstevel@tonic-gate 		sw.sw_head = swr->swr_next;
5017c478bd9Sstevel@tonic-gate 	}
502b50431b8Stl 	if (sw.swr_current == swr) {
503b50431b8Stl 		swr->suspend_destroy = SUSPEND_DESTROY;
504b50431b8Stl 		sw.swr_current = NULL;
505b50431b8Stl 	}
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	scsi_destroy_pkt(swr->swr_rqpkt);
5087c478bd9Sstevel@tonic-gate 	scsi_free_consistent_buf(swr->swr_rqbp);
50997ddcdceSArtem Kachitchkine 	if (swr->swr_mmcbp != NULL) {
51097ddcdceSArtem Kachitchkine 		scsi_free_consistent_buf(swr->swr_mmcbp);
51197ddcdceSArtem Kachitchkine 	}
5127c478bd9Sstevel@tonic-gate 	scsi_destroy_pkt(swr->swr_pkt);
5137c478bd9Sstevel@tonic-gate 	cv_signal(&swr->swr_terminate_cv);
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate /*
5177c478bd9Sstevel@tonic-gate  * scsi_watch_request_terminate()
5187c478bd9Sstevel@tonic-gate  * called by requestor to terminate any pending watch request.
5197c478bd9Sstevel@tonic-gate  * if the request is currently "busy", and the caller cannot wait, failure
5207c478bd9Sstevel@tonic-gate  * is returned. O/w the request is cleaned up immediately.
5217c478bd9Sstevel@tonic-gate  */
5227c478bd9Sstevel@tonic-gate int
scsi_watch_request_terminate(opaque_t token,int flags)5237c478bd9Sstevel@tonic-gate scsi_watch_request_terminate(opaque_t token, int flags)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate 	struct scsi_watch_request *swr =
526b50431b8Stl 	    (struct scsi_watch_request *)token;
5277c478bd9Sstevel@tonic-gate 	struct scsi_watch_request *sswr;
5287c478bd9Sstevel@tonic-gate 
529b50431b8Stl 	int count = 0;
530b50431b8Stl 	int free_flag = 0;
531b50431b8Stl 
5327c478bd9Sstevel@tonic-gate 	/*
5337c478bd9Sstevel@tonic-gate 	 * We try to clean up this request if we can. We also inform
5347c478bd9Sstevel@tonic-gate 	 * the watch thread that we mucked around the list so it has
5357c478bd9Sstevel@tonic-gate 	 * to start reading from head of list again.
5367c478bd9Sstevel@tonic-gate 	 */
5377c478bd9Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
538b50431b8Stl 	    "scsi_watch_request_terminate: Entering(0x%p) ...\n",
539b50431b8Stl 	    (void *)swr);
5407c478bd9Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	/*
5437c478bd9Sstevel@tonic-gate 	 * check if it is still in the list
5447c478bd9Sstevel@tonic-gate 	 */
5457c478bd9Sstevel@tonic-gate 	sswr = sw.sw_head;
5467c478bd9Sstevel@tonic-gate 	while (sswr) {
5477c478bd9Sstevel@tonic-gate 		if (sswr == swr) {
548b50431b8Stl 			swr->swr_ref--;
549b50431b8Stl 			count = swr->swr_ref;
550b50431b8Stl 
5517c478bd9Sstevel@tonic-gate 			if (swr->swr_busy) {
5527c478bd9Sstevel@tonic-gate 				if (flags == SCSI_WATCH_TERMINATE_NOWAIT) {
5537c478bd9Sstevel@tonic-gate 					mutex_exit(&sw.sw_mutex);
5547c478bd9Sstevel@tonic-gate 					return (SCSI_WATCH_TERMINATE_FAIL);
5557c478bd9Sstevel@tonic-gate 				}
556b50431b8Stl 				if (count != 0 && flags !=
557b50431b8Stl 				    SCSI_WATCH_TERMINATE_ALL_WAIT) {
558b50431b8Stl 					mutex_exit(&sw.sw_mutex);
559b50431b8Stl 					return (SCSI_WATCH_TERMINATE_SUCCESS);
560b50431b8Stl 				}
561b50431b8Stl 				if (SCSI_WATCH_TERMINATE_ALL_WAIT == flags) {
562b50431b8Stl 					swr->swr_ref = 0;
563b50431b8Stl 					count = 0;
564b50431b8Stl 				}
565b50431b8Stl 				swr->swr_what = SWR_STOP;
566b50431b8Stl 				cv_wait(&swr->swr_terminate_cv, &sw.sw_mutex);
567b50431b8Stl 				free_flag = 1;
568b50431b8Stl 				goto done;
5697c478bd9Sstevel@tonic-gate 			} else {
570b50431b8Stl 				if (SCSI_WATCH_TERMINATE_NOWAIT == flags ||
571b50431b8Stl 				    SCSI_WATCH_TERMINATE_ALL_WAIT == flags) {
572b50431b8Stl 					swr->swr_ref = 0;
573b50431b8Stl 					count = 0;
574b50431b8Stl 				}
5757c478bd9Sstevel@tonic-gate 				scsi_watch_request_destroy(swr);
576b50431b8Stl 				if (0 == count) {
577b50431b8Stl 					sw.sw_flags |= SW_START_HEAD;
578b50431b8Stl 					free_flag = 1;
579b50431b8Stl 				}
5807c478bd9Sstevel@tonic-gate 				goto done;
5817c478bd9Sstevel@tonic-gate 			}
5827c478bd9Sstevel@tonic-gate 		}
5837c478bd9Sstevel@tonic-gate 		sswr = sswr->swr_next;
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate done:
5867c478bd9Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
587b50431b8Stl 	if (!sswr) {
588b50431b8Stl 		return (SCSI_WATCH_TERMINATE_FAIL);
589b50431b8Stl 	}
590b50431b8Stl 	if (1 == free_flag &&
591b50431b8Stl 	    sswr->suspend_destroy != SUSPEND_DESTROY) {
5927c478bd9Sstevel@tonic-gate 		cv_destroy(&swr->swr_terminate_cv);
5937c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)swr, sizeof (struct scsi_watch_request));
5947c478bd9Sstevel@tonic-gate 	}
595b50431b8Stl 
596b50431b8Stl 	return (SCSI_WATCH_TERMINATE_SUCCESS);
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate /*
6017c478bd9Sstevel@tonic-gate  * The routines scsi_watch_thread & scsi_watch_request_intr are
6027c478bd9Sstevel@tonic-gate  * on different threads.
6037c478bd9Sstevel@tonic-gate  * If there is no work to be done by the lower level driver
6047c478bd9Sstevel@tonic-gate  * then swr->swr_busy will not be set.
6057c478bd9Sstevel@tonic-gate  * In this case we will call CALLB_CPR_SAFE_BEGIN before
6067c478bd9Sstevel@tonic-gate  * calling cv_timedwait.
6077c478bd9Sstevel@tonic-gate  * In the other case where there is work to be done by
6087c478bd9Sstevel@tonic-gate  * the lower level driver then the flag swr->swr_busy will
6097c478bd9Sstevel@tonic-gate  * be set.
6107c478bd9Sstevel@tonic-gate  * We cannot call CALLB_CPR_SAFE_BEGIN at this point the reason
6117c478bd9Sstevel@tonic-gate  * is the intr thread can interfere with our operations. So
6127c478bd9Sstevel@tonic-gate  * we do a cv_timedwait here. Now at the completion of the
6137c478bd9Sstevel@tonic-gate  * lower level driver's work we will call CALLB_CPR_SAFE_BEGIN
6147c478bd9Sstevel@tonic-gate  * in scsi_watch_request_intr.
6157c478bd9Sstevel@tonic-gate  * In all the cases we will call CALLB_CPR_SAFE_END only if
6167c478bd9Sstevel@tonic-gate  * we already called a CALLB_CPR_SAFE_BEGIN and this is flagged
6177c478bd9Sstevel@tonic-gate  * by sw_cpr_flag.
6187c478bd9Sstevel@tonic-gate  * Warlock has a problem when we use different locks
6197c478bd9Sstevel@tonic-gate  * on the same type of structure in different contexts.
6207c478bd9Sstevel@tonic-gate  * We use callb_cpr_t in both scsi_watch and esp_callback threads.
6217c478bd9Sstevel@tonic-gate  * we use different mutexe's in different threads. And
6227c478bd9Sstevel@tonic-gate  * this is not acceptable to warlock. To avoid this
6237c478bd9Sstevel@tonic-gate  * problem we use the same name for the mutex in
6247c478bd9Sstevel@tonic-gate  * both scsi_watch & esp_callback. when __lock_lint is not defined
6257c478bd9Sstevel@tonic-gate  * esp_callback uses the mutex on the stack and in scsi_watch
6267c478bd9Sstevel@tonic-gate  * a static variable. But when __lock_lint is defined
6277c478bd9Sstevel@tonic-gate  * we make a mutex which is global in esp_callback and
6287c478bd9Sstevel@tonic-gate  * a external mutex for scsi_watch.
6297c478bd9Sstevel@tonic-gate  */
6307c478bd9Sstevel@tonic-gate static int sw_cmd_count = 0;
6317c478bd9Sstevel@tonic-gate static int sw_cpr_flag = 0;
6327c478bd9Sstevel@tonic-gate static callb_cpr_t cpr_info;
6337c478bd9Sstevel@tonic-gate #ifndef __lock_lint
6347c478bd9Sstevel@tonic-gate static kmutex_t cpr_mutex;
6357c478bd9Sstevel@tonic-gate #else
6367c478bd9Sstevel@tonic-gate extern kmutex_t cpr_mutex;
6377c478bd9Sstevel@tonic-gate #endif
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate #if !defined(lint)
6407c478bd9Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(cpr_mutex, cpr_info))
_NOTE(MUTEX_PROTECTS_DATA (cpr_mutex,sw_cmd_count))6417c478bd9Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(cpr_mutex, sw_cmd_count))
6427c478bd9Sstevel@tonic-gate #endif
6437c478bd9Sstevel@tonic-gate /*
6447c478bd9Sstevel@tonic-gate  * the scsi watch thread:
6457c478bd9Sstevel@tonic-gate  * it either wakes up if there is work to do or if the cv_timeait
6467c478bd9Sstevel@tonic-gate  * timed out
6477c478bd9Sstevel@tonic-gate  * normally, it wakes up every <delay> seconds and checks the list.
6487c478bd9Sstevel@tonic-gate  * the interval is not very accurate if the cv was signalled but that
6497c478bd9Sstevel@tonic-gate  * really doesn't matter much
6507c478bd9Sstevel@tonic-gate  * it is more important that we fire off all TURs simulataneously so
6517c478bd9Sstevel@tonic-gate  * we don't have to wake up frequently
6527c478bd9Sstevel@tonic-gate  */
6537c478bd9Sstevel@tonic-gate static void
6547c478bd9Sstevel@tonic-gate scsi_watch_thread()
6557c478bd9Sstevel@tonic-gate {
6567c478bd9Sstevel@tonic-gate 	struct scsi_watch_request	*swr, *next;
6577c478bd9Sstevel@tonic-gate 	clock_t				last_delay = 0;
6587c478bd9Sstevel@tonic-gate 	clock_t				next_delay = 0;
6597c478bd9Sstevel@tonic-gate 	clock_t				onesec = drv_usectohz(1000000);
6607c478bd9Sstevel@tonic-gate 	clock_t				exit_delay = 60 * onesec;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
663b50431b8Stl 	    "scsi_watch_thread: Entering ...\n");
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate #if !defined(lint)
6667c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
6677c478bd9Sstevel@tonic-gate #endif
6687c478bd9Sstevel@tonic-gate 	mutex_init(&cpr_mutex, NULL, MUTEX_DRIVER, NULL);
6697c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cpr_info,
670b50431b8Stl 	    &cpr_mutex, callb_generic_cpr, "scsi_watch");
6717c478bd9Sstevel@tonic-gate 	sw_cpr_flag = 0;
6727c478bd9Sstevel@tonic-gate #if !defined(lint)
6737c478bd9Sstevel@tonic-gate 	/*LINTED*/
6747c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
6757c478bd9Sstevel@tonic-gate #endif
6767c478bd9Sstevel@tonic-gate 	/*
6777c478bd9Sstevel@tonic-gate 	 * grab the mutex and wait for work
6787c478bd9Sstevel@tonic-gate 	 */
6797c478bd9Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
6807c478bd9Sstevel@tonic-gate 	if (sw.sw_head == NULL) {
6817c478bd9Sstevel@tonic-gate 		cv_wait(&sw.sw_cv, &sw.sw_mutex);
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	/*
6857c478bd9Sstevel@tonic-gate 	 * now loop forever for work; if queue is empty exit
6867c478bd9Sstevel@tonic-gate 	 */
6877c478bd9Sstevel@tonic-gate 	for (;;) {
6887c478bd9Sstevel@tonic-gate head:
6897c478bd9Sstevel@tonic-gate 		swr = sw.sw_head;
6907c478bd9Sstevel@tonic-gate 		while (swr) {
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 			/*
6937c478bd9Sstevel@tonic-gate 			 * If state is not running, wait for scsi_watch_resume
6947c478bd9Sstevel@tonic-gate 			 * to signal restart, but before going into cv_wait
6957c478bd9Sstevel@tonic-gate 			 * need to let the PM framework know that it is safe
6967c478bd9Sstevel@tonic-gate 			 * to stop this thread for CPR
6977c478bd9Sstevel@tonic-gate 			 */
6987c478bd9Sstevel@tonic-gate 			if (sw.sw_state != SW_RUNNING) {
6997c478bd9Sstevel@tonic-gate 				SW_DEBUG(0, sw_label, SCSI_DEBUG,
700b50431b8Stl 				    "scsi_watch_thread suspended\n");
7017c478bd9Sstevel@tonic-gate 				mutex_enter(&cpr_mutex);
7027c478bd9Sstevel@tonic-gate 				if (!sw_cmd_count) {
7037c478bd9Sstevel@tonic-gate 					CALLB_CPR_SAFE_BEGIN(&cpr_info);
7047c478bd9Sstevel@tonic-gate 					sw_cpr_flag = 1;
7057c478bd9Sstevel@tonic-gate 				}
7067c478bd9Sstevel@tonic-gate 				mutex_exit(&cpr_mutex);
707b50431b8Stl 				sw.swr_current = swr;
7087c478bd9Sstevel@tonic-gate 				cv_wait(&sw.sw_cv, &sw.sw_mutex);
709b50431b8Stl 
710b50431b8Stl 
7117c478bd9Sstevel@tonic-gate 				/*
7127c478bd9Sstevel@tonic-gate 				 * Need to let the PM framework know that it
7137c478bd9Sstevel@tonic-gate 				 * is no longer safe to stop the thread for
7147c478bd9Sstevel@tonic-gate 				 * CPR.
7157c478bd9Sstevel@tonic-gate 				 */
7167c478bd9Sstevel@tonic-gate 				mutex_exit(&sw.sw_mutex);
7177c478bd9Sstevel@tonic-gate 				mutex_enter(&cpr_mutex);
7187c478bd9Sstevel@tonic-gate 				if (sw_cpr_flag == 1) {
7197c478bd9Sstevel@tonic-gate 					CALLB_CPR_SAFE_END(
720b50431b8Stl 					    &cpr_info, &cpr_mutex);
7217c478bd9Sstevel@tonic-gate 					sw_cpr_flag = 0;
7227c478bd9Sstevel@tonic-gate 				}
7237c478bd9Sstevel@tonic-gate 				mutex_exit(&cpr_mutex);
7247c478bd9Sstevel@tonic-gate 				mutex_enter(&sw.sw_mutex);
725b50431b8Stl 				if (SUSPEND_DESTROY == swr->suspend_destroy) {
726b50431b8Stl 					cv_destroy(&swr->swr_terminate_cv);
727b50431b8Stl 					kmem_free((caddr_t)swr,
728b50431b8Stl 					    sizeof (struct scsi_watch_request));
729b50431b8Stl 					goto head;
730b50431b8Stl 				} else {
731b50431b8Stl 					sw.swr_current = NULL;
732b50431b8Stl 				}
7337c478bd9Sstevel@tonic-gate 			}
7347c478bd9Sstevel@tonic-gate 			if (next_delay == 0) {
7357c478bd9Sstevel@tonic-gate 				next_delay = swr->swr_timeout;
7367c478bd9Sstevel@tonic-gate 			} else {
7377c478bd9Sstevel@tonic-gate 				next_delay = min(swr->swr_timeout, next_delay);
7387c478bd9Sstevel@tonic-gate 			}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 			swr->swr_timeout -= last_delay;
7417c478bd9Sstevel@tonic-gate 			next = swr->swr_next;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 			SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
744b50431b8Stl 			    "scsi_watch_thread: "
745b50431b8Stl 			    "swr(0x%p),what=%x,timeout=%lx,"
746b50431b8Stl 			    "interval=%lx,delay=%lx\n",
747b50431b8Stl 			    (void *)swr, swr->swr_what, swr->swr_timeout,
748b50431b8Stl 			    swr->swr_interval, last_delay);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 			switch (swr->swr_what) {
7517c478bd9Sstevel@tonic-gate 			case SWR_SUSPENDED:
7527c478bd9Sstevel@tonic-gate 			case SWR_SUSPEND_REQUESTED:
7537c478bd9Sstevel@tonic-gate 				/* if we are suspended, don't do anything */
7547c478bd9Sstevel@tonic-gate 				break;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 			case SWR_STOP:
7577c478bd9Sstevel@tonic-gate 				if (swr->swr_busy == 0) {
7587c478bd9Sstevel@tonic-gate 					scsi_watch_request_destroy(swr);
7597c478bd9Sstevel@tonic-gate 				}
7607c478bd9Sstevel@tonic-gate 				break;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 			default:
7637c478bd9Sstevel@tonic-gate 				if (swr->swr_timeout <= 0 && !swr->swr_busy) {
7647c478bd9Sstevel@tonic-gate 					swr->swr_busy = 1;
765bbe671d2SSriram Popuri 					swr->swr_timeout = swr->swr_interval;
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 					/*
7687c478bd9Sstevel@tonic-gate 					 * submit the cmd and let the completion
7697c478bd9Sstevel@tonic-gate 					 * function handle the result
7707c478bd9Sstevel@tonic-gate 					 * release the mutex (good practice)
7717c478bd9Sstevel@tonic-gate 					 * this should be safe even if the list
7727c478bd9Sstevel@tonic-gate 					 * is changing
7737c478bd9Sstevel@tonic-gate 					 */
7747c478bd9Sstevel@tonic-gate 					mutex_exit(&sw.sw_mutex);
7757c478bd9Sstevel@tonic-gate 					mutex_enter(&cpr_mutex);
7767c478bd9Sstevel@tonic-gate 					sw_cmd_count++;
7777c478bd9Sstevel@tonic-gate 					mutex_exit(&cpr_mutex);
7787c478bd9Sstevel@tonic-gate 					SW_DEBUG((dev_info_t *)NULL,
779b50431b8Stl 					    sw_label, SCSI_DEBUG,
780b50431b8Stl 					    "scsi_watch_thread: "
781b50431b8Stl 					    "Starting TUR\n");
7827c478bd9Sstevel@tonic-gate 					if (scsi_transport(swr->swr_pkt) !=
783b50431b8Stl 					    TRAN_ACCEPT) {
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 						/*
7867c478bd9Sstevel@tonic-gate 						 * try again later
7877c478bd9Sstevel@tonic-gate 						 */
7887c478bd9Sstevel@tonic-gate 						swr->swr_busy = 0;
7897c478bd9Sstevel@tonic-gate 						SW_DEBUG((dev_info_t *)NULL,
790b50431b8Stl 						    sw_label, SCSI_DEBUG,
791b50431b8Stl 						    "scsi_watch_thread: "
792b50431b8Stl 						    "Transport Failed\n");
7937c478bd9Sstevel@tonic-gate 						mutex_enter(&cpr_mutex);
7947c478bd9Sstevel@tonic-gate 						sw_cmd_count--;
7957c478bd9Sstevel@tonic-gate 						mutex_exit(&cpr_mutex);
7967c478bd9Sstevel@tonic-gate 					}
7977c478bd9Sstevel@tonic-gate 					mutex_enter(&sw.sw_mutex);
7987c478bd9Sstevel@tonic-gate 				}
7997c478bd9Sstevel@tonic-gate 				break;
8007c478bd9Sstevel@tonic-gate 			}
8017c478bd9Sstevel@tonic-gate 			swr = next;
8027c478bd9Sstevel@tonic-gate 			if (sw.sw_flags & SW_START_HEAD) {
8037c478bd9Sstevel@tonic-gate 				sw.sw_flags &= ~SW_START_HEAD;
8047c478bd9Sstevel@tonic-gate 				goto head;
8057c478bd9Sstevel@tonic-gate 			}
8067c478bd9Sstevel@tonic-gate 		}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 		/*
8097c478bd9Sstevel@tonic-gate 		 * delay using cv_timedwait; we return when
8107c478bd9Sstevel@tonic-gate 		 * signalled or timed out
8117c478bd9Sstevel@tonic-gate 		 */
8127c478bd9Sstevel@tonic-gate 		if (sw.sw_head != NULL) {
8137c478bd9Sstevel@tonic-gate 			if (next_delay <= 0) {
8147c478bd9Sstevel@tonic-gate 				next_delay = onesec;
8157c478bd9Sstevel@tonic-gate 			}
8167c478bd9Sstevel@tonic-gate 		} else {
8177c478bd9Sstevel@tonic-gate 			next_delay = exit_delay;
8187c478bd9Sstevel@tonic-gate 		}
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 		mutex_enter(&cpr_mutex);
8217c478bd9Sstevel@tonic-gate 		if (!sw_cmd_count) {
8227c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cpr_info);
8237c478bd9Sstevel@tonic-gate 			sw_cpr_flag = 1;
8247c478bd9Sstevel@tonic-gate 		}
8257c478bd9Sstevel@tonic-gate 		mutex_exit(&cpr_mutex);
8267c478bd9Sstevel@tonic-gate 		/*
8277c478bd9Sstevel@tonic-gate 		 * if we return from cv_timedwait because we were
8287c478bd9Sstevel@tonic-gate 		 * signalled, the delay is not accurate but that doesn't
8297c478bd9Sstevel@tonic-gate 		 * really matter
8307c478bd9Sstevel@tonic-gate 		 */
831*d3d50737SRafael Vanoni 		(void) cv_reltimedwait(&sw.sw_cv, &sw.sw_mutex, next_delay,
832*d3d50737SRafael Vanoni 		    TR_CLOCK_TICK);
8337c478bd9Sstevel@tonic-gate 		mutex_exit(&sw.sw_mutex);
8347c478bd9Sstevel@tonic-gate 		mutex_enter(&cpr_mutex);
8357c478bd9Sstevel@tonic-gate 		if (sw_cpr_flag == 1) {
8367c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cpr_info, &cpr_mutex);
8377c478bd9Sstevel@tonic-gate 			sw_cpr_flag = 0;
8387c478bd9Sstevel@tonic-gate 		}
8397c478bd9Sstevel@tonic-gate 		mutex_exit(&cpr_mutex);
8407c478bd9Sstevel@tonic-gate 		mutex_enter(&sw.sw_mutex);
8417c478bd9Sstevel@tonic-gate 		last_delay = next_delay;
8427c478bd9Sstevel@tonic-gate 		next_delay = 0;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 		/*
8457c478bd9Sstevel@tonic-gate 		 * is there still work to do?
8467c478bd9Sstevel@tonic-gate 		 */
8477c478bd9Sstevel@tonic-gate 		if (sw.sw_head == NULL) {
8487c478bd9Sstevel@tonic-gate 			break;
8497c478bd9Sstevel@tonic-gate 		}
8507c478bd9Sstevel@tonic-gate 	}
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	/*
8537c478bd9Sstevel@tonic-gate 	 * no more work to do, reset sw_thread and exit
8547c478bd9Sstevel@tonic-gate 	 */
8557c478bd9Sstevel@tonic-gate 	sw.sw_thread = 0;
8567c478bd9Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
8577c478bd9Sstevel@tonic-gate #ifndef __lock_lint
8587c478bd9Sstevel@tonic-gate 	mutex_enter(&cpr_mutex);
8597c478bd9Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cpr_info);
8607c478bd9Sstevel@tonic-gate #endif
8617c478bd9Sstevel@tonic-gate 	mutex_destroy(&cpr_mutex);
8627c478bd9Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
863b50431b8Stl 	    "scsi_watch_thread: Exiting ...\n");
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate /*
8677c478bd9Sstevel@tonic-gate  * callback completion function for scsi watch pkt
8687c478bd9Sstevel@tonic-gate  */
8697c478bd9Sstevel@tonic-gate #define	SCBP(pkt)	((struct scsi_status *)(pkt)->pkt_scbp)
8707c478bd9Sstevel@tonic-gate #define	SCBP_C(pkt)	((*(pkt)->pkt_scbp) & STATUS_MASK)
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate static void
scsi_watch_request_intr(struct scsi_pkt * pkt)8737c478bd9Sstevel@tonic-gate scsi_watch_request_intr(struct scsi_pkt *pkt)
8747c478bd9Sstevel@tonic-gate {
8757c478bd9Sstevel@tonic-gate 	struct scsi_watch_result	result;
8767c478bd9Sstevel@tonic-gate 	struct scsi_watch_request	*swr =
877b50431b8Stl 	    (struct scsi_watch_request *)pkt->pkt_private;
8787c478bd9Sstevel@tonic-gate 	struct scsi_status		*rqstatusp;
8797c478bd9Sstevel@tonic-gate 	struct scsi_extended_sense	*rqsensep = NULL;
8807c478bd9Sstevel@tonic-gate 	int				amt = 0;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
883b50431b8Stl 	    "scsi_watch_intr: Entering ...\n");
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	/*
8867c478bd9Sstevel@tonic-gate 	 * first check if it is the TUR or RQS pkt
8877c478bd9Sstevel@tonic-gate 	 */
8887c478bd9Sstevel@tonic-gate 	if (pkt == swr->swr_pkt) {
8897c478bd9Sstevel@tonic-gate 		if (SCBP_C(pkt) != STATUS_GOOD &&
890b50431b8Stl 		    SCBP_C(pkt) != STATUS_RESERVATION_CONFLICT) {
8917c478bd9Sstevel@tonic-gate 			if (SCBP(pkt)->sts_chk &&
8927c478bd9Sstevel@tonic-gate 			    ((pkt->pkt_state & STATE_ARQ_DONE) == 0)) {
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 				/*
8957c478bd9Sstevel@tonic-gate 				 * submit the request sense pkt
8967c478bd9Sstevel@tonic-gate 				 */
8977c478bd9Sstevel@tonic-gate 				SW_DEBUG((dev_info_t *)NULL,
898b50431b8Stl 				    sw_label, SCSI_DEBUG,
899b50431b8Stl 				    "scsi_watch_intr: "
900b50431b8Stl 				    "Submitting a Request Sense "
901b50431b8Stl 				    "Packet\n");
9027c478bd9Sstevel@tonic-gate 				if (scsi_transport(swr->swr_rqpkt) !=
903b50431b8Stl 				    TRAN_ACCEPT) {
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 					/*
9067c478bd9Sstevel@tonic-gate 					 * just give up and try again later
9077c478bd9Sstevel@tonic-gate 					 */
9087c478bd9Sstevel@tonic-gate 					SW_DEBUG((dev_info_t *)NULL,
909b50431b8Stl 					    sw_label, SCSI_DEBUG,
910b50431b8Stl 					    "scsi_watch_intr: "
911b50431b8Stl 					    "Request Sense "
912b50431b8Stl 					    "Transport Failed\n");
9137c478bd9Sstevel@tonic-gate 					goto done;
9147c478bd9Sstevel@tonic-gate 				}
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 				/*
9177c478bd9Sstevel@tonic-gate 				 * wait for rqsense to complete
9187c478bd9Sstevel@tonic-gate 				 */
9197c478bd9Sstevel@tonic-gate 				return;
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 			} else	if (SCBP(pkt)->sts_chk) {
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 				/*
9247c478bd9Sstevel@tonic-gate 				 * check the autorequest sense data
9257c478bd9Sstevel@tonic-gate 				 */
9267c478bd9Sstevel@tonic-gate 				struct scsi_arq_status	*arqstat =
9277c478bd9Sstevel@tonic-gate 				    (struct scsi_arq_status *)pkt->pkt_scbp;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 				rqstatusp = &arqstat->sts_rqpkt_status;
9307c478bd9Sstevel@tonic-gate 				rqsensep = &arqstat->sts_sensedata;
9317c478bd9Sstevel@tonic-gate 				amt = swr->swr_sense_length -
932b50431b8Stl 				    arqstat->sts_rqpkt_resid;
9337c478bd9Sstevel@tonic-gate 				SW_DEBUG((dev_info_t *)NULL,
934b50431b8Stl 				    sw_label, SCSI_DEBUG,
935b50431b8Stl 				    "scsi_watch_intr: "
936b50431b8Stl 				    "Auto Request Sense, amt=%x\n", amt);
9377c478bd9Sstevel@tonic-gate 			}
9387c478bd9Sstevel@tonic-gate 		}
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	} else if (pkt == swr->swr_rqpkt) {
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 		/*
9437c478bd9Sstevel@tonic-gate 		 * check the request sense data
9447c478bd9Sstevel@tonic-gate 		 */
9457c478bd9Sstevel@tonic-gate 		rqstatusp = (struct scsi_status *)pkt->pkt_scbp;
9467c478bd9Sstevel@tonic-gate 		rqsensep = (struct scsi_extended_sense *)
947b50431b8Stl 		    swr->swr_rqbp->b_un.b_addr;
9487c478bd9Sstevel@tonic-gate 		amt = swr->swr_sense_length - pkt->pkt_resid;
9497c478bd9Sstevel@tonic-gate 		SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
950b50431b8Stl 		    "scsi_watch_intr: "
951b50431b8Stl 		    "Request Sense Completed, amt=%x\n", amt);
9527c478bd9Sstevel@tonic-gate 	} else {
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 		/*
9557c478bd9Sstevel@tonic-gate 		 * should not reach here!!!
9567c478bd9Sstevel@tonic-gate 		 */
9577c478bd9Sstevel@tonic-gate 		scsi_log((dev_info_t *)NULL, sw_label, CE_PANIC,
958b50431b8Stl 		    "scsi_watch_intr: Bad Packet(0x%p)", (void *)pkt);
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	if (rqsensep) {
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 		/*
9647c478bd9Sstevel@tonic-gate 		 * check rqsense status and data
9657c478bd9Sstevel@tonic-gate 		 */
9667c478bd9Sstevel@tonic-gate 		if (rqstatusp->sts_busy || rqstatusp->sts_chk) {
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 			/*
9697c478bd9Sstevel@tonic-gate 			 * try again later
9707c478bd9Sstevel@tonic-gate 			 */
9717c478bd9Sstevel@tonic-gate 			SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
972b50431b8Stl 			    "scsi_watch_intr: "
973b50431b8Stl 			    "Auto Request Sense Failed - "
974b50431b8Stl 			    "Busy or Check Condition\n");
9757c478bd9Sstevel@tonic-gate 			goto done;
9767c478bd9Sstevel@tonic-gate 		}
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 		SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
979b50431b8Stl 		    "scsi_watch_intr: "
980b50431b8Stl 		    "es_key=%x, adq=%x, amt=%x\n",
981b50431b8Stl 		    rqsensep->es_key, rqsensep->es_add_code, amt);
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	/*
9857c478bd9Sstevel@tonic-gate 	 * callback to target driver to do the real work
9867c478bd9Sstevel@tonic-gate 	 */
9877c478bd9Sstevel@tonic-gate 	result.statusp = SCBP(swr->swr_pkt);
9887c478bd9Sstevel@tonic-gate 	result.sensep = rqsensep;
9897c478bd9Sstevel@tonic-gate 	result.actual_sense_length = (uchar_t)amt;
9907c478bd9Sstevel@tonic-gate 	result.pkt = swr->swr_pkt;
99197ddcdceSArtem Kachitchkine 	if (swr->swr_mmcbp != NULL) {
99297ddcdceSArtem Kachitchkine 		bcopy(swr->swr_mmcbp->b_un.b_addr, result.mmc_data, 8);
99397ddcdceSArtem Kachitchkine 	}
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	if ((*swr->swr_callback)(swr->swr_callback_arg, &result)) {
9967c478bd9Sstevel@tonic-gate 		swr->swr_what = SWR_STOP;
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate done:
10007c478bd9Sstevel@tonic-gate 	swr->swr_busy = 0;
10017c478bd9Sstevel@tonic-gate 	mutex_enter(&cpr_mutex);
10027c478bd9Sstevel@tonic-gate 	sw_cmd_count --;
10037c478bd9Sstevel@tonic-gate 	if (!sw_cmd_count) {
10047c478bd9Sstevel@tonic-gate 		CALLB_CPR_SAFE_BEGIN(&cpr_info);
10057c478bd9Sstevel@tonic-gate 		sw_cpr_flag = 1;
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 	mutex_exit(&cpr_mutex);
10087c478bd9Sstevel@tonic-gate }
1009257b6b01Syu, larry liu - Sun Microsystems - Beijing China 
1010257b6b01Syu, larry liu - Sun Microsystems - Beijing China /*
1011257b6b01Syu, larry liu - Sun Microsystems - Beijing China  * scsi_watch_get_ref_count
1012257b6b01Syu, larry liu - Sun Microsystems - Beijing China  * called by clients to query the reference count for a given token.
1013257b6b01Syu, larry liu - Sun Microsystems - Beijing China  * return the number of reference count or 0 if the given token is
1014257b6b01Syu, larry liu - Sun Microsystems - Beijing China  * not found.
1015257b6b01Syu, larry liu - Sun Microsystems - Beijing China  */
1016257b6b01Syu, larry liu - Sun Microsystems - Beijing China int
scsi_watch_get_ref_count(opaque_t token)1017257b6b01Syu, larry liu - Sun Microsystems - Beijing China scsi_watch_get_ref_count(opaque_t token)
1018257b6b01Syu, larry liu - Sun Microsystems - Beijing China {
1019257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	struct scsi_watch_request *swr =
1020257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	    (struct scsi_watch_request *)token;
1021257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	struct scsi_watch_request *sswr;
1022257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	int rval = 0;
1023257b6b01Syu, larry liu - Sun Microsystems - Beijing China 
1024257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
1025257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	    "scsi_watch_get_ref_count: Entering(0x%p) ...\n",
1026257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	    (void *)swr);
1027257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	mutex_enter(&sw.sw_mutex);
1028257b6b01Syu, larry liu - Sun Microsystems - Beijing China 
1029257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	sswr = sw.sw_head;
1030257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	while (sswr) {
1031257b6b01Syu, larry liu - Sun Microsystems - Beijing China 		if (sswr == swr) {
1032257b6b01Syu, larry liu - Sun Microsystems - Beijing China 			rval = swr->swr_ref;
1033257b6b01Syu, larry liu - Sun Microsystems - Beijing China 			mutex_exit(&sw.sw_mutex);
1034257b6b01Syu, larry liu - Sun Microsystems - Beijing China 			return (rval);
1035257b6b01Syu, larry liu - Sun Microsystems - Beijing China 		}
1036257b6b01Syu, larry liu - Sun Microsystems - Beijing China 		sswr = sswr->swr_next;
1037257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	}
1038257b6b01Syu, larry liu - Sun Microsystems - Beijing China 
1039257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	mutex_exit(&sw.sw_mutex);
1040257b6b01Syu, larry liu - Sun Microsystems - Beijing China 	return (rval);
1041257b6b01Syu, larry liu - Sun Microsystems - Beijing China }
1042