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/ata/atapi-tape.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) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org>
    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,
   10  *    without modification, immediately at the beginning of the file.
   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 THE AUTHOR ``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 THE AUTHOR 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 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include "opt_ata.h"
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/ata.h>
   34 #include <sys/kernel.h>
   35 #include <sys/module.h>
   36 #include <sys/malloc.h>
   37 #include <sys/conf.h>
   38 #include <sys/bio.h>
   39 #include <sys/bus.h>
   40 #include <sys/mtio.h>
   41 #include <sys/devicestat.h>
   42 #include <sys/sema.h>
   43 #include <sys/taskqueue.h>
   44 #include <vm/uma.h>
   45 #include <machine/bus.h>
   46 #include <dev/ata/ata-all.h>
   47 #include <dev/ata/atapi-tape.h>
   48 #include <ata_if.h>
   49 
   50 /* device structure */
   51 static  d_open_t        ast_open;
   52 static  d_close_t       ast_close;
   53 static  d_ioctl_t       ast_ioctl;
   54 static  d_strategy_t    ast_strategy;
   55 static struct cdevsw ast_cdevsw = {
   56         .d_version =    D_VERSION,
   57         .d_open =       ast_open,
   58         .d_close =      ast_close,
   59         .d_read =       physread,
   60         .d_write =      physwrite,
   61         .d_ioctl =      ast_ioctl,
   62         .d_strategy =   ast_strategy,
   63         .d_name =       "ast",
   64         .d_flags =      D_TAPE | D_TRACKCLOSE,
   65 };
   66 
   67 /* prototypes */
   68 static int ast_sense(device_t);
   69 static void ast_describe(device_t);
   70 static void ast_done(struct ata_request *);
   71 static int ast_mode_sense(device_t, int, void *, int); 
   72 static int ast_mode_select(device_t, void *, int);
   73 static int ast_write_filemark(device_t, u_int8_t);
   74 static int ast_read_position(device_t, int, struct ast_readposition *);
   75 static int ast_space(device_t, u_int8_t, int32_t);
   76 static int ast_locate(device_t, int, u_int32_t);
   77 static int ast_prevent_allow(device_t, int);
   78 static int ast_load_unload(device_t, u_int8_t);
   79 static int ast_rewind(device_t);
   80 static int ast_erase(device_t);
   81 static int ast_test_ready(device_t);
   82 static int ast_wait_dsc(device_t, int);
   83 
   84 /* internal vars */
   85 static u_int64_t ast_total = 0;
   86 static MALLOC_DEFINE(M_AST, "ast_driver", "ATAPI tape driver buffers");
   87 
   88 static int
   89 ast_probe(device_t dev)
   90 {
   91     struct ata_device *atadev = device_get_softc(dev);
   92 
   93     if ((atadev->param.config & ATA_PROTO_ATAPI) &&
   94         (atadev->param.config & ATA_ATAPI_TYPE_MASK) == ATA_ATAPI_TYPE_TAPE)
   95         return 0;
   96     else
   97         return ENXIO;
   98 }
   99 
  100 static int
  101 ast_attach(device_t dev)
  102 {
  103     struct ata_channel *ch = device_get_softc(device_get_parent(dev));
  104     struct ata_device *atadev = device_get_softc(dev);
  105     struct ast_softc *stp;
  106     struct ast_readposition position;
  107     struct cdev *device;
  108 
  109     if (!(stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO))) {
  110         device_printf(dev, "out of memory\n");
  111         return ENOMEM;
  112     }
  113     device_set_ivars(dev, stp);
  114     ATA_SETMODE(device_get_parent(dev), dev);
  115 
  116     if (ast_sense(dev)) {
  117         device_set_ivars(dev, NULL);
  118         free(stp, M_AST);
  119         return ENXIO;
  120     }
  121     if (!strcmp(atadev->param.model, "OnStream DI-30")) {
  122         struct ast_transferpage transfer;
  123         struct ast_identifypage identify;
  124 
  125         stp->flags |= F_ONSTREAM;
  126         bzero(&transfer, sizeof(struct ast_transferpage));
  127         ast_mode_sense(dev, ATAPI_TAPE_TRANSFER_PAGE,
  128                        &transfer, sizeof(transfer));
  129         bzero(&identify, sizeof(struct ast_identifypage));
  130         ast_mode_sense(dev, ATAPI_TAPE_IDENTIFY_PAGE,
  131                        &identify, sizeof(identify));
  132         strncpy(identify.ident, "FBSD", 4);
  133         ast_mode_select(dev, &identify, sizeof(identify));
  134         ast_read_position(dev, 0, &position);
  135     }
  136 
  137     stp->stats = devstat_new_entry("ast", device_get_unit(dev), DEV_BSIZE,
  138                       DEVSTAT_NO_ORDERED_TAGS,
  139                       DEVSTAT_TYPE_SEQUENTIAL | DEVSTAT_TYPE_IF_IDE,
  140                       DEVSTAT_PRIORITY_TAPE);
  141     device = make_dev(&ast_cdevsw, 2 * device_get_unit(dev),
  142                       UID_ROOT, GID_OPERATOR, 0640, "ast%d",
  143                       device_get_unit(dev));
  144     device->si_drv1 = dev;
  145     if (ch->dma)
  146         device->si_iosize_max = ch->dma->max_iosize;
  147     else
  148         device->si_iosize_max = DFLTPHYS;
  149     stp->dev1 = device;
  150     device = make_dev(&ast_cdevsw, 2 * device_get_unit(dev) + 1,
  151                       UID_ROOT, GID_OPERATOR, 0640, "nast%d",
  152                       device_get_unit(dev));
  153     device->si_drv1 = dev;
  154     if (ch->dma)
  155         device->si_iosize_max = ch->dma->max_iosize;
  156     else
  157         device->si_iosize_max = DFLTPHYS;
  158     stp->dev2 = device;
  159 
  160     /* announce we are here and ready */
  161     ast_describe(dev);
  162     return 0;
  163 }
  164 
  165 static int      
  166 ast_detach(device_t dev)
  167 {   
  168     struct ast_softc *stp = device_get_ivars(dev);
  169     
  170     /* detroy devices from the system so we dont get any further requests */
  171     destroy_dev(stp->dev1);
  172     destroy_dev(stp->dev2);
  173 
  174     /* fail requests on the queue and any thats "in flight" for this device */
  175     ata_fail_requests(dev);
  176 
  177     /* dont leave anything behind */
  178     devstat_remove_entry(stp->stats);
  179     device_set_ivars(dev, NULL);
  180     free(stp, M_AST);
  181     return 0;
  182 }
  183 
  184 static void
  185 ast_shutdown(device_t dev)
  186 {
  187     struct ata_device *atadev = device_get_softc(dev);
  188 
  189     if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
  190         ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0);
  191 }
  192 
  193 static int
  194 ast_reinit(device_t dev)
  195 {
  196     struct ata_channel *ch = device_get_softc(device_get_parent(dev));
  197     struct ata_device *atadev = device_get_softc(dev);
  198 
  199     if (((atadev->unit == ATA_MASTER) && !(ch->devices & ATA_ATAPI_MASTER)) ||
  200         ((atadev->unit == ATA_SLAVE) && !(ch->devices & ATA_ATAPI_SLAVE))) {
  201         return 1;
  202     }
  203     ATA_SETMODE(device_get_parent(dev), dev);
  204     return 0;
  205 }
  206 
  207 static int
  208 ast_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
  209 {
  210     device_t dev = cdev->si_drv1;
  211     struct ata_device *atadev = device_get_softc(dev);
  212     struct ast_softc *stp = device_get_ivars(dev);
  213 
  214     if (!stp)
  215         return ENXIO;
  216     if (!device_is_attached(dev))
  217         return EBUSY;
  218 
  219     ast_test_ready(dev);
  220     if (stp->cap.lock)
  221         ast_prevent_allow(dev, 1);
  222     if (ast_sense(dev))
  223         device_printf(dev, "sense media type failed\n");
  224 
  225     atadev->flags &= ~ATA_D_MEDIA_CHANGED;
  226     stp->flags &= ~(F_DATA_WRITTEN | F_FM_WRITTEN);
  227     ast_total = 0;
  228     return 0;
  229 }
  230 
  231 static int 
  232 ast_close(struct cdev *cdev, int flags, int fmt, struct thread *td)
  233 {
  234     device_t dev = cdev->si_drv1;
  235     struct ast_softc *stp = device_get_ivars(dev);
  236 
  237     /* flush buffers, some drives fail here, they should report ctl = 0 */
  238     if (stp->cap.ctl && (stp->flags & F_DATA_WRITTEN))
  239         ast_write_filemark(dev, 0);
  240 
  241     /* write filemark if data written to tape */
  242     if (!(stp->flags & F_ONSTREAM) &&
  243         (stp->flags & (F_DATA_WRITTEN | F_FM_WRITTEN)) == F_DATA_WRITTEN)
  244         ast_write_filemark(dev, ATAPI_WF_WRITE);
  245 
  246     /* if minor is even rewind on close */
  247     if (!(minor(cdev) & 0x01))
  248         ast_rewind(dev);
  249 
  250     if (stp->cap.lock && count_dev(cdev) == 1)
  251         ast_prevent_allow(dev, 0);
  252 
  253     stp->flags &= ~F_CTL_WARN;
  254 #ifdef AST_DEBUG
  255     device_printf(dev, "%ju total bytes transferred\n", (uintmax_t)ast_total);
  256 #endif
  257     return 0;
  258 }
  259 
  260 static int 
  261 ast_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flag, struct thread *td)
  262 {
  263     device_t dev = cdev->si_drv1;
  264     struct ast_softc *stp = device_get_ivars(dev);
  265     int error = 0;
  266 
  267     switch (cmd) {
  268     case MTIOCGET:
  269         {
  270             struct mtget *g = (struct mtget *) data;
  271 
  272             bzero(g, sizeof(struct mtget));
  273             g->mt_type = 7;
  274             g->mt_density = 1;
  275             g->mt_blksiz = stp->blksize;
  276             g->mt_comp = stp->cap.compress;
  277             g->mt_density0 = 0; g->mt_density1 = 0;
  278             g->mt_density2 = 0; g->mt_density3 = 0;
  279             g->mt_blksiz0 = 0; g->mt_blksiz1 = 0;
  280             g->mt_blksiz2 = 0; g->mt_blksiz3 = 0;
  281             g->mt_comp0 = 0; g->mt_comp1 = 0;
  282             g->mt_comp2 = 0; g->mt_comp3 = 0;
  283         }
  284         break;   
  285 
  286     case MTIOCTOP:
  287         {       
  288             int i;
  289             struct mtop *mt = (struct mtop *)data;
  290 
  291             switch ((int16_t) (mt->mt_op)) {
  292 
  293             case MTWEOF:
  294                 for (i=0; i < mt->mt_count && !error; i++)
  295                     error = ast_write_filemark(dev, ATAPI_WF_WRITE);
  296                 break;
  297 
  298             case MTFSF:
  299                 if (mt->mt_count)
  300                     error = ast_space(dev, ATAPI_SP_FM, mt->mt_count);
  301                 break;
  302 
  303             case MTBSF:
  304                 if (mt->mt_count)
  305                     error = ast_space(dev, ATAPI_SP_FM, -(mt->mt_count));
  306                 break;
  307 
  308             case MTREW:
  309                 error = ast_rewind(dev);
  310                 break;
  311 
  312             case MTOFFL:
  313                 error = ast_load_unload(dev, ATAPI_SS_EJECT);
  314                 break;
  315 
  316             case MTNOP:
  317                 error = ast_write_filemark(dev, 0);
  318                 break;
  319 
  320             case MTERASE:
  321                 error = ast_erase(dev);
  322                 break;
  323 
  324             case MTEOD:
  325                 error = ast_space(dev, ATAPI_SP_EOD, 0);
  326                 break;
  327 
  328             case MTRETENS:
  329                 error = ast_load_unload(dev, ATAPI_SS_RETENSION|ATAPI_SS_LOAD);
  330                 break;
  331 
  332             case MTFSR:         
  333             case MTBSR:
  334             case MTCACHE:
  335             case MTNOCACHE:
  336             case MTSETBSIZ:
  337             case MTSETDNSTY:
  338             case MTCOMP:
  339             default:
  340                 error = EINVAL;
  341             }
  342         }
  343         break;
  344 
  345     case MTIOCRDSPOS:
  346         {
  347             struct ast_readposition position;
  348 
  349             if ((error = ast_read_position(dev, 0, &position)))
  350                 break;
  351             *(u_int32_t *)data = position.tape;
  352         }
  353         break;
  354 
  355     case MTIOCRDHPOS:
  356         {
  357             struct ast_readposition position;
  358 
  359             if ((error = ast_read_position(dev, 1, &position)))
  360                 break;
  361             *(u_int32_t *)data = position.tape;
  362         }
  363         break;
  364 
  365     case MTIOCSLOCATE:
  366         error = ast_locate(dev, 0, *(u_int32_t *)data);
  367         break;
  368 
  369     case MTIOCHLOCATE:
  370         error = ast_locate(dev, 1, *(u_int32_t *)data);
  371         break;
  372 
  373     default:
  374         error = ata_device_ioctl(dev, cmd, data);
  375     }
  376     return error;
  377 }
  378 
  379 static void 
  380 ast_strategy(struct bio *bp)
  381 {
  382     device_t dev = bp->bio_dev->si_drv1;
  383     struct ata_device *atadev = device_get_softc(dev);
  384     struct ast_softc *stp = device_get_ivars(dev);
  385     struct ata_request *request;
  386     u_int32_t blkcount;
  387     int8_t ccb[16];
  388 
  389     /* if it's a null transfer, return immediatly. */
  390     if (bp->bio_bcount == 0) {
  391         bp->bio_resid = 0;
  392         biodone(bp);
  393         return;
  394     }
  395     if (!(bp->bio_cmd == BIO_READ) && stp->flags & F_WRITEPROTECT) {
  396         biofinish(bp, NULL, EPERM);
  397         return;
  398     }
  399         
  400     /* check for != blocksize requests */
  401     if (bp->bio_bcount % stp->blksize) {
  402         device_printf(dev, "transfers must be multiple of %d\n", stp->blksize);
  403         biofinish(bp, NULL, EIO);
  404         return;
  405     }
  406 
  407     /* warn about transfers bigger than the device suggests */
  408     if (bp->bio_bcount > stp->blksize * stp->cap.ctl) {  
  409         if ((stp->flags & F_CTL_WARN) == 0) {
  410             device_printf(dev, "WARNING: CTL exceeded %ld>%d\n",
  411                           bp->bio_bcount, stp->blksize * stp->cap.ctl);
  412             stp->flags |= F_CTL_WARN;
  413         }
  414     }
  415 
  416     bzero(ccb, sizeof(ccb));
  417 
  418     if (bp->bio_cmd == BIO_READ)
  419         ccb[0] = ATAPI_READ;
  420     else
  421         ccb[0] = ATAPI_WRITE;
  422     
  423     blkcount = bp->bio_bcount / stp->blksize;
  424 
  425     ccb[1] = 1;
  426     ccb[2] = blkcount >> 16;
  427     ccb[3] = blkcount >> 8;
  428     ccb[4] = blkcount;
  429 
  430     if (!(request = ata_alloc_request())) {
  431         biofinish(bp, NULL, ENOMEM);
  432         return;
  433     }
  434     request->dev = dev;
  435     request->driver = bp;
  436     bcopy(ccb, request->u.atapi.ccb,
  437           (atadev->param.config & ATA_PROTO_MASK) == 
  438           ATA_PROTO_ATAPI_12 ? 16 : 12);
  439     request->data = bp->bio_data;
  440     request->bytecount = blkcount * stp->blksize;
  441     request->transfersize = min(request->bytecount, 65534);
  442     request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 180 : 120;
  443     request->retries = 2;
  444     request->callback = ast_done;
  445     switch (bp->bio_cmd) {
  446     case BIO_READ:
  447         request->flags |= (ATA_R_ATAPI | ATA_R_READ);
  448         break;
  449     case BIO_WRITE:
  450         request->flags |= (ATA_R_ATAPI | ATA_R_WRITE);
  451         break;
  452     default:
  453         device_printf(dev, "unknown BIO operation\n");
  454         ata_free_request(request);
  455         biofinish(bp, NULL, EIO);
  456         return;
  457     }
  458     devstat_start_transaction_bio(stp->stats, bp);
  459     ata_queue_request(request);
  460 }
  461 
  462 static void 
  463 ast_done(struct ata_request *request)
  464 {
  465     struct ast_softc *stp = device_get_ivars(request->dev);
  466     struct bio *bp = request->driver;
  467 
  468     /* finish up transfer */
  469     if ((bp->bio_error = request->result))
  470         bp->bio_flags |= BIO_ERROR;
  471     if (bp->bio_cmd == BIO_WRITE)
  472         stp->flags |= F_DATA_WRITTEN;
  473     bp->bio_resid = bp->bio_bcount - request->donecount;
  474     ast_total += (bp->bio_bcount - bp->bio_resid);
  475     biofinish(bp, stp->stats, 0);
  476     ata_free_request(request);
  477 }
  478 
  479 static int
  480 ast_sense(device_t dev)
  481 {
  482     struct ast_softc *stp = device_get_ivars(dev);
  483     int count;
  484 
  485     /* get drive capabilities, some bugridden drives needs this repeated */
  486     for (count = 0 ; count < 5 ; count++) {
  487         if (!ast_mode_sense(dev, ATAPI_TAPE_CAP_PAGE,
  488                             &stp->cap, sizeof(stp->cap)) &&
  489             stp->cap.page_code == ATAPI_TAPE_CAP_PAGE) {
  490             if (stp->cap.blk32k)
  491                 stp->blksize = 32768;
  492             if (stp->cap.blk1024)
  493                 stp->blksize = 1024;
  494             if (stp->cap.blk512)
  495                 stp->blksize = 512;
  496             if (!stp->blksize)
  497                 continue;
  498             stp->cap.max_speed = ntohs(stp->cap.max_speed);
  499             stp->cap.max_defects = ntohs(stp->cap.max_defects);
  500             stp->cap.ctl = ntohs(stp->cap.ctl);
  501             stp->cap.speed = ntohs(stp->cap.speed);
  502             stp->cap.buffer_size = ntohs(stp->cap.buffer_size);
  503             return 0;
  504         }
  505     }
  506     return 1;
  507 }
  508 
  509 static int
  510 ast_mode_sense(device_t dev, int page, void *pagebuf, int pagesize)
  511 {
  512     int8_t ccb[16] = { ATAPI_MODE_SENSE, 0x08, page, pagesize>>8, pagesize,
  513                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  514     int error;
  515  
  516     error = ata_atapicmd(dev, ccb, pagebuf, pagesize, ATA_R_READ, 10);
  517     return error;
  518 }
  519 
  520 static int       
  521 ast_mode_select(device_t dev, void *pagebuf, int pagesize)
  522 {
  523     int8_t ccb[16] = { ATAPI_MODE_SELECT, 0x10, 0, pagesize>>8, pagesize,
  524                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  525      
  526     return ata_atapicmd(dev, ccb, pagebuf, pagesize, 0, 10);
  527 }
  528 
  529 static int
  530 ast_write_filemark(device_t dev, u_int8_t function)
  531 {
  532     struct ast_softc *stp = device_get_ivars(dev);
  533     int8_t ccb[16] = { ATAPI_WEOF, 0x01, 0, 0, function, 0, 0, 0,
  534                        0, 0, 0, 0, 0, 0, 0, 0 };
  535     int error;
  536 
  537     if (stp->flags & F_ONSTREAM)
  538         ccb[4] = 0x00;          /* only flush buffers supported */
  539     else {
  540         if (function) {
  541             if (stp->flags & F_FM_WRITTEN)
  542                 stp->flags &= ~F_DATA_WRITTEN;
  543             else
  544                 stp->flags |= F_FM_WRITTEN;
  545         }
  546     }
  547     error = ata_atapicmd(dev, ccb, NULL, 0, 0, 10);
  548     if (error)
  549         return error;
  550     return ast_wait_dsc(dev, 10*60);
  551 }
  552 
  553 static int
  554 ast_read_position(device_t dev, int hard, struct ast_readposition *position)
  555 {
  556     int8_t ccb[16] = { ATAPI_READ_POSITION, (hard ? 0x01 : 0), 0, 0, 0, 0, 0, 0,
  557                        0, 0, 0, 0, 0, 0, 0, 0 };
  558     int error;
  559 
  560     error = ata_atapicmd(dev, ccb, (caddr_t)position, 
  561                          sizeof(struct ast_readposition), ATA_R_READ, 10);
  562     position->tape = ntohl(position->tape);
  563     position->host = ntohl(position->host);
  564     return error;
  565 }
  566 
  567 static int
  568 ast_space(device_t dev, u_int8_t function, int32_t count)
  569 {
  570     int8_t ccb[16] = { ATAPI_SPACE, function, count>>16, count>>8, count,
  571                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  572 
  573     return ata_atapicmd(dev, ccb, NULL, 0, 0, 60*60);
  574 }
  575 
  576 static int
  577 ast_locate(device_t dev, int hard, u_int32_t pos)
  578 {
  579     int8_t ccb[16] = { ATAPI_LOCATE, 0x01 | (hard ? 0x4 : 0), 0,
  580                        pos>>24, pos>>16, pos>>8, pos,
  581                        0, 0, 0, 0, 0, 0, 0, 0, 0 };
  582     int error;
  583 
  584     error = ata_atapicmd(dev, ccb, NULL, 0, 0, 10);
  585     if (error)
  586         return error;
  587     return ast_wait_dsc(dev, 60*60);
  588 }
  589 
  590 static int
  591 ast_prevent_allow(device_t dev, int lock)
  592 {
  593     int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
  594                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  595 
  596     return ata_atapicmd(dev, ccb, NULL, 0, 0, 30);
  597 }
  598 
  599 static int
  600 ast_load_unload(device_t dev, u_int8_t function)
  601 {
  602     struct ast_softc *stp = device_get_ivars(dev);
  603     int8_t ccb[16] = { ATAPI_START_STOP, 0x01, 0, 0, function, 0, 0, 0,
  604                        0, 0, 0, 0, 0, 0, 0, 0 };
  605     int error;
  606 
  607     if ((function & ATAPI_SS_EJECT) && !stp->cap.eject)
  608         return 0;
  609     error = ata_atapicmd(dev, ccb, NULL, 0, 0, 10);
  610     if (error)
  611         return error;
  612     pause("astlu", 1 * hz);
  613     if (function == ATAPI_SS_EJECT)
  614         return 0;
  615     return ast_wait_dsc(dev, 60*60);
  616 }
  617 
  618 static int
  619 ast_rewind(device_t dev)
  620 {
  621     int8_t ccb[16] = { ATAPI_REZERO, 0x01, 0, 0, 0, 0, 0, 0,
  622                        0, 0, 0, 0, 0, 0, 0, 0 };
  623     int error;
  624 
  625     error = ata_atapicmd(dev, ccb, NULL, 0, 0, 10);
  626     if (error)
  627         return error;
  628     return ast_wait_dsc(dev, 60*60);
  629 }
  630 
  631 static int
  632 ast_erase(device_t dev)
  633 {
  634     int8_t ccb[16] = { ATAPI_ERASE, 3, 0, 0, 0, 0, 0, 0,
  635                        0, 0, 0, 0, 0, 0, 0, 0 };
  636     int error;
  637 
  638     if ((error = ast_rewind(dev)))
  639         return error;
  640 
  641     return ata_atapicmd(dev, ccb, NULL, 0, 0, 60*60);
  642 }
  643 
  644 static int
  645 ast_test_ready(device_t dev)
  646 {
  647     int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
  648                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  649 
  650     return ata_atapicmd(dev, ccb, NULL, 0, 0, 30);
  651 }
  652 
  653 static int
  654 ast_wait_dsc(device_t dev, int timeout)
  655 {
  656     int error = 0;
  657     int8_t ccb[16] = { ATAPI_POLL_DSC, 0, 0, 0, 0,
  658                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  659 
  660     timeout *= hz;
  661     while (timeout > 0) {
  662         error = ata_atapicmd(dev, ccb, NULL, 0, 0, 0);
  663         if (error != EBUSY)
  664             break;
  665         pause("atpwt", hz / 2);
  666         timeout -= (hz / 2);
  667     }
  668     return error;
  669 }
  670 
  671 static void 
  672 ast_describe(device_t dev)
  673 {
  674     struct ata_channel *ch = device_get_softc(device_get_parent(dev));
  675     struct ata_device *atadev = device_get_softc(dev);
  676     struct ast_softc *stp = device_get_ivars(dev);
  677 
  678     if (bootverbose) {
  679         device_printf(dev, "<%.40s/%.8s> tape drive at ata%d as %s\n",
  680                       atadev->param.model, atadev->param.revision,
  681                       device_get_unit(ch->dev),
  682                       (atadev->unit == ATA_MASTER) ? "master" : "slave");
  683         device_printf(dev, "%dKB/s, ", stp->cap.max_speed);
  684         printf("transfer limit %d blk%s, ",
  685                stp->cap.ctl, (stp->cap.ctl > 1) ? "s" : "");
  686         printf("%dKB buffer, ", (stp->cap.buffer_size * DEV_BSIZE) / 1024);
  687         printf("%s\n", ata_mode2str(atadev->mode));
  688         device_printf(dev, "Medium: ");
  689         switch (stp->cap.medium_type) {
  690             case 0x00:
  691                 printf("none"); break;
  692             case 0x17:
  693                 printf("Travan 1 (400 Mbyte)"); break;
  694             case 0xb6:
  695                 printf("Travan 4 (4 Gbyte)"); break;
  696             case 0xda:
  697                 printf("OnStream ADR (15Gyte)"); break;
  698             default:
  699                 printf("unknown (0x%x)", stp->cap.medium_type);
  700         }
  701         if (stp->cap.readonly) printf(", readonly");
  702         if (stp->cap.reverse) printf(", reverse");
  703         if (stp->cap.eformat) printf(", eformat");
  704         if (stp->cap.qfa) printf(", qfa");
  705         if (stp->cap.lock) printf(", lock");
  706         if (stp->cap.locked) printf(", locked");
  707         if (stp->cap.prevent) printf(", prevent");
  708         if (stp->cap.eject) printf(", eject");
  709         if (stp->cap.disconnect) printf(", disconnect");
  710         if (stp->cap.ecc) printf(", ecc");
  711         if (stp->cap.compress) printf(", compress");
  712         if (stp->cap.blk512) printf(", 512b");
  713         if (stp->cap.blk1024) printf(", 1024b");
  714         if (stp->cap.blk32k) printf(", 32kb");
  715         printf("\n");
  716     }
  717     else {
  718         device_printf(dev, "TAPE <%.40s/%.8s> at ata%d-%s %s\n",
  719                       atadev->param.model, atadev->param.revision,
  720                       device_get_unit(ch->dev),
  721                       (atadev->unit == ATA_MASTER) ? "master" : "slave",
  722                       ata_mode2str(atadev->mode));
  723     }
  724 }
  725 
  726 static device_method_t ast_methods[] = {
  727     /* device interface */
  728     DEVMETHOD(device_probe,     ast_probe),
  729     DEVMETHOD(device_attach,    ast_attach),
  730     DEVMETHOD(device_detach,    ast_detach),
  731     DEVMETHOD(device_shutdown,  ast_shutdown),
  732                            
  733     /* ATA methods */
  734     DEVMETHOD(ata_reinit,       ast_reinit),
  735 
  736     { 0, 0 }
  737 };
  738             
  739 static driver_t ast_driver = {
  740     "ast",
  741     ast_methods,
  742     0,
  743 };
  744 
  745 static devclass_t ast_devclass;
  746 
  747 DRIVER_MODULE(ast, ata, ast_driver, ast_devclass, NULL, NULL);
  748 MODULE_VERSION(ast, 1);
  749 MODULE_DEPEND(ast, ata, 1, 1, 1);

Cache object: bd390e780171d9e2f15cf121a1836e5f


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