Home | History | Annotate | Line # | Download | only in scsipi
scsipi_base.c revision 1.178.2.2
      1  1.178.2.2  christos /*	$NetBSD: scsipi_base.c,v 1.178.2.2 2017/07/14 17:50:12 christos Exp $	*/
      2  1.178.2.2  christos 
      3  1.178.2.2  christos /*-
      4  1.178.2.2  christos  * Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc.
      5  1.178.2.2  christos  * All rights reserved.
      6  1.178.2.2  christos  *
      7  1.178.2.2  christos  * This code is derived from software contributed to The NetBSD Foundation
      8  1.178.2.2  christos  * by Charles M. Hannum; by Jason R. Thorpe of the Numerical Aerospace
      9  1.178.2.2  christos  * Simulation Facility, NASA Ames Research Center.
     10  1.178.2.2  christos  *
     11  1.178.2.2  christos  * Redistribution and use in source and binary forms, with or without
     12  1.178.2.2  christos  * modification, are permitted provided that the following conditions
     13  1.178.2.2  christos  * are met:
     14  1.178.2.2  christos  * 1. Redistributions of source code must retain the above copyright
     15  1.178.2.2  christos  *    notice, this list of conditions and the following disclaimer.
     16  1.178.2.2  christos  * 2. Redistributions in binary form must reproduce the above copyright
     17  1.178.2.2  christos  *    notice, this list of conditions and the following disclaimer in the
     18  1.178.2.2  christos  *    documentation and/or other materials provided with the distribution.
     19  1.178.2.2  christos  *
     20  1.178.2.2  christos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  1.178.2.2  christos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  1.178.2.2  christos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  1.178.2.2  christos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  1.178.2.2  christos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  1.178.2.2  christos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  1.178.2.2  christos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  1.178.2.2  christos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  1.178.2.2  christos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  1.178.2.2  christos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  1.178.2.2  christos  * POSSIBILITY OF SUCH DAMAGE.
     31  1.178.2.2  christos  */
     32  1.178.2.2  christos 
     33  1.178.2.2  christos #include <sys/cdefs.h>
     34  1.178.2.2  christos __KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.178.2.2 2017/07/14 17:50:12 christos Exp $");
     35  1.178.2.2  christos 
     36  1.178.2.2  christos #ifdef _KERNEL_OPT
     37  1.178.2.2  christos #include "opt_scsi.h"
     38  1.178.2.2  christos #endif
     39  1.178.2.2  christos 
     40  1.178.2.2  christos #include <sys/param.h>
     41  1.178.2.2  christos #include <sys/systm.h>
     42  1.178.2.2  christos #include <sys/kernel.h>
     43  1.178.2.2  christos #include <sys/buf.h>
     44  1.178.2.2  christos #include <sys/uio.h>
     45  1.178.2.2  christos #include <sys/malloc.h>
     46  1.178.2.2  christos #include <sys/pool.h>
     47  1.178.2.2  christos #include <sys/errno.h>
     48  1.178.2.2  christos #include <sys/device.h>
     49  1.178.2.2  christos #include <sys/proc.h>
     50  1.178.2.2  christos #include <sys/kthread.h>
     51  1.178.2.2  christos #include <sys/hash.h>
     52  1.178.2.2  christos #include <sys/atomic.h>
     53  1.178.2.2  christos 
     54  1.178.2.2  christos #include <dev/scsipi/scsi_spc.h>
     55  1.178.2.2  christos #include <dev/scsipi/scsipi_all.h>
     56  1.178.2.2  christos #include <dev/scsipi/scsipi_disk.h>
     57  1.178.2.2  christos #include <dev/scsipi/scsipiconf.h>
     58  1.178.2.2  christos #include <dev/scsipi/scsipi_base.h>
     59  1.178.2.2  christos 
     60  1.178.2.2  christos #include <dev/scsipi/scsi_all.h>
     61  1.178.2.2  christos #include <dev/scsipi/scsi_message.h>
     62  1.178.2.2  christos 
     63  1.178.2.2  christos #include <machine/param.h>
     64  1.178.2.2  christos 
     65  1.178.2.2  christos static int	scsipi_complete(struct scsipi_xfer *);
     66  1.178.2.2  christos static void	scsipi_request_sense(struct scsipi_xfer *);
     67  1.178.2.2  christos static int	scsipi_enqueue(struct scsipi_xfer *);
     68  1.178.2.2  christos static void	scsipi_run_queue(struct scsipi_channel *chan);
     69  1.178.2.2  christos 
     70  1.178.2.2  christos static void	scsipi_completion_thread(void *);
     71  1.178.2.2  christos 
     72  1.178.2.2  christos static void	scsipi_get_tag(struct scsipi_xfer *);
     73  1.178.2.2  christos static void	scsipi_put_tag(struct scsipi_xfer *);
     74  1.178.2.2  christos 
     75  1.178.2.2  christos static int	scsipi_get_resource(struct scsipi_channel *);
     76  1.178.2.2  christos static void	scsipi_put_resource(struct scsipi_channel *);
     77  1.178.2.2  christos 
     78  1.178.2.2  christos static void	scsipi_async_event_max_openings(struct scsipi_channel *,
     79  1.178.2.2  christos 		    struct scsipi_max_openings *);
     80  1.178.2.2  christos static void	scsipi_async_event_channel_reset(struct scsipi_channel *);
     81  1.178.2.2  christos 
     82  1.178.2.2  christos static void	scsipi_channel_freeze_locked(struct scsipi_channel *, int);
     83  1.178.2.2  christos 
     84  1.178.2.2  christos static void	scsipi_adapter_lock(struct scsipi_adapter *adapt);
     85  1.178.2.2  christos static void	scsipi_adapter_unlock(struct scsipi_adapter *adapt);
     86  1.178.2.2  christos 
     87  1.178.2.2  christos static struct pool scsipi_xfer_pool;
     88  1.178.2.2  christos 
     89  1.178.2.2  christos int scsipi_xs_count = 0;
     90  1.178.2.2  christos 
     91  1.178.2.2  christos /*
     92  1.178.2.2  christos  * scsipi_init:
     93  1.178.2.2  christos  *
     94  1.178.2.2  christos  *	Called when a scsibus or atapibus is attached to the system
     95  1.178.2.2  christos  *	to initialize shared data structures.
     96  1.178.2.2  christos  */
     97  1.178.2.2  christos void
     98  1.178.2.2  christos scsipi_init(void)
     99  1.178.2.2  christos {
    100  1.178.2.2  christos 	static int scsipi_init_done;
    101  1.178.2.2  christos 
    102  1.178.2.2  christos 	if (scsipi_init_done)
    103  1.178.2.2  christos 		return;
    104  1.178.2.2  christos 	scsipi_init_done = 1;
    105  1.178.2.2  christos 
    106  1.178.2.2  christos 	/* Initialize the scsipi_xfer pool. */
    107  1.178.2.2  christos 	pool_init(&scsipi_xfer_pool, sizeof(struct scsipi_xfer), 0,
    108  1.178.2.2  christos 	    0, 0, "scxspl", NULL, IPL_BIO);
    109  1.178.2.2  christos 	if (pool_prime(&scsipi_xfer_pool,
    110  1.178.2.2  christos 	    PAGE_SIZE / sizeof(struct scsipi_xfer)) == ENOMEM) {
    111  1.178.2.2  christos 		printf("WARNING: not enough memory for scsipi_xfer_pool\n");
    112  1.178.2.2  christos 	}
    113  1.178.2.2  christos 
    114  1.178.2.2  christos 	scsipi_ioctl_init();
    115  1.178.2.2  christos }
    116  1.178.2.2  christos 
    117  1.178.2.2  christos /*
    118  1.178.2.2  christos  * scsipi_channel_init:
    119  1.178.2.2  christos  *
    120  1.178.2.2  christos  *	Initialize a scsipi_channel when it is attached.
    121  1.178.2.2  christos  */
    122  1.178.2.2  christos int
    123  1.178.2.2  christos scsipi_channel_init(struct scsipi_channel *chan)
    124  1.178.2.2  christos {
    125  1.178.2.2  christos 	struct scsipi_adapter *adapt = chan->chan_adapter;
    126  1.178.2.2  christos 	int i;
    127  1.178.2.2  christos 
    128  1.178.2.2  christos 	/* Initialize shared data. */
    129  1.178.2.2  christos 	scsipi_init();
    130  1.178.2.2  christos 
    131  1.178.2.2  christos 	/* Initialize the queues. */
    132  1.178.2.2  christos 	TAILQ_INIT(&chan->chan_queue);
    133  1.178.2.2  christos 	TAILQ_INIT(&chan->chan_complete);
    134  1.178.2.2  christos 
    135  1.178.2.2  christos 	for (i = 0; i < SCSIPI_CHAN_PERIPH_BUCKETS; i++)
    136  1.178.2.2  christos 		LIST_INIT(&chan->chan_periphtab[i]);
    137  1.178.2.2  christos 
    138  1.178.2.2  christos 	/*
    139  1.178.2.2  christos 	 * Create the asynchronous completion thread.
    140  1.178.2.2  christos 	 */
    141  1.178.2.2  christos 	if (kthread_create(PRI_NONE, 0, NULL, scsipi_completion_thread, chan,
    142  1.178.2.2  christos 	    &chan->chan_thread, "%s", chan->chan_name)) {
    143  1.178.2.2  christos 		aprint_error_dev(adapt->adapt_dev, "unable to create completion thread for "
    144  1.178.2.2  christos 		    "channel %d\n", chan->chan_channel);
    145  1.178.2.2  christos 		panic("scsipi_channel_init");
    146  1.178.2.2  christos 	}
    147  1.178.2.2  christos 
    148  1.178.2.2  christos 	return 0;
    149  1.178.2.2  christos }
    150  1.178.2.2  christos 
    151  1.178.2.2  christos /*
    152  1.178.2.2  christos  * scsipi_channel_shutdown:
    153  1.178.2.2  christos  *
    154  1.178.2.2  christos  *	Shutdown a scsipi_channel.
    155  1.178.2.2  christos  */
    156  1.178.2.2  christos void
    157  1.178.2.2  christos scsipi_channel_shutdown(struct scsipi_channel *chan)
    158  1.178.2.2  christos {
    159  1.178.2.2  christos 
    160  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
    161  1.178.2.2  christos 	/*
    162  1.178.2.2  christos 	 * Shut down the completion thread.
    163  1.178.2.2  christos 	 */
    164  1.178.2.2  christos 	chan->chan_tflags |= SCSIPI_CHANT_SHUTDOWN;
    165  1.178.2.2  christos 	cv_broadcast(chan_cv_complete(chan));
    166  1.178.2.2  christos 
    167  1.178.2.2  christos 	/*
    168  1.178.2.2  christos 	 * Now wait for the thread to exit.
    169  1.178.2.2  christos 	 */
    170  1.178.2.2  christos 	while (chan->chan_thread != NULL)
    171  1.178.2.2  christos 		cv_wait(chan_cv_thread(chan), chan_mtx(chan));
    172  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
    173  1.178.2.2  christos }
    174  1.178.2.2  christos 
    175  1.178.2.2  christos static uint32_t
    176  1.178.2.2  christos scsipi_chan_periph_hash(uint64_t t, uint64_t l)
    177  1.178.2.2  christos {
    178  1.178.2.2  christos 	uint32_t hash;
    179  1.178.2.2  christos 
    180  1.178.2.2  christos 	hash = hash32_buf(&t, sizeof(t), HASH32_BUF_INIT);
    181  1.178.2.2  christos 	hash = hash32_buf(&l, sizeof(l), hash);
    182  1.178.2.2  christos 
    183  1.178.2.2  christos 	return hash & SCSIPI_CHAN_PERIPH_HASHMASK;
    184  1.178.2.2  christos }
    185  1.178.2.2  christos 
    186  1.178.2.2  christos /*
    187  1.178.2.2  christos  * scsipi_insert_periph:
    188  1.178.2.2  christos  *
    189  1.178.2.2  christos  *	Insert a periph into the channel.
    190  1.178.2.2  christos  */
    191  1.178.2.2  christos void
    192  1.178.2.2  christos scsipi_insert_periph(struct scsipi_channel *chan, struct scsipi_periph *periph)
    193  1.178.2.2  christos {
    194  1.178.2.2  christos 	uint32_t hash;
    195  1.178.2.2  christos 
    196  1.178.2.2  christos 	hash = scsipi_chan_periph_hash(periph->periph_target,
    197  1.178.2.2  christos 	    periph->periph_lun);
    198  1.178.2.2  christos 
    199  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
    200  1.178.2.2  christos 	LIST_INSERT_HEAD(&chan->chan_periphtab[hash], periph, periph_hash);
    201  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
    202  1.178.2.2  christos }
    203  1.178.2.2  christos 
    204  1.178.2.2  christos /*
    205  1.178.2.2  christos  * scsipi_remove_periph:
    206  1.178.2.2  christos  *
    207  1.178.2.2  christos  *	Remove a periph from the channel.
    208  1.178.2.2  christos  */
    209  1.178.2.2  christos void
    210  1.178.2.2  christos scsipi_remove_periph(struct scsipi_channel *chan,
    211  1.178.2.2  christos     struct scsipi_periph *periph)
    212  1.178.2.2  christos {
    213  1.178.2.2  christos 
    214  1.178.2.2  christos 	LIST_REMOVE(periph, periph_hash);
    215  1.178.2.2  christos }
    216  1.178.2.2  christos 
    217  1.178.2.2  christos /*
    218  1.178.2.2  christos  * scsipi_lookup_periph:
    219  1.178.2.2  christos  *
    220  1.178.2.2  christos  *	Lookup a periph on the specified channel.
    221  1.178.2.2  christos  */
    222  1.178.2.2  christos static struct scsipi_periph *
    223  1.178.2.2  christos scsipi_lookup_periph_internal(struct scsipi_channel *chan, int target, int lun, bool lock)
    224  1.178.2.2  christos {
    225  1.178.2.2  christos 	struct scsipi_periph *periph;
    226  1.178.2.2  christos 	uint32_t hash;
    227  1.178.2.2  christos 
    228  1.178.2.2  christos 	if (target >= chan->chan_ntargets ||
    229  1.178.2.2  christos 	    lun >= chan->chan_nluns)
    230  1.178.2.2  christos 		return NULL;
    231  1.178.2.2  christos 
    232  1.178.2.2  christos 	hash = scsipi_chan_periph_hash(target, lun);
    233  1.178.2.2  christos 
    234  1.178.2.2  christos 	if (lock)
    235  1.178.2.2  christos 		mutex_enter(chan_mtx(chan));
    236  1.178.2.2  christos 	LIST_FOREACH(periph, &chan->chan_periphtab[hash], periph_hash) {
    237  1.178.2.2  christos 		if (periph->periph_target == target &&
    238  1.178.2.2  christos 		    periph->periph_lun == lun)
    239  1.178.2.2  christos 			break;
    240  1.178.2.2  christos 	}
    241  1.178.2.2  christos 	if (lock)
    242  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
    243  1.178.2.2  christos 
    244  1.178.2.2  christos 	return periph;
    245  1.178.2.2  christos }
    246  1.178.2.2  christos 
    247  1.178.2.2  christos struct scsipi_periph *
    248  1.178.2.2  christos scsipi_lookup_periph_locked(struct scsipi_channel *chan, int target, int lun)
    249  1.178.2.2  christos {
    250  1.178.2.2  christos 	return scsipi_lookup_periph_internal(chan, target, lun, false);
    251  1.178.2.2  christos }
    252  1.178.2.2  christos 
    253  1.178.2.2  christos struct scsipi_periph *
    254  1.178.2.2  christos scsipi_lookup_periph(struct scsipi_channel *chan, int target, int lun)
    255  1.178.2.2  christos {
    256  1.178.2.2  christos 	return scsipi_lookup_periph_internal(chan, target, lun, true);
    257  1.178.2.2  christos }
    258  1.178.2.2  christos 
    259  1.178.2.2  christos /*
    260  1.178.2.2  christos  * scsipi_get_resource:
    261  1.178.2.2  christos  *
    262  1.178.2.2  christos  *	Allocate a single xfer `resource' from the channel.
    263  1.178.2.2  christos  *
    264  1.178.2.2  christos  *	NOTE: Must be called with channel lock held
    265  1.178.2.2  christos  */
    266  1.178.2.2  christos static int
    267  1.178.2.2  christos scsipi_get_resource(struct scsipi_channel *chan)
    268  1.178.2.2  christos {
    269  1.178.2.2  christos 	struct scsipi_adapter *adapt = chan->chan_adapter;
    270  1.178.2.2  christos 
    271  1.178.2.2  christos 	if (chan->chan_flags & SCSIPI_CHAN_OPENINGS) {
    272  1.178.2.2  christos 		if (chan->chan_openings > 0) {
    273  1.178.2.2  christos 			chan->chan_openings--;
    274  1.178.2.2  christos 			return 1;
    275  1.178.2.2  christos 		}
    276  1.178.2.2  christos 		return 0;
    277  1.178.2.2  christos 	}
    278  1.178.2.2  christos 
    279  1.178.2.2  christos 	if (adapt->adapt_openings > 0) {
    280  1.178.2.2  christos 		adapt->adapt_openings--;
    281  1.178.2.2  christos 		return 1;
    282  1.178.2.2  christos 	}
    283  1.178.2.2  christos 	return 0;
    284  1.178.2.2  christos }
    285  1.178.2.2  christos 
    286  1.178.2.2  christos /*
    287  1.178.2.2  christos  * scsipi_grow_resources:
    288  1.178.2.2  christos  *
    289  1.178.2.2  christos  *	Attempt to grow resources for a channel.  If this succeeds,
    290  1.178.2.2  christos  *	we allocate one for our caller.
    291  1.178.2.2  christos  *
    292  1.178.2.2  christos  *	NOTE: Must be called with channel lock held
    293  1.178.2.2  christos  */
    294  1.178.2.2  christos static inline int
    295  1.178.2.2  christos scsipi_grow_resources(struct scsipi_channel *chan)
    296  1.178.2.2  christos {
    297  1.178.2.2  christos 
    298  1.178.2.2  christos 	if (chan->chan_flags & SCSIPI_CHAN_CANGROW) {
    299  1.178.2.2  christos 		if ((chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
    300  1.178.2.2  christos 			mutex_exit(chan_mtx(chan));
    301  1.178.2.2  christos 			scsipi_adapter_request(chan,
    302  1.178.2.2  christos 			    ADAPTER_REQ_GROW_RESOURCES, NULL);
    303  1.178.2.2  christos 			mutex_enter(chan_mtx(chan));
    304  1.178.2.2  christos 			return scsipi_get_resource(chan);
    305  1.178.2.2  christos 		}
    306  1.178.2.2  christos 		/*
    307  1.178.2.2  christos 		 * ask the channel thread to do it. It'll have to thaw the
    308  1.178.2.2  christos 		 * queue
    309  1.178.2.2  christos 		 */
    310  1.178.2.2  christos 		scsipi_channel_freeze_locked(chan, 1);
    311  1.178.2.2  christos 		chan->chan_tflags |= SCSIPI_CHANT_GROWRES;
    312  1.178.2.2  christos 		cv_broadcast(chan_cv_complete(chan));
    313  1.178.2.2  christos 		return 0;
    314  1.178.2.2  christos 	}
    315  1.178.2.2  christos 
    316  1.178.2.2  christos 	return 0;
    317  1.178.2.2  christos }
    318  1.178.2.2  christos 
    319  1.178.2.2  christos /*
    320  1.178.2.2  christos  * scsipi_put_resource:
    321  1.178.2.2  christos  *
    322  1.178.2.2  christos  *	Free a single xfer `resource' to the channel.
    323  1.178.2.2  christos  *
    324  1.178.2.2  christos  *	NOTE: Must be called with channel lock held
    325  1.178.2.2  christos  */
    326  1.178.2.2  christos static void
    327  1.178.2.2  christos scsipi_put_resource(struct scsipi_channel *chan)
    328  1.178.2.2  christos {
    329  1.178.2.2  christos 	struct scsipi_adapter *adapt = chan->chan_adapter;
    330  1.178.2.2  christos 
    331  1.178.2.2  christos 	if (chan->chan_flags & SCSIPI_CHAN_OPENINGS)
    332  1.178.2.2  christos 		chan->chan_openings++;
    333  1.178.2.2  christos 	else
    334  1.178.2.2  christos 		adapt->adapt_openings++;
    335  1.178.2.2  christos }
    336  1.178.2.2  christos 
    337  1.178.2.2  christos /*
    338  1.178.2.2  christos  * scsipi_get_tag:
    339  1.178.2.2  christos  *
    340  1.178.2.2  christos  *	Get a tag ID for the specified xfer.
    341  1.178.2.2  christos  *
    342  1.178.2.2  christos  *	NOTE: Must be called with channel lock held
    343  1.178.2.2  christos  */
    344  1.178.2.2  christos static void
    345  1.178.2.2  christos scsipi_get_tag(struct scsipi_xfer *xs)
    346  1.178.2.2  christos {
    347  1.178.2.2  christos 	struct scsipi_periph *periph = xs->xs_periph;
    348  1.178.2.2  christos 	int bit, tag;
    349  1.178.2.2  christos 	u_int word;
    350  1.178.2.2  christos 
    351  1.178.2.2  christos 	bit = 0;	/* XXX gcc */
    352  1.178.2.2  christos 	for (word = 0; word < PERIPH_NTAGWORDS; word++) {
    353  1.178.2.2  christos 		bit = ffs(periph->periph_freetags[word]);
    354  1.178.2.2  christos 		if (bit != 0)
    355  1.178.2.2  christos 			break;
    356  1.178.2.2  christos 	}
    357  1.178.2.2  christos #ifdef DIAGNOSTIC
    358  1.178.2.2  christos 	if (word == PERIPH_NTAGWORDS) {
    359  1.178.2.2  christos 		scsipi_printaddr(periph);
    360  1.178.2.2  christos 		printf("no free tags\n");
    361  1.178.2.2  christos 		panic("scsipi_get_tag");
    362  1.178.2.2  christos 	}
    363  1.178.2.2  christos #endif
    364  1.178.2.2  christos 
    365  1.178.2.2  christos 	bit -= 1;
    366  1.178.2.2  christos 	periph->periph_freetags[word] &= ~(1 << bit);
    367  1.178.2.2  christos 	tag = (word << 5) | bit;
    368  1.178.2.2  christos 
    369  1.178.2.2  christos 	/* XXX Should eventually disallow this completely. */
    370  1.178.2.2  christos 	if (tag >= periph->periph_openings) {
    371  1.178.2.2  christos 		scsipi_printaddr(periph);
    372  1.178.2.2  christos 		printf("WARNING: tag %d greater than available openings %d\n",
    373  1.178.2.2  christos 		    tag, periph->periph_openings);
    374  1.178.2.2  christos 	}
    375  1.178.2.2  christos 
    376  1.178.2.2  christos 	xs->xs_tag_id = tag;
    377  1.178.2.2  christos }
    378  1.178.2.2  christos 
    379  1.178.2.2  christos /*
    380  1.178.2.2  christos  * scsipi_put_tag:
    381  1.178.2.2  christos  *
    382  1.178.2.2  christos  *	Put the tag ID for the specified xfer back into the pool.
    383  1.178.2.2  christos  *
    384  1.178.2.2  christos  *	NOTE: Must be called with channel lock held
    385  1.178.2.2  christos  */
    386  1.178.2.2  christos static void
    387  1.178.2.2  christos scsipi_put_tag(struct scsipi_xfer *xs)
    388  1.178.2.2  christos {
    389  1.178.2.2  christos 	struct scsipi_periph *periph = xs->xs_periph;
    390  1.178.2.2  christos 	int word, bit;
    391  1.178.2.2  christos 
    392  1.178.2.2  christos 	word = xs->xs_tag_id >> 5;
    393  1.178.2.2  christos 	bit = xs->xs_tag_id & 0x1f;
    394  1.178.2.2  christos 
    395  1.178.2.2  christos 	periph->periph_freetags[word] |= (1 << bit);
    396  1.178.2.2  christos }
    397  1.178.2.2  christos 
    398  1.178.2.2  christos /*
    399  1.178.2.2  christos  * scsipi_get_xs:
    400  1.178.2.2  christos  *
    401  1.178.2.2  christos  *	Allocate an xfer descriptor and associate it with the
    402  1.178.2.2  christos  *	specified peripheral.  If the peripheral has no more
    403  1.178.2.2  christos  *	available command openings, we either block waiting for
    404  1.178.2.2  christos  *	one to become available, or fail.
    405  1.178.2.2  christos  *
    406  1.178.2.2  christos  *	When this routine is called with the channel lock held
    407  1.178.2.2  christos  *	the flags must include XS_CTL_NOSLEEP.
    408  1.178.2.2  christos  */
    409  1.178.2.2  christos struct scsipi_xfer *
    410  1.178.2.2  christos scsipi_get_xs(struct scsipi_periph *periph, int flags)
    411  1.178.2.2  christos {
    412  1.178.2.2  christos 	struct scsipi_xfer *xs;
    413  1.178.2.2  christos 	bool lock = (flags & XS_CTL_NOSLEEP) == 0;
    414  1.178.2.2  christos 
    415  1.178.2.2  christos 	SC_DEBUG(periph, SCSIPI_DB3, ("scsipi_get_xs\n"));
    416  1.178.2.2  christos 
    417  1.178.2.2  christos 	KASSERT(!cold);
    418  1.178.2.2  christos 
    419  1.178.2.2  christos #ifdef DIAGNOSTIC
    420  1.178.2.2  christos 	/*
    421  1.178.2.2  christos 	 * URGENT commands can never be ASYNC.
    422  1.178.2.2  christos 	 */
    423  1.178.2.2  christos 	if ((flags & (XS_CTL_URGENT|XS_CTL_ASYNC)) ==
    424  1.178.2.2  christos 	    (XS_CTL_URGENT|XS_CTL_ASYNC)) {
    425  1.178.2.2  christos 		scsipi_printaddr(periph);
    426  1.178.2.2  christos 		printf("URGENT and ASYNC\n");
    427  1.178.2.2  christos 		panic("scsipi_get_xs");
    428  1.178.2.2  christos 	}
    429  1.178.2.2  christos #endif
    430  1.178.2.2  christos 
    431  1.178.2.2  christos 	/*
    432  1.178.2.2  christos 	 * Wait for a command opening to become available.  Rules:
    433  1.178.2.2  christos 	 *
    434  1.178.2.2  christos 	 *	- All xfers must wait for an available opening.
    435  1.178.2.2  christos 	 *	  Exception: URGENT xfers can proceed when
    436  1.178.2.2  christos 	 *	  active == openings, because we use the opening
    437  1.178.2.2  christos 	 *	  of the command we're recovering for.
    438  1.178.2.2  christos 	 *	- if the periph has sense pending, only URGENT & REQSENSE
    439  1.178.2.2  christos 	 *	  xfers may proceed.
    440  1.178.2.2  christos 	 *
    441  1.178.2.2  christos 	 *	- If the periph is recovering, only URGENT xfers may
    442  1.178.2.2  christos 	 *	  proceed.
    443  1.178.2.2  christos 	 *
    444  1.178.2.2  christos 	 *	- If the periph is currently executing a recovery
    445  1.178.2.2  christos 	 *	  command, URGENT commands must block, because only
    446  1.178.2.2  christos 	 *	  one recovery command can execute at a time.
    447  1.178.2.2  christos 	 */
    448  1.178.2.2  christos 	if (lock)
    449  1.178.2.2  christos 		mutex_enter(chan_mtx(periph->periph_channel));
    450  1.178.2.2  christos 	for (;;) {
    451  1.178.2.2  christos 		if (flags & XS_CTL_URGENT) {
    452  1.178.2.2  christos 			if (periph->periph_active > periph->periph_openings)
    453  1.178.2.2  christos 				goto wait_for_opening;
    454  1.178.2.2  christos 			if (periph->periph_flags & PERIPH_SENSE) {
    455  1.178.2.2  christos 				if ((flags & XS_CTL_REQSENSE) == 0)
    456  1.178.2.2  christos 					goto wait_for_opening;
    457  1.178.2.2  christos 			} else {
    458  1.178.2.2  christos 				if ((periph->periph_flags &
    459  1.178.2.2  christos 				    PERIPH_RECOVERY_ACTIVE) != 0)
    460  1.178.2.2  christos 					goto wait_for_opening;
    461  1.178.2.2  christos 				periph->periph_flags |= PERIPH_RECOVERY_ACTIVE;
    462  1.178.2.2  christos 			}
    463  1.178.2.2  christos 			break;
    464  1.178.2.2  christos 		}
    465  1.178.2.2  christos 		if (periph->periph_active >= periph->periph_openings ||
    466  1.178.2.2  christos 		    (periph->periph_flags & PERIPH_RECOVERING) != 0)
    467  1.178.2.2  christos 			goto wait_for_opening;
    468  1.178.2.2  christos 		periph->periph_active++;
    469  1.178.2.2  christos 		break;
    470  1.178.2.2  christos 
    471  1.178.2.2  christos  wait_for_opening:
    472  1.178.2.2  christos 		if (flags & XS_CTL_NOSLEEP) {
    473  1.178.2.2  christos 			KASSERT(!lock);
    474  1.178.2.2  christos 			return NULL;
    475  1.178.2.2  christos 		}
    476  1.178.2.2  christos 		KASSERT(lock);
    477  1.178.2.2  christos 		SC_DEBUG(periph, SCSIPI_DB3, ("sleeping\n"));
    478  1.178.2.2  christos 		periph->periph_flags |= PERIPH_WAITING;
    479  1.178.2.2  christos 		cv_wait(periph_cv_periph(periph),
    480  1.178.2.2  christos 		    chan_mtx(periph->periph_channel));
    481  1.178.2.2  christos 	}
    482  1.178.2.2  christos 	if (lock)
    483  1.178.2.2  christos 		mutex_exit(chan_mtx(periph->periph_channel));
    484  1.178.2.2  christos 
    485  1.178.2.2  christos 	SC_DEBUG(periph, SCSIPI_DB3, ("calling pool_get\n"));
    486  1.178.2.2  christos 	xs = pool_get(&scsipi_xfer_pool,
    487  1.178.2.2  christos 	    ((flags & XS_CTL_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
    488  1.178.2.2  christos 	if (xs == NULL) {
    489  1.178.2.2  christos 		if (lock)
    490  1.178.2.2  christos 			mutex_enter(chan_mtx(periph->periph_channel));
    491  1.178.2.2  christos 		if (flags & XS_CTL_URGENT) {
    492  1.178.2.2  christos 			if ((flags & XS_CTL_REQSENSE) == 0)
    493  1.178.2.2  christos 				periph->periph_flags &= ~PERIPH_RECOVERY_ACTIVE;
    494  1.178.2.2  christos 		} else
    495  1.178.2.2  christos 			periph->periph_active--;
    496  1.178.2.2  christos 		if (lock)
    497  1.178.2.2  christos 			mutex_exit(chan_mtx(periph->periph_channel));
    498  1.178.2.2  christos 		scsipi_printaddr(periph);
    499  1.178.2.2  christos 		printf("unable to allocate %sscsipi_xfer\n",
    500  1.178.2.2  christos 		    (flags & XS_CTL_URGENT) ? "URGENT " : "");
    501  1.178.2.2  christos 	}
    502  1.178.2.2  christos 
    503  1.178.2.2  christos 	SC_DEBUG(periph, SCSIPI_DB3, ("returning\n"));
    504  1.178.2.2  christos 
    505  1.178.2.2  christos 	if (xs != NULL) {
    506  1.178.2.2  christos 		memset(xs, 0, sizeof(*xs));
    507  1.178.2.2  christos 		callout_init(&xs->xs_callout, 0);
    508  1.178.2.2  christos 		xs->xs_periph = periph;
    509  1.178.2.2  christos 		xs->xs_control = flags;
    510  1.178.2.2  christos 		xs->xs_status = 0;
    511  1.178.2.2  christos 		if ((flags & XS_CTL_NOSLEEP) == 0)
    512  1.178.2.2  christos 			mutex_enter(chan_mtx(periph->periph_channel));
    513  1.178.2.2  christos 		TAILQ_INSERT_TAIL(&periph->periph_xferq, xs, device_q);
    514  1.178.2.2  christos 		if ((flags & XS_CTL_NOSLEEP) == 0)
    515  1.178.2.2  christos 			mutex_exit(chan_mtx(periph->periph_channel));
    516  1.178.2.2  christos 	}
    517  1.178.2.2  christos 	return xs;
    518  1.178.2.2  christos }
    519  1.178.2.2  christos 
    520  1.178.2.2  christos /*
    521  1.178.2.2  christos  * scsipi_put_xs:
    522  1.178.2.2  christos  *
    523  1.178.2.2  christos  *	Release an xfer descriptor, decreasing the outstanding command
    524  1.178.2.2  christos  *	count for the peripheral.  If there is a thread waiting for
    525  1.178.2.2  christos  *	an opening, wake it up.  If not, kick any queued I/O the
    526  1.178.2.2  christos  *	peripheral may have.
    527  1.178.2.2  christos  *
    528  1.178.2.2  christos  *	NOTE: Must be called with channel lock held
    529  1.178.2.2  christos  */
    530  1.178.2.2  christos void
    531  1.178.2.2  christos scsipi_put_xs(struct scsipi_xfer *xs)
    532  1.178.2.2  christos {
    533  1.178.2.2  christos 	struct scsipi_periph *periph = xs->xs_periph;
    534  1.178.2.2  christos 	int flags = xs->xs_control;
    535  1.178.2.2  christos 
    536  1.178.2.2  christos 	SC_DEBUG(periph, SCSIPI_DB3, ("scsipi_free_xs\n"));
    537  1.178.2.2  christos 
    538  1.178.2.2  christos 	TAILQ_REMOVE(&periph->periph_xferq, xs, device_q);
    539  1.178.2.2  christos 	callout_destroy(&xs->xs_callout);
    540  1.178.2.2  christos 	pool_put(&scsipi_xfer_pool, xs);
    541  1.178.2.2  christos 
    542  1.178.2.2  christos #ifdef DIAGNOSTIC
    543  1.178.2.2  christos 	if ((periph->periph_flags & PERIPH_RECOVERY_ACTIVE) != 0 &&
    544  1.178.2.2  christos 	    periph->periph_active == 0) {
    545  1.178.2.2  christos 		scsipi_printaddr(periph);
    546  1.178.2.2  christos 		printf("recovery without a command to recovery for\n");
    547  1.178.2.2  christos 		panic("scsipi_put_xs");
    548  1.178.2.2  christos 	}
    549  1.178.2.2  christos #endif
    550  1.178.2.2  christos 
    551  1.178.2.2  christos 	if (flags & XS_CTL_URGENT) {
    552  1.178.2.2  christos 		if ((flags & XS_CTL_REQSENSE) == 0)
    553  1.178.2.2  christos 			periph->periph_flags &= ~PERIPH_RECOVERY_ACTIVE;
    554  1.178.2.2  christos 	} else
    555  1.178.2.2  christos 		periph->periph_active--;
    556  1.178.2.2  christos 	if (periph->periph_active == 0 &&
    557  1.178.2.2  christos 	    (periph->periph_flags & PERIPH_WAITDRAIN) != 0) {
    558  1.178.2.2  christos 		periph->periph_flags &= ~PERIPH_WAITDRAIN;
    559  1.178.2.2  christos 		cv_broadcast(periph_cv_active(periph));
    560  1.178.2.2  christos 	}
    561  1.178.2.2  christos 
    562  1.178.2.2  christos 	if (periph->periph_flags & PERIPH_WAITING) {
    563  1.178.2.2  christos 		periph->periph_flags &= ~PERIPH_WAITING;
    564  1.178.2.2  christos 		cv_broadcast(periph_cv_periph(periph));
    565  1.178.2.2  christos 	} else {
    566  1.178.2.2  christos 		if (periph->periph_switch->psw_start != NULL &&
    567  1.178.2.2  christos 		    device_is_active(periph->periph_dev)) {
    568  1.178.2.2  christos 			SC_DEBUG(periph, SCSIPI_DB2,
    569  1.178.2.2  christos 			    ("calling private start()\n"));
    570  1.178.2.2  christos 			(*periph->periph_switch->psw_start)(periph);
    571  1.178.2.2  christos 		}
    572  1.178.2.2  christos 	}
    573  1.178.2.2  christos }
    574  1.178.2.2  christos 
    575  1.178.2.2  christos /*
    576  1.178.2.2  christos  * scsipi_channel_freeze:
    577  1.178.2.2  christos  *
    578  1.178.2.2  christos  *	Freeze a channel's xfer queue.
    579  1.178.2.2  christos  */
    580  1.178.2.2  christos void
    581  1.178.2.2  christos scsipi_channel_freeze(struct scsipi_channel *chan, int count)
    582  1.178.2.2  christos {
    583  1.178.2.2  christos 	bool lock = chan_running(chan) > 0;
    584  1.178.2.2  christos 
    585  1.178.2.2  christos 	if (lock)
    586  1.178.2.2  christos 		mutex_enter(chan_mtx(chan));
    587  1.178.2.2  christos 	chan->chan_qfreeze += count;
    588  1.178.2.2  christos 	if (lock)
    589  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
    590  1.178.2.2  christos }
    591  1.178.2.2  christos 
    592  1.178.2.2  christos static void
    593  1.178.2.2  christos scsipi_channel_freeze_locked(struct scsipi_channel *chan, int count)
    594  1.178.2.2  christos {
    595  1.178.2.2  christos 
    596  1.178.2.2  christos 	chan->chan_qfreeze += count;
    597  1.178.2.2  christos }
    598  1.178.2.2  christos 
    599  1.178.2.2  christos /*
    600  1.178.2.2  christos  * scsipi_channel_thaw:
    601  1.178.2.2  christos  *
    602  1.178.2.2  christos  *	Thaw a channel's xfer queue.
    603  1.178.2.2  christos  */
    604  1.178.2.2  christos void
    605  1.178.2.2  christos scsipi_channel_thaw(struct scsipi_channel *chan, int count)
    606  1.178.2.2  christos {
    607  1.178.2.2  christos 	bool lock = chan_running(chan) > 0;
    608  1.178.2.2  christos 
    609  1.178.2.2  christos 	if (lock)
    610  1.178.2.2  christos 		mutex_enter(chan_mtx(chan));
    611  1.178.2.2  christos 	chan->chan_qfreeze -= count;
    612  1.178.2.2  christos 	/*
    613  1.178.2.2  christos 	 * Don't let the freeze count go negative.
    614  1.178.2.2  christos 	 *
    615  1.178.2.2  christos 	 * Presumably the adapter driver could keep track of this,
    616  1.178.2.2  christos 	 * but it might just be easier to do this here so as to allow
    617  1.178.2.2  christos 	 * multiple callers, including those outside the adapter driver.
    618  1.178.2.2  christos 	 */
    619  1.178.2.2  christos 	if (chan->chan_qfreeze < 0) {
    620  1.178.2.2  christos 		chan->chan_qfreeze = 0;
    621  1.178.2.2  christos 	}
    622  1.178.2.2  christos 	if (lock)
    623  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
    624  1.178.2.2  christos 
    625  1.178.2.2  christos 	/*
    626  1.178.2.2  christos 	 * until the channel is running
    627  1.178.2.2  christos 	 */
    628  1.178.2.2  christos 	if (!lock)
    629  1.178.2.2  christos 		return;
    630  1.178.2.2  christos 
    631  1.178.2.2  christos 	/*
    632  1.178.2.2  christos 	 * Kick the channel's queue here.  Note, we may be running in
    633  1.178.2.2  christos 	 * interrupt context (softclock or HBA's interrupt), so the adapter
    634  1.178.2.2  christos 	 * driver had better not sleep.
    635  1.178.2.2  christos 	 */
    636  1.178.2.2  christos 	if (chan->chan_qfreeze == 0)
    637  1.178.2.2  christos 		scsipi_run_queue(chan);
    638  1.178.2.2  christos }
    639  1.178.2.2  christos 
    640  1.178.2.2  christos /*
    641  1.178.2.2  christos  * scsipi_channel_timed_thaw:
    642  1.178.2.2  christos  *
    643  1.178.2.2  christos  *	Thaw a channel after some time has expired. This will also
    644  1.178.2.2  christos  * 	run the channel's queue if the freeze count has reached 0.
    645  1.178.2.2  christos  */
    646  1.178.2.2  christos void
    647  1.178.2.2  christos scsipi_channel_timed_thaw(void *arg)
    648  1.178.2.2  christos {
    649  1.178.2.2  christos 	struct scsipi_channel *chan = arg;
    650  1.178.2.2  christos 
    651  1.178.2.2  christos 	scsipi_channel_thaw(chan, 1);
    652  1.178.2.2  christos }
    653  1.178.2.2  christos 
    654  1.178.2.2  christos /*
    655  1.178.2.2  christos  * scsipi_periph_freeze:
    656  1.178.2.2  christos  *
    657  1.178.2.2  christos  *	Freeze a device's xfer queue.
    658  1.178.2.2  christos  */
    659  1.178.2.2  christos void
    660  1.178.2.2  christos scsipi_periph_freeze_locked(struct scsipi_periph *periph, int count)
    661  1.178.2.2  christos {
    662  1.178.2.2  christos 
    663  1.178.2.2  christos 	periph->periph_qfreeze += count;
    664  1.178.2.2  christos }
    665  1.178.2.2  christos 
    666  1.178.2.2  christos /*
    667  1.178.2.2  christos  * scsipi_periph_thaw:
    668  1.178.2.2  christos  *
    669  1.178.2.2  christos  *	Thaw a device's xfer queue.
    670  1.178.2.2  christos  */
    671  1.178.2.2  christos void
    672  1.178.2.2  christos scsipi_periph_thaw_locked(struct scsipi_periph *periph, int count)
    673  1.178.2.2  christos {
    674  1.178.2.2  christos 
    675  1.178.2.2  christos 	periph->periph_qfreeze -= count;
    676  1.178.2.2  christos #ifdef DIAGNOSTIC
    677  1.178.2.2  christos 	if (periph->periph_qfreeze < 0) {
    678  1.178.2.2  christos 		static const char pc[] = "periph freeze count < 0";
    679  1.178.2.2  christos 		scsipi_printaddr(periph);
    680  1.178.2.2  christos 		printf("%s\n", pc);
    681  1.178.2.2  christos 		panic(pc);
    682  1.178.2.2  christos 	}
    683  1.178.2.2  christos #endif
    684  1.178.2.2  christos 	if (periph->periph_qfreeze == 0 &&
    685  1.178.2.2  christos 	    (periph->periph_flags & PERIPH_WAITING) != 0)
    686  1.178.2.2  christos 		cv_broadcast(periph_cv_periph(periph));
    687  1.178.2.2  christos }
    688  1.178.2.2  christos 
    689  1.178.2.2  christos void
    690  1.178.2.2  christos scsipi_periph_freeze(struct scsipi_periph *periph, int count)
    691  1.178.2.2  christos {
    692  1.178.2.2  christos 
    693  1.178.2.2  christos 	mutex_enter(chan_mtx(periph->periph_channel));
    694  1.178.2.2  christos 	scsipi_periph_freeze_locked(periph, count);
    695  1.178.2.2  christos 	mutex_exit(chan_mtx(periph->periph_channel));
    696  1.178.2.2  christos }
    697  1.178.2.2  christos 
    698  1.178.2.2  christos void
    699  1.178.2.2  christos scsipi_periph_thaw(struct scsipi_periph *periph, int count)
    700  1.178.2.2  christos {
    701  1.178.2.2  christos 
    702  1.178.2.2  christos 	mutex_enter(chan_mtx(periph->periph_channel));
    703  1.178.2.2  christos 	scsipi_periph_thaw_locked(periph, count);
    704  1.178.2.2  christos 	mutex_exit(chan_mtx(periph->periph_channel));
    705  1.178.2.2  christos }
    706  1.178.2.2  christos 
    707  1.178.2.2  christos /*
    708  1.178.2.2  christos  * scsipi_periph_timed_thaw:
    709  1.178.2.2  christos  *
    710  1.178.2.2  christos  *	Thaw a device after some time has expired.
    711  1.178.2.2  christos  */
    712  1.178.2.2  christos void
    713  1.178.2.2  christos scsipi_periph_timed_thaw(void *arg)
    714  1.178.2.2  christos {
    715  1.178.2.2  christos 	struct scsipi_periph *periph = arg;
    716  1.178.2.2  christos 	struct scsipi_channel *chan = periph->periph_channel;
    717  1.178.2.2  christos 
    718  1.178.2.2  christos 	callout_stop(&periph->periph_callout);
    719  1.178.2.2  christos 
    720  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
    721  1.178.2.2  christos 	scsipi_periph_thaw_locked(periph, 1);
    722  1.178.2.2  christos 	if ((periph->periph_channel->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
    723  1.178.2.2  christos 		/*
    724  1.178.2.2  christos 		 * Kick the channel's queue here.  Note, we're running in
    725  1.178.2.2  christos 		 * interrupt context (softclock), so the adapter driver
    726  1.178.2.2  christos 		 * had better not sleep.
    727  1.178.2.2  christos 		 */
    728  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
    729  1.178.2.2  christos 		scsipi_run_queue(periph->periph_channel);
    730  1.178.2.2  christos 	} else {
    731  1.178.2.2  christos 		/*
    732  1.178.2.2  christos 		 * Tell the completion thread to kick the channel's queue here.
    733  1.178.2.2  christos 		 */
    734  1.178.2.2  christos 		periph->periph_channel->chan_tflags |= SCSIPI_CHANT_KICK;
    735  1.178.2.2  christos 		cv_broadcast(chan_cv_complete(chan));
    736  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
    737  1.178.2.2  christos 	}
    738  1.178.2.2  christos }
    739  1.178.2.2  christos 
    740  1.178.2.2  christos /*
    741  1.178.2.2  christos  * scsipi_wait_drain:
    742  1.178.2.2  christos  *
    743  1.178.2.2  christos  *	Wait for a periph's pending xfers to drain.
    744  1.178.2.2  christos  */
    745  1.178.2.2  christos void
    746  1.178.2.2  christos scsipi_wait_drain(struct scsipi_periph *periph)
    747  1.178.2.2  christos {
    748  1.178.2.2  christos 	struct scsipi_channel *chan = periph->periph_channel;
    749  1.178.2.2  christos 
    750  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
    751  1.178.2.2  christos 	while (periph->periph_active != 0) {
    752  1.178.2.2  christos 		periph->periph_flags |= PERIPH_WAITDRAIN;
    753  1.178.2.2  christos 		cv_wait(periph_cv_active(periph), chan_mtx(chan));
    754  1.178.2.2  christos 	}
    755  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
    756  1.178.2.2  christos }
    757  1.178.2.2  christos 
    758  1.178.2.2  christos /*
    759  1.178.2.2  christos  * scsipi_kill_pending:
    760  1.178.2.2  christos  *
    761  1.178.2.2  christos  *	Kill off all pending xfers for a periph.
    762  1.178.2.2  christos  *
    763  1.178.2.2  christos  *	NOTE: Must be called with channel lock held
    764  1.178.2.2  christos  */
    765  1.178.2.2  christos void
    766  1.178.2.2  christos scsipi_kill_pending(struct scsipi_periph *periph)
    767  1.178.2.2  christos {
    768  1.178.2.2  christos 	struct scsipi_channel *chan = periph->periph_channel;
    769  1.178.2.2  christos 
    770  1.178.2.2  christos 	(*chan->chan_bustype->bustype_kill_pending)(periph);
    771  1.178.2.2  christos 	while (periph->periph_active != 0) {
    772  1.178.2.2  christos 		periph->periph_flags |= PERIPH_WAITDRAIN;
    773  1.178.2.2  christos 		cv_wait(periph_cv_active(periph), chan_mtx(chan));
    774  1.178.2.2  christos 	}
    775  1.178.2.2  christos }
    776  1.178.2.2  christos 
    777  1.178.2.2  christos /*
    778  1.178.2.2  christos  * scsipi_print_cdb:
    779  1.178.2.2  christos  * prints a command descriptor block (for debug purpose, error messages,
    780  1.178.2.2  christos  * SCSIVERBOSE, ...)
    781  1.178.2.2  christos  */
    782  1.178.2.2  christos void
    783  1.178.2.2  christos scsipi_print_cdb(struct scsipi_generic *cmd)
    784  1.178.2.2  christos {
    785  1.178.2.2  christos 	int i, j;
    786  1.178.2.2  christos 
    787  1.178.2.2  christos  	printf("0x%02x", cmd->opcode);
    788  1.178.2.2  christos 
    789  1.178.2.2  christos  	switch (CDB_GROUPID(cmd->opcode)) {
    790  1.178.2.2  christos  	case CDB_GROUPID_0:
    791  1.178.2.2  christos  		j = CDB_GROUP0;
    792  1.178.2.2  christos  		break;
    793  1.178.2.2  christos  	case CDB_GROUPID_1:
    794  1.178.2.2  christos  		j = CDB_GROUP1;
    795  1.178.2.2  christos  		break;
    796  1.178.2.2  christos  	case CDB_GROUPID_2:
    797  1.178.2.2  christos  		j = CDB_GROUP2;
    798  1.178.2.2  christos  		break;
    799  1.178.2.2  christos  	case CDB_GROUPID_3:
    800  1.178.2.2  christos  		j = CDB_GROUP3;
    801  1.178.2.2  christos  		break;
    802  1.178.2.2  christos  	case CDB_GROUPID_4:
    803  1.178.2.2  christos  		j = CDB_GROUP4;
    804  1.178.2.2  christos  		break;
    805  1.178.2.2  christos  	case CDB_GROUPID_5:
    806  1.178.2.2  christos  		j = CDB_GROUP5;
    807  1.178.2.2  christos  		break;
    808  1.178.2.2  christos  	case CDB_GROUPID_6:
    809  1.178.2.2  christos  		j = CDB_GROUP6;
    810  1.178.2.2  christos  		break;
    811  1.178.2.2  christos  	case CDB_GROUPID_7:
    812  1.178.2.2  christos  		j = CDB_GROUP7;
    813  1.178.2.2  christos  		break;
    814  1.178.2.2  christos  	default:
    815  1.178.2.2  christos  		j = 0;
    816  1.178.2.2  christos  	}
    817  1.178.2.2  christos  	if (j == 0)
    818  1.178.2.2  christos  		j = sizeof (cmd->bytes);
    819  1.178.2.2  christos  	for (i = 0; i < j-1; i++) /* already done the opcode */
    820  1.178.2.2  christos  		printf(" %02x", cmd->bytes[i]);
    821  1.178.2.2  christos }
    822  1.178.2.2  christos 
    823  1.178.2.2  christos /*
    824  1.178.2.2  christos  * scsipi_interpret_sense:
    825  1.178.2.2  christos  *
    826  1.178.2.2  christos  *	Look at the returned sense and act on the error, determining
    827  1.178.2.2  christos  *	the unix error number to pass back.  (0 = report no error)
    828  1.178.2.2  christos  *
    829  1.178.2.2  christos  *	NOTE: If we return ERESTART, we are expected to haved
    830  1.178.2.2  christos  *	thawed the device!
    831  1.178.2.2  christos  *
    832  1.178.2.2  christos  *	THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES.
    833  1.178.2.2  christos  */
    834  1.178.2.2  christos int
    835  1.178.2.2  christos scsipi_interpret_sense(struct scsipi_xfer *xs)
    836  1.178.2.2  christos {
    837  1.178.2.2  christos 	struct scsi_sense_data *sense;
    838  1.178.2.2  christos 	struct scsipi_periph *periph = xs->xs_periph;
    839  1.178.2.2  christos 	u_int8_t key;
    840  1.178.2.2  christos 	int error;
    841  1.178.2.2  christos 	u_int32_t info;
    842  1.178.2.2  christos 	static const char *error_mes[] = {
    843  1.178.2.2  christos 		"soft error (corrected)",
    844  1.178.2.2  christos 		"not ready", "medium error",
    845  1.178.2.2  christos 		"non-media hardware failure", "illegal request",
    846  1.178.2.2  christos 		"unit attention", "readonly device",
    847  1.178.2.2  christos 		"no data found", "vendor unique",
    848  1.178.2.2  christos 		"copy aborted", "command aborted",
    849  1.178.2.2  christos 		"search returned equal", "volume overflow",
    850  1.178.2.2  christos 		"verify miscompare", "unknown error key"
    851  1.178.2.2  christos 	};
    852  1.178.2.2  christos 
    853  1.178.2.2  christos 	sense = &xs->sense.scsi_sense;
    854  1.178.2.2  christos #ifdef SCSIPI_DEBUG
    855  1.178.2.2  christos 	if (periph->periph_flags & SCSIPI_DB1) {
    856  1.178.2.2  christos 		int count;
    857  1.178.2.2  christos 		scsipi_printaddr(periph);
    858  1.178.2.2  christos 		printf(" sense debug information:\n");
    859  1.178.2.2  christos 		printf("\tcode 0x%x valid %d\n",
    860  1.178.2.2  christos 			SSD_RCODE(sense->response_code),
    861  1.178.2.2  christos 			sense->response_code & SSD_RCODE_VALID ? 1 : 0);
    862  1.178.2.2  christos 		printf("\tseg 0x%x key 0x%x ili 0x%x eom 0x%x fmark 0x%x\n",
    863  1.178.2.2  christos 			sense->segment,
    864  1.178.2.2  christos 			SSD_SENSE_KEY(sense->flags),
    865  1.178.2.2  christos 			sense->flags & SSD_ILI ? 1 : 0,
    866  1.178.2.2  christos 			sense->flags & SSD_EOM ? 1 : 0,
    867  1.178.2.2  christos 			sense->flags & SSD_FILEMARK ? 1 : 0);
    868  1.178.2.2  christos 		printf("\ninfo: 0x%x 0x%x 0x%x 0x%x followed by %d "
    869  1.178.2.2  christos 			"extra bytes\n",
    870  1.178.2.2  christos 			sense->info[0],
    871  1.178.2.2  christos 			sense->info[1],
    872  1.178.2.2  christos 			sense->info[2],
    873  1.178.2.2  christos 			sense->info[3],
    874  1.178.2.2  christos 			sense->extra_len);
    875  1.178.2.2  christos 		printf("\textra: ");
    876  1.178.2.2  christos 		for (count = 0; count < SSD_ADD_BYTES_LIM(sense); count++)
    877  1.178.2.2  christos 			printf("0x%x ", sense->csi[count]);
    878  1.178.2.2  christos 		printf("\n");
    879  1.178.2.2  christos 	}
    880  1.178.2.2  christos #endif
    881  1.178.2.2  christos 
    882  1.178.2.2  christos 	/*
    883  1.178.2.2  christos 	 * If the periph has its own error handler, call it first.
    884  1.178.2.2  christos 	 * If it returns a legit error value, return that, otherwise
    885  1.178.2.2  christos 	 * it wants us to continue with normal error processing.
    886  1.178.2.2  christos 	 */
    887  1.178.2.2  christos 	if (periph->periph_switch->psw_error != NULL) {
    888  1.178.2.2  christos 		SC_DEBUG(periph, SCSIPI_DB2,
    889  1.178.2.2  christos 		    ("calling private err_handler()\n"));
    890  1.178.2.2  christos 		error = (*periph->periph_switch->psw_error)(xs);
    891  1.178.2.2  christos 		if (error != EJUSTRETURN)
    892  1.178.2.2  christos 			return error;
    893  1.178.2.2  christos 	}
    894  1.178.2.2  christos 	/* otherwise use the default */
    895  1.178.2.2  christos 	switch (SSD_RCODE(sense->response_code)) {
    896  1.178.2.2  christos 
    897  1.178.2.2  christos 		/*
    898  1.178.2.2  christos 		 * Old SCSI-1 and SASI devices respond with
    899  1.178.2.2  christos 		 * codes other than 70.
    900  1.178.2.2  christos 		 */
    901  1.178.2.2  christos 	case 0x00:		/* no error (command completed OK) */
    902  1.178.2.2  christos 		return 0;
    903  1.178.2.2  christos 	case 0x04:		/* drive not ready after it was selected */
    904  1.178.2.2  christos 		if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
    905  1.178.2.2  christos 			periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
    906  1.178.2.2  christos 		if ((xs->xs_control & XS_CTL_IGNORE_NOT_READY) != 0)
    907  1.178.2.2  christos 			return 0;
    908  1.178.2.2  christos 		/* XXX - display some sort of error here? */
    909  1.178.2.2  christos 		return EIO;
    910  1.178.2.2  christos 	case 0x20:		/* invalid command */
    911  1.178.2.2  christos 		if ((xs->xs_control &
    912  1.178.2.2  christos 		     XS_CTL_IGNORE_ILLEGAL_REQUEST) != 0)
    913  1.178.2.2  christos 			return 0;
    914  1.178.2.2  christos 		return EINVAL;
    915  1.178.2.2  christos 	case 0x25:		/* invalid LUN (Adaptec ACB-4000) */
    916  1.178.2.2  christos 		return EACCES;
    917  1.178.2.2  christos 
    918  1.178.2.2  christos 		/*
    919  1.178.2.2  christos 		 * If it's code 70, use the extended stuff and
    920  1.178.2.2  christos 		 * interpret the key
    921  1.178.2.2  christos 		 */
    922  1.178.2.2  christos 	case 0x71:		/* delayed error */
    923  1.178.2.2  christos 		scsipi_printaddr(periph);
    924  1.178.2.2  christos 		key = SSD_SENSE_KEY(sense->flags);
    925  1.178.2.2  christos 		printf(" DEFERRED ERROR, key = 0x%x\n", key);
    926  1.178.2.2  christos 		/* FALLTHROUGH */
    927  1.178.2.2  christos 	case 0x70:
    928  1.178.2.2  christos 		if ((sense->response_code & SSD_RCODE_VALID) != 0)
    929  1.178.2.2  christos 			info = _4btol(sense->info);
    930  1.178.2.2  christos 		else
    931  1.178.2.2  christos 			info = 0;
    932  1.178.2.2  christos 		key = SSD_SENSE_KEY(sense->flags);
    933  1.178.2.2  christos 
    934  1.178.2.2  christos 		switch (key) {
    935  1.178.2.2  christos 		case SKEY_NO_SENSE:
    936  1.178.2.2  christos 		case SKEY_RECOVERED_ERROR:
    937  1.178.2.2  christos 			if (xs->resid == xs->datalen && xs->datalen) {
    938  1.178.2.2  christos 				/*
    939  1.178.2.2  christos 				 * Why is this here?
    940  1.178.2.2  christos 				 */
    941  1.178.2.2  christos 				xs->resid = 0;	/* not short read */
    942  1.178.2.2  christos 			}
    943  1.178.2.2  christos 		case SKEY_EQUAL:
    944  1.178.2.2  christos 			error = 0;
    945  1.178.2.2  christos 			break;
    946  1.178.2.2  christos 		case SKEY_NOT_READY:
    947  1.178.2.2  christos 			if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
    948  1.178.2.2  christos 				periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
    949  1.178.2.2  christos 			if ((xs->xs_control & XS_CTL_IGNORE_NOT_READY) != 0)
    950  1.178.2.2  christos 				return 0;
    951  1.178.2.2  christos 			if (sense->asc == 0x3A) {
    952  1.178.2.2  christos 				error = ENODEV; /* Medium not present */
    953  1.178.2.2  christos 				if (xs->xs_control & XS_CTL_SILENT_NODEV)
    954  1.178.2.2  christos 					return error;
    955  1.178.2.2  christos 			} else
    956  1.178.2.2  christos 				error = EIO;
    957  1.178.2.2  christos 			if ((xs->xs_control & XS_CTL_SILENT) != 0)
    958  1.178.2.2  christos 				return error;
    959  1.178.2.2  christos 			break;
    960  1.178.2.2  christos 		case SKEY_ILLEGAL_REQUEST:
    961  1.178.2.2  christos 			if ((xs->xs_control &
    962  1.178.2.2  christos 			     XS_CTL_IGNORE_ILLEGAL_REQUEST) != 0)
    963  1.178.2.2  christos 				return 0;
    964  1.178.2.2  christos 			/*
    965  1.178.2.2  christos 			 * Handle the case where a device reports
    966  1.178.2.2  christos 			 * Logical Unit Not Supported during discovery.
    967  1.178.2.2  christos 			 */
    968  1.178.2.2  christos 			if ((xs->xs_control & XS_CTL_DISCOVERY) != 0 &&
    969  1.178.2.2  christos 			    sense->asc == 0x25 &&
    970  1.178.2.2  christos 			    sense->ascq == 0x00)
    971  1.178.2.2  christos 				return EINVAL;
    972  1.178.2.2  christos 			if ((xs->xs_control & XS_CTL_SILENT) != 0)
    973  1.178.2.2  christos 				return EIO;
    974  1.178.2.2  christos 			error = EINVAL;
    975  1.178.2.2  christos 			break;
    976  1.178.2.2  christos 		case SKEY_UNIT_ATTENTION:
    977  1.178.2.2  christos 			if (sense->asc == 0x29 &&
    978  1.178.2.2  christos 			    sense->ascq == 0x00) {
    979  1.178.2.2  christos 				/* device or bus reset */
    980  1.178.2.2  christos 				return ERESTART;
    981  1.178.2.2  christos 			}
    982  1.178.2.2  christos 			if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
    983  1.178.2.2  christos 				periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
    984  1.178.2.2  christos 			if ((xs->xs_control &
    985  1.178.2.2  christos 			     XS_CTL_IGNORE_MEDIA_CHANGE) != 0 ||
    986  1.178.2.2  christos 				/* XXX Should reupload any transient state. */
    987  1.178.2.2  christos 				(periph->periph_flags &
    988  1.178.2.2  christos 				 PERIPH_REMOVABLE) == 0) {
    989  1.178.2.2  christos 				return ERESTART;
    990  1.178.2.2  christos 			}
    991  1.178.2.2  christos 			if ((xs->xs_control & XS_CTL_SILENT) != 0)
    992  1.178.2.2  christos 				return EIO;
    993  1.178.2.2  christos 			error = EIO;
    994  1.178.2.2  christos 			break;
    995  1.178.2.2  christos 		case SKEY_DATA_PROTECT:
    996  1.178.2.2  christos 			error = EROFS;
    997  1.178.2.2  christos 			break;
    998  1.178.2.2  christos 		case SKEY_BLANK_CHECK:
    999  1.178.2.2  christos 			error = 0;
   1000  1.178.2.2  christos 			break;
   1001  1.178.2.2  christos 		case SKEY_ABORTED_COMMAND:
   1002  1.178.2.2  christos 			if (xs->xs_retries != 0) {
   1003  1.178.2.2  christos 				xs->xs_retries--;
   1004  1.178.2.2  christos 				error = ERESTART;
   1005  1.178.2.2  christos 			} else
   1006  1.178.2.2  christos 				error = EIO;
   1007  1.178.2.2  christos 			break;
   1008  1.178.2.2  christos 		case SKEY_VOLUME_OVERFLOW:
   1009  1.178.2.2  christos 			error = ENOSPC;
   1010  1.178.2.2  christos 			break;
   1011  1.178.2.2  christos 		default:
   1012  1.178.2.2  christos 			error = EIO;
   1013  1.178.2.2  christos 			break;
   1014  1.178.2.2  christos 		}
   1015  1.178.2.2  christos 
   1016  1.178.2.2  christos 		/* Print verbose decode if appropriate and possible */
   1017  1.178.2.2  christos 		if ((key == 0) ||
   1018  1.178.2.2  christos 		    ((xs->xs_control & XS_CTL_SILENT) != 0) ||
   1019  1.178.2.2  christos 		    (scsipi_print_sense(xs, 0) != 0))
   1020  1.178.2.2  christos 			return error;
   1021  1.178.2.2  christos 
   1022  1.178.2.2  christos 		/* Print brief(er) sense information */
   1023  1.178.2.2  christos 		scsipi_printaddr(periph);
   1024  1.178.2.2  christos 		printf("%s", error_mes[key - 1]);
   1025  1.178.2.2  christos 		if ((sense->response_code & SSD_RCODE_VALID) != 0) {
   1026  1.178.2.2  christos 			switch (key) {
   1027  1.178.2.2  christos 			case SKEY_NOT_READY:
   1028  1.178.2.2  christos 			case SKEY_ILLEGAL_REQUEST:
   1029  1.178.2.2  christos 			case SKEY_UNIT_ATTENTION:
   1030  1.178.2.2  christos 			case SKEY_DATA_PROTECT:
   1031  1.178.2.2  christos 				break;
   1032  1.178.2.2  christos 			case SKEY_BLANK_CHECK:
   1033  1.178.2.2  christos 				printf(", requested size: %d (decimal)",
   1034  1.178.2.2  christos 				    info);
   1035  1.178.2.2  christos 				break;
   1036  1.178.2.2  christos 			case SKEY_ABORTED_COMMAND:
   1037  1.178.2.2  christos 				if (xs->xs_retries)
   1038  1.178.2.2  christos 					printf(", retrying");
   1039  1.178.2.2  christos 				printf(", cmd 0x%x, info 0x%x",
   1040  1.178.2.2  christos 				    xs->cmd->opcode, info);
   1041  1.178.2.2  christos 				break;
   1042  1.178.2.2  christos 			default:
   1043  1.178.2.2  christos 				printf(", info = %d (decimal)", info);
   1044  1.178.2.2  christos 			}
   1045  1.178.2.2  christos 		}
   1046  1.178.2.2  christos 		if (sense->extra_len != 0) {
   1047  1.178.2.2  christos 			int n;
   1048  1.178.2.2  christos 			printf(", data =");
   1049  1.178.2.2  christos 			for (n = 0; n < sense->extra_len; n++)
   1050  1.178.2.2  christos 				printf(" %02x",
   1051  1.178.2.2  christos 				    sense->csi[n]);
   1052  1.178.2.2  christos 		}
   1053  1.178.2.2  christos 		printf("\n");
   1054  1.178.2.2  christos 		return error;
   1055  1.178.2.2  christos 
   1056  1.178.2.2  christos 	/*
   1057  1.178.2.2  christos 	 * Some other code, just report it
   1058  1.178.2.2  christos 	 */
   1059  1.178.2.2  christos 	default:
   1060  1.178.2.2  christos #if    defined(SCSIDEBUG) || defined(DEBUG)
   1061  1.178.2.2  christos 	{
   1062  1.178.2.2  christos 		static const char *uc = "undecodable sense error";
   1063  1.178.2.2  christos 		int i;
   1064  1.178.2.2  christos 		u_int8_t *cptr = (u_int8_t *) sense;
   1065  1.178.2.2  christos 		scsipi_printaddr(periph);
   1066  1.178.2.2  christos 		if (xs->cmd == &xs->cmdstore) {
   1067  1.178.2.2  christos 			printf("%s for opcode 0x%x, data=",
   1068  1.178.2.2  christos 			    uc, xs->cmdstore.opcode);
   1069  1.178.2.2  christos 		} else {
   1070  1.178.2.2  christos 			printf("%s, data=", uc);
   1071  1.178.2.2  christos 		}
   1072  1.178.2.2  christos 		for (i = 0; i < sizeof (sense); i++)
   1073  1.178.2.2  christos 			printf(" 0x%02x", *(cptr++) & 0xff);
   1074  1.178.2.2  christos 		printf("\n");
   1075  1.178.2.2  christos 	}
   1076  1.178.2.2  christos #else
   1077  1.178.2.2  christos 		scsipi_printaddr(periph);
   1078  1.178.2.2  christos 		printf("Sense Error Code 0x%x",
   1079  1.178.2.2  christos 			SSD_RCODE(sense->response_code));
   1080  1.178.2.2  christos 		if ((sense->response_code & SSD_RCODE_VALID) != 0) {
   1081  1.178.2.2  christos 			struct scsi_sense_data_unextended *usense =
   1082  1.178.2.2  christos 			    (struct scsi_sense_data_unextended *)sense;
   1083  1.178.2.2  christos 			printf(" at block no. %d (decimal)",
   1084  1.178.2.2  christos 			    _3btol(usense->block));
   1085  1.178.2.2  christos 		}
   1086  1.178.2.2  christos 		printf("\n");
   1087  1.178.2.2  christos #endif
   1088  1.178.2.2  christos 		return EIO;
   1089  1.178.2.2  christos 	}
   1090  1.178.2.2  christos }
   1091  1.178.2.2  christos 
   1092  1.178.2.2  christos /*
   1093  1.178.2.2  christos  * scsipi_test_unit_ready:
   1094  1.178.2.2  christos  *
   1095  1.178.2.2  christos  *	Issue a `test unit ready' request.
   1096  1.178.2.2  christos  */
   1097  1.178.2.2  christos int
   1098  1.178.2.2  christos scsipi_test_unit_ready(struct scsipi_periph *periph, int flags)
   1099  1.178.2.2  christos {
   1100  1.178.2.2  christos 	struct scsi_test_unit_ready cmd;
   1101  1.178.2.2  christos 	int retries;
   1102  1.178.2.2  christos 
   1103  1.178.2.2  christos 	/* some ATAPI drives don't support TEST UNIT READY. Sigh */
   1104  1.178.2.2  christos 	if (periph->periph_quirks & PQUIRK_NOTUR)
   1105  1.178.2.2  christos 		return 0;
   1106  1.178.2.2  christos 
   1107  1.178.2.2  christos 	if (flags & XS_CTL_DISCOVERY)
   1108  1.178.2.2  christos 		retries = 0;
   1109  1.178.2.2  christos 	else
   1110  1.178.2.2  christos 		retries = SCSIPIRETRIES;
   1111  1.178.2.2  christos 
   1112  1.178.2.2  christos 	memset(&cmd, 0, sizeof(cmd));
   1113  1.178.2.2  christos 	cmd.opcode = SCSI_TEST_UNIT_READY;
   1114  1.178.2.2  christos 
   1115  1.178.2.2  christos 	return scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0,
   1116  1.178.2.2  christos 	    retries, 10000, NULL, flags);
   1117  1.178.2.2  christos }
   1118  1.178.2.2  christos 
   1119  1.178.2.2  christos static const struct scsipi_inquiry3_pattern {
   1120  1.178.2.2  christos 	const char vendor[8];
   1121  1.178.2.2  christos 	const char product[16];
   1122  1.178.2.2  christos 	const char revision[4];
   1123  1.178.2.2  christos } scsipi_inquiry3_quirk[] = {
   1124  1.178.2.2  christos 	{ "ES-6600 ", "", "" },
   1125  1.178.2.2  christos };
   1126  1.178.2.2  christos 
   1127  1.178.2.2  christos static int
   1128  1.178.2.2  christos scsipi_inquiry3_ok(const struct scsipi_inquiry_data *ib)
   1129  1.178.2.2  christos {
   1130  1.178.2.2  christos 	for (size_t i = 0; i < __arraycount(scsipi_inquiry3_quirk); i++) {
   1131  1.178.2.2  christos 		const struct scsipi_inquiry3_pattern *q =
   1132  1.178.2.2  christos 		    &scsipi_inquiry3_quirk[i];
   1133  1.178.2.2  christos #define MATCH(field) \
   1134  1.178.2.2  christos     (q->field[0] ? memcmp(ib->field, q->field, sizeof(ib->field)) == 0 : 1)
   1135  1.178.2.2  christos 		if (MATCH(vendor) && MATCH(product) && MATCH(revision))
   1136  1.178.2.2  christos 			return 0;
   1137  1.178.2.2  christos 	}
   1138  1.178.2.2  christos 	return 1;
   1139  1.178.2.2  christos }
   1140  1.178.2.2  christos 
   1141  1.178.2.2  christos /*
   1142  1.178.2.2  christos  * scsipi_inquire:
   1143  1.178.2.2  christos  *
   1144  1.178.2.2  christos  *	Ask the device about itself.
   1145  1.178.2.2  christos  */
   1146  1.178.2.2  christos int
   1147  1.178.2.2  christos scsipi_inquire(struct scsipi_periph *periph, struct scsipi_inquiry_data *inqbuf,
   1148  1.178.2.2  christos     int flags)
   1149  1.178.2.2  christos {
   1150  1.178.2.2  christos 	struct scsipi_inquiry cmd;
   1151  1.178.2.2  christos 	int error;
   1152  1.178.2.2  christos 	int retries;
   1153  1.178.2.2  christos 
   1154  1.178.2.2  christos 	if (flags & XS_CTL_DISCOVERY)
   1155  1.178.2.2  christos 		retries = 0;
   1156  1.178.2.2  christos 	else
   1157  1.178.2.2  christos 		retries = SCSIPIRETRIES;
   1158  1.178.2.2  christos 
   1159  1.178.2.2  christos 	/*
   1160  1.178.2.2  christos 	 * If we request more data than the device can provide, it SHOULD just
   1161  1.178.2.2  christos 	 * return a short response.  However, some devices error with an
   1162  1.178.2.2  christos 	 * ILLEGAL REQUEST sense code, and yet others have even more special
   1163  1.178.2.2  christos 	 * failture modes (such as the GL641USB flash adapter, which goes loony
   1164  1.178.2.2  christos 	 * and sends corrupted CRCs).  To work around this, and to bring our
   1165  1.178.2.2  christos 	 * behavior more in line with other OSes, we do a shorter inquiry,
   1166  1.178.2.2  christos 	 * covering all the SCSI-2 information, first, and then request more
   1167  1.178.2.2  christos 	 * data iff the "additional length" field indicates there is more.
   1168  1.178.2.2  christos 	 * - mycroft, 2003/10/16
   1169  1.178.2.2  christos 	 */
   1170  1.178.2.2  christos 	memset(&cmd, 0, sizeof(cmd));
   1171  1.178.2.2  christos 	cmd.opcode = INQUIRY;
   1172  1.178.2.2  christos 	cmd.length = SCSIPI_INQUIRY_LENGTH_SCSI2;
   1173  1.178.2.2  christos 	error = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
   1174  1.178.2.2  christos 	    (void *)inqbuf, SCSIPI_INQUIRY_LENGTH_SCSI2, retries,
   1175  1.178.2.2  christos 	    10000, NULL, flags | XS_CTL_DATA_IN);
   1176  1.178.2.2  christos 	if (!error &&
   1177  1.178.2.2  christos 	    inqbuf->additional_length > SCSIPI_INQUIRY_LENGTH_SCSI2 - 4) {
   1178  1.178.2.2  christos 	    if (scsipi_inquiry3_ok(inqbuf)) {
   1179  1.178.2.2  christos #if 0
   1180  1.178.2.2  christos printf("inquire: addlen=%d, retrying\n", inqbuf->additional_length);
   1181  1.178.2.2  christos #endif
   1182  1.178.2.2  christos 		cmd.length = SCSIPI_INQUIRY_LENGTH_SCSI3;
   1183  1.178.2.2  christos 		error = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
   1184  1.178.2.2  christos 		    (void *)inqbuf, SCSIPI_INQUIRY_LENGTH_SCSI3, retries,
   1185  1.178.2.2  christos 		    10000, NULL, flags | XS_CTL_DATA_IN);
   1186  1.178.2.2  christos #if 0
   1187  1.178.2.2  christos printf("inquire: error=%d\n", error);
   1188  1.178.2.2  christos #endif
   1189  1.178.2.2  christos 	    }
   1190  1.178.2.2  christos 	}
   1191  1.178.2.2  christos 
   1192  1.178.2.2  christos #ifdef SCSI_OLD_NOINQUIRY
   1193  1.178.2.2  christos 	/*
   1194  1.178.2.2  christos 	 * Kludge for the Adaptec ACB-4000 SCSI->MFM translator.
   1195  1.178.2.2  christos 	 * This board doesn't support the INQUIRY command at all.
   1196  1.178.2.2  christos 	 */
   1197  1.178.2.2  christos 	if (error == EINVAL || error == EACCES) {
   1198  1.178.2.2  christos 		/*
   1199  1.178.2.2  christos 		 * Conjure up an INQUIRY response.
   1200  1.178.2.2  christos 		 */
   1201  1.178.2.2  christos 		inqbuf->device = (error == EINVAL ?
   1202  1.178.2.2  christos 			 SID_QUAL_LU_PRESENT :
   1203  1.178.2.2  christos 			 SID_QUAL_LU_NOTPRESENT) | T_DIRECT;
   1204  1.178.2.2  christos 		inqbuf->dev_qual2 = 0;
   1205  1.178.2.2  christos 		inqbuf->version = 0;
   1206  1.178.2.2  christos 		inqbuf->response_format = SID_FORMAT_SCSI1;
   1207  1.178.2.2  christos 		inqbuf->additional_length = SCSIPI_INQUIRY_LENGTH_SCSI2 - 4;
   1208  1.178.2.2  christos 		inqbuf->flags1 = inqbuf->flags2 = inqbuf->flags3 = 0;
   1209  1.178.2.2  christos 		memcpy(inqbuf->vendor, "ADAPTEC ACB-4000            ", 28);
   1210  1.178.2.2  christos 		error = 0;
   1211  1.178.2.2  christos 	}
   1212  1.178.2.2  christos 
   1213  1.178.2.2  christos 	/*
   1214  1.178.2.2  christos 	 * Kludge for the Emulex MT-02 SCSI->QIC translator.
   1215  1.178.2.2  christos 	 * This board gives an empty response to an INQUIRY command.
   1216  1.178.2.2  christos 	 */
   1217  1.178.2.2  christos 	else if (error == 0 &&
   1218  1.178.2.2  christos 	    inqbuf->device == (SID_QUAL_LU_PRESENT | T_DIRECT) &&
   1219  1.178.2.2  christos 	    inqbuf->dev_qual2 == 0 &&
   1220  1.178.2.2  christos 	    inqbuf->version == 0 &&
   1221  1.178.2.2  christos 	    inqbuf->response_format == SID_FORMAT_SCSI1) {
   1222  1.178.2.2  christos 		/*
   1223  1.178.2.2  christos 		 * Fill out the INQUIRY response.
   1224  1.178.2.2  christos 		 */
   1225  1.178.2.2  christos 		inqbuf->device = (SID_QUAL_LU_PRESENT | T_SEQUENTIAL);
   1226  1.178.2.2  christos 		inqbuf->dev_qual2 = SID_REMOVABLE;
   1227  1.178.2.2  christos 		inqbuf->additional_length = SCSIPI_INQUIRY_LENGTH_SCSI2 - 4;
   1228  1.178.2.2  christos 		inqbuf->flags1 = inqbuf->flags2 = inqbuf->flags3 = 0;
   1229  1.178.2.2  christos 		memcpy(inqbuf->vendor, "EMULEX  MT-02 QIC           ", 28);
   1230  1.178.2.2  christos 	}
   1231  1.178.2.2  christos #endif /* SCSI_OLD_NOINQUIRY */
   1232  1.178.2.2  christos 
   1233  1.178.2.2  christos 	return error;
   1234  1.178.2.2  christos }
   1235  1.178.2.2  christos 
   1236  1.178.2.2  christos /*
   1237  1.178.2.2  christos  * scsipi_prevent:
   1238  1.178.2.2  christos  *
   1239  1.178.2.2  christos  *	Prevent or allow the user to remove the media
   1240  1.178.2.2  christos  */
   1241  1.178.2.2  christos int
   1242  1.178.2.2  christos scsipi_prevent(struct scsipi_periph *periph, int type, int flags)
   1243  1.178.2.2  christos {
   1244  1.178.2.2  christos 	struct scsi_prevent_allow_medium_removal cmd;
   1245  1.178.2.2  christos 
   1246  1.178.2.2  christos 	if (periph->periph_quirks & PQUIRK_NODOORLOCK)
   1247  1.178.2.2  christos 		return 0;
   1248  1.178.2.2  christos 
   1249  1.178.2.2  christos 	memset(&cmd, 0, sizeof(cmd));
   1250  1.178.2.2  christos 	cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL;
   1251  1.178.2.2  christos 	cmd.how = type;
   1252  1.178.2.2  christos 
   1253  1.178.2.2  christos 	return (scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0,
   1254  1.178.2.2  christos 	    SCSIPIRETRIES, 5000, NULL, flags));
   1255  1.178.2.2  christos }
   1256  1.178.2.2  christos 
   1257  1.178.2.2  christos /*
   1258  1.178.2.2  christos  * scsipi_start:
   1259  1.178.2.2  christos  *
   1260  1.178.2.2  christos  *	Send a START UNIT.
   1261  1.178.2.2  christos  */
   1262  1.178.2.2  christos int
   1263  1.178.2.2  christos scsipi_start(struct scsipi_periph *periph, int type, int flags)
   1264  1.178.2.2  christos {
   1265  1.178.2.2  christos 	struct scsipi_start_stop cmd;
   1266  1.178.2.2  christos 
   1267  1.178.2.2  christos 	memset(&cmd, 0, sizeof(cmd));
   1268  1.178.2.2  christos 	cmd.opcode = START_STOP;
   1269  1.178.2.2  christos 	cmd.byte2 = 0x00;
   1270  1.178.2.2  christos 	cmd.how = type;
   1271  1.178.2.2  christos 
   1272  1.178.2.2  christos 	return scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0,
   1273  1.178.2.2  christos 	    SCSIPIRETRIES, (type & SSS_START) ? 60000 : 10000, NULL, flags);
   1274  1.178.2.2  christos }
   1275  1.178.2.2  christos 
   1276  1.178.2.2  christos /*
   1277  1.178.2.2  christos  * scsipi_mode_sense, scsipi_mode_sense_big:
   1278  1.178.2.2  christos  *	get a sense page from a device
   1279  1.178.2.2  christos  */
   1280  1.178.2.2  christos 
   1281  1.178.2.2  christos int
   1282  1.178.2.2  christos scsipi_mode_sense(struct scsipi_periph *periph, int byte2, int page,
   1283  1.178.2.2  christos     struct scsi_mode_parameter_header_6 *data, int len, int flags, int retries,
   1284  1.178.2.2  christos     int timeout)
   1285  1.178.2.2  christos {
   1286  1.178.2.2  christos 	struct scsi_mode_sense_6 cmd;
   1287  1.178.2.2  christos 
   1288  1.178.2.2  christos 	memset(&cmd, 0, sizeof(cmd));
   1289  1.178.2.2  christos 	cmd.opcode = SCSI_MODE_SENSE_6;
   1290  1.178.2.2  christos 	cmd.byte2 = byte2;
   1291  1.178.2.2  christos 	cmd.page = page;
   1292  1.178.2.2  christos 	cmd.length = len & 0xff;
   1293  1.178.2.2  christos 
   1294  1.178.2.2  christos 	return scsipi_command(periph, (void *)&cmd, sizeof(cmd),
   1295  1.178.2.2  christos 	    (void *)data, len, retries, timeout, NULL, flags | XS_CTL_DATA_IN);
   1296  1.178.2.2  christos }
   1297  1.178.2.2  christos 
   1298  1.178.2.2  christos int
   1299  1.178.2.2  christos scsipi_mode_sense_big(struct scsipi_periph *periph, int byte2, int page,
   1300  1.178.2.2  christos     struct scsi_mode_parameter_header_10 *data, int len, int flags, int retries,
   1301  1.178.2.2  christos     int timeout)
   1302  1.178.2.2  christos {
   1303  1.178.2.2  christos 	struct scsi_mode_sense_10 cmd;
   1304  1.178.2.2  christos 
   1305  1.178.2.2  christos 	memset(&cmd, 0, sizeof(cmd));
   1306  1.178.2.2  christos 	cmd.opcode = SCSI_MODE_SENSE_10;
   1307  1.178.2.2  christos 	cmd.byte2 = byte2;
   1308  1.178.2.2  christos 	cmd.page = page;
   1309  1.178.2.2  christos 	_lto2b(len, cmd.length);
   1310  1.178.2.2  christos 
   1311  1.178.2.2  christos 	return scsipi_command(periph, (void *)&cmd, sizeof(cmd),
   1312  1.178.2.2  christos 	    (void *)data, len, retries, timeout, NULL, flags | XS_CTL_DATA_IN);
   1313  1.178.2.2  christos }
   1314  1.178.2.2  christos 
   1315  1.178.2.2  christos int
   1316  1.178.2.2  christos scsipi_mode_select(struct scsipi_periph *periph, int byte2,
   1317  1.178.2.2  christos     struct scsi_mode_parameter_header_6 *data, int len, int flags, int retries,
   1318  1.178.2.2  christos     int timeout)
   1319  1.178.2.2  christos {
   1320  1.178.2.2  christos 	struct scsi_mode_select_6 cmd;
   1321  1.178.2.2  christos 
   1322  1.178.2.2  christos 	memset(&cmd, 0, sizeof(cmd));
   1323  1.178.2.2  christos 	cmd.opcode = SCSI_MODE_SELECT_6;
   1324  1.178.2.2  christos 	cmd.byte2 = byte2;
   1325  1.178.2.2  christos 	cmd.length = len & 0xff;
   1326  1.178.2.2  christos 
   1327  1.178.2.2  christos 	return scsipi_command(periph, (void *)&cmd, sizeof(cmd),
   1328  1.178.2.2  christos 	    (void *)data, len, retries, timeout, NULL, flags | XS_CTL_DATA_OUT);
   1329  1.178.2.2  christos }
   1330  1.178.2.2  christos 
   1331  1.178.2.2  christos int
   1332  1.178.2.2  christos scsipi_mode_select_big(struct scsipi_periph *periph, int byte2,
   1333  1.178.2.2  christos     struct scsi_mode_parameter_header_10 *data, int len, int flags, int retries,
   1334  1.178.2.2  christos     int timeout)
   1335  1.178.2.2  christos {
   1336  1.178.2.2  christos 	struct scsi_mode_select_10 cmd;
   1337  1.178.2.2  christos 
   1338  1.178.2.2  christos 	memset(&cmd, 0, sizeof(cmd));
   1339  1.178.2.2  christos 	cmd.opcode = SCSI_MODE_SELECT_10;
   1340  1.178.2.2  christos 	cmd.byte2 = byte2;
   1341  1.178.2.2  christos 	_lto2b(len, cmd.length);
   1342  1.178.2.2  christos 
   1343  1.178.2.2  christos 	return scsipi_command(periph, (void *)&cmd, sizeof(cmd),
   1344  1.178.2.2  christos 	    (void *)data, len, retries, timeout, NULL, flags | XS_CTL_DATA_OUT);
   1345  1.178.2.2  christos }
   1346  1.178.2.2  christos 
   1347  1.178.2.2  christos /*
   1348  1.178.2.2  christos  * scsipi_done:
   1349  1.178.2.2  christos  *
   1350  1.178.2.2  christos  *	This routine is called by an adapter's interrupt handler when
   1351  1.178.2.2  christos  *	an xfer is completed.
   1352  1.178.2.2  christos  */
   1353  1.178.2.2  christos void
   1354  1.178.2.2  christos scsipi_done(struct scsipi_xfer *xs)
   1355  1.178.2.2  christos {
   1356  1.178.2.2  christos 	struct scsipi_periph *periph = xs->xs_periph;
   1357  1.178.2.2  christos 	struct scsipi_channel *chan = periph->periph_channel;
   1358  1.178.2.2  christos 	int freezecnt;
   1359  1.178.2.2  christos 
   1360  1.178.2.2  christos 	SC_DEBUG(periph, SCSIPI_DB2, ("scsipi_done\n"));
   1361  1.178.2.2  christos #ifdef SCSIPI_DEBUG
   1362  1.178.2.2  christos 	if (periph->periph_dbflags & SCSIPI_DB1)
   1363  1.178.2.2  christos 		show_scsipi_cmd(xs);
   1364  1.178.2.2  christos #endif
   1365  1.178.2.2  christos 
   1366  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
   1367  1.178.2.2  christos 	/*
   1368  1.178.2.2  christos 	 * The resource this command was using is now free.
   1369  1.178.2.2  christos 	 */
   1370  1.178.2.2  christos 	if (xs->xs_status & XS_STS_DONE) {
   1371  1.178.2.2  christos 		/* XXX in certain circumstances, such as a device
   1372  1.178.2.2  christos 		 * being detached, a xs that has already been
   1373  1.178.2.2  christos 		 * scsipi_done()'d by the main thread will be done'd
   1374  1.178.2.2  christos 		 * again by scsibusdetach(). Putting the xs on the
   1375  1.178.2.2  christos 		 * chan_complete queue causes list corruption and
   1376  1.178.2.2  christos 		 * everyone dies. This prevents that, but perhaps
   1377  1.178.2.2  christos 		 * there should be better coordination somewhere such
   1378  1.178.2.2  christos 		 * that this won't ever happen (and can be turned into
   1379  1.178.2.2  christos 		 * a KASSERT().
   1380  1.178.2.2  christos 		 */
   1381  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
   1382  1.178.2.2  christos 		goto out;
   1383  1.178.2.2  christos 	}
   1384  1.178.2.2  christos 	scsipi_put_resource(chan);
   1385  1.178.2.2  christos 	xs->xs_periph->periph_sent--;
   1386  1.178.2.2  christos 
   1387  1.178.2.2  christos 	/*
   1388  1.178.2.2  christos 	 * If the command was tagged, free the tag.
   1389  1.178.2.2  christos 	 */
   1390  1.178.2.2  christos 	if (XS_CTL_TAGTYPE(xs) != 0)
   1391  1.178.2.2  christos 		scsipi_put_tag(xs);
   1392  1.178.2.2  christos 	else
   1393  1.178.2.2  christos 		periph->periph_flags &= ~PERIPH_UNTAG;
   1394  1.178.2.2  christos 
   1395  1.178.2.2  christos 	/* Mark the command as `done'. */
   1396  1.178.2.2  christos 	xs->xs_status |= XS_STS_DONE;
   1397  1.178.2.2  christos 
   1398  1.178.2.2  christos #ifdef DIAGNOSTIC
   1399  1.178.2.2  christos 	if ((xs->xs_control & (XS_CTL_ASYNC|XS_CTL_POLL)) ==
   1400  1.178.2.2  christos 	    (XS_CTL_ASYNC|XS_CTL_POLL))
   1401  1.178.2.2  christos 		panic("scsipi_done: ASYNC and POLL");
   1402  1.178.2.2  christos #endif
   1403  1.178.2.2  christos 
   1404  1.178.2.2  christos 	/*
   1405  1.178.2.2  christos 	 * If the xfer had an error of any sort, freeze the
   1406  1.178.2.2  christos 	 * periph's queue.  Freeze it again if we were requested
   1407  1.178.2.2  christos 	 * to do so in the xfer.
   1408  1.178.2.2  christos 	 */
   1409  1.178.2.2  christos 	freezecnt = 0;
   1410  1.178.2.2  christos 	if (xs->error != XS_NOERROR)
   1411  1.178.2.2  christos 		freezecnt++;
   1412  1.178.2.2  christos 	if (xs->xs_control & XS_CTL_FREEZE_PERIPH)
   1413  1.178.2.2  christos 		freezecnt++;
   1414  1.178.2.2  christos 	if (freezecnt != 0)
   1415  1.178.2.2  christos 		scsipi_periph_freeze_locked(periph, freezecnt);
   1416  1.178.2.2  christos 
   1417  1.178.2.2  christos 	/*
   1418  1.178.2.2  christos 	 * record the xfer with a pending sense, in case a SCSI reset is
   1419  1.178.2.2  christos 	 * received before the thread is waked up.
   1420  1.178.2.2  christos 	 */
   1421  1.178.2.2  christos 	if (xs->error == XS_BUSY && xs->status == SCSI_CHECK) {
   1422  1.178.2.2  christos 		periph->periph_flags |= PERIPH_SENSE;
   1423  1.178.2.2  christos 		periph->periph_xscheck = xs;
   1424  1.178.2.2  christos 	}
   1425  1.178.2.2  christos 
   1426  1.178.2.2  christos 	/*
   1427  1.178.2.2  christos 	 * If this was an xfer that was not to complete asynchronously,
   1428  1.178.2.2  christos 	 * let the requesting thread perform error checking/handling
   1429  1.178.2.2  christos 	 * in its context.
   1430  1.178.2.2  christos 	 */
   1431  1.178.2.2  christos 	if ((xs->xs_control & XS_CTL_ASYNC) == 0) {
   1432  1.178.2.2  christos 		/*
   1433  1.178.2.2  christos 		 * If it's a polling job, just return, to unwind the
   1434  1.178.2.2  christos 		 * call graph.  We don't need to restart the queue,
   1435  1.178.2.2  christos 		 * because pollings jobs are treated specially, and
   1436  1.178.2.2  christos 		 * are really only used during crash dumps anyway
   1437  1.178.2.2  christos 		 * (XXX or during boot-time autconfiguration of
   1438  1.178.2.2  christos 		 * ATAPI devices).
   1439  1.178.2.2  christos 		 */
   1440  1.178.2.2  christos 		if (xs->xs_control & XS_CTL_POLL) {
   1441  1.178.2.2  christos 			mutex_exit(chan_mtx(chan));
   1442  1.178.2.2  christos 			return;
   1443  1.178.2.2  christos 		}
   1444  1.178.2.2  christos 		cv_broadcast(xs_cv(xs));
   1445  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
   1446  1.178.2.2  christos 		goto out;
   1447  1.178.2.2  christos 	}
   1448  1.178.2.2  christos 
   1449  1.178.2.2  christos 	/*
   1450  1.178.2.2  christos 	 * Catch the extremely common case of I/O completing
   1451  1.178.2.2  christos 	 * without error; no use in taking a context switch
   1452  1.178.2.2  christos 	 * if we can handle it in interrupt context.
   1453  1.178.2.2  christos 	 */
   1454  1.178.2.2  christos 	if (xs->error == XS_NOERROR) {
   1455  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
   1456  1.178.2.2  christos 		(void) scsipi_complete(xs);
   1457  1.178.2.2  christos 		goto out;
   1458  1.178.2.2  christos 	}
   1459  1.178.2.2  christos 
   1460  1.178.2.2  christos 	/*
   1461  1.178.2.2  christos 	 * There is an error on this xfer.  Put it on the channel's
   1462  1.178.2.2  christos 	 * completion queue, and wake up the completion thread.
   1463  1.178.2.2  christos 	 */
   1464  1.178.2.2  christos 	TAILQ_INSERT_TAIL(&chan->chan_complete, xs, channel_q);
   1465  1.178.2.2  christos 	cv_broadcast(chan_cv_complete(chan));
   1466  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
   1467  1.178.2.2  christos 
   1468  1.178.2.2  christos  out:
   1469  1.178.2.2  christos 	/*
   1470  1.178.2.2  christos 	 * If there are more xfers on the channel's queue, attempt to
   1471  1.178.2.2  christos 	 * run them.
   1472  1.178.2.2  christos 	 */
   1473  1.178.2.2  christos 	scsipi_run_queue(chan);
   1474  1.178.2.2  christos }
   1475  1.178.2.2  christos 
   1476  1.178.2.2  christos /*
   1477  1.178.2.2  christos  * scsipi_complete:
   1478  1.178.2.2  christos  *
   1479  1.178.2.2  christos  *	Completion of a scsipi_xfer.  This is the guts of scsipi_done().
   1480  1.178.2.2  christos  *
   1481  1.178.2.2  christos  *	NOTE: This routine MUST be called with valid thread context
   1482  1.178.2.2  christos  *	except for the case where the following two conditions are
   1483  1.178.2.2  christos  *	true:
   1484  1.178.2.2  christos  *
   1485  1.178.2.2  christos  *		xs->error == XS_NOERROR
   1486  1.178.2.2  christos  *		XS_CTL_ASYNC is set in xs->xs_control
   1487  1.178.2.2  christos  *
   1488  1.178.2.2  christos  *	The semantics of this routine can be tricky, so here is an
   1489  1.178.2.2  christos  *	explanation:
   1490  1.178.2.2  christos  *
   1491  1.178.2.2  christos  *		0		Xfer completed successfully.
   1492  1.178.2.2  christos  *
   1493  1.178.2.2  christos  *		ERESTART	Xfer had an error, but was restarted.
   1494  1.178.2.2  christos  *
   1495  1.178.2.2  christos  *		anything else	Xfer had an error, return value is Unix
   1496  1.178.2.2  christos  *				errno.
   1497  1.178.2.2  christos  *
   1498  1.178.2.2  christos  *	If the return value is anything but ERESTART:
   1499  1.178.2.2  christos  *
   1500  1.178.2.2  christos  *		- If XS_CTL_ASYNC is set, `xs' has been freed back to
   1501  1.178.2.2  christos  *		  the pool.
   1502  1.178.2.2  christos  *		- If there is a buf associated with the xfer,
   1503  1.178.2.2  christos  *		  it has been biodone()'d.
   1504  1.178.2.2  christos  */
   1505  1.178.2.2  christos static int
   1506  1.178.2.2  christos scsipi_complete(struct scsipi_xfer *xs)
   1507  1.178.2.2  christos {
   1508  1.178.2.2  christos 	struct scsipi_periph *periph = xs->xs_periph;
   1509  1.178.2.2  christos 	struct scsipi_channel *chan = periph->periph_channel;
   1510  1.178.2.2  christos 	int error;
   1511  1.178.2.2  christos 
   1512  1.178.2.2  christos #ifdef DIAGNOSTIC
   1513  1.178.2.2  christos 	if ((xs->xs_control & XS_CTL_ASYNC) != 0 && xs->bp == NULL)
   1514  1.178.2.2  christos 		panic("scsipi_complete: XS_CTL_ASYNC but no buf");
   1515  1.178.2.2  christos #endif
   1516  1.178.2.2  christos 	/*
   1517  1.178.2.2  christos 	 * If command terminated with a CHECK CONDITION, we need to issue a
   1518  1.178.2.2  christos 	 * REQUEST_SENSE command. Once the REQUEST_SENSE has been processed
   1519  1.178.2.2  christos 	 * we'll have the real status.
   1520  1.178.2.2  christos 	 * Must be processed with channel lock held to avoid missing
   1521  1.178.2.2  christos 	 * a SCSI bus reset for this command.
   1522  1.178.2.2  christos 	 */
   1523  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
   1524  1.178.2.2  christos 	if (xs->error == XS_BUSY && xs->status == SCSI_CHECK) {
   1525  1.178.2.2  christos 		/* request sense for a request sense ? */
   1526  1.178.2.2  christos 		if (xs->xs_control & XS_CTL_REQSENSE) {
   1527  1.178.2.2  christos 			scsipi_printaddr(periph);
   1528  1.178.2.2  christos 			printf("request sense for a request sense ?\n");
   1529  1.178.2.2  christos 			/* XXX maybe we should reset the device ? */
   1530  1.178.2.2  christos 			/* we've been frozen because xs->error != XS_NOERROR */
   1531  1.178.2.2  christos 			scsipi_periph_thaw_locked(periph, 1);
   1532  1.178.2.2  christos 			mutex_exit(chan_mtx(chan));
   1533  1.178.2.2  christos 			if (xs->resid < xs->datalen) {
   1534  1.178.2.2  christos 				printf("we read %d bytes of sense anyway:\n",
   1535  1.178.2.2  christos 				    xs->datalen - xs->resid);
   1536  1.178.2.2  christos 				scsipi_print_sense_data((void *)xs->data, 0);
   1537  1.178.2.2  christos 			}
   1538  1.178.2.2  christos 			return EINVAL;
   1539  1.178.2.2  christos 		}
   1540  1.178.2.2  christos 		mutex_exit(chan_mtx(chan)); // XXX allows other commands to queue or run
   1541  1.178.2.2  christos 		scsipi_request_sense(xs);
   1542  1.178.2.2  christos 	} else
   1543  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
   1544  1.178.2.2  christos 
   1545  1.178.2.2  christos 	/*
   1546  1.178.2.2  christos 	 * If it's a user level request, bypass all usual completion
   1547  1.178.2.2  christos 	 * processing, let the user work it out..
   1548  1.178.2.2  christos 	 */
   1549  1.178.2.2  christos 	if ((xs->xs_control & XS_CTL_USERCMD) != 0) {
   1550  1.178.2.2  christos 		SC_DEBUG(periph, SCSIPI_DB3, ("calling user done()\n"));
   1551  1.178.2.2  christos 		mutex_enter(chan_mtx(chan));
   1552  1.178.2.2  christos 		if (xs->error != XS_NOERROR)
   1553  1.178.2.2  christos 			scsipi_periph_thaw_locked(periph, 1);
   1554  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
   1555  1.178.2.2  christos 		scsipi_user_done(xs);
   1556  1.178.2.2  christos 		SC_DEBUG(periph, SCSIPI_DB3, ("returned from user done()\n "));
   1557  1.178.2.2  christos 		return 0;
   1558  1.178.2.2  christos 	}
   1559  1.178.2.2  christos 
   1560  1.178.2.2  christos 	switch (xs->error) {
   1561  1.178.2.2  christos 	case XS_NOERROR:
   1562  1.178.2.2  christos 		error = 0;
   1563  1.178.2.2  christos 		break;
   1564  1.178.2.2  christos 
   1565  1.178.2.2  christos 	case XS_SENSE:
   1566  1.178.2.2  christos 	case XS_SHORTSENSE:
   1567  1.178.2.2  christos 		error = (*chan->chan_bustype->bustype_interpret_sense)(xs);
   1568  1.178.2.2  christos 		break;
   1569  1.178.2.2  christos 
   1570  1.178.2.2  christos 	case XS_RESOURCE_SHORTAGE:
   1571  1.178.2.2  christos 		/*
   1572  1.178.2.2  christos 		 * XXX Should freeze channel's queue.
   1573  1.178.2.2  christos 		 */
   1574  1.178.2.2  christos 		scsipi_printaddr(periph);
   1575  1.178.2.2  christos 		printf("adapter resource shortage\n");
   1576  1.178.2.2  christos 		/* FALLTHROUGH */
   1577  1.178.2.2  christos 
   1578  1.178.2.2  christos 	case XS_BUSY:
   1579  1.178.2.2  christos 		if (xs->error == XS_BUSY && xs->status == SCSI_QUEUE_FULL) {
   1580  1.178.2.2  christos 			struct scsipi_max_openings mo;
   1581  1.178.2.2  christos 
   1582  1.178.2.2  christos 			/*
   1583  1.178.2.2  christos 			 * We set the openings to active - 1, assuming that
   1584  1.178.2.2  christos 			 * the command that got us here is the first one that
   1585  1.178.2.2  christos 			 * can't fit into the device's queue.  If that's not
   1586  1.178.2.2  christos 			 * the case, I guess we'll find out soon enough.
   1587  1.178.2.2  christos 			 */
   1588  1.178.2.2  christos 			mo.mo_target = periph->periph_target;
   1589  1.178.2.2  christos 			mo.mo_lun = periph->periph_lun;
   1590  1.178.2.2  christos 			if (periph->periph_active < periph->periph_openings)
   1591  1.178.2.2  christos 				mo.mo_openings = periph->periph_active - 1;
   1592  1.178.2.2  christos 			else
   1593  1.178.2.2  christos 				mo.mo_openings = periph->periph_openings - 1;
   1594  1.178.2.2  christos #ifdef DIAGNOSTIC
   1595  1.178.2.2  christos 			if (mo.mo_openings < 0) {
   1596  1.178.2.2  christos 				scsipi_printaddr(periph);
   1597  1.178.2.2  christos 				printf("QUEUE FULL resulted in < 0 openings\n");
   1598  1.178.2.2  christos 				panic("scsipi_done");
   1599  1.178.2.2  christos 			}
   1600  1.178.2.2  christos #endif
   1601  1.178.2.2  christos 			if (mo.mo_openings == 0) {
   1602  1.178.2.2  christos 				scsipi_printaddr(periph);
   1603  1.178.2.2  christos 				printf("QUEUE FULL resulted in 0 openings\n");
   1604  1.178.2.2  christos 				mo.mo_openings = 1;
   1605  1.178.2.2  christos 			}
   1606  1.178.2.2  christos 			scsipi_async_event(chan, ASYNC_EVENT_MAX_OPENINGS, &mo);
   1607  1.178.2.2  christos 			error = ERESTART;
   1608  1.178.2.2  christos 		} else if (xs->xs_retries != 0) {
   1609  1.178.2.2  christos 			xs->xs_retries--;
   1610  1.178.2.2  christos 			/*
   1611  1.178.2.2  christos 			 * Wait one second, and try again.
   1612  1.178.2.2  christos 			 */
   1613  1.178.2.2  christos 			mutex_enter(chan_mtx(chan));
   1614  1.178.2.2  christos 			if ((xs->xs_control & XS_CTL_POLL) ||
   1615  1.178.2.2  christos 			    (chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
   1616  1.178.2.2  christos 				/* XXX: quite extreme */
   1617  1.178.2.2  christos 				kpause("xsbusy", false, hz, chan_mtx(chan));
   1618  1.178.2.2  christos 			} else if (!callout_pending(&periph->periph_callout)) {
   1619  1.178.2.2  christos 				scsipi_periph_freeze_locked(periph, 1);
   1620  1.178.2.2  christos 				callout_reset(&periph->periph_callout,
   1621  1.178.2.2  christos 				    hz, scsipi_periph_timed_thaw, periph);
   1622  1.178.2.2  christos 			}
   1623  1.178.2.2  christos 			mutex_exit(chan_mtx(chan));
   1624  1.178.2.2  christos 			error = ERESTART;
   1625  1.178.2.2  christos 		} else
   1626  1.178.2.2  christos 			error = EBUSY;
   1627  1.178.2.2  christos 		break;
   1628  1.178.2.2  christos 
   1629  1.178.2.2  christos 	case XS_REQUEUE:
   1630  1.178.2.2  christos 		error = ERESTART;
   1631  1.178.2.2  christos 		break;
   1632  1.178.2.2  christos 
   1633  1.178.2.2  christos 	case XS_SELTIMEOUT:
   1634  1.178.2.2  christos 	case XS_TIMEOUT:
   1635  1.178.2.2  christos 		/*
   1636  1.178.2.2  christos 		 * If the device hasn't gone away, honor retry counts.
   1637  1.178.2.2  christos 		 *
   1638  1.178.2.2  christos 		 * Note that if we're in the middle of probing it,
   1639  1.178.2.2  christos 		 * it won't be found because it isn't here yet so
   1640  1.178.2.2  christos 		 * we won't honor the retry count in that case.
   1641  1.178.2.2  christos 		 */
   1642  1.178.2.2  christos 		if (scsipi_lookup_periph(chan, periph->periph_target,
   1643  1.178.2.2  christos 		    periph->periph_lun) && xs->xs_retries != 0) {
   1644  1.178.2.2  christos 			xs->xs_retries--;
   1645  1.178.2.2  christos 			error = ERESTART;
   1646  1.178.2.2  christos 		} else
   1647  1.178.2.2  christos 			error = EIO;
   1648  1.178.2.2  christos 		break;
   1649  1.178.2.2  christos 
   1650  1.178.2.2  christos 	case XS_RESET:
   1651  1.178.2.2  christos 		if (xs->xs_control & XS_CTL_REQSENSE) {
   1652  1.178.2.2  christos 			/*
   1653  1.178.2.2  christos 			 * request sense interrupted by reset: signal it
   1654  1.178.2.2  christos 			 * with EINTR return code.
   1655  1.178.2.2  christos 			 */
   1656  1.178.2.2  christos 			error = EINTR;
   1657  1.178.2.2  christos 		} else {
   1658  1.178.2.2  christos 			if (xs->xs_retries != 0) {
   1659  1.178.2.2  christos 				xs->xs_retries--;
   1660  1.178.2.2  christos 				error = ERESTART;
   1661  1.178.2.2  christos 			} else
   1662  1.178.2.2  christos 				error = EIO;
   1663  1.178.2.2  christos 		}
   1664  1.178.2.2  christos 		break;
   1665  1.178.2.2  christos 
   1666  1.178.2.2  christos 	case XS_DRIVER_STUFFUP:
   1667  1.178.2.2  christos 		scsipi_printaddr(periph);
   1668  1.178.2.2  christos 		printf("generic HBA error\n");
   1669  1.178.2.2  christos 		error = EIO;
   1670  1.178.2.2  christos 		break;
   1671  1.178.2.2  christos 	default:
   1672  1.178.2.2  christos 		scsipi_printaddr(periph);
   1673  1.178.2.2  christos 		printf("invalid return code from adapter: %d\n", xs->error);
   1674  1.178.2.2  christos 		error = EIO;
   1675  1.178.2.2  christos 		break;
   1676  1.178.2.2  christos 	}
   1677  1.178.2.2  christos 
   1678  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
   1679  1.178.2.2  christos 	if (error == ERESTART) {
   1680  1.178.2.2  christos 		/*
   1681  1.178.2.2  christos 		 * If we get here, the periph has been thawed and frozen
   1682  1.178.2.2  christos 		 * again if we had to issue recovery commands.  Alternatively,
   1683  1.178.2.2  christos 		 * it may have been frozen again and in a timed thaw.  In
   1684  1.178.2.2  christos 		 * any case, we thaw the periph once we re-enqueue the
   1685  1.178.2.2  christos 		 * command.  Once the periph is fully thawed, it will begin
   1686  1.178.2.2  christos 		 * operation again.
   1687  1.178.2.2  christos 		 */
   1688  1.178.2.2  christos 		xs->error = XS_NOERROR;
   1689  1.178.2.2  christos 		xs->status = SCSI_OK;
   1690  1.178.2.2  christos 		xs->xs_status &= ~XS_STS_DONE;
   1691  1.178.2.2  christos 		xs->xs_requeuecnt++;
   1692  1.178.2.2  christos 		error = scsipi_enqueue(xs);
   1693  1.178.2.2  christos 		if (error == 0) {
   1694  1.178.2.2  christos 			scsipi_periph_thaw_locked(periph, 1);
   1695  1.178.2.2  christos 			mutex_exit(chan_mtx(chan));
   1696  1.178.2.2  christos 			return ERESTART;
   1697  1.178.2.2  christos 		}
   1698  1.178.2.2  christos 	}
   1699  1.178.2.2  christos 
   1700  1.178.2.2  christos 	/*
   1701  1.178.2.2  christos 	 * scsipi_done() freezes the queue if not XS_NOERROR.
   1702  1.178.2.2  christos 	 * Thaw it here.
   1703  1.178.2.2  christos 	 */
   1704  1.178.2.2  christos 	if (xs->error != XS_NOERROR)
   1705  1.178.2.2  christos 		scsipi_periph_thaw_locked(periph, 1);
   1706  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
   1707  1.178.2.2  christos 
   1708  1.178.2.2  christos 	if (periph->periph_switch->psw_done)
   1709  1.178.2.2  christos 		periph->periph_switch->psw_done(xs, error);
   1710  1.178.2.2  christos 
   1711  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
   1712  1.178.2.2  christos 	if (xs->xs_control & XS_CTL_ASYNC)
   1713  1.178.2.2  christos 		scsipi_put_xs(xs);
   1714  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
   1715  1.178.2.2  christos 
   1716  1.178.2.2  christos 	return error;
   1717  1.178.2.2  christos }
   1718  1.178.2.2  christos 
   1719  1.178.2.2  christos /*
   1720  1.178.2.2  christos  * Issue a request sense for the given scsipi_xfer. Called when the xfer
   1721  1.178.2.2  christos  * returns with a CHECK_CONDITION status. Must be called in valid thread
   1722  1.178.2.2  christos  * context.
   1723  1.178.2.2  christos  */
   1724  1.178.2.2  christos 
   1725  1.178.2.2  christos static void
   1726  1.178.2.2  christos scsipi_request_sense(struct scsipi_xfer *xs)
   1727  1.178.2.2  christos {
   1728  1.178.2.2  christos 	struct scsipi_periph *periph = xs->xs_periph;
   1729  1.178.2.2  christos 	int flags, error;
   1730  1.178.2.2  christos 	struct scsi_request_sense cmd;
   1731  1.178.2.2  christos 
   1732  1.178.2.2  christos 	periph->periph_flags |= PERIPH_SENSE;
   1733  1.178.2.2  christos 
   1734  1.178.2.2  christos 	/* if command was polling, request sense will too */
   1735  1.178.2.2  christos 	flags = xs->xs_control & XS_CTL_POLL;
   1736  1.178.2.2  christos 	/* Polling commands can't sleep */
   1737  1.178.2.2  christos 	if (flags)
   1738  1.178.2.2  christos 		flags |= XS_CTL_NOSLEEP;
   1739  1.178.2.2  christos 
   1740  1.178.2.2  christos 	flags |= XS_CTL_REQSENSE | XS_CTL_URGENT | XS_CTL_DATA_IN |
   1741  1.178.2.2  christos 	    XS_CTL_THAW_PERIPH | XS_CTL_FREEZE_PERIPH;
   1742  1.178.2.2  christos 
   1743  1.178.2.2  christos 	memset(&cmd, 0, sizeof(cmd));
   1744  1.178.2.2  christos 	cmd.opcode = SCSI_REQUEST_SENSE;
   1745  1.178.2.2  christos 	cmd.length = sizeof(struct scsi_sense_data);
   1746  1.178.2.2  christos 
   1747  1.178.2.2  christos 	error = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
   1748  1.178.2.2  christos 	    (void *)&xs->sense.scsi_sense, sizeof(struct scsi_sense_data),
   1749  1.178.2.2  christos 	    0, 1000, NULL, flags);
   1750  1.178.2.2  christos 	periph->periph_flags &= ~PERIPH_SENSE;
   1751  1.178.2.2  christos 	periph->periph_xscheck = NULL;
   1752  1.178.2.2  christos 	switch (error) {
   1753  1.178.2.2  christos 	case 0:
   1754  1.178.2.2  christos 		/* we have a valid sense */
   1755  1.178.2.2  christos 		xs->error = XS_SENSE;
   1756  1.178.2.2  christos 		return;
   1757  1.178.2.2  christos 	case EINTR:
   1758  1.178.2.2  christos 		/* REQUEST_SENSE interrupted by bus reset. */
   1759  1.178.2.2  christos 		xs->error = XS_RESET;
   1760  1.178.2.2  christos 		return;
   1761  1.178.2.2  christos 	case EIO:
   1762  1.178.2.2  christos 		 /* request sense coudn't be performed */
   1763  1.178.2.2  christos 		/*
   1764  1.178.2.2  christos 		 * XXX this isn't quite right but we don't have anything
   1765  1.178.2.2  christos 		 * better for now
   1766  1.178.2.2  christos 		 */
   1767  1.178.2.2  christos 		xs->error = XS_DRIVER_STUFFUP;
   1768  1.178.2.2  christos 		return;
   1769  1.178.2.2  christos 	default:
   1770  1.178.2.2  christos 		 /* Notify that request sense failed. */
   1771  1.178.2.2  christos 		xs->error = XS_DRIVER_STUFFUP;
   1772  1.178.2.2  christos 		scsipi_printaddr(periph);
   1773  1.178.2.2  christos 		printf("request sense failed with error %d\n", error);
   1774  1.178.2.2  christos 		return;
   1775  1.178.2.2  christos 	}
   1776  1.178.2.2  christos }
   1777  1.178.2.2  christos 
   1778  1.178.2.2  christos /*
   1779  1.178.2.2  christos  * scsipi_enqueue:
   1780  1.178.2.2  christos  *
   1781  1.178.2.2  christos  *	Enqueue an xfer on a channel.
   1782  1.178.2.2  christos  */
   1783  1.178.2.2  christos static int
   1784  1.178.2.2  christos scsipi_enqueue(struct scsipi_xfer *xs)
   1785  1.178.2.2  christos {
   1786  1.178.2.2  christos 	struct scsipi_channel *chan = xs->xs_periph->periph_channel;
   1787  1.178.2.2  christos 	struct scsipi_xfer *qxs;
   1788  1.178.2.2  christos 
   1789  1.178.2.2  christos 	/*
   1790  1.178.2.2  christos 	 * If the xfer is to be polled, and there are already jobs on
   1791  1.178.2.2  christos 	 * the queue, we can't proceed.
   1792  1.178.2.2  christos 	 */
   1793  1.178.2.2  christos 	if ((xs->xs_control & XS_CTL_POLL) != 0 &&
   1794  1.178.2.2  christos 	    TAILQ_FIRST(&chan->chan_queue) != NULL) {
   1795  1.178.2.2  christos 		xs->error = XS_DRIVER_STUFFUP;
   1796  1.178.2.2  christos 		return EAGAIN;
   1797  1.178.2.2  christos 	}
   1798  1.178.2.2  christos 
   1799  1.178.2.2  christos 	/*
   1800  1.178.2.2  christos 	 * If we have an URGENT xfer, it's an error recovery command
   1801  1.178.2.2  christos 	 * and it should just go on the head of the channel's queue.
   1802  1.178.2.2  christos 	 */
   1803  1.178.2.2  christos 	if (xs->xs_control & XS_CTL_URGENT) {
   1804  1.178.2.2  christos 		TAILQ_INSERT_HEAD(&chan->chan_queue, xs, channel_q);
   1805  1.178.2.2  christos 		goto out;
   1806  1.178.2.2  christos 	}
   1807  1.178.2.2  christos 
   1808  1.178.2.2  christos 	/*
   1809  1.178.2.2  christos 	 * If this xfer has already been on the queue before, we
   1810  1.178.2.2  christos 	 * need to reinsert it in the correct order.  That order is:
   1811  1.178.2.2  christos 	 *
   1812  1.178.2.2  christos 	 *	Immediately before the first xfer for this periph
   1813  1.178.2.2  christos 	 *	with a requeuecnt less than xs->xs_requeuecnt.
   1814  1.178.2.2  christos 	 *
   1815  1.178.2.2  christos 	 * Failing that, at the end of the queue.  (We'll end up
   1816  1.178.2.2  christos 	 * there naturally.)
   1817  1.178.2.2  christos 	 */
   1818  1.178.2.2  christos 	if (xs->xs_requeuecnt != 0) {
   1819  1.178.2.2  christos 		for (qxs = TAILQ_FIRST(&chan->chan_queue); qxs != NULL;
   1820  1.178.2.2  christos 		     qxs = TAILQ_NEXT(qxs, channel_q)) {
   1821  1.178.2.2  christos 			if (qxs->xs_periph == xs->xs_periph &&
   1822  1.178.2.2  christos 			    qxs->xs_requeuecnt < xs->xs_requeuecnt)
   1823  1.178.2.2  christos 				break;
   1824  1.178.2.2  christos 		}
   1825  1.178.2.2  christos 		if (qxs != NULL) {
   1826  1.178.2.2  christos 			TAILQ_INSERT_AFTER(&chan->chan_queue, qxs, xs,
   1827  1.178.2.2  christos 			    channel_q);
   1828  1.178.2.2  christos 			goto out;
   1829  1.178.2.2  christos 		}
   1830  1.178.2.2  christos 	}
   1831  1.178.2.2  christos 	TAILQ_INSERT_TAIL(&chan->chan_queue, xs, channel_q);
   1832  1.178.2.2  christos  out:
   1833  1.178.2.2  christos 	if (xs->xs_control & XS_CTL_THAW_PERIPH)
   1834  1.178.2.2  christos 		scsipi_periph_thaw_locked(xs->xs_periph, 1);
   1835  1.178.2.2  christos 	return 0;
   1836  1.178.2.2  christos }
   1837  1.178.2.2  christos 
   1838  1.178.2.2  christos /*
   1839  1.178.2.2  christos  * scsipi_run_queue:
   1840  1.178.2.2  christos  *
   1841  1.178.2.2  christos  *	Start as many xfers as possible running on the channel.
   1842  1.178.2.2  christos  */
   1843  1.178.2.2  christos static void
   1844  1.178.2.2  christos scsipi_run_queue(struct scsipi_channel *chan)
   1845  1.178.2.2  christos {
   1846  1.178.2.2  christos 	struct scsipi_xfer *xs;
   1847  1.178.2.2  christos 	struct scsipi_periph *periph;
   1848  1.178.2.2  christos 
   1849  1.178.2.2  christos 	for (;;) {
   1850  1.178.2.2  christos 		mutex_enter(chan_mtx(chan));
   1851  1.178.2.2  christos 
   1852  1.178.2.2  christos 		/*
   1853  1.178.2.2  christos 		 * If the channel is frozen, we can't do any work right
   1854  1.178.2.2  christos 		 * now.
   1855  1.178.2.2  christos 		 */
   1856  1.178.2.2  christos 		if (chan->chan_qfreeze != 0) {
   1857  1.178.2.2  christos 			mutex_exit(chan_mtx(chan));
   1858  1.178.2.2  christos 			return;
   1859  1.178.2.2  christos 		}
   1860  1.178.2.2  christos 
   1861  1.178.2.2  christos 		/*
   1862  1.178.2.2  christos 		 * Look for work to do, and make sure we can do it.
   1863  1.178.2.2  christos 		 */
   1864  1.178.2.2  christos 		for (xs = TAILQ_FIRST(&chan->chan_queue); xs != NULL;
   1865  1.178.2.2  christos 		     xs = TAILQ_NEXT(xs, channel_q)) {
   1866  1.178.2.2  christos 			periph = xs->xs_periph;
   1867  1.178.2.2  christos 
   1868  1.178.2.2  christos 			if ((periph->periph_sent >= periph->periph_openings) ||
   1869  1.178.2.2  christos 			    periph->periph_qfreeze != 0 ||
   1870  1.178.2.2  christos 			    (periph->periph_flags & PERIPH_UNTAG) != 0)
   1871  1.178.2.2  christos 				continue;
   1872  1.178.2.2  christos 
   1873  1.178.2.2  christos 			if ((periph->periph_flags &
   1874  1.178.2.2  christos 			    (PERIPH_RECOVERING | PERIPH_SENSE)) != 0 &&
   1875  1.178.2.2  christos 			    (xs->xs_control & XS_CTL_URGENT) == 0)
   1876  1.178.2.2  christos 				continue;
   1877  1.178.2.2  christos 
   1878  1.178.2.2  christos 			/*
   1879  1.178.2.2  christos 			 * We can issue this xfer!
   1880  1.178.2.2  christos 			 */
   1881  1.178.2.2  christos 			goto got_one;
   1882  1.178.2.2  christos 		}
   1883  1.178.2.2  christos 
   1884  1.178.2.2  christos 		/*
   1885  1.178.2.2  christos 		 * Can't find any work to do right now.
   1886  1.178.2.2  christos 		 */
   1887  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
   1888  1.178.2.2  christos 		return;
   1889  1.178.2.2  christos 
   1890  1.178.2.2  christos  got_one:
   1891  1.178.2.2  christos 		/*
   1892  1.178.2.2  christos 		 * Have an xfer to run.  Allocate a resource from
   1893  1.178.2.2  christos 		 * the adapter to run it.  If we can't allocate that
   1894  1.178.2.2  christos 		 * resource, we don't dequeue the xfer.
   1895  1.178.2.2  christos 		 */
   1896  1.178.2.2  christos 		if (scsipi_get_resource(chan) == 0) {
   1897  1.178.2.2  christos 			/*
   1898  1.178.2.2  christos 			 * Adapter is out of resources.  If the adapter
   1899  1.178.2.2  christos 			 * supports it, attempt to grow them.
   1900  1.178.2.2  christos 			 */
   1901  1.178.2.2  christos 			if (scsipi_grow_resources(chan) == 0) {
   1902  1.178.2.2  christos 				/*
   1903  1.178.2.2  christos 				 * Wasn't able to grow resources,
   1904  1.178.2.2  christos 				 * nothing more we can do.
   1905  1.178.2.2  christos 				 */
   1906  1.178.2.2  christos 				if (xs->xs_control & XS_CTL_POLL) {
   1907  1.178.2.2  christos 					scsipi_printaddr(xs->xs_periph);
   1908  1.178.2.2  christos 					printf("polling command but no "
   1909  1.178.2.2  christos 					    "adapter resources");
   1910  1.178.2.2  christos 					/* We'll panic shortly... */
   1911  1.178.2.2  christos 				}
   1912  1.178.2.2  christos 				mutex_exit(chan_mtx(chan));
   1913  1.178.2.2  christos 
   1914  1.178.2.2  christos 				/*
   1915  1.178.2.2  christos 				 * XXX: We should be able to note that
   1916  1.178.2.2  christos 				 * XXX: that resources are needed here!
   1917  1.178.2.2  christos 				 */
   1918  1.178.2.2  christos 				return;
   1919  1.178.2.2  christos 			}
   1920  1.178.2.2  christos 			/*
   1921  1.178.2.2  christos 			 * scsipi_grow_resources() allocated the resource
   1922  1.178.2.2  christos 			 * for us.
   1923  1.178.2.2  christos 			 */
   1924  1.178.2.2  christos 		}
   1925  1.178.2.2  christos 
   1926  1.178.2.2  christos 		/*
   1927  1.178.2.2  christos 		 * We have a resource to run this xfer, do it!
   1928  1.178.2.2  christos 		 */
   1929  1.178.2.2  christos 		TAILQ_REMOVE(&chan->chan_queue, xs, channel_q);
   1930  1.178.2.2  christos 
   1931  1.178.2.2  christos 		/*
   1932  1.178.2.2  christos 		 * If the command is to be tagged, allocate a tag ID
   1933  1.178.2.2  christos 		 * for it.
   1934  1.178.2.2  christos 		 */
   1935  1.178.2.2  christos 		if (XS_CTL_TAGTYPE(xs) != 0)
   1936  1.178.2.2  christos 			scsipi_get_tag(xs);
   1937  1.178.2.2  christos 		else
   1938  1.178.2.2  christos 			periph->periph_flags |= PERIPH_UNTAG;
   1939  1.178.2.2  christos 		periph->periph_sent++;
   1940  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
   1941  1.178.2.2  christos 
   1942  1.178.2.2  christos 		scsipi_adapter_request(chan, ADAPTER_REQ_RUN_XFER, xs);
   1943  1.178.2.2  christos 	}
   1944  1.178.2.2  christos #ifdef DIAGNOSTIC
   1945  1.178.2.2  christos 	panic("scsipi_run_queue: impossible");
   1946  1.178.2.2  christos #endif
   1947  1.178.2.2  christos }
   1948  1.178.2.2  christos 
   1949  1.178.2.2  christos /*
   1950  1.178.2.2  christos  * scsipi_execute_xs:
   1951  1.178.2.2  christos  *
   1952  1.178.2.2  christos  *	Begin execution of an xfer, waiting for it to complete, if necessary.
   1953  1.178.2.2  christos  */
   1954  1.178.2.2  christos int
   1955  1.178.2.2  christos scsipi_execute_xs(struct scsipi_xfer *xs)
   1956  1.178.2.2  christos {
   1957  1.178.2.2  christos 	struct scsipi_periph *periph = xs->xs_periph;
   1958  1.178.2.2  christos 	struct scsipi_channel *chan = periph->periph_channel;
   1959  1.178.2.2  christos 	int oasync, async, poll, error;
   1960  1.178.2.2  christos 
   1961  1.178.2.2  christos 	KASSERT(!cold);
   1962  1.178.2.2  christos 
   1963  1.178.2.2  christos 	(chan->chan_bustype->bustype_cmd)(xs);
   1964  1.178.2.2  christos 
   1965  1.178.2.2  christos 	xs->xs_status &= ~XS_STS_DONE;
   1966  1.178.2.2  christos 	xs->error = XS_NOERROR;
   1967  1.178.2.2  christos 	xs->resid = xs->datalen;
   1968  1.178.2.2  christos 	xs->status = SCSI_OK;
   1969  1.178.2.2  christos 
   1970  1.178.2.2  christos #ifdef SCSIPI_DEBUG
   1971  1.178.2.2  christos 	if (xs->xs_periph->periph_dbflags & SCSIPI_DB3) {
   1972  1.178.2.2  christos 		printf("scsipi_execute_xs: ");
   1973  1.178.2.2  christos 		show_scsipi_xs(xs);
   1974  1.178.2.2  christos 		printf("\n");
   1975  1.178.2.2  christos 	}
   1976  1.178.2.2  christos #endif
   1977  1.178.2.2  christos 
   1978  1.178.2.2  christos 	/*
   1979  1.178.2.2  christos 	 * Deal with command tagging:
   1980  1.178.2.2  christos 	 *
   1981  1.178.2.2  christos 	 *	- If the device's current operating mode doesn't
   1982  1.178.2.2  christos 	 *	  include tagged queueing, clear the tag mask.
   1983  1.178.2.2  christos 	 *
   1984  1.178.2.2  christos 	 *	- If the device's current operating mode *does*
   1985  1.178.2.2  christos 	 *	  include tagged queueing, set the tag_type in
   1986  1.178.2.2  christos 	 *	  the xfer to the appropriate byte for the tag
   1987  1.178.2.2  christos 	 *	  message.
   1988  1.178.2.2  christos 	 */
   1989  1.178.2.2  christos 	if ((PERIPH_XFER_MODE(periph) & PERIPH_CAP_TQING) == 0 ||
   1990  1.178.2.2  christos 		(xs->xs_control & XS_CTL_REQSENSE)) {
   1991  1.178.2.2  christos 		xs->xs_control &= ~XS_CTL_TAGMASK;
   1992  1.178.2.2  christos 		xs->xs_tag_type = 0;
   1993  1.178.2.2  christos 	} else {
   1994  1.178.2.2  christos 		/*
   1995  1.178.2.2  christos 		 * If the request doesn't specify a tag, give Head
   1996  1.178.2.2  christos 		 * tags to URGENT operations and Simple tags to
   1997  1.178.2.2  christos 		 * everything else.
   1998  1.178.2.2  christos 		 */
   1999  1.178.2.2  christos 		if (XS_CTL_TAGTYPE(xs) == 0) {
   2000  1.178.2.2  christos 			if (xs->xs_control & XS_CTL_URGENT)
   2001  1.178.2.2  christos 				xs->xs_control |= XS_CTL_HEAD_TAG;
   2002  1.178.2.2  christos 			else
   2003  1.178.2.2  christos 				xs->xs_control |= XS_CTL_SIMPLE_TAG;
   2004  1.178.2.2  christos 		}
   2005  1.178.2.2  christos 
   2006  1.178.2.2  christos 		switch (XS_CTL_TAGTYPE(xs)) {
   2007  1.178.2.2  christos 		case XS_CTL_ORDERED_TAG:
   2008  1.178.2.2  christos 			xs->xs_tag_type = MSG_ORDERED_Q_TAG;
   2009  1.178.2.2  christos 			break;
   2010  1.178.2.2  christos 
   2011  1.178.2.2  christos 		case XS_CTL_SIMPLE_TAG:
   2012  1.178.2.2  christos 			xs->xs_tag_type = MSG_SIMPLE_Q_TAG;
   2013  1.178.2.2  christos 			break;
   2014  1.178.2.2  christos 
   2015  1.178.2.2  christos 		case XS_CTL_HEAD_TAG:
   2016  1.178.2.2  christos 			xs->xs_tag_type = MSG_HEAD_OF_Q_TAG;
   2017  1.178.2.2  christos 			break;
   2018  1.178.2.2  christos 
   2019  1.178.2.2  christos 		default:
   2020  1.178.2.2  christos 			scsipi_printaddr(periph);
   2021  1.178.2.2  christos 			printf("invalid tag mask 0x%08x\n",
   2022  1.178.2.2  christos 			    XS_CTL_TAGTYPE(xs));
   2023  1.178.2.2  christos 			panic("scsipi_execute_xs");
   2024  1.178.2.2  christos 		}
   2025  1.178.2.2  christos 	}
   2026  1.178.2.2  christos 
   2027  1.178.2.2  christos 	/* If the adaptor wants us to poll, poll. */
   2028  1.178.2.2  christos 	if (chan->chan_adapter->adapt_flags & SCSIPI_ADAPT_POLL_ONLY)
   2029  1.178.2.2  christos 		xs->xs_control |= XS_CTL_POLL;
   2030  1.178.2.2  christos 
   2031  1.178.2.2  christos 	/*
   2032  1.178.2.2  christos 	 * If we don't yet have a completion thread, or we are to poll for
   2033  1.178.2.2  christos 	 * completion, clear the ASYNC flag.
   2034  1.178.2.2  christos 	 */
   2035  1.178.2.2  christos 	oasync =  (xs->xs_control & XS_CTL_ASYNC);
   2036  1.178.2.2  christos 	if (chan->chan_thread == NULL || (xs->xs_control & XS_CTL_POLL) != 0)
   2037  1.178.2.2  christos 		xs->xs_control &= ~XS_CTL_ASYNC;
   2038  1.178.2.2  christos 
   2039  1.178.2.2  christos 	async = (xs->xs_control & XS_CTL_ASYNC);
   2040  1.178.2.2  christos 	poll = (xs->xs_control & XS_CTL_POLL);
   2041  1.178.2.2  christos 
   2042  1.178.2.2  christos #ifdef DIAGNOSTIC
   2043  1.178.2.2  christos 	if (oasync != 0 && xs->bp == NULL)
   2044  1.178.2.2  christos 		panic("scsipi_execute_xs: XS_CTL_ASYNC but no buf");
   2045  1.178.2.2  christos #endif
   2046  1.178.2.2  christos 
   2047  1.178.2.2  christos 	/*
   2048  1.178.2.2  christos 	 * Enqueue the transfer.  If we're not polling for completion, this
   2049  1.178.2.2  christos 	 * should ALWAYS return `no error'.
   2050  1.178.2.2  christos 	 */
   2051  1.178.2.2  christos 	error = scsipi_enqueue(xs);
   2052  1.178.2.2  christos 	if (error) {
   2053  1.178.2.2  christos 		if (poll == 0) {
   2054  1.178.2.2  christos 			scsipi_printaddr(periph);
   2055  1.178.2.2  christos 			printf("not polling, but enqueue failed with %d\n",
   2056  1.178.2.2  christos 			    error);
   2057  1.178.2.2  christos 			panic("scsipi_execute_xs");
   2058  1.178.2.2  christos 		}
   2059  1.178.2.2  christos 
   2060  1.178.2.2  christos 		scsipi_printaddr(periph);
   2061  1.178.2.2  christos 		printf("should have flushed queue?\n");
   2062  1.178.2.2  christos 		goto free_xs;
   2063  1.178.2.2  christos 	}
   2064  1.178.2.2  christos 
   2065  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
   2066  1.178.2.2  christos  restarted:
   2067  1.178.2.2  christos 	scsipi_run_queue(chan);
   2068  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
   2069  1.178.2.2  christos 
   2070  1.178.2.2  christos 	/*
   2071  1.178.2.2  christos 	 * The xfer is enqueued, and possibly running.  If it's to be
   2072  1.178.2.2  christos 	 * completed asynchronously, just return now.
   2073  1.178.2.2  christos 	 */
   2074  1.178.2.2  christos 	if (async)
   2075  1.178.2.2  christos 		return 0;
   2076  1.178.2.2  christos 
   2077  1.178.2.2  christos 	/*
   2078  1.178.2.2  christos 	 * Not an asynchronous command; wait for it to complete.
   2079  1.178.2.2  christos 	 */
   2080  1.178.2.2  christos 	while ((xs->xs_status & XS_STS_DONE) == 0) {
   2081  1.178.2.2  christos 		if (poll) {
   2082  1.178.2.2  christos 			scsipi_printaddr(periph);
   2083  1.178.2.2  christos 			printf("polling command not done\n");
   2084  1.178.2.2  christos 			panic("scsipi_execute_xs");
   2085  1.178.2.2  christos 		}
   2086  1.178.2.2  christos 		cv_wait(xs_cv(xs), chan_mtx(chan));
   2087  1.178.2.2  christos 	}
   2088  1.178.2.2  christos 
   2089  1.178.2.2  christos 	/*
   2090  1.178.2.2  christos 	 * Command is complete.  scsipi_done() has awakened us to perform
   2091  1.178.2.2  christos 	 * the error handling.
   2092  1.178.2.2  christos 	 */
   2093  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
   2094  1.178.2.2  christos 	error = scsipi_complete(xs);
   2095  1.178.2.2  christos 	if (error == ERESTART)
   2096  1.178.2.2  christos 		goto restarted;
   2097  1.178.2.2  christos 
   2098  1.178.2.2  christos 	/*
   2099  1.178.2.2  christos 	 * If it was meant to run async and we cleared aync ourselve,
   2100  1.178.2.2  christos 	 * don't return an error here. It has already been handled
   2101  1.178.2.2  christos 	 */
   2102  1.178.2.2  christos 	if (oasync)
   2103  1.178.2.2  christos 		error = 0;
   2104  1.178.2.2  christos 	/*
   2105  1.178.2.2  christos 	 * Command completed successfully or fatal error occurred.  Fall
   2106  1.178.2.2  christos 	 * into....
   2107  1.178.2.2  christos 	 */
   2108  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
   2109  1.178.2.2  christos  free_xs:
   2110  1.178.2.2  christos 	scsipi_put_xs(xs);
   2111  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
   2112  1.178.2.2  christos 
   2113  1.178.2.2  christos 	/*
   2114  1.178.2.2  christos 	 * Kick the queue, keep it running in case it stopped for some
   2115  1.178.2.2  christos 	 * reason.
   2116  1.178.2.2  christos 	 */
   2117  1.178.2.2  christos 	scsipi_run_queue(chan);
   2118  1.178.2.2  christos 
   2119  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
   2120  1.178.2.2  christos 	return error;
   2121  1.178.2.2  christos }
   2122  1.178.2.2  christos 
   2123  1.178.2.2  christos /*
   2124  1.178.2.2  christos  * scsipi_completion_thread:
   2125  1.178.2.2  christos  *
   2126  1.178.2.2  christos  *	This is the completion thread.  We wait for errors on
   2127  1.178.2.2  christos  *	asynchronous xfers, and perform the error handling
   2128  1.178.2.2  christos  *	function, restarting the command, if necessary.
   2129  1.178.2.2  christos  */
   2130  1.178.2.2  christos static void
   2131  1.178.2.2  christos scsipi_completion_thread(void *arg)
   2132  1.178.2.2  christos {
   2133  1.178.2.2  christos 	struct scsipi_channel *chan = arg;
   2134  1.178.2.2  christos 	struct scsipi_xfer *xs;
   2135  1.178.2.2  christos 
   2136  1.178.2.2  christos 	if (chan->chan_init_cb)
   2137  1.178.2.2  christos 		(*chan->chan_init_cb)(chan, chan->chan_init_cb_arg);
   2138  1.178.2.2  christos 
   2139  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
   2140  1.178.2.2  christos 	chan->chan_flags |= SCSIPI_CHAN_TACTIVE;
   2141  1.178.2.2  christos 	for (;;) {
   2142  1.178.2.2  christos 		xs = TAILQ_FIRST(&chan->chan_complete);
   2143  1.178.2.2  christos 		if (xs == NULL && chan->chan_tflags == 0) {
   2144  1.178.2.2  christos 			/* nothing to do; wait */
   2145  1.178.2.2  christos 			cv_wait(chan_cv_complete(chan), chan_mtx(chan));
   2146  1.178.2.2  christos 			continue;
   2147  1.178.2.2  christos 		}
   2148  1.178.2.2  christos 		if (chan->chan_tflags & SCSIPI_CHANT_CALLBACK) {
   2149  1.178.2.2  christos 			/* call chan_callback from thread context */
   2150  1.178.2.2  christos 			chan->chan_tflags &= ~SCSIPI_CHANT_CALLBACK;
   2151  1.178.2.2  christos 			chan->chan_callback(chan, chan->chan_callback_arg);
   2152  1.178.2.2  christos 			continue;
   2153  1.178.2.2  christos 		}
   2154  1.178.2.2  christos 		if (chan->chan_tflags & SCSIPI_CHANT_GROWRES) {
   2155  1.178.2.2  christos 			/* attempt to get more openings for this channel */
   2156  1.178.2.2  christos 			chan->chan_tflags &= ~SCSIPI_CHANT_GROWRES;
   2157  1.178.2.2  christos 			mutex_exit(chan_mtx(chan));
   2158  1.178.2.2  christos 			scsipi_adapter_request(chan,
   2159  1.178.2.2  christos 			    ADAPTER_REQ_GROW_RESOURCES, NULL);
   2160  1.178.2.2  christos 			scsipi_channel_thaw(chan, 1);
   2161  1.178.2.2  christos 			if (chan->chan_tflags & SCSIPI_CHANT_GROWRES)
   2162  1.178.2.2  christos 				kpause("scsizzz", FALSE, hz/10, NULL);
   2163  1.178.2.2  christos 			mutex_enter(chan_mtx(chan));
   2164  1.178.2.2  christos 			continue;
   2165  1.178.2.2  christos 		}
   2166  1.178.2.2  christos 		if (chan->chan_tflags & SCSIPI_CHANT_KICK) {
   2167  1.178.2.2  christos 			/* explicitly run the queues for this channel */
   2168  1.178.2.2  christos 			chan->chan_tflags &= ~SCSIPI_CHANT_KICK;
   2169  1.178.2.2  christos 			mutex_exit(chan_mtx(chan));
   2170  1.178.2.2  christos 			scsipi_run_queue(chan);
   2171  1.178.2.2  christos 			mutex_enter(chan_mtx(chan));
   2172  1.178.2.2  christos 			continue;
   2173  1.178.2.2  christos 		}
   2174  1.178.2.2  christos 		if (chan->chan_tflags & SCSIPI_CHANT_SHUTDOWN) {
   2175  1.178.2.2  christos 			break;
   2176  1.178.2.2  christos 		}
   2177  1.178.2.2  christos 		if (xs) {
   2178  1.178.2.2  christos 			TAILQ_REMOVE(&chan->chan_complete, xs, channel_q);
   2179  1.178.2.2  christos 			mutex_exit(chan_mtx(chan));
   2180  1.178.2.2  christos 
   2181  1.178.2.2  christos 			/*
   2182  1.178.2.2  christos 			 * Have an xfer with an error; process it.
   2183  1.178.2.2  christos 			 */
   2184  1.178.2.2  christos 			(void) scsipi_complete(xs);
   2185  1.178.2.2  christos 
   2186  1.178.2.2  christos 			/*
   2187  1.178.2.2  christos 			 * Kick the queue; keep it running if it was stopped
   2188  1.178.2.2  christos 			 * for some reason.
   2189  1.178.2.2  christos 			 */
   2190  1.178.2.2  christos 			scsipi_run_queue(chan);
   2191  1.178.2.2  christos 			mutex_enter(chan_mtx(chan));
   2192  1.178.2.2  christos 		}
   2193  1.178.2.2  christos 	}
   2194  1.178.2.2  christos 
   2195  1.178.2.2  christos 	chan->chan_thread = NULL;
   2196  1.178.2.2  christos 
   2197  1.178.2.2  christos 	/* In case parent is waiting for us to exit. */
   2198  1.178.2.2  christos 	cv_broadcast(chan_cv_thread(chan));
   2199  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
   2200  1.178.2.2  christos 
   2201  1.178.2.2  christos 	kthread_exit(0);
   2202  1.178.2.2  christos }
   2203  1.178.2.2  christos /*
   2204  1.178.2.2  christos  * scsipi_thread_call_callback:
   2205  1.178.2.2  christos  *
   2206  1.178.2.2  christos  * 	request to call a callback from the completion thread
   2207  1.178.2.2  christos  */
   2208  1.178.2.2  christos int
   2209  1.178.2.2  christos scsipi_thread_call_callback(struct scsipi_channel *chan,
   2210  1.178.2.2  christos     void (*callback)(struct scsipi_channel *, void *), void *arg)
   2211  1.178.2.2  christos {
   2212  1.178.2.2  christos 
   2213  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
   2214  1.178.2.2  christos 	if ((chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
   2215  1.178.2.2  christos 		/* kernel thread doesn't exist yet */
   2216  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
   2217  1.178.2.2  christos 		return ESRCH;
   2218  1.178.2.2  christos 	}
   2219  1.178.2.2  christos 	if (chan->chan_tflags & SCSIPI_CHANT_CALLBACK) {
   2220  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
   2221  1.178.2.2  christos 		return EBUSY;
   2222  1.178.2.2  christos 	}
   2223  1.178.2.2  christos 	scsipi_channel_freeze(chan, 1);
   2224  1.178.2.2  christos 	chan->chan_callback = callback;
   2225  1.178.2.2  christos 	chan->chan_callback_arg = arg;
   2226  1.178.2.2  christos 	chan->chan_tflags |= SCSIPI_CHANT_CALLBACK;
   2227  1.178.2.2  christos 	cv_broadcast(chan_cv_complete(chan));
   2228  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
   2229  1.178.2.2  christos 	return 0;
   2230  1.178.2.2  christos }
   2231  1.178.2.2  christos 
   2232  1.178.2.2  christos /*
   2233  1.178.2.2  christos  * scsipi_async_event:
   2234  1.178.2.2  christos  *
   2235  1.178.2.2  christos  *	Handle an asynchronous event from an adapter.
   2236  1.178.2.2  christos  */
   2237  1.178.2.2  christos void
   2238  1.178.2.2  christos scsipi_async_event(struct scsipi_channel *chan, scsipi_async_event_t event,
   2239  1.178.2.2  christos     void *arg)
   2240  1.178.2.2  christos {
   2241  1.178.2.2  christos 	bool lock = chan_running(chan) > 0;
   2242  1.178.2.2  christos 
   2243  1.178.2.2  christos 	if (lock)
   2244  1.178.2.2  christos 		mutex_enter(chan_mtx(chan));
   2245  1.178.2.2  christos 	switch (event) {
   2246  1.178.2.2  christos 	case ASYNC_EVENT_MAX_OPENINGS:
   2247  1.178.2.2  christos 		scsipi_async_event_max_openings(chan,
   2248  1.178.2.2  christos 		    (struct scsipi_max_openings *)arg);
   2249  1.178.2.2  christos 		break;
   2250  1.178.2.2  christos 
   2251  1.178.2.2  christos 	case ASYNC_EVENT_XFER_MODE:
   2252  1.178.2.2  christos 		if (chan->chan_bustype->bustype_async_event_xfer_mode) {
   2253  1.178.2.2  christos 			chan->chan_bustype->bustype_async_event_xfer_mode(
   2254  1.178.2.2  christos 			    chan, arg);
   2255  1.178.2.2  christos 		}
   2256  1.178.2.2  christos 		break;
   2257  1.178.2.2  christos 	case ASYNC_EVENT_RESET:
   2258  1.178.2.2  christos 		scsipi_async_event_channel_reset(chan);
   2259  1.178.2.2  christos 		break;
   2260  1.178.2.2  christos 	}
   2261  1.178.2.2  christos 	if (lock)
   2262  1.178.2.2  christos 		mutex_exit(chan_mtx(chan));
   2263  1.178.2.2  christos }
   2264  1.178.2.2  christos 
   2265  1.178.2.2  christos /*
   2266  1.178.2.2  christos  * scsipi_async_event_max_openings:
   2267  1.178.2.2  christos  *
   2268  1.178.2.2  christos  *	Update the maximum number of outstanding commands a
   2269  1.178.2.2  christos  *	device may have.
   2270  1.178.2.2  christos  */
   2271  1.178.2.2  christos static void
   2272  1.178.2.2  christos scsipi_async_event_max_openings(struct scsipi_channel *chan,
   2273  1.178.2.2  christos     struct scsipi_max_openings *mo)
   2274  1.178.2.2  christos {
   2275  1.178.2.2  christos 	struct scsipi_periph *periph;
   2276  1.178.2.2  christos 	int minlun, maxlun;
   2277  1.178.2.2  christos 
   2278  1.178.2.2  christos 	if (mo->mo_lun == -1) {
   2279  1.178.2.2  christos 		/*
   2280  1.178.2.2  christos 		 * Wildcarded; apply it to all LUNs.
   2281  1.178.2.2  christos 		 */
   2282  1.178.2.2  christos 		minlun = 0;
   2283  1.178.2.2  christos 		maxlun = chan->chan_nluns - 1;
   2284  1.178.2.2  christos 	} else
   2285  1.178.2.2  christos 		minlun = maxlun = mo->mo_lun;
   2286  1.178.2.2  christos 
   2287  1.178.2.2  christos 	/* XXX This could really suck with a large LUN space. */
   2288  1.178.2.2  christos 	for (; minlun <= maxlun; minlun++) {
   2289  1.178.2.2  christos 		periph = scsipi_lookup_periph_locked(chan, mo->mo_target, minlun);
   2290  1.178.2.2  christos 		if (periph == NULL)
   2291  1.178.2.2  christos 			continue;
   2292  1.178.2.2  christos 
   2293  1.178.2.2  christos 		if (mo->mo_openings < periph->periph_openings)
   2294  1.178.2.2  christos 			periph->periph_openings = mo->mo_openings;
   2295  1.178.2.2  christos 		else if (mo->mo_openings > periph->periph_openings &&
   2296  1.178.2.2  christos 		    (periph->periph_flags & PERIPH_GROW_OPENINGS) != 0)
   2297  1.178.2.2  christos 			periph->periph_openings = mo->mo_openings;
   2298  1.178.2.2  christos 	}
   2299  1.178.2.2  christos }
   2300  1.178.2.2  christos 
   2301  1.178.2.2  christos /*
   2302  1.178.2.2  christos  * scsipi_set_xfer_mode:
   2303  1.178.2.2  christos  *
   2304  1.178.2.2  christos  *	Set the xfer mode for the specified I_T Nexus.
   2305  1.178.2.2  christos  */
   2306  1.178.2.2  christos void
   2307  1.178.2.2  christos scsipi_set_xfer_mode(struct scsipi_channel *chan, int target, int immed)
   2308  1.178.2.2  christos {
   2309  1.178.2.2  christos 	struct scsipi_xfer_mode xm;
   2310  1.178.2.2  christos 	struct scsipi_periph *itperiph;
   2311  1.178.2.2  christos 	int lun;
   2312  1.178.2.2  christos 
   2313  1.178.2.2  christos 	/*
   2314  1.178.2.2  christos 	 * Go to the minimal xfer mode.
   2315  1.178.2.2  christos 	 */
   2316  1.178.2.2  christos 	xm.xm_target = target;
   2317  1.178.2.2  christos 	xm.xm_mode = 0;
   2318  1.178.2.2  christos 	xm.xm_period = 0;			/* ignored */
   2319  1.178.2.2  christos 	xm.xm_offset = 0;			/* ignored */
   2320  1.178.2.2  christos 
   2321  1.178.2.2  christos 	/*
   2322  1.178.2.2  christos 	 * Find the first LUN we know about on this I_T Nexus.
   2323  1.178.2.2  christos 	 */
   2324  1.178.2.2  christos 	for (itperiph = NULL, lun = 0; lun < chan->chan_nluns; lun++) {
   2325  1.178.2.2  christos 		itperiph = scsipi_lookup_periph(chan, target, lun);
   2326  1.178.2.2  christos 		if (itperiph != NULL)
   2327  1.178.2.2  christos 			break;
   2328  1.178.2.2  christos 	}
   2329  1.178.2.2  christos 	if (itperiph != NULL) {
   2330  1.178.2.2  christos 		xm.xm_mode = itperiph->periph_cap;
   2331  1.178.2.2  christos 		/*
   2332  1.178.2.2  christos 		 * Now issue the request to the adapter.
   2333  1.178.2.2  christos 		 */
   2334  1.178.2.2  christos 		scsipi_adapter_request(chan, ADAPTER_REQ_SET_XFER_MODE, &xm);
   2335  1.178.2.2  christos 		/*
   2336  1.178.2.2  christos 		 * If we want this to happen immediately, issue a dummy
   2337  1.178.2.2  christos 		 * command, since most adapters can't really negotiate unless
   2338  1.178.2.2  christos 		 * they're executing a job.
   2339  1.178.2.2  christos 		 */
   2340  1.178.2.2  christos 		if (immed != 0) {
   2341  1.178.2.2  christos 			(void) scsipi_test_unit_ready(itperiph,
   2342  1.178.2.2  christos 			    XS_CTL_DISCOVERY | XS_CTL_IGNORE_ILLEGAL_REQUEST |
   2343  1.178.2.2  christos 			    XS_CTL_IGNORE_NOT_READY |
   2344  1.178.2.2  christos 			    XS_CTL_IGNORE_MEDIA_CHANGE);
   2345  1.178.2.2  christos 		}
   2346  1.178.2.2  christos 	}
   2347  1.178.2.2  christos }
   2348  1.178.2.2  christos 
   2349  1.178.2.2  christos /*
   2350  1.178.2.2  christos  * scsipi_channel_reset:
   2351  1.178.2.2  christos  *
   2352  1.178.2.2  christos  *	handle scsi bus reset
   2353  1.178.2.2  christos  * called with channel lock held
   2354  1.178.2.2  christos  */
   2355  1.178.2.2  christos static void
   2356  1.178.2.2  christos scsipi_async_event_channel_reset(struct scsipi_channel *chan)
   2357  1.178.2.2  christos {
   2358  1.178.2.2  christos 	struct scsipi_xfer *xs, *xs_next;
   2359  1.178.2.2  christos 	struct scsipi_periph *periph;
   2360  1.178.2.2  christos 	int target, lun;
   2361  1.178.2.2  christos 
   2362  1.178.2.2  christos 	/*
   2363  1.178.2.2  christos 	 * Channel has been reset. Also mark as reset pending REQUEST_SENSE
   2364  1.178.2.2  christos 	 * commands; as the sense is not available any more.
   2365  1.178.2.2  christos 	 * can't call scsipi_done() from here, as the command has not been
   2366  1.178.2.2  christos 	 * sent to the adapter yet (this would corrupt accounting).
   2367  1.178.2.2  christos 	 */
   2368  1.178.2.2  christos 
   2369  1.178.2.2  christos 	for (xs = TAILQ_FIRST(&chan->chan_queue); xs != NULL; xs = xs_next) {
   2370  1.178.2.2  christos 		xs_next = TAILQ_NEXT(xs, channel_q);
   2371  1.178.2.2  christos 		if (xs->xs_control & XS_CTL_REQSENSE) {
   2372  1.178.2.2  christos 			TAILQ_REMOVE(&chan->chan_queue, xs, channel_q);
   2373  1.178.2.2  christos 			xs->error = XS_RESET;
   2374  1.178.2.2  christos 			if ((xs->xs_control & XS_CTL_ASYNC) != 0)
   2375  1.178.2.2  christos 				TAILQ_INSERT_TAIL(&chan->chan_complete, xs,
   2376  1.178.2.2  christos 				    channel_q);
   2377  1.178.2.2  christos 		}
   2378  1.178.2.2  christos 	}
   2379  1.178.2.2  christos 	cv_broadcast(chan_cv_complete(chan));
   2380  1.178.2.2  christos 	/* Catch xs with pending sense which may not have a REQSENSE xs yet */
   2381  1.178.2.2  christos 	for (target = 0; target < chan->chan_ntargets; target++) {
   2382  1.178.2.2  christos 		if (target == chan->chan_id)
   2383  1.178.2.2  christos 			continue;
   2384  1.178.2.2  christos 		for (lun = 0; lun <  chan->chan_nluns; lun++) {
   2385  1.178.2.2  christos 			periph = scsipi_lookup_periph_locked(chan, target, lun);
   2386  1.178.2.2  christos 			if (periph) {
   2387  1.178.2.2  christos 				xs = periph->periph_xscheck;
   2388  1.178.2.2  christos 				if (xs)
   2389  1.178.2.2  christos 					xs->error = XS_RESET;
   2390  1.178.2.2  christos 			}
   2391  1.178.2.2  christos 		}
   2392  1.178.2.2  christos 	}
   2393  1.178.2.2  christos }
   2394  1.178.2.2  christos 
   2395  1.178.2.2  christos /*
   2396  1.178.2.2  christos  * scsipi_target_detach:
   2397  1.178.2.2  christos  *
   2398  1.178.2.2  christos  *	detach all periph associated with a I_T
   2399  1.178.2.2  christos  * 	must be called from valid thread context
   2400  1.178.2.2  christos  */
   2401  1.178.2.2  christos int
   2402  1.178.2.2  christos scsipi_target_detach(struct scsipi_channel *chan, int target, int lun,
   2403  1.178.2.2  christos     int flags)
   2404  1.178.2.2  christos {
   2405  1.178.2.2  christos 	struct scsipi_periph *periph;
   2406  1.178.2.2  christos 	device_t tdev;
   2407  1.178.2.2  christos 	int ctarget, mintarget, maxtarget;
   2408  1.178.2.2  christos 	int clun, minlun, maxlun;
   2409  1.178.2.2  christos 	int error = 0;
   2410  1.178.2.2  christos 
   2411  1.178.2.2  christos 	if (target == -1) {
   2412  1.178.2.2  christos 		mintarget = 0;
   2413  1.178.2.2  christos 		maxtarget = chan->chan_ntargets;
   2414  1.178.2.2  christos 	} else {
   2415  1.178.2.2  christos 		if (target == chan->chan_id)
   2416  1.178.2.2  christos 			return EINVAL;
   2417  1.178.2.2  christos 		if (target < 0 || target >= chan->chan_ntargets)
   2418  1.178.2.2  christos 			return EINVAL;
   2419  1.178.2.2  christos 		mintarget = target;
   2420  1.178.2.2  christos 		maxtarget = target + 1;
   2421  1.178.2.2  christos 	}
   2422  1.178.2.2  christos 
   2423  1.178.2.2  christos 	if (lun == -1) {
   2424  1.178.2.2  christos 		minlun = 0;
   2425  1.178.2.2  christos 		maxlun = chan->chan_nluns;
   2426  1.178.2.2  christos 	} else {
   2427  1.178.2.2  christos 		if (lun < 0 || lun >= chan->chan_nluns)
   2428  1.178.2.2  christos 			return EINVAL;
   2429  1.178.2.2  christos 		minlun = lun;
   2430  1.178.2.2  christos 		maxlun = lun + 1;
   2431  1.178.2.2  christos 	}
   2432  1.178.2.2  christos 
   2433  1.178.2.2  christos 	/* for config_detach */
   2434  1.178.2.2  christos 	KERNEL_LOCK(1, curlwp);
   2435  1.178.2.2  christos 
   2436  1.178.2.2  christos 	mutex_enter(chan_mtx(chan));
   2437  1.178.2.2  christos 	for (ctarget = mintarget; ctarget < maxtarget; ctarget++) {
   2438  1.178.2.2  christos 		if (ctarget == chan->chan_id)
   2439  1.178.2.2  christos 			continue;
   2440  1.178.2.2  christos 
   2441  1.178.2.2  christos 		for (clun = minlun; clun < maxlun; clun++) {
   2442  1.178.2.2  christos 			periph = scsipi_lookup_periph_locked(chan, ctarget, clun);
   2443  1.178.2.2  christos 			if (periph == NULL)
   2444  1.178.2.2  christos 				continue;
   2445  1.178.2.2  christos 			tdev = periph->periph_dev;
   2446  1.178.2.2  christos 			mutex_exit(chan_mtx(chan));
   2447  1.178.2.2  christos 			error = config_detach(tdev, flags);
   2448  1.178.2.2  christos 			if (error)
   2449  1.178.2.2  christos 				goto out;
   2450  1.178.2.2  christos 			mutex_enter(chan_mtx(chan));
   2451  1.178.2.2  christos 			KASSERT(scsipi_lookup_periph_locked(chan, ctarget, clun) == NULL);
   2452  1.178.2.2  christos 		}
   2453  1.178.2.2  christos 	}
   2454  1.178.2.2  christos 	mutex_exit(chan_mtx(chan));
   2455  1.178.2.2  christos 
   2456  1.178.2.2  christos out:
   2457  1.178.2.2  christos 	KERNEL_UNLOCK_ONE(curlwp);
   2458  1.178.2.2  christos 
   2459  1.178.2.2  christos 	return error;
   2460  1.178.2.2  christos }
   2461  1.178.2.2  christos 
   2462  1.178.2.2  christos /*
   2463  1.178.2.2  christos  * scsipi_adapter_addref:
   2464  1.178.2.2  christos  *
   2465  1.178.2.2  christos  *	Add a reference to the adapter pointed to by the provided
   2466  1.178.2.2  christos  *	link, enabling the adapter if necessary.
   2467  1.178.2.2  christos  */
   2468  1.178.2.2  christos int
   2469  1.178.2.2  christos scsipi_adapter_addref(struct scsipi_adapter *adapt)
   2470  1.178.2.2  christos {
   2471  1.178.2.2  christos 	int error = 0;
   2472  1.178.2.2  christos 
   2473  1.178.2.2  christos 	if (atomic_inc_uint_nv(&adapt->adapt_refcnt) == 1
   2474  1.178.2.2  christos 	    && adapt->adapt_enable != NULL) {
   2475  1.178.2.2  christos 		scsipi_adapter_lock(adapt);
   2476  1.178.2.2  christos 		error = scsipi_adapter_enable(adapt, 1);
   2477  1.178.2.2  christos 		scsipi_adapter_unlock(adapt);
   2478  1.178.2.2  christos 		if (error)
   2479  1.178.2.2  christos 			atomic_dec_uint(&adapt->adapt_refcnt);
   2480  1.178.2.2  christos 	}
   2481  1.178.2.2  christos 	return error;
   2482  1.178.2.2  christos }
   2483  1.178.2.2  christos 
   2484  1.178.2.2  christos /*
   2485  1.178.2.2  christos  * scsipi_adapter_delref:
   2486  1.178.2.2  christos  *
   2487  1.178.2.2  christos  *	Delete a reference to the adapter pointed to by the provided
   2488  1.178.2.2  christos  *	link, disabling the adapter if possible.
   2489  1.178.2.2  christos  */
   2490  1.178.2.2  christos void
   2491  1.178.2.2  christos scsipi_adapter_delref(struct scsipi_adapter *adapt)
   2492  1.178.2.2  christos {
   2493  1.178.2.2  christos 
   2494  1.178.2.2  christos 	if (atomic_dec_uint_nv(&adapt->adapt_refcnt) == 0
   2495  1.178.2.2  christos 	    && adapt->adapt_enable != NULL) {
   2496  1.178.2.2  christos 		scsipi_adapter_lock(adapt);
   2497  1.178.2.2  christos 		(void) scsipi_adapter_enable(adapt, 0);
   2498  1.178.2.2  christos 		scsipi_adapter_unlock(adapt);
   2499  1.178.2.2  christos 	}
   2500  1.178.2.2  christos }
   2501  1.178.2.2  christos 
   2502  1.178.2.2  christos static struct scsipi_syncparam {
   2503  1.178.2.2  christos 	int	ss_factor;
   2504  1.178.2.2  christos 	int	ss_period;	/* ns * 100 */
   2505  1.178.2.2  christos } scsipi_syncparams[] = {
   2506  1.178.2.2  christos 	{ 0x08,		 625 },	/* FAST-160 (Ultra320) */
   2507  1.178.2.2  christos 	{ 0x09,		1250 },	/* FAST-80 (Ultra160) */
   2508  1.178.2.2  christos 	{ 0x0a,		2500 },	/* FAST-40 40MHz (Ultra2) */
   2509  1.178.2.2  christos 	{ 0x0b,		3030 },	/* FAST-40 33MHz (Ultra2) */
   2510  1.178.2.2  christos 	{ 0x0c,		5000 },	/* FAST-20 (Ultra) */
   2511  1.178.2.2  christos };
   2512  1.178.2.2  christos static const int scsipi_nsyncparams =
   2513  1.178.2.2  christos     sizeof(scsipi_syncparams) / sizeof(scsipi_syncparams[0]);
   2514  1.178.2.2  christos 
   2515  1.178.2.2  christos int
   2516  1.178.2.2  christos scsipi_sync_period_to_factor(int period /* ns * 100 */)
   2517  1.178.2.2  christos {
   2518  1.178.2.2  christos 	int i;
   2519  1.178.2.2  christos 
   2520  1.178.2.2  christos 	for (i = 0; i < scsipi_nsyncparams; i++) {
   2521  1.178.2.2  christos 		if (period <= scsipi_syncparams[i].ss_period)
   2522  1.178.2.2  christos 			return scsipi_syncparams[i].ss_factor;
   2523  1.178.2.2  christos 	}
   2524  1.178.2.2  christos 
   2525  1.178.2.2  christos 	return (period / 100) / 4;
   2526  1.178.2.2  christos }
   2527  1.178.2.2  christos 
   2528  1.178.2.2  christos int
   2529  1.178.2.2  christos scsipi_sync_factor_to_period(int factor)
   2530  1.178.2.2  christos {
   2531  1.178.2.2  christos 	int i;
   2532  1.178.2.2  christos 
   2533  1.178.2.2  christos 	for (i = 0; i < scsipi_nsyncparams; i++) {
   2534  1.178.2.2  christos 		if (factor == scsipi_syncparams[i].ss_factor)
   2535  1.178.2.2  christos 			return scsipi_syncparams[i].ss_period;
   2536  1.178.2.2  christos 	}
   2537  1.178.2.2  christos 
   2538  1.178.2.2  christos 	return (factor * 4) * 100;
   2539  1.178.2.2  christos }
   2540  1.178.2.2  christos 
   2541  1.178.2.2  christos int
   2542  1.178.2.2  christos scsipi_sync_factor_to_freq(int factor)
   2543  1.178.2.2  christos {
   2544  1.178.2.2  christos 	int i;
   2545  1.178.2.2  christos 
   2546  1.178.2.2  christos 	for (i = 0; i < scsipi_nsyncparams; i++) {
   2547  1.178.2.2  christos 		if (factor == scsipi_syncparams[i].ss_factor)
   2548  1.178.2.2  christos 			return 100000000 / scsipi_syncparams[i].ss_period;
   2549  1.178.2.2  christos 	}
   2550  1.178.2.2  christos 
   2551  1.178.2.2  christos 	return 10000000 / ((factor * 4) * 10);
   2552  1.178.2.2  christos }
   2553  1.178.2.2  christos 
   2554  1.178.2.2  christos static inline void
   2555  1.178.2.2  christos scsipi_adapter_lock(struct scsipi_adapter *adapt)
   2556  1.178.2.2  christos {
   2557  1.178.2.2  christos 
   2558  1.178.2.2  christos 	if ((adapt->adapt_flags & SCSIPI_ADAPT_MPSAFE) == 0)
   2559  1.178.2.2  christos 		KERNEL_LOCK(1, NULL);
   2560  1.178.2.2  christos }
   2561  1.178.2.2  christos 
   2562  1.178.2.2  christos static inline void
   2563  1.178.2.2  christos scsipi_adapter_unlock(struct scsipi_adapter *adapt)
   2564  1.178.2.2  christos {
   2565  1.178.2.2  christos 
   2566  1.178.2.2  christos 	if ((adapt->adapt_flags & SCSIPI_ADAPT_MPSAFE) == 0)
   2567  1.178.2.2  christos 		KERNEL_UNLOCK_ONE(NULL);
   2568  1.178.2.2  christos }
   2569  1.178.2.2  christos 
   2570  1.178.2.2  christos void
   2571  1.178.2.2  christos scsipi_adapter_minphys(struct scsipi_channel *chan, struct buf *bp)
   2572  1.178.2.2  christos {
   2573  1.178.2.2  christos 	struct scsipi_adapter *adapt = chan->chan_adapter;
   2574  1.178.2.2  christos 
   2575  1.178.2.2  christos 	scsipi_adapter_lock(adapt);
   2576  1.178.2.2  christos 	(adapt->adapt_minphys)(bp);
   2577  1.178.2.2  christos 	scsipi_adapter_unlock(chan->chan_adapter);
   2578  1.178.2.2  christos }
   2579  1.178.2.2  christos 
   2580  1.178.2.2  christos void
   2581  1.178.2.2  christos scsipi_adapter_request(struct scsipi_channel *chan,
   2582  1.178.2.2  christos 	scsipi_adapter_req_t req, void *arg)
   2583  1.178.2.2  christos 
   2584  1.178.2.2  christos {
   2585  1.178.2.2  christos 	struct scsipi_adapter *adapt = chan->chan_adapter;
   2586  1.178.2.2  christos 
   2587  1.178.2.2  christos 	scsipi_adapter_lock(adapt);
   2588  1.178.2.2  christos 	(adapt->adapt_request)(chan, req, arg);
   2589  1.178.2.2  christos 	scsipi_adapter_unlock(adapt);
   2590  1.178.2.2  christos }
   2591  1.178.2.2  christos 
   2592  1.178.2.2  christos int
   2593  1.178.2.2  christos scsipi_adapter_ioctl(struct scsipi_channel *chan, u_long cmd,
   2594  1.178.2.2  christos 	void *data, int flag, struct proc *p)
   2595  1.178.2.2  christos {
   2596  1.178.2.2  christos 	struct scsipi_adapter *adapt = chan->chan_adapter;
   2597  1.178.2.2  christos 	int error;
   2598  1.178.2.2  christos 
   2599  1.178.2.2  christos 	if (adapt->adapt_ioctl == NULL)
   2600  1.178.2.2  christos 		return ENOTTY;
   2601  1.178.2.2  christos 
   2602  1.178.2.2  christos 	scsipi_adapter_lock(adapt);
   2603  1.178.2.2  christos 	error = (adapt->adapt_ioctl)(chan, cmd, data, flag, p);
   2604  1.178.2.2  christos 	scsipi_adapter_unlock(adapt);
   2605  1.178.2.2  christos 	return error;
   2606  1.178.2.2  christos }
   2607  1.178.2.2  christos 
   2608  1.178.2.2  christos int
   2609  1.178.2.2  christos scsipi_adapter_enable(struct scsipi_adapter *adapt, int enable)
   2610  1.178.2.2  christos {
   2611  1.178.2.2  christos 	int error;
   2612  1.178.2.2  christos 
   2613  1.178.2.2  christos 	scsipi_adapter_lock(adapt);
   2614  1.178.2.2  christos 	error = (adapt->adapt_enable)(adapt->adapt_dev, enable);
   2615  1.178.2.2  christos 	scsipi_adapter_unlock(adapt);
   2616  1.178.2.2  christos 	return error;
   2617  1.178.2.2  christos }
   2618  1.178.2.2  christos 
   2619  1.178.2.2  christos #ifdef SCSIPI_DEBUG
   2620  1.178.2.2  christos /*
   2621  1.178.2.2  christos  * Given a scsipi_xfer, dump the request, in all its glory
   2622  1.178.2.2  christos  */
   2623  1.178.2.2  christos void
   2624  1.178.2.2  christos show_scsipi_xs(struct scsipi_xfer *xs)
   2625  1.178.2.2  christos {
   2626  1.178.2.2  christos 
   2627  1.178.2.2  christos 	printf("xs(%p): ", xs);
   2628  1.178.2.2  christos 	printf("xs_control(0x%08x)", xs->xs_control);
   2629  1.178.2.2  christos 	printf("xs_status(0x%08x)", xs->xs_status);
   2630  1.178.2.2  christos 	printf("periph(%p)", xs->xs_periph);
   2631  1.178.2.2  christos 	printf("retr(0x%x)", xs->xs_retries);
   2632  1.178.2.2  christos 	printf("timo(0x%x)", xs->timeout);
   2633  1.178.2.2  christos 	printf("cmd(%p)", xs->cmd);
   2634  1.178.2.2  christos 	printf("len(0x%x)", xs->cmdlen);
   2635  1.178.2.2  christos 	printf("data(%p)", xs->data);
   2636  1.178.2.2  christos 	printf("len(0x%x)", xs->datalen);
   2637  1.178.2.2  christos 	printf("res(0x%x)", xs->resid);
   2638  1.178.2.2  christos 	printf("err(0x%x)", xs->error);
   2639  1.178.2.2  christos 	printf("bp(%p)", xs->bp);
   2640  1.178.2.2  christos 	show_scsipi_cmd(xs);
   2641  1.178.2.2  christos }
   2642  1.178.2.2  christos 
   2643  1.178.2.2  christos void
   2644  1.178.2.2  christos show_scsipi_cmd(struct scsipi_xfer *xs)
   2645  1.178.2.2  christos {
   2646  1.178.2.2  christos 	u_char *b = (u_char *) xs->cmd;
   2647  1.178.2.2  christos 	int i = 0;
   2648  1.178.2.2  christos 
   2649  1.178.2.2  christos 	scsipi_printaddr(xs->xs_periph);
   2650  1.178.2.2  christos 	printf(" command: ");
   2651  1.178.2.2  christos 
   2652  1.178.2.2  christos 	if ((xs->xs_control & XS_CTL_RESET) == 0) {
   2653  1.178.2.2  christos 		while (i < xs->cmdlen) {
   2654  1.178.2.2  christos 			if (i)
   2655  1.178.2.2  christos 				printf(",");
   2656  1.178.2.2  christos 			printf("0x%x", b[i++]);
   2657  1.178.2.2  christos 		}
   2658  1.178.2.2  christos 		printf("-[%d bytes]\n", xs->datalen);
   2659  1.178.2.2  christos 		if (xs->datalen)
   2660  1.178.2.2  christos 			show_mem(xs->data, min(64, xs->datalen));
   2661  1.178.2.2  christos 	} else
   2662  1.178.2.2  christos 		printf("-RESET-\n");
   2663  1.178.2.2  christos }
   2664  1.178.2.2  christos 
   2665  1.178.2.2  christos void
   2666  1.178.2.2  christos show_mem(u_char *address, int num)
   2667  1.178.2.2  christos {
   2668  1.178.2.2  christos 	int x;
   2669  1.178.2.2  christos 
   2670  1.178.2.2  christos 	printf("------------------------------");
   2671  1.178.2.2  christos 	for (x = 0; x < num; x++) {
   2672  1.178.2.2  christos 		if ((x % 16) == 0)
   2673  1.178.2.2  christos 			printf("\n%03d: ", x);
   2674  1.178.2.2  christos 		printf("%02x ", *address++);
   2675  1.178.2.2  christos 	}
   2676  1.178.2.2  christos 	printf("\n------------------------------\n");
   2677  1.178.2.2  christos }
   2678  1.178.2.2  christos #endif /* SCSIPI_DEBUG */
   2679