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.27 2008/04/28 20:23:58 martin 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.27 2008/04/28 20:23:58 martin Exp $");
   54 
   55 #include "opt_scsi.h"
   56 #include "rnd.h"
   57 
   58 #include <sys/param.h>
   59 #include <sys/device.h>
   60 #include <sys/buf.h>
   61 #include <sys/bufq.h>
   62 #include <sys/conf.h>
   63 #include <sys/kernel.h>
   64 #include <sys/systm.h>
   65 
   66 #include <dev/scsipi/scsi_all.h>
   67 #include <dev/scsipi/scsi_tape.h>
   68 #include <dev/scsipi/stvar.h>
   69 
   70 static int      st_scsibus_match(struct device *, struct cfdata *, void *);
   71 static void     st_scsibus_attach(struct device *, struct device *, void *);
   72 static int      st_scsibus_ops(struct st_softc *, int, int);
   73 static int      st_scsibus_read_block_limits(struct st_softc *, int);
   74 static int      st_scsibus_mode_sense(struct st_softc *, int);
   75 static int      st_scsibus_mode_select(struct st_softc *, int);
   76 static int      st_scsibus_cmprss(struct st_softc *, int, int);
   77 
   78 CFATTACH_DECL(st_scsibus, sizeof(struct st_softc),
   79     st_scsibus_match, st_scsibus_attach, stdetach, stactivate);
   80 
   81 static const struct scsipi_inquiry_pattern st_scsibus_patterns[] = {
   82         {T_SEQUENTIAL, T_REMOV,
   83          "",         "",                 ""},
   84 };
   85 
   86 static int
   87 st_scsibus_match(struct device *parent, struct cfdata *match,
   88     void *aux)
   89 {
   90         struct scsipibus_attach_args *sa = aux;
   91         int priority;
   92 
   93         if (scsipi_periph_bustype(sa->sa_periph) != SCSIPI_BUSTYPE_SCSI)
   94                 return (0);
   95 
   96         (void)scsipi_inqmatch(&sa->sa_inqbuf,
   97             st_scsibus_patterns,
   98             sizeof(st_scsibus_patterns)/sizeof(st_scsibus_patterns[0]),
   99             sizeof(st_scsibus_patterns[0]), &priority);
  100         return (priority);
  101 }
  102 
  103 static void
  104 st_scsibus_attach(struct device *parent, struct device *self, void *aux)
  105 {
  106         struct st_softc *st = device_private(self);
  107 
  108         st->ops = st_scsibus_ops;
  109         stattach(parent, st, aux);
  110 }
  111 
  112 static int
  113 st_scsibus_ops(struct st_softc *st, int op, int flags)
  114 {
  115         switch(op) {
  116         case ST_OPS_RBL:
  117                 return st_scsibus_read_block_limits(st, flags);
  118         case ST_OPS_MODESENSE:
  119                 return st_scsibus_mode_sense(st, flags);
  120         case ST_OPS_MODESELECT:
  121                 return st_scsibus_mode_select(st, flags);
  122         case ST_OPS_CMPRSS_ON:
  123         case ST_OPS_CMPRSS_OFF:
  124                 return st_scsibus_cmprss(st, flags,
  125                     (op == ST_OPS_CMPRSS_ON) ? 1 : 0);
  126         default:
  127                 panic("st_scsibus_ops: invalid op");
  128                 return 0; /* XXX to appease gcc */
  129         }
  130         /* NOTREACHED */
  131 }
  132 
  133 /*
  134  * Ask the drive what it's min and max blk sizes are.
  135  */
  136 static int
  137 st_scsibus_read_block_limits(struct st_softc *st, int flags)
  138 {
  139         struct scsi_block_limits cmd;
  140         struct scsi_block_limits_data block_limits;
  141         struct scsipi_periph *periph = st->sc_periph;
  142         int error;
  143 
  144         /*
  145          * do a 'Read Block Limits'
  146          */
  147         memset(&cmd, 0, sizeof(cmd));
  148         cmd.opcode = READ_BLOCK_LIMITS;
  149 
  150         /*
  151          * do the command, update the global values
  152          */
  153         error = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
  154             (void *)&block_limits, sizeof(block_limits),
  155             ST_RETRIES, ST_CTL_TIME, NULL,
  156             flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK);
  157         if (error)
  158                 return (error);
  159 
  160         st->blkmin = _2btol(block_limits.min_length);
  161         st->blkmax = _3btol(block_limits.max_length);
  162 
  163         SC_DEBUG(periph, SCSIPI_DB3,
  164             ("(%d <= blksize <= %d)\n", st->blkmin, st->blkmax));
  165         return (0);
  166 }
  167 
  168 /*
  169  * Get the scsi driver to send a full inquiry to the
  170  * device and use the results to fill out the global
  171  * parameter structure.
  172  *
  173  * called from:
  174  * attach
  175  * open
  176  * ioctl (to reset original blksize)
  177  */
  178 static int
  179 st_scsibus_mode_sense(struct st_softc *st, int flags)
  180 {
  181         u_int scsipi_sense_len;
  182         int error;
  183         struct scsipi_sense {
  184                 struct scsi_mode_parameter_header_6 header;
  185                 struct scsi_general_block_descriptor blk_desc;
  186                 u_char sense_data[MAX_PAGE_0_SIZE];
  187         } scsipi_sense;
  188         struct scsipi_periph *periph = st->sc_periph;
  189 
  190         scsipi_sense_len = 12 + st->page_0_size;
  191 
  192         /*
  193          * Set up a mode sense
  194          * We don't need the results. Just print them for our interest's sake,
  195          * if asked, or if we need it as a template for the mode select store
  196          * it away.
  197          */
  198         error = scsipi_mode_sense(st->sc_periph, 0, SMS_PCTRL_CURRENT,
  199             &scsipi_sense.header, scsipi_sense_len, flags | XS_CTL_DATA_ONSTACK,
  200             ST_RETRIES, ST_CTL_TIME);
  201         if (error)
  202                 return (error);
  203 
  204         st->numblks = _3btol(scsipi_sense.blk_desc.nblocks);
  205         st->media_blksize = _3btol(scsipi_sense.blk_desc.blklen);
  206         st->media_density = scsipi_sense.blk_desc.density;
  207         if (scsipi_sense.header.dev_spec & SMH_DSP_WRITE_PROT)
  208                 st->flags |= ST_READONLY;
  209         else
  210                 st->flags &= ~ST_READONLY;
  211         SC_DEBUG(periph, SCSIPI_DB3,
  212             ("density code %d, %d-byte blocks, write-%s, ",
  213             st->media_density, st->media_blksize,
  214             st->flags & ST_READONLY ? "protected" : "enabled"));
  215         SC_DEBUG(periph, SCSIPI_DB3,
  216             ("%sbuffered\n",
  217             scsipi_sense.header.dev_spec & SMH_DSP_BUFF_MODE ? "" : "un"));
  218         if (st->page_0_size)
  219                 memcpy(st->sense_data, scsipi_sense.sense_data,
  220                     st->page_0_size);
  221         periph->periph_flags |= PERIPH_MEDIA_LOADED;
  222         return (0);
  223 }
  224 
  225 /*
  226  * Send a filled out parameter structure to the drive to
  227  * set it into the desire modes etc.
  228  */
  229 static int
  230 st_scsibus_mode_select(struct st_softc *st, int flags)
  231 {
  232         u_int scsi_select_len;
  233         struct scsi_select {
  234                 struct scsi_mode_parameter_header_6 header;
  235                 struct scsi_general_block_descriptor blk_desc;
  236                 u_char sense_data[MAX_PAGE_0_SIZE];
  237         } scsi_select;
  238         struct scsipi_periph *periph = st->sc_periph;
  239 
  240         scsi_select_len = 12 + st->page_0_size;
  241 
  242         /*
  243          * This quirk deals with drives that have only one valid mode
  244          * and think this gives them license to reject all mode selects,
  245          * even if the selected mode is the one that is supported.
  246          */
  247         if (st->quirks & ST_Q_UNIMODAL) {
  248                 SC_DEBUG(periph, SCSIPI_DB3,
  249                     ("not setting density 0x%x blksize 0x%x\n",
  250                     st->density, st->blksize));
  251                 return (0);
  252         }
  253 
  254         /*
  255          * Set up for a mode select
  256          */
  257         memset(&scsi_select, 0, scsi_select_len);
  258         scsi_select.header.blk_desc_len = sizeof(struct scsi_general_block_descriptor);
  259         scsi_select.header.dev_spec &= ~SMH_DSP_BUFF_MODE;
  260         scsi_select.blk_desc.density = st->density;
  261         if (st->flags & ST_DONTBUFFER)
  262                 scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_OFF;
  263         else
  264                 scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
  265         if (st->flags & ST_FIXEDBLOCKS)
  266                 _lto3b(st->blksize, scsi_select.blk_desc.blklen);
  267         if (st->page_0_size)
  268                 memcpy(scsi_select.sense_data, st->sense_data, st->page_0_size);
  269 
  270         /*
  271          * do the command
  272          */
  273         return scsipi_mode_select(periph, 0, &scsi_select.header,
  274             scsi_select_len, flags | XS_CTL_DATA_ONSTACK,
  275             ST_RETRIES, ST_CTL_TIME);
  276 }
  277 
  278 static int
  279 st_scsibus_cmprss(struct st_softc *st, int flags, int onoff)
  280 {
  281         u_int scsi_dlen;
  282         int byte2, page;
  283         struct scsi_select {
  284                 struct scsi_mode_parameter_header_6 header;
  285                 struct scsi_general_block_descriptor blk_desc;
  286                 u_char pdata[MAX(sizeof(struct scsi_tape_dev_conf_page),
  287                     sizeof(struct scsi_tape_dev_compression_page))];
  288         } scsi_pdata;
  289         struct scsi_tape_dev_conf_page *ptr;
  290         struct scsi_tape_dev_compression_page *cptr;
  291         struct scsipi_periph *periph = st->sc_periph;
  292         int error, ison;
  293 
  294         scsi_dlen = sizeof(scsi_pdata);
  295         /*
  296          * Do DATA COMPRESSION page first.
  297          */
  298         page = SMS_PCTRL_CURRENT | 0xf;
  299         byte2 = 0;
  300 
  301         /*
  302          * Do the MODE SENSE command...
  303          */
  304 again:
  305         memset(&scsi_pdata, 0, scsi_dlen);
  306         error = scsipi_mode_sense(periph, byte2, page,
  307             &scsi_pdata.header, scsi_dlen, flags | XS_CTL_DATA_ONSTACK,
  308             ST_RETRIES, ST_CTL_TIME);
  309 
  310         if (error) {
  311                 if (byte2 != SMS_DBD) {
  312                         byte2 = SMS_DBD;
  313                         goto again;
  314                 }
  315                 /*
  316                  * Try a different page?
  317                  */
  318                 if (page == (SMS_PCTRL_CURRENT | 0xf)) {
  319                         page = SMS_PCTRL_CURRENT | 0x10;
  320                         byte2 = 0;
  321                         goto again;
  322                 }
  323                 return (error);
  324         }
  325 
  326         if (scsi_pdata.header.blk_desc_len)
  327                 ptr = (struct scsi_tape_dev_conf_page *) scsi_pdata.pdata;
  328         else
  329                 ptr = (struct scsi_tape_dev_conf_page *) &scsi_pdata.blk_desc;
  330 
  331         if ((page & SMS_PAGE_MASK) == 0xf) {
  332                 cptr = (struct scsi_tape_dev_compression_page *) ptr;
  333                 ison = (cptr->dce_dcc & DCP_DCE) != 0;
  334                 if (onoff)
  335                         cptr->dce_dcc |= DCP_DCE;
  336                 else
  337                         cptr->dce_dcc &= ~DCP_DCE;
  338                 cptr->pagecode &= ~0x80;
  339         } else {
  340                 ison =  (ptr->sel_comp_alg != 0);
  341                 if (onoff)
  342                         ptr->sel_comp_alg = 1;
  343                 else
  344                         ptr->sel_comp_alg = 0;
  345                 ptr->pagecode &= ~0x80;
  346                 ptr->byte2 = 0;
  347                 ptr->active_partition = 0;
  348                 ptr->wb_full_ratio = 0;
  349                 ptr->rb_empty_ratio = 0;
  350                 ptr->byte8 &= ~0x30;
  351                 ptr->gap_size = 0;
  352                 ptr->byte10 &= ~0xe7;
  353                 ptr->ew_bufsize[0] = 0;
  354                 ptr->ew_bufsize[1] = 0;
  355                 ptr->ew_bufsize[2] = 0;
  356                 ptr->reserved = 0;
  357         }
  358         /*
  359          * There might be a virtue in actually doing the MODE SELECTS,
  360          * but let's not clog the bus over it.
  361          */
  362         if (onoff == ison)
  363                 return (0);
  364 
  365         /*
  366          * Set up for a mode select
  367          */
  368 
  369         scsi_pdata.header.data_length = 0;
  370         scsi_pdata.header.medium_type = 0;
  371         if ((st->flags & ST_DONTBUFFER) == 0)
  372                 scsi_pdata.header.dev_spec = SMH_DSP_BUFF_MODE_ON;
  373         else
  374                 scsi_pdata.header.dev_spec = 0;
  375 
  376         if (scsi_pdata.header.blk_desc_len) {
  377                 scsi_pdata.blk_desc.density = 0;
  378                 scsi_pdata.blk_desc.nblocks[0] = 0;
  379                 scsi_pdata.blk_desc.nblocks[1] = 0;
  380                 scsi_pdata.blk_desc.nblocks[2] = 0;
  381         }
  382 
  383         /*
  384          * Do the command
  385          */
  386         error = scsipi_mode_select(periph, SMS_PF, &scsi_pdata.header,
  387             scsi_dlen, flags | XS_CTL_DATA_ONSTACK, ST_RETRIES, ST_CTL_TIME);
  388 
  389         if (error && (page & SMS_PAGE_MASK) == 0xf) {
  390                 /*
  391                  * Try DEVICE CONFIGURATION page.
  392                  */
  393                 page = SMS_PCTRL_CURRENT | 0x10;
  394                 goto again;
  395         }
  396         return (error);
  397 }

Cache object: 4d972eb4a3792705c0de5d50486d96c1


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