Home | History | Annotate | Line # | Download | only in scsipi
      1  1.93   mlelstv /*	$NetBSD: scsi_base.c,v 1.93 2019/05/03 16:06:56 mlelstv Exp $	*/
      2  1.14       cgd 
      3  1.65   mycroft /*-
      4  1.82   mycroft  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
      5  1.65   mycroft  * All rights reserved.
      6  1.65   mycroft  *
      7  1.65   mycroft  * This code is derived from software contributed to The NetBSD Foundation
      8  1.65   mycroft  * by Charles M. Hannum.
      9   1.9   mycroft  *
     10   1.9   mycroft  * Redistribution and use in source and binary forms, with or without
     11   1.9   mycroft  * modification, are permitted provided that the following conditions
     12   1.9   mycroft  * are met:
     13   1.9   mycroft  * 1. Redistributions of source code must retain the above copyright
     14   1.9   mycroft  *    notice, this list of conditions and the following disclaimer.
     15   1.9   mycroft  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.9   mycroft  *    notice, this list of conditions and the following disclaimer in the
     17   1.9   mycroft  *    documentation and/or other materials provided with the distribution.
     18   1.9   mycroft  *
     19  1.65   mycroft  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.65   mycroft  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.65   mycroft  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.65   mycroft  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.65   mycroft  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.65   mycroft  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.65   mycroft  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.65   mycroft  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.65   mycroft  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.65   mycroft  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.65   mycroft  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1   mycroft  */
     31  1.76     lukem 
     32  1.76     lukem #include <sys/cdefs.h>
     33  1.93   mlelstv __KERNEL_RCSID(0, "$NetBSD: scsi_base.c,v 1.93 2019/05/03 16:06:56 mlelstv Exp $");
     34  1.49     enami 
     35   1.1   mycroft #include <sys/param.h>
     36  1.30   thorpej #include <sys/systm.h>
     37  1.11   mycroft #include <sys/kernel.h>
     38   1.1   mycroft #include <sys/buf.h>
     39   1.1   mycroft #include <sys/uio.h>
     40   1.1   mycroft #include <sys/malloc.h>
     41   1.1   mycroft #include <sys/errno.h>
     42   1.1   mycroft #include <sys/device.h>
     43  1.33  christos #include <sys/proc.h>
     44   1.2   mycroft 
     45  1.47    bouyer #include <dev/scsipi/scsipi_all.h>
     46  1.47    bouyer #include <dev/scsipi/scsi_all.h>
     47  1.47    bouyer #include <dev/scsipi/scsi_disk.h>
     48  1.47    bouyer #include <dev/scsipi/scsiconf.h>
     49  1.47    bouyer #include <dev/scsipi/scsipi_base.h>
     50  1.47    bouyer 
     51  1.90    bouyer static void scsi_print_xfer_mode(struct scsipi_periph *);
     52   1.1   mycroft /*
     53   1.1   mycroft  * Do a scsi operation, asking a device to run as SCSI-II if it can.
     54   1.1   mycroft  */
     55  1.50     enami int
     56  1.79   thorpej scsi_change_def(struct scsipi_periph *periph, int flags)
     57   1.1   mycroft {
     58  1.84   mycroft 	struct scsi_changedef cmd;
     59   1.1   mycroft 
     60  1.84   mycroft 	memset(&cmd, 0, sizeof(cmd));
     61  1.84   mycroft 	cmd.opcode = SCSI_CHANGE_DEFINITION;
     62  1.84   mycroft 	cmd.how = SC_SCSI_2;
     63  1.84   mycroft 
     64  1.84   mycroft 	return (scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0,
     65  1.84   mycroft 	    SCSIPIRETRIES, 100000, NULL, flags));
     66  1.22   mycroft }
     67  1.22   mycroft 
     68  1.22   mycroft /*
     69  1.22   mycroft  * ask the scsi driver to perform a command for us.
     70  1.22   mycroft  * tell it where to read/write the data, and how
     71  1.22   mycroft  * long the data is supposed to be. If we have  a buf
     72  1.22   mycroft  * to associate with the transfer, we need that too.
     73  1.22   mycroft  */
     74  1.82   mycroft void
     75  1.82   mycroft scsi_scsipi_cmd(struct scsipi_xfer *xs)
     76  1.22   mycroft {
     77  1.82   mycroft 	struct scsipi_periph *periph = xs->xs_periph;
     78  1.22   mycroft 
     79  1.74    bouyer 	SC_DEBUG(periph, SCSIPI_DB2, ("scsi_scsipi_cmd\n"));
     80  1.22   mycroft 
     81  1.58       cgd 	/*
     82  1.58       cgd 	 * Set the LUN in the CDB if we have an older device.  We also
     83  1.74    bouyer 	 * set it for more modern SCSI-2 devices "just in case".
     84  1.58       cgd 	 */
     85  1.74    bouyer 	if (periph->periph_version <= 2)
     86  1.58       cgd 		xs->cmd->bytes[0] |=
     87  1.74    bouyer 		    ((periph->periph_lun << SCSI_CMD_LUN_SHIFT) &
     88  1.58       cgd 			SCSI_CMD_LUN_MASK);
     89   1.1   mycroft }
     90   1.1   mycroft 
     91   1.1   mycroft /*
     92   1.1   mycroft  * Utility routines often used in SCSI stuff
     93   1.1   mycroft  */
     94   1.1   mycroft 
     95   1.1   mycroft /*
     96  1.74    bouyer  * Print out the periph's address info.
     97   1.1   mycroft  */
     98   1.1   mycroft void
     99  1.79   thorpej scsi_print_addr(struct scsipi_periph *periph)
    100   1.1   mycroft {
    101  1.74    bouyer 	struct scsipi_channel *chan = periph->periph_channel;
    102  1.74    bouyer 	struct scsipi_adapter *adapt = chan->chan_adapter;
    103   1.1   mycroft 
    104  1.74    bouyer 	printf("%s(%s:%d:%d:%d): ", periph->periph_dev != NULL ?
    105  1.88    cegger 	    device_xname(periph->periph_dev) : "probe",
    106  1.88    cegger 	    device_xname(adapt->adapt_dev),
    107  1.74    bouyer 	    chan->chan_channel, periph->periph_target,
    108  1.74    bouyer 	    periph->periph_lun);
    109  1.70     enami }
    110  1.70     enami 
    111  1.70     enami /*
    112  1.74    bouyer  * Kill off all pending xfers for a periph.
    113  1.70     enami  *
    114  1.91   mlelstv  * Must be called with channel lock held
    115  1.70     enami  */
    116  1.70     enami void
    117  1.87  christos scsi_kill_pending(struct scsipi_periph *periph)
    118  1.70     enami {
    119  1.92   mlelstv 	struct scsipi_xfer *xs;
    120  1.92   mlelstv 
    121  1.92   mlelstv 	TAILQ_FOREACH(xs, &periph->periph_xferq, device_q) {
    122  1.92   mlelstv 		callout_stop(&xs->xs_callout);
    123  1.92   mlelstv 		scsi_print_addr(periph);
    124  1.92   mlelstv 		printf("killed ");
    125  1.92   mlelstv 		scsipi_print_cdb(xs->cmd);
    126  1.92   mlelstv 		xs->error = XS_DRIVER_STUFFUP;
    127  1.92   mlelstv 		scsipi_done(xs);
    128  1.92   mlelstv 	}
    129   1.1   mycroft }
    130  1.90    bouyer 
    131  1.90    bouyer /*
    132  1.90    bouyer  * scsi_print_xfer_mode:
    133  1.90    bouyer  *
    134  1.90    bouyer  *	Print a parallel SCSI periph's capabilities.
    135  1.90    bouyer  */
    136  1.90    bouyer static void
    137  1.90    bouyer scsi_print_xfer_mode(struct scsipi_periph *periph)
    138  1.90    bouyer {
    139  1.93   mlelstv 	struct scsipi_channel *chan = periph->periph_channel;
    140  1.93   mlelstv 	struct scsipi_adapter *adapt = chan->chan_adapter;
    141  1.90    bouyer 	int period, freq, speed, mbs;
    142  1.90    bouyer 
    143  1.93   mlelstv 	if (periph->periph_dev)
    144  1.93   mlelstv 		aprint_normal_dev(periph->periph_dev, "");
    145  1.93   mlelstv 	else
    146  1.93   mlelstv 		aprint_normal("probe(%s:%d:%d:%d): ",
    147  1.93   mlelstv 			device_xname(adapt->adapt_dev),
    148  1.93   mlelstv 			chan->chan_channel, periph->periph_target,
    149  1.93   mlelstv 			periph->periph_lun);
    150  1.90    bouyer 	if (periph->periph_mode & (PERIPH_CAP_SYNC | PERIPH_CAP_DT)) {
    151  1.90    bouyer 		period = scsipi_sync_factor_to_period(periph->periph_period);
    152  1.90    bouyer 		aprint_normal("sync (%d.%02dns offset %d)",
    153  1.90    bouyer 		    period / 100, period % 100, periph->periph_offset);
    154  1.90    bouyer 	} else
    155  1.90    bouyer 		aprint_normal("async");
    156  1.90    bouyer 
    157  1.90    bouyer 	if (periph->periph_mode & PERIPH_CAP_WIDE32)
    158  1.90    bouyer 		aprint_normal(", 32-bit");
    159  1.90    bouyer 	else if (periph->periph_mode & (PERIPH_CAP_WIDE16 | PERIPH_CAP_DT))
    160  1.90    bouyer 		aprint_normal(", 16-bit");
    161  1.90    bouyer 	else
    162  1.90    bouyer 		aprint_normal(", 8-bit");
    163  1.90    bouyer 
    164  1.90    bouyer 	if (periph->periph_mode & (PERIPH_CAP_SYNC | PERIPH_CAP_DT)) {
    165  1.90    bouyer 		freq = scsipi_sync_factor_to_freq(periph->periph_period);
    166  1.90    bouyer 		speed = freq;
    167  1.90    bouyer 		if (periph->periph_mode & PERIPH_CAP_WIDE32)
    168  1.90    bouyer 			speed *= 4;
    169  1.90    bouyer 		else if (periph->periph_mode &
    170  1.90    bouyer 		    (PERIPH_CAP_WIDE16 | PERIPH_CAP_DT))
    171  1.90    bouyer 			speed *= 2;
    172  1.90    bouyer 		mbs = speed / 1000;
    173  1.90    bouyer 		if (mbs > 0) {
    174  1.90    bouyer 			aprint_normal(" (%d.%03dMB/s)", mbs,
    175  1.90    bouyer 			    speed % 1000);
    176  1.90    bouyer 		} else
    177  1.90    bouyer 			aprint_normal(" (%dKB/s)", speed % 1000);
    178  1.90    bouyer 	}
    179  1.90    bouyer 
    180  1.90    bouyer 	aprint_normal(" transfers");
    181  1.90    bouyer 
    182  1.90    bouyer 	if (periph->periph_mode & PERIPH_CAP_TQING)
    183  1.90    bouyer 		aprint_normal(", tagged queueing");
    184  1.90    bouyer 
    185  1.90    bouyer 	aprint_normal("\n");
    186  1.90    bouyer }
    187  1.90    bouyer 
    188  1.90    bouyer /*
    189  1.90    bouyer  * scsi_async_event_xfer_mode:
    190  1.90    bouyer  *
    191  1.90    bouyer  *	Update the xfer mode for all parallel SCSI periphs sharing the
    192  1.90    bouyer  *	specified I_T Nexus.
    193  1.90    bouyer  */
    194  1.90    bouyer void
    195  1.90    bouyer scsi_async_event_xfer_mode(struct scsipi_channel *chan, void *arg)
    196  1.90    bouyer {
    197  1.90    bouyer 	struct scsipi_xfer_mode *xm = arg;
    198  1.90    bouyer 	struct scsipi_periph *periph;
    199  1.90    bouyer 	int lun, announce, mode, period, offset;
    200  1.90    bouyer 
    201  1.90    bouyer 	for (lun = 0; lun < chan->chan_nluns; lun++) {
    202  1.91   mlelstv 		periph = scsipi_lookup_periph_locked(chan, xm->xm_target, lun);
    203  1.90    bouyer 		if (periph == NULL)
    204  1.90    bouyer 			continue;
    205  1.90    bouyer 		announce = 0;
    206  1.90    bouyer 
    207  1.90    bouyer 		/*
    208  1.90    bouyer 		 * Clamp the xfer mode down to this periph's capabilities.
    209  1.90    bouyer 		 */
    210  1.90    bouyer 		mode = xm->xm_mode & periph->periph_cap;
    211  1.90    bouyer 		if (mode & PERIPH_CAP_SYNC) {
    212  1.90    bouyer 			period = xm->xm_period;
    213  1.90    bouyer 			offset = xm->xm_offset;
    214  1.90    bouyer 		} else {
    215  1.90    bouyer 			period = 0;
    216  1.90    bouyer 			offset = 0;
    217  1.90    bouyer 		}
    218  1.90    bouyer 
    219  1.90    bouyer 		/*
    220  1.90    bouyer 		 * If we do not have a valid xfer mode yet, or the parameters
    221  1.90    bouyer 		 * are different, announce them.
    222  1.90    bouyer 		 */
    223  1.90    bouyer 		if ((periph->periph_flags & PERIPH_MODE_VALID) == 0 ||
    224  1.90    bouyer 		    periph->periph_mode != mode ||
    225  1.90    bouyer 		    periph->periph_period != period ||
    226  1.90    bouyer 		    periph->periph_offset != offset)
    227  1.90    bouyer 			announce = 1;
    228  1.90    bouyer 
    229  1.90    bouyer 		periph->periph_mode = mode;
    230  1.90    bouyer 		periph->periph_period = period;
    231  1.90    bouyer 		periph->periph_offset = offset;
    232  1.90    bouyer 		periph->periph_flags |= PERIPH_MODE_VALID;
    233  1.90    bouyer 
    234  1.90    bouyer 		if (announce)
    235  1.90    bouyer 			scsi_print_xfer_mode(periph);
    236  1.90    bouyer 	}
    237  1.90    bouyer }
    238  1.90    bouyer 
    239  1.90    bouyer /*
    240  1.90    bouyer  * scsipi_async_event_xfer_mode:
    241  1.90    bouyer  *
    242  1.90    bouyer  *	Update the xfer mode for all SAS/FC periphs sharing the
    243  1.90    bouyer  *	specified I_T Nexus.
    244  1.90    bouyer  */
    245  1.90    bouyer void
    246  1.90    bouyer scsi_fc_sas_async_event_xfer_mode(struct scsipi_channel *chan, void *arg)
    247  1.90    bouyer {
    248  1.90    bouyer 	struct scsipi_xfer_mode *xm = arg;
    249  1.90    bouyer 	struct scsipi_periph *periph;
    250  1.90    bouyer 	int lun, announce, mode;
    251  1.90    bouyer 
    252  1.90    bouyer 	for (lun = 0; lun < chan->chan_nluns; lun++) {
    253  1.91   mlelstv 		periph = scsipi_lookup_periph_locked(chan, xm->xm_target, lun);
    254  1.90    bouyer 		if (periph == NULL)
    255  1.90    bouyer 			continue;
    256  1.90    bouyer 		announce = 0;
    257  1.90    bouyer 
    258  1.90    bouyer 		/*
    259  1.90    bouyer 		 * Clamp the xfer mode down to this periph's capabilities.
    260  1.90    bouyer 		 */
    261  1.90    bouyer 		mode = xm->xm_mode & periph->periph_cap;
    262  1.90    bouyer 		/*
    263  1.90    bouyer 		 * If we do not have a valid xfer mode yet, or the parameters
    264  1.90    bouyer 		 * are different, announce them.
    265  1.90    bouyer 		 */
    266  1.90    bouyer 		if ((periph->periph_flags & PERIPH_MODE_VALID) == 0 ||
    267  1.90    bouyer 		    periph->periph_mode != mode)
    268  1.90    bouyer 			announce = 1;
    269  1.90    bouyer 
    270  1.90    bouyer 		periph->periph_mode = mode;
    271  1.90    bouyer 		periph->periph_flags |= PERIPH_MODE_VALID;
    272  1.90    bouyer 
    273  1.90    bouyer 		if (announce &&
    274  1.90    bouyer 		    (periph->periph_mode & PERIPH_CAP_TQING) != 0) {
    275  1.90    bouyer 			aprint_normal_dev(periph->periph_dev,
    276  1.90    bouyer 			    "tagged queueing\n");
    277  1.90    bouyer 		}
    278  1.90    bouyer 	}
    279  1.90    bouyer }
    280