The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/scsipi/st_scsi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: st_scsi.c,v 1.37 2015/08/24 23:13:15 pooka Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Charles M. Hannum.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Originally written by Julian Elischer (julian@tfs.com)
   34  * for TRW Financial Systems for use under the MACH(2.5) operating system.
   35  *
   36  * TRW Financial Systems, in accordance with their agreement with Carnegie
   37  * Mellon University, makes this software available to CMU to distribute
   38  * or use in any manner that they see fit as long as this message is kept with
   39  * the software. For this reason TFS also grants any other persons or
   40  * organisations permission to use or modify this software.
   41  *
   42  * TFS supplies this software to be publicly redistributed
   43  * on the understanding that TFS is not responsible for the correct
   44  * functioning of this software in any circumstances.
   45  *
   46  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
   47  * major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993
   48  *
   49  * A lot of rewhacking done by mjacob (mjacob@nas.nasa.gov).
   50  */
   51 
   52 #include <sys/cdefs.h>
   53 __KERNEL_RCSID(0, "$NetBSD: st_scsi.c,v 1.37 2015/08/24 23:13:15 pooka Exp $");
   54 
   55 #ifdef _KERNEL_OPT
   56 #include "opt_scsi.h"
   57 #endif
   58 
   59 #include <sys/param.h>
   60 #include <sys/device.h>
   61 #include <sys/buf.h>
   62 #include <sys/bufq.h>
   63 #include <sys/conf.h>
   64 #include <sys/kernel.h>
   65 #include <sys/systm.h>
   66 
   67 #include <dev/scsipi/scsi_all.h>
   68 #include <dev/scsipi/scsi_tape.h>
   69 #include <dev/scsipi/stvar.h>
   70 
   71 static int      st_scsibus_match(device_t, cfdata_t, void *);
   72 static void     st_scsibus_attach(device_t, device_t, void *);
   73 static int      st_scsibus_ops(struct st_softc *, int, int);
   74 static int      st_scsibus_read_block_limits(struct st_softc *, int);
   75 static int      st_scsibus_mode_sense(struct st_softc *, int);
   76 static int      st_scsibus_cmprss(struct st_softc *, int, int);
   77 
   78 CFATTACH_DECL_NEW(
   79         st_scsibus,
   80         sizeof(struct st_softc),
   81         st_scsibus_match,
   82         st_scsibus_attach,
   83         stdetach,
   84         NULL
   85 );
   86 
   87 static const struct scsipi_inquiry_pattern st_scsibus_patterns[] = {
   88         {T_SEQUENTIAL, T_REMOV,
   89          "",         "",                 ""},
   90 };
   91 
   92 static int
   93 st_scsibus_match(device_t parent, cfdata_t match, void *aux)
   94 {
   95         struct scsipibus_attach_args *sa = aux;
   96         int priority;
   97 
   98         if (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph)) !=
   99             SCSIPI_BUSTYPE_SCSI)
  100                 return 0;
  101 
  102         (void)scsipi_inqmatch(&sa->sa_inqbuf,
  103             st_scsibus_patterns,
  104             sizeof(st_scsibus_patterns)/sizeof(st_scsibus_patterns[0]),
  105             sizeof(st_scsibus_patterns[0]), &priority);
  106         return priority;
  107 }
  108 
  109 static void
  110 st_scsibus_attach(device_t parent, device_t self, void *aux)
  111 {
  112         struct st_softc *st = device_private(self);
  113 
  114         st->ops = st_scsibus_ops;
  115         stattach(parent, self, aux);
  116 }
  117 
  118 static int
  119 st_scsibus_ops(struct st_softc *st, int op, int flags)
  120 {
  121         switch(op) {
  122         case ST_OPS_RBL:
  123                 return st_scsibus_read_block_limits(st, flags);
  124         case ST_OPS_MODESENSE:
  125                 return st_scsibus_mode_sense(st, flags);
  126         case ST_OPS_MODESELECT:
  127                 return st_mode_select(st, flags);
  128         case ST_OPS_CMPRSS_ON:
  129         case ST_OPS_CMPRSS_OFF:
  130                 return st_scsibus_cmprss(st, flags,
  131                     (op == ST_OPS_CMPRSS_ON) ? 1 : 0);
  132         default:
  133                 panic("st_scsibus_ops: invalid op");
  134                 return 0; /* XXX to appease gcc */
  135         }
  136         /* NOTREACHED */
  137 }
  138 
  139 /*
  140  * Ask the drive what its min and max blk sizes are.
  141  */
  142 static int
  143 st_scsibus_read_block_limits(struct st_softc *st, int flags)
  144 {
  145         struct scsi_block_limits cmd;
  146         struct scsi_block_limits_data block_limits;
  147         struct scsipi_periph *periph = st->sc_periph;
  148         int error;
  149 
  150         /* do a 'Read Block Limits' */
  151         memset(&cmd, 0, sizeof(cmd));
  152         cmd.opcode = READ_BLOCK_LIMITS;
  153 
  154         /* do the command, update the global values */
  155         error = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
  156             (void *)&block_limits, sizeof(block_limits),
  157             ST_RETRIES, ST_CTL_TIME, NULL, flags | XS_CTL_DATA_IN);
  158         if (error)
  159                 return error;
  160 
  161         st->blkmin = _2btol(block_limits.min_length);
  162         st->blkmax = _3btol(block_limits.max_length);
  163 
  164         SC_DEBUG(periph, SCSIPI_DB3,
  165             ("(%d <= blksize <= %d)\n", st->blkmin, st->blkmax));
  166         return 0;
  167 }
  168 
  169 /*
  170  * Get the scsi driver to send a full inquiry to the
  171  * device and use the results to fill out the global
  172  * parameter structure.
  173  *
  174  * called from:
  175  * attach
  176  * open
  177  * ioctl (to reset original blksize)
  178  */
  179 static int
  180 st_scsibus_mode_sense(struct st_softc *st, int flags)
  181 {
  182         u_int scsipi_sense_len;
  183         int error;
  184         struct scsipi_sense {
  185                 struct scsi_mode_parameter_header_6 header;
  186                 struct scsi_general_block_descriptor blk_desc;
  187                 u_char sense_data[MAX_PAGE_0_SIZE];
  188         } scsipi_sense;
  189         struct scsipi_periph *periph = st->sc_periph;
  190 
  191         scsipi_sense_len = sizeof(scsipi_sense.header) +
  192                            sizeof(scsipi_sense.blk_desc) +
  193                            st->page_0_size;
  194 
  195         /*
  196          * Set up a mode sense
  197          * We don't need the results. Just print them for our interest's sake,
  198          * if asked, or if we need it as a template for the mode select store
  199          * it away.
  200          */
  201         error = scsipi_mode_sense(st->sc_periph, 0, SMS_PCTRL_CURRENT,
  202             &scsipi_sense.header, scsipi_sense_len, flags,
  203             ST_RETRIES, ST_CTL_TIME);
  204         if (error)
  205                 return error;
  206 
  207         st->numblks = _3btol(scsipi_sense.blk_desc.nblocks);
  208         st->media_blksize = _3btol(scsipi_sense.blk_desc.blklen);
  209         st->media_density = scsipi_sense.blk_desc.density;
  210         if (scsipi_sense.header.dev_spec & SMH_DSP_WRITE_PROT)
  211                 st->flags |= ST_READONLY;
  212         else
  213                 st->flags &= ~ST_READONLY;
  214         SC_DEBUG(periph, SCSIPI_DB3,
  215             ("density code %d, %d-byte blocks, write-%s, ",
  216             st->media_density, st->media_blksize,
  217             st->flags & ST_READONLY ? "protected" : "enabled"));
  218         SC_DEBUG(periph, SCSIPI_DB3,
  219             ("%sbuffered\n",
  220             scsipi_sense.header.dev_spec & SMH_DSP_BUFF_MODE ? "" : "un"));
  221         if (st->page_0_size)
  222                 memcpy(st->sense_data, scsipi_sense.sense_data,
  223                     st->page_0_size);
  224         periph->periph_flags |= PERIPH_MEDIA_LOADED;
  225         return 0;
  226 }
  227 
  228 static int
  229 st_scsibus_cmprss(struct st_softc *st, int flags, int onoff)
  230 {
  231         u_int scsi_dlen;
  232         int byte2, page;
  233         struct scsi_select {
  234                 struct scsi_mode_parameter_header_6 header;
  235                 struct scsi_general_block_descriptor blk_desc;
  236                 u_char pdata[MAX(sizeof(struct scsi_tape_dev_conf_page),
  237                     sizeof(struct scsi_tape_dev_compression_page))];
  238         } scsi_pdata;
  239         struct scsi_tape_dev_conf_page *ptr;
  240         struct scsi_tape_dev_compression_page *cptr;
  241         struct scsipi_periph *periph = st->sc_periph;
  242         int error, ison;
  243 
  244         scsi_dlen = sizeof(scsi_pdata);
  245         /* Do DATA COMPRESSION page first. */
  246         page = SMS_PCTRL_CURRENT | 0xf;
  247         byte2 = 0;
  248 
  249         /*  Do the MODE SENSE command... */
  250 again:
  251         memset(&scsi_pdata, 0, scsi_dlen);
  252         error = scsipi_mode_sense(periph, byte2, page,
  253             &scsi_pdata.header, scsi_dlen, flags, ST_RETRIES, ST_CTL_TIME);
  254 
  255         if (error) {
  256                 if (byte2 != SMS_DBD) {
  257                         byte2 = SMS_DBD;
  258                         goto again;
  259                 }
  260                 /* Try a different page? */
  261                 if (page == (SMS_PCTRL_CURRENT | 0xf)) {
  262                         page = SMS_PCTRL_CURRENT | 0x10;
  263                         byte2 = 0;
  264                         goto again;
  265                 }
  266                 return error;
  267         }
  268 
  269         if (scsi_pdata.header.blk_desc_len)
  270                 ptr = (struct scsi_tape_dev_conf_page *) scsi_pdata.pdata;
  271         else
  272                 ptr = (struct scsi_tape_dev_conf_page *) &scsi_pdata.blk_desc;
  273 
  274         if ((page & SMS_PAGE_MASK) == 0xf) {
  275                 cptr = (struct scsi_tape_dev_compression_page *) ptr;
  276                 ison = (cptr->dce_dcc & DCP_DCE) != 0;
  277                 if (onoff)
  278                         cptr->dce_dcc |= DCP_DCE;
  279                 else
  280                         cptr->dce_dcc &= ~DCP_DCE;
  281                 cptr->pagecode &= ~0x80;
  282         } else {
  283                 ison =  (ptr->sel_comp_alg != 0);
  284                 if (onoff)
  285                         ptr->sel_comp_alg = 1;
  286                 else
  287                         ptr->sel_comp_alg = 0;
  288                 ptr->pagecode &= ~0x80;
  289                 ptr->byte2 = 0;
  290                 ptr->active_partition = 0;
  291                 ptr->wb_full_ratio = 0;
  292                 ptr->rb_empty_ratio = 0;
  293                 ptr->byte8 &= ~0x30;
  294                 ptr->gap_size = 0;
  295                 ptr->byte10 &= ~0xe7;
  296                 ptr->ew_bufsize[0] = 0;
  297                 ptr->ew_bufsize[1] = 0;
  298                 ptr->ew_bufsize[2] = 0;
  299                 ptr->reserved = 0;
  300         }
  301         /*
  302          * There might be a virtue in actually doing the MODE SELECTS,
  303          * but let's not clog the bus over it.
  304          */
  305         if (onoff == ison)
  306                 return 0;
  307 
  308         /* Set up for a mode select */
  309         scsi_pdata.header.data_length = 0;
  310         scsi_pdata.header.medium_type = 0;
  311         if ((st->flags & ST_DONTBUFFER) == 0)
  312                 scsi_pdata.header.dev_spec = SMH_DSP_BUFF_MODE_ON;
  313         else
  314                 scsi_pdata.header.dev_spec = 0;
  315 
  316         if (scsi_pdata.header.blk_desc_len) {
  317                 scsi_pdata.blk_desc.density = 0;
  318                 scsi_pdata.blk_desc.nblocks[0] = 0;
  319                 scsi_pdata.blk_desc.nblocks[1] = 0;
  320                 scsi_pdata.blk_desc.nblocks[2] = 0;
  321         }
  322 
  323         /* Do the command */
  324         error = scsipi_mode_select(periph, SMS_PF, &scsi_pdata.header,
  325             scsi_dlen, flags, ST_RETRIES, ST_CTL_TIME);
  326 
  327         if (error && (page & SMS_PAGE_MASK) == 0xf) {
  328                 /* Try DEVICE CONFIGURATION page. */
  329                 page = SMS_PCTRL_CURRENT | 0x10;
  330                 goto again;
  331         }
  332         return error;
  333 }

Cache object: 17c4a75cb41fdf8b74beb62f61b5306e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.