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/scsi/rz.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 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1993-1990 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        rz.c,v $
   29  * Revision 2.19  93/05/15  19:42:33  mrt
   30  *      machparam.h -> machspl.h
   31  * 
   32  * Revision 2.18  93/05/10  21:22:18  rvb
   33  *      Removed depend on DEV_BSIZE. Lint.
   34  *      [93/05/06  10:14:29  af]
   35  * 
   36  * Revision 2.17  93/03/09  10:57:31  danner
   37  *      rz_check now is officially exported by this module.
   38  *      [93/03/06            af]
   39  * 
   40  * Revision 2.16  93/01/14  17:55:09  danner
   41  *      Proper spl typing.
   42  *      [92/12/01            af]
   43  * 
   44  *      Added rz_simple_strategy(), common strategy routine for (most) devices
   45  *      that do not need to reorder requests.
   46  *      [92/11/29            af]
   47  * 
   48  * Revision 2.15  92/08/03  17:53:15  jfriedl
   49  *      removed silly prototypes
   50  *      [92/08/02            jfriedl]
   51  * 
   52  * Revision 2.14  92/05/21  17:23:17  jfriedl
   53  *      Cleanup to quiet gcc warnings.
   54  *      [92/05/16            jfriedl]
   55  * 
   56  * Revision 2.13  92/02/23  22:44:12  elf
   57  *      Changed the interface of a number of functions not to
   58  *      require the scsi_softc pointer any longer.  It was
   59  *      mostly unused, now it can be found via tgt->masterno.
   60  *      [92/02/22  19:31:18  af]
   61  * 
   62  * Revision 2.12  92/01/03  20:44:06  dbg
   63  *      Added rz_devinfo().
   64  *      [91/12/26  11:10:59  af]
   65  * 
   66  * Revision 2.11  91/10/09  16:16:57  af
   67  *      Zero io_error before using the ior.
   68  * 
   69  * Revision 2.10  91/08/24  12:27:43  af
   70  *      Pass along the ior in open calls.
   71  *      Removed luna88k specialization, as the device headers have been
   72  *       rationalized. 
   73  *      [91/08/02  03:51:40  af]
   74  * 
   75  * Revision 2.9  91/07/09  23:22:23  danner
   76  *      Added gross ifdef luna88k to use <sd.h> instead of <scsi.h>. Will
   77  *       be fixed as soon as I figure out the configuration tools.
   78  *      [91/07/09  11:05:28  danner]
   79  * 
   80  * Revision 2.8  91/06/19  11:56:54  rvb
   81  *      File moved here from mips/PMAX since it is now "MI" code, also
   82  *      used by Vax3100 and soon -- the omron luna88k.
   83  *      [91/06/04            rvb]
   84  * 
   85  * Revision 2.7  91/05/14  17:26:11  mrt
   86  *      Correcting copyright
   87  * 
   88  * Revision 2.6  91/05/13  06:04:14  af
   89  *      Use a longer timeout on opens (exabytes are so slooooow to
   90  *      get ready).  If we are still rewinding the tape make open
   91  *      fail.  Start watchdog on first open, for those adapters
   92  *      that need it.  Ask for sense data when unit does not
   93  *      come online quickly enough. On close, invoke anything
   94  *      target-specific that needs to.
   95  *      [91/05/12  16:04:29  af]
   96  * 
   97  * Revision 2.5.1.1  91/03/29  17:21:00  af
   98  *      Use a longer timeout on opens (exabytes are so slooooow to
   99  *      get ready).  If we are still rewinding the tape make open
  100  *      fail.  Start watchdog on first open, for those adapters
  101  *      that need it.  Ask for sense data when unit does not
  102  *      come online quickly enough. On close, invoke anything
  103  *      target-specific that needs to.
  104  * 
  105  * Revision 2.5  91/02/05  17:43:37  mrt
  106  *      Added author notices
  107  *      [91/02/04  11:16:27  mrt]
  108  * 
  109  *      Changed to use new Mach copyright
  110  *      [91/02/02  12:15:22  mrt]
  111  * 
  112  * Revision 2.4  90/12/20  16:59:59  jeffreyh
  113  *      Do not use minphys(), we do not need to trim requests.
  114  *      [90/12/11            af]
  115  * 
  116  * Revision 2.3  90/12/05  23:33:46  af
  117  *      Cut&retry for requests that exceed the HBA's dma capacity.
  118  *      [90/12/03  23:32:38  af]
  119  * 
  120  * Revision 2.1.1.1  90/11/01  03:43:31  af
  121  *      Created.
  122  *      [90/10/21            af]
  123  */
  124 /*
  125  *      File: rz.c
  126  *      Author: Alessandro Forin, Carnegie Mellon University
  127  *      Date:   10/90
  128  *
  129  *      Top layer of the SCSI driver: interface with the MI side.
  130  */
  131 
  132 /*
  133  * This file contains the code that is common to all scsi devices,
  134  * operations and/or behaviours specific to certain devices live
  135  * in the corresponding rz_mumble files.
  136  */
  137 
  138 #include <scsi.h>
  139 
  140 #if     (NSCSI>0)
  141 
  142 #include <mach/std_types.h>
  143 #include <machine/machspl.h>            /* spl definitions */
  144 #include <scsi/compat_30.h>
  145 
  146 #ifdef  MACH_KERNEL
  147 #include <kern/time_out.h>
  148 #else   /*MACH_KERNEL*/
  149 #include <sys/kernel.h>         /* for hz */
  150 
  151 static io_req_t getbp();
  152 #endif  /*MACH_KERNEL*/
  153 
  154 #include <scsi/scsi_defs.h>
  155 #include <scsi/rz.h>
  156 
  157 
  158 boolean_t
  159 rz_check(dev, p_sc, p_tgt)
  160         int dev;
  161         scsi_softc_t    **p_sc;
  162         target_info_t   **p_tgt;
  163 {
  164         if (rzcontroller(dev) >= NSCSI ||
  165             (*p_sc = scsi_softc[rzcontroller(dev)]) == 0)
  166                 return FALSE;
  167 
  168         *p_tgt = (*p_sc)->target[rzslave(dev)];
  169 
  170         if (!*p_tgt ||
  171             !((*p_tgt)->flags&TGT_ALIVE))
  172                 return FALSE;
  173         return TRUE;
  174 }
  175 
  176 /*
  177  * Open routine
  178  *
  179  * On tapes and other devices might have to wait a bit for
  180  * the unit to come alive. The following patchable variable
  181  * takes this into account
  182  */
  183 int rz_open_timeout = 60;/* seconds */
  184 
  185 int rz_open(dev, mode, ior)
  186         int             dev;
  187         dev_mode_t      mode;
  188         io_req_t        ior;
  189 {
  190         scsi_softc_t    *sc = 0;
  191         target_info_t   *tgt;
  192         scsi_ret_t      ret;
  193         register int    i;
  194 
  195         if (!rz_check(dev, &sc, &tgt)) {
  196                 /*
  197                  * Probe it again: might have installed a new device
  198                  */
  199                 if (!sc || !scsi_probe(sc, &tgt, rzslave(dev), ior))
  200                         return D_NO_SUCH_DEVICE;
  201         }
  202 
  203         /* tapes do not wait for rewind to complete on close */
  204         if (tgt->ior && !(tgt->flags & TGT_ONLINE))
  205                 return D_WOULD_BLOCK;
  206 
  207         if (scsi_debug)
  208                 printf("opening %s%d..", (*tgt->dev_ops->driver_name)(TRUE), dev&0xff);
  209 
  210         if (sc->watchdog) {
  211                 (*sc->watchdog)(tgt->hw_state);
  212                 sc->watchdog = 0;
  213         }
  214 
  215         /*
  216          * Bring the unit online, retrying if necessary.
  217          * If the target is spinning up we wait for it.
  218          */
  219         if ( ! (tgt->flags & TGT_ONLINE)) {
  220                 io_req_t        tmp_ior;
  221 
  222                 io_req_alloc(tmp_ior,0);                
  223                 tmp_ior->io_next = 0;
  224                 tmp_ior->io_count = 0;
  225 
  226                 for (i = 0; i < rz_open_timeout; i++) {
  227 
  228                         tmp_ior->io_op = IO_INTERNAL;
  229                         tmp_ior->io_error = 0;
  230                         ret = scsi_test_unit_ready(tgt, tmp_ior);
  231 
  232                         if (ret == SCSI_RET_SUCCESS)
  233                                 break;
  234 
  235                         if (ret == SCSI_RET_DEVICE_DOWN) {
  236                                 i = rz_open_timeout;
  237                                 break;
  238                         }
  239 
  240                         if (ret == SCSI_RET_NEED_SENSE) {
  241 
  242                                 tmp_ior->io_op = IO_INTERNAL;
  243                                 tmp_ior->io_count = 0;
  244                                 tmp_ior->io_residual = 0;
  245                                 tgt->ior = tmp_ior;
  246                                 scsi_request_sense(tgt, tmp_ior, 0);
  247                                 iowait(tmp_ior);
  248 
  249                         }
  250 
  251                         if (i == 5) printf("%s%d: %s\n", 
  252                                            (*tgt->dev_ops->driver_name)(TRUE),
  253                                            tgt->target_id,
  254                                            "Waiting to come online..");
  255                         timeout(wakeup, tgt, hz);
  256                         await(tgt);
  257                 }
  258 
  259                 /* lock on removable media */
  260                 if ((i != rz_open_timeout) && (tgt->flags & TGT_REMOVABLE_MEDIA)) {
  261                         tmp_ior->io_op = IO_INTERNAL;
  262                         /* too many dont support it. Sigh */
  263                         tgt->flags |= TGT_OPTIONAL_CMD;
  264                         (void) scsi_medium_removal( tgt, FALSE, tmp_ior);
  265                         tgt->flags &= ~TGT_OPTIONAL_CMD;
  266                 }
  267 
  268                 io_req_free(tmp_ior);
  269                 if (i == rz_open_timeout)
  270                         return D_DEVICE_DOWN;
  271         }
  272         /*
  273          * Perform anything open-time special on the device
  274          */
  275         if (tgt->dev_ops->open != SCSI_OPEN_NULL) {
  276                 ret = (*tgt->dev_ops->open)(tgt, ior);
  277                 if (ret != SCSI_RET_SUCCESS) {
  278                         if (scsi_debug) printf("%s%d: open failed x%x\n",
  279                                  (*tgt->dev_ops->driver_name)(TRUE), dev&0xff, ret);
  280                         return ret;
  281                 }
  282         }
  283         tgt->flags |= TGT_ONLINE;
  284         ior->io_device->bsize = tgt->block_size;
  285         return D_SUCCESS;
  286 }
  287 
  288 int rz_close(dev)
  289         int             dev;
  290 {
  291         scsi_softc_t    *sc;
  292         target_info_t   *tgt;
  293         scsi_ret_t      ret;
  294 
  295         if (!rz_check(dev, &sc, &tgt))
  296                 return D_NO_SUCH_DEVICE;
  297 
  298         if (scsi_debug)
  299                 printf("closing %s%d..", (*tgt->dev_ops->driver_name)(TRUE), dev&0xff);
  300 
  301         if (tgt->flags & TGT_REMOVABLE_MEDIA) {
  302                 io_req_t        ior;
  303 
  304                 io_req_alloc(ior,0);            
  305                 ior->io_next = 0;
  306                 ior->io_count = 0;
  307                 ior->io_op = IO_INTERNAL;
  308                 ior->io_error = 0;
  309                 /* too many dont support it. Sigh */
  310                 tgt->flags |= TGT_OPTIONAL_CMD;
  311                 (void) scsi_medium_removal( tgt, TRUE, ior);
  312                 tgt->flags &= ~TGT_OPTIONAL_CMD;
  313                 io_req_free(ior);
  314         }
  315 
  316         /*
  317          * Perform anything close-time special on the device
  318          */
  319         if (tgt->dev_ops->close != SCSI_CLOSE_NULL) {
  320                 ret = (*tgt->dev_ops->close)(tgt);
  321                 if (ret != SCSI_RET_SUCCESS) {
  322                          printf("%s%d: close failed x%x\n",
  323                          (*tgt->dev_ops->driver_name)(TRUE), dev&0xff, ret);
  324                 }
  325         }
  326         if (tgt->flags & TGT_REMOVABLE_MEDIA)
  327                 tgt->flags &= ~TGT_ONLINE;
  328 
  329         return D_SUCCESS;
  330 }
  331 
  332 /* our own minphys */
  333 void rz_minphys(ior)
  334         io_req_t        ior;
  335 {
  336 #ifdef  MACH_KERNEL
  337 #else   /*MACH_KERNEL*/
  338         if (ior->io_count > scsi_per_target_virtual)
  339                 ior->io_count = scsi_per_target_virtual;
  340 #endif  /*MACH_KERNEL*/
  341 }
  342 
  343 int rz_read(dev, ior)
  344         int             dev;
  345         io_req_t        ior;
  346 {
  347         target_info_t   *tgt;
  348 
  349         tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
  350 
  351 #ifdef  MACH_KERNEL
  352         return block_io(tgt->dev_ops->strategy, rz_minphys, ior);
  353 #else   /*MACH_KERNEL*/
  354         return physio(tgt->dev_ops->strategy, getbp(dev), dev, IO_READ, rz_minphys, ior);
  355 #endif  /*MACH_KERNEL*/
  356 }
  357 
  358 int rz_write(dev, ior)
  359         int             dev;
  360         io_req_t        ior;
  361 {
  362         target_info_t   *tgt;
  363 
  364         tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
  365 
  366         if (tgt->flags & TGT_READONLY)
  367                 return D_INVALID_OPERATION;
  368 
  369 #ifdef  MACH_KERNEL
  370         return block_io(tgt->dev_ops->strategy, rz_minphys, ior);
  371 #else   /*MACH_KERNEL*/
  372         return physio(tgt->dev_ops->strategy, getbp(dev), dev, IO_WRITE, rz_minphys, ior);
  373 #endif  /*MACH_KERNEL*/
  374 }
  375 
  376 int rz_get_status(dev, flavor, status, status_count)
  377         int             dev;
  378         dev_flavor_t    flavor;
  379         dev_status_t    status;
  380         natural_t       *status_count;
  381 {
  382         target_info_t   *tgt;
  383 
  384         tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
  385 
  386         if (scsi_debug)
  387                 printf("rz_get_status: x%x x%x x%x x%x\n",
  388                         dev, flavor, status, *status_count);
  389         return (*tgt->dev_ops->get_status)(dev, tgt, flavor, status, status_count);
  390 }
  391 
  392 int rz_set_status(dev, flavor, status, status_count)
  393         int             dev;
  394         dev_flavor_t    flavor;
  395         dev_status_t    status;
  396         natural_t       status_count;
  397 {
  398         target_info_t   *tgt;
  399 
  400         tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
  401 
  402         if (scsi_debug)
  403                 printf("rz_set_status: x%x x%x x%x x%x\n",
  404                         dev, flavor, status, status_count);
  405         return (*tgt->dev_ops->set_status)(dev, tgt, flavor, status, status_count);
  406 }
  407 
  408 /*
  409  *      Routine to return information to kernel.
  410  */
  411 int
  412 rz_devinfo(dev, flavor, info)
  413         int     dev;
  414         int     flavor;
  415         char    *info;
  416 {
  417         register int    result;
  418 
  419         result = D_SUCCESS;
  420 
  421         switch (flavor) {
  422         /* Caller stupidity, should use device->bsize instead */
  423         case D_INFO_BLOCK_SIZE:
  424                 *((int *) info) = scsi_softc[rzcontroller(dev)]->
  425                                   target[rzslave(dev)]->block_size;
  426                 break;
  427         default:
  428                 result = D_INVALID_OPERATION;
  429         }
  430 
  431         return(result);
  432 }
  433 
  434 void
  435 rz_simpleq_strategy(ior, start)
  436         io_req_t        ior;
  437         void            (*start)();
  438 {
  439         target_info_t  *tgt;
  440         register scsi_softc_t   *sc;
  441         scsi_ret_t      ret;
  442         register int    i = ior->io_unit;
  443         io_req_t        head, tail;
  444         spl_t           s;
  445 
  446         sc = scsi_softc[rzcontroller(i)];
  447         tgt = sc->target[rzslave(i)];
  448 
  449         ior->io_next = 0;
  450         ior->io_prev = 0;
  451 
  452         s = splbio();
  453         simple_lock(&tgt->target_lock);
  454         if (head = tgt->ior) {
  455                 /* Queue it up at the end of the list */
  456                 if (tail = head->io_prev)
  457                         tail->io_next = ior;
  458                 else
  459                         head->io_next = ior;
  460                 head->io_prev = ior;    /* tail pointer */
  461                 simple_unlock(&tgt->target_lock);
  462         } else {
  463                 /* Was empty, start operation */
  464                 tgt->ior = ior;
  465                 simple_unlock(&tgt->target_lock);
  466                 (*start)( tgt, FALSE);
  467         }
  468         splx(s);
  469 }
  470 #ifdef  MACH_KERNEL
  471 #else   /*MACH_KERNEL*/
  472 
  473 rz_strategy(ior)
  474         io_req_t        ior;
  475 {
  476         target_info_t   *tgt;
  477         register int    dev = ior->io_unit;
  478 
  479         tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
  480 
  481         return (*tgt->dev_ops->strategy)(ior);
  482 }
  483 
  484 #include <sys/ioctl.h>
  485 
  486 #define IOCPARM_SIZE(c)         (((c)>>16)&IOCPARM_MASK)
  487 #define IOC_WDSIZE(s)           ((IOCPARM_SIZE(s))>>2)
  488 
  489 rz_ioctl(dev, cmd, data, flag)
  490 {
  491         io_return_t     error;
  492         unsigned int    count;
  493 
  494         count = IOC_WDSIZE(cmd);
  495         if (cmd & (IOC_VOID|IOC_IN)) {
  496             error = rz_set_status(dev, cmd, (dev_status_t)data, count);
  497             if (error)
  498                 return (error);
  499         }
  500         if (cmd & IOC_OUT) {
  501             error = rz_get_status(dev, cmd, (dev_status_t *)data, &count);
  502             if (error)
  503                 return (error);
  504         }
  505         return (0);
  506 }
  507 
  508 /* This is a very simple-minded config,
  509  * assumes we have << 8 disks per bus */
  510 #define NBUF    (NSCSI*8)
  511 struct  io_req  rz_buffers[NBUF];
  512 
  513 static io_req_t
  514 getbp(dev)
  515 {
  516         io_req_t        ior;
  517         int             hash = minor(dev) >> 3;
  518 
  519         ior = &rz_buffers[hash];
  520         if (ior->io_op & IO_BUSY) {
  521                 register io_req_t ior;
  522                 for (ior = rz_buffers; ior < &rz_buffers[NBUF]; ior++)
  523                         if ((ior->io_op & IO_BUSY) == 0)
  524                                 return ior;
  525                 
  526         }
  527         return ior;
  528 }
  529 
  530 /*
  531  * This ugliness is only needed because of the
  532  * way the minor is encoded for tapes.
  533  */
  534 tz_open(dev, mode, ior)
  535         int             dev;
  536         dev_mode_t      mode;
  537         io_req_t        ior;
  538 {
  539         io_return_t     error;
  540 
  541         error = rz_open(TAPE_UNIT(dev), mode, ior);
  542         if(error)
  543                 return error;
  544         if (TAPE_REWINDS(dev)) {
  545                 scsi_softc_t    *sc;
  546                 target_info_t   *tgt;
  547 
  548                 rz_check(TAPE_UNIT(dev), &sc, &tgt);
  549                 tgt->flags |= TGT_REWIND_ON_CLOSE;
  550         }
  551         return 0;
  552 }
  553 
  554 tz_close(dev) { return rz_close(TAPE_UNIT(dev));}
  555 tz_read(dev, ior) { return rz_read(TAPE_UNIT(dev), ior);}
  556 tz_write(dev, ior) { return rz_write(TAPE_UNIT(dev), ior);}
  557 tz_ioctl(dev, cmd, data, flag) { return rz_ioctl(TAPE_UNIT(dev), cmd, data, flag);}
  558 
  559 #endif  /*MACH_KERNEL*/
  560 
  561 #endif  (NSCSI>0)

Cache object: fb21e979c39edcccf0ae4bffd8c6a329


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