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

Cache object: aa5d0e9c6555cd2af98b6d1cc935ba21


[ 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.