Home | History | Annotate | Line # | Download | only in scsipi
ss.c revision 1.84.2.3
      1  1.84.2.2       tls /*	$NetBSD: ss.c,v 1.84.2.3 2017/12/03 11:37:32 jdolecek Exp $	*/
      2       1.1   mycroft 
      3       1.1   mycroft /*
      4       1.1   mycroft  * Copyright (c) 1995 Kenneth Stailey.  All rights reserved.
      5       1.1   mycroft  *   modified for configurable scanner support by Joachim Koenig
      6       1.1   mycroft  *
      7       1.1   mycroft  * Redistribution and use in source and binary forms, with or without
      8       1.1   mycroft  * modification, are permitted provided that the following conditions
      9       1.1   mycroft  * are met:
     10       1.1   mycroft  * 1. Redistributions of source code must retain the above copyright
     11       1.1   mycroft  *    notice, this list of conditions and the following disclaimer.
     12       1.1   mycroft  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1   mycroft  *    notice, this list of conditions and the following disclaimer in the
     14       1.1   mycroft  *    documentation and/or other materials provided with the distribution.
     15       1.1   mycroft  * 3. All advertising materials mentioning features or use of this software
     16       1.1   mycroft  *    must display the following acknowledgement:
     17       1.1   mycroft  *	This product includes software developed by Kenneth Stailey.
     18       1.1   mycroft  * 4. The name of the author may not be used to endorse or promote products
     19       1.1   mycroft  *    derived from this software without specific prior written permission.
     20       1.1   mycroft  *
     21       1.1   mycroft  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22       1.1   mycroft  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23       1.1   mycroft  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24       1.1   mycroft  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25       1.1   mycroft  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26       1.1   mycroft  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27       1.1   mycroft  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28       1.1   mycroft  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29       1.1   mycroft  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30       1.1   mycroft  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31       1.1   mycroft  */
     32      1.37     lukem 
     33      1.37     lukem #include <sys/cdefs.h>
     34  1.84.2.2       tls __KERNEL_RCSID(0, "$NetBSD: ss.c,v 1.84.2.3 2017/12/03 11:37:32 jdolecek Exp $");
     35       1.1   mycroft 
     36       1.1   mycroft #include <sys/param.h>
     37       1.1   mycroft #include <sys/systm.h>
     38       1.1   mycroft #include <sys/fcntl.h>
     39       1.1   mycroft #include <sys/errno.h>
     40       1.1   mycroft #include <sys/ioctl.h>
     41       1.1   mycroft #include <sys/malloc.h>
     42       1.1   mycroft #include <sys/buf.h>
     43      1.57      yamt #include <sys/bufq.h>
     44       1.1   mycroft #include <sys/proc.h>
     45       1.1   mycroft #include <sys/device.h>
     46       1.9  christos #include <sys/conf.h>
     47      1.32  augustss #include <sys/vnode.h>
     48       1.1   mycroft #include <sys/scanio.h>
     49       1.1   mycroft 
     50      1.16    bouyer #include <dev/scsipi/scsi_all.h>
     51      1.16    bouyer #include <dev/scsipi/scsipi_all.h>
     52      1.16    bouyer #include <dev/scsipi/scsi_scanner.h>
     53      1.16    bouyer #include <dev/scsipi/scsiconf.h>
     54      1.16    bouyer #include <dev/scsipi/ssvar.h>
     55       1.1   mycroft 
     56      1.16    bouyer #include <dev/scsipi/ss_mustek.h>
     57       1.1   mycroft 
     58       1.1   mycroft #define SSMODE(z)	( minor(z)       & 0x03)
     59       1.1   mycroft #define SSUNIT(z)	((minor(z) >> 4)       )
     60      1.33  augustss #define SSNMINOR 16
     61       1.1   mycroft 
     62       1.1   mycroft /*
     63       1.1   mycroft  * If the mode is 3 (e.g. minor = 3,7,11,15)
     64       1.1   mycroft  * then the device has been openned to set defaults
     65       1.1   mycroft  * This mode does NOT ALLOW I/O, only ioctls
     66       1.1   mycroft  */
     67       1.1   mycroft #define MODE_REWIND	0
     68       1.1   mycroft #define MODE_NONREWIND	1
     69       1.1   mycroft #define MODE_CONTROL	3
     70       1.1   mycroft 
     71      1.78    cegger static int	ssmatch(device_t, cfdata_t, void *);
     72      1.78    cegger static void	ssattach(device_t, device_t, void *);
     73      1.78    cegger static int	ssdetach(device_t self, int flags);
     74       1.1   mycroft 
     75      1.81   mbalmer CFATTACH_DECL_NEW(
     76      1.81   mbalmer 	ss,
     77      1.81   mbalmer 	sizeof(struct ss_softc),
     78      1.81   mbalmer 	ssmatch,
     79      1.81   mbalmer 	ssattach,
     80      1.81   mbalmer 	ssdetach,
     81      1.81   mbalmer 	NULL
     82      1.81   mbalmer );
     83       1.8   thorpej 
     84      1.19   thorpej extern struct cfdriver ss_cd;
     85       1.1   mycroft 
     86      1.52   thorpej static dev_type_open(ssopen);
     87      1.52   thorpej static dev_type_close(ssclose);
     88      1.52   thorpej static dev_type_read(ssread);
     89      1.52   thorpej static dev_type_ioctl(ssioctl);
     90      1.40   gehenna 
     91      1.40   gehenna const struct cdevsw ss_cdevsw = {
     92  1.84.2.2       tls 	.d_open = ssopen,
     93  1.84.2.2       tls 	.d_close = ssclose,
     94  1.84.2.2       tls 	.d_read = ssread,
     95  1.84.2.2       tls 	.d_write = nowrite,
     96  1.84.2.2       tls 	.d_ioctl = ssioctl,
     97  1.84.2.2       tls 	.d_stop = nostop,
     98  1.84.2.2       tls 	.d_tty = notty,
     99  1.84.2.2       tls 	.d_poll = nopoll,
    100  1.84.2.2       tls 	.d_mmap = nommap,
    101  1.84.2.2       tls 	.d_kqfilter = nokqfilter,
    102  1.84.2.2       tls 	.d_discard = nodiscard,
    103  1.84.2.3  jdolecek 	.d_flag = D_OTHER | D_MPSAFE
    104      1.40   gehenna };
    105      1.40   gehenna 
    106      1.52   thorpej static void	ssstrategy(struct buf *);
    107      1.52   thorpej static void	ssstart(struct scsipi_periph *);
    108      1.54   mycroft static void	ssdone(struct scsipi_xfer *, int);
    109      1.52   thorpej static void	ssminphys(struct buf *);
    110       1.1   mycroft 
    111      1.52   thorpej static const struct scsipi_periphsw ss_switch = {
    112       1.1   mycroft 	NULL,
    113       1.1   mycroft 	ssstart,
    114       1.1   mycroft 	NULL,
    115      1.54   mycroft 	ssdone,
    116       1.1   mycroft };
    117       1.1   mycroft 
    118      1.52   thorpej static const struct scsipi_inquiry_pattern ss_patterns[] = {
    119       1.1   mycroft 	{T_SCANNER, T_FIXED,
    120       1.1   mycroft 	 "",         "",                 ""},
    121       1.1   mycroft 	{T_SCANNER, T_REMOV,
    122       1.1   mycroft 	 "",         "",                 ""},
    123       1.1   mycroft 	{T_PROCESSOR, T_FIXED,
    124      1.41       chs 	 "HP      ", "C1130A          ", ""},
    125      1.41       chs 	{T_PROCESSOR, T_FIXED,
    126       1.1   mycroft 	 "HP      ", "C1750A          ", ""},
    127       1.1   mycroft 	{T_PROCESSOR, T_FIXED,
    128       1.1   mycroft 	 "HP      ", "C2500A          ", ""},
    129      1.14   thorpej 	{T_PROCESSOR, T_FIXED,
    130      1.41       chs 	 "HP      ", "C2520A          ", ""},
    131      1.18  augustss 	{T_PROCESSOR, T_FIXED,
    132      1.18  augustss 	 "HP      ", "C5110A          ", ""},
    133      1.31      phil 	{T_PROCESSOR, T_FIXED,
    134      1.31      phil 	 "HP      ", "C7670A          ", ""},
    135      1.41       chs 	{T_PROCESSOR, T_FIXED,
    136      1.41       chs 	 "HP      ", "", ""},
    137       1.1   mycroft };
    138       1.1   mycroft 
    139      1.52   thorpej static int
    140      1.81   mbalmer ssmatch(device_t parent, cfdata_t match, void *aux)
    141       1.1   mycroft {
    142      1.16    bouyer 	struct scsipibus_attach_args *sa = aux;
    143       1.1   mycroft 	int priority;
    144       1.1   mycroft 
    145      1.16    bouyer 	(void)scsipi_inqmatch(&sa->sa_inqbuf,
    146      1.61  christos 	    ss_patterns, sizeof(ss_patterns) / sizeof(ss_patterns[0]),
    147       1.1   mycroft 	    sizeof(ss_patterns[0]), &priority);
    148      1.81   mbalmer 	return priority;
    149       1.1   mycroft }
    150       1.1   mycroft 
    151       1.1   mycroft /*
    152       1.1   mycroft  * The routine called by the low level scsi routine when it discovers
    153       1.1   mycroft  * A device suitable for this driver
    154       1.1   mycroft  * If it is a know special, call special attach routine to install
    155       1.1   mycroft  * special handlers into the ss_softc structure
    156       1.1   mycroft  */
    157      1.52   thorpej static void
    158      1.78    cegger ssattach(device_t parent, device_t self, void *aux)
    159       1.1   mycroft {
    160      1.66   thorpej 	struct ss_softc *ss = device_private(self);
    161      1.16    bouyer 	struct scsipibus_attach_args *sa = aux;
    162      1.34    bouyer 	struct scsipi_periph *periph = sa->sa_periph;
    163       1.1   mycroft 
    164      1.34    bouyer 	SC_DEBUG(periph, SCSIPI_DB2, ("ssattach: "));
    165      1.81   mbalmer 	ss->sc_dev = self;
    166       1.1   mycroft 
    167      1.20        pk 	ss->flags |= SSF_AUTOCONF;
    168      1.20        pk 
    169      1.81   mbalmer 	/* Store information needed to contact our base driver */
    170      1.34    bouyer 	ss->sc_periph = periph;
    171      1.81   mbalmer 	periph->periph_dev = ss->sc_dev;
    172      1.34    bouyer 	periph->periph_switch = &ss_switch;
    173      1.28       abs 
    174      1.28       abs 	printf("\n");
    175       1.1   mycroft 
    176      1.81   mbalmer 	/* Set up the buf queue for this device */
    177      1.62      yamt 	bufq_alloc(&ss->buf_queue, "fcfs", 0);
    178      1.39   hannken 
    179      1.71        ad 	callout_init(&ss->sc_callout, 0);
    180      1.53    bouyer 
    181      1.39   hannken 	/*
    182       1.1   mycroft 	 * look for non-standard scanners with help of the quirk table
    183       1.1   mycroft 	 * and install functions for special handling
    184       1.1   mycroft 	 */
    185      1.35    bouyer 	SC_DEBUG(periph, SCSIPI_DB2, ("ssattach:\n"));
    186      1.32  augustss 	if (memcmp(sa->sa_inqbuf.vendor, "MUSTEK", 6) == 0)
    187       1.1   mycroft 		mustek_attach(ss, sa);
    188      1.32  augustss 	if (memcmp(sa->sa_inqbuf.vendor, "HP      ", 8) == 0 &&
    189      1.32  augustss 	    memcmp(sa->sa_inqbuf.product, "ScanJet 5300C", 13) != 0)
    190       1.1   mycroft 		scanjet_attach(ss, sa);
    191      1.82   mbalmer 
    192       1.1   mycroft 	if (ss->special == NULL) {
    193       1.1   mycroft 		/* XXX add code to restart a SCSI2 scanner, if any */
    194       1.1   mycroft 	}
    195      1.20        pk 	ss->flags &= ~SSF_AUTOCONF;
    196       1.1   mycroft }
    197       1.1   mycroft 
    198      1.52   thorpej static int
    199      1.78    cegger ssdetach(device_t self, int flags)
    200      1.32  augustss {
    201      1.66   thorpej 	struct ss_softc *ss = device_private(self);
    202  1.84.2.3  jdolecek 	struct scsipi_periph *periph = ss->sc_periph;
    203  1.84.2.3  jdolecek 	struct scsipi_channel *chan = periph->periph_channel;
    204  1.84.2.3  jdolecek 	int cmaj, mn;
    205      1.32  augustss 
    206      1.32  augustss 	/* locate the major number */
    207      1.40   gehenna 	cmaj = cdevsw_lookup_major(&ss_cdevsw);
    208      1.32  augustss 
    209      1.53    bouyer 	/* kill any pending restart */
    210  1.84.2.3  jdolecek 	callout_halt(&ss->sc_callout, NULL);
    211      1.53    bouyer 
    212  1.84.2.3  jdolecek 	mutex_enter(chan_mtx(chan));
    213      1.32  augustss 
    214      1.32  augustss 	/* Kill off any queued buffers. */
    215      1.62      yamt 	bufq_drain(ss->buf_queue);
    216      1.32  augustss 
    217      1.32  augustss 	/* Kill off any pending commands. */
    218  1.84.2.3  jdolecek 	scsipi_kill_pending(periph);
    219      1.32  augustss 
    220  1.84.2.3  jdolecek 	mutex_exit(chan_mtx(chan));
    221  1.84.2.3  jdolecek 
    222  1.84.2.3  jdolecek 	bufq_free(ss->buf_queue);
    223      1.32  augustss 
    224      1.32  augustss 	/* Nuke the vnodes for any open instances */
    225      1.65   thorpej 	mn = SSUNIT(device_unit(self));
    226      1.33  augustss 	vdevgone(cmaj, mn, mn+SSNMINOR-1, VCHR);
    227      1.32  augustss 
    228      1.81   mbalmer 	return 0;
    229      1.32  augustss }
    230      1.32  augustss 
    231      1.84   mbalmer /*  open the device. */
    232      1.52   thorpej static int
    233      1.69  christos ssopen(dev_t dev, int flag, int mode, struct lwp *l)
    234       1.1   mycroft {
    235       1.1   mycroft 	int unit;
    236      1.59   reinoud 	u_int ssmode;
    237      1.23   thorpej 	int error;
    238       1.1   mycroft 	struct ss_softc *ss;
    239      1.34    bouyer 	struct scsipi_periph *periph;
    240      1.34    bouyer 	struct scsipi_adapter *adapt;
    241       1.1   mycroft 
    242       1.1   mycroft 	unit = SSUNIT(dev);
    243      1.74   tsutsui 	ss = device_lookup_private(&ss_cd, unit);
    244      1.74   tsutsui 	if (ss == NULL)
    245      1.81   mbalmer 		return ENXIO;
    246       1.1   mycroft 
    247      1.81   mbalmer 	if (!device_is_active(ss->sc_dev))
    248      1.81   mbalmer 		return ENODEV;
    249      1.32  augustss 
    250       1.5   mycroft 	ssmode = SSMODE(dev);
    251       1.1   mycroft 
    252      1.34    bouyer 	periph = ss->sc_periph;
    253      1.34    bouyer 	adapt = periph->periph_channel->chan_adapter;
    254      1.34    bouyer 
    255      1.81   mbalmer 	SC_DEBUG(periph, SCSIPI_DB1,
    256      1.81   mbalmer 	    ("open: dev=0x%"PRIx64" (unit %d (of %d))\n", dev, unit,
    257      1.81   mbalmer 	    ss_cd.cd_ndevs));
    258       1.1   mycroft 
    259      1.34    bouyer 	if (periph->periph_flags & PERIPH_OPEN) {
    260      1.81   mbalmer 		aprint_error_dev(ss->sc_dev, "already open\n");
    261      1.81   mbalmer 		return EBUSY;
    262       1.1   mycroft 	}
    263       1.1   mycroft 
    264      1.34    bouyer 	if ((error = scsipi_adapter_addref(adapt)) != 0)
    265      1.81   mbalmer 		return error;
    266      1.23   thorpej 
    267       1.1   mycroft 	/*
    268       1.1   mycroft 	 * Catch any unit attention errors.
    269       1.1   mycroft 	 *
    270      1.26   thorpej 	 * XS_CTL_IGNORE_MEDIA_CHANGE: when you have an ADF, some scanners
    271       1.1   mycroft 	 * consider paper to be a changeable media
    272       1.1   mycroft 	 *
    273       1.1   mycroft 	 */
    274      1.34    bouyer 	error = scsipi_test_unit_ready(periph,
    275      1.26   thorpej 	    XS_CTL_IGNORE_MEDIA_CHANGE | XS_CTL_IGNORE_ILLEGAL_REQUEST |
    276      1.26   thorpej 	    (ssmode == MODE_CONTROL ? XS_CTL_IGNORE_NOT_READY : 0));
    277       1.1   mycroft 	if (error)
    278       1.1   mycroft 		goto bad;
    279       1.1   mycroft 
    280      1.34    bouyer 	periph->periph_flags |= PERIPH_OPEN;	/* unit attn now errors */
    281       1.1   mycroft 
    282       1.1   mycroft 	/*
    283       1.1   mycroft 	 * If the mode is 3 (e.g. minor = 3,7,11,15)
    284       1.1   mycroft 	 * then the device has been opened to set defaults
    285       1.1   mycroft 	 * This mode does NOT ALLOW I/O, only ioctls
    286       1.1   mycroft 	 */
    287       1.5   mycroft 	if (ssmode == MODE_CONTROL)
    288      1.81   mbalmer 		return 0;
    289       1.1   mycroft 
    290      1.34    bouyer 	SC_DEBUG(periph, SCSIPI_DB2, ("open complete\n"));
    291      1.81   mbalmer 	return 0;
    292       1.1   mycroft 
    293       1.1   mycroft bad:
    294      1.34    bouyer 	scsipi_adapter_delref(adapt);
    295      1.34    bouyer 	periph->periph_flags &= ~PERIPH_OPEN;
    296      1.81   mbalmer 	return error;
    297       1.1   mycroft }
    298       1.1   mycroft 
    299       1.1   mycroft /*
    300       1.1   mycroft  * close the device.. only called if we are the LAST
    301       1.1   mycroft  * occurence of an open device
    302       1.1   mycroft  */
    303      1.52   thorpej static int
    304      1.69  christos ssclose(dev_t dev, int flag, int mode, struct lwp *l)
    305       1.1   mycroft {
    306      1.74   tsutsui 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(dev));
    307      1.34    bouyer 	struct scsipi_periph *periph = ss->sc_periph;
    308      1.34    bouyer 	struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
    309       1.1   mycroft 	int error;
    310       1.1   mycroft 
    311      1.34    bouyer 	SC_DEBUG(ss->sc_periph, SCSIPI_DB1, ("closing\n"));
    312       1.1   mycroft 
    313       1.1   mycroft 	if (SSMODE(dev) == MODE_REWIND) {
    314      1.21  explorer 		if (ss->special && ss->special->rewind_scanner) {
    315       1.1   mycroft 			/* call special handler to rewind/abort scan */
    316       1.1   mycroft 			error = (ss->special->rewind_scanner)(ss);
    317       1.1   mycroft 			if (error)
    318      1.81   mbalmer 				return error;
    319      1.82   mbalmer 		} else {
    320       1.1   mycroft 			/* XXX add code to restart a SCSI2 scanner, if any */
    321       1.1   mycroft 		}
    322       1.4   mycroft 		ss->sio.scan_window_size = 0;
    323       1.1   mycroft 		ss->flags &= ~SSF_TRIGGERED;
    324       1.1   mycroft 	}
    325      1.24   thorpej 
    326      1.34    bouyer 	scsipi_wait_drain(periph);
    327      1.23   thorpej 
    328      1.34    bouyer 	scsipi_adapter_delref(adapt);
    329      1.34    bouyer 	periph->periph_flags &= ~PERIPH_OPEN;
    330       1.1   mycroft 
    331      1.81   mbalmer 	return 0;
    332       1.1   mycroft }
    333       1.1   mycroft 
    334       1.1   mycroft /*
    335      1.84   mbalmer  * trim the size of the transfer if needed, called by physio
    336      1.84   mbalmer  * basically the smaller of our min and the scsi driver's minphys
    337       1.1   mycroft  */
    338      1.52   thorpej static void
    339      1.32  augustss ssminphys(struct buf *bp)
    340       1.1   mycroft {
    341      1.74   tsutsui 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(bp->b_dev));
    342      1.34    bouyer 	struct scsipi_periph *periph = ss->sc_periph;
    343  1.84.2.1       tls 	long xmax;
    344       1.1   mycroft 
    345  1.84.2.1       tls 	/* Impose any restrictions inherited down the device tree */
    346  1.84.2.1       tls 	xmax = ss->sc_dev->dv_maxphys;
    347  1.84.2.1       tls 	if (bp->b_bcount > xmax)
    348  1.84.2.1       tls 		bp->b_bcount = xmax;
    349  1.84.2.1       tls 
    350  1.84.2.1       tls 	/* Adapters could enforce their own limits on the
    351  1.84.2.1       tls 	   attached scsibuses via the device tree, but existing
    352  1.84.2.1       tls 	   drivers mostly do it in their own minphys routines. */
    353      1.51   thorpej 	scsipi_adapter_minphys(periph->periph_channel, bp);
    354       1.1   mycroft 
    355       1.1   mycroft 	/*
    356       1.1   mycroft 	 * trim the transfer further for special devices this is
    357       1.1   mycroft 	 * because some scanners only read multiples of a line at a
    358       1.1   mycroft 	 * time, also some cannot disconnect, so the read must be
    359       1.1   mycroft 	 * short enough to happen quickly
    360       1.1   mycroft 	 */
    361      1.21  explorer 	if (ss->special && ss->special->minphys)
    362       1.1   mycroft 		(ss->special->minphys)(ss, bp);
    363       1.1   mycroft }
    364       1.1   mycroft 
    365       1.1   mycroft /*
    366       1.1   mycroft  * Do a read on a device for a user process.
    367       1.1   mycroft  * Prime scanner at start of read, check uio values, call ssstrategy
    368       1.1   mycroft  * via physio for the actual transfer.
    369       1.1   mycroft  */
    370      1.52   thorpej static int
    371      1.69  christos ssread(dev_t dev, struct uio *uio, int flag)
    372       1.1   mycroft {
    373      1.74   tsutsui 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(dev));
    374       1.1   mycroft 	int error;
    375       1.1   mycroft 
    376      1.81   mbalmer 	if (!device_is_active(ss->sc_dev))
    377      1.81   mbalmer 		return ENODEV;
    378      1.32  augustss 
    379       1.1   mycroft 	/* if the scanner has not yet been started, do it now */
    380       1.1   mycroft 	if (!(ss->flags & SSF_TRIGGERED)) {
    381      1.21  explorer 		if (ss->special && ss->special->trigger_scanner) {
    382       1.1   mycroft 			error = (ss->special->trigger_scanner)(ss);
    383       1.1   mycroft 			if (error)
    384       1.1   mycroft 				return (error);
    385       1.1   mycroft 		}
    386       1.1   mycroft 		ss->flags |= SSF_TRIGGERED;
    387       1.1   mycroft 	}
    388       1.1   mycroft 
    389      1.81   mbalmer 	return physio(ssstrategy, NULL, dev, B_READ, ssminphys, uio);
    390       1.1   mycroft }
    391       1.1   mycroft 
    392       1.1   mycroft /*
    393       1.1   mycroft  * Actually translate the requested transfer into one the physical
    394       1.1   mycroft  * driver can understand The transfer is described by a buf and will
    395       1.1   mycroft  * include only one physical transfer.
    396       1.1   mycroft  */
    397      1.52   thorpej static void
    398      1.52   thorpej ssstrategy(struct buf *bp)
    399       1.1   mycroft {
    400      1.74   tsutsui 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(bp->b_dev));
    401      1.34    bouyer 	struct scsipi_periph *periph = ss->sc_periph;
    402  1.84.2.3  jdolecek 	struct scsipi_channel *chan = periph->periph_channel;
    403       1.1   mycroft 
    404      1.34    bouyer 	SC_DEBUG(ss->sc_periph, SCSIPI_DB1,
    405      1.81   mbalmer 	    ("ssstrategy %d bytes @ blk %" PRId64 "\n", bp->b_bcount,
    406      1.81   mbalmer 	    bp->b_blkno));
    407      1.25    bouyer 
    408      1.81   mbalmer 	/* If the device has been made invalid, error out */
    409      1.81   mbalmer 	if (!device_is_active(ss->sc_dev)) {
    410      1.34    bouyer 		if (periph->periph_flags & PERIPH_OPEN)
    411      1.32  augustss 			bp->b_error = EIO;
    412      1.32  augustss 		else
    413      1.32  augustss 			bp->b_error = ENODEV;
    414      1.32  augustss 		goto done;
    415      1.32  augustss 	}
    416      1.32  augustss 
    417      1.25    bouyer 	/* If negative offset, error */
    418      1.25    bouyer 	if (bp->b_blkno < 0) {
    419      1.25    bouyer 		bp->b_error = EINVAL;
    420      1.25    bouyer 		goto done;
    421      1.25    bouyer 	}
    422       1.6   mycroft 
    423       1.6   mycroft 	if (bp->b_bcount > ss->sio.scan_window_size)
    424       1.6   mycroft 		bp->b_bcount = ss->sio.scan_window_size;
    425       1.1   mycroft 
    426      1.81   mbalmer 	/* If it's a null transfer, return immediatly */
    427       1.1   mycroft 	if (bp->b_bcount == 0)
    428       1.1   mycroft 		goto done;
    429       1.1   mycroft 
    430  1.84.2.3  jdolecek 	mutex_enter(chan_mtx(chan));
    431       1.1   mycroft 
    432       1.1   mycroft 	/*
    433       1.1   mycroft 	 * Place it in the queue of activities for this scanner
    434       1.1   mycroft 	 * at the end (a bit silly because we only have on user..
    435       1.1   mycroft 	 * (but it could fork()))
    436       1.1   mycroft 	 */
    437      1.76      yamt 	bufq_put(ss->buf_queue, bp);
    438       1.1   mycroft 
    439       1.1   mycroft 	/*
    440       1.1   mycroft 	 * Tell the device to get going on the transfer if it's
    441       1.1   mycroft 	 * not doing anything, otherwise just wait for completion
    442       1.1   mycroft 	 * (All a bit silly if we're only allowing 1 open but..)
    443       1.1   mycroft 	 */
    444  1.84.2.3  jdolecek 	ssstart(periph);
    445       1.1   mycroft 
    446  1.84.2.3  jdolecek 	mutex_exit(chan_mtx(chan));
    447       1.1   mycroft 	return;
    448       1.1   mycroft done:
    449      1.81   mbalmer 	/* Correctly set the buf to indicate a completed xfer */
    450       1.1   mycroft 	bp->b_resid = bp->b_bcount;
    451       1.1   mycroft 	biodone(bp);
    452       1.1   mycroft }
    453       1.1   mycroft 
    454       1.1   mycroft /*
    455       1.1   mycroft  * ssstart looks to see if there is a buf waiting for the device
    456       1.1   mycroft  * and that the device is not already busy. If both are true,
    457       1.1   mycroft  * It dequeues the buf and creates a scsi command to perform the
    458      1.16    bouyer  * transfer required. The transfer request will call scsipi_done
    459       1.1   mycroft  * on completion, which will in turn call this routine again
    460       1.1   mycroft  * so that the next queued transfer is performed.
    461       1.1   mycroft  * The bufs are queued by the strategy routine (ssstrategy)
    462       1.1   mycroft  *
    463       1.1   mycroft  * This routine is also called after other non-queued requests
    464       1.1   mycroft  * have been made of the scsi driver, to ensure that the queue
    465       1.1   mycroft  * continues to be drained.
    466  1.84.2.3  jdolecek  * ssstart() is called with channel lock held.
    467       1.1   mycroft  */
    468      1.52   thorpej static void
    469      1.52   thorpej ssstart(struct scsipi_periph *periph)
    470       1.1   mycroft {
    471      1.81   mbalmer 	struct ss_softc *ss = device_private(periph->periph_dev);
    472      1.30  augustss 	struct buf *bp;
    473       1.1   mycroft 
    474      1.34    bouyer 	SC_DEBUG(periph, SCSIPI_DB2, ("ssstart "));
    475      1.84   mbalmer 
    476      1.84   mbalmer 	/* See if there is a buf to do and we are not already doing one */
    477      1.34    bouyer 	while (periph->periph_active < periph->periph_openings) {
    478       1.1   mycroft 		/* if a special awaits, let it proceed first */
    479      1.34    bouyer 		if (periph->periph_flags & PERIPH_WAITING) {
    480      1.34    bouyer 			periph->periph_flags &= ~PERIPH_WAITING;
    481  1.84.2.3  jdolecek 			cv_broadcast(periph_cv_periph(periph));
    482       1.1   mycroft 			return;
    483       1.1   mycroft 		}
    484       1.1   mycroft 
    485      1.84   mbalmer 		/* See if there is a buf with work for us to do.. */
    486      1.76      yamt 		if ((bp = bufq_peek(ss->buf_queue)) == NULL)
    487       1.1   mycroft 			return;
    488       1.1   mycroft 
    489      1.81   mbalmer 		if (ss->special && ss->special->read)
    490       1.1   mycroft 			(ss->special->read)(ss, bp);
    491      1.83   mbalmer 		else {
    492       1.1   mycroft 			/* generic scsi2 scanner read */
    493       1.1   mycroft 			/* XXX add code for SCSI2 scanner read */
    494       1.1   mycroft 		}
    495       1.1   mycroft 	}
    496       1.1   mycroft }
    497       1.1   mycroft 
    498      1.55   mycroft void
    499      1.53    bouyer ssrestart(void *v)
    500      1.53    bouyer {
    501  1.84.2.3  jdolecek 	struct scsipi_periph *periph = v;
    502  1.84.2.3  jdolecek 	struct scsipi_channel *chan = periph->periph_channel;
    503  1.84.2.3  jdolecek 
    504  1.84.2.3  jdolecek 	mutex_enter(chan_mtx(chan));
    505  1.84.2.3  jdolecek 	ssstart(periph);
    506  1.84.2.3  jdolecek 	mutex_exit(chan_mtx(chan));
    507      1.53    bouyer }
    508      1.54   mycroft 
    509      1.54   mycroft static void
    510      1.54   mycroft ssdone(struct scsipi_xfer *xs, int error)
    511      1.54   mycroft {
    512      1.54   mycroft 	struct buf *bp = xs->bp;
    513      1.54   mycroft 
    514      1.54   mycroft 	if (bp) {
    515      1.54   mycroft 		bp->b_error = error;
    516      1.54   mycroft 		bp->b_resid = xs->resid;
    517      1.54   mycroft 		biodone(bp);
    518      1.54   mycroft 	}
    519      1.54   mycroft }
    520      1.53    bouyer 
    521      1.53    bouyer 
    522       1.1   mycroft /*
    523       1.1   mycroft  * Perform special action on behalf of the user;
    524       1.1   mycroft  * knows about the internals of this device
    525       1.1   mycroft  */
    526       1.1   mycroft int
    527      1.70  christos ssioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
    528       1.1   mycroft {
    529      1.74   tsutsui 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(dev));
    530       1.1   mycroft 	int error = 0;
    531       1.1   mycroft 	struct scan_io *sio;
    532      1.32  augustss 
    533      1.81   mbalmer 	if (!device_is_active(ss->sc_dev))
    534      1.81   mbalmer 		return ENODEV;
    535       1.1   mycroft 
    536       1.1   mycroft 	switch (cmd) {
    537       1.1   mycroft 	case SCIOCGET:
    538      1.21  explorer 		if (ss->special && ss->special->get_params) {
    539       1.1   mycroft 			/* call special handler */
    540       1.3   mycroft 			error = (ss->special->get_params)(ss);
    541       1.3   mycroft 			if (error)
    542      1.81   mbalmer 				return error;
    543      1.81   mbalmer 		} else
    544       1.1   mycroft 			/* XXX add code for SCSI2 scanner, if any */
    545      1.81   mbalmer 			return EOPNOTSUPP;
    546      1.36   thorpej 		memcpy(addr, &ss->sio, sizeof(struct scan_io));
    547       1.1   mycroft 		break;
    548       1.1   mycroft 	case SCIOCSET:
    549       1.1   mycroft 		sio = (struct scan_io *)addr;
    550       1.1   mycroft 
    551      1.21  explorer 		if (ss->special && ss->special->set_params) {
    552       1.1   mycroft 			/* call special handler */
    553       1.3   mycroft 			error = (ss->special->set_params)(ss, sio);
    554       1.3   mycroft 			if (error)
    555      1.81   mbalmer 				return error;
    556      1.81   mbalmer 		} else
    557       1.1   mycroft 			/* XXX add code for SCSI2 scanner, if any */
    558      1.81   mbalmer 			return EOPNOTSUPP;
    559       1.1   mycroft 		break;
    560       1.1   mycroft 	case SCIOCRESTART:
    561      1.21  explorer 		if (ss->special && ss->special->rewind_scanner ) {
    562       1.1   mycroft 			/* call special handler */
    563       1.3   mycroft 			error = (ss->special->rewind_scanner)(ss);
    564       1.3   mycroft 			if (error)
    565      1.81   mbalmer 				return error;
    566       1.1   mycroft 		} else
    567       1.1   mycroft 			/* XXX add code for SCSI2 scanner, if any */
    568      1.81   mbalmer 			return EOPNOTSUPP;
    569       1.1   mycroft 		ss->flags &= ~SSF_TRIGGERED;
    570       1.1   mycroft 		break;
    571       1.1   mycroft #ifdef NOTYET
    572       1.1   mycroft 	case SCAN_USE_ADF:
    573       1.1   mycroft 		break;
    574       1.1   mycroft #endif
    575       1.1   mycroft 	default:
    576      1.81   mbalmer 		return scsipi_do_ioctl(ss->sc_periph, dev, cmd, addr, flag, l);
    577       1.1   mycroft 	}
    578      1.81   mbalmer 	return error;
    579       1.1   mycroft }
    580