xref: /onnv-gate/usr/src/uts/common/io/scsi/impl/scsi_watch.c (revision 11066:cebb50cbe4f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57191Stl223370  * Common Development and Distribution License (the "License").
67191Stl223370  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
229977SSriram.Popuri@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * generic scsi device watch
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #if DEBUG || lint
310Sstevel@tonic-gate #define	SWDEBUG
320Sstevel@tonic-gate #endif
330Sstevel@tonic-gate 
340Sstevel@tonic-gate /*
350Sstevel@tonic-gate  * debug goodies
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate #ifdef SWDEBUG
380Sstevel@tonic-gate static int swdebug = 0;
390Sstevel@tonic-gate #define	DEBUGGING	((scsi_options & SCSI_DEBUG_TGT) && sddebug > 1)
400Sstevel@tonic-gate #define	SW_DEBUG	if (swdebug == 1) scsi_log
410Sstevel@tonic-gate #define	SW_DEBUG2	if (swdebug > 1) scsi_log
420Sstevel@tonic-gate #else	/* SWDEBUG */
430Sstevel@tonic-gate #define	swdebug		(0)
440Sstevel@tonic-gate #define	DEBUGGING	(0)
450Sstevel@tonic-gate #define	SW_DEBUG	if (0) scsi_log
460Sstevel@tonic-gate #define	SW_DEBUG2	if (0) scsi_log
470Sstevel@tonic-gate #endif
480Sstevel@tonic-gate 
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate  * Includes, Declarations and Local Data
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #include <sys/note.h>
560Sstevel@tonic-gate #include <sys/scsi/scsi.h>
570Sstevel@tonic-gate #include <sys/var.h>
580Sstevel@tonic-gate #include <sys/proc.h>
590Sstevel@tonic-gate #include <sys/thread.h>
600Sstevel@tonic-gate #include <sys/callb.h>
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /*
630Sstevel@tonic-gate  * macro for filling in lun value for scsi-1 support
640Sstevel@tonic-gate  */
650Sstevel@tonic-gate #define	FILL_SCSI1_LUN(devp, pkt) \
660Sstevel@tonic-gate 	if ((devp->sd_address.a_lun > 0) && \
670Sstevel@tonic-gate 	    (devp->sd_inq->inq_ansi == 0x1)) { \
680Sstevel@tonic-gate 		((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun = \
690Sstevel@tonic-gate 		    devp->sd_address.a_lun; \
700Sstevel@tonic-gate 	}
710Sstevel@tonic-gate 
720Sstevel@tonic-gate char *sw_label = "scsi-watch";
730Sstevel@tonic-gate 
740Sstevel@tonic-gate static int scsi_watch_io_time = SCSI_WATCH_IO_TIME;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate  * all info resides in the scsi watch structure
780Sstevel@tonic-gate  *
790Sstevel@tonic-gate  * the monitoring is performed by one separate thread which works
800Sstevel@tonic-gate  * from a linked list of scsi_watch_request packets
810Sstevel@tonic-gate  */
820Sstevel@tonic-gate static struct scsi_watch {
830Sstevel@tonic-gate 	kthread_t		*sw_thread;	/* the watch thread	*/
840Sstevel@tonic-gate 	kmutex_t		sw_mutex;	/* mutex protecting list */
850Sstevel@tonic-gate 						/* and this structure */
860Sstevel@tonic-gate 	kcondvar_t		sw_cv;		/* cv for waking up thread */
870Sstevel@tonic-gate 	struct scsi_watch_request *sw_head;	/* head of linked list	*/
880Sstevel@tonic-gate 						/* of request structures */
890Sstevel@tonic-gate 	uchar_t			sw_state;	/* for suspend-resume */
900Sstevel@tonic-gate 	uchar_t			sw_flags;	/* to start at head of list */
910Sstevel@tonic-gate 						/* for watch thread */
927191Stl223370 	struct scsi_watch_request *swr_current; /* the command waiting to be */
937191Stl223370 						/* processed by the watch */
947191Stl223370 						/* thread which is being */
957191Stl223370 						/* blocked */
960Sstevel@tonic-gate } sw;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate #if !defined(lint)
990Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(scsi_watch::sw_mutex, scsi_watch))
1000Sstevel@tonic-gate #endif
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate  * Values for sw_state
1040Sstevel@tonic-gate  */
1050Sstevel@tonic-gate #define	SW_RUNNING		0
1060Sstevel@tonic-gate #define	SW_SUSPEND_REQUESTED	1
1070Sstevel@tonic-gate #define	SW_SUSPENDED		2
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate /*
1100Sstevel@tonic-gate  * values for sw_flags
1110Sstevel@tonic-gate  */
1120Sstevel@tonic-gate #define	SW_START_HEAD		0x1
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate struct scsi_watch_request {
1150Sstevel@tonic-gate 	struct scsi_watch_request *swr_next;	/* linked request list	*/
1160Sstevel@tonic-gate 	struct scsi_watch_request *swr_prev;
1170Sstevel@tonic-gate 	clock_t			swr_interval;	/* interval between TURs */
1180Sstevel@tonic-gate 	clock_t			swr_timeout;	/* count down		*/
1190Sstevel@tonic-gate 	uchar_t			swr_busy;	/* TUR in progress	*/
1200Sstevel@tonic-gate 	uchar_t			swr_what;	/* watch or stop	*/
1210Sstevel@tonic-gate 	uchar_t			swr_sense_length; /* required sense length */
1220Sstevel@tonic-gate 	struct scsi_pkt		*swr_pkt;	/* TUR pkt itself	*/
1230Sstevel@tonic-gate 	struct scsi_pkt		*swr_rqpkt;	/* request sense pkt	*/
1240Sstevel@tonic-gate 	struct buf		*swr_rqbp;	/* bp for request sense data */
12510459SArtem.Kachitchkin@Sun.COM 	struct buf		*swr_mmcbp;	/* bp for MMC command data */
1260Sstevel@tonic-gate 	int			(*swr_callback)(); /* callback to driver */
1270Sstevel@tonic-gate 	caddr_t			swr_callback_arg;
1280Sstevel@tonic-gate 	kcondvar_t		swr_terminate_cv; /* cv to wait on to cleanup */
1290Sstevel@tonic-gate 						/* request synchronously */
1307191Stl223370 	int			swr_ref;	/*  refer count to the swr */
1317191Stl223370 	uchar_t			suspend_destroy; /* flag for free later */
1320Sstevel@tonic-gate };
1330Sstevel@tonic-gate 
1347191Stl223370 /*
1357191Stl223370  * values for swr flags
1367191Stl223370  */
1377191Stl223370 #define	SUSPEND_DESTROY		1
1387191Stl223370 
1390Sstevel@tonic-gate #if !defined(lint)
1400Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unshared data", scsi_watch_request))
1410Sstevel@tonic-gate #endif
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /*
1440Sstevel@tonic-gate  * values for sw_what
1450Sstevel@tonic-gate  */
1460Sstevel@tonic-gate #define	SWR_WATCH		0	/* device watch */
1470Sstevel@tonic-gate #define	SWR_STOP		1	/* stop monitoring and destroy swr */
1480Sstevel@tonic-gate #define	SWR_SUSPEND_REQUESTED	2	/* req. pending suspend */
1490Sstevel@tonic-gate #define	SWR_SUSPENDED		3	/* req. is suspended */
1500Sstevel@tonic-gate 
15110459SArtem.Kachitchkin@Sun.COM static opaque_t scsi_watch_request_submit_impl(struct scsi_device *devp,
15210459SArtem.Kachitchkin@Sun.COM     int interval, int sense_length, int (*callback)(), caddr_t cb_arg,
15310459SArtem.Kachitchkin@Sun.COM     boolean_t mmc);
1540Sstevel@tonic-gate static void scsi_watch_request_destroy(struct scsi_watch_request *swr);
1550Sstevel@tonic-gate static void scsi_watch_thread(void);
1560Sstevel@tonic-gate static void scsi_watch_request_intr(struct scsi_pkt *pkt);
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /*
1590Sstevel@tonic-gate  * setup, called from _init(), the thread is created when we need it
1600Sstevel@tonic-gate  * and exits when there is nothing to do anymore and everything has been
1610Sstevel@tonic-gate  * cleaned up (ie. resources deallocated)
1620Sstevel@tonic-gate  */
1630Sstevel@tonic-gate void
scsi_watch_init()1640Sstevel@tonic-gate scsi_watch_init()
1650Sstevel@tonic-gate {
1660Sstevel@tonic-gate /* NO OTHER THREADS ARE RUNNING */
1670Sstevel@tonic-gate 	mutex_init(&sw.sw_mutex, NULL, MUTEX_DRIVER, NULL);
1680Sstevel@tonic-gate 	cv_init(&sw.sw_cv, NULL, CV_DRIVER, NULL);
1690Sstevel@tonic-gate 	sw.sw_state = SW_RUNNING;
1700Sstevel@tonic-gate 	sw.sw_flags = 0;
1717191Stl223370 	sw.swr_current = NULL;
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate  * cleaning up, called from _fini()
1760Sstevel@tonic-gate  */
1770Sstevel@tonic-gate void
scsi_watch_fini()1780Sstevel@tonic-gate scsi_watch_fini()
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate /* NO OTHER THREADS ARE RUNNING */
1810Sstevel@tonic-gate 	/*
1820Sstevel@tonic-gate 	 * hope and pray that the thread has exited
1830Sstevel@tonic-gate 	 */
1840Sstevel@tonic-gate 	ASSERT(sw.sw_thread == 0);
1850Sstevel@tonic-gate 	mutex_destroy(&sw.sw_mutex);
1860Sstevel@tonic-gate 	cv_destroy(&sw.sw_cv);
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate /*
1900Sstevel@tonic-gate  * allocate an swr (scsi watch request structure) and initialize pkts
1910Sstevel@tonic-gate  */
1920Sstevel@tonic-gate #define	ROUTE		&devp->sd_address
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate opaque_t
scsi_watch_request_submit(struct scsi_device * devp,int interval,int sense_length,int (* callback)(),caddr_t cb_arg)1950Sstevel@tonic-gate scsi_watch_request_submit(
1960Sstevel@tonic-gate 	struct scsi_device	*devp,
1970Sstevel@tonic-gate 	int			interval,
1980Sstevel@tonic-gate 	int			sense_length,
1990Sstevel@tonic-gate 	int			(*callback)(),	/* callback function */
2000Sstevel@tonic-gate 	caddr_t			cb_arg)		/* device number */
2010Sstevel@tonic-gate {
20210459SArtem.Kachitchkin@Sun.COM 	return (scsi_watch_request_submit_impl(devp, interval, sense_length,
20310459SArtem.Kachitchkin@Sun.COM 	    callback, cb_arg, B_FALSE));
20410459SArtem.Kachitchkin@Sun.COM }
20510459SArtem.Kachitchkin@Sun.COM 
20610459SArtem.Kachitchkin@Sun.COM opaque_t
scsi_mmc_watch_request_submit(struct scsi_device * devp,int interval,int sense_length,int (* callback)(),caddr_t cb_arg)20710459SArtem.Kachitchkin@Sun.COM scsi_mmc_watch_request_submit(
20810459SArtem.Kachitchkin@Sun.COM 	struct scsi_device	*devp,
20910459SArtem.Kachitchkin@Sun.COM 	int			interval,
21010459SArtem.Kachitchkin@Sun.COM 	int			sense_length,
21110459SArtem.Kachitchkin@Sun.COM 	int			(*callback)(),	/* callback function */
21210459SArtem.Kachitchkin@Sun.COM 	caddr_t			cb_arg)		/* device number */
21310459SArtem.Kachitchkin@Sun.COM {
21410459SArtem.Kachitchkin@Sun.COM 	return (scsi_watch_request_submit_impl(devp, interval, sense_length,
21510459SArtem.Kachitchkin@Sun.COM 	    callback, cb_arg, B_TRUE));
21610459SArtem.Kachitchkin@Sun.COM }
21710459SArtem.Kachitchkin@Sun.COM 
21810459SArtem.Kachitchkin@Sun.COM 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)21910459SArtem.Kachitchkin@Sun.COM scsi_watch_request_submit_impl(
22010459SArtem.Kachitchkin@Sun.COM 	struct scsi_device	*devp,
22110459SArtem.Kachitchkin@Sun.COM 	int			interval,
22210459SArtem.Kachitchkin@Sun.COM 	int			sense_length,
22310459SArtem.Kachitchkin@Sun.COM 	int			(*callback)(),	/* callback function */
22410459SArtem.Kachitchkin@Sun.COM 	caddr_t			cb_arg,		/* device number */
22510459SArtem.Kachitchkin@Sun.COM 	boolean_t		mmc)
22610459SArtem.Kachitchkin@Sun.COM {
2270Sstevel@tonic-gate 	register struct scsi_watch_request	*swr = NULL;
2280Sstevel@tonic-gate 	register struct scsi_watch_request	*sswr, *p;
2290Sstevel@tonic-gate 	struct buf				*bp = NULL;
23010459SArtem.Kachitchkin@Sun.COM 	struct buf				*mmcbp = NULL;
2310Sstevel@tonic-gate 	struct scsi_pkt				*rqpkt = NULL;
2320Sstevel@tonic-gate 	struct scsi_pkt				*pkt = NULL;
2330Sstevel@tonic-gate 	uchar_t					dtype;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
2367191Stl223370 	    "scsi_watch_request_submit: Entering ...\n");
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
2390Sstevel@tonic-gate 	if (sw.sw_thread == 0) {
2400Sstevel@tonic-gate 		register kthread_t	*t;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		t = thread_create((caddr_t)NULL, 0, scsi_watch_thread,
2437191Stl223370 		    NULL, 0, &p0, TS_RUN, v.v_maxsyspri - 2);
2440Sstevel@tonic-gate 		sw.sw_thread = t;
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	for (p = sw.sw_head; p != NULL; p = p->swr_next) {
2480Sstevel@tonic-gate 		if ((p->swr_callback_arg == cb_arg) &&
2497191Stl223370 		    (p->swr_callback == callback))
2500Sstevel@tonic-gate 			break;
2510Sstevel@tonic-gate 	}
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	/* update time interval for an existing request */
2540Sstevel@tonic-gate 	if (p) {
2557191Stl223370 		if (p->swr_what != SWR_STOP) {
2567191Stl223370 			p->swr_timeout = p->swr_interval
2577191Stl223370 			    = drv_usectohz(interval);
2587191Stl223370 			p->swr_what = SWR_WATCH;
2597191Stl223370 			p->swr_ref++;
2607191Stl223370 			cv_signal(&sw.sw_cv);
2617191Stl223370 			mutex_exit(&sw.sw_mutex);
2627191Stl223370 			return ((opaque_t)p);
2637191Stl223370 		}
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	/*
2680Sstevel@tonic-gate 	 * allocate space for scsi_watch_request
2690Sstevel@tonic-gate 	 */
2700Sstevel@tonic-gate 	swr = kmem_zalloc(sizeof (struct scsi_watch_request), KM_SLEEP);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	/*
2730Sstevel@tonic-gate 	 * allocate request sense bp and pkt and make cmd
2740Sstevel@tonic-gate 	 * we shouldn't really need it if ARQ is enabled but it is useful
2750Sstevel@tonic-gate 	 * if the ARQ failed.
2760Sstevel@tonic-gate 	 */
2770Sstevel@tonic-gate 	bp = scsi_alloc_consistent_buf(ROUTE, NULL,
2787191Stl223370 	    sense_length, B_READ, SLEEP_FUNC, NULL);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	rqpkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
2817191Stl223370 	    bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT, SLEEP_FUNC, NULL);
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	(void) scsi_setup_cdb((union scsi_cdb *)rqpkt->pkt_cdbp,
2840Sstevel@tonic-gate 	    SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0);
2850Sstevel@tonic-gate 	FILL_SCSI1_LUN(devp, rqpkt);
2860Sstevel@tonic-gate 	rqpkt->pkt_private = (opaque_t)swr;
2870Sstevel@tonic-gate 	rqpkt->pkt_time = scsi_watch_io_time;
2880Sstevel@tonic-gate 	rqpkt->pkt_comp = scsi_watch_request_intr;
2890Sstevel@tonic-gate 	rqpkt->pkt_flags |= FLAG_HEAD;
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	/*
29210459SArtem.Kachitchkin@Sun.COM 	 * Create TUR pkt or GET STATUS EVENT NOTIFICATION for MMC requests or
29310459SArtem.Kachitchkin@Sun.COM 	 * a zero byte WRITE(10) based on the disk-type for reservation state.
2940Sstevel@tonic-gate 	 * For inq_dtype of SBC (DIRECT, dtype == 0)
2950Sstevel@tonic-gate 	 * OR for RBC devices (dtype is 0xE) AND for
2960Sstevel@tonic-gate 	 * ANSI version of SPC/SPC-2/SPC-3 (inq_ansi == 3-5).
2970Sstevel@tonic-gate 	 */
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	dtype = devp->sd_inq->inq_dtype & DTYPE_MASK;
30010459SArtem.Kachitchkin@Sun.COM 	if (mmc) {
30110459SArtem.Kachitchkin@Sun.COM 		mmcbp = scsi_alloc_consistent_buf(ROUTE, NULL,
30210459SArtem.Kachitchkin@Sun.COM 		    8, B_READ, SLEEP_FUNC, NULL);
30310459SArtem.Kachitchkin@Sun.COM 
30410459SArtem.Kachitchkin@Sun.COM 		pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, mmcbp,
30510459SArtem.Kachitchkin@Sun.COM 		    CDB_GROUP1, sizeof (struct scsi_arq_status),
30610459SArtem.Kachitchkin@Sun.COM 		    0, 0, SLEEP_FUNC, NULL);
30710459SArtem.Kachitchkin@Sun.COM 
30810459SArtem.Kachitchkin@Sun.COM 		(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
30910459SArtem.Kachitchkin@Sun.COM 		    SCMD_GET_EVENT_STATUS_NOTIFICATION, 0, 8, 0);
31010459SArtem.Kachitchkin@Sun.COM 		pkt->pkt_cdbp[1] = 1; /* polled */
31110459SArtem.Kachitchkin@Sun.COM 		pkt->pkt_cdbp[4] = 1 << SD_GESN_MEDIA_CLASS;
31210459SArtem.Kachitchkin@Sun.COM 	} else if (((dtype == 0) || (dtype == 0xE)) &&
3137191Stl223370 	    (devp->sd_inq->inq_ansi > 2)) {
3140Sstevel@tonic-gate 		pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, NULL,
3157191Stl223370 		    CDB_GROUP1, sizeof (struct scsi_arq_status),
3167191Stl223370 		    0, 0, SLEEP_FUNC, NULL);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 		(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
3197191Stl223370 		    SCMD_WRITE_G1, 0, 0, 0);
3200Sstevel@tonic-gate 	} else {
3210Sstevel@tonic-gate 		pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, NULL,
3227191Stl223370 		    CDB_GROUP0, sizeof (struct scsi_arq_status),
3237191Stl223370 		    0, 0, SLEEP_FUNC, NULL);
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 		(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
3267191Stl223370 		    SCMD_TEST_UNIT_READY, 0, 0, 0);
3270Sstevel@tonic-gate 		FILL_SCSI1_LUN(devp, pkt);
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	pkt->pkt_private = (opaque_t)swr;
3310Sstevel@tonic-gate 	pkt->pkt_time = scsi_watch_io_time;
3320Sstevel@tonic-gate 	pkt->pkt_comp = scsi_watch_request_intr;
3330Sstevel@tonic-gate 	if (scsi_ifgetcap(&pkt->pkt_address, "tagged-qing", 1) == 1) {
3340Sstevel@tonic-gate 		pkt->pkt_flags |= FLAG_STAG;
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	/*
3380Sstevel@tonic-gate 	 * set the allocated resources in swr
3390Sstevel@tonic-gate 	 */
3400Sstevel@tonic-gate 	swr->swr_rqbp = bp;
3410Sstevel@tonic-gate 	swr->swr_rqpkt = rqpkt;
34210459SArtem.Kachitchkin@Sun.COM 	swr->swr_mmcbp = mmcbp;
3430Sstevel@tonic-gate 	swr->swr_pkt = pkt;
3440Sstevel@tonic-gate 	swr->swr_timeout = swr->swr_interval = drv_usectohz(interval);
3450Sstevel@tonic-gate 	swr->swr_callback = callback;
3460Sstevel@tonic-gate 	swr->swr_callback_arg = cb_arg;
3470Sstevel@tonic-gate 	swr->swr_what = SWR_WATCH;
3480Sstevel@tonic-gate 	swr->swr_sense_length = (uchar_t)sense_length;
3497191Stl223370 	swr->swr_ref = 1;
3500Sstevel@tonic-gate 	cv_init(&swr->swr_terminate_cv, NULL, CV_DRIVER, NULL);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/*
3530Sstevel@tonic-gate 	 * add to the list and wake up the thread
3540Sstevel@tonic-gate 	 */
3550Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
3560Sstevel@tonic-gate 	swr->swr_next = sw.sw_head;
3570Sstevel@tonic-gate 	swr->swr_prev = NULL;
3580Sstevel@tonic-gate 	if (sw.sw_head) {
3590Sstevel@tonic-gate 		sw.sw_head->swr_prev = swr;
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 	sw.sw_head = swr;
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/*
3640Sstevel@tonic-gate 	 * reset all timeouts, so all requests are in sync again
3650Sstevel@tonic-gate 	 * XXX there is a small window where the watch thread releases
3660Sstevel@tonic-gate 	 * the mutex so that could upset the resyncing
3670Sstevel@tonic-gate 	 */
3680Sstevel@tonic-gate 	sswr = swr;
3690Sstevel@tonic-gate 	while (sswr) {
3700Sstevel@tonic-gate 		sswr->swr_timeout = swr->swr_interval;
3710Sstevel@tonic-gate 		sswr = sswr->swr_next;
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 	cv_signal(&sw.sw_cv);
3740Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
3750Sstevel@tonic-gate 	return ((opaque_t)swr);
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate  * called by (eg. pwr management) to resume the scsi_watch_thread
3810Sstevel@tonic-gate  */
3820Sstevel@tonic-gate void
scsi_watch_resume(opaque_t token)3830Sstevel@tonic-gate scsi_watch_resume(opaque_t token)
3840Sstevel@tonic-gate {
3850Sstevel@tonic-gate 	struct scsi_watch_request *swr = (struct scsi_watch_request *)NULL;
3860Sstevel@tonic-gate 	/*
3870Sstevel@tonic-gate 	 * Change the state to SW_RUNNING and wake up the scsi_watch_thread
3880Sstevel@tonic-gate 	 */
3890Sstevel@tonic-gate 	SW_DEBUG(0, sw_label, SCSI_DEBUG, "scsi_watch_resume:\n");
3900Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	if (!sw.sw_head)
3930Sstevel@tonic-gate 		goto exit;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	/* search for token */
3960Sstevel@tonic-gate 	for (swr = sw.sw_head; swr; swr = swr->swr_next) {
3970Sstevel@tonic-gate 		if (swr == (struct scsi_watch_request *)token)
3980Sstevel@tonic-gate 			break;
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	/* if we can't find this value, then we just do nothing */
4020Sstevel@tonic-gate 	if (swr == (struct scsi_watch_request *)NULL)
4030Sstevel@tonic-gate 		goto exit;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	swr->swr_what = SWR_WATCH;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/* see if all swr's are awake, then start the thread again */
4090Sstevel@tonic-gate 	for (swr = sw.sw_head; swr; swr = swr->swr_next) {
4100Sstevel@tonic-gate 		if (swr->swr_what != SWR_WATCH)
4110Sstevel@tonic-gate 			goto exit;
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	sw.sw_state = SW_RUNNING;
4150Sstevel@tonic-gate 	cv_signal(&sw.sw_cv);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate exit:
4180Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate /*
4230Sstevel@tonic-gate  * called by clients (eg. pwr management) to suspend the scsi_watch_thread
4240Sstevel@tonic-gate  */
4250Sstevel@tonic-gate void
scsi_watch_suspend(opaque_t token)4260Sstevel@tonic-gate scsi_watch_suspend(opaque_t token)
4270Sstevel@tonic-gate {
4280Sstevel@tonic-gate 	struct scsi_watch_request *swr = (struct scsi_watch_request *)NULL;
4290Sstevel@tonic-gate 	clock_t halfsec_delay = drv_usectohz(500000);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	SW_DEBUG(0, sw_label, SCSI_DEBUG, "scsi_watch_suspend:\n");
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	if (!sw.sw_head)
4360Sstevel@tonic-gate 		goto exit;
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	/* search for token */
4390Sstevel@tonic-gate 	for (swr = sw.sw_head; swr; swr = swr->swr_next) {
4400Sstevel@tonic-gate 		if (swr == (struct scsi_watch_request *)token)
4410Sstevel@tonic-gate 			break;
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	/* if we can't find this value, then we just do nothing */
4450Sstevel@tonic-gate 	if (swr == (struct scsi_watch_request *)NULL)
4460Sstevel@tonic-gate 		goto exit;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	for (;;) {
4500Sstevel@tonic-gate 		if (swr->swr_busy) {
4510Sstevel@tonic-gate 			/*
4520Sstevel@tonic-gate 			 * XXX: Assumes that this thread can rerun
4530Sstevel@tonic-gate 			 * till all outstanding cmds are complete
4540Sstevel@tonic-gate 			 */
4550Sstevel@tonic-gate 			swr->swr_what = SWR_SUSPEND_REQUESTED;
456*11066Srafael.vanoni@sun.com 			(void) cv_reltimedwait(&sw.sw_cv, &sw.sw_mutex,
457*11066Srafael.vanoni@sun.com 			    halfsec_delay, TR_CLOCK_TICK);
4580Sstevel@tonic-gate 		} else {
4590Sstevel@tonic-gate 			swr->swr_what = SWR_SUSPENDED;
4600Sstevel@tonic-gate 			break;
4610Sstevel@tonic-gate 		}
4620Sstevel@tonic-gate 	}
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	/* see if all swr's are suspended, then suspend the thread */
4650Sstevel@tonic-gate 	for (swr = sw.sw_head; swr; swr = swr->swr_next) {
4660Sstevel@tonic-gate 		if (swr->swr_what != SWR_SUSPENDED)
4670Sstevel@tonic-gate 			goto exit;
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	sw.sw_state = SW_SUSPENDED;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate exit:
4730Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate /*
4770Sstevel@tonic-gate  * destroy swr, called for watch thread
4780Sstevel@tonic-gate  */
4790Sstevel@tonic-gate static void
scsi_watch_request_destroy(struct scsi_watch_request * swr)4800Sstevel@tonic-gate scsi_watch_request_destroy(struct scsi_watch_request *swr)
4810Sstevel@tonic-gate {
4820Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&sw.sw_mutex));
4830Sstevel@tonic-gate 	ASSERT(swr->swr_busy == 0);
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
4867191Stl223370 	    "scsi_watch_request_destroy: Entering ...\n");
4877191Stl223370 	if (swr->swr_ref != 0)
4887191Stl223370 		return;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	/*
4910Sstevel@tonic-gate 	 * remove swr from linked list and destroy pkts
4920Sstevel@tonic-gate 	 */
4930Sstevel@tonic-gate 	if (swr->swr_prev) {
4940Sstevel@tonic-gate 		swr->swr_prev->swr_next = swr->swr_next;
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate 	if (swr->swr_next) {
4970Sstevel@tonic-gate 		swr->swr_next->swr_prev = swr->swr_prev;
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 	if (sw.sw_head == swr) {
5000Sstevel@tonic-gate 		sw.sw_head = swr->swr_next;
5010Sstevel@tonic-gate 	}
5027191Stl223370 	if (sw.swr_current == swr) {
5037191Stl223370 		swr->suspend_destroy = SUSPEND_DESTROY;
5047191Stl223370 		sw.swr_current = NULL;
5057191Stl223370 	}
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	scsi_destroy_pkt(swr->swr_rqpkt);
5080Sstevel@tonic-gate 	scsi_free_consistent_buf(swr->swr_rqbp);
50910459SArtem.Kachitchkin@Sun.COM 	if (swr->swr_mmcbp != NULL) {
51010459SArtem.Kachitchkin@Sun.COM 		scsi_free_consistent_buf(swr->swr_mmcbp);
51110459SArtem.Kachitchkin@Sun.COM 	}
5120Sstevel@tonic-gate 	scsi_destroy_pkt(swr->swr_pkt);
5130Sstevel@tonic-gate 	cv_signal(&swr->swr_terminate_cv);
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate  * scsi_watch_request_terminate()
5180Sstevel@tonic-gate  * called by requestor to terminate any pending watch request.
5190Sstevel@tonic-gate  * if the request is currently "busy", and the caller cannot wait, failure
5200Sstevel@tonic-gate  * is returned. O/w the request is cleaned up immediately.
5210Sstevel@tonic-gate  */
5220Sstevel@tonic-gate int
scsi_watch_request_terminate(opaque_t token,int flags)5230Sstevel@tonic-gate scsi_watch_request_terminate(opaque_t token, int flags)
5240Sstevel@tonic-gate {
5250Sstevel@tonic-gate 	struct scsi_watch_request *swr =
5267191Stl223370 	    (struct scsi_watch_request *)token;
5270Sstevel@tonic-gate 	struct scsi_watch_request *sswr;
5280Sstevel@tonic-gate 
5297191Stl223370 	int count = 0;
5307191Stl223370 	int free_flag = 0;
5317191Stl223370 
5320Sstevel@tonic-gate 	/*
5330Sstevel@tonic-gate 	 * We try to clean up this request if we can. We also inform
5340Sstevel@tonic-gate 	 * the watch thread that we mucked around the list so it has
5350Sstevel@tonic-gate 	 * to start reading from head of list again.
5360Sstevel@tonic-gate 	 */
5370Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
5387191Stl223370 	    "scsi_watch_request_terminate: Entering(0x%p) ...\n",
5397191Stl223370 	    (void *)swr);
5400Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	/*
5430Sstevel@tonic-gate 	 * check if it is still in the list
5440Sstevel@tonic-gate 	 */
5450Sstevel@tonic-gate 	sswr = sw.sw_head;
5460Sstevel@tonic-gate 	while (sswr) {
5470Sstevel@tonic-gate 		if (sswr == swr) {
5487191Stl223370 			swr->swr_ref--;
5497191Stl223370 			count = swr->swr_ref;
5507191Stl223370 
5510Sstevel@tonic-gate 			if (swr->swr_busy) {
5520Sstevel@tonic-gate 				if (flags == SCSI_WATCH_TERMINATE_NOWAIT) {
5530Sstevel@tonic-gate 					mutex_exit(&sw.sw_mutex);
5540Sstevel@tonic-gate 					return (SCSI_WATCH_TERMINATE_FAIL);
5557191Stl223370 				}
5567191Stl223370 				if (count != 0 && flags !=
5577191Stl223370 				    SCSI_WATCH_TERMINATE_ALL_WAIT) {
5587191Stl223370 					mutex_exit(&sw.sw_mutex);
5597191Stl223370 					return (SCSI_WATCH_TERMINATE_SUCCESS);
5607191Stl223370 				}
5617191Stl223370 				if (SCSI_WATCH_TERMINATE_ALL_WAIT == flags) {
5627191Stl223370 					swr->swr_ref = 0;
5637191Stl223370 					count = 0;
5640Sstevel@tonic-gate 				}
5657191Stl223370 				swr->swr_what = SWR_STOP;
5667191Stl223370 				cv_wait(&swr->swr_terminate_cv, &sw.sw_mutex);
5677191Stl223370 				free_flag = 1;
5687191Stl223370 				goto done;
5690Sstevel@tonic-gate 			} else {
5707191Stl223370 				if (SCSI_WATCH_TERMINATE_NOWAIT == flags ||
5717191Stl223370 				    SCSI_WATCH_TERMINATE_ALL_WAIT == flags) {
5727191Stl223370 					swr->swr_ref = 0;
5737191Stl223370 					count = 0;
5747191Stl223370 				}
5750Sstevel@tonic-gate 				scsi_watch_request_destroy(swr);
5767191Stl223370 				if (0 == count) {
5777191Stl223370 					sw.sw_flags |= SW_START_HEAD;
5787191Stl223370 					free_flag = 1;
5797191Stl223370 				}
5800Sstevel@tonic-gate 				goto done;
5810Sstevel@tonic-gate 			}
5820Sstevel@tonic-gate 		}
5830Sstevel@tonic-gate 		sswr = sswr->swr_next;
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate done:
5860Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
5877191Stl223370 	if (!sswr) {
5887191Stl223370 		return (SCSI_WATCH_TERMINATE_FAIL);
5897191Stl223370 	}
5907191Stl223370 	if (1 == free_flag &&
5917191Stl223370 	    sswr->suspend_destroy != SUSPEND_DESTROY) {
5920Sstevel@tonic-gate 		cv_destroy(&swr->swr_terminate_cv);
5930Sstevel@tonic-gate 		kmem_free((caddr_t)swr, sizeof (struct scsi_watch_request));
5940Sstevel@tonic-gate 	}
5957191Stl223370 
5967191Stl223370 	return (SCSI_WATCH_TERMINATE_SUCCESS);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate /*
6010Sstevel@tonic-gate  * The routines scsi_watch_thread & scsi_watch_request_intr are
6020Sstevel@tonic-gate  * on different threads.
6030Sstevel@tonic-gate  * If there is no work to be done by the lower level driver
6040Sstevel@tonic-gate  * then swr->swr_busy will not be set.
6050Sstevel@tonic-gate  * In this case we will call CALLB_CPR_SAFE_BEGIN before
6060Sstevel@tonic-gate  * calling cv_timedwait.
6070Sstevel@tonic-gate  * In the other case where there is work to be done by
6080Sstevel@tonic-gate  * the lower level driver then the flag swr->swr_busy will
6090Sstevel@tonic-gate  * be set.
6100Sstevel@tonic-gate  * We cannot call CALLB_CPR_SAFE_BEGIN at this point the reason
6110Sstevel@tonic-gate  * is the intr thread can interfere with our operations. So
6120Sstevel@tonic-gate  * we do a cv_timedwait here. Now at the completion of the
6130Sstevel@tonic-gate  * lower level driver's work we will call CALLB_CPR_SAFE_BEGIN
6140Sstevel@tonic-gate  * in scsi_watch_request_intr.
6150Sstevel@tonic-gate  * In all the cases we will call CALLB_CPR_SAFE_END only if
6160Sstevel@tonic-gate  * we already called a CALLB_CPR_SAFE_BEGIN and this is flagged
6170Sstevel@tonic-gate  * by sw_cpr_flag.
6180Sstevel@tonic-gate  * Warlock has a problem when we use different locks
6190Sstevel@tonic-gate  * on the same type of structure in different contexts.
6200Sstevel@tonic-gate  * We use callb_cpr_t in both scsi_watch and esp_callback threads.
6210Sstevel@tonic-gate  * we use different mutexe's in different threads. And
6220Sstevel@tonic-gate  * this is not acceptable to warlock. To avoid this
6230Sstevel@tonic-gate  * problem we use the same name for the mutex in
6240Sstevel@tonic-gate  * both scsi_watch & esp_callback. when __lock_lint is not defined
6250Sstevel@tonic-gate  * esp_callback uses the mutex on the stack and in scsi_watch
6260Sstevel@tonic-gate  * a static variable. But when __lock_lint is defined
6270Sstevel@tonic-gate  * we make a mutex which is global in esp_callback and
6280Sstevel@tonic-gate  * a external mutex for scsi_watch.
6290Sstevel@tonic-gate  */
6300Sstevel@tonic-gate static int sw_cmd_count = 0;
6310Sstevel@tonic-gate static int sw_cpr_flag = 0;
6320Sstevel@tonic-gate static callb_cpr_t cpr_info;
6330Sstevel@tonic-gate #ifndef __lock_lint
6340Sstevel@tonic-gate static kmutex_t cpr_mutex;
6350Sstevel@tonic-gate #else
6360Sstevel@tonic-gate extern kmutex_t cpr_mutex;
6370Sstevel@tonic-gate #endif
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate #if !defined(lint)
6400Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(cpr_mutex, cpr_info))
_NOTE(MUTEX_PROTECTS_DATA (cpr_mutex,sw_cmd_count))6410Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(cpr_mutex, sw_cmd_count))
6420Sstevel@tonic-gate #endif
6430Sstevel@tonic-gate /*
6440Sstevel@tonic-gate  * the scsi watch thread:
6450Sstevel@tonic-gate  * it either wakes up if there is work to do or if the cv_timeait
6460Sstevel@tonic-gate  * timed out
6470Sstevel@tonic-gate  * normally, it wakes up every <delay> seconds and checks the list.
6480Sstevel@tonic-gate  * the interval is not very accurate if the cv was signalled but that
6490Sstevel@tonic-gate  * really doesn't matter much
6500Sstevel@tonic-gate  * it is more important that we fire off all TURs simulataneously so
6510Sstevel@tonic-gate  * we don't have to wake up frequently
6520Sstevel@tonic-gate  */
6530Sstevel@tonic-gate static void
6540Sstevel@tonic-gate scsi_watch_thread()
6550Sstevel@tonic-gate {
6560Sstevel@tonic-gate 	struct scsi_watch_request	*swr, *next;
6570Sstevel@tonic-gate 	clock_t				last_delay = 0;
6580Sstevel@tonic-gate 	clock_t				next_delay = 0;
6590Sstevel@tonic-gate 	clock_t				onesec = drv_usectohz(1000000);
6600Sstevel@tonic-gate 	clock_t				exit_delay = 60 * onesec;
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
6637191Stl223370 	    "scsi_watch_thread: Entering ...\n");
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate #if !defined(lint)
6660Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
6670Sstevel@tonic-gate #endif
6680Sstevel@tonic-gate 	mutex_init(&cpr_mutex, NULL, MUTEX_DRIVER, NULL);
6690Sstevel@tonic-gate 	CALLB_CPR_INIT(&cpr_info,
6707191Stl223370 	    &cpr_mutex, callb_generic_cpr, "scsi_watch");
6710Sstevel@tonic-gate 	sw_cpr_flag = 0;
6720Sstevel@tonic-gate #if !defined(lint)
6730Sstevel@tonic-gate 	/*LINTED*/
6740Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
6750Sstevel@tonic-gate #endif
6760Sstevel@tonic-gate 	/*
6770Sstevel@tonic-gate 	 * grab the mutex and wait for work
6780Sstevel@tonic-gate 	 */
6790Sstevel@tonic-gate 	mutex_enter(&sw.sw_mutex);
6800Sstevel@tonic-gate 	if (sw.sw_head == NULL) {
6810Sstevel@tonic-gate 		cv_wait(&sw.sw_cv, &sw.sw_mutex);
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	/*
6850Sstevel@tonic-gate 	 * now loop forever for work; if queue is empty exit
6860Sstevel@tonic-gate 	 */
6870Sstevel@tonic-gate 	for (;;) {
6880Sstevel@tonic-gate head:
6890Sstevel@tonic-gate 		swr = sw.sw_head;
6900Sstevel@tonic-gate 		while (swr) {
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 			/*
6930Sstevel@tonic-gate 			 * If state is not running, wait for scsi_watch_resume
6940Sstevel@tonic-gate 			 * to signal restart, but before going into cv_wait
6950Sstevel@tonic-gate 			 * need to let the PM framework know that it is safe
6960Sstevel@tonic-gate 			 * to stop this thread for CPR
6970Sstevel@tonic-gate 			 */
6980Sstevel@tonic-gate 			if (sw.sw_state != SW_RUNNING) {
6990Sstevel@tonic-gate 				SW_DEBUG(0, sw_label, SCSI_DEBUG,
7007191Stl223370 				    "scsi_watch_thread suspended\n");
7010Sstevel@tonic-gate 				mutex_enter(&cpr_mutex);
7020Sstevel@tonic-gate 				if (!sw_cmd_count) {
7030Sstevel@tonic-gate 					CALLB_CPR_SAFE_BEGIN(&cpr_info);
7040Sstevel@tonic-gate 					sw_cpr_flag = 1;
7050Sstevel@tonic-gate 				}
7060Sstevel@tonic-gate 				mutex_exit(&cpr_mutex);
7077191Stl223370 				sw.swr_current = swr;
7080Sstevel@tonic-gate 				cv_wait(&sw.sw_cv, &sw.sw_mutex);
7097191Stl223370 
7107191Stl223370 
7110Sstevel@tonic-gate 				/*
7120Sstevel@tonic-gate 				 * Need to let the PM framework know that it
7130Sstevel@tonic-gate 				 * is no longer safe to stop the thread for
7140Sstevel@tonic-gate 				 * CPR.
7150Sstevel@tonic-gate 				 */
7160Sstevel@tonic-gate 				mutex_exit(&sw.sw_mutex);
7170Sstevel@tonic-gate 				mutex_enter(&cpr_mutex);
7180Sstevel@tonic-gate 				if (sw_cpr_flag == 1) {
7190Sstevel@tonic-gate 					CALLB_CPR_SAFE_END(
7207191Stl223370 					    &cpr_info, &cpr_mutex);
7210Sstevel@tonic-gate 					sw_cpr_flag = 0;
7220Sstevel@tonic-gate 				}
7230Sstevel@tonic-gate 				mutex_exit(&cpr_mutex);
7240Sstevel@tonic-gate 				mutex_enter(&sw.sw_mutex);
7257191Stl223370 				if (SUSPEND_DESTROY == swr->suspend_destroy) {
7267191Stl223370 					cv_destroy(&swr->swr_terminate_cv);
7277191Stl223370 					kmem_free((caddr_t)swr,
7287191Stl223370 					    sizeof (struct scsi_watch_request));
7297191Stl223370 					goto head;
7307191Stl223370 				} else {
7317191Stl223370 					sw.swr_current = NULL;
7327191Stl223370 				}
7330Sstevel@tonic-gate 			}
7340Sstevel@tonic-gate 			if (next_delay == 0) {
7350Sstevel@tonic-gate 				next_delay = swr->swr_timeout;
7360Sstevel@tonic-gate 			} else {
7370Sstevel@tonic-gate 				next_delay = min(swr->swr_timeout, next_delay);
7380Sstevel@tonic-gate 			}
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 			swr->swr_timeout -= last_delay;
7410Sstevel@tonic-gate 			next = swr->swr_next;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 			SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
7447191Stl223370 			    "scsi_watch_thread: "
7457191Stl223370 			    "swr(0x%p),what=%x,timeout=%lx,"
7467191Stl223370 			    "interval=%lx,delay=%lx\n",
7477191Stl223370 			    (void *)swr, swr->swr_what, swr->swr_timeout,
7487191Stl223370 			    swr->swr_interval, last_delay);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 			switch (swr->swr_what) {
7510Sstevel@tonic-gate 			case SWR_SUSPENDED:
7520Sstevel@tonic-gate 			case SWR_SUSPEND_REQUESTED:
7530Sstevel@tonic-gate 				/* if we are suspended, don't do anything */
7540Sstevel@tonic-gate 				break;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 			case SWR_STOP:
7570Sstevel@tonic-gate 				if (swr->swr_busy == 0) {
7580Sstevel@tonic-gate 					scsi_watch_request_destroy(swr);
7590Sstevel@tonic-gate 				}
7600Sstevel@tonic-gate 				break;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 			default:
7630Sstevel@tonic-gate 				if (swr->swr_timeout <= 0 && !swr->swr_busy) {
7640Sstevel@tonic-gate 					swr->swr_busy = 1;
7659977SSriram.Popuri@sun.com 					swr->swr_timeout = swr->swr_interval;
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 					/*
7680Sstevel@tonic-gate 					 * submit the cmd and let the completion
7690Sstevel@tonic-gate 					 * function handle the result
7700Sstevel@tonic-gate 					 * release the mutex (good practice)
7710Sstevel@tonic-gate 					 * this should be safe even if the list
7720Sstevel@tonic-gate 					 * is changing
7730Sstevel@tonic-gate 					 */
7740Sstevel@tonic-gate 					mutex_exit(&sw.sw_mutex);
7750Sstevel@tonic-gate 					mutex_enter(&cpr_mutex);
7760Sstevel@tonic-gate 					sw_cmd_count++;
7770Sstevel@tonic-gate 					mutex_exit(&cpr_mutex);
7780Sstevel@tonic-gate 					SW_DEBUG((dev_info_t *)NULL,
7797191Stl223370 					    sw_label, SCSI_DEBUG,
7807191Stl223370 					    "scsi_watch_thread: "
7817191Stl223370 					    "Starting TUR\n");
7820Sstevel@tonic-gate 					if (scsi_transport(swr->swr_pkt) !=
7837191Stl223370 					    TRAN_ACCEPT) {
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 						/*
7860Sstevel@tonic-gate 						 * try again later
7870Sstevel@tonic-gate 						 */
7880Sstevel@tonic-gate 						swr->swr_busy = 0;
7890Sstevel@tonic-gate 						SW_DEBUG((dev_info_t *)NULL,
7907191Stl223370 						    sw_label, SCSI_DEBUG,
7917191Stl223370 						    "scsi_watch_thread: "
7927191Stl223370 						    "Transport Failed\n");
7930Sstevel@tonic-gate 						mutex_enter(&cpr_mutex);
7940Sstevel@tonic-gate 						sw_cmd_count--;
7950Sstevel@tonic-gate 						mutex_exit(&cpr_mutex);
7960Sstevel@tonic-gate 					}
7970Sstevel@tonic-gate 					mutex_enter(&sw.sw_mutex);
7980Sstevel@tonic-gate 				}
7990Sstevel@tonic-gate 				break;
8000Sstevel@tonic-gate 			}
8010Sstevel@tonic-gate 			swr = next;
8020Sstevel@tonic-gate 			if (sw.sw_flags & SW_START_HEAD) {
8030Sstevel@tonic-gate 				sw.sw_flags &= ~SW_START_HEAD;
8040Sstevel@tonic-gate 				goto head;
8050Sstevel@tonic-gate 			}
8060Sstevel@tonic-gate 		}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 		/*
8090Sstevel@tonic-gate 		 * delay using cv_timedwait; we return when
8100Sstevel@tonic-gate 		 * signalled or timed out
8110Sstevel@tonic-gate 		 */
8120Sstevel@tonic-gate 		if (sw.sw_head != NULL) {
8130Sstevel@tonic-gate 			if (next_delay <= 0) {
8140Sstevel@tonic-gate 				next_delay = onesec;
8150Sstevel@tonic-gate 			}
8160Sstevel@tonic-gate 		} else {
8170Sstevel@tonic-gate 			next_delay = exit_delay;
8180Sstevel@tonic-gate 		}
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 		mutex_enter(&cpr_mutex);
8210Sstevel@tonic-gate 		if (!sw_cmd_count) {
8220Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cpr_info);
8230Sstevel@tonic-gate 			sw_cpr_flag = 1;
8240Sstevel@tonic-gate 		}
8250Sstevel@tonic-gate 		mutex_exit(&cpr_mutex);
8260Sstevel@tonic-gate 		/*
8270Sstevel@tonic-gate 		 * if we return from cv_timedwait because we were
8280Sstevel@tonic-gate 		 * signalled, the delay is not accurate but that doesn't
8290Sstevel@tonic-gate 		 * really matter
8300Sstevel@tonic-gate 		 */
831*11066Srafael.vanoni@sun.com 		(void) cv_reltimedwait(&sw.sw_cv, &sw.sw_mutex, next_delay,
832*11066Srafael.vanoni@sun.com 		    TR_CLOCK_TICK);
8330Sstevel@tonic-gate 		mutex_exit(&sw.sw_mutex);
8340Sstevel@tonic-gate 		mutex_enter(&cpr_mutex);
8350Sstevel@tonic-gate 		if (sw_cpr_flag == 1) {
8360Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cpr_info, &cpr_mutex);
8370Sstevel@tonic-gate 			sw_cpr_flag = 0;
8380Sstevel@tonic-gate 		}
8390Sstevel@tonic-gate 		mutex_exit(&cpr_mutex);
8400Sstevel@tonic-gate 		mutex_enter(&sw.sw_mutex);
8410Sstevel@tonic-gate 		last_delay = next_delay;
8420Sstevel@tonic-gate 		next_delay = 0;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 		/*
8450Sstevel@tonic-gate 		 * is there still work to do?
8460Sstevel@tonic-gate 		 */
8470Sstevel@tonic-gate 		if (sw.sw_head == NULL) {
8480Sstevel@tonic-gate 			break;
8490Sstevel@tonic-gate 		}
8500Sstevel@tonic-gate 	}
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	/*
8530Sstevel@tonic-gate 	 * no more work to do, reset sw_thread and exit
8540Sstevel@tonic-gate 	 */
8550Sstevel@tonic-gate 	sw.sw_thread = 0;
8560Sstevel@tonic-gate 	mutex_exit(&sw.sw_mutex);
8570Sstevel@tonic-gate #ifndef __lock_lint
8580Sstevel@tonic-gate 	mutex_enter(&cpr_mutex);
8590Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cpr_info);
8600Sstevel@tonic-gate #endif
8610Sstevel@tonic-gate 	mutex_destroy(&cpr_mutex);
8620Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
8637191Stl223370 	    "scsi_watch_thread: Exiting ...\n");
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate /*
8670Sstevel@tonic-gate  * callback completion function for scsi watch pkt
8680Sstevel@tonic-gate  */
8690Sstevel@tonic-gate #define	SCBP(pkt)	((struct scsi_status *)(pkt)->pkt_scbp)
8700Sstevel@tonic-gate #define	SCBP_C(pkt)	((*(pkt)->pkt_scbp) & STATUS_MASK)
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate static void
scsi_watch_request_intr(struct scsi_pkt * pkt)8730Sstevel@tonic-gate scsi_watch_request_intr(struct scsi_pkt *pkt)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate 	struct scsi_watch_result	result;
8760Sstevel@tonic-gate 	struct scsi_watch_request	*swr =
8777191Stl223370 	    (struct scsi_watch_request *)pkt->pkt_private;
8780Sstevel@tonic-gate 	struct scsi_status		*rqstatusp;
8790Sstevel@tonic-gate 	struct scsi_extended_sense	*rqsensep = NULL;
8800Sstevel@tonic-gate 	int				amt = 0;
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
8837191Stl223370 	    "scsi_watch_intr: Entering ...\n");
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	/*
8860Sstevel@tonic-gate 	 * first check if it is the TUR or RQS pkt
8870Sstevel@tonic-gate 	 */
8880Sstevel@tonic-gate 	if (pkt == swr->swr_pkt) {
8890Sstevel@tonic-gate 		if (SCBP_C(pkt) != STATUS_GOOD &&
8907191Stl223370 		    SCBP_C(pkt) != STATUS_RESERVATION_CONFLICT) {
8910Sstevel@tonic-gate 			if (SCBP(pkt)->sts_chk &&
8920Sstevel@tonic-gate 			    ((pkt->pkt_state & STATE_ARQ_DONE) == 0)) {
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 				/*
8950Sstevel@tonic-gate 				 * submit the request sense pkt
8960Sstevel@tonic-gate 				 */
8970Sstevel@tonic-gate 				SW_DEBUG((dev_info_t *)NULL,
8987191Stl223370 				    sw_label, SCSI_DEBUG,
8997191Stl223370 				    "scsi_watch_intr: "
9007191Stl223370 				    "Submitting a Request Sense "
9017191Stl223370 				    "Packet\n");
9020Sstevel@tonic-gate 				if (scsi_transport(swr->swr_rqpkt) !=
9037191Stl223370 				    TRAN_ACCEPT) {
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 					/*
9060Sstevel@tonic-gate 					 * just give up and try again later
9070Sstevel@tonic-gate 					 */
9080Sstevel@tonic-gate 					SW_DEBUG((dev_info_t *)NULL,
9097191Stl223370 					    sw_label, SCSI_DEBUG,
9107191Stl223370 					    "scsi_watch_intr: "
9117191Stl223370 					    "Request Sense "
9127191Stl223370 					    "Transport Failed\n");
9130Sstevel@tonic-gate 					goto done;
9140Sstevel@tonic-gate 				}
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 				/*
9170Sstevel@tonic-gate 				 * wait for rqsense to complete
9180Sstevel@tonic-gate 				 */
9190Sstevel@tonic-gate 				return;
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 			} else	if (SCBP(pkt)->sts_chk) {
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 				/*
9240Sstevel@tonic-gate 				 * check the autorequest sense data
9250Sstevel@tonic-gate 				 */
9260Sstevel@tonic-gate 				struct scsi_arq_status	*arqstat =
9270Sstevel@tonic-gate 				    (struct scsi_arq_status *)pkt->pkt_scbp;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 				rqstatusp = &arqstat->sts_rqpkt_status;
9300Sstevel@tonic-gate 				rqsensep = &arqstat->sts_sensedata;
9310Sstevel@tonic-gate 				amt = swr->swr_sense_length -
9327191Stl223370 				    arqstat->sts_rqpkt_resid;
9330Sstevel@tonic-gate 				SW_DEBUG((dev_info_t *)NULL,
9347191Stl223370 				    sw_label, SCSI_DEBUG,
9357191Stl223370 				    "scsi_watch_intr: "
9367191Stl223370 				    "Auto Request Sense, amt=%x\n", amt);
9370Sstevel@tonic-gate 			}
9380Sstevel@tonic-gate 		}
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	} else if (pkt == swr->swr_rqpkt) {
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 		/*
9430Sstevel@tonic-gate 		 * check the request sense data
9440Sstevel@tonic-gate 		 */
9450Sstevel@tonic-gate 		rqstatusp = (struct scsi_status *)pkt->pkt_scbp;
9460Sstevel@tonic-gate 		rqsensep = (struct scsi_extended_sense *)
9477191Stl223370 		    swr->swr_rqbp->b_un.b_addr;
9480Sstevel@tonic-gate 		amt = swr->swr_sense_length - pkt->pkt_resid;
9490Sstevel@tonic-gate 		SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
9507191Stl223370 		    "scsi_watch_intr: "
9517191Stl223370 		    "Request Sense Completed, amt=%x\n", amt);
9520Sstevel@tonic-gate 	} else {
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 		/*
9550Sstevel@tonic-gate 		 * should not reach here!!!
9560Sstevel@tonic-gate 		 */
9570Sstevel@tonic-gate 		scsi_log((dev_info_t *)NULL, sw_label, CE_PANIC,
9587191Stl223370 		    "scsi_watch_intr: Bad Packet(0x%p)", (void *)pkt);
9590Sstevel@tonic-gate 	}
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	if (rqsensep) {
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 		/*
9640Sstevel@tonic-gate 		 * check rqsense status and data
9650Sstevel@tonic-gate 		 */
9660Sstevel@tonic-gate 		if (rqstatusp->sts_busy || rqstatusp->sts_chk) {
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 			/*
9690Sstevel@tonic-gate 			 * try again later
9700Sstevel@tonic-gate 			 */
9710Sstevel@tonic-gate 			SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
9727191Stl223370 			    "scsi_watch_intr: "
9737191Stl223370 			    "Auto Request Sense Failed - "
9747191Stl223370 			    "Busy or Check Condition\n");
9750Sstevel@tonic-gate 			goto done;
9760Sstevel@tonic-gate 		}
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 		SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
9797191Stl223370 		    "scsi_watch_intr: "
9807191Stl223370 		    "es_key=%x, adq=%x, amt=%x\n",
9817191Stl223370 		    rqsensep->es_key, rqsensep->es_add_code, amt);
9820Sstevel@tonic-gate 	}
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	/*
9850Sstevel@tonic-gate 	 * callback to target driver to do the real work
9860Sstevel@tonic-gate 	 */
9870Sstevel@tonic-gate 	result.statusp = SCBP(swr->swr_pkt);
9880Sstevel@tonic-gate 	result.sensep = rqsensep;
9890Sstevel@tonic-gate 	result.actual_sense_length = (uchar_t)amt;
9900Sstevel@tonic-gate 	result.pkt = swr->swr_pkt;
99110459SArtem.Kachitchkin@Sun.COM 	if (swr->swr_mmcbp != NULL) {
99210459SArtem.Kachitchkin@Sun.COM 		bcopy(swr->swr_mmcbp->b_un.b_addr, result.mmc_data, 8);
99310459SArtem.Kachitchkin@Sun.COM 	}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	if ((*swr->swr_callback)(swr->swr_callback_arg, &result)) {
9960Sstevel@tonic-gate 		swr->swr_what = SWR_STOP;
9970Sstevel@tonic-gate 	}
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate done:
10000Sstevel@tonic-gate 	swr->swr_busy = 0;
10010Sstevel@tonic-gate 	mutex_enter(&cpr_mutex);
10020Sstevel@tonic-gate 	sw_cmd_count --;
10030Sstevel@tonic-gate 	if (!sw_cmd_count) {
10040Sstevel@tonic-gate 		CALLB_CPR_SAFE_BEGIN(&cpr_info);
10050Sstevel@tonic-gate 		sw_cpr_flag = 1;
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 	mutex_exit(&cpr_mutex);
10080Sstevel@tonic-gate }
10098330SLarry.Liu@Sun.COM 
10108330SLarry.Liu@Sun.COM /*
10118330SLarry.Liu@Sun.COM  * scsi_watch_get_ref_count
10128330SLarry.Liu@Sun.COM  * called by clients to query the reference count for a given token.
10138330SLarry.Liu@Sun.COM  * return the number of reference count or 0 if the given token is
10148330SLarry.Liu@Sun.COM  * not found.
10158330SLarry.Liu@Sun.COM  */
10168330SLarry.Liu@Sun.COM int
scsi_watch_get_ref_count(opaque_t token)10178330SLarry.Liu@Sun.COM scsi_watch_get_ref_count(opaque_t token)
10188330SLarry.Liu@Sun.COM {
10198330SLarry.Liu@Sun.COM 	struct scsi_watch_request *swr =
10208330SLarry.Liu@Sun.COM 	    (struct scsi_watch_request *)token;
10218330SLarry.Liu@Sun.COM 	struct scsi_watch_request *sswr;
10228330SLarry.Liu@Sun.COM 	int rval = 0;
10238330SLarry.Liu@Sun.COM 
10248330SLarry.Liu@Sun.COM 	SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG,
10258330SLarry.Liu@Sun.COM 	    "scsi_watch_get_ref_count: Entering(0x%p) ...\n",
10268330SLarry.Liu@Sun.COM 	    (void *)swr);
10278330SLarry.Liu@Sun.COM 	mutex_enter(&sw.sw_mutex);
10288330SLarry.Liu@Sun.COM 
10298330SLarry.Liu@Sun.COM 	sswr = sw.sw_head;
10308330SLarry.Liu@Sun.COM 	while (sswr) {
10318330SLarry.Liu@Sun.COM 		if (sswr == swr) {
10328330SLarry.Liu@Sun.COM 			rval = swr->swr_ref;
10338330SLarry.Liu@Sun.COM 			mutex_exit(&sw.sw_mutex);
10348330SLarry.Liu@Sun.COM 			return (rval);
10358330SLarry.Liu@Sun.COM 		}
10368330SLarry.Liu@Sun.COM 		sswr = sswr->swr_next;
10378330SLarry.Liu@Sun.COM 	}
10388330SLarry.Liu@Sun.COM 
10398330SLarry.Liu@Sun.COM 	mutex_exit(&sw.sw_mutex);
10408330SLarry.Liu@Sun.COM 	return (rval);
10418330SLarry.Liu@Sun.COM }
1042