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/i386/isa/wfd.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  * Copyright (c) 1997,1998  Junichi Satoh <junichi@astec.co.jp>
    3  *   All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer as
   10  *    the first lines of this file unmodified.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY Junichi Satoh ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL Junichi Satoh BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  */
   28 
   29 /*
   30  * ATAPI Floppy, LS-120 driver
   31  */
   32 
   33 #include "wdc.h"
   34 #include "wfd.h"
   35 #include "opt_atapi.h"
   36 
   37 #if NWFD > 0 && NWDC > 0 && defined (ATAPI)
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/kernel.h>
   42 #include <sys/conf.h>
   43 #include <sys/proc.h>
   44 #include <sys/malloc.h>
   45 #include <sys/buf.h>
   46 #include <sys/devicestat.h>
   47 #include <sys/disklabel.h>
   48 #include <sys/diskslice.h>
   49 #include <sys/cdio.h>
   50 #ifdef DEVFS
   51 #include <sys/devfsext.h>
   52 #endif /*DEVFS*/
   53 
   54 #include <i386/isa/atapi.h>
   55 
   56 static  d_open_t        wfdopen;
   57 static  d_read_t        wfdread;
   58 static  d_write_t       wfdwrite;
   59 static  d_close_t       wfdclose;
   60 static  d_ioctl_t       wfdioctl;
   61 static  d_strategy_t    wfdstrategy;
   62 
   63 #define CDEV_MAJOR 87
   64 #define BDEV_MAJOR 1
   65 
   66 static struct cdevsw wfd_cdevsw = {
   67           wfdopen,      wfdclose,       wfdread,        wfdwrite,
   68           wfdioctl,     nostop,         nullreset,      nodevtotty,
   69           seltrue,      nommap,         wfdstrategy,    "wfd",
   70           NULL,         -1,             nodump,         nopsize,
   71           D_DISK,       0,              -1 };
   72 
   73 #ifndef ATAPI_STATIC
   74 static
   75 #endif
   76 int  wfdattach(struct atapi*, int, struct atapi_params*, int);
   77 
   78 #define NUNIT   (NWDC*2)                /* Max. number of devices */
   79 #define UNIT(d) ((minor(d) >> 3) & 3)   /* Unit part of minor device number */
   80 
   81 #define F_BOPEN         0x0001          /* The block device is opened */
   82 #define F_MEDIA_CHANGED 0x0002          /* The media have changed since open */
   83 #define F_DEBUG         0x0004          /* Print debug info */
   84 
   85 /*
   86  * LS-120 Capabilities and Mechanical Status Page
   87  */
   88 struct cappage {
   89     /* Mode data header */
   90     u_short     data_length;
   91     u_char      medium_type;
   92 #define MDT_UNKNOWN     0x00
   93 #define MDT_NO_DISC     0x70
   94 #define MDT_DOOR_OPEN   0x71
   95 #define MDT_FMT_ERROR   0x72
   96 
   97 #define MDT_2DD_UN      0x10
   98 #define MDT_2DD         0x11
   99 #define MDT_2HD_UN      0x20
  100 #define MDT_2HD_12_98   0x22
  101 #define MDT_2HD_12      0x23
  102 #define MDT_2HD_144     0x24
  103 #define MDT_LS120       0x31
  104 
  105     unsigned        reserved0       :7;
  106     unsigned        wp              :1;     /* Write protect */
  107     u_char          reserved1[4];
  108 
  109     /* Capabilities page */
  110     unsigned        page_code       :6;     /* Page code - Should be 0x5 */
  111 #define CAP_PAGE        0x05
  112     unsigned        reserved1_6     :1;     /* Reserved */
  113     unsigned        ps              :1;     /* The device is capable of saving the page */
  114     u_char          page_length;            /* Page Length - Should be 0x1e */
  115     u_short         transfer_rate;          /* In kilobits per second */
  116     u_char          heads, sectors;         /* Number of heads, Number of sectors per track */
  117     u_short         sector_size;            /* Byes per sector */
  118     u_short         cyls;                   /* Number of cylinders */
  119     u_char          reserved10[10];
  120     u_char          motor_delay;            /* Motor off delay */
  121     u_char          reserved21[7];
  122     u_short         rpm;                    /* Rotations per minute */
  123     u_char          reserved30[2];
  124 };
  125 
  126 /* misuse a flag to identify format operation */
  127 #define B_FORMAT B_XXX
  128 
  129 struct wfd {
  130         struct atapi *ata;              /* Controller structure */
  131         int unit;                       /* IDE bus drive unit */
  132         int lun;                        /* Logical device unit */
  133         int flags;                      /* Device state flags */
  134         int refcnt;                     /* The number of raw opens */
  135         int maxblks;                    /* transfer size limit */
  136         struct buf_queue_head buf_queue;  /* Queue of i/o requests */
  137         struct atapi_params *param;     /* Drive parameters table */
  138         struct cappage cap;             /* Capabilities page info */
  139         char description[80];           /* Device description */
  140 #ifdef  DEVFS
  141         void    *cdevs;
  142         void    *bdevs;
  143 #endif
  144         struct diskslices *dk_slices;   /* virtual drives */
  145 
  146         struct devstat device_stats;
  147 };
  148 
  149 static struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */
  150 static int wfdnlun = 0;           /* Number of configured drives */
  151 
  152 static void wfd_start (struct wfd *t);
  153 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
  154         struct atapires result);
  155 static void wfd_error (struct wfd *t, struct atapires result);
  156 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
  157         u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
  158         u_char a9, char *addr, int count);
  159 static void wfd_describe (struct wfd *t);
  160 static int wfd_eject (struct wfd *t, int closeit);
  161 static void wfdstrategy1(struct buf *bp);
  162 
  163 /*
  164  * Dump the array in hexadecimal format for debugging purposes.
  165  */
  166 static void wfd_dump (int lun, char *label, void *data, int len)
  167 {
  168         u_char *p = data;
  169 
  170         printf ("wfd%d: %s %x", lun, label, *p++);
  171         while (--len > 0)
  172                 printf ("-%x", *p++);
  173         printf ("\n");
  174 }
  175 
  176 #ifndef ATAPI_STATIC
  177 static
  178 #endif
  179 int 
  180 wfdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
  181 {
  182         struct wfd *t;
  183         struct atapires result;
  184         int lun, i;
  185 
  186 #ifdef DEVFS
  187         int     mynor;
  188 #endif
  189         if (wfdnlun >= NUNIT) {
  190                 printf ("wfd: too many units\n");
  191                 return (0);
  192         }
  193         if (!atapi_request_immediate) {
  194                 printf("wfd: configuration error, ATAPI core code not present!\n");
  195                 printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n");
  196                 return (0);
  197         }
  198         t = malloc (sizeof (struct wfd), M_TEMP, M_NOWAIT);
  199         if (! t) {
  200                 printf ("wfd: out of memory\n");
  201                 return (0);
  202         }
  203         wfdtab[wfdnlun] = t;
  204         bzero (t, sizeof (struct wfd));
  205         bufq_init(&t->buf_queue);
  206         t->ata = ata;
  207         t->unit = unit;
  208         lun = t->lun = wfdnlun;
  209         t->param = ap;
  210         t->flags = F_MEDIA_CHANGED;
  211         t->refcnt = 0;
  212         if (debug) {
  213                 t->flags |= F_DEBUG;
  214                 /* Print params. */
  215                 wfd_dump (t->lun, "info", ap, sizeof *ap);
  216         }
  217 
  218         /* Get drive capabilities. */
  219         /* Do it twice to avoid the stale media changed state. */
  220         for (i = 0; i < 2; i++) {
  221                 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
  222                         0, CAP_PAGE, 0, 0, 0, 0, 
  223                         sizeof (t->cap) >> 8, sizeof (t->cap),
  224                         0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
  225         }
  226 
  227         if (result.code == RES_ERR &&
  228             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
  229                 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
  230                         0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
  231                         sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
  232                         (char*) &t->cap, sizeof (t->cap));
  233 
  234         /* Some drives have shorter capabilities page. */
  235         if (result.code == RES_UNDERRUN)
  236                 result.code = 0;
  237 
  238         if (result.code == 0) {
  239                 wfd_describe (t);
  240                 if (t->flags & F_DEBUG)
  241                         wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
  242         } else
  243                 return -1;
  244 
  245         /*
  246          * The IOMEGA ZIP 100, at firmware 21.* and 23.* at least
  247          * is known to lock up if transfers > 64 blocks are
  248          * requested.
  249          */
  250         if (!strcmp(ap->model, "IOMEGA  ZIP 100       ATAPI")) {
  251                 printf("wfd%d: buggy Zip drive, 64-block transfer limit set\n",
  252                        t->lun);
  253                 t->maxblks = 64;
  254         } else {
  255                 t->maxblks = 0; /* no limit */
  256         }
  257         
  258         
  259 
  260 #ifdef DEVFS
  261         mynor = dkmakeminor(t->lun, WHOLE_DISK_SLICE, RAW_PART);
  262         t->bdevs = devfs_add_devswf(&wfd_cdevsw, mynor, 
  263                                     DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
  264                                     "wfd%d", t->lun);
  265         t->cdevs = devfs_add_devswf(&wfd_cdevsw, mynor, 
  266                                     DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
  267                                     "rwfd%d", t->lun);
  268 #endif /* DEVFS */
  269 
  270         /*
  271          * Export the drive to the devstat interface.
  272          */
  273         devstat_add_entry(&t->device_stats, "wfd", 
  274                           t->lun, t->cap.sector_size,
  275                           DEVSTAT_NO_ORDERED_TAGS,
  276                           DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_IDE,
  277                           DEVSTAT_PRIORITY_WFD);
  278         wfdnlun++;
  279         return (1);
  280 }
  281 
  282 void wfd_describe (struct wfd *t)
  283 {
  284         int no_print = 0;
  285 
  286         t->cap.cyls = ntohs (t->cap.cyls);
  287         t->cap.sector_size = ntohs (t->cap.sector_size);
  288 
  289         printf ("wfd%d: ", t->lun);
  290         switch (t->cap.medium_type) {
  291         case MDT_UNKNOWN:
  292                 printf ("medium type unknown (no disk)");
  293                 no_print = 1;
  294                 break;
  295         case MDT_2DD_UN:
  296                 printf ("2DD(capacity unknown) floppy disk loaded");
  297                 no_print = 1;
  298                 break;
  299         case MDT_2DD:
  300                 printf ("720KB floppy disk loaded");
  301                 break;
  302         case MDT_2HD_UN:
  303                 printf ("2HD(capacity unknown) floppy disk loaded");
  304                 no_print = 1;
  305                 break;
  306         case MDT_2HD_12_98:
  307                 printf ("1.25MB(PC-9801 format) floppy disk loaded");
  308                 break;
  309         case MDT_2HD_12:
  310                 printf ("1.2MB floppy disk loaded");
  311                 break;
  312         case MDT_2HD_144:
  313                 printf ("1.44MB floppy disk loaded");
  314                 break;
  315         case MDT_LS120:
  316                 printf ("120MB floppy disk loaded");
  317                 break;
  318         case MDT_NO_DISC:
  319                 printf ("no disc inside");
  320                 no_print = 1;
  321                 break;
  322         case MDT_DOOR_OPEN:
  323                 printf ("door open");
  324                 no_print = 1;
  325                 break;
  326         case MDT_FMT_ERROR:
  327                 printf ("medium format error");
  328                 no_print = 1;
  329                 break;
  330         default:
  331                 printf ("medium type=0x%x", t->cap.medium_type);
  332                 break;
  333         }
  334         if (t->cap.wp)
  335                 printf(", write protected");
  336         printf ("\n");
  337 
  338         if (!no_print) {
  339                 printf ("wfd%d: ", t->lun);
  340                 printf ("%u cyls", t->cap.cyls);
  341                 printf (", %u heads, %u S/T", t->cap.heads, t->cap.sectors);
  342                 printf (", %u B/S", t->cap.sector_size);
  343                 printf ("\n");
  344         }
  345 }
  346 
  347 int wfdopen (dev_t dev, int flags, int fmt, struct proc *p)
  348 {
  349         int lun = UNIT(dev);
  350         struct wfd *t;
  351         struct atapires result;
  352         int errcode = 0;
  353         struct disklabel label;
  354 
  355         /* Check that the device number is legal
  356          * and the ATAPI driver is loaded. */
  357         if (lun >= wfdnlun || ! atapi_request_immediate)
  358                 return (ENXIO);
  359         t = wfdtab[lun];
  360 
  361         t->flags &= ~F_MEDIA_CHANGED;
  362         /* Lock the media. */
  363         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  364                           0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  365 
  366         /* Sense the media type */
  367         result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE,
  368                                      0, CAP_PAGE, 0, 0, 0, 0, 
  369                                      sizeof (t->cap) >> 8, sizeof (t->cap),
  370                                      0, 0, 0, 0, 0, 0, 0, 
  371                                      (char*) &t->cap, sizeof (t->cap));
  372         if (result.code)
  373                 printf ("wfd%d: Sense the media type is failed.\n", t->lun);
  374         else {
  375                 t->cap.cyls = ntohs (t->cap.cyls);
  376                 t->cap.sector_size = ntohs (t->cap.sector_size);
  377         }
  378 
  379         /* Build label for whole disk. */
  380         bzero(&label, sizeof label);
  381         label.d_secsize = t->cap.sector_size;
  382         label.d_nsectors = t->cap.sectors;
  383         label.d_ntracks = t->cap.heads;
  384         label.d_ncylinders = t->cap.cyls;
  385         label.d_secpercyl = t->cap.heads * t->cap.sectors;
  386         label.d_rpm = 720;
  387         label.d_secperunit = label.d_secpercyl * t->cap.cyls;
  388 
  389         /* Initialize slice tables. */
  390         errcode = dsopen("wfd", dev, fmt, 0, &t->dk_slices, &label,
  391                          wfdstrategy1, (ds_setgeom_t *)NULL, &wfd_cdevsw);
  392         if (errcode != 0)
  393                 return errcode;
  394 
  395         t->flags |= F_BOPEN;
  396         return (0);
  397 }
  398 
  399 /*
  400  * Close the device.  Only called if we are the LAST
  401  * occurence of an open device.
  402  */
  403 int wfdclose (dev_t dev, int flags, int fmt, struct proc *p)
  404 {
  405         int lun = UNIT(dev);
  406         struct wfd *t = wfdtab[lun];
  407 
  408         dsclose(dev, fmt, t->dk_slices);
  409         if(!dsisopen(t->dk_slices)) {
  410                 /* If we were the last open of the entire device, release it. */
  411                 if (! t->refcnt)
  412                         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  413                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  414                 t->flags &= ~F_BOPEN;
  415         }
  416         return (0);
  417 }
  418 
  419 static int
  420 wfdread(dev_t dev, struct uio *uio, int ioflag)
  421 {
  422         return (physio(wfdstrategy, NULL, dev, 1, minphys, uio));
  423 }
  424 
  425 static int
  426 wfdwrite(dev_t dev, struct uio *uio, int ioflag)
  427 {
  428         return (physio(wfdstrategy, NULL, dev, 0, minphys, uio));
  429 }
  430 
  431 static void
  432 wfdstrategy1(struct buf *bp)
  433 {
  434         /*
  435          * XXX - do something to make wdstrategy() but not this block while
  436          * we're doing dsinit() and dsioctl().
  437          */
  438         wfdstrategy(bp);
  439 }
  440 
  441 /*
  442  * Actually translate the requested transfer into one the physical driver can
  443  * understand. The transfer is described by a buf and will include only one
  444  * physical transfer.
  445  */
  446 void wfdstrategy (struct buf *bp)
  447 {
  448         int lun = UNIT(bp->b_dev);
  449         struct wfd *t = wfdtab[lun];
  450         int x;
  451 
  452         /* If it's a null transfer, return immediatly. */
  453         if (bp->b_bcount == 0) {
  454                 bp->b_resid = 0;
  455                 biodone (bp);
  456                 return;
  457         }
  458 
  459         /*
  460          * Do bounds checking, adjust transfer, and set b_pblkno.
  461          */
  462         if (dscheck(bp, t->dk_slices) <= 0) {
  463                 biodone(bp);
  464                 return;
  465         }
  466 
  467         x = splbio();
  468 
  469         /* Place it in the queue of disk activities for this disk. */
  470         bufqdisksort (&t->buf_queue, bp);
  471 
  472         /* Tell the device to get going on the transfer if it's
  473          * not doing anything, otherwise just wait for completion. */
  474         wfd_start (t);
  475         splx(x);
  476 }
  477 
  478 /*
  479  * Look to see if there is a buf waiting for the device
  480  * and that the device is not already busy. If both are true,
  481  * It dequeues the buf and creates an ATAPI command to perform the
  482  * transfer in the buf.
  483  * The bufs are queued by the strategy routine (wfdstrategy).
  484  * Must be called at the correct (splbio) level.
  485  */
  486 static void wfd_start (struct wfd *t)
  487 {
  488         struct buf *bp = bufq_first(&t->buf_queue);
  489         u_long blkno, nblk;
  490         u_char op_code;
  491         long count;
  492         int pxcount, pxnblk;
  493         u_char *pxdest;
  494         
  495 
  496         /* See if there is a buf to do and we are not already doing one. */
  497         if (! bp)
  498                 return;
  499 
  500         /* Unqueue the request. */
  501         bufq_remove(&t->buf_queue, bp);
  502 
  503         /* Tell devstat we are starting on the transaction */
  504         devstat_start_transaction(&t->device_stats);
  505 
  506         /* We have a buf, now we should make a command
  507          * First, translate the block to absolute and put it in terms of the
  508          * logical blocksize of the device. */
  509         blkno = bp->b_pblkno / (t->cap.sector_size / 512);
  510         nblk = (bp->b_bcount + (t->cap.sector_size - 1)) / t->cap.sector_size;
  511 
  512         if ((t->maxblks == 0) || (nblk <= t->maxblks)) {
  513 
  514                 if(bp->b_flags & B_READ) {
  515                         op_code = ATAPI_READ_BIG;
  516                         count = bp->b_bcount;
  517                 } else {
  518                         op_code = ATAPI_WRITE_BIG;
  519                         count = -bp->b_bcount;
  520                 }
  521 
  522                 /* only one transfer */
  523                 (int)bp->b_driver1 = 0;
  524                 (int)bp->b_driver2 = 0;
  525                 atapi_request_callback (t->ata, t->unit, op_code, 0,
  526                                         blkno>>24, blkno>>16, blkno>>8, blkno,
  527                                         0, nblk>>8, nblk, 0, 0,
  528                                         0, 0, 0, 0, 0, 
  529                                         (u_char*) bp->b_data, count, 
  530                                         (void*)wfd_done, t, bp);
  531         } else {
  532 
  533                 /*
  534                  * We can't handle this request in a single
  535                  * read/write operation.  Instead, queue a set of
  536                  * transfers, and record the number of transfers
  537                  * and the running residual in the b_driver
  538                  * fields of the bp.
  539                  */ 
  540 
  541                 if(bp->b_flags & B_READ) {
  542                         op_code = ATAPI_READ_BIG;
  543                 } else {
  544                         op_code = ATAPI_WRITE_BIG;
  545                 }
  546 
  547                 /* calculate number of transfers */
  548                 (int)bp->b_driver1 = (nblk - 1) / t->maxblks;
  549                 (int)bp->b_driver2 = 0;
  550 
  551                 pxdest = (u_char *)bp->b_data;
  552                 pxcount = bp->b_bcount;
  553 
  554                 /* construct partial transfer requests */
  555                 while (nblk > 0) {
  556                         pxnblk = min(nblk, t->maxblks);
  557                         count = min(pxcount, t->maxblks * t->cap.sector_size);
  558 
  559                         atapi_request_callback(t->ata, t->unit, op_code, 0,
  560                                                blkno>>24, blkno>>16, blkno>>8,
  561                                                blkno, 0, pxnblk>>8, pxnblk, 
  562                                                0, 0, 0, 0, 0, 0, 0,
  563                                                pxdest, 
  564                                                (bp->b_flags & B_READ) ?
  565                                                count : -count, 
  566                                                (void*)wfd_done, t, bp);
  567                         nblk -= pxnblk;
  568                         pxcount -= count;
  569                         pxdest += count;
  570                         blkno += pxnblk;
  571                 }
  572         }
  573 }
  574 
  575 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
  576         struct atapires result)
  577 {
  578                 
  579         if (result.code) {
  580                 wfd_error (t, result);
  581                 bp->b_error = EIO;
  582                 bp->b_flags |= B_ERROR;
  583         } else
  584                 (int)bp->b_driver2 += resid;
  585         /*
  586          * We can't call biodone until all outstanding
  587          * transfer fragments are handled.  If one hits
  588          * an error, we will be returning an error, but
  589          * only when all are complete.
  590          */
  591         if (((int)bp->b_driver1)-- <= 0) {
  592                 bp->b_resid = (int)bp->b_driver2;
  593 
  594                 /* Tell devstat we have finished with the transaction */
  595                 devstat_end_transaction(&t->device_stats,
  596                                         bp->b_bcount - bp->b_resid,
  597                                         DEVSTAT_TAG_NONE,
  598                                         (bp->b_flags & B_READ) ? DEVSTAT_READ : DEVSTAT_WRITE);
  599 
  600                 biodone (bp);
  601         }
  602         
  603         wfd_start (t);
  604 }
  605 
  606 static void wfd_error (struct wfd *t, struct atapires result)
  607 {
  608         if (result.code != RES_ERR)
  609                 return;
  610         switch (result.error & AER_SKEY) {
  611         case AER_SK_NOT_READY:
  612                 if (result.error & ~AER_SKEY) {
  613                         /* Not Ready */
  614                         printf ("wfd%d: not ready\n", t->lun);
  615                         return;
  616                 }
  617                 /* Tray open. */
  618                 if (! (t->flags & F_MEDIA_CHANGED))
  619                         printf ("wfd%d: tray open\n", t->lun);
  620                 t->flags |= F_MEDIA_CHANGED;
  621                 return;
  622 
  623         case AER_SK_UNIT_ATTENTION:
  624                 /* Media changed. */
  625                 if (! (t->flags & F_MEDIA_CHANGED))
  626                         printf ("wfd%d: media changed\n", t->lun);
  627                 t->flags |= F_MEDIA_CHANGED;
  628                 return;
  629 
  630         case AER_SK_ILLEGAL_REQUEST:
  631                 /* Unknown command or invalid command arguments. */
  632                 if (t->flags & F_DEBUG)
  633                         printf ("wfd%d: invalid command\n", t->lun);
  634                 return;
  635         }
  636         printf ("wfd%d: i/o error, status=%b, error=%b\n", t->lun,
  637                 result.status, ARS_BITS, result.error, AER_BITS);
  638 }
  639 
  640 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
  641         u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
  642         u_char a9, char *addr, int count)
  643 {
  644         struct atapires result;
  645 
  646         result = atapi_request_wait (t->ata, t->unit, cmd,
  647                 a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
  648                 addr, count);
  649         if (result.code) {
  650                 wfd_error (t, result);
  651                 return (EIO);
  652         }
  653         return (0);
  654 }
  655 
  656 /*
  657  * Perform special action on behalf of the user.
  658  * Knows about the internals of this device
  659  */
  660 int wfdioctl (dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
  661 {
  662         int lun = UNIT(dev);
  663         struct wfd *t = wfdtab[lun];
  664         int error = 0;
  665 
  666         error = dsioctl("wfd", dev, cmd, addr, flag, &t->dk_slices,
  667                         wfdstrategy1, (ds_setgeom_t *)NULL);
  668         if (error != ENOIOCTL)
  669                 return (error);
  670 
  671         if (t->flags & F_MEDIA_CHANGED)
  672                 switch (cmd) {
  673                 case CDIOCSETDEBUG:
  674                 case CDIOCCLRDEBUG:
  675                 case CDIOCRESET:
  676                         /* These ops are media change transparent. */
  677                         break;
  678                 default:
  679                         /* Lock the media. */
  680                         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  681                                 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  682                         break;
  683                 }
  684         switch (cmd) {
  685         case CDIOCSETDEBUG:
  686                 if (p->p_cred->pc_ucred->cr_uid)
  687                         return (EPERM);
  688                 t->flags |= F_DEBUG;
  689                 atapi_debug (t->ata, 1);
  690                 return 0;
  691         case CDIOCCLRDEBUG:
  692                 if (p->p_cred->pc_ucred->cr_uid)
  693                         return (EPERM);
  694                 t->flags &= ~F_DEBUG;
  695                 atapi_debug (t->ata, 0);
  696                 return 0;
  697         case CDIOCRESET:
  698                 if (p->p_cred->pc_ucred->cr_uid)
  699                         return (EPERM);
  700                 return wfd_request_wait (t, ATAPI_TEST_UNIT_READY,
  701                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  702         case CDIOCEJECT:
  703                 /* Don't allow eject if the device is opened
  704                  * by somebody (not us) in block mode. */
  705                 if ((t->flags & F_BOPEN) && t->refcnt)
  706                         return (EBUSY);
  707                 return wfd_eject (t, 0);
  708         case CDIOCCLOSE:
  709                 if ((t->flags & F_BOPEN) && t->refcnt)
  710                         return (0);
  711                 return wfd_eject (t, 1);
  712         default:
  713                 return (ENOTTY);
  714         }
  715         return (error);
  716 }
  717 
  718 static int wfd_eject (struct wfd *t, int closeit)
  719 {
  720         struct atapires result;
  721 
  722         /* Try to stop the disc. */
  723         result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
  724                 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  725 
  726         if (result.code == RES_ERR &&
  727             ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
  728             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
  729                 int err;
  730 
  731                 if (!closeit)
  732                         return (0);
  733                 /*
  734                  * The disc was unloaded.
  735                  * Load it (close tray).
  736                  * Read the table of contents.
  737                  */
  738                 err = wfd_request_wait (t, ATAPI_START_STOP,
  739                         0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
  740                 if (err)
  741                         return (err);
  742 
  743                 /* Lock the media. */
  744                 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  745                         0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  746 
  747                 return (0);
  748         }
  749 
  750         if (result.code) {
  751                 wfd_error (t, result);
  752                 return (EIO);
  753         }
  754 
  755         if (closeit)
  756                 return (0);
  757 
  758         /* Give it some time to stop spinning. */
  759         tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej1", 0);
  760         tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej2", 0);
  761 
  762         /* Unlock. */
  763         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  764                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  765 
  766         /* Eject. */
  767         t->flags |= F_MEDIA_CHANGED;
  768         return wfd_request_wait (t, ATAPI_START_STOP,
  769                 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
  770 }
  771 
  772 #ifdef WFD_MODULE
  773 /*
  774  * Loadable ATAPI Floppy driver stubs.
  775  */
  776 #include <sys/exec.h>
  777 #include <sys/sysent.h>
  778 #include <sys/lkm.h>
  779 
  780 /*
  781  * Construct lkm_dev structures (see lkm.h).
  782  * Our bdevsw/cdevsw slot numbers are 19/69.
  783  */
  784 
  785 
  786 MOD_DEV(wfd, LM_DT_BLOCK, BDEV_MAJOR, &wfd_cdevsw);
  787 MOD_DEV(rwfd, LM_DT_CHAR, CDEV_MAJOR, &wfd_cdevsw);
  788 
  789 /*
  790  * Function called when loading the driver.
  791  */
  792 int wfd_load (struct lkm_table *lkmtp, int cmd)
  793 {
  794         struct atapi *ata;
  795         int n, u;
  796 
  797         if (! atapi_start)
  798                 /* No ATAPI driver available. */
  799                 return EPROTONOSUPPORT;
  800         n = 0;
  801         for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
  802                 if (ata->port)
  803                         for (u=0; u<2; ++u)
  804                                 /* Probing controller ata->ctrlr, unit u. */
  805                                 if (ata->params[u] && ! ata->attached[u] &&
  806                                     wfdattach (ata, u, ata->params[u],
  807                                     ata->debug) >= 0)
  808                                 {
  809                                         /* Drive found. */
  810                                         ata->attached[u] = 1;
  811                                         ++n;
  812                                 }
  813         if (! n)
  814                 /* No IDE Floppies found. */
  815                 return ENXIO;
  816         return 0;
  817 }
  818 
  819 /*
  820  * Function called when unloading the driver.
  821  */
  822 int wfd_unload (struct lkm_table *lkmtp, int cmd)
  823 {
  824         struct wfd **t;
  825 
  826         for (t=wfdtab; t<wfdtab+wfdnlun; ++t)
  827                 if (((*t)->flags & F_BOPEN) || (*t)->refcnt)
  828                         /* The device is opened, cannot unload the driver. */
  829                         return EBUSY;
  830         for (t=wfdtab; t<wfdtab+wfdnlun; ++t) {
  831                 (*t)->ata->attached[(*t)->unit] = 0;
  832                 free (*t, M_TEMP);
  833         }
  834         wfdnlun = 0;
  835         bzero (wfdtab, sizeof(wfdtab));
  836         return 0;
  837 }
  838 
  839 /*
  840  * Dispatcher function for the module (load/unload/stat).
  841  */
  842 int wfd_mod (struct lkm_table *lkmtp, int cmd, int ver)
  843 {
  844         int err = 0;
  845 
  846         if (ver != LKM_VERSION)
  847                 return EINVAL;
  848 
  849         if (cmd == LKM_E_LOAD)
  850                 err = wfd_load (lkmtp, cmd);
  851         else if (cmd == LKM_E_UNLOAD)
  852                 err = wfd_unload (lkmtp, cmd);
  853         if (err)
  854                 return err;
  855 
  856         /* XXX Poking around in the LKM internals like this is bad.
  857          */
  858         /* Register the cdevsw entry. */
  859         lkmtp->private.lkm_dev = & MOD_PRIVATE(rwfd);
  860         err = lkmdispatch (lkmtp, cmd);
  861         if (err)
  862                 return err;
  863 
  864         /* Register the bdevsw entry. */
  865         lkmtp->private.lkm_dev = & MOD_PRIVATE(wfd);
  866         return lkmdispatch (lkmtp, cmd);
  867 }
  868 #endif /* WFD_MODULE */
  869 
  870 static wfd_devsw_installed = 0;
  871 
  872 static void     wfd_drvinit(void *unused)
  873 {
  874         if( ! wfd_devsw_installed ) {
  875                 cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &wfd_cdevsw);
  876                 wfd_devsw_installed = 1;
  877         }
  878 }
  879 
  880 SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)
  881 
  882 
  883 #endif /* NWFD && NWDC && ATAPI */

Cache object: e1ef42ade6f18dd286a9afa136bc6149


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