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 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/conf.h>
   39 #include <sys/proc.h>
   40 #include <sys/malloc.h>
   41 #include <sys/buf.h>
   42 #include <sys/devicestat.h>
   43 #include <sys/disklabel.h>
   44 #include <sys/diskslice.h>
   45 #include <sys/cdio.h>
   46 
   47 #include <i386/isa/atapi.h>
   48 
   49 static  d_open_t        wfdopen;
   50 static  d_close_t       wfdclose;
   51 static  d_ioctl_t       wfdioctl;
   52 static  d_strategy_t    wfdstrategy;
   53 
   54 #define CDEV_MAJOR 87
   55 #define BDEV_MAJOR 1
   56 
   57 static struct cdevsw wfd_cdevsw = {
   58         /* open */      wfdopen,
   59         /* close */     wfdclose,
   60         /* read */      physread,
   61         /* write */     physwrite,
   62         /* ioctl */     wfdioctl,
   63         /* poll */      nopoll,
   64         /* mmap */      nommap,
   65         /* strategy */  wfdstrategy,
   66         /* name */      "wfd",
   67         /* maj */       CDEV_MAJOR,
   68         /* dump */      nodump,
   69         /* psize */     nopsize,
   70         /* flags */     D_DISK,
   71         /* bmaj */      BDEV_MAJOR
   72 };
   73 
   74 int  wfdattach(struct atapi*, int, struct atapi_params*, int);
   75 
   76 #define NUNIT   (NWDC*2)                /* Max. number of devices */
   77 #define UNIT(d) ((minor(d) >> 3) & 3)   /* Unit part of minor device number */
   78 
   79 #define F_BOPEN         0x0001          /* The block device is opened */
   80 #define F_MEDIA_CHANGED 0x0002          /* The media have changed since open */
   81 #define F_DEBUG         0x0004          /* Print debug info */
   82 
   83 /*
   84  * LS-120 Capabilities and Mechanical Status Page
   85  */
   86 struct cappage {
   87     /* Mode data header */
   88     u_short     data_length;
   89     u_char      medium_type;
   90 #define MDT_UNKNOWN     0x00
   91 #define MDT_NO_DISC     0x70
   92 #define MDT_DOOR_OPEN   0x71
   93 #define MDT_FMT_ERROR   0x72
   94 
   95 #define MDT_2DD_UN      0x10
   96 #define MDT_2DD         0x11
   97 #define MDT_2HD_UN      0x20
   98 #define MDT_2HD_12_98   0x22
   99 #define MDT_2HD_12      0x23
  100 #define MDT_2HD_144     0x24
  101 #define MDT_LS120       0x31
  102 
  103     unsigned        reserved0       :7;
  104     unsigned        wp              :1;     /* Write protect */
  105     u_char          reserved1[4];
  106 
  107     /* Capabilities page */
  108     unsigned        page_code       :6;     /* Page code - Should be 0x5 */
  109 #define CAP_PAGE        0x05
  110     unsigned        reserved1_6     :1;     /* Reserved */
  111     unsigned        ps              :1;     /* The device is capable of saving the page */
  112     u_char          page_length;            /* Page Length - Should be 0x1e */
  113     u_short         transfer_rate;          /* In kilobits per second */
  114     u_char          heads, sectors;         /* Number of heads, Number of sectors per track */
  115     u_short         sector_size;            /* Byes per sector */
  116     u_short         cyls;                   /* Number of cylinders */
  117     u_char          reserved10[10];
  118     u_char          motor_delay;            /* Motor off delay */
  119     u_char          reserved21[7];
  120     u_short         rpm;                    /* Rotations per minute */
  121     u_char          reserved30[2];
  122 };
  123 
  124 struct wfd {
  125         struct atapi *ata;              /* Controller structure */
  126         int unit;                       /* IDE bus drive unit */
  127         int lun;                        /* Logical device unit */
  128         int flags;                      /* Device state flags */
  129         int refcnt;                     /* The number of raw opens */
  130         int maxblks;                    /* transfer size limit */
  131         struct buf_queue_head buf_queue;  /* Queue of i/o requests */
  132         struct atapi_params *param;     /* Drive parameters table */
  133         struct cappage cap;             /* Capabilities page info */
  134         char description[80];           /* Device description */
  135         struct diskslices *dk_slices;   /* virtual drives */
  136 
  137         struct devstat device_stats;
  138 };
  139 
  140 static struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */
  141 static int wfdnlun = 0;           /* Number of configured drives */
  142 
  143 static void wfd_start (struct wfd *t);
  144 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
  145         struct atapires result);
  146 static void wfd_error (struct wfd *t, struct atapires result);
  147 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
  148         u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
  149         u_char a9, char *addr, int count);
  150 static void wfd_describe (struct wfd *t);
  151 static int wfd_eject (struct wfd *t, int closeit);
  152 
  153 /*
  154  * Dump the array in hexadecimal format for debugging purposes.
  155  */
  156 static void wfd_dump (int lun, char *label, void *data, int len)
  157 {
  158         u_char *p = data;
  159 
  160         printf ("wfd%d: %s %x", lun, label, *p++);
  161         while (--len > 0)
  162                 printf ("-%x", *p++);
  163         printf ("\n");
  164 }
  165 
  166 int 
  167 wfdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
  168 {
  169         struct wfd *t;
  170         struct atapires result;
  171         int lun, i;
  172 
  173         if (wfdnlun >= NUNIT) {
  174                 printf ("wfd: too many units\n");
  175                 return (0);
  176         }
  177         if (!atapi_request_immediate) {
  178                 printf("wfd: configuration error, ATAPI core code not present!\n");
  179                 printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n");
  180                 return (0);
  181         }
  182         t = malloc (sizeof (struct wfd), M_TEMP, M_NOWAIT);
  183         if (! t) {
  184                 printf ("wfd: out of memory\n");
  185                 return (0);
  186         }
  187         wfdtab[wfdnlun] = t;
  188         bzero (t, sizeof (struct wfd));
  189         bufq_init(&t->buf_queue);
  190         t->ata = ata;
  191         t->unit = unit;
  192         lun = t->lun = wfdnlun;
  193         t->param = ap;
  194         t->flags = F_MEDIA_CHANGED;
  195         t->refcnt = 0;
  196         if (debug) {
  197                 t->flags |= F_DEBUG;
  198                 /* Print params. */
  199                 wfd_dump (t->lun, "info", ap, sizeof *ap);
  200         }
  201 
  202         /* Get drive capabilities. */
  203         /* Do it twice to avoid the stale media changed state. */
  204         for (i = 0; i < 2; i++) {
  205                 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
  206                         0, CAP_PAGE, 0, 0, 0, 0, 
  207                         sizeof (t->cap) >> 8, sizeof (t->cap),
  208                         0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
  209         }
  210 
  211         if (result.code == RES_ERR &&
  212             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
  213                 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
  214                         0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
  215                         sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
  216                         (char*) &t->cap, sizeof (t->cap));
  217 
  218         /* Some drives have shorter capabilities page. */
  219         if (result.code == RES_UNDERRUN)
  220                 result.code = 0;
  221 
  222         if (result.code == 0) {
  223                 wfd_describe (t);
  224                 if (t->flags & F_DEBUG)
  225                         wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
  226         } else
  227                 return -1;
  228 
  229         /*
  230          * The IOMEGA ZIP 100, at firmware 21.* and 23.* at least
  231          * is known to lock up if transfers > 64 blocks are
  232          * requested.
  233          */
  234         if (!strcmp(ap->model, "IOMEGA  ZIP 100       ATAPI")) {
  235                 printf("wfd%d: buggy Zip drive, 64-block transfer limit set\n",
  236                        t->lun);
  237                 t->maxblks = 64;
  238         } else {
  239                 t->maxblks = 0; /* no limit */
  240         }
  241         
  242         
  243 
  244         make_dev(&wfd_cdevsw, dkmakeminor(t->lun, WHOLE_DISK_SLICE, RAW_PART),
  245             UID_ROOT, GID_OPERATOR, 0640, "rwfd%d", t->lun);
  246 
  247         /*
  248          * Export the drive to the devstat interface.
  249          */
  250         devstat_add_entry(&t->device_stats, "wfd", 
  251                           t->lun, t->cap.sector_size,
  252                           DEVSTAT_NO_ORDERED_TAGS,
  253                           DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_IDE,
  254                           DEVSTAT_PRIORITY_WFD);
  255         wfdnlun++;
  256         return (1);
  257 }
  258 
  259 void wfd_describe (struct wfd *t)
  260 {
  261         int no_print = 0;
  262 
  263         t->cap.cyls = ntohs (t->cap.cyls);
  264         t->cap.sector_size = ntohs (t->cap.sector_size);
  265 
  266         printf ("wfd%d: ", t->lun);
  267         switch (t->cap.medium_type) {
  268         case MDT_UNKNOWN:
  269                 printf ("medium type unknown (no disk)");
  270                 no_print = 1;
  271                 break;
  272         case MDT_2DD_UN:
  273                 printf ("2DD(capacity unknown) floppy disk loaded");
  274                 no_print = 1;
  275                 break;
  276         case MDT_2DD:
  277                 printf ("720KB floppy disk loaded");
  278                 break;
  279         case MDT_2HD_UN:
  280                 printf ("2HD(capacity unknown) floppy disk loaded");
  281                 no_print = 1;
  282                 break;
  283         case MDT_2HD_12_98:
  284                 printf ("1.25MB(PC-9801 format) floppy disk loaded");
  285                 break;
  286         case MDT_2HD_12:
  287                 printf ("1.2MB floppy disk loaded");
  288                 break;
  289         case MDT_2HD_144:
  290                 printf ("1.44MB floppy disk loaded");
  291                 break;
  292         case MDT_LS120:
  293                 printf ("120MB floppy disk loaded");
  294                 break;
  295         case MDT_NO_DISC:
  296                 printf ("no disc inside");
  297                 no_print = 1;
  298                 break;
  299         case MDT_DOOR_OPEN:
  300                 printf ("door open");
  301                 no_print = 1;
  302                 break;
  303         case MDT_FMT_ERROR:
  304                 printf ("medium format error");
  305                 no_print = 1;
  306                 break;
  307         default:
  308                 printf ("medium type=0x%x", t->cap.medium_type);
  309                 break;
  310         }
  311         if (t->cap.wp)
  312                 printf(", write protected");
  313         printf ("\n");
  314 
  315         if (!no_print) {
  316                 printf ("wfd%d: ", t->lun);
  317                 printf ("%u cyls", t->cap.cyls);
  318                 printf (", %u heads, %u S/T", t->cap.heads, t->cap.sectors);
  319                 printf (", %u B/S", t->cap.sector_size);
  320                 printf ("\n");
  321         }
  322 }
  323 
  324 int wfdopen (dev_t dev, int flags, int fmt, struct proc *p)
  325 {
  326         int lun = UNIT(dev);
  327         struct wfd *t;
  328         struct atapires result;
  329         int errcode = 0;
  330         struct disklabel label;
  331 
  332         /* Check that the device number is legal
  333          * and the ATAPI driver is loaded. */
  334         if (lun >= wfdnlun || ! atapi_request_immediate)
  335                 return (ENXIO);
  336         t = wfdtab[lun];
  337 
  338         t->flags &= ~F_MEDIA_CHANGED;
  339         /* Lock the media. */
  340         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  341                           0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  342 
  343         /* Sense the media type */
  344         result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE,
  345                                      0, CAP_PAGE, 0, 0, 0, 0, 
  346                                      sizeof (t->cap) >> 8, sizeof (t->cap),
  347                                      0, 0, 0, 0, 0, 0, 0, 
  348                                      (char*) &t->cap, sizeof (t->cap));
  349         if (result.code)
  350                 printf ("wfd%d: Sense the media type is failed.\n", t->lun);
  351         else {
  352                 t->cap.cyls = ntohs (t->cap.cyls);
  353                 t->cap.sector_size = ntohs (t->cap.sector_size);
  354         }
  355 
  356         /* Build label for whole disk. */
  357         bzero(&label, sizeof label);
  358         label.d_secsize = t->cap.sector_size;
  359         label.d_nsectors = t->cap.sectors;
  360         label.d_ntracks = t->cap.heads;
  361         label.d_ncylinders = t->cap.cyls;
  362         label.d_secpercyl = t->cap.heads * t->cap.sectors;
  363         label.d_rpm = 720;
  364         label.d_secperunit = label.d_secpercyl * t->cap.cyls;
  365 
  366         /* Initialize slice tables. */
  367         errcode = dsopen(dev, fmt, 0, &t->dk_slices, &label);
  368         if (errcode != 0)
  369                 return errcode;
  370 
  371         t->flags |= F_BOPEN;
  372         return (0);
  373 }
  374 
  375 /*
  376  * Close the device.  Only called if we are the LAST
  377  * occurence of an open device.
  378  */
  379 int wfdclose (dev_t dev, int flags, int fmt, struct proc *p)
  380 {
  381         int lun = UNIT(dev);
  382         struct wfd *t = wfdtab[lun];
  383 
  384         dsclose(dev, fmt, t->dk_slices);
  385         if(!dsisopen(t->dk_slices)) {
  386                 /* If we were the last open of the entire device, release it. */
  387                 if (! t->refcnt)
  388                         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  389                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  390                 t->flags &= ~F_BOPEN;
  391         }
  392         return (0);
  393 }
  394 
  395 /*
  396  * Actually translate the requested transfer into one the physical driver can
  397  * understand. The transfer is described by a buf and will include only one
  398  * physical transfer.
  399  */
  400 void wfdstrategy (struct buf *bp)
  401 {
  402         int lun = UNIT(bp->b_dev);
  403         struct wfd *t = wfdtab[lun];
  404         int x;
  405 
  406         /* If it's a null transfer, return immediatly. */
  407         if (bp->b_bcount == 0) {
  408                 bp->b_resid = 0;
  409                 biodone (bp);
  410                 return;
  411         }
  412 
  413         /*
  414          * Do bounds checking, adjust transfer, and set b_pblkno.
  415          */
  416         if (dscheck(bp, t->dk_slices) <= 0) {
  417                 biodone(bp);
  418                 return;
  419         }
  420 
  421         x = splbio();
  422 
  423         /* Place it in the queue of disk activities for this disk. */
  424         bufqdisksort (&t->buf_queue, bp);
  425 
  426         /* Tell the device to get going on the transfer if it's
  427          * not doing anything, otherwise just wait for completion. */
  428         wfd_start (t);
  429         splx(x);
  430 }
  431 
  432 /*
  433  * Look to see if there is a buf waiting for the device
  434  * and that the device is not already busy. If both are true,
  435  * It dequeues the buf and creates an ATAPI command to perform the
  436  * transfer in the buf.
  437  * The bufs are queued by the strategy routine (wfdstrategy).
  438  * Must be called at the correct (splbio) level.
  439  */
  440 static void wfd_start (struct wfd *t)
  441 {
  442         struct buf *bp = bufq_first(&t->buf_queue);
  443         u_long blkno, nblk;
  444         u_char op_code;
  445         long count;
  446         int pxcount, pxnblk;
  447         u_char *pxdest;
  448         
  449 
  450         /* See if there is a buf to do and we are not already doing one. */
  451         if (! bp)
  452                 return;
  453 
  454         /* Unqueue the request. */
  455         bufq_remove(&t->buf_queue, bp);
  456 
  457         /* Tell devstat we are starting on the transaction */
  458         devstat_start_transaction(&t->device_stats);
  459 
  460         /* We have a buf, now we should make a command
  461          * First, translate the block to absolute and put it in terms of the
  462          * logical blocksize of the device. */
  463         blkno = bp->b_pblkno / (t->cap.sector_size / 512);
  464         nblk = (bp->b_bcount + (t->cap.sector_size - 1)) / t->cap.sector_size;
  465 
  466         if ((t->maxblks == 0) || (nblk <= t->maxblks)) {
  467 
  468                 if(bp->b_flags & B_READ) {
  469                         op_code = ATAPI_READ_BIG;
  470                         count = bp->b_bcount;
  471                 } else {
  472                         op_code = ATAPI_WRITE_BIG;
  473                         count = -bp->b_bcount;
  474                 }
  475 
  476                 /* only one transfer */
  477                 (int)bp->b_driver1 = 0;
  478                 (int)bp->b_driver2 = 0;
  479                 atapi_request_callback (t->ata, t->unit, op_code, 0,
  480                                         blkno>>24, blkno>>16, blkno>>8, blkno,
  481                                         0, nblk>>8, nblk, 0, 0,
  482                                         0, 0, 0, 0, 0, 
  483                                         (u_char*) bp->b_data, count, 
  484                                         (void*)wfd_done, t, bp);
  485         } else {
  486 
  487                 /*
  488                  * We can't handle this request in a single
  489                  * read/write operation.  Instead, queue a set of
  490                  * transfers, and record the number of transfers
  491                  * and the running residual in the b_driver
  492                  * fields of the bp.
  493                  */ 
  494 
  495                 if(bp->b_flags & B_READ) {
  496                         op_code = ATAPI_READ_BIG;
  497                 } else {
  498                         op_code = ATAPI_WRITE_BIG;
  499                 }
  500 
  501                 /* calculate number of transfers */
  502                 (int)bp->b_driver1 = (nblk - 1) / t->maxblks;
  503                 (int)bp->b_driver2 = 0;
  504 
  505                 pxdest = (u_char *)bp->b_data;
  506                 pxcount = bp->b_bcount;
  507 
  508                 /* construct partial transfer requests */
  509                 while (nblk > 0) {
  510                         pxnblk = min(nblk, t->maxblks);
  511                         count = min(pxcount, t->maxblks * t->cap.sector_size);
  512 
  513                         atapi_request_callback(t->ata, t->unit, op_code, 0,
  514                                                blkno>>24, blkno>>16, blkno>>8,
  515                                                blkno, 0, pxnblk>>8, pxnblk, 
  516                                                0, 0, 0, 0, 0, 0, 0,
  517                                                pxdest, 
  518                                                (bp->b_flags & B_READ) ?
  519                                                count : -count, 
  520                                                (void*)wfd_done, t, bp);
  521                         nblk -= pxnblk;
  522                         pxcount -= count;
  523                         pxdest += count;
  524                         blkno += pxnblk;
  525                 }
  526         }
  527 }
  528 
  529 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
  530         struct atapires result)
  531 {
  532                 
  533         if (result.code) {
  534                 wfd_error (t, result);
  535                 bp->b_error = EIO;
  536                 bp->b_flags |= B_ERROR;
  537         } else
  538                 (int)bp->b_driver2 += resid;
  539         /*
  540          * We can't call biodone until all outstanding
  541          * transfer fragments are handled.  If one hits
  542          * an error, we will be returning an error, but
  543          * only when all are complete.
  544          */
  545         if (((int)bp->b_driver1)-- <= 0) {
  546                 bp->b_resid = (int)bp->b_driver2;
  547                 devstat_end_transaction_buf(&t->device_stats, bp);
  548                 biodone (bp);
  549         }
  550         
  551         wfd_start (t);
  552 }
  553 
  554 static void wfd_error (struct wfd *t, struct atapires result)
  555 {
  556         if (result.code != RES_ERR)
  557                 return;
  558         switch (result.error & AER_SKEY) {
  559         case AER_SK_NOT_READY:
  560                 if (result.error & ~AER_SKEY) {
  561                         /* Not Ready */
  562                         printf ("wfd%d: not ready\n", t->lun);
  563                         return;
  564                 }
  565                 /* Tray open. */
  566                 if (! (t->flags & F_MEDIA_CHANGED))
  567                         printf ("wfd%d: tray open\n", t->lun);
  568                 t->flags |= F_MEDIA_CHANGED;
  569                 return;
  570 
  571         case AER_SK_UNIT_ATTENTION:
  572                 /* Media changed. */
  573                 if (! (t->flags & F_MEDIA_CHANGED))
  574                         printf ("wfd%d: media changed\n", t->lun);
  575                 t->flags |= F_MEDIA_CHANGED;
  576                 return;
  577 
  578         case AER_SK_ILLEGAL_REQUEST:
  579                 /* Unknown command or invalid command arguments. */
  580                 if (t->flags & F_DEBUG)
  581                         printf ("wfd%d: invalid command\n", t->lun);
  582                 return;
  583         }
  584         printf ("wfd%d: i/o error, status=%b, error=%b\n", t->lun,
  585                 result.status, ARS_BITS, result.error, AER_BITS);
  586 }
  587 
  588 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
  589         u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
  590         u_char a9, char *addr, int count)
  591 {
  592         struct atapires result;
  593 
  594         result = atapi_request_wait (t->ata, t->unit, cmd,
  595                 a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
  596                 addr, count);
  597         if (result.code) {
  598                 wfd_error (t, result);
  599                 return (EIO);
  600         }
  601         return (0);
  602 }
  603 
  604 /*
  605  * Perform special action on behalf of the user.
  606  * Knows about the internals of this device
  607  */
  608 int wfdioctl (dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
  609 {
  610         int lun = UNIT(dev);
  611         struct wfd *t = wfdtab[lun];
  612         int error = 0;
  613 
  614         error = dsioctl(dev, cmd, addr, flag, &t->dk_slices);
  615         if (error != ENOIOCTL)
  616                 return (error);
  617 
  618         if (t->flags & F_MEDIA_CHANGED)
  619                 switch (cmd) {
  620                 case CDIOCSETDEBUG:
  621                 case CDIOCCLRDEBUG:
  622                 case CDIOCRESET:
  623                         /* These ops are media change transparent. */
  624                         break;
  625                 default:
  626                         /* Lock the media. */
  627                         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  628                                 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  629                         break;
  630                 }
  631         switch (cmd) {
  632         case CDIOCSETDEBUG:
  633                 error = suser(p);
  634                 if (error)
  635                         return (error);
  636                 t->flags |= F_DEBUG;
  637                 atapi_debug (t->ata, 1);
  638                 return 0;
  639         case CDIOCCLRDEBUG:
  640                 error = suser(p);
  641                 if (error)
  642                         return (error);
  643                 t->flags &= ~F_DEBUG;
  644                 atapi_debug (t->ata, 0);
  645                 return 0;
  646         case CDIOCRESET:
  647                 error = suser(p);
  648                 if (error)
  649                         return (error);
  650                 return wfd_request_wait (t, ATAPI_TEST_UNIT_READY,
  651                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  652         case CDIOCEJECT:
  653                 /* Don't allow eject if the device is opened
  654                  * by somebody (not us) in block mode. */
  655                 if ((t->flags & F_BOPEN) && t->refcnt)
  656                         return (EBUSY);
  657                 return wfd_eject (t, 0);
  658         case CDIOCCLOSE:
  659                 if ((t->flags & F_BOPEN) && t->refcnt)
  660                         return (0);
  661                 return wfd_eject (t, 1);
  662         default:
  663                 return (ENOTTY);
  664         }
  665         return (error);
  666 }
  667 
  668 static int wfd_eject (struct wfd *t, int closeit)
  669 {
  670         struct atapires result;
  671 
  672         /* Try to stop the disc. */
  673         result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
  674                 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  675 
  676         if (result.code == RES_ERR &&
  677             ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
  678             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
  679                 int err;
  680 
  681                 if (!closeit)
  682                         return (0);
  683                 /*
  684                  * The disc was unloaded.
  685                  * Load it (close tray).
  686                  * Read the table of contents.
  687                  */
  688                 err = wfd_request_wait (t, ATAPI_START_STOP,
  689                         0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
  690                 if (err)
  691                         return (err);
  692 
  693                 /* Lock the media. */
  694                 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  695                         0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  696 
  697                 return (0);
  698         }
  699 
  700         if (result.code) {
  701                 wfd_error (t, result);
  702                 return (EIO);
  703         }
  704 
  705         if (closeit)
  706                 return (0);
  707 
  708         /* Give it some time to stop spinning. */
  709         tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej1", 0);
  710         tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej2", 0);
  711 
  712         /* Unlock. */
  713         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  714                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  715 
  716         /* Eject. */
  717         t->flags |= F_MEDIA_CHANGED;
  718         return wfd_request_wait (t, ATAPI_START_STOP,
  719                 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
  720 }
  721 
  722 static void     wfd_drvinit(void *unused)
  723 {
  724         cdevsw_add(&wfd_cdevsw);
  725 }
  726 
  727 SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)

Cache object: 97666e7df4cd55e2d1857acf4373f889


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