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