]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/isa/wst.c
This commit was generated by cvs2svn to compensate for changes in r56893,
[FreeBSD/FreeBSD.git] / sys / i386 / isa / wst.c
1 /*-
2  * Copyright (c) 1998 Søren Schmidt
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  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 #include "wdc.h"
32 #include "opt_ddb.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/conf.h>
38 #include <sys/malloc.h>
39 #include <sys/buf.h>
40 #include <sys/mtio.h>
41 #include <machine/clock.h>
42 #include <i386/isa/atapi.h>
43
44 static  d_open_t    wstopen;
45 static  d_close_t   wstclose;
46 static  d_ioctl_t   wstioctl;
47 static  d_strategy_t    wststrategy;
48
49 #define CDEV_MAJOR 90
50
51 static struct cdevsw wst_cdevsw = {
52         /* open */      wstopen,
53         /* close */     wstclose,
54         /* read */      physread,
55         /* write */     physwrite,
56         /* ioctl */     wstioctl,
57         /* poll */      nopoll,
58         /* mmap */      nommap,
59         /* strategy */  wststrategy,
60         /* name */      "wst",
61         /* maj */       CDEV_MAJOR,
62         /* dump */      nodump,
63         /* psize */     nopsize,
64         /* flags */     0,
65         /* bmaj */      -1
66 };
67
68 static unsigned int wst_total = 0;
69
70 #define NUNIT                   (NWDC*2)
71 #define UNIT(d)                 ((minor(d) >> 3) & 3)
72
73 #define WST_OPEN                0x0001  /* The device is opened */
74 #define WST_MEDIA_CHANGED       0x0002  /* The media have changed */
75 #define WST_DATA_WRITTEN        0x0004  /* Data has been written */
76 #define WST_FM_WRITTEN          0x0008  /* Filemark has been written */
77 #define WST_DEBUG               0x0010  /* Print debug info */
78 #define WST_CTL_WARN            0x0020  /* Have we warned about CTL wrong? */
79
80 /* ATAPI tape commands not in std ATAPI command set */
81 #define ATAPI_TAPE_REWIND               0x01
82 #define ATAPI_TAPE_REQUEST_SENSE        0x03
83 #define ATAPI_TAPE_READ_CMD             0x08
84 #define ATAPI_TAPE_WRITE_CMD            0x0a
85 #define ATAPI_TAPE_WEOF                 0x10
86 #define     WEOF_WRITE_MASK                     0x01
87 #define ATAPI_TAPE_SPACE_CMD            0x11
88 #define     SP_FM                               0x01
89 #define     SP_EOD                              0x03
90 #define ATAPI_TAPE_ERASE                0x19
91 #define ATAPI_TAPE_MODE_SENSE           0x1a
92 #define ATAPI_TAPE_LOAD_UNLOAD          0x1b
93 #define     LU_LOAD_MASK                        0x01
94 #define     LU_RETENSION_MASK                   0x02
95 #define     LU_EOT_MASK                         0x04
96
97 #define DSC_POLL_INTERVAL       10
98
99 /* 
100  * MODE SENSE parameter header
101  */
102 struct wst_header {
103     u_char  data_length;                /* Total length of data */
104     u_char  medium_type;                /* Medium type (if any) */
105     u_char  dsp;                        /* Device specific parameter */
106     u_char  bdl;                        /* Block Descriptor Length */
107 };
108
109 /*
110  * ATAPI tape drive Capabilities and Mechanical Status Page
111  */
112 #define ATAPI_TAPE_CAP_PAGE     0x2a
113
114 struct wst_cappage {
115     u_int   page_code           :6;     /* Page code == 0x2a */
116     u_int   reserved1_67        :2;
117     u_char  page_length;                /* Page Length == 0x12 */
118     u_char  reserved2;
119     u_char  reserved3;
120     u_int   readonly            :1;     /* Read Only Mode */
121     u_int   reserved4_1234      :4;
122     u_int   reverse             :1;     /* Supports reverse direction */
123     u_int   reserved4_67        :2;
124     u_int   reserved5_012       :3;
125     u_int   eformat             :1;     /* Supports ERASE formatting */
126     u_int   reserved5_4         :1;
127     u_int   qfa                 :1;     /* Supports QFA formats */
128     u_int   reserved5_67        :2;
129     u_int   lock                :1;     /* Supports locking media */
130     u_int   locked              :1;     /* The media is locked */
131     u_int   prevent             :1;     /* Defaults  to prevent state */
132     u_int   eject               :1;     /* Supports eject */
133     u_int   disconnect          :1;     /* Can break request > ctl */
134     u_int   reserved6_5         :1;
135     u_int   ecc                 :1;     /* Supports error correction */
136     u_int   compress            :1;     /* Supports data compression */
137     u_int   reserved7_0         :1;
138     u_int   blk512              :1;     /* Supports 512b block size */
139     u_int   blk1024             :1;     /* Supports 1024b block size */
140     u_int   reserved7_3456      :4;
141     u_int   slowb               :1;     /* Restricts byte count */
142     u_short max_speed;                  /* Supported speed in KBps */
143     u_short max_defects;                /* Max stored defect entries */
144     u_short ctl;                        /* Continuous Transfer Limit */
145     u_short speed;                      /* Current Speed, in KBps */
146     u_short buffer_size;                /* Buffer Size, in 512 bytes */
147     u_char  reserved18;
148     u_char  reserved19;
149 };
150
151 /*
152  * REQUEST SENSE structure
153  */
154 struct wst_reqsense {
155     u_int   error_code          :7;     /* Current or deferred errors */
156     u_int   valid               :1;     /* Follows QIC-157C */
157     u_char  reserved1;                  /* Segment Number - Reserved */
158     u_int   sense_key           :4;     /* Sense Key */
159     u_int   reserved2_4         :1;     /* Reserved */
160     u_int   ili                 :1;     /* Incorrect Length Indicator */
161     u_int   eom                 :1;     /* End Of Medium */
162     u_int   filemark            :1;     /* Filemark */
163     u_int   info __attribute__((packed)); /* Cmd specific info */
164     u_char  asl;                        /* Additional sense length (n-7) */
165     u_int   command_specific;           /* Additional cmd specific info */
166     u_char  asc;                        /* Additional Sense Code */
167     u_char  ascq;                       /* Additional Sense Code Qualifier */
168     u_char  replaceable_unit_code;      /* Field Replaceable Unit Code */
169     u_int   sk_specific1        :7;     /* Sense Key Specific */
170     u_int   sksv                :1;     /* Sense Key Specific info valid */
171     u_char  sk_specific2;               /* Sense Key Specific */
172     u_char  sk_specific3;               /* Sense Key Specific */
173     u_char  pad[2];                     /* Padding */
174 };
175
176 struct wst {
177     struct atapi *ata;                  /* Controller structure */
178     int unit;                           /* IDE bus drive unit */
179     int lun;                            /* Logical device unit */
180     int flags;                          /* Device state flags */
181     int blksize;                        /* Block size (512 | 1024) */
182     struct buf_queue_head buf_queue;    /* Queue of i/o requests */
183     struct atapi_params *param;         /* Drive parameters table */
184     struct wst_header header;           /* MODE SENSE param header */
185     struct wst_cappage cap;             /* Capabilities page info */
186 };
187
188 static struct wst *wsttab[NUNIT];       /* Drive info by unit number */
189 static int wstnlun = 0;                 /* Number of config'd drives */
190
191 int wstattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug);
192 static int wst_sense(struct wst *t);
193 static void wst_describe(struct wst *t);
194 static void wst_poll_dsc(struct wst *t);
195 static void wst_start(struct wst *t);
196 static void wst_done(struct wst *t, struct buf *bp, int resid, struct atapires result);
197 static int wst_error(struct wst *t, struct atapires result);
198 static void wst_drvinit(void *unused);
199 static int wst_space_cmd(struct wst *t, u_char function, u_int count);
200 static int wst_write_filemark(struct wst *t, u_char function);
201 static int wst_erase(struct wst *t);
202 static int wst_load_unload(struct wst *t, u_char finction);
203 static int wst_rewind(struct wst *t);
204 static void wst_reset(struct wst *t);
205
206 #ifdef DDB
207 void  wst_dump(int lun, char *label, void *data, int len);
208
209 void 
210 wst_dump(int lun, char *label, void *data, int len)
211 {
212     u_char *p = data;
213
214     printf("wst%d: %s %x", lun, label, *p++);
215     while(--len > 0)
216         printf("-%x", *p++);
217     printf("\n");
218 }
219 #endif
220
221 int 
222 wstattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug)
223 {
224     struct wst *t;
225     int lun;
226
227     if (wstnlun >= NUNIT) {
228         printf("wst: too many units\n");
229         return(-1);
230     }
231     if (!atapi_request_immediate) {
232         printf("wst: configuration error, ATAPI core code not present!\n");
233         printf(
234             "wst: check `options ATAPI_STATIC' in your kernel config file!\n");
235         return(-1);
236     }
237     t = malloc(sizeof(struct wst), M_TEMP, M_NOWAIT);
238     if (!t) {
239         printf("wst: out of memory\n");
240         return(-1);
241     }
242     wsttab[wstnlun] = t;
243     bzero(t, sizeof(struct wst));
244     bufq_init(&t->buf_queue);
245     t->ata = ata;
246     t->unit = unit;
247     t->ata->use_dsc = 1;
248     lun = t->lun = wstnlun;
249     t->param = ap;
250     t->flags = WST_MEDIA_CHANGED | WST_DEBUG;
251
252     if (wst_sense(t))
253         return -1;
254
255     wst_describe(t);
256     wstnlun++;
257
258     make_dev(&wst_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0640, "rwst%d", t->lun);
259     return(1);
260 }
261
262 static int 
263 wst_sense(struct wst *t)
264 {
265     struct atapires result;
266     int count;
267     char buffer[255];
268
269     /* Get drive capabilities, some drives needs this repeated */
270     for (count = 0 ; count < 5 ; count++) {
271         result = atapi_request_immediate(t->ata, t->unit,
272             ATAPI_TAPE_MODE_SENSE,
273             8, /* DBD = 1 no block descr */
274             ATAPI_TAPE_CAP_PAGE,
275             sizeof(buffer)>>8, sizeof(buffer),
276             0, 0, 0, 0, 0, 0, 0,
277             0, 0, 0, 0, buffer, sizeof(buffer));
278         if (result.code == 0 || result.code == RES_UNDERRUN)
279             break;
280     }
281
282     /* Some drives have shorter capabilities page. */
283     if (result.code == RES_UNDERRUN)
284         result.code = 0;
285
286     if (result.code == 0) {
287         bcopy(buffer, &t->header, sizeof(struct wst_header));
288         bcopy(buffer+sizeof(struct wst_header),
289             &t->cap, sizeof(struct wst_cappage));
290         if (t->cap.page_code != ATAPI_TAPE_CAP_PAGE)
291             return 1;   
292         t->cap.max_speed = ntohs(t->cap.max_speed);
293         t->cap.max_defects = ntohs(t->cap.max_defects);
294         t->cap.ctl = ntohs(t->cap.ctl);
295         t->cap.speed = ntohs(t->cap.speed);
296         t->cap.buffer_size = ntohs(t->cap.buffer_size);
297         t->blksize = (t->cap.blk512 ? 512 : (t->cap.blk1024 ? 1024 : 0));
298         return 0;
299     }
300     return 1;
301 }
302
303 static void 
304 wst_describe(struct wst *t)
305 {
306     printf("wst%d: ", t->lun);
307     switch (t->header.medium_type) {
308         case 0x00:      printf("Drive empty"); break;
309         case 0x17:      printf("Travan 1 (400 Mbyte) media"); break;
310         case 0xb6:      printf("Travan 4 (4 Gbyte) media"); break;
311         default: printf("Unknown media (0x%x)", t->header.medium_type);
312     }
313     if (t->cap.readonly) printf(", readonly");
314     if (t->cap.reverse) printf(", reverse");
315     if (t->cap.eformat) printf(", eformat");
316     if (t->cap.qfa) printf(", qfa");
317     if (t->cap.lock) printf(", lock");
318     if (t->cap.locked) printf(", locked");
319     if (t->cap.prevent) printf(", prevent");
320     if (t->cap.eject) printf(", eject");
321     if (t->cap.disconnect) printf(", disconnect");
322     if (t->cap.ecc) printf(", ecc");
323     if (t->cap.compress) printf(", compress");
324     if (t->cap.blk512) printf(", 512b");
325     if (t->cap.blk1024) printf(", 1024b");
326     if (t->cap.slowb) printf(", slowb");
327     printf("\nwst%d: ", t->lun);
328     printf("Max speed=%dKb/s, ", t->cap.max_speed);
329     printf("Transfer limit=%d blocks, ", t->cap.ctl);
330     printf("Buffer size=%d blocks", t->cap.buffer_size);
331     printf("\n");
332 }
333
334 int
335 wstopen(dev_t dev, int flags, int fmt, struct proc *p)
336 {
337     int lun = UNIT(dev);
338     struct wst *t;
339
340     /* Check that the device number and that the ATAPI driver is loaded. */
341     if (lun >= wstnlun || !atapi_request_immediate) {
342         printf("ENXIO lun=%d, wstnlun=%d, im=%p\n",
343                lun, wstnlun, (void *)atapi_request_immediate);
344         return(ENXIO);
345     }
346     t = wsttab[lun];
347     if (t->flags == WST_OPEN)
348         return EBUSY;
349     if (wst_sense(t))
350         printf("wst%d: Sense media type failed\n", t->lun);
351     t->flags &= ~WST_MEDIA_CHANGED;
352     t->flags &= ~(WST_DATA_WRITTEN | WST_FM_WRITTEN);
353     t->flags |= WST_OPEN;
354     return(0);
355 }
356
357 int 
358 wstclose(dev_t dev, int flags, int fmt, struct proc *p)
359 {
360     int lun = UNIT(dev);
361     struct wst *t = wsttab[lun];
362
363     /* Flush buffers, some drives fail here, but they should report ctl = 0 */
364     if (t->cap.ctl && (t->flags & WST_DATA_WRITTEN))
365         wst_write_filemark(t, 0);
366
367     /* Write filemark if data written to tape */
368     if ((t->flags & (WST_DATA_WRITTEN | WST_FM_WRITTEN)) == WST_DATA_WRITTEN)
369         wst_write_filemark(t, WEOF_WRITE_MASK);
370
371     /* If minor is even rewind on close */
372     if (!(minor(dev) & 0x01))   
373         wst_rewind(t);
374
375     t->flags &= ~WST_OPEN;
376     if (t->flags & WST_DEBUG)
377         printf("wst%d: %ud total bytes transferred\n", t->lun, wst_total);
378     t->flags &= ~WST_CTL_WARN;
379     return(0);
380 }
381
382 void 
383 wststrategy(struct buf *bp)
384 {
385     int lun = UNIT(bp->b_dev);
386     struct wst *t = wsttab[lun];
387     int x;
388
389     /* If it's a null transfer, return immediatly. */
390     if (bp->b_bcount == 0) {
391         bp->b_resid = 0;
392         biodone(bp);
393         return;
394     }
395
396     /* Check for != blocksize requests */
397     if (bp->b_bcount % t->blksize) {
398         printf("wst%d: bad request, must be multiple of %d\n", lun, t->blksize);
399         bp->b_error = EIO;
400         bp->b_flags |= B_ERROR;
401         biodone(bp);
402         return;
403     }
404
405     if (bp->b_bcount > t->blksize*t->cap.ctl) {  
406         if ((t->flags & WST_CTL_WARN) == 0) {
407             printf("wst%d: WARNING: CTL exceeded %ld>%d\n", 
408                     lun, bp->b_bcount, t->blksize*t->cap.ctl);
409             t->flags |= WST_CTL_WARN;
410         }
411     }
412
413     x = splbio();
414     wst_total += bp->b_bcount;
415     bufq_insert_tail(&t->buf_queue, bp);
416     wst_start(t);
417     splx(x);
418 }
419
420 static void     
421 wst_poll_dsc(struct wst *t)
422
423     /* We should use a final timeout here SOS XXX */
424     if (!(inb(t->ata->port + AR_STATUS) & ARS_DSC)) {
425         timeout((timeout_t*)wst_poll_dsc, t, DSC_POLL_INTERVAL);
426         return;
427     }       
428     t->ata->wait_for_dsc = 0;
429     wakeup((caddr_t)t);
430 }
431
432 static void 
433 wst_start(struct wst *t)
434 {
435     struct buf *bp = bufq_first(&t->buf_queue);
436     u_long blk_count;
437     u_char op_code;
438     long byte_count;
439     
440     if (!bp)
441         return;
442
443     if (t->ata->wait_for_dsc)
444         printf("wst%d: ERROR! allready waiting for DSC\n", t->lun);
445
446     /* Sleep waiting for a ready drive (DSC) */
447     if (t->ata->use_dsc && !(inb(t->ata->port + AR_STATUS) & ARS_DSC)) {
448         t->ata->wait_for_dsc = 1;
449         timeout((timeout_t*)wst_poll_dsc, t, DSC_POLL_INTERVAL);
450         tsleep((caddr_t) t, 0, "wstdsc", 0);
451     }
452
453     bufq_remove(&t->buf_queue, bp);
454     blk_count = bp->b_bcount / t->blksize;
455
456     if (bp->b_flags & B_READ) {
457         op_code = ATAPI_TAPE_READ_CMD;
458         byte_count = bp->b_bcount;
459     } else {
460         op_code = ATAPI_TAPE_WRITE_CMD;
461         t->flags |= WST_DATA_WRITTEN;
462         byte_count = -bp->b_bcount;
463     }
464
465     atapi_request_callback(t->ata, t->unit, op_code, 1,
466                            blk_count>>16, blk_count>>8, blk_count,
467                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
468                            (u_char*) bp->b_data, byte_count, 
469                            (void*)wst_done, t, bp);
470 }
471
472 static void 
473 wst_done(struct wst *t, struct buf *bp, int resid,
474     struct atapires result)
475 {
476     if (result.code) {
477         printf("wst_done: ");
478         wst_error(t, result);
479         bp->b_error = EIO;
480         bp->b_flags |= B_ERROR;
481     }
482     else
483         bp->b_resid = resid;
484
485     biodone(bp);
486     /*wst_start(t);*/
487 }
488
489 static int 
490 wst_error(struct wst *t, struct atapires result)
491 {
492     struct wst_reqsense sense;
493
494     if (result.code != RES_ERR) {
495         printf("wst%d: ERROR code=%d, status=%b, error=%b\n", t->lun,
496                result.code, result.status, ARS_BITS, result.error, AER_BITS);
497         return 1;
498     }
499
500     if ((result.error & AER_SKEY) && (result.status & ARS_CHECK)) {
501         atapi_request_immediate(t->ata, t->unit,
502             ATAPI_TAPE_REQUEST_SENSE,
503             0, 0, 0, sizeof(sense),
504             0, 0, 0, 0, 0, 0, 0,
505             0, 0, 0, 0, (char*) &sense, sizeof(struct wst_reqsense));
506         /*wst_dump(t->lun, "req_sense", &sense, sizeof(struct wst_reqsense));*/
507     }
508     switch (result.error & AER_SKEY) {
509     case AER_SK_NOT_READY:
510         if (result.error & ~AER_SKEY) {
511             if (t->flags & WST_DEBUG)
512                 printf("wst%d: not ready\n", t->lun);
513             break;
514         }
515         if (!(t->flags & WST_MEDIA_CHANGED))
516             if (t->flags & WST_DEBUG)
517                 printf("wst%d: no media\n", t->lun);
518         t->flags |= WST_MEDIA_CHANGED;
519         break;
520
521     case AER_SK_BLANK_CHECK:
522         if (t->flags & WST_DEBUG)
523             printf("wst%d: EOD encountered\n", t->lun);
524         break;
525
526     case AER_SK_MEDIUM_ERROR:
527         if (t->flags & WST_DEBUG)
528             printf("wst%d: nonrecovered data error\n", t->lun);
529         break;
530
531     case AER_SK_HARDWARE_ERROR:
532         if (t->flags & WST_DEBUG)
533             printf("wst%d: nonrecovered hardware error\n", t->lun);
534         break;
535
536     case AER_SK_ILLEGAL_REQUEST:
537         if (t->flags & WST_DEBUG)
538             printf("wst%d: invalid command\n", t->lun);
539         break;
540
541     case AER_SK_UNIT_ATTENTION:
542         if (!(t->flags & WST_MEDIA_CHANGED))
543             printf("wst%d: media changed\n", t->lun);
544         t->flags |= WST_MEDIA_CHANGED;
545         break;
546
547     case AER_SK_DATA_PROTECT:
548         if (t->flags & WST_DEBUG)
549             printf("wst%d: reading read protected data\n", t->lun);
550         break;
551
552     case AER_SK_ABORTED_COMMAND:
553         if (t->flags & WST_DEBUG)
554             printf("wst%d: command aborted\n", t->lun);
555         break;
556
557     case AER_SK_MISCOMPARE:
558         if (t->flags & WST_DEBUG)
559             printf("wst%d: data don't match medium\n", t->lun);
560         break;
561
562     default:
563         printf("wst%d: i/o error, status=%b, error=%b\n", t->lun,
564                 result.status, ARS_BITS, result.error, AER_BITS);
565     }
566     printf("total=%u ERR=%x len=%ld ASC=%x ASCQ=%x\n", 
567            wst_total, sense.error_code, (long)ntohl(sense.info), 
568            sense.asc, sense.ascq);
569     return 1;
570 }
571
572 int 
573 wstioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
574 {
575     int lun = UNIT(dev);
576     int error = 0;
577     struct wst *t = wsttab[lun];
578
579     switch (cmd) {
580     case MTIOCGET:
581         {
582             struct mtget *g = (struct mtget *) addr;
583
584             bzero(g, sizeof(struct mtget));
585             g->mt_type = 7;
586             g->mt_density = 1;
587             g->mt_blksiz = t->blksize;
588             g->mt_comp = t->cap.compress;
589             g->mt_density0 = 0; g->mt_density1 = 0;
590             g->mt_density2 = 0; g->mt_density3 = 0;
591             g->mt_blksiz0 = 0; g->mt_blksiz1 = 0;
592             g->mt_blksiz2 = 0; g->mt_blksiz3 = 0;
593             g->mt_comp0 = 0; g->mt_comp1 = 0;
594             g->mt_comp2 = 0; g->mt_comp3 = 0;
595             break;       
596         }
597     case MTIOCTOP:
598         {       
599             int i;
600             struct mtop *mt = (struct mtop *)addr;
601
602             switch ((short) (mt->mt_op)) {
603             case MTWEOF:
604                 for (i=0; i < mt->mt_count && !error; i++)
605                         error = wst_write_filemark(t, WEOF_WRITE_MASK);
606                 break;
607             case MTFSF:
608                 if (mt->mt_count)
609                         error = wst_space_cmd(t, SP_FM, mt->mt_count);
610                 break;
611             case MTBSF:
612                 if (mt->mt_count)
613                         error = wst_space_cmd(t, SP_FM, -(mt->mt_count));
614                 break;
615             case MTFSR:
616                 error = EINVAL; break;
617             case MTBSR:
618                 error = EINVAL; break;
619             case MTREW:
620                 error = wst_rewind(t);
621                 break;
622             case MTOFFL:
623 #if 1                           /* Misuse as a reset func for now */
624                 wst_reset(t);
625                 wst_sense(t);
626                 wst_describe(t);
627 #else
628                 if (error = wst_rewind(t))
629                     break;
630                 error = wst_load_unload(t, !LU_LOAD_MASK);
631 #endif
632                     break;
633             case MTNOP:
634                 error = wst_write_filemark(t, 0);
635                 break;
636             case MTCACHE:
637                 error = EINVAL; break;
638             case MTNOCACHE:
639                 error = EINVAL; break;
640             case MTSETBSIZ:
641                 error = EINVAL; break;
642             case MTSETDNSTY:
643                 error = EINVAL; break;
644             case MTERASE:
645                 error = wst_erase(t);
646                 break;
647             case MTEOD:
648                 error = wst_space_cmd(t, SP_EOD, 0);
649                 break;
650             case MTCOMP:
651                 error = EINVAL; break;
652             case MTRETENS:
653                 error = wst_load_unload(t, LU_RETENSION_MASK|LU_LOAD_MASK);
654                 break;
655             default:
656                 error = EINVAL;
657             }
658             return error;
659         }
660     default:
661         return(ENOTTY);
662     }
663     return(error);
664 }
665
666 static int
667 wst_space_cmd(struct wst *t, u_char function, u_int count)
668 {
669     struct atapires result;
670
671     result = atapi_request_wait(t->ata, t->unit, 
672                                 ATAPI_TAPE_SPACE_CMD, function,
673                                 count>>16, count>>8, count,
674                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
675     if (result.code) {
676         printf("wst_space_cmd: ");
677         wst_error(t, result);
678         return EIO;
679     }
680     return 0;
681 }
682
683 static int
684 wst_write_filemark(struct wst *t, u_char function)
685 {
686     struct atapires result;
687
688     if (function) {
689         if (t->flags & WST_FM_WRITTEN)
690             t->flags &= ~WST_DATA_WRITTEN;
691         else
692             t->flags |= WST_FM_WRITTEN;
693     }
694     result = atapi_request_wait(t->ata, t->unit, 
695                                 ATAPI_TAPE_WEOF, 0, 0, 0, function,
696                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
697     if (result.code) {
698         printf("wst_write_filemark: ");
699         wst_error(t, result);
700         return EIO;
701     }
702     return 0;
703 }
704
705 static int
706 wst_load_unload(struct wst *t, u_char function)
707 {
708     struct atapires result;
709
710     result = atapi_request_wait(t->ata, t->unit, 
711                                 ATAPI_TAPE_LOAD_UNLOAD, 0, 0, 0, function,
712                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
713     if (result.code) {
714         printf("wst_load_unload: ");
715         wst_error(t, result);
716         return EIO;
717     }
718     return 0;
719 }
720
721 static int
722 wst_erase(struct wst *t)
723 {
724     int error;
725     struct atapires result;
726
727     error = wst_rewind(t);
728     if (error)
729         return error;
730     result = atapi_request_wait(t->ata, t->unit, 
731                                 ATAPI_TAPE_ERASE, 3, 0, 0, 0,
732                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
733                                 NULL, 0);
734     if (result.code) {
735         printf("wst_erase: ");
736         wst_error(t, result);
737         return EIO;
738     }
739     return 0;
740 }
741
742 static int
743 wst_rewind(struct wst *t)
744 {
745     struct atapires result;       
746
747     result = atapi_request_wait(t->ata, t->unit,
748                                     ATAPI_TAPE_REWIND, 0, 0, 0, 0,
749                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
750                                     NULL, 0);
751     if (result.code) {
752         printf("wst_rewind: ");
753         wst_error(t, result);
754         return EIO;
755     }
756     return 0;
757 }
758
759 static void
760 wst_reset(struct wst *t)
761 {
762     outb(t->ata->port + AR_DRIVE, ARD_DRIVE1);
763     DELAY(30);
764     outb(t->ata->port + AR_COMMAND, 0x08);
765     DELAY(30);
766 }
767
768 static void 
769 wst_drvinit(void *unused)
770 {
771     cdevsw_add(&wst_cdevsw);
772 }
773
774 SYSINIT(wstdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wst_drvinit,NULL)